From e2650add402d9377cc0f8a5246d5dabcced73de0 Mon Sep 17 00:00:00 2001 From: Xinwei Xiong <3293172751NSS@gmail.com> Date: Fri, 26 Jan 2024 20:53:25 +0800 Subject: [PATCH 001/188] feat: Enhanced Automation for OpenIM Advanced CICD and GitOps Support (#1819) * feat: add advanced version cicd * fix: fix openim server deployment --- build/images/openim-rpc-encryption/Dockerfile | 45 +++++++++++++++++++ build/images/openim-rpc-extend-msg/Dockerfile | 45 +++++++++++++++++++ scripts/install-im-server.sh | 9 ++-- scripts/lib/release.sh | 5 ++- scripts/make-rules/image.mk | 3 +- scripts/release.sh | 2 +- 6 files changed, 102 insertions(+), 7 deletions(-) create mode 100644 build/images/openim-rpc-encryption/Dockerfile create mode 100644 build/images/openim-rpc-extend-msg/Dockerfile diff --git a/build/images/openim-rpc-encryption/Dockerfile b/build/images/openim-rpc-encryption/Dockerfile new file mode 100644 index 0000000000..e3f232eaf0 --- /dev/null +++ b/build/images/openim-rpc-encryption/Dockerfile @@ -0,0 +1,45 @@ +# 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. + +# OpenIM base image: https://github.com/openim-sigs/openim-base-image + +# Set go mod installation source and proxy + +FROM golang:1.20 AS builder + +ARG GO111MODULE=on +ARG GOPROXY=https://goproxy.cn,direct + +WORKDIR /openim/openim-server + +ENV GO111MODULE=$GO111MODULE +ENV GOPROXY=$GOPROXY + +COPY go.mod go.sum ./ +RUN go mod download + +COPY . . + +RUN make build BINS=openim-rpc-encryption + +RUN cp /openim/openim-server/_output/bin/platforms/$(go env GOOS)/$(go env GOARCH)/openim-rpc-encryption /usr/bin/openim-rpc-encryption + +# FROM ghcr.io/openim-sigs/openim-bash-image:latest +FROM ghcr.io/openim-sigs/openim-bash-image:latest + +WORKDIR /openim/openim-server + +COPY --from=builder /usr/bin/openim-rpc-encryption ./bin/openim-rpc-encryption + +ENTRYPOINT ["./bin/openim-rpc-encryption"] \ No newline at end of file diff --git a/build/images/openim-rpc-extend-msg/Dockerfile b/build/images/openim-rpc-extend-msg/Dockerfile new file mode 100644 index 0000000000..3ed94019b7 --- /dev/null +++ b/build/images/openim-rpc-extend-msg/Dockerfile @@ -0,0 +1,45 @@ +# 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. + +# OpenIM base image: https://github.com/openim-sigs/openim-base-image + +# Set go mod installation source and proxy + +FROM golang:1.20 AS builder + +ARG GO111MODULE=on +ARG GOPROXY=https://goproxy.cn,direct + +WORKDIR /openim/openim-server + +ENV GO111MODULE=$GO111MODULE +ENV GOPROXY=$GOPROXY + +COPY go.mod go.sum ./ +RUN go mod download + +COPY . . + +RUN make build BINS=openim-rpc-extend-msg + +RUN cp /openim/openim-server/_output/bin/platforms/$(go env GOOS)/$(go env GOARCH)/openim-rpc-extend-msg /usr/bin/openim-rpc-extend-msg + +# FROM ghcr.io/openim-sigs/openim-bash-image:latest +FROM ghcr.io/openim-sigs/openim-bash-image:latest + +WORKDIR /openim/openim-server + +COPY --from=builder /usr/bin/openim-rpc-extend-msg ./bin/openim-rpc-extend-msg + +ENTRYPOINT ["./bin/openim-rpc-extend-msg"] \ No newline at end of file diff --git a/scripts/install-im-server.sh b/scripts/install-im-server.sh index 9588032d7b..c1224e30c8 100755 --- a/scripts/install-im-server.sh +++ b/scripts/install-im-server.sh @@ -69,17 +69,18 @@ ${DOCKER_COMPOSE_COMMAND} up -d check_containers() { if ! ${DOCKER_COMPOSE_COMMAND} ps | grep -q 'Up'; then echo "Error: One or more docker containers failed to start." - ${DOCKER_COMPOSE_COMMAND} logs + ${DOCKER_COMPOSE_COMMAND} logs openim-server + ${DOCKER_COMPOSE_COMMAND} logs openim-chat return 1 fi return 0 } # Wait for a short period to allow containers to initialize -sleep 30 -check_containers +sleep 100 -${DOCKER_COMPOSE_COMMAND} logs openim-server ${DOCKER_COMPOSE_COMMAND} ps +check_containers + popd \ No newline at end of file diff --git a/scripts/lib/release.sh b/scripts/lib/release.sh index 2a525f12c2..521e5cedc1 100755 --- a/scripts/lib/release.sh +++ b/scripts/lib/release.sh @@ -25,6 +25,7 @@ readonly BUCKET="openim-1306374445" readonly REGION="ap-guangzhou" readonly COS_RELEASE_DIR="openim-release" +# readonly COS_RELEASE_DIR="openim-advanced-release" # !pro # default cos command tool coscli or coscmd readonly COSTOOL="coscli" @@ -37,9 +38,11 @@ readonly RELEASE_IMAGES="${LOCAL_OUTPUT_ROOT}/release-images" # OpenIM github account info readonly OPENIM_GITHUB_ORG=openimsdk readonly OPENIM_GITHUB_REPO=open-im-server -readonly CHAT_GITHUB_REPO=chat +# readonly OPENIM_GITHUB_REPO=open-im-server-enterprise # !pro readonly ARTIFACT=openim.tar.gz +# readonly ARTIFACT=openim-enterprise.tar.gz # !pro + readonly CHECKSUM=${ARTIFACT}.sha1sum OPENIM_BUILD_CONFORMANCE=${OPENIM_BUILD_CONFORMANCE:-y} diff --git a/scripts/make-rules/image.mk b/scripts/make-rules/image.mk index 14a4b2c319..eaec4a1271 100644 --- a/scripts/make-rules/image.mk +++ b/scripts/make-rules/image.mk @@ -45,7 +45,8 @@ endif IMAGES_DIR ?= $(wildcard ${ROOT_DIR}/build/images/*) # Determine images names by stripping out the dir names, and filter out the undesired directories # IMAGES ?= $(filter-out Dockerfile,$(foreach image,${IMAGES_DIR},$(notdir ${image}))) -IMAGES ?= $(filter-out Dockerfile openim-tools openim-cmdutils,$(foreach image,${IMAGES_DIR},$(notdir ${image}))) +IMAGES ?= $(filter-out Dockerfile openim-tools openim-rpc-extend-msg openim-rpc-encryption openim-cmdutils,$(foreach image,${IMAGES_DIR},$(notdir ${image}))) +# IMAGES ?= $(filter-out Dockerfile openim-tools openim-cmdutils,$(foreach image,${IMAGES_DIR},$(notdir ${image}))) # !pro ifeq (${IMAGES},) $(error Could not determine IMAGES, set ROOT_DIR or run in source dir) diff --git a/scripts/release.sh b/scripts/release.sh index 4984b21663..a34d5ee229 100755 --- a/scripts/release.sh +++ b/scripts/release.sh @@ -130,7 +130,7 @@ perform_action() { if [ "$flag" == true ]; then openim::log::info "## $message..." - if ! $command; then + if ! eval "$command"; then openim::log::errexit "Error in $message" fi fi From c86df88b59157cc52cc87add2d4a5b4eaeb18d7f Mon Sep 17 00:00:00 2001 From: chao <48119764+withchao@users.noreply.github.com> Date: Fri, 26 Jan 2024 20:55:37 +0800 Subject: [PATCH 002/188] fix: conversation aggregate find error (#1822) * fix: GroupApplicationAcceptedNotification * fix: GroupApplicationAcceptedNotification * fix: NotificationUserInfoUpdate * cicd: robot automated Change * fix: conversation aggregate find error --------- Co-authored-by: withchao --- go.mod | 4 ++-- go.sum | 8 ++++---- pkg/common/db/mgo/conversation.go | 3 ++- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/go.mod b/go.mod index fdc6a58dec..c709e9ba49 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.19 require ( firebase.google.com/go v3.13.0+incompatible github.com/OpenIMSDK/protocol v0.0.48 - github.com/OpenIMSDK/tools v0.0.28 + github.com/OpenIMSDK/tools v0.0.29 github.com/bwmarrin/snowflake v0.3.0 // indirect github.com/dtm-labs/rockscache v0.1.1 github.com/gin-gonic/gin v1.9.1 @@ -127,7 +127,7 @@ require ( github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect go.opencensus.io v0.24.0 // indirect go.uber.org/atomic v1.7.0 // indirect - go.uber.org/multierr v1.6.0 // indirect + go.uber.org/multierr v1.11.0 // indirect golang.org/x/arch v0.3.0 // indirect golang.org/x/net v0.17.0 // indirect golang.org/x/oauth2 v0.13.0 // indirect diff --git a/go.sum b/go.sum index 5539b41fc4..b7b40632f9 100644 --- a/go.sum +++ b/go.sum @@ -20,8 +20,8 @@ github.com/IBM/sarama v1.41.3 h1:MWBEJ12vHC8coMjdEXFq/6ftO6DUZnQlFYcxtOJFa7c= github.com/IBM/sarama v1.41.3/go.mod h1:Xxho9HkHd4K/MDUo/T/sOqwtX/17D33++E9Wib6hUdQ= github.com/OpenIMSDK/protocol v0.0.48 h1:8MIMjyzJRsruYhVv2ZKArFiOveroaofDOb3dlAdgjsw= github.com/OpenIMSDK/protocol v0.0.48/go.mod h1:F25dFrwrIx3lkNoiuf6FkCfxuwf8L4Z8UIsdTHP/r0Y= -github.com/OpenIMSDK/tools v0.0.28 h1:UT0rN1ysCFvsxQXyuxAj2TEkHt4C/sUezy+ChKpgt2Y= -github.com/OpenIMSDK/tools v0.0.28/go.mod h1:eg+q4A34Qmu73xkY0mt37FHGMCMfC6CtmOnm0kFEGFI= +github.com/OpenIMSDK/tools v0.0.29 h1:NS4PEwYl9sX3SWsMjDOLVxMo3LcTWREMr+2cjzWjcqc= +github.com/OpenIMSDK/tools v0.0.29/go.mod h1:eg+q4A34Qmu73xkY0mt37FHGMCMfC6CtmOnm0kFEGFI= github.com/QcloudApi/qcloud_sign_golang v0.0.0-20141224014652-e4130a326409/go.mod h1:1pk82RBxDY/JZnPQrtqHlUFfCctgdorsd9M06fMynOM= github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7 h1:uSoVVbwJiQipAclBbw+8quDsfcvFjOpI5iCf4p/cqCs= github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs= @@ -356,8 +356,8 @@ go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/automaxprocs v1.5.3 h1:kWazyxZUrS3Gs4qUpbwo5kEIMGe/DAvi5Z4tl2NW4j8= go.uber.org/automaxprocs v1.5.3/go.mod h1:eRbA25aqJrxAbsLO0xy5jVwPt7FQnRgjW+efnwa1WM0= go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= -go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= -go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= +go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= +go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60= go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= diff --git a/pkg/common/db/mgo/conversation.go b/pkg/common/db/mgo/conversation.go index bf5d1a145b..1614cfec5f 100644 --- a/pkg/common/db/mgo/conversation.go +++ b/pkg/common/db/mgo/conversation.go @@ -114,7 +114,8 @@ func (c *ConversationMgo) GetAllConversationIDs(ctx context.Context) ([]string, func (c *ConversationMgo) GetAllConversationIDsNumber(ctx context.Context) (int64, error) { counts, err := mgoutil.Aggregate[int64](ctx, c.coll, []bson.M{ {"$group": bson.M{"_id": "$conversation_id"}}, - {"$project": bson.M{"_id": 0, "conversation_id": "$_id"}}, + {"$group": bson.M{"_id": nil, "count": bson.M{"$sum": 1}}}, + {"$project": bson.M{"_id": 0}}, }) if err != nil { return 0, err From e79532aa936ec31a63db9ddf1e5e11b0cb0f1732 Mon Sep 17 00:00:00 2001 From: Xinwei Xiong <3293172751NSS@gmail.com> Date: Sat, 27 Jan 2024 00:10:42 +0800 Subject: [PATCH 003/188] feat: add pull request set workflows (#1824) * feat: add pull request set workflows * Update pull-request.yml --- .github/workflows/pull-request.yml | 39 +++++++++++++----------------- 1 file changed, 17 insertions(+), 22 deletions(-) diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index 828d30d7d2..065bcfa8ca 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -14,13 +14,8 @@ name: Github Pull Request on: - push: - branches: [main] - paths-ignore: - - 'README.md' - - 'CONTRIBUTING.md' - - 'docs/**' workflow_dispatch: + push: schedule: - cron: '0 2 * * *' @@ -37,24 +32,18 @@ jobs: with: fetch-depth: 0 - - name: Get League branch Patch - run: | - git config user.name 'openimbot' - git config user.email 'openimsdk@qq.com' - BRANCH_NAME="auto-pr-$(date +'%Y%m%d%H%M%S')" - git checkout -b $BRANCH_NAME - - uses: actions/setup-node@v4 - name: Setup Go uses: actions/setup-go@v4 - 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 + - name: Run go format and lint run: | sudo make format echo "Run go format successfully" @@ -69,7 +58,14 @@ jobs: - name: Generate all necessary files, such as error code files run: | make generate - echo "Generate all necessary files successfully" + ./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: Run unit test and get test coverage @@ -90,13 +86,13 @@ jobs: with: token: ${{ secrets.BOT_GITHUB_TOKEN }} commit-message: "cicd: bump League Patch" - author: kubbot - signoff: false - draft: false - branch: '' + author: kubbot <3293172751ysy@gmail.com> + committer: kubbot <3293172751ysy@gmail.com> + # signoff: false + # draft: false + branch: "asf-auto-updates" assignees: cubxxw reviewers: cubxxw - delete-branch: true title: "Bump League Patch auto PR: $(date +'%Y%m%d')" body: | Review criteria: @@ -105,8 +101,7 @@ jobs: This is an automated PR. @ $(date +'%Y%m%d') [workflow](https://github.com/openimsdk/open-im-server/blob/main/.github/workflows/pull-request.yml). - base: main labels: | kind/documentation enhancement - report \ No newline at end of file + report From 19ffde31961cfc63efc1160846eca333961ec769 Mon Sep 17 00:00:00 2001 From: OpenIM Bot <124379614+kubbot@users.noreply.github.com> Date: Sat, 27 Jan 2024 00:49:37 +0800 Subject: [PATCH 004/188] cicd: bump League Patch (#1825) --- internal/rpc/user/user.go | 1 - pkg/common/config/version | 2 +- pkg/common/discoveryregister/direct/directResolver.go | 5 +++-- pkg/common/discoveryregister/direct/directconn.go | 4 +++- pkg/common/discoveryregister/discoveryregister.go | 3 ++- 5 files changed, 9 insertions(+), 6 deletions(-) diff --git a/internal/rpc/user/user.go b/internal/rpc/user/user.go index 981e0ccc45..0be5f97f48 100644 --- a/internal/rpc/user/user.go +++ b/internal/rpc/user/user.go @@ -61,7 +61,6 @@ type userServer struct { RegisterCenter registry.SvcDiscoveryRegistry } - func Start(client registry.SvcDiscoveryRegistry, server *grpc.Server) error { rdb, err := cache.NewRedis() if err != nil { diff --git a/pkg/common/config/version b/pkg/common/config/version index 4d0729e54b..d5c0c99142 100644 --- a/pkg/common/config/version +++ b/pkg/common/config/version @@ -1 +1 @@ -v3.5.0 \ No newline at end of file +3.5.1 diff --git a/pkg/common/discoveryregister/direct/directResolver.go b/pkg/common/discoveryregister/direct/directResolver.go index 285f551127..d5482ab624 100644 --- a/pkg/common/discoveryregister/direct/directResolver.go +++ b/pkg/common/discoveryregister/direct/directResolver.go @@ -2,10 +2,11 @@ package direct import ( "context" - "github.com/OpenIMSDK/tools/log" - "google.golang.org/grpc/resolver" "math/rand" "strings" + + "github.com/OpenIMSDK/tools/log" + "google.golang.org/grpc/resolver" ) const ( diff --git a/pkg/common/discoveryregister/direct/directconn.go b/pkg/common/discoveryregister/direct/directconn.go index 3eaa6fa194..6589e3aba1 100644 --- a/pkg/common/discoveryregister/direct/directconn.go +++ b/pkg/common/discoveryregister/direct/directconn.go @@ -4,10 +4,12 @@ import ( "context" "errors" "fmt" + "github.com/OpenIMSDK/tools/errs" - config2 "github.com/openimsdk/open-im-server/v3/pkg/common/config" "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" + + config2 "github.com/openimsdk/open-im-server/v3/pkg/common/config" ) type ServiceAddresses map[string][]int diff --git a/pkg/common/discoveryregister/discoveryregister.go b/pkg/common/discoveryregister/discoveryregister.go index 76c8fb2672..23a9e32450 100644 --- a/pkg/common/discoveryregister/discoveryregister.go +++ b/pkg/common/discoveryregister/discoveryregister.go @@ -16,9 +16,10 @@ package discoveryregister import ( "errors" - "github.com/openimsdk/open-im-server/v3/pkg/common/discoveryregister/direct" "os" + "github.com/openimsdk/open-im-server/v3/pkg/common/discoveryregister/direct" + "github.com/openimsdk/open-im-server/v3/pkg/common/discoveryregister/kubernetes" "github.com/openimsdk/open-im-server/v3/pkg/common/discoveryregister/zookeeper" From 7ef32bf8a0a6171f09fc1114d0f0f36b3c92f6c6 Mon Sep 17 00:00:00 2001 From: Xinwei Xiong <3293172751NSS@gmail.com> Date: Sat, 27 Jan 2024 00:50:11 +0800 Subject: [PATCH 005/188] [Auto PR] Bump League Patch in '"base branch' (#1827) --- .github/workflows/pull-request.yml | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index 065bcfa8ca..6f39c93b28 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -15,7 +15,6 @@ name: Github Pull Request on: workflow_dispatch: - push: schedule: - cron: '0 2 * * *' @@ -58,6 +57,13 @@ jobs: - 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 @@ -76,7 +82,6 @@ jobs: - name: OpenIM verify copyright run: | - sudo make verify-copyright sudo make add-copyright echo "OpenIM verify successfully" continue-on-error: true @@ -93,13 +98,19 @@ jobs: branch: "asf-auto-updates" assignees: cubxxw reviewers: cubxxw - title: "Bump League Patch auto PR: $(date +'%Y%m%d')" + 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/open-im-server/actions/workflows/pull-request.yml/badge.svg)](https://github.com/openimsdk/open-im-server/actions/workflows/pull-request.yml) - This is an automated PR. @ $(date +'%Y%m%d') + This is an automated PR. [workflow](https://github.com/openimsdk/open-im-server/blob/main/.github/workflows/pull-request.yml). labels: | kind/documentation From 1d5732c97e3f86789d82ee2816c42b0f2ccf506c Mon Sep 17 00:00:00 2001 From: OpenIM Bot <124379614+kubbot@users.noreply.github.com> Date: Sat, 27 Jan 2024 10:50:25 +0800 Subject: [PATCH 006/188] cicd: bump League Patch (#1828) --- .../discoveryregister/direct/directResolver.go | 14 ++++++++++++++ pkg/common/discoveryregister/direct/directconn.go | 14 ++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/pkg/common/discoveryregister/direct/directResolver.go b/pkg/common/discoveryregister/direct/directResolver.go index d5482ab624..a706ce5e4d 100644 --- a/pkg/common/discoveryregister/direct/directResolver.go +++ b/pkg/common/discoveryregister/direct/directResolver.go @@ -1,3 +1,17 @@ +// 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 direct import ( diff --git a/pkg/common/discoveryregister/direct/directconn.go b/pkg/common/discoveryregister/direct/directconn.go index 6589e3aba1..84f173ea6d 100644 --- a/pkg/common/discoveryregister/direct/directconn.go +++ b/pkg/common/discoveryregister/direct/directconn.go @@ -1,3 +1,17 @@ +// 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 direct import ( From b14c0475d28bb192e5764c64757c2c4f677f6c80 Mon Sep 17 00:00:00 2001 From: a3d21 <93191329+a3d21@users.noreply.github.com> Date: Sat, 27 Jan 2024 10:52:13 +0800 Subject: [PATCH 007/188] fix duplicated offline push (#1816) --- internal/push/push_to_client.go | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/internal/push/push_to_client.go b/internal/push/push_to_client.go index 72deb720d1..caa39e6185 100644 --- a/internal/push/push_to_client.go +++ b/internal/push/push_to_client.go @@ -118,18 +118,25 @@ func (p *Pusher) Push2User(ctx context.Context, userIDs []string, msg *sdkws.Msg return nil } - for _, v := range wsResults { - if !v.OnlinePush && msg.SendID == v.UserID { - if err = callbackOfflinePush(ctx, userIDs, msg, &[]string{}); err != nil { - return err - } + if len(wsResults) == 0 { + return nil + } + onlinePushSuccUserIDSet := utils.SliceSet(utils.Filter(wsResults, func(e *msggateway.SingleMsgToUserResults) (string, bool) { + return e.UserID, e.OnlinePush && e.UserID != "" + })) + offlinePushUserIDList := utils.Filter(wsResults, func(e *msggateway.SingleMsgToUserResults) (string, bool) { + _, exist := onlinePushSuccUserIDSet[e.UserID] + return e.UserID, !exist && e.UserID != "" && e.UserID != msg.SendID + }) - err = p.offlinePushMsg(ctx, msg.SendID, msg, []string{v.UserID}) - if err != nil { - return err - } + if len(offlinePushUserIDList) > 0 { + if err = callbackOfflinePush(ctx, offlinePushUserIDList, msg, &[]string{}); err != nil { + return err + } + err = p.offlinePushMsg(ctx, msg.SendID, msg, offlinePushUserIDList) + if err != nil { + return err } - } return nil } From 34551a82a2fb8e35931b0e9cd0011b6aa2d134e3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 28 Jan 2024 18:30:51 +0800 Subject: [PATCH 008/188] chore(deps): bump golang.org/x/crypto in /tools/data-conversion (#1580) Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.16.0 to 0.17.0. - [Commits](https://github.com/golang/crypto/compare/v0.16.0...v0.17.0) --- updated-dependencies: - dependency-name: golang.org/x/crypto dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- tools/data-conversion/go.mod | 2 +- tools/data-conversion/go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/data-conversion/go.mod b/tools/data-conversion/go.mod index 37d1776c2c..9637559236 100644 --- a/tools/data-conversion/go.mod +++ b/tools/data-conversion/go.mod @@ -63,7 +63,7 @@ require ( go.uber.org/multierr v1.6.0 // indirect go.uber.org/zap v1.24.0 // indirect golang.org/x/arch v0.3.0 // indirect - golang.org/x/crypto v0.16.0 // indirect + golang.org/x/crypto v0.17.0 // indirect golang.org/x/image v0.13.0 // indirect golang.org/x/sys v0.15.0 // indirect golang.org/x/text v0.14.0 // indirect diff --git a/tools/data-conversion/go.sum b/tools/data-conversion/go.sum index 66f85785b7..d6dc23742f 100644 --- a/tools/data-conversion/go.sum +++ b/tools/data-conversion/go.sum @@ -146,8 +146,8 @@ golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= -golang.org/x/crypto v0.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY= -golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= +golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= +golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= golang.org/x/image v0.13.0 h1:3cge/F/QTkNLauhf2QoE9zp+7sr+ZcL4HnoZmdwg9sg= golang.org/x/image v0.13.0/go.mod h1:6mmbMOeV28HuMTgA6OSRkdXKYw/t5W9Uwn2Yv1r3Yxk= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= From f94d8af737439e9c6ec2b5c937e430eb970bff5d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 28 Jan 2024 18:32:34 +0800 Subject: [PATCH 009/188] chore(deps): bump google.golang.org/grpc in /tools/url2im (#1283) Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.56.2 to 1.56.3. - [Release notes](https://github.com/grpc/grpc-go/releases) - [Commits](https://github.com/grpc/grpc-go/compare/v1.56.2...v1.56.3) --- updated-dependencies: - dependency-name: google.golang.org/grpc dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- tools/url2im/go.mod | 2 +- tools/url2im/go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/url2im/go.mod b/tools/url2im/go.mod index 236af91c7e..b6011909db 100644 --- a/tools/url2im/go.mod +++ b/tools/url2im/go.mod @@ -15,6 +15,6 @@ require ( golang.org/x/sys v0.13.0 // indirect golang.org/x/text v0.13.0 // indirect google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect - google.golang.org/grpc v1.56.2 // indirect + google.golang.org/grpc v1.56.3 // indirect google.golang.org/protobuf v1.31.0 // indirect ) diff --git a/tools/url2im/go.sum b/tools/url2im/go.sum index 071d9c3aa1..1970dce2c7 100644 --- a/tools/url2im/go.sum +++ b/tools/url2im/go.sum @@ -24,8 +24,8 @@ golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 h1:KpwkzHKEF7B9Zxg18WzOa7djJ+Ha5DzthMyZYQfEn2A= google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU= -google.golang.org/grpc v1.56.2 h1:fVRFRnXvU+x6C4IlHZewvJOVHoOv1TUuQyoRsYnB4bI= -google.golang.org/grpc v1.56.2/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s= +google.golang.org/grpc v1.56.3 h1:8I4C0Yq1EjstUzUJzpcRVbuYA2mODtEmpWiQoN/b2nc= +google.golang.org/grpc v1.56.3/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= From 32cd79044bbdd00ff28eea1272ea46c9c528038f Mon Sep 17 00:00:00 2001 From: Brabem <69128477+luhaoling@users.noreply.github.com> Date: Mon, 29 Jan 2024 19:57:37 +0800 Subject: [PATCH 010/188] feat: del the manager configure and it's initializestatement (#1830) * fix: del the manager config and manger init statement * fix: fix the Manger judge condition * fix: fix revokeMsg error * fix: find erors * fix: find error * fix: fix the AdminAccount error * fix: del the debug statement --- deployments/templates/config.yaml | 7 ++++--- docs/contrib/environment.md | 6 ------ internal/push/push_to_client.go | 3 +++ internal/rpc/msg/revoke.go | 9 ++++++++- internal/rpc/msg/verify.go | 10 ++++++++-- internal/rpc/user/user.go | 6 ------ pkg/authverify/token.go | 11 +++++------ scripts/install/environment.sh | 6 ------ 8 files changed, 28 insertions(+), 30 deletions(-) diff --git a/deployments/templates/config.yaml b/deployments/templates/config.yaml index 82f76597c3..cc318adcde 100644 --- a/deployments/templates/config.yaml +++ b/deployments/templates/config.yaml @@ -243,9 +243,10 @@ push: # # Built-in app manager user IDs # Built-in app manager nicknames +# Attention, this configure is discarded. If you have used him before, configure your own manager: - userID: [ "${MANAGER_USERID_1}", "${MANAGER_USERID_2}", "${MANAGER_USERID_3}" ] - nickname: [ "${NICKNAME_1}", "${NICKNAME_2}", "${NICKNAME_3}" ] + userID: + nickname: # chatAdmin, use for send notification # @@ -329,7 +330,7 @@ callback: timeout: ${CALLBACK_TIMEOUT} failedContinue: ${CALLBACK_FAILED_CONTINUE} afterSendSingleMsg: - enable: true + enable: ${CALLBACK_ENABLE} timeout: ${CALLBACK_TIMEOUT} failedContinue: ${CALLBACK_FAILED_CONTINUE} beforeSendGroupMsg: diff --git a/docs/contrib/environment.md b/docs/contrib/environment.md index 366a1d94fc..fb696eb548 100644 --- a/docs/contrib/environment.md +++ b/docs/contrib/environment.md @@ -477,12 +477,6 @@ This section involves setting up additional configuration variables for Websocke | JPNS_MASTER_SECRET | [User Defined] | JPNS Master Secret | | JPNS_PUSH_URL | [User Defined] | JPNS Push Notification URL | | JPNS_PUSH_INTENT | [User Defined] | JPNS Push Intent | -| MANAGER_USERID_1 | "openIM123456" | Administrator ID 1 | -| MANAGER_USERID_2 | "openIM654321" | Administrator ID 2 | -| MANAGER_USERID_3 | "openIMAdmin" | Administrator ID 3 | -| NICKNAME_1 | "system1" | Nickname 1 | -| NICKNAME_2 | "system2" | Nickname 2 | -| NICKNAME_3 | "system3" | Nickname 3 | | IM_ADMIN_USERID | "imAdmin" | IM Administrator ID | | IM_ADMIN_NAME | "imAdmin" | IM Administrator Nickname | | MULTILOGIN_POLICY | "1" | Multi-login Policy | diff --git a/internal/push/push_to_client.go b/internal/push/push_to_client.go index caa39e6185..5fce34e83b 100644 --- a/internal/push/push_to_client.go +++ b/internal/push/push_to_client.go @@ -238,6 +238,9 @@ func (p *Pusher) Push2SuperGroup(ctx context.Context, groupID string, msg *sdkws if len(config.Config.Manager.UserID) > 0 { ctx = mcontext.WithOpUserIDContext(ctx, config.Config.Manager.UserID[0]) } + if len(config.Config.Manager.UserID) == 0 && len(config.Config.IMAdmin.UserID) > 0 { + ctx = mcontext.WithOpUserIDContext(ctx, config.Config.IMAdmin.UserID[0]) + } defer func(groupID string) { if err = p.groupRpcClient.DismissGroup(ctx, groupID); err != nil { log.ZError(ctx, "DismissGroup Notification clear members", err, "groupID", groupID) diff --git a/internal/rpc/msg/revoke.go b/internal/rpc/msg/revoke.go index d7362d3392..0a24753b2d 100644 --- a/internal/rpc/msg/revoke.go +++ b/internal/rpc/msg/revoke.go @@ -111,6 +111,13 @@ func (m *msgServer) RevokeMsg(ctx context.Context, req *msg.RevokeMsgReq) (*msg. return nil, err } revokerUserID := mcontext.GetOpUserID(ctx) + var flag bool + if len(config.Config.Manager.UserID) > 0 { + flag = utils.Contain(revokerUserID, config.Config.Manager.UserID...) + } + if len(config.Config.Manager.UserID) == 0 && len(config.Config.IMAdmin.UserID) > 0 { + flag = utils.Contain(revokerUserID, config.Config.IMAdmin.UserID...) + } tips := sdkws.RevokeMsgTips{ RevokerUserID: revokerUserID, ClientMsgID: msgs[0].ClientMsgID, @@ -118,7 +125,7 @@ func (m *msgServer) RevokeMsg(ctx context.Context, req *msg.RevokeMsgReq) (*msg. Seq: req.Seq, SesstionType: msgs[0].SessionType, ConversationID: req.ConversationID, - IsAdminRevoke: utils.Contain(revokerUserID, config.Config.Manager.UserID...), + IsAdminRevoke: flag, } var recvID string if msgs[0].SessionType == constant.SuperGroupChatType { diff --git a/internal/rpc/msg/verify.go b/internal/rpc/msg/verify.go index 2837cb944c..0080b6fdb8 100644 --- a/internal/rpc/msg/verify.go +++ b/internal/rpc/msg/verify.go @@ -51,7 +51,10 @@ type MessageRevoked struct { func (m *msgServer) messageVerification(ctx context.Context, data *msg.SendMsgReq) error { switch data.MsgData.SessionType { case constant.SingleChatType: - if utils.IsContain(data.MsgData.SendID, config.Config.Manager.UserID) { + if len(config.Config.Manager.UserID) > 0 && utils.IsContain(data.MsgData.SendID, config.Config.Manager.UserID) { + return nil + } + if utils.IsContain(data.MsgData.SendID, config.Config.IMAdmin.UserID) { return nil } if data.MsgData.ContentType <= constant.NotificationEnd && @@ -88,7 +91,10 @@ func (m *msgServer) messageVerification(ctx context.Context, data *msg.SendMsgRe if groupInfo.GroupType == constant.SuperGroup { return nil } - if utils.IsContain(data.MsgData.SendID, config.Config.Manager.UserID) { + if len(config.Config.Manager.UserID) > 0 && utils.IsContain(data.MsgData.SendID, config.Config.Manager.UserID) { + return nil + } + if utils.IsContain(data.MsgData.SendID, config.Config.IMAdmin.UserID) { return nil } if data.MsgData.ContentType <= constant.NotificationEnd && diff --git a/internal/rpc/user/user.go b/internal/rpc/user/user.go index 0be5f97f48..e5567f436b 100644 --- a/internal/rpc/user/user.go +++ b/internal/rpc/user/user.go @@ -71,12 +71,6 @@ func Start(client registry.SvcDiscoveryRegistry, server *grpc.Server) error { return err } users := make([]*tablerelation.UserModel, 0) - if len(config.Config.Manager.UserID) != len(config.Config.Manager.Nickname) { - return errors.New("len(config.Config.Manager.AppManagerUid) != len(config.Config.Manager.Nickname)") - } - for k, v := range config.Config.Manager.UserID { - users = append(users, &tablerelation.UserModel{UserID: v, Nickname: config.Config.Manager.Nickname[k], AppMangerLevel: constant.AppAdmin}) - } if len(config.Config.IMAdmin.UserID) != len(config.Config.IMAdmin.Nickname) { return errors.New("len(config.Config.AppNotificationAdmin.AppManagerUid) != len(config.Config.AppNotificationAdmin.Nickname)") } diff --git a/pkg/authverify/token.go b/pkg/authverify/token.go index 4c71224eec..224693f858 100644 --- a/pkg/authverify/token.go +++ b/pkg/authverify/token.go @@ -17,7 +17,6 @@ package authverify import ( "context" "fmt" - "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/mcontext" "github.com/OpenIMSDK/tools/tokenverify" @@ -35,7 +34,7 @@ func Secret() jwt.Keyfunc { func CheckAccessV3(ctx context.Context, ownerUserID string) (err error) { opUserID := mcontext.GetOpUserID(ctx) - if utils.IsContain(opUserID, config.Config.Manager.UserID) { + if len(config.Config.Manager.UserID) > 0 && utils.IsContain(opUserID, config.Config.Manager.UserID) { return nil } if utils.IsContain(opUserID, config.Config.IMAdmin.UserID) { @@ -48,11 +47,11 @@ func CheckAccessV3(ctx context.Context, ownerUserID string) (err error) { } func IsAppManagerUid(ctx context.Context) bool { - return utils.IsContain(mcontext.GetOpUserID(ctx), config.Config.Manager.UserID) || utils.IsContain(mcontext.GetOpUserID(ctx), config.Config.IMAdmin.UserID) + return (len(config.Config.Manager.UserID) > 0 && utils.IsContain(mcontext.GetOpUserID(ctx), config.Config.Manager.UserID)) || utils.IsContain(mcontext.GetOpUserID(ctx), config.Config.IMAdmin.UserID) } func CheckAdmin(ctx context.Context) error { - if utils.IsContain(mcontext.GetOpUserID(ctx), config.Config.Manager.UserID) { + if len(config.Config.Manager.UserID) > 0 && utils.IsContain(mcontext.GetOpUserID(ctx), config.Config.Manager.UserID) { return nil } if utils.IsContain(mcontext.GetOpUserID(ctx), config.Config.IMAdmin.UserID) { @@ -64,7 +63,7 @@ func CheckIMAdmin(ctx context.Context) error { if utils.IsContain(mcontext.GetOpUserID(ctx), config.Config.IMAdmin.UserID) { return nil } - if utils.IsContain(mcontext.GetOpUserID(ctx), config.Config.Manager.UserID) { + if len(config.Config.Manager.UserID) > 0 && utils.IsContain(mcontext.GetOpUserID(ctx), config.Config.Manager.UserID) { return nil } return errs.ErrNoPermission.Wrap(fmt.Sprintf("user %s is not CheckIMAdmin userID", mcontext.GetOpUserID(ctx))) @@ -75,7 +74,7 @@ func ParseRedisInterfaceToken(redisToken any) (*tokenverify.Claims, error) { } func IsManagerUserID(opUserID string) bool { - return utils.IsContain(opUserID, config.Config.Manager.UserID) || utils.IsContain(opUserID, config.Config.IMAdmin.UserID) + return (len(config.Config.Manager.UserID) > 0 && utils.IsContain(opUserID, config.Config.Manager.UserID)) || utils.IsContain(opUserID, config.Config.IMAdmin.UserID) } func WsVerifyToken(token, userID string, platformID int) error { diff --git a/scripts/install/environment.sh b/scripts/install/environment.sh index aeb4fcc364..b1d2354b94 100755 --- a/scripts/install/environment.sh +++ b/scripts/install/environment.sh @@ -349,12 +349,6 @@ def "JPNS_APP_KEY" "" # JPNS应用密钥 def "JPNS_MASTER_SECRET" "" # JPNS主密钥 def "JPNS_PUSH_URL" "" # JPNS推送URL def "JPNS_PUSH_INTENT" "" # JPNS推送意图 -def "MANAGER_USERID_1" "openIM123456" # 管理员ID 1 -def "MANAGER_USERID_2" "openIM654321" # 管理员ID 2 -def "MANAGER_USERID_3" "openIMAdmin" # 管理员ID 3 -def "NICKNAME_1" "system1" # 昵称1 -def "NICKNAME_2" "system2" # 昵称2 -def "NICKNAME_3" "system3" # 昵称3 def "IM_ADMIN_USERID" "imAdmin" # IM管理员ID def "IM_ADMIN_NAME" "imAdmin" # IM管理员昵称 def "MULTILOGIN_POLICY" "1" # 多登录策略 From bd9e50d9e08edc9d6a87fa8c443cf8f0bf825117 Mon Sep 17 00:00:00 2001 From: Xinwei Xiong <3293172751NSS@gmail.com> Date: Mon, 29 Jan 2024 19:58:19 +0800 Subject: [PATCH 011/188] fix(docker-compose): Update the env template to uncomment the mongo port (#1833) --- deployments/templates/env-template.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deployments/templates/env-template.yaml b/deployments/templates/env-template.yaml index 9b21c8c657..1044dd6bcc 100644 --- a/deployments/templates/env-template.yaml +++ b/deployments/templates/env-template.yaml @@ -100,7 +100,7 @@ ZOOKEEPER_PORT=${ZOOKEEPER_PORT} # MongoDB service port configuration. # Default: MONGO_PORT=37017 -# MONGO_PORT=${MONGO_PORT} +MONGO_PORT=${MONGO_PORT} # Password for MongoDB admin user. Used for service authentication. # Default: MONGO_PASSWORD=openIM123 From 0a245df2f8cf60f5fd0767c840dc66399a668f33 Mon Sep 17 00:00:00 2001 From: OpenIM Bot <124379614+kubbot@users.noreply.github.com> Date: Wed, 31 Jan 2024 14:14:03 +0800 Subject: [PATCH 012/188] cicd: bump League Patch (#1837) --- pkg/authverify/token.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pkg/authverify/token.go b/pkg/authverify/token.go index 224693f858..97bb033916 100644 --- a/pkg/authverify/token.go +++ b/pkg/authverify/token.go @@ -17,6 +17,7 @@ package authverify import ( "context" "fmt" + "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/mcontext" "github.com/OpenIMSDK/tools/tokenverify" @@ -47,7 +48,8 @@ func CheckAccessV3(ctx context.Context, ownerUserID string) (err error) { } func IsAppManagerUid(ctx context.Context) bool { - return (len(config.Config.Manager.UserID) > 0 && utils.IsContain(mcontext.GetOpUserID(ctx), config.Config.Manager.UserID)) || utils.IsContain(mcontext.GetOpUserID(ctx), config.Config.IMAdmin.UserID) + return (len(config.Config.Manager.UserID) > 0 && utils.IsContain(mcontext.GetOpUserID(ctx), config.Config.Manager.UserID)) || + utils.IsContain(mcontext.GetOpUserID(ctx), config.Config.IMAdmin.UserID) } func CheckAdmin(ctx context.Context) error { From 4ded2cffed2bd3abfb29e777e048c628d569294f Mon Sep 17 00:00:00 2001 From: Xinwei Xiong <3293172751NSS@gmail.com> Date: Wed, 31 Jan 2024 14:16:09 +0800 Subject: [PATCH 013/188] Delete build/images/openim-rpc-extend-msg directory (#1841) --- build/images/openim-rpc-extend-msg/Dockerfile | 45 ------------------- 1 file changed, 45 deletions(-) delete mode 100644 build/images/openim-rpc-extend-msg/Dockerfile diff --git a/build/images/openim-rpc-extend-msg/Dockerfile b/build/images/openim-rpc-extend-msg/Dockerfile deleted file mode 100644 index 3ed94019b7..0000000000 --- a/build/images/openim-rpc-extend-msg/Dockerfile +++ /dev/null @@ -1,45 +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. - -# OpenIM base image: https://github.com/openim-sigs/openim-base-image - -# Set go mod installation source and proxy - -FROM golang:1.20 AS builder - -ARG GO111MODULE=on -ARG GOPROXY=https://goproxy.cn,direct - -WORKDIR /openim/openim-server - -ENV GO111MODULE=$GO111MODULE -ENV GOPROXY=$GOPROXY - -COPY go.mod go.sum ./ -RUN go mod download - -COPY . . - -RUN make build BINS=openim-rpc-extend-msg - -RUN cp /openim/openim-server/_output/bin/platforms/$(go env GOOS)/$(go env GOARCH)/openim-rpc-extend-msg /usr/bin/openim-rpc-extend-msg - -# FROM ghcr.io/openim-sigs/openim-bash-image:latest -FROM ghcr.io/openim-sigs/openim-bash-image:latest - -WORKDIR /openim/openim-server - -COPY --from=builder /usr/bin/openim-rpc-extend-msg ./bin/openim-rpc-extend-msg - -ENTRYPOINT ["./bin/openim-rpc-extend-msg"] \ No newline at end of file From 18047859b8f46098b79189d04888845d12202ca1 Mon Sep 17 00:00:00 2001 From: Xinwei Xiong <3293172751NSS@gmail.com> Date: Wed, 31 Jan 2024 14:16:19 +0800 Subject: [PATCH 014/188] Delete build/images/openim-rpc-encryption directory (#1842) --- build/images/openim-rpc-encryption/Dockerfile | 45 ------------------- 1 file changed, 45 deletions(-) delete mode 100644 build/images/openim-rpc-encryption/Dockerfile diff --git a/build/images/openim-rpc-encryption/Dockerfile b/build/images/openim-rpc-encryption/Dockerfile deleted file mode 100644 index e3f232eaf0..0000000000 --- a/build/images/openim-rpc-encryption/Dockerfile +++ /dev/null @@ -1,45 +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. - -# OpenIM base image: https://github.com/openim-sigs/openim-base-image - -# Set go mod installation source and proxy - -FROM golang:1.20 AS builder - -ARG GO111MODULE=on -ARG GOPROXY=https://goproxy.cn,direct - -WORKDIR /openim/openim-server - -ENV GO111MODULE=$GO111MODULE -ENV GOPROXY=$GOPROXY - -COPY go.mod go.sum ./ -RUN go mod download - -COPY . . - -RUN make build BINS=openim-rpc-encryption - -RUN cp /openim/openim-server/_output/bin/platforms/$(go env GOOS)/$(go env GOARCH)/openim-rpc-encryption /usr/bin/openim-rpc-encryption - -# FROM ghcr.io/openim-sigs/openim-bash-image:latest -FROM ghcr.io/openim-sigs/openim-bash-image:latest - -WORKDIR /openim/openim-server - -COPY --from=builder /usr/bin/openim-rpc-encryption ./bin/openim-rpc-encryption - -ENTRYPOINT ["./bin/openim-rpc-encryption"] \ No newline at end of file From c205013436b219c0ec629aec425bee23d10bce2f Mon Sep 17 00:00:00 2001 From: Xinwei Xiong <3293172751NSS@gmail.com> Date: Wed, 31 Jan 2024 14:16:32 +0800 Subject: [PATCH 015/188] Update offline-deployment.md openim offine deployment docs (#1843) --- docs/contrib/offline-deployment.md | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/docs/contrib/offline-deployment.md b/docs/contrib/offline-deployment.md index a96f82d4a6..5e44318c49 100644 --- a/docs/contrib/offline-deployment.md +++ b/docs/contrib/offline-deployment.md @@ -1,5 +1,3 @@ - - # OpenIM Offline Deployment Design ## 1. Base Images @@ -10,7 +8,7 @@ Below are the base images and their versions you'll need: - [ ] redis:7.0.0 - [ ] mongo:6.0.2 - [ ] bitnami/zookeeper:3.8 -- [ ] minio/minio:latest +- [ ] minio/minio:RELEASE.2024-01-11T07-46-16Z > [!IMPORTANT] > It is important to note that OpenIM removed mysql components from versions v3.5.0 (release-v3.5) and above, so mysql can be deployed without this requirement or above @@ -22,10 +20,10 @@ OpenIM: > [!TIP] > If you need to install more IM components or monitoring products [images.md](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/images.md) -- [ ] ghcr.io/openimsdk/openim-web:latest -- [ ] ghcr.io/openimsdk/openim-admin:latest -- [ ] ghcr.io/openimsdk/openim-chat:latest -- [ ] ghcr.io/openimsdk/openim-server:latest +- [ ] ghcr.io/openimsdk/openim-web: +- [ ] ghcr.io/openimsdk/openim-admin: +- [ ] ghcr.io/openimsdk/openim-chat: +- [ ] ghcr.io/openimsdk/openim-server: Monitoring: @@ -42,9 +40,9 @@ Use the following commands to pull these base images: docker pull bitnami/kafka:3.5.1 docker pull redis:7.0.0 docker pull mongo:6.0.2 -docker pull mysql:5.7 +docker pull mariadb:10.6 docker pull bitnami/zookeeper:3.8 -docker pull minio/minio:latest +docker pull minio/minio:2024-01-11T07-46-16Z ``` If you need to install more IM components or monitoring products: @@ -177,4 +175,4 @@ docker compose ps # Verify - [openimsdk Issue #432](https://github.com/openimsdk/open-im-server/issues/432) - [Notion Link](https://nsddd.notion.site/435ee747c0bc44048da9300a2d745ad3?pvs=25) -- [openimsdk Issue #474](https://github.com/openimsdk/open-im-server/issues/474) \ No newline at end of file +- [openimsdk Issue #474](https://github.com/openimsdk/open-im-server/issues/474) From 42a3084a6f6dadc7097906b76d6d9cc7b4523c94 Mon Sep 17 00:00:00 2001 From: Xinwei Xiong <3293172751NSS@gmail.com> Date: Wed, 31 Jan 2024 17:58:24 +0800 Subject: [PATCH 016/188] Update environment.md fix environment mongo username (#1847) --- docs/contrib/environment.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/contrib/environment.md b/docs/contrib/environment.md index fb696eb548..e18246afad 100644 --- a/docs/contrib/environment.md +++ b/docs/contrib/environment.md @@ -311,7 +311,7 @@ This section involves setting up MongoDB, including its port, address, and crede | MONGO_ADDRESS | [Generated IP] | IP address for MongoDB. | | MONGO_USERNAME | [User Defined] | Admin Username for MongoDB. | | MONGO_PASSWORD | [User Defined] | Admin Password for MongoDB. | -| MONGO_OPENIM_PASSWORD | [User Defined] | OpenIM Username for MongoDB. | +| MONGO_OPENIM_USERNAME | [User Defined] | OpenIM Username for MongoDB. | | MONGO_OPENIM_PASSWORD | [User Defined] | OpenIM Password for MongoDB. | ### 2.8. Tencent Cloud COS Configuration From 4c0121849d8240c471a1eb2a18e56d046ff506dd Mon Sep 17 00:00:00 2001 From: Seal Bell <495950007@qq.com> Date: Thu, 1 Feb 2024 09:38:21 +0800 Subject: [PATCH 017/188] docs:Add multi-language README.md in ./docs/ file (#1852) * Add Simplified Chinese README.md * Add Ukrainian README.md * Add Traditional Chinese README.md * Add Czech README.md * Add Hungarian README.md * Add spanish README.md * Add Persian README.md * Add French README.md * Add German README.md * Add Japanese README.md * Add Polish README.md * Add Indonesian README.md * Add Finnish README.md * Add Malayalam README.md * Add Dutch README.md * Add Italian README.md * Add Russian README.md * Added Brazilian Portuguese README.md * Add Esperanto README.md * Add Korean README.md * Add Vietnamese README.md * Add Arabic README.md * Add Danish README.md * Add Greek README.md * Add Turkish README.md --- docs/README_ar.md | 67 ++++++++++++++++++++++++++++++++++++++++++++ docs/README_cs.md | 67 ++++++++++++++++++++++++++++++++++++++++++++ docs/README_da.md | 67 ++++++++++++++++++++++++++++++++++++++++++++ docs/README_de.md | 66 +++++++++++++++++++++++++++++++++++++++++++ docs/README_el.md | 67 ++++++++++++++++++++++++++++++++++++++++++++ docs/README_eo.md | 67 ++++++++++++++++++++++++++++++++++++++++++++ docs/README_es.md | 67 ++++++++++++++++++++++++++++++++++++++++++++ docs/README_fa.md | 67 ++++++++++++++++++++++++++++++++++++++++++++ docs/README_fi.md | 67 ++++++++++++++++++++++++++++++++++++++++++++ docs/README_fr.md | 66 +++++++++++++++++++++++++++++++++++++++++++ docs/README_hu.md | 67 ++++++++++++++++++++++++++++++++++++++++++++ docs/README_id.md | 67 ++++++++++++++++++++++++++++++++++++++++++++ docs/README_it.md | 67 ++++++++++++++++++++++++++++++++++++++++++++ docs/README_ja.md | 67 ++++++++++++++++++++++++++++++++++++++++++++ docs/README_ko.md | 67 ++++++++++++++++++++++++++++++++++++++++++++ docs/README_ml.md | 67 ++++++++++++++++++++++++++++++++++++++++++++ docs/README_nl.md | 67 ++++++++++++++++++++++++++++++++++++++++++++ docs/README_pl.md | 67 ++++++++++++++++++++++++++++++++++++++++++++ docs/README_pt_BR.md | 67 ++++++++++++++++++++++++++++++++++++++++++++ docs/README_ru.md | 67 ++++++++++++++++++++++++++++++++++++++++++++ docs/README_tr.md | 67 ++++++++++++++++++++++++++++++++++++++++++++ docs/README_ua.md | 67 ++++++++++++++++++++++++++++++++++++++++++++ docs/README_vi.md | 67 ++++++++++++++++++++++++++++++++++++++++++++ docs/README_zh_CN.md | 67 ++++++++++++++++++++++++++++++++++++++++++++ docs/README_zh_TW.md | 67 ++++++++++++++++++++++++++++++++++++++++++++ 25 files changed, 1673 insertions(+) create mode 100644 docs/README_ar.md create mode 100644 docs/README_cs.md create mode 100644 docs/README_da.md create mode 100644 docs/README_de.md create mode 100644 docs/README_el.md create mode 100644 docs/README_eo.md create mode 100644 docs/README_es.md create mode 100644 docs/README_fa.md create mode 100644 docs/README_fi.md create mode 100644 docs/README_fr.md create mode 100644 docs/README_hu.md create mode 100644 docs/README_id.md create mode 100644 docs/README_it.md create mode 100644 docs/README_ja.md create mode 100644 docs/README_ko.md create mode 100644 docs/README_ml.md create mode 100644 docs/README_nl.md create mode 100644 docs/README_pl.md create mode 100644 docs/README_pt_BR.md create mode 100644 docs/README_ru.md create mode 100644 docs/README_tr.md create mode 100644 docs/README_ua.md create mode 100644 docs/README_vi.md create mode 100644 docs/README_zh_CN.md create mode 100644 docs/README_zh_TW.md diff --git a/docs/README_ar.md b/docs/README_ar.md new file mode 100644 index 0000000000..bdd616e6a6 --- /dev/null +++ b/docs/README_ar.md @@ -0,0 +1,67 @@ +# وثائق OpenIM Server + +مرحبًا بكم في مركز وثائق OpenIM! يوفر هذا المركز مجموعة شاملة من الأدلة والكتيبات التي صُممت لمساعدتك في الاستفادة القصوى من تجربة OpenIM الخاصة بك. + +## جدول المحتويات + +1. [Contrib](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib) - إرشادات حول المساهمة والتكوينات للمطورين +2. [Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib) - اتفاقيات الكود، سياسات التسجيل، وأدوات التحويل الأخرى + +------ + +## مساهمة + +هذا القسم يقدم للمطورين دليلاً مفصلاً حول كيفية المساهمة في الكود، إعداد بيئتهم، واتباع العمليات المرتبطة. + +- [Code Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/code-conventions.md) - قواعد واتفاقيات لكتابة الكود في OpenIM. +- [Development Guide](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/development.md) - دليل حول كيفية القيام بالتطوير داخل OpenIM. +- [Git Cherry Pick](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/gitcherry-pick.md) - إرشادات حول عمليات اختيار الجيت. +- [Git Workflow](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/git-workflow.md) - سير عمل الجيت في OpenIM. +- [Initialization Configurations](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/init-config.md) - إرشادات حول إعداد وتهيئة OpenIM. +- [Docker Installation](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/install-docker.md) - كيفية تثبيت الدوكر على جهازك. +- [Linux Development Environment](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/linux-development.md) - دليل لإعداد بيئة التطوير على لينكس. +- [Local Actions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/local-actions.md) - إرشادات حول كيفية القيام ببعض الأعمال الشائعة محليًا. +- [Offline Deployment](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/offline-deployment.md) - طرق توظيف OpenIM دون اتصال. +- [Protoc Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/protoc-tools.md) - دليل حول استخدام أدوات بروتوك. +- [Go Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-go.md) - أدوات ومكتبات في OpenIM للغة Go. +- [Makefile Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-makefile.md) - أفضل الممارسات والأدوات لملفات الصيانة. +- [Script Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-scripts.md) - أفضل الممارسات والأدوات للسكربتات. + +## التحويلات + +يقدم هذا القسم مختلف الاتفاقيات والسياسات داخل OpenIM، التي تشمل الكود، السجلات، الإصدارات، والمزيد. + +- [API Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/api.md) - إرشادات وطرق لتحويلات API. +- [Logging Policy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/bash-log.md) - سياسات واتفاقيات التسجيل في OpenIM. +- [CI/CD Actions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/cicd-actions.md) - إجراءات واتفاقيات لـ CI/CD. +- [Commit Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/commit.md) - اتفاقيات لالتزامات الكود في OpenIM. +- [Directory Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/directory.md) - هيكل الدليل واتفاقياته داخل OpenIM. +- [Error Codes](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/error-code.md) - قائمة وأوصاف رموز الخطأ. +- [Go Code Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/go-code.md) - اتفاقيات وتحويلات لكود Go. +- [Docker Image Strategy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/images.md) - استراتيجيات إدارة صور الدوكر في OpenIM، تشمل عدة معماريات ومستودعات الصور. +- [Logging Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/logging.md) - اتفاقيات أكثر تفصيلاً حول التسجيل. +- [Version Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/version.md) - استراتيجيات التسمية والإدارة لإصدارات OpenIM. + + +## للمطورين والمساهمين ومشرفي المجتمع + +### المطورون والمساهمون + +إذا كنت مطورًا أو شخصًا حريصًا على المساهمة: + +- تعرف على [Code Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/code-conventions.md) و[Git Workflow](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/git-workflow.md) لضمان سلاسة المساهمات. +- اغمر نفسك في [Development Guide](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/development.md) للتعرف على ممارسات التطوير في OpenIM. + +### مشرفو المجتمع + +كمشرف على المجتمع: + +- تأكد من أن المساهمات تتوافق مع المعايير الموضحة في وثائقنا. +- راجع بانتظام [Logging Policy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/bash-log.md) و[Error Codes](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/error-code.md) للبقاء على اطلاع. + +## للمستخدمين + +يجب أن يولي المستخدمون اهتمامًا خاصًا لـ: + +- [Docker Installation](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/install-docker.md) - ضروري إذا كنت تخطط لاستخدام صور الدوكر لـ OpenIM. +- [Docker Image Strategy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/images.md) - لفهم الصور المختلفة المتاحة وكيفية اختيار ال diff --git a/docs/README_cs.md b/docs/README_cs.md new file mode 100644 index 0000000000..0c40b63b11 --- /dev/null +++ b/docs/README_cs.md @@ -0,0 +1,67 @@ +# Dokumenty serveru OpenIM + +Vítejte v centru dokumentace OpenIM! Toto centrum poskytuje komplexní řadu průvodců a manuálů navržených tak, aby vám pomohly co nejlépe využít vaše zkušenosti s OpenIM. + +## Obsah + +1. [Contrib](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib) - Pokyny pro přispívání a konfigurace pro vývojáře +2. [Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib) - Konvence kódování, zásady protokolování a další transformační nástroje + +------ + +## Contrib + +Tato část nabízí vývojářům podrobný návod, jak přispívat kódem, nastavovat prostředí a sledovat související procesy. + +- [Code Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/code-conventions.md) - Pravidla a konvence pro psaní kódu v OpenIM. +- [Development Guide](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/development.md) - Návod, jak provádět vývoj v rámci OpenIM. +- [Git Cherry Pick](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/gitcherry-pick.md) - Pokyny pro operace sběru třešní. +- [Git Workflow](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/git-workflow.md) - Pracovní postup git v OpenIM. +- [Initialization Configurations](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/init-config.md) - Pokyny k nastavení a inicializaci OpenIM. +- [Docker Installation](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/install-docker.md) - Jak nainstalovat Docker na váš počítač. +- [Linux Development Environment](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/linux-development.md) - Průvodce nastavením vývojového prostředí na Linuxu. +- [Local Actions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/local-actions.md) - Pokyny k provádění určitých společných akcí na místní úrovni. +- [Offline Deployment](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/offline-deployment.md) - Metody nasazení OpenIM offline. +- [Protoc Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/protoc-tools.md) - Průvodce používáním protokolových nástrojů. +- [Go Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-go.md) - Nástroje a knihovny v OpenIM for Go. +- [Makefile Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-makefile.md) - Osvědčené postupy a nástroje pro Makefile. +- [Script Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-scripts.md) - Doporučené postupy a nástroje pro skripty. + +## Konverze + +Tato část představuje různé konvence a zásady v rámci OpenIM, zahrnující kód, protokoly, verze a další. + +- [API Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/api.md) - Pokyny a metody pro konverze API. +- [Logging Policy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/bash-log.md) - Zásady a konvence protokolování v OpenIM. +- [CI/CD Actions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/cicd-actions.md) - Postupy a konvence pro CI/CD. +- [Commit Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/commit.md) - Konvence pro odevzdání kódu v OpenIM. +- [Directory Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/directory.md) - Struktura adresářů a konvence v rámci OpenIM. +- [Error Codes](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/error-code.md) - Seznam a popisy chybových kódů. +- [Go Code Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/go-code.md) - Konvence a převody pro kód Go. +- [Docker Image Strategy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/images.md) - Strategie správy pro obrazy OpenIM Docker, zahrnující různé architektury a úložiště obrazů. +- [Logging Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/logging.md) - Další podrobné konvence o protokolování. +- [Version Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/version.md) - Strategie pojmenování a správy verzí OpenIM. + + +## Pro vývojáře, přispěvatele a správce komunity + +### Vývojáři a přispěvatelé + +Pokud jste vývojář nebo někdo, kdo má zájem přispívat: + +- Seznamte se s našimi [Code Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/code-conventions.md) a [Git Workflow](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/git-workflow.md), abyste zajistili hladké příspěvky. +- Ponořte se do [Development Guide](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/development.md), abyste se seznámili s vývojovými postupy v OpenIM. + +### Správci komunity + +Jako správce komunity: + +- Zajistěte, aby příspěvky odpovídaly standardům uvedeným v naší dokumentaci. +- Pravidelně kontrolujte [Logging Policy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/bash-log.md) a [Error Codes](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/error-code.md) , abyste zůstali aktuální. + +## Pro uživatele + +Uživatelé by měli věnovat zvláštní pozornost: + +- [Docker Installation](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/install-docker.md) - Nezbytné, pokud plánujete používat obrazy OpenIM Docker. +- [Docker Image Strategy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/images.md) - Chcete-li porozumět různým dostupným obrázkům a jak vybrat ten správný pro vaši architekturu. \ No newline at end of file diff --git a/docs/README_da.md b/docs/README_da.md new file mode 100644 index 0000000000..d14c6adb5d --- /dev/null +++ b/docs/README_da.md @@ -0,0 +1,67 @@ +# OpenIM Server Dokumentation + +Velkommen til OpenIM Dokumentationscentret! Dette center indeholder en omfattende række vejledninger og manualer, der er designet til at hjælpe dig med at få mest muligt ud af din OpenIM-oplevelse. + +## Indholdsfortegnelse + +1. [Contrib](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib) - Vejledning om bidrag og konfigurationer for udviklere +2. [Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib) - Kodningskonventioner, logningspolitikker og andre transformationsværktøjer + +------ + +## Bidrag + +Denne sektion tilbyder udviklere en detaljeret vejledning om, hvordan de kan bidrage med kode, konfigurere deres miljø og følge de tilknyttede processer. + +- [Kodekonventioner](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/code-conventions.md) - Regler og konventioner for at skrive kode i OpenIM. +- [Udviklingsguide](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/development.md) - En guide om, hvordan man udfører udvikling inden for OpenIM. +- [Git Cherry Pick](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/gitcherry-pick.md) - Retningslinjer for cherry-picking-operationer. +- [Git Workflow](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/git-workflow.md) - Git-workflowen i OpenIM. +- [Initialiseringskonfigurationer](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/init-config.md) - Vejledning om opsætning og initialisering af OpenIM. +- [Docker Installation](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/install-docker.md) - Sådan installeres Docker på din maskine. +- [Linux Udviklingsmiljø](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/linux-development.md) - Guide til opsætning af udviklingsmiljøet på Linux. +- [Lokale handlinger](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/local-actions.md) - Retningslinjer for, hvordan man udfører visse almindelige handlinger lokalt. +- [Offline-deploering](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/offline-deployment.md) - Metoder til at udrulle OpenIM offline. +- [Protoc-værktøjer](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/protoc-tools.md) - Guide til brug af protoc-værktøjer. +- [Go-værktøjer](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-go.md) - Værktøjer og biblioteker i OpenIM til Go. +- [Makefile-værktøjer](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-makefile.md) - Bedste praksis og værktøjer til Makefile. +- [Scriptværktøjer](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-scripts.md) - Bedste praksis og værktøjer til scripts. + +## Konverteringer + +Denne sektion introducerer forskellige konventioner og politikker inden for OpenIM, herunder kode, logfiler, versioner og meget mere. + +- [API-konverteringer](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/api.md) - Retningslinjer og metoder til API-konverteringer. +- [Logningspolitik](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/bash-log.md) - Politikker og konventioner for logning i OpenIM. +- [CI/CD-handlinger](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/cicd-actions.md) - Procedurer og konventioner for CI/CD. +- [Commit-konventioner](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/commit.md) - Konventioner for kodeforpligtelser i OpenIM. +- [Mappekonventioner](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/directory.md) - Mappens struktur og konventioner inden for OpenIM. +- [Fejlkoder](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/error-code.md) - Liste og beskrivelser af fejlkoder. +- [Go-kodekonverteringer](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/go-code.md) - Konventioner og konverteringer for Go-kode. +- [Docker Image-strategi](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/images.md) - Styringsstrategier for OpenIM Docker-billeder, der dækker flere arkitekturer og billedarkiver. +- [Logningskonventioner](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/logging.md) - Yderligere detaljerede konventioner om logning. +- [Versionkonventioner](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/version.md) - Navngivnings- og styringsstrategier for OpenIM-versioner. + + +## For udviklere, bidragsydere og samfundsvedligeholdere + +### Udviklere og bidragsydere + +Hvis du er en udvikler eller nogen, der gerne vil bidrage: + +- Gør dig fortrolig med vores [Kodekonventioner](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/code-conventions.md) og [Git Workflow](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/git-workflow.md) for at sikre en problemfri bidragelse. +- Dyk ned i [Udviklingsguiden](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/development.md) for at få en idé om udviklingspraksis i OpenIM. + +### Samfundsvedligeholdere + +Som samfundsvedligeholder: + +- Sørg for, at bidrag stemmer overens med standarderne beskrevet i vores dokumentation. +- Gennemgå regelmæssigt [Logningspolitikken](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/bash-log.md) og [Fejlkoderne](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/error-code.md) for at holde dig opdateret. + +## For brugere + +Brugere bør være opmærksomme på følgende: + +- [Docker Installation](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/install-docker.md) - Nødvendigt, hvis du planlægger at bruge Docker-billeder af OpenIM. +- [Docker Image-strategi](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/images.md) - For at forstå de forskellige tilgængelige billeder og hvordan man vælger det rigtige for din arkitektur. diff --git a/docs/README_de.md b/docs/README_de.md new file mode 100644 index 0000000000..101eba41b3 --- /dev/null +++ b/docs/README_de.md @@ -0,0 +1,66 @@ +# OpenIM-Serverdokumente + +Willkommen im OpenIM-Dokumentationshub! Dieses Zentrum bietet eine umfassende Auswahl an Leitfäden und Handbüchern, die Ihnen dabei helfen sollen, das Beste aus Ihrem OpenIM-Erlebnis herauszuholen. + +## Inhaltsverzeichnis + +1. [Contrib](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib) - Anleitung zu Beiträgen und Konfigurationen für Entwickler +2. [Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib) - Codierungskonventionen, Protokollierungsrichtlinien und andere Transformationstools + +------ + +## Beitrag + +Dieser Abschnitt bietet Entwicklern eine detaillierte Anleitung zum Beitragen von Code, zum Einrichten ihrer Umgebung und zum Befolgen der zugehörigen Prozesse. + +- [Code Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/code-conventions.md) - Regeln und Konventionen zum Schreiben von Code in OpenIM. +- [Development Guide](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/development.md) - Eine Anleitung zur Durchführung der Entwicklung innerhalb von OpenIM. +- [Git Cherry Pick](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/gitcherry-pick.md) - Richtlinien zur Rosinenpickerei. +- [Git Workflow](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/git-workflow.md) - Der Git-Workflow in OpenIM. +- [Initialization Configurations](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/init-config.md) - Anleitung zum Einrichten und Initialisieren von OpenIM. +- [Docker Installation](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/install-docker.md) - So installieren Sie Docker auf Ihrem Computer. +- [Linux Development Environment](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/linux-development.md) - Anleitung zum Einrichten der Entwicklungsumgebung unter Linux. +- [Local Actions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/local-actions.md) - Richtlinien zur Durchführung bestimmter allgemeiner Aktionen vor Ort. +- [Offline Deployment](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/offline-deployment.md) - Methoden zur Offline-Bereitstellung von OpenIM. +- [Protoc Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/protoc-tools.md) - Anleitung zur Verwendung von Protokolltools. +- [Go Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-go.md) - Tools und Bibliotheken in OpenIM für Go. +- [Makefile Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-makefile.md) - Best Practices und Tools für Makefile. +- [Script Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-scripts.md) - Best Practices und Tools für Skripte. + +## Konvertierungen + +In diesem Abschnitt werden verschiedene Konventionen und Richtlinien innerhalb von OpenIM vorgestellt, die Code, Protokolle, Versionen und mehr umfassen. + +- [API Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/api.md) - Richtlinien und Methoden für API-Konvertierungen. +- [Logging Policy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/bash-log.md) - Protokollierungsrichtlinien und -konventionen in OpenIM. +- [CI/CD Actions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/cicd-actions.md) - Verfahren und Konventionen für CI/CD. +- [Commit Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/commit.md) - Konventionen für Code-Commits in OpenIM. +- [Directory Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/directory.md) - Verzeichnisstruktur und Konventionen innerhalb von OpenIM. +- [Error Codes](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/error-code.md) - Liste und Beschreibungen der Fehlercodes. +- [Go Code Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/go-code.md) - Konventionen und Konvertierungen für Go-Code. +- [Docker Image Strategy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/images.md) - Verwaltungsstrategien für OpenIM-Docker-Images, die mehrere Architekturen und Image-Repositorys umfassen. +- [Logging Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/logging.md) - Weitere detaillierte Konventionen zur Protokollierung. +- [Version Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/version.md) - Benennungs- und Verwaltungsstrategien für OpenIM-Versionen. + + +## Für Entwickler, Mitwirkende und Community-Betreuer + +### Entwickler und Mitwirkende + +Wenn Sie Entwickler sind oder gerne einen Beitrag leisten möchten: +- Machen Sie sich mit unseren [Code Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/code-conventions.md) und unserem [Git Workflow](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/git-workflow.md) vertraut, um reibungslose Beiträge zu gewährleisten. +- Tauchen Sie ein in den [Development Guide](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/development.md), um sich mit den Entwicklungspraktiken in OpenIM vertraut zu machen. + +### Community-Betreuer + +Als Community-Betreuer: + +- Stellen Sie sicher, dass die Beiträge den in unserer Dokumentation dargelegten Standards entsprechen. +- Überprüfen Sie regelmäßig die [Logging Policy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/bash-log.md) und die [Error Codes](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/error-code.md), um auf dem Laufenden zu bleiben. + +## Für Benutzer + +Benutzer sollten besonders auf Folgendes achten: + +- [Docker Installation](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/install-docker.md) - Erforderlich, wenn Sie Docker-Images von OpenIM verwenden möchten. +- [Docker Image Strategy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/images.md) - Um die verschiedenen verfügbaren Bilder zu verstehen und wie Sie das richtige für Ihre Architektur auswählen. \ No newline at end of file diff --git a/docs/README_el.md b/docs/README_el.md new file mode 100644 index 0000000000..68438628fd --- /dev/null +++ b/docs/README_el.md @@ -0,0 +1,67 @@ +# Έγγραφα διακομιστή OpenIM + +Καλώς ήρθατε στο κέντρο τεκμηρίωσης OpenIM! Αυτό το κέντρο παρέχει μια ολοκληρωμένη σειρά οδηγών και εγχειριδίων που έχουν σχεδιαστεί για να σας βοηθήσουν να αξιοποιήσετε στο έπακρο την εμπειρία σας στο OpenIM. + +## Πίνακας περιεχομένων + +1. [Contrib](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib) - Οδηγίες για τη συνεισφορά και τις διαμορφώσεις για προγραμματιστές +2. [Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib) - Συμβάσεις κωδικοποίησης, πολιτικές καταγραφής και άλλα εργαλεία μετασχηματισμού + +------ + +## Συνεισφορά + +Αυτή η ενότητα προσφέρει στους προγραμματιστές έναν λεπτομερή οδηγό για το πώς να συνεισφέρουν κώδικα, να ρυθμίσουν το περιβάλλον τους και να ακολουθήσουν τις σχετικές διαδικασίες. + +- [Code Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/code-conventions.md) - Κανόνες και συμβάσεις για τη σύνταξη κώδικα στο OpenIM. +- [Development Guide](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/development.md) - Ένας οδηγός για το πώς να πραγματοποιήσετε ανάπτυξη στο OpenIM. +- [Git Cherry Pick](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/gitcherry-pick.md) - Οδηγίες για τις εργασίες συλλογής κερασιών. +- [Git Workflow](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/git-workflow.md) - Η ροή εργασίας git στο OpenIM. +- [Initialization Configurations](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/init-config.md) - Οδηγίες για τη ρύθμιση και την προετοιμασία του OpenIM. +- [Docker Installation](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/install-docker.md) - Πώς να εγκαταστήσετε το Docker στο μηχάνημά σας. +- [Linux Development Environment](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/linux-development.md) - Οδηγός για τη ρύθμιση του περιβάλλοντος ανάπτυξης στο Linux. +- [Local Actions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/local-actions.md) - Οδηγίες για τον τρόπο εκτέλεσης ορισμένων κοινών ενεργειών σε τοπικό επίπεδο. +- [Offline Deployment](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/offline-deployment.md) - Μέθοδοι ανάπτυξης OpenIM εκτός σύνδεσης. +- [Protoc Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/protoc-tools.md) - Οδηγός χρήσης εργαλείων πρωτοκόλλου. +- [Go Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-go.md) - Εργαλεία και βιβλιοθήκες στο OpenIM for Go. +- [Makefile Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-makefile.md) - Βέλτιστες πρακτικές και εργαλεία για το Makefile. +- [Script Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-scripts.md) - Βέλτιστες πρακτικές και εργαλεία για σενάρια. + +## Μετατροπές + +Αυτή η ενότητα εισάγει διάφορες συμβάσεις και πολιτικές στο OpenIM, που περιλαμβάνουν κώδικα, αρχεία καταγραφής, εκδόσεις και άλλα. + +- [API Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/api.md) - Οδηγίες και μέθοδοι για μετατροπές API. +- [Logging Policy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/bash-log.md) - Πολιτικές και συμβάσεις καταγραφής στο OpenIM. +- [CI/CD Actions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/cicd-actions.md) - Διαδικασίες και συμβάσεις για CI/CD. +- [Commit Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/commit.md) - Συμβάσεις για δεσμεύσεις κώδικα στο OpenIM. +- [Directory Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/directory.md) - Δομή καταλόγου και συμβάσεις στο OpenIM. +- [Error Codes](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/error-code.md) - Λίστα και περιγραφές κωδικών σφαλμάτων. +- [Go Code Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/go-code.md) - Συμβάσεις και μετατροπές για τον κώδικα Go. +- [Docker Image Strategy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/images.md) - Στρατηγικές διαχείρισης για εικόνες OpenIM Docker, που εκτείνονται σε πολλαπλές αρχιτεκτονικές και αποθετήρια εικόνων. +- [Logging Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/logging.md) - Περαιτέρω λεπτομερείς συμβάσεις για την υλοτομία. +- [Version Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/version.md) - Στρατηγικές ονομασίας και διαχείρισης για εκδόσεις OpenIM. + + +## Για προγραμματιστές, συνεισφέροντες και συντηρητές κοινότητας + +### Προγραμματιστές & Συνεισφέροντες + +Εάν είστε προγραμματιστής ή κάποιος που επιθυμεί να συνεισφέρει: + +- Εξοικειωθείτε με τις [Code Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/code-conventions.md) και [Git Workflow](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/git-workflow.md) για να εξασφαλίσετε ομαλή συνεισφορά. +- Βουτήξτε στον [Development Guide](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/development.md) για να δείτε τις πρακτικές ανάπτυξης στο OpenIM. + +### Συντηρητές της Κοινότητας + +Ως συντηρητής κοινότητας: + +- Βεβαιωθείτε ότι οι συνεισφορές ευθυγραμμίζονται με τα πρότυπα που περιγράφονται στην τεκμηρίωσή μας. +- Να ελέγχετε τακτικά την [Logging Policy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/bash-log.md) και τους [Error Codes](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/error-code.md) για να ενημερώνεστε. + +## Για Χρήστες + +Οι χρήστες θα πρέπει να δώσουν ιδιαίτερη προσοχή: + +- [Docker Installation](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/install-docker.md) - Απαραίτητο εάν σκοπεύετε να χρησιμοποιήσετε εικόνες Docker του OpenIM. +- [Docker Image Strategy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/images.md) - Για να κατανοήσετε τις διάφορες διαθέσιμες εικόνες και πώς να επιλέξετε τη σωστή για την αρχιτεκτονική σας. \ No newline at end of file diff --git a/docs/README_eo.md b/docs/README_eo.md new file mode 100644 index 0000000000..d7ae8c08cb --- /dev/null +++ b/docs/README_eo.md @@ -0,0 +1,67 @@ +# OpenIM Server Docs + +Bonvenon al la OpenIM Dokumenta nabo! Ĉi tiu centro disponigas ampleksan gamon da gvidiloj kaj manlibroj desegnitaj por helpi vin eltiri la plej grandan parton de via OpenIM-sperto. + +## Enhavtabelo + +1. [Contrib](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib) - Gvidilo pri kontribuado kaj agordoj por programistoj +2. [Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib) - Kodigaj konvencioj, registradaj politikoj kaj aliaj transformaj iloj + +------ + +## Kontribui + +Ĉi tiu sekcio ofertas al programistoj detalan gvidilon pri kiel kontribui kodon, agordi sian medion kaj sekvi la rilatajn procezojn. + +- [Code Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/code-conventions.md) - Reguloj kaj konvencioj por skribi kodon en OpenIM. +- [Development Guide](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/development.md) - Gvidilo pri kiel efektivigi disvolviĝon ene de OpenIM. +- [Git Cherry Pick](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/gitcherry-pick.md) - Gvidlinioj pri ĉeriz-plukaj operacioj. +- [Git Workflow](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/git-workflow.md) - La git-laborfluo en OpenIM. +- [Initialization Configurations](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/init-config.md) - Gvidilo pri agordo kaj pravalorigo de OpenIM. +- [Docker Installation](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/install-docker.md) - Kiel instali Docker sur via maŝino. +- [Linux Development Environment](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/linux-development.md) - Gvidilo por agordi la evolumedion en Linukso. +- [Local Actions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/local-actions.md) - Gvidlinioj pri kiel efektivigi certajn komunajn agojn loke. +- [Offline Deployment](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/offline-deployment.md) - Metodoj por disfaldi OpenIM eksterrete. +- [Protoc Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/protoc-tools.md) - Gvidilo pri uzado de protokaj iloj. +- [Go Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-go.md) - Iloj kaj bibliotekoj en OpenIM for Go. +- [Makefile Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-makefile.md) - Plej bonaj praktikoj kaj iloj por Makefile. +- [Script Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-scripts.md) - Plej bonaj praktikoj kaj iloj por skriptoj. + +## Konvertiĝoj + +Ĉi tiu sekcio enkondukas diversajn konvenciojn kaj politikojn ene de OpenIM, ampleksante kodon, protokolojn, versiojn kaj pli. + +- [API Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/api.md) - Gvidlinioj kaj metodoj por API-konvertoj. +- [Logging Policy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/bash-log.md) - Registrado de politikoj kaj konvencioj en OpenIM. +- [CI/CD Actions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/cicd-actions.md) - Proceduroj kaj konvencioj por CI/CD. +- [Commit Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/commit.md) - Konvencioj por kodoj en OpenIM. +- [Directory Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/directory.md) - Dosierujo-strukturo kaj konvencioj ene de OpenIM. +- [Error Codes](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/error-code.md) - Listo kaj priskriboj de erarkodoj. +- [Go Code Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/go-code.md) - Konvencioj kaj konvertiĝoj por Go-kodo. +- [Docker Image Strategy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/images.md) - Administradstrategioj por OpenIM Docker-bildoj, ampleksante plurajn arkitekturojn kaj bilddeponejojn. +- [Logging Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/logging.md) - Pliaj detalaj konvencioj pri arbohakado. +- [Version Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/version.md) - Strategioj pri nomado kaj administrado por OpenIM-versioj. + + +## Por Programistoj, Kontribuantoj kaj Komunumaj Prizorgantoj + +### Programistoj kaj Kontribuantoj + +Se vi estas programisto aŭ iu fervora kontribui: + +- Familiariĝu kun niaj [Code Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/code-conventions.md) [Git Workflow](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/git-workflow.md) por certigi glatajn kontribuojn. +- Plonĝu en la[Development Guide](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/development.md) por ekkompreni la evolupraktikojn en OpenIM. + +### Komunumaj Prizorgantoj + +Kiel komunuma prizorganto: + +- Certigu, ke kontribuoj kongruas kun la normoj skizitaj en nia dokumentaro. +- Regule reviziu la [Logging Policy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/bash-log.md) kaj [Error Codes](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/error-code.md) por resti ĝisdatigita. + +## Por Uzantoj + +Uzantoj devas aparte atenti: + +- [Docker Installation](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/install-docker.md) - Necesas se vi planas uzi Docker-bildojn de OpenIM. +- [Docker Image Strategy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/images.md) - Por kompreni la malsamajn bildojn disponeblajn kaj kiel elekti la ĝustan por via arkitekturo. \ No newline at end of file diff --git a/docs/README_es.md b/docs/README_es.md new file mode 100644 index 0000000000..96523120ab --- /dev/null +++ b/docs/README_es.md @@ -0,0 +1,67 @@ +# Documentos del servidor OpenIM + +¡Bienvenido al centro de documentación de OpenIM! Este centro proporciona una amplia gama de guías y manuales diseñados para ayudarle a aprovechar al máximo su experiencia OpenIM. + +## Tabla de contenido + +1. [Contrib](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib) - Orientación sobre contribuciones y configuraciones para desarrolladores +2. [Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib) - Convenciones de codificación, políticas de registro y otras herramientas de transformación + +------ + +## Contribuir + +Esta sección ofrece a los desarrolladores una guía detallada sobre cómo contribuir con código, configurar su entorno y seguir los procesos asociados. + +- [Code Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/code-conventions.md) - Reglas y convenciones para escribir código en OpenIM. +- [Development Guide](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/development.md) - Una guía sobre cómo realizar el desarrollo dentro de OpenIM. +- [Git Cherry Pick](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/gitcherry-pick.md) - Directrices sobre operaciones de selección selectiva. +- [Git Workflow](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/git-workflow.md) - El flujo de trabajo de git en OpenIM. +- [Initialization Configurations](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/init-config.md) - Orientación sobre la configuración e inicialización de OpenIM. +- [Docker Installation](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/install-docker.md) - Cómo instalar Docker en su máquina. +- [Linux Development Environment](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/linux-development.md) - Guía para configurar el entorno de desarrollo en Linux. +- [Local Actions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/local-actions.md) - Lineamientos sobre cómo llevar a cabo determinadas acciones comunes a nivel local. +- [Offline Deployment](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/offline-deployment.md) - Métodos de implementación de OpenIM sin conexión. +- [Protoc Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/protoc-tools.md) - Guía sobre el uso de herramientas de protocolo. +- [Go Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-go.md) - Herramientas y bibliotecas en OpenIM for Go. +- [Makefile Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-makefile.md) - Mejores prácticas y herramientas para Makefile. +- [Script Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-scripts.md) - Mejores prácticas y herramientas para scripts. + +## Conversiones + +Esta sección presenta varias convenciones y políticas dentro de OpenIM, que abarcan código, registros, versiones y más. + +- [API Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/api.md) - Directrices y métodos para conversiones de API. +- [Logging Policy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/bash-log.md) - Políticas y convenciones de registro en OpenIM. +- [CI/CD Actions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/cicd-actions.md) - Procedimientos y convenciones para CI/CD. +- [Commit Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/commit.md) - Convenciones para confirmaciones de código en OpenIM. +- [Directory Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/directory.md) - Estructura de directorios y convenciones dentro de OpenIM. +- [Error Codes](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/error-code.md) - Lista y descripciones de códigos de error. +- [Go Code Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/go-code.md) - Convenciones y conversiones para código Go. +- [Docker Image Strategy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/images.md) - Estrategias de gestión para imágenes OpenIM Docker, que abarcan múltiples arquitecturas y repositorios de imágenes. +- [Logging Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/logging.md) - Convenciones más detalladas sobre el registro. +- [Version Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/version.md) - Estrategias de nomenclatura y gestión de versiones OpenIM. + + +## Para desarrolladores, contribuyentes y mantenedores de la comunidad + +### Desarrolladores y colaboradores + +Si eres desarrollador o alguien interesado en contribuir: + +- Familiarícese con nuestras [Code Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/code-conventions.md) y [Git Workflow](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/git-workflow.md) to ensure smooth contributions. +- Sumérgete en la [Development Guide](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/development.md) para familiarizarte con las prácticas de desarrollo en OpenIM. + +### Mantenedores de la comunidad + +Como mantenedor de la comunidad: + +- Asegúrese de que las contribuciones se alineen con los estándares descritos en nuestra documentación. +- Revise periódicamente la [Logging Policy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/bash-log.md) y los [Error Codes](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/error-code.md) para mantenerse actualizado. + +## Para usuarios + +Los usuarios deben prestar especial atención a: + +- [Docker Installation](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/install-docker.md) - Necesario si planea utilizar imágenes Docker de OpenIM. +- [Docker Image Strategy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/images.md) - Comprender las diferentes imágenes disponibles y cómo elegir la adecuada para su arquitectura. \ No newline at end of file diff --git a/docs/README_fa.md b/docs/README_fa.md new file mode 100644 index 0000000000..43056647a7 --- /dev/null +++ b/docs/README_fa.md @@ -0,0 +1,67 @@ +# اسناد سرور OpenIM + +به مرکز اسناد OpenIM خوش آمدید! این مرکز طیف گسترده ای از راهنماها و راهنماها را ارائه می دهد که به شما کمک می کند تا از تجربه OpenIM خود بیشترین بهره را ببرید. + +## فهرست مطالب + +1. [Contrib](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib) - راهنمایی در مورد مشارکت و تنظیمات برای توسعه دهندگان +2. [Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib) - کنوانسیون های کدگذاری، سیاست های ورود به سیستم و سایر ابزارهای تبدیل + +------ + +## مشارکت + +این بخش به توسعه دهندگان راهنمای دقیقی در مورد نحوه مشارکت کد، تنظیم محیط خود و پیروی از فرآیندهای مرتبط ارائه می دهد. + +- [Code Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/code-conventions.md) - قوانین و مقررات برای نوشتن کد در OpenIM. +- [Development Guide](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/development.md) - راهنمای نحوه انجام توسعه در OpenIM. +- [Git Cherry Pick](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/gitcherry-pick.md) - دستورالعمل عملیات چیدن گیلاس +- [Git Workflow](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/git-workflow.md) - گردش کار git در OpenIM. +- [Initialization Configurations](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/init-config.md) - راهنمایی در مورد راه اندازی و مقداردهی اولیه OpenIM. +- [Docker Installation](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/install-docker.md) - چگونه داکر را روی دستگاه خود نصب کنیم. +- [Linux Development Environment](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/linux-development.md) - راهنمای راه اندازی محیط توسعه در لینوکس. +- [Local Actions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/local-actions.md) - رهنمودهایی در مورد نحوه انجام برخی از اقدامات مشترک به صورت محلی. +- [Offline Deployment](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/offline-deployment.md) - روش های استقرار OpenIM به صورت آفلاین +- [Protoc Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/protoc-tools.md) - راهنمای استفاده از ابزار پروتک +- [Go Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-go.md) - ابزارها و کتابخانه ها در OpenIM for Go. +- [Makefile Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-makefile.md) - بهترین روش ها و ابزارها برای Makefile. +- [Script Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-scripts.md) - بهترین روش ها و ابزارها برای اسکریپت ها. + +## تبدیل ها + +این بخش قراردادها و سیاست‌های مختلفی را در OpenIM معرفی می‌کند که شامل کد، گزارش‌ها، نسخه‌ها و موارد دیگر می‌شود. + +- [API Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/api.md) - دستورالعمل ها و روش های تبدیل API. +- [Logging Policy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/bash-log.md) - سیاست‌های ورود به سیستم و قراردادها در OpenIM. +- [CI/CD Actions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/cicd-actions.md) - رویه ها و قراردادها برای CI/CD. +- [Commit Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/commit.md) - کنوانسیون‌ها برای تعهدات کد در OpenIM. +- [Directory Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/directory.md) - ساختار دایرکتوری و قراردادها در OpenIM. +- [Error Codes](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/error-code.md) - لیست و توضیحات کدهای خطا +- [Go Code Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/go-code.md) - کنوانسیون ها و تبدیل ها برای کد Go. +- [Docker Image Strategy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/images.md) - استراتژی های مدیریتی برای تصاویر OpenIM Docker، شامل چندین معماری و مخازن تصویر. +- [Logging Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/logging.md) - کنوانسیون های دقیق تر در مورد ورود به سیستم. +- [Version Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/version.md) - استراتژی های نامگذاری و مدیریت برای نسخه های OpenIM. + + +## برای توسعه‌دهندگان، مشارکت‌کنندگان و نگهبانان انجمن + +### توسعه دهندگان و مشارکت کنندگان + +اگر توسعه‌دهنده هستید یا کسی که مشتاق مشارکت است: + +- - برای اطمینان از مشارکت های روان، با [Code Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/code-conventions.md) و [Git Workflow](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/git-workflow.md) ما آشنا شوید. +- - در [Development Guide](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/development.md) شیرجه بزنید تا از شیوه های توسعه در OpenIM مطلع شوید. + +### نگهبانان جامعه + +به عنوان یک نگهدارنده جامعه: + +- اطمینان حاصل کنید که مشارکت ها با استانداردهای ذکر شده در اسناد ما مطابقت دارند. +- [Logging Policy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/bash-log.md) و [Error Codes](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/error-code.md) را به‌طور مرتب مرور کنید تا به‌روز بمانید. + +## برای کاربران + +کاربران باید توجه ویژه ای به موارد زیر داشته باشند: + +- [Docker Installation](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/install-docker.md) - اگر قصد دارید از تصاویر Docker OpenIM استفاده کنید، ضروری است. +- [Docker Image Strategy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/images.md) - برای درک تصاویر مختلف موجود و نحوه انتخاب تصویر مناسب برای معماری خود. \ No newline at end of file diff --git a/docs/README_fi.md b/docs/README_fi.md new file mode 100644 index 0000000000..9678763d97 --- /dev/null +++ b/docs/README_fi.md @@ -0,0 +1,67 @@ +# OpenIM Server Docs + +Tervetuloa OpenIM-dokumentaatiokeskukseen! Tämä keskus tarjoaa kattavan valikoiman oppaita ja oppaita, jotka on suunniteltu auttamaan sinua saamaan kaiken irti OpenIM-kokemuksestasi. + +## Sisällysluettelo + +1. [Contrib](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib) - Ohjeita kehittäjille osallistumiseen ja määrityksiin +2. [Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib) - Koodauskäytännöt, lokikäytännöt ja muut muunnostyökalut + +------ + +## Contrib + +Tämä osio tarjoaa kehittäjille yksityiskohtaisen oppaan koodin lisäämisestä, ympäristön määrittämisestä ja siihen liittyvien prosessien seuraamisesta. + +- [Code Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/code-conventions.md) - Säännöt ja käytännöt koodin kirjoittamiselle OpenIM:ssä. +- [Development Guide](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/development.md) - Opas kehitystyön toteuttamiseen OpenIM:ssä. +- [Git Cherry Pick](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/gitcherry-pick.md) - Kirsikoiden poimimista koskevat ohjeet. +- [Git Workflow](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/git-workflow.md) - Git-työnkulku OpenIM:ssä. +- [Initialization Configurations](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/init-config.md) - Ohjeita OpenIM:n käyttöönottoon ja alustamiseen. +- [Docker Installation](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/install-docker.md) - Kuinka asentaa Docker koneellesi. +- [Linux Development Environment](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/linux-development.md) - Ohje kehitysympäristön määrittämiseen Linuxissa. +- [Local Actions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/local-actions.md) - Ohjeita tiettyjen yhteisten toimien toteuttamiseen paikallisesti. +- [Offline Deployment](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/offline-deployment.md) - OpenIM:n offline-käyttöönottomenetelmät. +- [Protoc Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/protoc-tools.md) - Opas protokollatyökalujen käyttöön. +- [Go Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-go.md) - OpenIM for Go -työkalut ja kirjastot. +- [Makefile Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-makefile.md) - Makefilen parhaat käytännöt ja työkalut. +- [Script Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-scripts.md) - Skriptien parhaat käytännöt ja työkalut. + +## Tulokset + +Tässä osiossa esitellään erilaisia OpenIM:n käytäntöjä ja käytäntöjä, jotka kattavat koodin, lokit, versiot ja paljon muuta. + +- [API Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/api.md) - Ohjeita ja menetelmiä API-muunnoksille. +- [Logging Policy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/bash-log.md) - Kirjauskäytännöt ja käytännöt OpenIM:ssä. +- [CI/CD Actions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/cicd-actions.md) - CI/CD:n menettelyt ja käytännöt. +- [Commit Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/commit.md) - OpenIM:n koodisitoumusten käytännöt. +- [Directory Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/directory.md) - Hakemistorakenne ja käytännöt OpenIM:ssä. +- [Error Codes](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/error-code.md) - Luettelo ja kuvaukset virhekoodeista. +- [Go Code Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/go-code.md) - Go-koodin sopimukset ja muunnokset. +- [Docker Image Strategy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/images.md) - Hallintastrategiat OpenIM Docker -kuville, jotka kattavat useita arkkitehtuureja ja kuvavarastoja. +- [Logging Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/logging.md) - Tarkemmat hakkuiden käytännöt. +- [Version Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/version.md) - Nimeämis- ja hallintastrategiat OpenIM-versioille. + + +## Kehittäjille, avustajille ja yhteisön ylläpitäjille + +### Kehittäjät ja avustajat + +Jos olet kehittäjä tai joku, joka haluaa osallistua: + +- Tutustu [Code Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/code-conventions.md)- ja [Git Workflow](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/git-workflow.md) -käytäntöihimme varmistaaksesi sujuvan osallistumisen. +- Sukella [Development Guide](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/development.md) saadaksesi tietoa OpenIM:n kehityskäytännöistä. + +### Yhteisön ylläpitäjät + +Yhteisön ylläpitäjänä: + +- Varmista, että osallistumiset ovat asiakirjoissamme esitettyjen standardien mukaisia. +- Tarkista säännöllisesti [Logging Policy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/bash-log.md) ja [Error Codes](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/error-code.md) pysyäksesi ajan tasalla. + +## Käyttäjille + +Käyttäjien tulee kiinnittää erityistä huomiota: + +- [Docker Installation](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/install-docker.md) - Välttämätön, jos aiot käyttää OpenIM:n Docker-kuvia. +- [Docker Image Strategy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/images.md) - Ymmärtääksesi saatavilla olevat erilaiset kuvat ja kuinka valita oikea arkkitehtuuriisi. \ No newline at end of file diff --git a/docs/README_fr.md b/docs/README_fr.md new file mode 100644 index 0000000000..747ef5349b --- /dev/null +++ b/docs/README_fr.md @@ -0,0 +1,66 @@ +# Documentation du serveur OpenIM + +Bienvenue dans le hub de documentation OpenIM ! Ce centre propose une gamme complète de guides et de manuels conçus pour vous aider à tirer le meilleur parti de votre expérience OpenIM. + +## Table des matières + +1. [Contrib](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib) - Conseils sur la contribution et les configurations pour les développeurs +2. [Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib) - Conventions de codage, politiques de journalisation et autres outils de transformation + +------ + +## Contribuer + +Cette section propose aux développeurs un guide détaillé sur la façon de contribuer au code, de configurer leur environnement et de suivre les processus associés. + +- [Code Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/code-conventions.md) - Règles et conventions pour écrire du code dans OpenIM. +- [Development Guide](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/development.md) - Un guide sur la façon de réaliser du développement au sein d'OpenIM. +- [Git Cherry Pick](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/gitcherry-pick.md) - Lignes directrices sur les opérations de triage. +- [Git Workflow](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/git-workflow.md) - Le flux de travail git dans OpenIM. +- [Initialization Configurations](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/init-config.md) - Conseils sur la configuration et l’initialisation d’OpenIM. +- [Docker Installation](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/install-docker.md) - Comment installer Docker sur votre machine. +- [Linux Development Environment](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/linux-development.md) - Guide pour configurer l'environnement de développement sous Linux. +- [Local Actions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/local-actions.md) - Des lignes directrices pour mener localement certaines actions communes. +- [Offline Deployment](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/offline-deployment.md) - Méthodes de déploiement d'OpenIM hors ligne. +- [Protoc Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/protoc-tools.md) - Guide sur l'utilisation des outils de protocole. +- [Go Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-go.md) - Outils et bibliothèques dans OpenIM for Go. +- [Makefile Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-makefile.md) - Meilleures pratiques et outils pour Makefile. +- [Script Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-scripts.md) - Meilleures pratiques et outils pour les scripts. + +## Conversions + +Cette section présente diverses conventions et politiques au sein d'OpenIM, englobant le code, les journaux, les versions, etc. + +- [API Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/api.md) - Lignes directrices et méthodes pour les conversions API. +- [Logging Policy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/bash-log.md) - Politiques et conventions de journalisation dans OpenIM. +- [CI/CD Actions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/cicd-actions.md) - Politiques et conventions de journalisation dans OpenIM. +- [Commit Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/commit.md) - Politiques et conventions de journalisation dans OpenIM. +- [Directory Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/directory.md) - Structure de répertoire et conventions au sein d'OpenIM. +- [Error Codes](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/error-code.md) - Liste et descriptions des codes d'erreur. +- [Go Code Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/go-code.md) - Conventions et conversions pour le code Go. +- [Docker Image Strategy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/images.md) - Stratégies de gestion des images OpenIM Docker, couvrant plusieurs architectures et référentiels d'images. +- [Logging Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/logging.md) - Conventions plus détaillées sur la journalisation. +- [Version Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/version.md) - Stratégies de nommage et de gestion pour les versions OpenIM. + + +## Pour les développeurs, les contributeurs et les responsables de la communauté + +### Développeurs et contributeurs + +Si vous êtes un développeur ou quelqu'un désireux de contribuer : +- Familiarisez-vous avec nos [Code Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/code-conventions.md) et notre [Git Workflow](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/git-workflow.md) pour garantir des contributions fluides. +- Plongez dans le [Development Guide](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/development.md) pour vous familiariser avec les pratiques de développement dans OpenIM. + +### Responsables de la communauté + +En tant que responsable de la communauté : + +- EAssurez-vous que les contributions sont conformes aux normes décrites dans notre documentation. +- onsultez régulièrement la [Logging Policy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/bash-log.md) et les [Error Codes](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/error-code.md) pour rester à jour. + +## Pour les utilisateurs + +Les utilisateurs doivent prêter une attention particulière à : + +- [Docker Installation](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/install-docker.md) - Nécessaire si vous prévoyez d'utiliser des images Docker d'OpenIM. +- [Docker Image Strategy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/images.md) - Pour comprendre les différentes images disponibles et comment choisir celle qui convient à votre architecture. \ No newline at end of file diff --git a/docs/README_hu.md b/docs/README_hu.md new file mode 100644 index 0000000000..62cb54bb23 --- /dev/null +++ b/docs/README_hu.md @@ -0,0 +1,67 @@ +# OpenIM Server Docs + +Üdvözöljük az OpenIM dokumentációs központjában! Ez a központ útmutatók és kézikönyvek átfogó választékát kínálja, amelyek célja, hogy a legtöbbet hozza ki az OpenIM-élményből. + +## Tartalomjegyzék + +1. [Contrib](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib) - Útmutató a fejlesztőknek a hozzájáruláshoz és a konfigurációkhoz +2. [Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib) - Kódolási konvenciók, naplózási szabályzatok és egyéb átalakítási eszközök + +------ + +## Contrib + +Ez a rész részletes útmutatót nyújt a fejlesztőknek a kód hozzáadásával, a környezet beállításával és a kapcsolódó folyamatok követésével kapcsolatban. + +- [Code Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/code-conventions.md) - Az OpenIM kódírásának szabályai és konvenciói. +- [Development Guide](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/development.md) - Útmutató az OpenIM-en belüli fejlesztés végrehajtásához. +- [Git Cherry Pick](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/gitcherry-pick.md) - Útmutató a cseresznyeszedési műveletekhez. +- [Git Workflow](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/git-workflow.md) - A git munkafolyamat az OpenIM-ben. +- [Initialization Configurations](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/init-config.md) - Útmutató az OpenIM beállításához és inicializálásához. +- [Docker Installation](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/install-docker.md) - A Docker telepítése a gépére. +- [Linux Development Environment](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/linux-development.md) - Guide to set up the development environment on Linux. +- [Local Actions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/local-actions.md) - Útmutató a fejlesztői környezet beállításához Linuxon. +- [Offline Deployment](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/offline-deployment.md) - Az OpenIM offline üzembe helyezésének módszerei. +- [Protoc Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/protoc-tools.md) - Útmutató a protokolleszközök használatához. +- [Go Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-go.md) - Eszközök és könyvtárak az OpenIM for Go-ban. +- [Makefile Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-makefile.md) - A Makefile legjobb gyakorlatai és eszközei. +- [Script Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-scripts.md) - Bevált módszerek és eszközök a szkriptekhez. + +## Conversions + +Ez a rész az OpenIM különféle konvencióit és szabályzatait mutatja be, beleértve a kódot, a naplókat, a verziókat és egyebeket. + +- [API Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/api.md) - Irányelvek és módszerek az API-konverziókhoz. +- [Logging Policy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/bash-log.md) - Naplózási szabályzatok és konvenciók az OpenIM-ben. +- [CI/CD Actions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/cicd-actions.md) - CI/CD eljárások és konvenciók. +- [Commit Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/commit.md) - A kód véglegesítésének konvenciói az OpenIM-ben. +- [Directory Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/directory.md) - Címtárszerkezet és konvenciók az OpenIM-en belül. +- [Error Codes](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/error-code.md) - A hibakódok listája és leírása. +- [Go Code Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/go-code.md) - Konvenciók és átalakítások a Go kódhoz. +- [Docker Image Strategy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/images.md) - Kezelési stratégiák az OpenIM Docker-képekhez, amelyek több architektúrára és képtárra is kiterjednek. +- [Logging Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/logging.md) - További részletes egyezmények a fakitermelésről. +- [Version Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/version.md) - Elnevezési és kezelési stratégiák az OpenIM verziókhoz. + + +## Fejlesztőknek, közreműködőknek és közösségi fenntartóknak + +### Fejlesztők és közreműködők + +Ha Ön fejlesztő vagy valaki, aki szeretne hozzájárulni: + +- A zökkenőmentes hozzájárulás érdekében ismerkedjen meg [Code Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/code-conventions.md) és [Git Workflow](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/git-workflow.md)-val. +- Merüljön el a [Development Guide](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/development.md), hogy megismerje az OpenIM fejlesztési gyakorlatát. + +### Közösségfenntartók + +Közösségfenntartóként: + +- Győződjön meg arról, hogy a hozzájárulások megfelelnek a dokumentációnkban felvázolt szabványoknak. +- Rendszeresen tekintse át a [Logging Policy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/bash-log.md) és a [Error Codes](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/error-code.md), hogy naprakész maradjon. + +## Felhasználóknak + +A felhasználóknak különös figyelmet kell fordítaniuk a következőkre: + +- [Docker Installation](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/install-docker.md) - Szükséges, ha az OpenIM Docker-képeit szeretné használni. +- [Docker Image Strategy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/images.md) - Hogy megértse a rendelkezésre álló különböző képeket, és hogyan válassza ki a megfelelőt az építészetéhez. \ No newline at end of file diff --git a/docs/README_id.md b/docs/README_id.md new file mode 100644 index 0000000000..988e25efe9 --- /dev/null +++ b/docs/README_id.md @@ -0,0 +1,67 @@ +# Dokumen Server OpenIM + +Selamat datang di pusat Dokumentasi OpenIM! Pusat ini menyediakan berbagai panduan dan manual yang komprehensif untuk membantu Anda memaksimalkan pengalaman Anda dengan OpenIM. + +## Daftar Isi + +1. [Contrib](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib) - Panduan tentang kontribusi dan konfigurasi untuk pengembang +2. [Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib) - Konvensi pengkodean, kebijakan logging, dan alat transformasi lainnya + +------ + +## Contrib + +Bagian ini menawarkan panduan rinci bagi pengembang tentang cara berkontribusi kode, menyiapkan lingkungan mereka, dan mengikuti proses yang terkait. + +- [Code Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/code-conventions.md) - Aturan dan konvensi untuk menulis kode di OpenIM. +- [Development Guide](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/development.md) - Panduan tentang cara melakukan pengembangan di dalam OpenIM. +- [Git Cherry Pick](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/gitcherry-pick.md) - Pedoman tentang operasi cherry-picking. +- [Git Workflow](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/git-workflow.md) - Alur kerja git di OpenIM. +- [Initialization Configurations](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/init-config.md) - Panduan untuk mengatur dan menginisialisasi OpenIM. +- [Docker Installation](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/install-docker.md) - Cara memasang Docker di mesin Anda. +- [Linux Development Environment](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/linux-development.md) - Panduan untuk menyiapkan lingkungan pengembangan di Linux. +- [Local Actions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/local-actions.md) - Pedoman tentang cara melakukan beberapa tindakan umum secara lokal. +- [Offline Deployment](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/offline-deployment.md) - Metode penyebaran OpenIM secara offline. +- [Protoc Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/protoc-tools.md) - Panduan tentang menggunakan alat protoc. +- [Go Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-go.md) - Alat dan perpustakaan di OpenIM untuk Go. +- [Makefile Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-makefile.md) - Praktik terbaik dan alat untuk Makefile. +- [Script Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-scripts.md) - Praktik terbaik dan alat untuk skrip. + +## Conversions + +Bagian ini memperkenalkan berbagai konvensi dan kebijakan dalam OpenIM, meliputi kode, log, versi, dan lainnya. + +- [API Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/api.md) - Pedoman dan metode untuk konversi API. +- [Logging Policy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/bash-log.md) - Kebijakan dan konvensi logging di OpenIM. +- [CI/CD Actions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/cicd-actions.md) - Prosedur dan konvensi untuk CI/CD. +- [Commit Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/commit.md) - Konvensi untuk commit kode di OpenIM. +- [Directory Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/directory.md) - Struktur direktori dan konvensi dalam OpenIM. +- [Error Codes](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/error-code.md) - Daftar dan deskripsi kode kesalahan. +- [Go Code Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/go-code.md) - Konvensi dan konversi untuk kode Go. +- [Docker Image Strategy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/images.md) - Strategi manajemen gambar Docker OpenIM, mencakup berbagai arsitektur dan repositori gambar. +- [Logging Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/logging.md) - Konvensi logging yang lebih detail. +- [Version Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/version.md) - Strategi penamaan dan manajemen versi OpenIM. + + +## Untuk Pengembang, Kontributor, dan Pemelihara Komunitas + +### Pengembang & Kontributor + +Jika Anda seorang pengembang atau seseorang yang ingin berkontribusi: + +- Kenali [Code Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/code-conventions.md) dan [Git Workflow](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/git-workflow.md) kami untuk memastikan kontribusi yang lancar. +- Pelajari [Development Guide](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/development.md) untuk memahami praktik pengembangan di OpenIM. + +### Pemelihara Komunitas + +Sebagai pemelihara komunitas: + +- Pastikan kontribusi sesuai dengan standar yang diuraikan dalam dokumentasi kami. +- Tinjau secara teratur [Logging Policy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/bash-log.md) dan [Error Codes](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/error-code.md) untuk tetap terupdate. + +## Untuk Pengguna + +Pengguna harus memberikan perhatian khusus kepada: + +- [Docker Installation](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/install-docker.md) - Diperlukan jika Anda berencana menggunakan gambar Docker dari OpenIM. +- [Docker Image Strategy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/images.md) - Untuk memahami gambar yang tersedia dan bagaimana memilih yang tepat untuk arsitektur Anda. diff --git a/docs/README_it.md b/docs/README_it.md new file mode 100644 index 0000000000..76e41b5e7b --- /dev/null +++ b/docs/README_it.md @@ -0,0 +1,67 @@ +# Documentazione del Server OpenIM + +Benvenuti al centro documentazione di OpenIM! Questo centro offre una gamma completa di guide e manuali progettati per aiutarvi a ottenere il massimo dalla vostra esperienza con OpenIM. + +## Indice dei Contenuti + +1. [Contrib](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib) - Guida al contributo e alle configurazioni per gli sviluppatori +2. [Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib) - Convenzioni di codifica, politiche di registrazione e altri strumenti di trasformazione + +------ + +## Contrib + +Questa sezione offre agli sviluppatori una guida dettagliata su come contribuire al codice, configurare il loro ambiente e seguire i processi associati. + +- [Code Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/code-conventions.md) - Regole e convenzioni per scrivere codice in OpenIM. +- [Development Guide](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/development.md) - Una guida su come svolgere lo sviluppo all'interno di OpenIM. +- [Git Cherry Pick](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/gitcherry-pick.md) - Linee guida sulle operazioni di cherry-picking. +- [Git Workflow](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/git-workflow.md) - Il flusso di lavoro git in OpenIM. +- [Initialization Configurations](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/init-config.md) - Guida per configurare e inizializzare OpenIM. +- [Docker Installation](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/install-docker.md) - Come installare Docker sul tuo dispositivo. +- [Linux Development Environment](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/linux-development.md) - Guida per configurare l'ambiente di sviluppo su Linux. +- [Local Actions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/local-actions.md) - Linee guida su come eseguire determinate azioni comuni localmente. +- [Offline Deployment](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/offline-deployment.md) - Metodi per distribuire OpenIM offline. +- [Protoc Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/protoc-tools.md) - Guida all'uso degli strumenti protoc. +- [Go Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-go.md) - Strumenti e librerie in OpenIM per Go. +- [Makefile Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-makefile.md) - Migliori pratiche e strumenti per Makefile. +- [Script Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-scripts.md) - Migliori pratiche e strumenti per gli script. + +## Conversions + +Questa sezione introduce varie convenzioni e politiche all'interno di OpenIM, che comprendono codice, registrazioni, versioni e altro. + +- [API Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/api.md) - Linee guida e metodi per le conversioni API. +- [Logging Policy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/bash-log.md) - Politiche e convenzioni di registrazione in OpenIM. +- [CI/CD Actions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/cicd-actions.md) - Procedure e convenzioni per CI/CD. +- [Commit Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/commit.md) - Convenzioni per i commit di codice in OpenIM. +- [Directory Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/directory.md) - Struttura delle directory e convenzioni all'interno di OpenIM. +- [Error Codes](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/error-code.md) - Elenco e descrizioni dei codici di errore. +- [Go Code Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/go-code.md) - Convenzioni e conversioni per il codice Go. +- [Docker Image Strategy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/images.md) - Strategie di gestione delle immagini Docker di OpenIM, che coprono più architetture e repository di immagini. +- [Logging Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/logging.md) - Ulteriori dettagliate convenzioni sulla registrazione. +- [Version Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/version.md) - Strategie di denominazione e gestione delle versioni di OpenIM. + + +## Per Sviluppatori, Contributori e Manutentori della Comunità + +### Sviluppatori & Contributori + +Se sei uno sviluppatore o qualcuno interessato a contribuire: + +- Familiarizza con le nostre [Code Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/code-conventions.md) e [Git Workflow](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/git-workflow.md) per garantire contributi fluidi. +- Approfondisci la [Development Guide](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/development.md) per ottenere una conoscenza delle pratiche di sviluppo in OpenIM. + +### Manutentori della Comunità + +Come manutentore della comunità: + +- Assicurati che i contributi siano in linea con gli standard delineati nella nostra documentazione. +- Rivedi regolarmente la [Logging Policy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/bash-log.md) e [Error Codes](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/error-code.md) per rimanere aggiornato. + +## Per gli Utenti + +Gli utenti dovrebbero prestare particolare attenzione a: + +- [Docker Installation](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/install-docker.md) - Necessario se si prevede di utilizzare le immagini Docker di OpenIM. +- [Docker Image Strategy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/images.md) - Per comprendere le diverse immagini disponibili e come scegliere quella giusta per la propria architettura. diff --git a/docs/README_ja.md b/docs/README_ja.md new file mode 100644 index 0000000000..3971037fb6 --- /dev/null +++ b/docs/README_ja.md @@ -0,0 +1,67 @@ +# OpenIMサーバードキュメンテーション + +OpenIMドキュメンテーションハブへようこそ!このセンターでは、OpenIM体験を最大限に活用するための包括的なガイドとマニュアルを提供しています。 + +## 目次 + +1. [Contrib](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib) - 開発者向けの貢献と設定に関するガイダンス +2. [Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib) - コーディング規約、ログポリシー、その他の変換ツール + +------ + +## 投稿 + +このセクションでは、開発者がコードを貢献し、環境を設定し、関連するプロセスに従う方法についての詳細なガイドを提供します。 + +- [Code Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/code-conventions.md) - OpenIMでのコード記述のルールと規約。 +- [Development Guide](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/development.md) - OpenIM内での開発を行うためのガイド。 +- [Git Cherry Pick](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/gitcherry-pick.md) - チェリーピッキング操作のガイドライン。 +- [Git Workflow](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/git-workflow.md) - OpenIMにおけるGitのワークフロー。 +- [Initialization Configurations](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/init-config.md) - OpenIMの設定と初期化に関するガイダンス。 +- [Docker Installation](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/install-docker.md) - マシンにDockerをインストールする方法。 +- [Linux Development Environment](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/linux-development.md) - Linux上での開発環境の設定ガイド。 +- [Local Actions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/local-actions.md) - ローカルで一般的なアクションを実行する方法に関するガイドライン。 +- [Offline Deployment](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/offline-deployment.md) - OpenIMをオフラインでデプロイする方法。 +- [Protoc Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/protoc-tools.md) - protocツールの使用ガイド。 +- [Go Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-go.md) - GoのためのOpenIM内のツールとライブラリ。 +- [Makefile Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-makefile.md) - Makefileのベストプラクティスとツール。 +- [Script Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-scripts.md) - スクリプトのベストプラクティスとツール。 + +## Conversions + +このセクションでは、OpenIM内のさまざまな規約とポリシーを紹介します。これには、コード、ログ、バージョンなどが含まれます。 + +- [API Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/api.md) - API変換のためのガイドラインと方法。 +- [Logging Policy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/bash-log.md) - OpenIMにおけるログポリシーと規約。 +- [CI/CD Actions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/cicd-actions.md) - CI/CDの手順と規約。 +- [Commit Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/commit.md) - OpenIMでのコードコミットのための規約。 +- [Directory Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/directory.md) - OpenIM内のディレクトリ構造と規約。 +- [Error Codes](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/error-code.md) - エラーコードのリストと説明。 +- [Go Code Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/go-code.md) - Goコードのための規約と変換。 +- [Docker Image Strategy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/images.md) - 複数のアーキテクチャとイメージリポジトリにまたがるOpenIM Dockerイメージの管理戦略。 +- [Logging Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/logging.md) - ロギングに関するさらに詳細な規約。 +- [Version Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/version.md) - OpenIMバージョンの命名と管理戦略。 + + +## 開発者、コントリビューター、コミュニティメンテナー向け + +### 開発者およびコントリビューター + +開発者または貢献に熱心な方へ: + +- スムーズな貢献を確実にするために、私たちの[Code Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/code-conventions.md)と[Git Workflow](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/git-workflow.md)に慣れ親しみましょう。 +- OpenIMの開発実践に慣れるために、[Development Guide](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/development.md)をご覧ください。 + +### コミュニティメンテナー + +コミュニティメンテナーとして: + +- 貢献が私たちのドキュメンテーションで概説された基準に沿っていることを確認してください。 +- 最新の情報を得るために、定期的に[Logging Policy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/bash-log.md)と[Error Codes](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/error-code.md)をレビューしてください。 + +## ユーザー向け + +ユーザーは特に以下の点に注意してください: + +- [Docker Installation](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/install-docker.md) - OpenIMのDockerイメージを使用する予定の場合に必要です。 +- [Docker Image Strategy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/images.md) - 利用可能なさまざまなイメージを理解し、アーキテクチャに適したものを選択する方法。 diff --git a/docs/README_ko.md b/docs/README_ko.md new file mode 100644 index 0000000000..9cd728c5d9 --- /dev/null +++ b/docs/README_ko.md @@ -0,0 +1,67 @@ +# OpenIM 서버 문서 + +OpenIM 문서 허브에 오신 것을 환영합니다! 이 센터는 OpenIM 경험을 최대한 활용하는 데 도움이 되도록 다양한 가이드와 매뉴얼을 제공합니다. + +## 목차 + +1. [Contrib](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib) - 개발자를 위한 기여 및 구성에 대한 안내 +2. [Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib) - 코딩 규칙, 로깅 정책 및 기타 변환 도구 + +------ + +## 기여 + +이 섹션은 개발자들에게 코드를 기여하는 방법, 환경을 설정하는 방법 및 관련 프로세스를 따르는 방법에 대한 자세한 가이드를 제공합니다. + +- [Code Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/code-conventions.md) - OpenIM에서 코드를 작성하기 위한 규칙 및 규약. +- [Development Guide](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/development.md) - OpenIM 내에서 개발을 수행하는 방법에 대한 가이드. +- [Git Cherry Pick](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/gitcherry-pick.md) - 체리피킹 작업에 대한 지침. +- [Git Workflow](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/git-workflow.md) - OpenIM에서의 깃 워크플로우. +- [Initialization Configurations](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/init-config.md) - OpenIM 설정 및 초기화에 대한 안내. +- [Docker Installation](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/install-docker.md) - 컴퓨터에 도커를 설치하는 방법. +- [Linux Development Environment](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/linux-development.md) - 리눅스에서 개발 환경을 설정하는 가이드. +- [Local Actions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/local-actions.md) - 일부 일반적인 작업을 로컬에서 수행하는 방법에 대한 지침. +- [Offline Deployment](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/offline-deployment.md) - 오프라인에서 OpenIM을 배포하는 방법. +- [Protoc Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/protoc-tools.md) - 프로토콜 도구 사용에 대한 가이드. +- [Go Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-go.md) - Go용 OpenIM 도구 및 라이브러리. +- [Makefile Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-makefile.md) - 메이크파일을 위한 모범 사례 및 도구. +- [Script Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-scripts.md) - 스크립트를 위한 모범 사례 및 도구. + +## 전환 + +이 섹션에서는 코드, 로그, 버전 등을 포함하는 OpenIM 내의 다양한 규칙과 정책을 소개합니다. + +- [API Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/api.md) - API 변환을 위한 지침 및 방법. +- [Logging Policy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/bash-log.md) - OpenIM의 로깅 정책 및 관습. +- [CI/CD Actions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/cicd-actions.md) - CI/CD 절차 및 관습. +- [Commit Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/commit.md) - OpenIM에서 코드 커밋을 위한 관습. +- [Directory Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/directory.md) - OpenIM 내의 디렉토리 구조 및 관습. +- [Error Codes](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/error-code.md) - 오류 코드 목록 및 설명. +- [Go Code Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/go-code.md) - Go 코드를 위한 관습 및 변환. +- [Docker Image Strategy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/images.md) - 다양한 아키텍처 및 이미지 저장소를 아우르는 OpenIM Docker 이미지 관리 전략. +- [Logging Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/logging.md) - 로깅에 대한 추가적인 상세한 관습. +- [Version Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/version.md) - OpenIM 버전의 명명 및 관리 전략. + + +## 개발자, 기여자 및 커뮤니티 관리자를 위한 정보 + +### 개발자 및 기여자 + +개발자이거나 기여에 관심이 있다면: + +- 원활한 기여를 위해 [Code Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/code-conventions.md) 및 [Git Workflow](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/git-workflow.md)에 익숙해지십시오. +- OpenIM에서의 개발 관행을 파악하려면 [Development Guide](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/development.md)를 참조하십시오. + +### 커뮤니티 관리자 + +커뮤니티 관리자로서: + +- 기여가 우리 문서에 명시된 표준에 부합하는지 확인하십시오. +- [Logging Policy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/bash-log.md) 및 [Error Codes](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/error-code.md)를 정기적으로 검토하여 최신 정보를 유지하십시오. + +## 사용자를 위한 정보 + +사용자는 특히 다음 사항에 주의를 기울여야 합니다: + +- [Docker Installation](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/install-docker.md) - OpenIM의 Docker 이미지를 사용할 계획이라면 필요합니다. +- [Docker Image Strategy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/images.md) - 사용 가능한 다양한 이미지를 이해하고 아키텍처에 적합한 이미지를 선택하는 방법. diff --git a/docs/README_ml.md b/docs/README_ml.md new file mode 100644 index 0000000000..7f3aa8c0df --- /dev/null +++ b/docs/README_ml.md @@ -0,0 +1,67 @@ +# OpenIM സെർവർ ഡോക്യുമെന്റേഷൻ + +OpenIM ഡോക്യുമെന്റേഷൻ ഹബ്ബിലേക്ക് സ്വാഗതം! ഈ കേന്ദ്രം OpenIM അനുഭവത്തിൽ നിന്ന് പരമാവധി ഉപയോഗം നേടാൻ സഹായിക്കുന്ന വ്യാപകമായ നിർദേശങ്ങളുടെയും മാനുവലുകളുടെയും ശ്രേണി നൽകുന്നു. + +## ഉള്ളടക്കം + +1. [Contrib](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib) - ഡെവലപ്പർമാർക്കുള്ള സംഭാവനകൾ നൽകുന്നതിനും കോൺഫിഗറേഷനുകൾക്കുള്ള നിർദേശങ്ങൾ +2. [Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib) - കോഡിംഗ് കൺവെൻഷനുകൾ, ലോഗ്ഗിംഗ് നയങ്ങൾ, മറ്റ് പരിവർത്തന ഉപകരണങ്ങൾ + +------ + +## Contrib + +ഈ ഭാഗം ഡെവലപ്പർമാർക്ക് കോഡ് സംഭാവന നൽകുന്നതിന്റെയും അവരുടെ പരിസ്ഥിതി സജ്ജമാക്കുന്നതിന്റെയും ബന്ധപ്പെട്ട പ്രക്രിയകൾ പിന്തുടരുന്നതിന്റെയും വിശദമായ ഗൈഡ് നൽകുന്നു. + +- [Code Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/code-conventions.md) - OpenIM-ൽ കോഡ് എഴുതുന്നതിന്റെ നിയമങ്ങൾ കൺവെൻഷനുകൾ. +- [Development Guide](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/development.md) - OpenIM-ൽ വികസനം നടത്തുന്നതിന്റെ ഗൈഡ്. +- [Git Cherry Pick](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/gitcherry-pick.md) - ചെറി-പിക്കിംഗ് ഓപ്പറേഷനുകൾക്കുള്ള മാർഗ്ഗനിർദേശങ്ങൾ. +- [Git Workflow](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/git-workflow.md) - OpenIM-ൽ ഗിറ്റിന്റെ വർക്ക്ഫ്ലോ. +- [Initialization Configurations](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/init-config.md) - OpenIM സജ്ജമാക്കുന്നതിനും ആരംഭിക്കുന്നതിനും നിർദേശങ്ങൾ. +- [Docker Installation](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/install-docker.md) - നിങ്ങളുടെ യന്ത്രത്തിൽ ഡോക്കർ ഇൻസ്റ്റാൾ ചെയ്യുന്ന രീതി. +- [Linux Development Environment](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/linux-development.md) - ലിനക്സിൽ വികസന പരിസ്ഥിതി സജ്ജമാക്കുന്നതിന്റെ ഗൈഡ്. +- [Local Actions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/local-actions.md) - ചില പൊതുവായ നടപടികൾ പ്രദേശികമായി നടത്തുന്നതിന്റെ മാർഗ്ഗനിർദേശങ്ങൾ. +- [Offline Deployment](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/offline-deployment.md) - OpenIM ഓഫ്‌ലൈൻ ഡിപ്ലോയ് ചെയ്യുന്ന രീതികൾ. +- [Protoc Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/protoc-tools.md) - പ്രോട്ടോക് ഉപകരണങ്ങൾ ഉപയോഗിക്കുന്ന ഗൈഡ്. +- [Go Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-go.md) - Go വേണ്ടി OpenIM-ൽ ഉള്ള ഉപകരണങ്ങളും ലൈബ്രറികളും. +- [Makefile Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-makefile.md) - Makefile ഉപകരണങ്ങളുടെയും മികച്ച പ്രാക്ടീസുകളുടെയും ഗൈഡ്. +- [Script Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-scripts.md) - സ്ക്രിപ്റ്റുകൾക്കുള്ള മികച്ച പ്രാക്ടീസുകളും ഉപകരണങ്ങളും. + +## Conversions + +ഈ ഭാഗം OpenIM-ൽ ഉള്ള വിവിധ കൺവെൻഷനുകളെയും നയങ്ങളെയും ആവിഷ്കരിക്കുന്നു, ഇതിൽ കോഡ്, ലോഗുകൾ, പതിപ്പുകൾ എന്നിവ ഉൾപ്പെടുന്നു. + +- [API Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/api.md) - API കൺവെർഷനുകൾക്കുള്ള നിർദേശങ്ങൾ രീതികൾ. +- [Logging Policy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/bash-log.md) - OpenIM-ൽ ലോഗ്ഗിംഗ് നയങ്ങൾ കൺവെൻഷനുകൾ. +- [CI/CD Actions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/cicd-actions.md) - CI/CD പ്രക്രിയകൾ കൺവെൻഷനുകൾ. +- [Commit Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/commit.md) - OpenIM-ൽ കോഡ് കമ്മിറ്റുകൾക്കുള്ള കൺവെൻഷനുകൾ. +- [Directory Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/directory.md) - OpenIM-ൽ ഡയറക്ടറി ഘടന കൺവെൻഷനുകൾ. +- [Error Codes](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/error-code.md) - പിശക് കോഡുകളുടെ പട്ടിക വിവരണങ്ങൾ. +- [Go Code Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/go-code.md) - Go കോഡിനുള്ള കൺവെൻഷനുകൾ പരിവർത്തനങ്ങൾ. +- [Docker Image Strategy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/images.md) - വിവിധ ആർക്കിടെക്ചറുകൾ ഇമേജ് റെപ്പോസിറ്ററികൾ ഉൾപ്പെടുന്ന OpenIM Docker ഇമേജുകളുടെ മാനേജ്മെന്റ് സ്ട്രാറ്റജീസ്. +- [Logging Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/logging.md) - ലോഗ്ഗിംഗിന്റെ കൂടുതൽ വിശദമായ കൺവെൻഷനുകൾ. +- [Version Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/version.md) - OpenIM പതിപ്പുകൾക്കുള്ള നാമകരണ മാനേജ്മെന്റ് സ്ട്രാറ്റജീസ്. + + +## ഡെവലപ്പർമാർക്കും, സംഭാവനകൾ നൽകുന്നവർക്കും, കമ്മ്യൂണിറ്റി മെയിന്റെയിനർമാർക്കും + +### ഡെവലപ്പർമാർ & സംഭാവനകൾ നൽകുന്നവർ + +നിങ്ങൾ ഒരു ഡെവലപ്പർ അല്ലെങ്കിൽ സംഭാവനകൾ നൽകാൻ ആഗ്രഹിക്കുന്ന ആളാണെങ്കിൽ: + +- നിരവധി സംഭാവനകൾ ഉറപ്പാക്കാൻ ഞങ്ങളുടെ [Code Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/code-conventions.md) എന്നിവയുമായി പരിചിതരാകുക. +- OpenIM-ൽ വികസന പ്രാക്ടീസുകൾ ലഭ്യമാക്കാൻ [Development Guide](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/development.md) അന്വേഷിക്കുക. + +### കമ്മ്യൂണിറ്റി മെയിന്റെയിനർമാർ + +ഒരു കമ്മ്യൂണിറ്റി മെയിന്റെയിനറായി: + +- സംഭാവനകൾ ഞങ്ങളുടെ ഡോക്യുമെന്റേഷനിൽ വിവരിച്ച മാനദണ്ഡങ്ങൾക്ക് അനുസൃതമാണെന്ന് ഉറപ്പാക്കുക. +- [Logging Policy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/bash-log.md) എന്നിവ പുതുക്കി വായിക്കുക. + +## ഉപയോക്താക്കൾക്ക് + +ഉപയോക്താക്കൾ പ്രത്യേകം ശ്രദ്ധിക്കേണ്ട കാര്യങ്ങൾ: + +- [Docker Installation](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/install-docker.md) - OpenIM-ന്റെ ഡോക്കർ ഇമേജുകൾ ഉപയോഗിക്കാൻ പദ്ധതിയിടുന്നെങ്കിൽ ആവശ്യമാണ്. +- [Docker Image Strategy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/images.md) - ലഭ്യമായ വിവിധ ഇമേജുകൾ മനസ്സിലാക്കുകയും നിങ്ങളുടെ ആർക്കിടെക്ചറിന് അനുയോജ്യമായത് എങ്ങനെ തിരഞ്ഞെടുക്കണം എന്ന് അറിയുക. diff --git a/docs/README_nl.md b/docs/README_nl.md new file mode 100644 index 0000000000..755145e6f4 --- /dev/null +++ b/docs/README_nl.md @@ -0,0 +1,67 @@ +# OpenIM Server-documenten + +Welkom bij de OpenIM-documentatiehub! Dit centrum biedt een uitgebreide reeks handleidingen en handleidingen die zijn ontworpen om u te helpen het meeste uit uw OpenIM-ervaring te halen. + +## Inhoudsopgave + +1. [Contrib](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib) - Richtlijnen voor bijdragen en configuraties voor ontwikkelaars +2. [Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib) - Codeerconventies, logboekbeleid en andere transformatietools + +------ + +## Draag bij + +Deze sectie biedt ontwikkelaars een gedetailleerde handleiding over hoe ze code kunnen bijdragen, hun omgeving kunnen instellen en de bijbehorende processen kunnen volgen. + +- [Code Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/code-conventions.md) - Regels en conventies voor het schrijven van code in OpenIM. +- [Development Guide](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/development.md) - Een handleiding voor het uitvoeren van ontwikkelingen binnen OpenIM. +- [Git Cherry Pick](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/gitcherry-pick.md) - Richtlijnen voor kersenplukoperaties. +- [Git Workflow](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/git-workflow.md) - De git-workflow in OpenIM. +- [Initialization Configurations](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/init-config.md) - Begeleiding bij het instellen en initialiseren van OpenIM. +- [Docker Installation](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/install-docker.md) - Hoe Docker op uw machine te installeren. +- [Linux Development Environment](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/linux-development.md) - Handleiding voor het opzetten van de ontwikkelomgeving op Linux. +- [Local Actions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/local-actions.md) - Richtlijnen voor het lokaal uitvoeren van bepaalde gemeenschappelijke acties. +- [Offline Deployment](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/offline-deployment.md) - Methoden voor het offline inzetten van OpenIM. +- [Protoc Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/protoc-tools.md) - Handleiding voor het gebruik van protocoltools. +- [Go Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-go.md) - Tools en bibliotheken in OpenIM for Go. +- [Makefile Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-makefile.md) - Best practices en tools voor Makefile. +- [Script Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-scripts.md) - Best practices en tools voor scripts. + +## Conversies + +In deze sectie worden verschillende conventies en beleidsregels binnen OpenIM geïntroduceerd, waaronder code, logs, versies en meer. + +- [API Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/api.md) - Richtlijnen en methoden voor API-conversies. +- [Logging Policy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/bash-log.md) - Logboekbeleid en -conventies in OpenIM. +- [CI/CD Actions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/cicd-actions.md) - Procedures en conventies voor CI/CD. +- [Commit Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/commit.md) - Conventies voor code-commits in OpenIM. +- [Directory Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/directory.md) - Directorystructuur en conventies binnen OpenIM. +- [Error Codes](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/error-code.md) - Lijst en beschrijvingen van foutcodes. +- [Go Code Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/go-code.md) - Conventies en conversies voor Go-code. +- [Docker Image Strategy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/images.md) - Beheerstrategieën voor OpenIM Docker-images, verspreid over meerdere architecturen en image-opslagplaatsen. +- [Logging Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/logging.md) - Verdere gedetailleerde conventies over houtkap. +- [Version Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/version.md) - Naamgevings- en beheerstrategieën voor OpenIM-versies. + + +## Voor ontwikkelaars, bijdragers en communitybeheerders + +### Ontwikkelaars en bijdragers + +Als u een ontwikkelaar bent of iemand die graag een bijdrage wil leveren: + +- Maak uzelf vertrouwd met onze [Code Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/code-conventions.md) en [Git Workflow](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/git-workflow.md) om soepele bijdragen te garanderen. +- Duik in de [Development Guide](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/development.md) om de ontwikkelpraktijken in OpenIM onder de knie te krijgen. + +### Gemeenschapsbeheerders + +Als gemeenschapsbeheerder: + +- Zorg ervoor dat bijdragen in overeenstemming zijn met de normen die in onze documentatie worden beschreven. +- Controleer regelmatig het [Logging Policy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/bash-log.md) en de [Error Codes](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/error-code.md) om op de hoogte te blijven. + +## Voor gebruikers + +Gebruikers moeten bijzondere aandacht besteden aan: + +- [Docker Installation](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/install-docker.md) - Noodzakelijk als u van plan bent Docker-images van OpenIM te gebruiken. +- [Docker Image Strategy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/images.md) - Om de verschillende beschikbare afbeeldingen te begrijpen en hoe u de juiste voor uw architectuur kiest. \ No newline at end of file diff --git a/docs/README_pl.md b/docs/README_pl.md new file mode 100644 index 0000000000..9e89c9dae3 --- /dev/null +++ b/docs/README_pl.md @@ -0,0 +1,67 @@ +# Dokumentacja serwera OpenIM + +Witamy w centrum dokumentacji OpenIM! Centrum to zapewnia kompleksową gamę przewodników i podręczników zaprojektowanych, aby pomóc Ci w pełni wykorzystać możliwości OpenIM. + +## Spis treści + +1. [Contrib](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib) - Wskazówki dotyczące współtworzenia i konfiguracji dla programistów +2. [Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib) - Konwencje kodowania, zasady rejestrowania i inne narzędzia do transformacji + +------ + +## Wkład + +W tej sekcji deweloperzy mogą znaleźć szczegółowy przewodnik dotyczący udostępniania kodu, konfigurowania środowiska i wykonywania powiązanych procesów. + +- [Code Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/code-conventions.md) - Zasady i konwencje pisania kodu w OpenIM. +- [Development Guide](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/development.md) - Poradnik dotyczący programowania w OpenIM. +- [Git Cherry Pick](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/gitcherry-pick.md) - Wytyczne dotyczące operacji zbierania wiśni. +- [Git Workflow](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/git-workflow.md) - Przepływ pracy git w OpenIM. +- [Initialization Configurations](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/init-config.md) - Wskazówki dotyczące konfigurowania i inicjowania OpenIM. +- [Docker Installation](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/install-docker.md) - Jak zainstalować Docker na swoim komputerze. +- [Linux Development Environment](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/linux-development.md) - Przewodnik po konfigurowaniu środowiska programistycznego w systemie Linux. +- [Local Actions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/local-actions.md) - Wytyczne dotyczące sposobu przeprowadzania niektórych typowych działań lokalnie. +- [Offline Deployment](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/offline-deployment.md) - Metody wdrażania OpenIM offline. +- [Protoc Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/protoc-tools.md) - Przewodnik dotyczący korzystania z narzędzi protoc. +- [Go Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-go.md) - Narzędzia i biblioteki w OpenIM for Go. +- [Makefile Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-makefile.md) - Najlepsze praktyki i narzędzia dla Makefile. +- [Script Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-scripts.md) - Najlepsze praktyki i narzędzia dotyczące skryptów. + +## Konwersje + +W tej sekcji przedstawiono różne konwencje i zasady w OpenIM, obejmujące kod, dzienniki, wersje i nie tylko. + +- [API Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/api.md) - Wytyczne i metody konwersji API. +- [Logging Policy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/bash-log.md) - Zasady i konwencje rejestrowania w OpenIM. +- [CI/CD Actions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/cicd-actions.md) - Procedury i konwencje dotyczące CI/CD. +- [Commit Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/commit.md) - Konwencje dotyczące zatwierdzania kodu w OpenIM. +- [Directory Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/directory.md) - Struktura katalogów i konwencje w OpenIM. +- [Error Codes](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/error-code.md) - Lista i opisy kodów błędów. +- [Go Code Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/go-code.md) - Konwencje i konwersje dla kodu Go. +- [Docker Image Strategy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/images.md) - Strategie zarządzania obrazami Dockera OpenIM obejmujące wiele architektur i repozytoriów obrazów. +- [Logging Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/logging.md) - Dalsze szczegółowe konwencje dotyczące pozyskiwania drewna. +- [Version Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/version.md) - Strategie nazewnictwa i zarządzania wersjami OpenIM. + + +## Dla programistów, współpracowników i opiekunów społeczności + +### Programiści i współpracownicy + +Jeśli jesteś programistą lub osobą, która chce wnieść swój wkład: + +- Zapoznaj się z naszymi [Code Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/code-conventions.md) i [Git Workflow](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/git-workflow.md), aby zapewnić płynną współpracę. +- Zajrzyj do [Development Guide](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/development.md), aby zapoznać się z praktykami programistycznymi w OpenIM. + +### Opiekunowie społeczności + +Jako opiekun społeczności: + +- Upewnij się, że wkład jest zgodny ze standardami określonymi w naszej dokumentacji. +- Regularnie przeglądaj [Logging Policy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/bash-log.md) i [Error Codes](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/error-code.md), aby być na bieżąco. + +## Dla Użytkowników + +Użytkownicy powinni zwrócić szczególną uwagę na: + +- [Docker Installation](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/install-docker.md) - Niezbędne, jeśli planujesz używać obrazów Dockera OpenIM. +- [Docker Image Strategy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/images.md) - Aby zrozumieć różne dostępne obrazy i dowiedzieć się, jak wybrać odpowiedni dla swojej architektury. \ No newline at end of file diff --git a/docs/README_pt_BR.md b/docs/README_pt_BR.md new file mode 100644 index 0000000000..e28db74a61 --- /dev/null +++ b/docs/README_pt_BR.md @@ -0,0 +1,67 @@ +# Documentação do Servidor OpenIM + +Bem-vindo ao centro de documentação do OpenIM! Este centro oferece uma ampla gama de guias e manuais projetados para ajudá-lo a aproveitar ao máximo sua experiência com o OpenIM. + +## Índice de Conteúdos + +1. [Contrib](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib) - Orientações sobre contribuições e configurações para desenvolvedores +2. [Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib) - Convenções de codificação, políticas de registro e outras ferramentas de transformação + +------ + +## Contrib + +Esta seção oferece aos desenvolvedores um guia detalhado sobre como contribuir com código, configurar seu ambiente e seguir os processos associados. + +- [Code Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/code-conventions.md) - Regras e convenções para escrever código no OpenIM. +- [Development Guide](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/development.md) - Um guia sobre como realizar o desenvolvimento dentro do OpenIM. +- [Git Cherry Pick](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/gitcherry-pick.md) - Diretrizes sobre operações de cherry-picking. +- [Git Workflow](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/git-workflow.md) - O fluxo de trabalho git no OpenIM. +- [Initialization Configurations](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/init-config.md) - Orientações sobre configuração e inicialização do OpenIM. +- [Docker Installation](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/install-docker.md) - Como instalar o Docker em sua máquina. +- [Linux Development Environment](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/linux-development.md) - Guia para configurar o ambiente de desenvolvimento no Linux. +- [Local Actions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/local-actions.md) - Diretrizes sobre como realizar certas ações comuns localmente. +- [Offline Deployment](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/offline-deployment.md) - Métodos para implantar o OpenIM offline. +- [Protoc Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/protoc-tools.md) - Guia sobre o uso de ferramentas protoc. +- [Go Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-go.md) - Ferramentas e bibliotecas no OpenIM para Go. +- [Makefile Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-makefile.md) - Melhores práticas e ferramentas para Makefile. +- [Script Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-scripts.md) - Melhores práticas e ferramentas para scripts. + +## Conversions + +Esta seção apresenta várias convenções e políticas dentro do OpenIM, abrangendo código, logs, versões e mais. + +- [API Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/api.md) - Diretrizes e métodos para conversões de API. +- [Logging Policy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/bash-log.md) - Políticas e convenções de registro no OpenIM. +- [CI/CD Actions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/cicd-actions.md) - Procedimentos e convenções para CI/CD. +- [Commit Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/commit.md) - Convenções para commits de código no OpenIM. +- [Directory Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/directory.md) - Estrutura de diretórios e convenções dentro do OpenIM. +- [Error Codes](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/error-code.md) - Lista e descrições de códigos de erro. +- [Go Code Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/go-code.md) - Convenções e conversões para código Go. +- [Docker Image Strategy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/images.md) - Estratégias de gerenciamento para imagens Docker do OpenIM, abrangendo várias arquiteturas e repositórios de imagens. +- [Logging Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/logging.md) - Convenções mais detalhadas sobre registro. +- [Version Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/version.md) - Estratégias de nomeação e gerenciamento para versões do OpenIM. + + +## Para Desenvolvedores, Contribuidores e Mantenedores da Comunidade + +### Desenvolvedores & Contribuidores + +Se você é um desenvolvedor ou alguém interessado em contribuir: + +- Familiarize-se com nossas [Code Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/code-conventions.md) e [Git Workflow](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/git-workflow.md) para garantir contribuições suaves. +- Mergulhe no [Development Guide](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/development.md) para se familiarizar com as práticas de desenvolvimento no OpenIM. + +### Mantenedores da Comunidade + +Como mantenedor da comunidade: + +- Garanta que as contribuições estejam alinhadas com os padrões descritos em nossa documentação. +- Reveja regularmente a [Logging Policy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/bash-log.md) e [Error Codes](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/error-code.md) para se manter atualizado. + +## Para Usuários + +Os usuários devem prestar atenção especial a: + +- [Docker Installation](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/install-docker.md) - Necessário se você planeja usar imagens Docker do OpenIM. +- [Docker Image Strategy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/images.md) - Para entender as diferentes imagens disponíveis e como escolher a certa para a sua arquitetura. diff --git a/docs/README_ru.md b/docs/README_ru.md new file mode 100644 index 0000000000..0e89df7c77 --- /dev/null +++ b/docs/README_ru.md @@ -0,0 +1,67 @@ +# Документация по серверу OpenIM + +Добро пожаловать в центр документации OpenIM! Этот центр предоставляет широкий спектр руководств и руководств, призванных помочь вам максимально эффективно использовать возможности OpenIM. + +## Оглавление + +1. [Contrib](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib) - Руководство по участию и настройке для разработчиков +2. [Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib) - Соглашения по кодированию, политики ведения журналов и другие инструменты преобразования. + +------ + +## Вклад + +В этом разделе разработчикам предлагается подробное руководство о том, как добавлять код, настраивать среду и следовать соответствующим процессам. + +- [Code Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/code-conventions.md) - Правила и соглашения по написанию кода в OpenIM. +- [Development Guide](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/development.md) - Руководство о том, как вести разработку в OpenIM. +- [Git Cherry Pick](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/gitcherry-pick.md) - Руководство по сбору урожая. +- [Git Workflow](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/git-workflow.md) - Рабочий процесс git в OpenIM. +- [Initialization Configurations](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/init-config.md) - Руководство по настройке и инициализации OpenIM. +- [Docker Installation](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/install-docker.md) - Как установить Docker на свой компьютер. +- [Linux Development Environment](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/linux-development.md) - Руководство по настройке среды разработки в Linux. +- [Local Actions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/local-actions.md) - Рекомендации о том, как выполнять определенные общие действия на местном уровне. +- [Offline Deployment](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/offline-deployment.md) - Способы развертывания OpenIM в автономном режиме. +- [Protoc Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/protoc-tools.md) - Руководство по использованию инструментов протокола. +- [Go Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-go.md) - Инструменты и библиотеки в OpenIM для Go. +- [Makefile Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-makefile.md) - Лучшие практики и инструменты для Makefile. +- [Script Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-scripts.md) - Лучшие практики и инструменты для сценариев. + +## Конверсии + +В этом разделе представлены различные соглашения и политики OpenIM, включая код, журналы, версии и многое другое. + +- [API Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/api.md) - Рекомендации и методы преобразования API. +- [Logging Policy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/bash-log.md) - Политики и соглашения ведения журналов в OpenIM. +- [CI/CD Actions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/cicd-actions.md) - Процедуры и соглашения для CI/CD. +- [Commit Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/commit.md) - Соглашения о фиксации кода в OpenIM. +- [Directory Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/directory.md) - Структура каталогов и соглашения в OpenIM. +- [Error Codes](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/error-code.md) - Список и описание кодов ошибок. +- [Go Code Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/go-code.md) - Соглашения и преобразования для кода Go. +- [Docker Image Strategy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/images.md) - Стратегии управления образами OpenIM Docker, охватывающими несколько архитектур и репозиториев изображений. +- [Logging Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/logging.md) - Дальнейшие подробные соглашения о ведении журнала. +- [Version Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/version.md) - Стратегии именования и управления версиями OpenIM. + + +## Для разработчиков, участников и сопровождающих сообщества + +### Разработчики и участники + +Если вы разработчик или кто-то хочет внести свой вклад: + +- Ознакомьтесь с нашими [Code Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/code-conventions.md) и [Git Workflow](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/git-workflow.md), чтобы обеспечить бесперебойную работу. +- Погрузитесь в [Development Guide](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/development.md), чтобы ознакомиться с методами разработки в OpenIM. + +### Сопровождающие сообщества + +Как администратор сообщества: + +- Убедитесь, что вклады соответствуют стандартам, изложенным в нашей документации. +- Регулярно просматривайте [Logging Policy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/bash-log.md) и [Error Codes](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/error-code.md), чтобы оставаться в курсе событий. + +## Для пользователей + +Пользователям следует обратить особое внимание на: + +- [Docker Installation](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/install-docker.md) - Необходимо, если вы планируете использовать Docker-образы OpenIM. +- [Docker Image Strategy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/images.md) - Чтобы понять различные доступные изображения и как выбрать подходящее для вашей архитектуры. \ No newline at end of file diff --git a/docs/README_tr.md b/docs/README_tr.md new file mode 100644 index 0000000000..d2bd119e4e --- /dev/null +++ b/docs/README_tr.md @@ -0,0 +1,67 @@ +# OpenIM Sunucu Belgeleri + +OpenIM Belgeleri merkezine hoş geldiniz! Bu merkez, OpenIM deneyiminizden en iyi şekilde faydalanmanıza yardımcı olmak için tasarlanmış kapsamlı bir rehber ve kılavuzlar koleksiyonu sunar. + +## İçindekiler + +1. [Katılım](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib) - Geliştiriciler için katkıda bulunma ve yapılandırma rehberi +2. [Dönüşümler](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib) - Kodlama kuralları, günlükleme politikaları ve diğer dönüşüm araçları + +------ + +## Katılım + +Bu bölüm, geliştiricilere kod katkısında bulunma, çevrelerini kurma ve ilişkilendirilmiş süreçleri takip etme konusunda detaylı bir rehber sunar. + +- [Kod Kuralları](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/code-conventions.md) - OpenIM'de kod yazma kuralları ve gelenekleri. +- [Geliştirme Rehberi](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/development.md) - OpenIM içinde geliştirme nasıl yapılır konusunda bir rehber. +- [Git Cherry Pick](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/gitcherry-pick.md) - Cherry-pick işlemleri için yönergeler. +- [Git Çalışma Akışı](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/git-workflow.md) - OpenIM'deki git çalışma akışı. +- [Başlangıç Yapılandırmaları](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/init-config.md) - OpenIM'i kurma ve başlatma konusunda rehberlik. +- [Docker Kurulumu](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/install-docker.md) - Makinenize Docker nasıl kurulur. +- [Linux Geliştirme Ortamı](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/linux-development.md) - Linux üzerinde geliştirme ortamını kurma kılavuzu. +- [Yerel İşlemler](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/local-actions.md) - Yerelde belirli yaygın işlemleri nasıl gerçekleştireceğiniz hakkında yönergeler. +- [Çevrimdışı Dağıtım](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/offline-deployment.md) - OpenIM'in çevrimdışı nasıl dağıtılacağı yöntemleri. +- [Protoc Araçları](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/protoc-tools.md) - Protoc araçlarını kullanma rehberi. +- [Go Araçları](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-go.md) - Go için OpenIM'deki araçlar ve kütüphaneler. +- [Makefile Araçları](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-makefile.md) - Makefile için en iyi uygulamalar ve araçlar. +- [Betik Araçları](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-scripts.md) - Betikler için en iyi uygulamalar ve araçlar. + +## Dönüşümler + +Bu bölüm, kod, günlükler, sürümler ve daha fazlasını içeren çeşitli OpenIM içindeki kuralları ve politikaları tanıtır. + +- [API Dönüşümleri](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/api.md) - API dönüşümleri için yönergeler ve yöntemler. +- [Günlükleme Politikası](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/bash-log.md) - OpenIM'deki günlükleme politikaları ve gelenekleri. +- [CI/CD İşlemleri](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/cicd-actions.md) - CI/CD için prosedürler ve gelenekler. +- [Taahhüt Kuralları](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/commit.md) - OpenIM'deki kod taahhütleri için kurallar. +- [Dizin Kuralları](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/directory.md) - OpenIM içindeki dizin yapısı ve kurallar. +- [Hata Kodları](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/error-code.md) - Hata kodlarının listesi ve açıklamaları. +- [Go Kod Dönüşümleri](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/go-code.md) - Go kodu için kurallar ve dönüşümler. +- [Docker İmaj Stratejisi](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/images.md) - OpenIM Docker imajlarının yönetim stratejileri, birden fazla mimariyi ve imaj depolarını kapsar. +- [Günlükleme Kuralları](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/logging.md) - Günlükleme hakkında daha fazla ayrıntılı kurallar. +- [Sürüm Kuralları](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/version.md) - OpenIM sürümleri için adlandırma ve yönetim stratejileri. + + +## Geliştiriciler, Katkıda Bulunanlar ve Topluluk Bakımı + +### Geliştiriciler & Katkıda Bulunanlar + +Eğer bir geliştirici veya katkıda bulunmaya hevesli biriyseniz: + +- Katkılarınızı düzgün bir şekilde yapmak için [Kod Kuralları](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/code-conventions.md) ve [Git Çalışma Akışı](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/git-workflow.md) ile tanışın. +- OpenIM'deki geliştirme uygulamalarını anlamak için [Geliştirme Rehberi'ne](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/development.md) göz atın. + +### Topluluk Bakımı + +Topluluk bakımı olarak: + +- Katkıların belirtilen standartlarla uyumlu olduğundan emin olun. +- [Günlükleme Politikası](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/bash-log.md) ve [Hata Kodları](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/error-code.md) sık sık gözden geçirerek güncel kalın. + +## Kullanıcılar İçin + +Kullanıcılar, özellikle dikkat etmelidir: + +- [Docker Kurulumu](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/install-docker.md) - OpenIM Docker imajlarını kullanmayı planlıyorsanız gereklidir. +- [Docker İmaj Stratejisi](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/images.md) - Mevcut farklı imajları anlamak ve mimarinize uygun olanı nasıl seçeceğinizi öğrenmek için. diff --git a/docs/README_ua.md b/docs/README_ua.md new file mode 100644 index 0000000000..1eaf6b5d1b --- /dev/null +++ b/docs/README_ua.md @@ -0,0 +1,67 @@ +# OpenIM Server документ + +Ласкаво просимо до Центру документації OpenIM! Цей центр надає вичерпні посібники та посібники, розроблені, щоб допомогти вам отримати максимальну віддачу від роботи з OpenIM. + +## Зміст + +1. [Contrib](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib) - Посібник із внесків і налаштування для розробників +2. [Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib) - Інструкції з кодування, політики журналювання та інші інструменти перетворення + +------ + +## Посібник із внесків + +Цей розділ надає розробникам докладні вказівки щодо того, як додати код, налаштувати своє середовище та дотримуватися пов’язаних процесів. + +- [Code Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/code-conventions.md) - Правила та умовності для написання коду в OpenIM. +- [Development Guide](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/development.md) - Посібник з розробки в OpenIM. +- [Git Cherry Pick](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/gitcherry-pick.md) - Ретельно підібрані інструкції. +- [Git Workflow](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/git-workflow.md) - робочий процес git у OpenIM. +- [Initialization Configurations](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/init-config.md) - Посібник із налаштування та ініціалізації OpenIM. +- [Docker Installation](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/install-docker.md) - Як встановити Docker на вашу машину. +- [Linux Development Environment](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/linux-development.md) - Посібник із налаштування середовища розробки в Linux. +- [Local Actions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/local-actions.md) - Посібник із виконання деяких типових операцій локально. +- [Offline Deployment](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/offline-deployment.md) - Як розгорнути OpenIM офлайн. +- [Protoc Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/protoc-tools.md) - Посібник із використання інструменту protoc. +- [Go Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-go.md) - Інструменти та бібліотеки для Go в OpenIM. +- [Makefile Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-makefile.md) - Найкращі практики та інструменти для Makefiles. +- [Script Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-scripts.md) - Найкращі практики та інструменти для створення сценаріїв. + +## Методи внеску + +У цьому розділі описано різні практики та політики в OpenIM, зокрема код, журнали, версії тощо. + +- [API Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/api.md) - Рекомендації та методи перетворення API. +- [Logging Policy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/bash-log.md) - Політика та практика журналювання в OpenIM. +- [CI/CD Actions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/cicd-actions.md) - Процедури та практики CI/CD. +- [Commit Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/commit.md) - Конвенції для подання коду в OpenIM. +- [Directory Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/directory.md) - Конвенції для подання коду в OpenIM. +- [Error Codes](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/error-code.md) - Перелік і опис кодів помилок. +- [Go Code Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/go-code.md) - Конвенції та перетворення коду Go. +- [Docker Image Strategy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/images.md) - Стратегія керування зображеннями OpenIM Docker, що охоплює кілька архітектур і сховищ зображень. +- [Logging Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/logging.md) - Більш детальні умови для журналювання. +- [Version Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/version.md) - Стратегії іменування та керування для версій OpenIM. + + +## Для розробників, співавторів і супроводжувачів спільноти + +### Розробники та учасники + +Якщо ви розробник або бажаєте зробити внесок: + +- знайомі з нами [Code Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/code-conventions.md) і [Git Workflow](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/git-workflow.md), щоб забезпечити плавний внесок. +- зрозуміти глибше [Development Guide](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/development.md), освоїти практики розробки OpenIM. + +### супроводжувач спільноти + +Як супроводжувач спільноти: + +- Переконайтеся, що внески відповідають стандартам, викладеним у нашій документації. +- Регулярно перевіряйте [Logging Policy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/bash-log.md) i [Error Codes](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/error-code.md), щоб бути в курсі подій. + +## Для користувачів + +Користувачам слід звернути особливу увагу на: + +- [Docker Installation](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/install-docker.md) - Це буде необхідно, якщо ви плануєте використовувати образ Docker OpenIM. +- [Docker Image Strategy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/images.md) - Дізнайтеся про доступні зображення та про те, як вибрати правильний для вашої архітектури. diff --git a/docs/README_vi.md b/docs/README_vi.md new file mode 100644 index 0000000000..55a99b8e5a --- /dev/null +++ b/docs/README_vi.md @@ -0,0 +1,67 @@ +# Tài liệu Máy chủ OpenIM + +Chào mừng bạn đến với trung tâm tài liệu OpenIM! Trung tâm này cung cấp một loạt các hướng dẫn và hướng dẫn chi tiết được thiết kế để giúp bạn tận dụng tối đa trải nghiệm OpenIM của mình. + +## Mục lục + +1. [Contrib](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib) - Hướng dẫn về đóng góp và cấu hình cho các nhà phát triển +2. [Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib) - Quy ước mã hóa, chính sách ghi nhật ký và các công cụ chuyển đổi khác + +------ + +## Đóng góp + +Phần này cung cấp cho các nhà phát triển một hướng dẫn chi tiết về cách đóng góp mã, thiết lập môi trường của họ và tuân theo các quy trình liên quan. + +- [Code Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/code-conventions.md) - Quy tắc và quy ước viết mã trong OpenIM. +- [Development Guide](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/development.md) - Hướng dẫn về cách thực hiện phát triển trong OpenIM. +- [Git Cherry Pick](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/gitcherry-pick.md) - Hướng dẫn về các hoạt động chọn lọc. +- [Git Workflow](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/git-workflow.md) - Quy trình làm việc git trong OpenIM. +- [Initialization Configurations](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/init-config.md) - Hướng dẫn về thiết lập và khởi tạo OpenIM. +- [Docker Installation](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/install-docker.md) - Cách cài đặt Docker trên máy của bạn. +- [Linux Development Environment](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/linux-development.md) - Hướng dẫn thiết lập môi trường phát triển trên Linux. +- [Local Actions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/local-actions.md) - Hướng dẫn về cách thực hiện một số hành động phổ biến ở cấp địa phương. +- [Offline Deployment](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/offline-deployment.md) - Các phương pháp triển khai OpenIM ngoại tuyến. +- [Protoc Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/protoc-tools.md) - Hướng dẫn sử dụng công cụ protoc. +- [Go Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-go.md) - Công cụ và thư viện trong OpenIM cho Go. +- [Makefile Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-makefile.md) - Thực hành tốt nhất và công cụ cho Makefile. +- [Script Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-scripts.md) - Thực hành tốt nhất và công cụ cho kịch bản. + +## Chuyển đổi + +Phần này giới thiệu các quy ước và chính sách khác nhau trong OpenIM, bao gồm mã, nhật ký, phiên bản và hơn thế nữa. + +- [API Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/api.md) - Hướng dẫn và phương pháp chuyển đổi API. +- [Logging Policy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/bash-log.md) - Chính sách và quy ước ghi nhật ký trong OpenIM. +- [CI/CD Actions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/cicd-actions.md) - Quy trình và quy ước cho CI/CD. +- [Commit Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/commit.md) - Quy ước cho các cam kết mã trong OpenIM. +- [Directory Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/directory.md) - Cấu trúc thư mục và quy ước trong OpenIM. +- [Error Codes](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/error-code.md) - Danh sách và mô tả các mã lỗi. +- [Go Code Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/go-code.md) - Quy ước và chuyển đổi cho mã Go. +- [Docker Image Strategy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/images.md) - Chiến lược quản lý hình ảnh Docker của OpenIM, bao gồm nhiều kiến trúc và kho lưu trữ hình ảnh. +- [Logging Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/logging.md) - Quy ước chi tiết hơn về ghi nhật ký. +- [Version Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/version.md) - Chiến lược đặt tên và quản lý phiên bản OpenIM. + + +## Dành cho Nhà phát triển, Người đóng góp và Người duy trì Cộng đồng + +### Nhà phát triển & Người đóng góp + +Nếu bạn là nhà phát triển hoặc ai đó muốn đóng góp: + +- Làm quen với [Code Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/code-conventions.md) và [Git Workflow](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/git-workflow.md) của chúng tôi để đảm bảo đóng góp trôi chảy. +- Tìm hiểu [Development Guide](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/development.md) để nắm bắt các thực hành phát triển trong OpenIM. + +### Người duy trì Cộng đồng + +Là người duy trì cộng đồng: + +- Đảm bảo rằng các đóng góp phù hợp với các tiêu chuẩn được nêu trong tài liệu của chúng tôi. +- Thường xuyên xem lại [Logging Policy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/bash-log.md) và [Error Codes](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/error-code.md) để cập nhật thông tin. + +## Dành cho Người dùng + +Người dùng nên chú ý đặc biệt đến: + +- [Docker Installation](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/install-docker.md) - Cần thiết nếu bạn dự định sử dụng hình ảnh Docker của OpenIM. +- [Docker Image Strategy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/images.md) - Để hiểu các hình ảnh khác nhau có sẵn và cách chọn hình ảnh phù hợp cho kiến trúc của bạn. diff --git a/docs/README_zh_CN.md b/docs/README_zh_CN.md new file mode 100644 index 0000000000..413d5dfa18 --- /dev/null +++ b/docs/README_zh_CN.md @@ -0,0 +1,67 @@ +# OpenIM Server 文档 + +欢迎来到 OpenIM 文档中心!本中心提供全面的指南和手册,旨在帮助您最大限度地利用 OpenIM 体验。 + +## 目录 + +1. [Contrib](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib) - 为开发者提供的贡献指南和配置 +2. [Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib) - 编码规范、日志策略和其他转换工具 + +------ + +## 贡献指南 + +本节为开发人员提供了如何贡献代码、设置环境以及遵循相关流程的详细指南。 + +- [Code Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/code-conventions.md) - OpenIM 中编写代码的规则和惯例。 +- [Development Guide](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/development.md) - 关于如何在 OpenIM 内进行开发的指南。 +- [Git Cherry Pick](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/gitcherry-pick.md) - 精挑细选的操作指南。 +- [Git Workflow](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/git-workflow.md) - OpenIM 中的 git 工作流程。 +- [Initialization Configurations](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/init-config.md) - 设置和初始化 OpenIM 的指南。 +- [Docker Installation](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/install-docker.md) - 如何在您的机器上安装 Docker。 +- [Linux Development Environment](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/linux-development.md) - 在 Linux 上设置开发环境的指南。 +- [Local Actions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/local-actions.md) - 关于如何在本地执行某些常见操作的指南。 +- [Offline Deployment](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/offline-deployment.md) - 离线部署 OpenIM 的方法。 +- [Protoc Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/protoc-tools.md) - 使用 protoc 工具的指南。 +- [Go Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-go.md) - OpenIM 中 Go 的工具和库。 +- [Makefile Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-makefile.md) - Makefile 的最佳实践和工具。 +- [Script Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-scripts.md) - 脚本的最佳实践和工具。 + +## 贡献方法 + +本节介绍 OpenIM 内的各种惯例和政策,包括代码、日志、版本等。 + +- [API Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/api.md) - API 转换的指南和方法。 +- [Logging Policy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/bash-log.md) - OpenIM 中的日志策略和惯例。 +- [CI/CD Actions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/cicd-actions.md) - CI/CD 的程序和惯例。 +- [Commit Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/commit.md) - OpenIM 中代码提交的惯例。 +- [Directory Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/directory.md) - OpenIM 内的目录结构和惯例。 +- [Error Codes](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/error-code.md) - 错误代码的列表和描述。 +- [Go Code Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/go-code.md) - Go 代码的惯例和转换。 +- [Docker Image Strategy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/images.md) - OpenIM Docker 镜像的管理策略,涵盖多个架构和镜像仓库。 +- [Logging Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/logging.md) - 有关日志的更详细的惯例。 +- [Version Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/version.md) - OpenIM 版本的命名和管理策略。 + + +## 对于开发者、贡献者和社区维护者 + +### 开发者和贡献者 + +如果您是一名开发者或热衷于贡献: + +- 熟悉我们的 [Code Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/code-conventions.md) 和 [Git Workflow](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/git-workflow.md),以确保顺利贡献。 +- 深入了解 [Development Guide](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/development.md),掌握 OpenIM 的开发实践。 + +### 社区维护者 + +作为社区维护者: + +- 确保贡献符合我们文档中概述的标准。 +- 定期查看 [Logging Policy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/bash-log.md) 和 [Error Codes](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/error-code.md),以保持最新状态。 + +## 对于用户 + +用户应特别注意: + +- [Docker Installation](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/install-docker.md) - 如果您计划使用 OpenIM 的 Docker 镜像,那么这个将会是必须的。 +- [Docker Image Strategy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/images.md) - 了解可用的镜像以及如何为您的架构选择正确的镜像。 diff --git a/docs/README_zh_TW.md b/docs/README_zh_TW.md new file mode 100644 index 0000000000..8ca00ba17d --- /dev/null +++ b/docs/README_zh_TW.md @@ -0,0 +1,67 @@ +# OpenIM 伺服器文檔 + +歡迎來到 OpenIM 文件中心! 該中心提供全面的指南和手冊,旨在幫助您充分利用 OpenIM 體驗。 + +## 目錄 + +1. [Contrib](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib) - 開發人員貢獻和配置指南 +2. [Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib) - 編碼約定、日誌記錄策略和其他轉換工具 + +------ + +## 貢獻 + +本節為開發人員提供了有關如何貢獻程式碼、設定環境以及遵循相關流程的詳細指南。 + +- [Code Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/code-conventions.md) - 在 OpenIM 中編寫程式碼的規則和約定。 +- [Development Guide](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/development.md) - 有關如何在 OpenIM 中進行開發的指南。 +- [Git Cherry Pick](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/gitcherry-pick.md) - 精挑細選操作指南。 +- [Git Workflow](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/git-workflow.md) - OpenIM 中的 git 工作流程。 +- [Initialization Configurations](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/init-config.md) - 設定和初始化 OpenIM 的指南。 +- [Docker Installation](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/install-docker.md) - 如何在您的電腦上安裝 Docker。 +- [Linux Development Environment](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/linux-development.md) - Linux 上的開發環境設定指南。 +- [Local Actions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/local-actions.md) - 關於如何在當地進行某些共同行動的指南。 +- [Offline Deployment](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/offline-deployment.md) - 離線部署OpenIM的方法。 +- [Protoc Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/protoc-tools.md) - 協議工具使用指南。 +- [Go Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-go.md) - OpenIM 在 Go 中的工具和函式庫。 +- [Makefile Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-makefile.md) - Makefile 的最佳實務和工具。 +- [Script Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-scripts.md) - 腳本的最佳實踐和工具。 + +## 轉換 + +本節介紹 OpenIM 中的各種約定和策略,包括程式碼、日誌、版本等。 + +- [API Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/api.md) - API 轉換的指南和方法。 +- [Logging Policy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/bash-log.md) - OpenIM 中的日誌記錄策略和約定。 +- [CI/CD Actions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/cicd-actions.md) - CI/CD 的程序和約定。 +- [Commit Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/commit.md) - OpenIM 中程式碼提交的約定。 +- [Directory Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/directory.md) - OpenIM 中的目錄結構和約定。 +- [Error Codes](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/error-code.md) - 錯誤代碼的清單和描述。 +- [Go Code Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/go-code.md) - Go 程式碼的約定和轉換。 +- [Docker Image Strategy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/images.md) - OpenIM Docker 映像的管理策略,跨越多種架構和映像儲存庫。 +- [Logging Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/logging.md) - 有關日誌記錄的更詳細約定。 +- [Version Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/version.md) - OpenIM 版本的命名與管理策略。 + + +## 對於開發者、貢獻者和社區維護者 + +### 開發者和貢獻者 + +如果您是開發人員或熱衷於做出貢獻的人: + +- 熟悉我們的 [Code Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/code-conventions.md) 和 [Git Workflow](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/git-workflow.md) 以確保順利貢獻。 +- 深入閱讀 [Development Guide](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/development.md) ,掌握 OpenIM 的開發實務。 + +### 社區維護者 + +作為社區維護者: + +- 確保貢獻符合我們文件中概述的標準。 +- 定期查看 [Logging Policy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/bash-log.md) 和 [Error Codes](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/error-code.md) 以保持更新。 + +## 對於用戶 + +使用者應特別注意: + +- [Docker Installation](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/install-docker.md) - 如果您打算使用 OpenIM 的 Docker 映像,則這是必要的。 +- [Docker Image Strategy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/images.md) - 了解可用的不同影像以及如何為您的架構選擇正確的影像。 \ No newline at end of file From 551781a0ee4ddbfbe9af64b7431866f2d0ee69b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=9B=E8=9B=8B=E7=99=BD?= Date: Thu, 1 Feb 2024 10:10:38 +0800 Subject: [PATCH 018/188] fix document parameter errors (#1848) Co-authored-by: Xinwei Xiong <3293172751NSS@gmail.com> --- docs/contrib/environment.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/contrib/environment.md b/docs/contrib/environment.md index e18246afad..dc11a3c7b8 100644 --- a/docs/contrib/environment.md +++ b/docs/contrib/environment.md @@ -305,6 +305,7 @@ Feel free to explore the MinIO documentation for more advanced configurations an This section involves setting up MongoDB, including its port, address, and credentials. + | Parameter | Example Value | Description | | -------------- | -------------- | ----------------------- | | MONGO_PORT | "27017" | Port used by MongoDB. | From 55ca661d138e548dbd94ad2e557f11482d286ad1 Mon Sep 17 00:00:00 2001 From: Brabem <69128477+luhaoling@users.noreply.github.com> Date: Thu, 1 Feb 2024 10:11:22 +0800 Subject: [PATCH 019/188] Bug: replace the component check func by tools pkg (#1846) * fix: del the manager config and manger init statement * fix: fix the Manger judge condition * fix: fix revokeMsg error * fix: find erors * fix: find error * fix: fix the AdminAccount error * fix: del the debug statement * fix: fix the component check func * fix: fix the get zkAddress error * fix: fix the kafka client close error * fix: add env in minio connected * fix: del the minio env * fix: fix the go.mod tools version * fix: del get env in minio conneted --- go.mod | 12 +- go.sum | 25 ++- pkg/rpcclient/third.go | 4 +- tools/component/component.go | 300 ++++++++++++----------------------- 4 files changed, 123 insertions(+), 218 deletions(-) diff --git a/go.mod b/go.mod index c709e9ba49..a5fecb5eec 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.19 require ( firebase.google.com/go v3.13.0+incompatible github.com/OpenIMSDK/protocol v0.0.48 - github.com/OpenIMSDK/tools v0.0.29 + github.com/OpenIMSDK/tools v0.0.31 github.com/bwmarrin/snowflake v0.3.0 // indirect github.com/dtm-labs/rockscache v0.1.1 github.com/gin-gonic/gin v1.9.1 @@ -31,7 +31,7 @@ require ( gopkg.in/yaml.v3 v3.0.1 ) -require github.com/google/uuid v1.3.1 +require github.com/google/uuid v1.5.0 require ( github.com/IBM/sarama v1.41.3 @@ -94,8 +94,8 @@ require ( github.com/jinzhu/now v1.1.5 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd // indirect - github.com/klauspost/compress v1.16.7 // indirect - github.com/klauspost/cpuid/v2 v2.2.5 // indirect + github.com/klauspost/compress v1.17.4 // indirect + github.com/klauspost/cpuid/v2 v2.2.6 // indirect github.com/leodido/go-urn v1.2.4 // indirect github.com/lithammer/shortuuid v3.0.0+incompatible // indirect github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect @@ -129,7 +129,7 @@ require ( go.uber.org/atomic v1.7.0 // indirect go.uber.org/multierr v1.11.0 // indirect golang.org/x/arch v0.3.0 // indirect - golang.org/x/net v0.17.0 // indirect + golang.org/x/net v0.19.0 // indirect golang.org/x/oauth2 v0.13.0 // indirect golang.org/x/sys v0.15.0 // indirect golang.org/x/text v0.14.0 // indirect @@ -141,7 +141,7 @@ require ( google.golang.org/genproto/googleapis/rpc v0.0.0-20231012201019-e917dd12ba7a // indirect gopkg.in/src-d/go-billy.v4 v4.3.2 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect - gorm.io/gorm v1.23.8 // indirect + gorm.io/gorm v1.25.4 // indirect stathat.com/c/consistent v1.0.0 // indirect ) diff --git a/go.sum b/go.sum index b7b40632f9..fbd9366c33 100644 --- a/go.sum +++ b/go.sum @@ -20,8 +20,8 @@ github.com/IBM/sarama v1.41.3 h1:MWBEJ12vHC8coMjdEXFq/6ftO6DUZnQlFYcxtOJFa7c= github.com/IBM/sarama v1.41.3/go.mod h1:Xxho9HkHd4K/MDUo/T/sOqwtX/17D33++E9Wib6hUdQ= github.com/OpenIMSDK/protocol v0.0.48 h1:8MIMjyzJRsruYhVv2ZKArFiOveroaofDOb3dlAdgjsw= github.com/OpenIMSDK/protocol v0.0.48/go.mod h1:F25dFrwrIx3lkNoiuf6FkCfxuwf8L4Z8UIsdTHP/r0Y= -github.com/OpenIMSDK/tools v0.0.29 h1:NS4PEwYl9sX3SWsMjDOLVxMo3LcTWREMr+2cjzWjcqc= -github.com/OpenIMSDK/tools v0.0.29/go.mod h1:eg+q4A34Qmu73xkY0mt37FHGMCMfC6CtmOnm0kFEGFI= +github.com/OpenIMSDK/tools v0.0.31 h1:fSrhcPTvHEMTSyrJZDupe730mL4nuhvSOUP/BaZiHaY= +github.com/OpenIMSDK/tools v0.0.31/go.mod h1:wBfR5CYmEyvxl03QJbTkhz1CluK6J4/lX0lviu8JAjE= github.com/QcloudApi/qcloud_sign_golang v0.0.0-20141224014652-e4130a326409/go.mod h1:1pk82RBxDY/JZnPQrtqHlUFfCctgdorsd9M06fMynOM= github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7 h1:uSoVVbwJiQipAclBbw+8quDsfcvFjOpI5iCf4p/cqCs= github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs= @@ -152,8 +152,8 @@ github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o= github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= -github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU= +github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/enterprise-certificate-proxy v0.3.1 h1:SBWmZhjUDRorQxrN0nwzf+AHBxnbFjViHQS4P0yVpmQ= github.com/googleapis/enterprise-certificate-proxy v0.3.1/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= github.com/googleapis/gax-go/v2 v2.12.0 h1:A+gCJKdRfqXkr+BIRGtZLibNXf0m1f9E4HG56etFpas= @@ -194,7 +194,6 @@ github.com/jinzhu/copier v0.3.5 h1:GlvfUwHk62RokgqVNvYsku0TATCF7bAHVwEXoBh3iJg= github.com/jinzhu/copier v0.3.5/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= -github.com/jinzhu/now v1.1.4/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= 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= @@ -205,12 +204,12 @@ github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd/go.mod h1:CT github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= -github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I= -github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/klauspost/compress v1.17.4 h1:Ej5ixsIri7BrIjBkRZLTo6ghwrEtHFk7ijlczPW4fZ4= +github.com/klauspost/compress v1.17.4/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM= github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= -github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg= -github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= +github.com/klauspost/cpuid/v2 v2.2.6 h1:ndNyv040zDGIDh8thGkXYjnFtiN02M1PVVF+JE/48xc= +github.com/klauspost/cpuid/v2 v2.2.6/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= @@ -402,8 +401,8 @@ golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= -golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= +golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c= +golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.13.0 h1:jDDenyj+WgFtmV3zYVoi8aE2BwtXFLWOA67ZfNWftiY= golang.org/x/oauth2 v0.13.0/go.mod h1:/JMhi4ZRXAf4HG9LiNmxvk+45+96RUlVThiH8FzNBn0= @@ -531,8 +530,8 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 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.23.8 h1:h8sGJ+biDgBA1AD1Ha9gFCx7h8npU7AsLdlkX0n2TpE= -gorm.io/gorm v1.23.8/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk= +gorm.io/gorm v1.25.4 h1:iyNd8fNAe8W9dvtlgeRI5zSVZPsq3OpcTu37cYcpCmw= +gorm.io/gorm v1.25.4/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k= gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/pkg/rpcclient/third.go b/pkg/rpcclient/third.go index 48a5371122..0d5708fc8e 100755 --- a/pkg/rpcclient/third.go +++ b/pkg/rpcclient/third.go @@ -16,12 +16,10 @@ package rpcclient import ( "context" - "net/url" - "github.com/minio/minio-go/v7" "github.com/minio/minio-go/v7/pkg/credentials" - "google.golang.org/grpc" + "net/url" "github.com/OpenIMSDK/protocol/third" "github.com/OpenIMSDK/tools/discoveryregistry" diff --git a/tools/component/component.go b/tools/component/component.go index 220b845eef..4200b46f56 100644 --- a/tools/component/component.go +++ b/tools/component/component.go @@ -15,44 +15,26 @@ package main import ( - "context" "errors" "flag" "fmt" - "net" - "net/url" "os" "strings" "time" - "github.com/IBM/sarama" + "github.com/OpenIMSDK/tools/component" "github.com/OpenIMSDK/tools/errs" - "github.com/go-zookeeper/zk" - "go.mongodb.org/mongo-driver/mongo" - "go.mongodb.org/mongo-driver/mongo/options" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" - "github.com/minio/minio-go/v7" - "github.com/minio/minio-go/v7/pkg/credentials" - "github.com/redis/go-redis/v9" "gopkg.in/yaml.v3" ) const ( // defaultCfgPath is the default path of the configuration file. - defaultCfgPath = "../../../../../config/config.yaml" - minioHealthCheckDuration = 1 - maxRetry = 300 - componentStartErrCode = 6000 - configErrCode = 6001 - mongoConnTimeout = 30 * time.Second -) - -const ( - colorRed = 31 - colorGreen = 32 - colorYellow = 33 + defaultCfgPath = "../../../../../config/config.yaml" + maxRetry = 300 + componentStartErrCode = 6000 + configErrCode = 6001 ) var ( @@ -103,16 +85,16 @@ func main() { for _, check := range checks { str, err := check.function() if err != nil { - errorPrint(fmt.Sprintf("Starting %s failed, %v", check.name, err)) + component.ErrorPrint(fmt.Sprintf("Starting %s failed, %v", check.name, err)) allSuccess = false break } else { - successPrint(fmt.Sprintf("%s connected successfully, %s", check.name, str)) + component.SuccessPrint(fmt.Sprintf("%s connected successfully, %s", check.name, str)) } } if allSuccess { - successPrint("All components started successfully!") + component.SuccessPrint("All components started successfully!") return } @@ -120,19 +102,6 @@ func main() { os.Exit(1) } -func exactIP(urll string) string { - u, _ := url.Parse(urll) - host, _, err := net.SplitHostPort(u.Host) - if err != nil { - host = u.Host - } - if strings.HasSuffix(host, ":") { - host = host[0 : len(host)-1] - } - - return host -} - // Helper function to get environment variable or default value func getEnv(key, fallback string) string { if value, exists := os.LookupEnv(key); exists { @@ -143,45 +112,23 @@ func getEnv(key, fallback string) string { // checkMongo checks the MongoDB connection without retries func checkMongo() (string, error) { - uri := getEnv("MONGO_URI", buildMongoURI()) - - ctx, cancel := context.WithTimeout(context.Background(), mongoConnTimeout) - defer cancel() - - str := "ths addr is:" + strings.Join(config.Config.Mongo.Address, ",") - - client, err := mongo.Connect(ctx, options.Client().ApplyURI(uri)) - if err != nil { - return "", errs.Wrap(errStr(err, str)) + mongo := &component.Mongo{ + Address: config.Config.Mongo.Address, + Database: config.Config.Mongo.Database, + Username: config.Config.Mongo.Username, + Password: config.Config.Mongo.Password, + MaxPoolSize: config.Config.Mongo.MaxPoolSize, } - defer client.Disconnect(context.Background()) - - ctx, cancel = context.WithTimeout(context.Background(), mongoConnTimeout) - defer cancel() - - if err = client.Ping(ctx, nil); err != nil { - return "", errs.Wrap(errStr(err, str)) + uri, uriExist := os.LookupEnv("MONGO_URI") + if uriExist { + mongo.URL = uri } - return str, nil -} - -// buildMongoURI constructs the MongoDB URI using configuration settings -func buildMongoURI() string { - // Fallback to config if environment variables are not set - username := config.Config.Mongo.Username - password := config.Config.Mongo.Password - database := config.Config.Mongo.Database - maxPoolSize := config.Config.Mongo.MaxPoolSize - - mongodbHosts := strings.Join(config.Config.Mongo.Address, ",") - - if username != "" && password != "" { - return fmt.Sprintf("mongodb://%s:%s@%s/%s?maxPoolSize=%d", - username, password, mongodbHosts, database, maxPoolSize) + str, err := component.CheckMongo(mongo) + if err != nil { + return "", err } - return fmt.Sprintf("mongodb://%s/%s?maxPoolSize=%d", - mongodbHosts, database, maxPoolSize) + return str, nil } // checkMinio checks the MinIO connection @@ -191,52 +138,24 @@ func checkMinio() (string, error) { return "", nil } - // Prioritize environment variables - endpoint := getEnv("MINIO_ENDPOINT", config.Config.Object.Minio.Endpoint) - accessKeyID := getEnv("MINIO_ACCESS_KEY_ID", config.Config.Object.Minio.AccessKeyID) - secretAccessKey := getEnv("MINIO_SECRET_ACCESS_KEY", config.Config.Object.Minio.SecretAccessKey) - useSSL := getEnv("MINIO_USE_SSL", "false") // Assuming SSL is not used by default - - if endpoint == "" || accessKeyID == "" || secretAccessKey == "" { - return "", ErrConfig.Wrap("MinIO configuration missing") - } - - // Parse endpoint URL to determine if SSL is enabled - u, err := url.Parse(endpoint) + endpoint, err := getMinioAddr("MINIO_ENDPOINT", "MINIO_ADDRESS", "MINIO_PORT", config.Config.Object.Minio.Endpoint) if err != nil { - str := "the endpoint is:" + endpoint - return "", errs.Wrap(errStr(err, str)) - } - secure := u.Scheme == "https" || useSSL == "true" - - // Initialize MinIO client - minioClient, err := minio.New(u.Host, &minio.Options{ - Creds: credentials.NewStaticV4(accessKeyID, secretAccessKey, ""), - Secure: secure, - }) - str := "ths addr is:" + u.Host - if err != nil { - strs := fmt.Sprintf("%v;host:%s,accessKeyID:%s,secretAccessKey:%s,Secure:%v", err, u.Host, accessKeyID, secretAccessKey, secure) - return "", errs.Wrap(err, strs) + return "", err } - // Perform health check - cancel, err := minioClient.HealthCheck(time.Duration(minioHealthCheckDuration) * time.Second) - if err != nil { - return "", errs.Wrap(errStr(err, str)) + minio := &component.Minio{ + ApiURL: config.Config.Object.ApiURL, + Endpoint: endpoint, + AccessKeyID: getEnv("MINIO_ACCESS_KEY_ID", config.Config.Object.Minio.AccessKeyID), + SecretAccessKey: getEnv("MINIO_SECRET_ACCESS_KEY", config.Config.Object.Minio.SecretAccessKey), + SignEndpoint: config.Config.Object.Minio.SignEndpoint, + UseSSL: getEnv("MINIO_USE_SSL", "false"), } - defer cancel() - if minioClient.IsOffline() { - str := fmt.Sprintf("Minio server is offline;%s", str) - return "", ErrComponentStart.Wrap(str) - } - - // Check for localhost in API URL and Minio SignEndpoint - if exactIP(config.Config.Object.ApiURL) == "127.0.0.1" || exactIP(config.Config.Object.Minio.SignEndpoint) == "127.0.0.1" { - return "", ErrConfig.Wrap("apiURL or Minio SignEndpoint endpoint contain 127.0.0.1") + str, err := component.CheckMinio(minio) + if err != nil { + return "", err } - return str, nil } @@ -247,76 +166,48 @@ func checkRedis() (string, error) { username := getEnv("REDIS_USERNAME", config.Config.Redis.Username) password := getEnv("REDIS_PASSWORD", config.Config.Redis.Password) - // Split address to handle multiple addresses for cluster setup - redisAddresses := strings.Split(address, ",") - - var redisClient redis.UniversalClient - if len(redisAddresses) > 1 { - // Use cluster client for multiple addresses - redisClient = redis.NewClusterClient(&redis.ClusterOptions{ - Addrs: redisAddresses, - Username: username, - Password: password, - }) - } else { - // Use regular client for single address - redisClient = redis.NewClient(&redis.Options{ - Addr: redisAddresses[0], - Username: username, - Password: password, - }) + redis := &component.Redis{ + Address: strings.Split(address, ","), + Username: username, + Password: password, } - defer redisClient.Close() - // Ping Redis to check connectivity - _, err := redisClient.Ping(context.Background()).Result() - str := "the addr is:" + strings.Join(redisAddresses, ",") + addresses, err := getAddress("REDIS_ADDRESS", "REDIS_PORT", config.Config.Redis.Address) if err != nil { - return "", errs.Wrap(errStr(err, str)) + return "", err } + redis.Address = addresses + str, err := component.CheckRedis(redis) + if err != nil { + return "", err + } return str, nil } // checkZookeeper checks the Zookeeper connection func checkZookeeper() (string, error) { // Prioritize environment variables - schema := getEnv("ZOOKEEPER_SCHEMA", "digest") + address := getEnv("ZOOKEEPER_ADDRESS", strings.Join(config.Config.Zookeeper.ZkAddr, ",")) - username := getEnv("ZOOKEEPER_USERNAME", config.Config.Zookeeper.Username) - password := getEnv("ZOOKEEPER_PASSWORD", config.Config.Zookeeper.Password) - // Split addresses to handle multiple Zookeeper nodes - zookeeperAddresses := strings.Split(address, ",") + zk := &component.Zookeeper{ + Schema: getEnv("ZOOKEEPER_SCHEMA", "digest"), + ZkAddr: strings.Split(address, ","), + Username: getEnv("ZOOKEEPER_USERNAME", config.Config.Zookeeper.Username), + Password: getEnv("ZOOKEEPER_PASSWORD", config.Config.Zookeeper.Password), + } - // Connect to Zookeeper - str := "the addr is:" + address - c, eventChan, err := zk.Connect(zookeeperAddresses, time.Second) // Adjust the timeout as necessary + addresses, err := getAddress("ZOOKEEPER_ADDRESS", "ZOOKEEPER_PORT", config.Config.Zookeeper.ZkAddr) if err != nil { - return "", errs.Wrap(errStr(err, str)) - } - timeout := time.After(5 * time.Second) - for { - select { - case event := <-eventChan: - if event.State == zk.StateConnected { - fmt.Println("Connected to Zookeeper") - goto Connected - } - case <-timeout: - return "", errs.Wrap(errors.New("timeout waiting for Zookeeper connection"), "Zookeeper Addr: "+strings.Join(config.Config.Zookeeper.ZkAddr, " ")) - } + return "", nil } -Connected: - defer c.Close() + zk.ZkAddr = addresses - // Set authentication if username and password are provided - if username != "" && password != "" { - if err := c.AddAuth(schema, []byte(username+":"+password)); err != nil { - return "", errs.Wrap(errStr(err, str)) - } + str, err := component.CheckZookeeper(zk) + if err != nil { + return "", err } - return str, nil } @@ -327,24 +218,21 @@ func checkKafka() (string, error) { password := getEnv("KAFKA_PASSWORD", config.Config.Kafka.Password) address := getEnv("KAFKA_ADDRESS", strings.Join(config.Config.Kafka.Addr, ",")) - // Split addresses to handle multiple Kafka brokers - kafkaAddresses := strings.Split(address, ",") + kafka := &component.Kafka{ + Username: username, + Password: password, + Addr: strings.Split(address, ","), + } - // Configure Kafka client - cfg := sarama.NewConfig() - if username != "" && password != "" { - cfg.Net.SASL.Enable = true - cfg.Net.SASL.User = username - cfg.Net.SASL.Password = password + addresses, err := getAddress("KAFKA_ADDRESS", "KAFKA_PORT", config.Config.Kafka.Addr) + if err != nil { + return "", nil } - // Additional Kafka setup (e.g., TLS configuration) can be added here - // kafka.SetupTLSConfig(cfg) + kafka.Addr = addresses - // Create Kafka client - str := "the addr is:" + address - kafkaClient, err := sarama.NewClient(kafkaAddresses, cfg) + str, kafkaClient, err := component.CheckKafka(kafka) if err != nil { - return "", errs.Wrap(errStr(err, str)) + return "", err } defer kafkaClient.Close() @@ -379,22 +267,42 @@ func isTopicPresent(topic string, topics []string) bool { return false } -func colorPrint(colorCode int, format string, a ...interface{}) { - fmt.Printf("\x1b[%dm%s\x1b[0m\n", colorCode, fmt.Sprintf(format, a...)) -} - -func errorPrint(s string) { - colorPrint(colorRed, "%v", s) -} - -func successPrint(s string) { - colorPrint(colorGreen, "%v", s) -} +func getAddress(key1, key2 string, fallback []string) ([]string, error) { + address, addrExist := os.LookupEnv(key1) + port, portExist := os.LookupEnv(key2) -func warningPrint(s string) { - colorPrint(colorYellow, "Warning: But %v", s) + if addrExist && portExist { + addresses := strings.Split(address, ",") + for i, addr := range addresses { + addresses[i] = addr + ":" + port + } + return addresses, nil + } else if !addrExist && portExist { + result := make([]string, len(config.Config.Redis.Address)) + for i, addr := range config.Config.Redis.Address { + add := strings.Split(addr, ":") + result[i] = add[0] + ":" + port + } + return result, nil + } else if addrExist && !portExist { + return nil, errs.Wrap(errors.New("the ZOOKEEPER_PORT of minio is empty")) + } + return fallback, nil } -func errStr(err error, str string) error { - return fmt.Errorf("%v;%s", err, str) -} +func getMinioAddr(key1, key2, key3, fallback string) (string, error) { + // Prioritize environment variables + endpoint := getEnv(key1, fallback) + address, addressExist := os.LookupEnv(key2) + port, portExist := os.LookupEnv(key3) + if portExist && addressExist { + endpoint = "http://" + address + ":" + port + } else if !portExist && addressExist { + return "", errs.Wrap(errors.New("the MINIO_PORT of minio is empty")) + } else if portExist && !addressExist { + arr := strings.Split(config.Config.Object.Minio.Endpoint, ":") + arr[2] = port + endpoint = strings.Join(arr, ":") + } + return endpoint, nil +} \ No newline at end of file From c55e03dc70b0fbe9091e9c8d4123546348ecb30f Mon Sep 17 00:00:00 2001 From: OpenIM-Gordon <46924906+FGadvancer@users.noreply.github.com> Date: Fri, 2 Feb 2024 10:11:13 +0800 Subject: [PATCH 020/188] fix: process add errors wrap. (#1862) * fix: process add errors wrap. * fix: process add errors wrap. --- cmd/openim-api/main.go | 25 ++-------- internal/msgtransfer/init.go | 49 +++++++++++-------- .../msgtransfer/online_history_msg_handler.go | 7 +-- .../online_msg_to_mongo_handler.go | 21 +++++--- internal/push/consumer_init.go | 17 ++++--- internal/push/push_handler.go | 10 ++-- internal/push/push_rpc_server.go | 5 +- internal/rpc/msg/server.go | 5 +- internal/tools/cron_task.go | 14 +++--- internal/tools/msg.go | 5 +- pkg/common/db/cache/init_redis.go | 4 +- pkg/common/db/controller/msg.go | 27 +++++++--- pkg/common/db/mgo/conversation.go | 3 +- pkg/common/db/mgo/group.go | 3 +- pkg/common/db/mgo/group_member.go | 3 +- pkg/common/db/mgo/group_request.go | 3 +- pkg/common/db/mgo/user.go | 2 +- pkg/common/db/unrelation/mongo.go | 8 ++- pkg/common/kafka/consumer_group.go | 16 +++--- pkg/common/kafka/producer.go | 9 ++-- pkg/common/startrpc/start.go | 16 +++--- 21 files changed, 142 insertions(+), 110 deletions(-) diff --git a/cmd/openim-api/main.go b/cmd/openim-api/main.go index f0b62e31f7..59e0b7f9e3 100644 --- a/cmd/openim-api/main.go +++ b/cmd/openim-api/main.go @@ -17,6 +17,7 @@ package main import ( "context" "fmt" + "github.com/OpenIMSDK/tools/errs" "net" "net/http" _ "net/http/pprof" @@ -28,8 +29,6 @@ import ( "github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/tools/discoveryregistry" - "github.com/OpenIMSDK/tools/log" - "github.com/openimsdk/open-im-server/v3/internal/api" "github.com/openimsdk/open-im-server/v3/pkg/common/cmd" "github.com/openimsdk/open-im-server/v3/pkg/common/config" @@ -44,55 +43,42 @@ func main() { apiCmd.AddPortFlag() apiCmd.AddApi(run) if err := apiCmd.Execute(); err != nil { - log.ZError(context.Background(), "API command execution failed", err) panic(err.Error()) } } func run(port int, proPort int) error { - log.ZInfo(context.Background(), "Openim api port:", "port", port, "proPort", proPort) - if port == 0 || proPort == 0 { err := "port or proPort is empty:" + strconv.Itoa(port) + "," + strconv.Itoa(proPort) - log.ZError(context.Background(), err, nil) - return fmt.Errorf(err) + return errs.Wrap(fmt.Errorf(err)) } - rdb, err := cache.NewRedis() if err != nil { - log.ZError(context.Background(), "Failed to initialize Redis", err) return err } - log.ZInfo(context.Background(), "api start init discov client") var client discoveryregistry.SvcDiscoveryRegistry // Determine whether zk is passed according to whether it is a clustered deployment client, err = kdisc.NewDiscoveryRegister(config.Config.Envs.Discovery) if err != nil { - log.ZError(context.Background(), "Failed to initialize discovery register", err) - return err + return errs.Wrap(err, "register discovery err") } if err = client.CreateRpcRootNodes(config.Config.GetServiceNames()); err != nil { - log.ZError(context.Background(), "Failed to create RPC root nodes", err) - return err + return errs.Wrap(err, "create rpc root nodes error") } - log.ZInfo(context.Background(), "api register public config to discov") if err = client.RegisterConf2Registry(constant.OpenIMCommonConfigKey, config.Config.EncodeConfig()); err != nil { - log.ZError(context.Background(), "Failed to register public config to discov", err) return err } - log.ZInfo(context.Background(), "api register public config to discov success") router := api.NewGinRouter(client, rdb) if config.Config.Prometheus.Enable { p := ginprom.NewPrometheus("app", prommetrics.GetGinCusMetrics("Api")) p.SetListenAddress(fmt.Sprintf(":%d", proPort)) p.Use(router) } - log.ZInfo(context.Background(), "api init router success") var address string if config.Config.Api.ListenIP != "" { @@ -100,13 +86,11 @@ func run(port int, proPort int) error { } else { address = net.JoinHostPort("0.0.0.0", strconv.Itoa(port)) } - log.ZInfo(context.Background(), "start api server", "address", address, "OpenIM version", config.Version) server := http.Server{Addr: address, Handler: router} go func() { err = server.ListenAndServe() if err != nil && err != http.ErrServerClosed { - log.ZError(context.Background(), "api run failed", err, "address", address) os.Exit(1) } }() @@ -120,7 +104,6 @@ func run(port int, proPort int) error { // graceful shutdown operation. if err := server.Shutdown(ctx); err != nil { - log.ZError(context.Background(), "failed to api-server shutdown", err) return err } diff --git a/internal/msgtransfer/init.go b/internal/msgtransfer/init.go index 7d692662d3..969761a9d6 100644 --- a/internal/msgtransfer/init.go +++ b/internal/msgtransfer/init.go @@ -15,8 +15,10 @@ package msgtransfer import ( + "context" "errors" "fmt" + "github.com/OpenIMSDK/tools/errs" "log" "net/http" "sync" @@ -69,40 +71,47 @@ func StartTransfer(prometheusPort int) error { client.AddOption(mw.GrpcClient(), grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithDefaultServiceConfig(fmt.Sprintf(`{"LoadBalancingPolicy": "%s"}`, "round_robin"))) msgModel := cache.NewMsgCacheModel(rdb) msgDocModel := unrelation.NewMsgMongoDriver(mongo.GetDatabase()) - msgDatabase := controller.NewCommonMsgDatabase(msgDocModel, msgModel) + msgDatabase, err := controller.NewCommonMsgDatabase(msgDocModel, msgModel) + if err != nil { + return err + } conversationRpcClient := rpcclient.NewConversationRpcClient(client) groupRpcClient := rpcclient.NewGroupRpcClient(client) - msgTransfer := NewMsgTransfer(msgDatabase, &conversationRpcClient, &groupRpcClient) + msgTransfer, err := NewMsgTransfer(msgDatabase, &conversationRpcClient, &groupRpcClient) + if err != nil { + return err + } return msgTransfer.Start(prometheusPort) } -func NewMsgTransfer(msgDatabase controller.CommonMsgDatabase, conversationRpcClient *rpcclient.ConversationRpcClient, groupRpcClient *rpcclient.GroupRpcClient) *MsgTransfer { - return &MsgTransfer{ - historyCH: NewOnlineHistoryRedisConsumerHandler(msgDatabase, conversationRpcClient, groupRpcClient), - historyMongoCH: NewOnlineHistoryMongoConsumerHandler(msgDatabase), +func NewMsgTransfer(msgDatabase controller.CommonMsgDatabase, conversationRpcClient *rpcclient.ConversationRpcClient, groupRpcClient *rpcclient.GroupRpcClient) (*MsgTransfer, error) { + historyCH, err := NewOnlineHistoryRedisConsumerHandler(msgDatabase, conversationRpcClient, groupRpcClient) + if err != nil { + return nil, err } + historyMongoCH, err := NewOnlineHistoryMongoConsumerHandler(msgDatabase) + if err != nil { + return nil, err + } + + return &MsgTransfer{ + historyCH: historyCH, + historyMongoCH: historyMongoCH, + }, nil } func (m *MsgTransfer) Start(prometheusPort int) error { + ctx := context.Background() var wg sync.WaitGroup wg.Add(1) fmt.Println("start msg transfer", "prometheusPort:", prometheusPort) if prometheusPort <= 0 { - return errors.New("prometheusPort not correct") - } - if config.Config.ChatPersistenceMysql { - // go m.persistentCH.persistentConsumerGroup.RegisterHandleAndConsumer(m.persistentCH) - } else { - fmt.Println("msg transfer not start mysql consumer") + return errs.Wrap(errors.New("prometheusPort not correct")) } - go m.historyCH.historyConsumerGroup.RegisterHandleAndConsumer(m.historyCH) - go m.historyMongoCH.historyConsumerGroup.RegisterHandleAndConsumer(m.historyMongoCH) - // go m.modifyCH.modifyMsgConsumerGroup.RegisterHandleAndConsumer(m.modifyCH) - /*err := prome.StartPrometheusSrv(prometheusPort) - if err != nil { - return err - }*/ - //////////////////////////// + + go m.historyCH.historyConsumerGroup.RegisterHandleAndConsumer(ctx, m.historyCH) + go m.historyMongoCH.historyConsumerGroup.RegisterHandleAndConsumer(ctx, m.historyMongoCH) + if config.Config.Prometheus.Enable { reg := prometheus.NewRegistry() reg.MustRegister( diff --git a/internal/msgtransfer/online_history_msg_handler.go b/internal/msgtransfer/online_history_msg_handler.go index 127cede716..35af330c95 100644 --- a/internal/msgtransfer/online_history_msg_handler.go +++ b/internal/msgtransfer/online_history_msg_handler.go @@ -87,7 +87,7 @@ func NewOnlineHistoryRedisConsumerHandler( database controller.CommonMsgDatabase, conversationRpcClient *rpcclient.ConversationRpcClient, groupRpcClient *rpcclient.GroupRpcClient, -) *OnlineHistoryRedisConsumerHandler { +) (*OnlineHistoryRedisConsumerHandler, error) { var och OnlineHistoryRedisConsumerHandler och.msgDatabase = database och.msgDistributionCh = make(chan Cmd2Value) // no buffer channel @@ -98,14 +98,15 @@ func NewOnlineHistoryRedisConsumerHandler( } och.conversationRpcClient = conversationRpcClient och.groupRpcClient = groupRpcClient - och.historyConsumerGroup = kafka.NewMConsumerGroup(&kafka.MConsumerGroupConfig{ + var err error + och.historyConsumerGroup, err = kafka.NewMConsumerGroup(&kafka.MConsumerGroupConfig{ KafkaVersion: sarama.V2_0_0_0, OffsetsInitial: sarama.OffsetNewest, IsReturnErr: false, }, []string{config.Config.Kafka.LatestMsgToRedis.Topic}, config.Config.Kafka.Addr, config.Config.Kafka.ConsumerGroupID.MsgToRedis) // statistics.NewStatistics(&och.singleMsgSuccessCount, config.Config.ModuleName.MsgTransferName, fmt.Sprintf("%d // second singleMsgCount insert to mongo", constant.StatisticsTimeInterval), constant.StatisticsTimeInterval) - return &och + return &och, err } func (och *OnlineHistoryRedisConsumerHandler) Run(channelID int) { diff --git a/internal/msgtransfer/online_msg_to_mongo_handler.go b/internal/msgtransfer/online_msg_to_mongo_handler.go index 8ef15fe72e..6e6c4c8195 100644 --- a/internal/msgtransfer/online_msg_to_mongo_handler.go +++ b/internal/msgtransfer/online_msg_to_mongo_handler.go @@ -34,16 +34,21 @@ type OnlineHistoryMongoConsumerHandler struct { msgDatabase controller.CommonMsgDatabase } -func NewOnlineHistoryMongoConsumerHandler(database controller.CommonMsgDatabase) *OnlineHistoryMongoConsumerHandler { +func NewOnlineHistoryMongoConsumerHandler(database controller.CommonMsgDatabase) (*OnlineHistoryMongoConsumerHandler, error) { + historyConsumerGroup, err := kfk.NewMConsumerGroup(&kfk.MConsumerGroupConfig{ + KafkaVersion: sarama.V2_0_0_0, + OffsetsInitial: sarama.OffsetNewest, IsReturnErr: false, + }, []string{config.Config.Kafka.MsgToMongo.Topic}, + config.Config.Kafka.Addr, config.Config.Kafka.ConsumerGroupID.MsgToMongo) + if err != nil { + return nil, err + } + mc := &OnlineHistoryMongoConsumerHandler{ - historyConsumerGroup: kfk.NewMConsumerGroup(&kfk.MConsumerGroupConfig{ - KafkaVersion: sarama.V2_0_0_0, - OffsetsInitial: sarama.OffsetNewest, IsReturnErr: false, - }, []string{config.Config.Kafka.MsgToMongo.Topic}, - config.Config.Kafka.Addr, config.Config.Kafka.ConsumerGroupID.MsgToMongo), - msgDatabase: database, + historyConsumerGroup: historyConsumerGroup, + msgDatabase: database, } - return mc + return mc, nil } func (mc *OnlineHistoryMongoConsumerHandler) handleChatWs2Mongo( diff --git a/internal/push/consumer_init.go b/internal/push/consumer_init.go index b72c32bb13..ceab861653 100644 --- a/internal/push/consumer_init.go +++ b/internal/push/consumer_init.go @@ -14,19 +14,24 @@ package push +import "context" + type Consumer struct { pushCh ConsumerHandler successCount uint64 } -func NewConsumer(pusher *Pusher) *Consumer { - return &Consumer{ - pushCh: *NewConsumerHandler(pusher), +func NewConsumer(pusher *Pusher) (*Consumer, error) { + c, err := NewConsumerHandler(pusher) + if err != nil { + return nil, err } + return &Consumer{ + pushCh: *c, + }, nil } func (c *Consumer) Start() { - // statistics.NewStatistics(&c.successCount, config.Config.ModuleName.PushName, fmt.Sprintf("%d second push to - // msg_gateway count", constant.StatisticsTimeInterval), constant.StatisticsTimeInterval) - go c.pushCh.pushConsumerGroup.RegisterHandleAndConsumer(&c.pushCh) + + go c.pushCh.pushConsumerGroup.RegisterHandleAndConsumer(context.Background(), &c.pushCh) } diff --git a/internal/push/push_handler.go b/internal/push/push_handler.go index c91206ecc2..19d42ebb9e 100644 --- a/internal/push/push_handler.go +++ b/internal/push/push_handler.go @@ -35,15 +35,19 @@ type ConsumerHandler struct { pusher *Pusher } -func NewConsumerHandler(pusher *Pusher) *ConsumerHandler { +func NewConsumerHandler(pusher *Pusher) (*ConsumerHandler, error) { var consumerHandler ConsumerHandler consumerHandler.pusher = pusher - consumerHandler.pushConsumerGroup = kfk.NewMConsumerGroup(&kfk.MConsumerGroupConfig{ + var err error + consumerHandler.pushConsumerGroup, err = kfk.NewMConsumerGroup(&kfk.MConsumerGroupConfig{ KafkaVersion: sarama.V2_0_0_0, OffsetsInitial: sarama.OffsetNewest, IsReturnErr: false, }, []string{config.Config.Kafka.MsgToPush.Topic}, config.Config.Kafka.Addr, config.Config.Kafka.ConsumerGroupID.MsgToPush) - return &consumerHandler + if err != nil { + return nil, err + } + return &consumerHandler, nil } func (c *ConsumerHandler) handleMs2PsChat(ctx context.Context, msg []byte) { diff --git a/internal/push/push_rpc_server.go b/internal/push/push_rpc_server.go index 188ddc0e15..c1226ce6bc 100644 --- a/internal/push/push_rpc_server.go +++ b/internal/push/push_rpc_server.go @@ -66,9 +66,12 @@ func Start(client discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) e pusher: pusher, }) }() + consumer, err := NewConsumer(pusher) + if err != nil { + return err + } go func() { defer wg.Done() - consumer := NewConsumer(pusher) consumer.Start() }() wg.Wait() diff --git a/internal/rpc/msg/server.go b/internal/rpc/msg/server.go index 88be287fd5..fe1baa4531 100644 --- a/internal/rpc/msg/server.go +++ b/internal/rpc/msg/server.go @@ -80,7 +80,10 @@ func Start(client discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) e userRpcClient := rpcclient.NewUserRpcClient(client) groupRpcClient := rpcclient.NewGroupRpcClient(client) friendRpcClient := rpcclient.NewFriendRpcClient(client) - msgDatabase := controller.NewCommonMsgDatabase(msgDocModel, cacheModel) + msgDatabase, err := controller.NewCommonMsgDatabase(msgDocModel, cacheModel) + if err != nil { + return err + } s := &msgServer{ Conversation: &conversationClient, User: &userRpcClient, diff --git a/internal/tools/cron_task.go b/internal/tools/cron_task.go index e22504bbbf..cf2068d8ec 100644 --- a/internal/tools/cron_task.go +++ b/internal/tools/cron_task.go @@ -17,6 +17,7 @@ package tools import ( "context" "fmt" + "github.com/OpenIMSDK/tools/errs" "os" "os/signal" "syscall" @@ -25,14 +26,13 @@ import ( "github.com/redis/go-redis/v9" "github.com/robfig/cron/v3" - "github.com/OpenIMSDK/tools/log" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" ) func StartTask() error { fmt.Println("cron task start, config", config.Config.ChatRecordsClearTime) + msgTool, err := InitMsgTool() if err != nil { return err @@ -47,18 +47,16 @@ func StartTask() error { // register cron tasks var crontab = cron.New() - log.ZInfo(context.Background(), "start chatRecordsClearTime cron task", "cron config", config.Config.ChatRecordsClearTime) + fmt.Println("start chatRecordsClearTime cron task", "cron config", config.Config.ChatRecordsClearTime) _, err = crontab.AddFunc(config.Config.ChatRecordsClearTime, cronWrapFunc(rdb, "cron_clear_msg_and_fix_seq", msgTool.AllConversationClearMsgAndFixSeq)) if err != nil { - log.ZError(context.Background(), "start allConversationClearMsgAndFixSeq cron failed", err) - panic(err) + return errs.Wrap(err) } - log.ZInfo(context.Background(), "start msgDestruct cron task", "cron config", config.Config.MsgDestructTime) + fmt.Println("start msgDestruct cron task", "cron config", config.Config.MsgDestructTime) _, err = crontab.AddFunc(config.Config.MsgDestructTime, cronWrapFunc(rdb, "cron_conversations_destruct_msgs", msgTool.ConversationsDestructMsgs)) if err != nil { - log.ZError(context.Background(), "start conversationsDestructMsgs cron failed", err) - panic(err) + return errs.Wrap(err) } // start crontab diff --git a/internal/tools/msg.go b/internal/tools/msg.go index 30006670e5..1ec1e03a25 100644 --- a/internal/tools/msg.go +++ b/internal/tools/msg.go @@ -84,7 +84,10 @@ func InitMsgTool() (*MsgTool, error) { if err != nil { return nil, err } - msgDatabase := controller.InitCommonMsgDatabase(rdb, mongo.GetDatabase()) + msgDatabase, err := controller.InitCommonMsgDatabase(rdb, mongo.GetDatabase()) + if err != nil { + return nil, err + } userMongoDB := unrelation.NewUserMongoDriver(mongo.GetDatabase()) ctxTx := tx.NewMongo(mongo.GetClient()) userDatabase := controller.NewUserDatabase( diff --git a/pkg/common/db/cache/init_redis.go b/pkg/common/db/cache/init_redis.go index 1308e96498..c593089e6d 100644 --- a/pkg/common/db/cache/init_redis.go +++ b/pkg/common/db/cache/init_redis.go @@ -49,7 +49,7 @@ func NewRedis() (redis.UniversalClient, error) { overrideConfigFromEnv() if len(config.Config.Redis.Address) == 0 { - return nil, errors.New("redis address is empty") + return nil, errs.Wrap(errors.New("redis address is empty")) } specialerror.AddReplace(redis.Nil, errs.ErrRecordNotFound) var rdb redis.UniversalClient @@ -77,7 +77,7 @@ func NewRedis() (redis.UniversalClient, error) { defer cancel() err = rdb.Ping(ctx).Err() if err != nil { - return nil, fmt.Errorf("redis ping %w", err) + return nil, errs.Wrap(fmt.Errorf("redis ping %w", err)) } redisClient = rdb diff --git a/pkg/common/db/controller/msg.go b/pkg/common/db/controller/msg.go index dfff5c61de..b841a7d310 100644 --- a/pkg/common/db/controller/msg.go +++ b/pkg/common/db/controller/msg.go @@ -126,21 +126,32 @@ type CommonMsgDatabase interface { ConvertMsgsDocLen(ctx context.Context, conversationIDs []string) } -func NewCommonMsgDatabase(msgDocModel unrelationtb.MsgDocModelInterface, cacheModel cache.MsgModel) CommonMsgDatabase { +func NewCommonMsgDatabase(msgDocModel unrelationtb.MsgDocModelInterface, cacheModel cache.MsgModel) (CommonMsgDatabase, error) { + producerToRedis, err := kafka.NewKafkaProducer(config.Config.Kafka.Addr, config.Config.Kafka.LatestMsgToRedis.Topic) + if err != nil { + return nil, err + } + producerToMongo, err := kafka.NewKafkaProducer(config.Config.Kafka.Addr, config.Config.Kafka.MsgToMongo.Topic) + if err != nil { + return nil, err + } + producerToPush, err := kafka.NewKafkaProducer(config.Config.Kafka.Addr, config.Config.Kafka.MsgToPush.Topic) + if err != nil { + return nil, err + } return &commonMsgDatabase{ msgDocDatabase: msgDocModel, cache: cacheModel, - producer: kafka.NewKafkaProducer(config.Config.Kafka.Addr, config.Config.Kafka.LatestMsgToRedis.Topic), - producerToMongo: kafka.NewKafkaProducer(config.Config.Kafka.Addr, config.Config.Kafka.MsgToMongo.Topic), - producerToPush: kafka.NewKafkaProducer(config.Config.Kafka.Addr, config.Config.Kafka.MsgToPush.Topic), - } + producer: producerToRedis, + producerToMongo: producerToMongo, + producerToPush: producerToPush, + }, nil } -func InitCommonMsgDatabase(rdb redis.UniversalClient, database *mongo.Database) CommonMsgDatabase { +func InitCommonMsgDatabase(rdb redis.UniversalClient, database *mongo.Database) (CommonMsgDatabase, error) { cacheModel := cache.NewMsgCacheModel(rdb) msgDocModel := unrelation.NewMsgMongoDriver(database) - CommonMsgDatabase := NewCommonMsgDatabase(msgDocModel, cacheModel) - return CommonMsgDatabase + return NewCommonMsgDatabase(msgDocModel, cacheModel) } type commonMsgDatabase struct { diff --git a/pkg/common/db/mgo/conversation.go b/pkg/common/db/mgo/conversation.go index 1614cfec5f..0b8d597dcf 100644 --- a/pkg/common/db/mgo/conversation.go +++ b/pkg/common/db/mgo/conversation.go @@ -16,6 +16,7 @@ package mgo import ( "context" + "github.com/OpenIMSDK/tools/errs" "time" "github.com/OpenIMSDK/protocol/constant" @@ -38,7 +39,7 @@ func NewConversationMongo(db *mongo.Database) (*ConversationMgo, error) { Options: options.Index().SetUnique(true), }) if err != nil { - return nil, err + return nil, errs.Wrap(err) } return &ConversationMgo{coll: coll}, nil } diff --git a/pkg/common/db/mgo/group.go b/pkg/common/db/mgo/group.go index a9c6d1eb8c..9a4c660a60 100644 --- a/pkg/common/db/mgo/group.go +++ b/pkg/common/db/mgo/group.go @@ -16,6 +16,7 @@ package mgo import ( "context" + "github.com/OpenIMSDK/tools/errs" "time" "github.com/OpenIMSDK/tools/mgoutil" @@ -36,7 +37,7 @@ func NewGroupMongo(db *mongo.Database) (relation.GroupModelInterface, error) { Options: options.Index().SetUnique(true), }) if err != nil { - return nil, err + return nil, errs.Wrap(err) } return &GroupMgo{coll: coll}, nil } diff --git a/pkg/common/db/mgo/group_member.go b/pkg/common/db/mgo/group_member.go index 8e3dd1efaa..fce79830e2 100644 --- a/pkg/common/db/mgo/group_member.go +++ b/pkg/common/db/mgo/group_member.go @@ -16,6 +16,7 @@ package mgo import ( "context" + "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/tools/mgoutil" @@ -37,7 +38,7 @@ func NewGroupMember(db *mongo.Database) (relation.GroupMemberModelInterface, err Options: options.Index().SetUnique(true), }) if err != nil { - return nil, err + return nil, errs.Wrap(err) } return &GroupMemberMgo{coll: coll}, nil } diff --git a/pkg/common/db/mgo/group_request.go b/pkg/common/db/mgo/group_request.go index cb04d23081..dce0878ee7 100644 --- a/pkg/common/db/mgo/group_request.go +++ b/pkg/common/db/mgo/group_request.go @@ -16,6 +16,7 @@ package mgo import ( "context" + "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/mgoutil" "github.com/OpenIMSDK/tools/pagination" @@ -36,7 +37,7 @@ func NewGroupRequestMgo(db *mongo.Database) (relation.GroupRequestModelInterface Options: options.Index().SetUnique(true), }) if err != nil { - return nil, err + return nil, errs.Wrap(err) } return &GroupRequestMgo{coll: coll}, nil } diff --git a/pkg/common/db/mgo/user.go b/pkg/common/db/mgo/user.go index 34a25ed08e..2797bc53ff 100644 --- a/pkg/common/db/mgo/user.go +++ b/pkg/common/db/mgo/user.go @@ -40,7 +40,7 @@ func NewUserMongo(db *mongo.Database) (relation.UserModelInterface, error) { Options: options.Index().SetUnique(true), }) if err != nil { - return nil, err + return nil, errs.Wrap(err) } return &UserMgo{coll: coll}, nil } diff --git a/pkg/common/db/unrelation/mongo.go b/pkg/common/db/unrelation/mongo.go index b8184d767a..e07c5b7f43 100644 --- a/pkg/common/db/unrelation/mongo.go +++ b/pkg/common/db/unrelation/mongo.go @@ -27,8 +27,6 @@ import ( "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/mw/specialerror" - "github.com/OpenIMSDK/tools/utils" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/unrelation" ) @@ -63,9 +61,9 @@ func NewMongo() (*Mongo, error) { time.Sleep(time.Second) // exponential backoff could be implemented here continue } - return nil, err + return nil, errs.Wrap(err) } - return nil, err + return nil, errs.Wrap(err) } func buildMongoURI() string { @@ -150,7 +148,7 @@ func (m *Mongo) createMongoIndex(collection string, isUnique bool, keys ...strin _, err := indexView.CreateOne(context.Background(), index, opts) if err != nil { - return utils.Wrap(err, "CreateIndex") + return errs.Wrap(err, "CreateIndex") } return nil } diff --git a/pkg/common/kafka/consumer_group.go b/pkg/common/kafka/consumer_group.go index 1eb7b522a8..05006f582c 100644 --- a/pkg/common/kafka/consumer_group.go +++ b/pkg/common/kafka/consumer_group.go @@ -16,6 +16,8 @@ package kafka import ( "context" + "github.com/OpenIMSDK/tools/errs" + "strings" "github.com/OpenIMSDK/tools/log" @@ -36,7 +38,7 @@ type MConsumerGroupConfig struct { IsReturnErr bool } -func NewMConsumerGroup(consumerConfig *MConsumerGroupConfig, topics, addrs []string, groupID string) *MConsumerGroup { +func NewMConsumerGroup(consumerConfig *MConsumerGroupConfig, topics, addrs []string, groupID string) (*MConsumerGroup, error) { consumerGroupConfig := sarama.NewConfig() consumerGroupConfig.Version = consumerConfig.KafkaVersion consumerGroupConfig.Consumer.Offsets.Initial = consumerConfig.OffsetsInitial @@ -49,26 +51,28 @@ func NewMConsumerGroup(consumerConfig *MConsumerGroupConfig, topics, addrs []str SetupTLSConfig(consumerGroupConfig) consumerGroup, err := sarama.NewConsumerGroup(addrs, groupID, consumerGroupConfig) if err != nil { - panic(err.Error()) + return nil, errs.Wrap(err, strings.Join(topics, ","), strings.Join(addrs, ","), groupID) } return &MConsumerGroup{ consumerGroup, groupID, topics, - } + }, nil } func (mc *MConsumerGroup) GetContextFromMsg(cMsg *sarama.ConsumerMessage) context.Context { return GetContextWithMQHeader(cMsg.Headers) } -func (mc *MConsumerGroup) RegisterHandleAndConsumer(handler sarama.ConsumerGroupHandler) { +func (mc *MConsumerGroup) RegisterHandleAndConsumer(ctx context.Context, handler sarama.ConsumerGroupHandler) { log.ZDebug(context.Background(), "register consumer group", "groupID", mc.groupID) - ctx := context.Background() for { err := mc.ConsumerGroup.Consume(ctx, mc.topics, handler) if err != nil { - panic(err.Error()) + log.ZWarn(ctx, "consume err", err, "topic", mc.topics, "groupID", mc.groupID) + } + if ctx.Err() != nil { + return } } } diff --git a/pkg/common/kafka/producer.go b/pkg/common/kafka/producer.go index 06b1e2b4c0..b9f0b46568 100644 --- a/pkg/common/kafka/producer.go +++ b/pkg/common/kafka/producer.go @@ -18,6 +18,7 @@ import ( "bytes" "context" "errors" + "github.com/OpenIMSDK/tools/errs" "strings" "time" @@ -44,7 +45,7 @@ type Producer struct { } // NewKafkaProducer initializes a new Kafka producer. -func NewKafkaProducer(addr []string, topic string) *Producer { +func NewKafkaProducer(addr []string, topic string) (*Producer, error) { p := Producer{ addr: addr, topic: topic, @@ -87,17 +88,17 @@ func NewKafkaProducer(addr []string, topic string) *Producer { for i := 0; i <= maxRetry; i++ { p.producer, err = sarama.NewSyncProducer(p.addr, p.config) if err == nil { - return &p + return &p, nil } time.Sleep(1 * time.Second) // Wait before retrying } // Panic if unable to create producer after retries if err != nil { - panic("Failed to create Kafka producer: " + err.Error()) + return nil, errs.Wrap(errors.New("failed to create Kafka producer: " + err.Error())) } - return &p + return &p, nil } // configureProducerAck configures the producer's acknowledgement level. diff --git a/pkg/common/startrpc/start.go b/pkg/common/startrpc/start.go index 8295404d3a..31fe4fdd56 100644 --- a/pkg/common/startrpc/start.go +++ b/pkg/common/startrpc/start.go @@ -17,6 +17,7 @@ package startrpc import ( "errors" "fmt" + "github.com/OpenIMSDK/tools/errs" "log" "net" "net/http" @@ -43,7 +44,6 @@ import ( "github.com/OpenIMSDK/tools/discoveryregistry" "github.com/OpenIMSDK/tools/mw" "github.com/OpenIMSDK/tools/network" - "github.com/OpenIMSDK/tools/utils" ) // Start rpc server. @@ -61,20 +61,20 @@ func Start( net.JoinHostPort(network.GetListenIP(config.Config.Rpc.ListenIP), strconv.Itoa(rpcPort)), ) if err != nil { - return err + return errs.Wrap(err, network.GetListenIP(config.Config.Rpc.ListenIP), strconv.Itoa(rpcPort)) } defer listener.Close() client, err := kdisc.NewDiscoveryRegister(config.Config.Envs.Discovery) if err != nil { - return utils.Wrap1(err) + return errs.Wrap(err) } defer client.Close() client.AddOption(mw.GrpcClient(), grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithDefaultServiceConfig(fmt.Sprintf(`{"LoadBalancingPolicy": "%s"}`, "round_robin"))) registerIP, err := network.GetRpcRegisterIP(config.Config.Rpc.RegisterIP) if err != nil { - return err + return errs.Wrap(err) } var reg *prometheus.Registry @@ -96,7 +96,7 @@ func Start( err = rpcFn(client, srv) if err != nil { - return utils.Wrap1(err) + return errs.Wrap(err) } err = client.Register( rpcRegisterName, @@ -105,7 +105,7 @@ func Start( grpc.WithTransportCredentials(insecure.NewCredentials()), ) if err != nil { - return utils.Wrap1(err) + return errs.Wrap(err) } var wg errgroup.Group @@ -123,7 +123,7 @@ func Start( }) wg.Go(func() error { - return utils.Wrap1(srv.Serve(listener)) + return errs.Wrap(srv.Serve(listener)) }) sigs := make(chan os.Signal, 1) @@ -146,7 +146,7 @@ func Start( return gerr case <-time.After(15 * time.Second): - return utils.Wrap1(errors.New("timeout exit")) + return errs.Wrap(errors.New("timeout exit")) } } From bb862bd20768d0b2701cca1ef8d1e3fd3322169e Mon Sep 17 00:00:00 2001 From: OpenIM Bot <124379614+kubbot@users.noreply.github.com> Date: Fri, 2 Feb 2024 11:41:01 +0800 Subject: [PATCH 021/188] cicd: bump League Patch (#1863) --- pkg/rpcclient/third.go | 3 ++- tools/component/component.go | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/pkg/rpcclient/third.go b/pkg/rpcclient/third.go index 0d5708fc8e..73d8740051 100755 --- a/pkg/rpcclient/third.go +++ b/pkg/rpcclient/third.go @@ -16,10 +16,11 @@ package rpcclient import ( "context" + "net/url" + "github.com/minio/minio-go/v7" "github.com/minio/minio-go/v7/pkg/credentials" "google.golang.org/grpc" - "net/url" "github.com/OpenIMSDK/protocol/third" "github.com/OpenIMSDK/tools/discoveryregistry" diff --git a/tools/component/component.go b/tools/component/component.go index 4200b46f56..823d8174bb 100644 --- a/tools/component/component.go +++ b/tools/component/component.go @@ -24,6 +24,7 @@ import ( "github.com/OpenIMSDK/tools/component" "github.com/OpenIMSDK/tools/errs" + "github.com/openimsdk/open-im-server/v3/pkg/common/config" "gopkg.in/yaml.v3" @@ -305,4 +306,4 @@ func getMinioAddr(key1, key2, key3, fallback string) (string, error) { endpoint = strings.Join(arr, ":") } return endpoint, nil -} \ No newline at end of file +} From f551b50e7909f012457add662c42937be10dd6d7 Mon Sep 17 00:00:00 2001 From: Brabem <69128477+luhaoling@users.noreply.github.com> Date: Fri, 2 Feb 2024 16:21:14 +0800 Subject: [PATCH 022/188] fix: Refactoring the code for component detection (#1868) * feat: add component check func * fix: fix the outpu error * fix: fix the stderr outpu * fix: fix the component check func * fix: fix the error * fix: fix the output error * fix: del the disruptions code * fix the log output format * fix: fix the tools version --- go.mod | 2 +- go.sum | 4 +- pkg/common/db/cache/init_redis.go | 5 +- pkg/common/db/unrelation/mongo.go | 4 +- .../discoveryregister/zookeeper/zookeeper.go | 14 +- pkg/common/kafka/consumer_group.go | 2 +- tools/component/component.go | 249 +++++++----------- 7 files changed, 115 insertions(+), 165 deletions(-) diff --git a/go.mod b/go.mod index a5fecb5eec..16a10a945e 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.19 require ( firebase.google.com/go v3.13.0+incompatible github.com/OpenIMSDK/protocol v0.0.48 - github.com/OpenIMSDK/tools v0.0.31 + github.com/OpenIMSDK/tools v0.0.32 github.com/bwmarrin/snowflake v0.3.0 // indirect github.com/dtm-labs/rockscache v0.1.1 github.com/gin-gonic/gin v1.9.1 diff --git a/go.sum b/go.sum index fbd9366c33..136035cef0 100644 --- a/go.sum +++ b/go.sum @@ -20,8 +20,8 @@ github.com/IBM/sarama v1.41.3 h1:MWBEJ12vHC8coMjdEXFq/6ftO6DUZnQlFYcxtOJFa7c= github.com/IBM/sarama v1.41.3/go.mod h1:Xxho9HkHd4K/MDUo/T/sOqwtX/17D33++E9Wib6hUdQ= github.com/OpenIMSDK/protocol v0.0.48 h1:8MIMjyzJRsruYhVv2ZKArFiOveroaofDOb3dlAdgjsw= github.com/OpenIMSDK/protocol v0.0.48/go.mod h1:F25dFrwrIx3lkNoiuf6FkCfxuwf8L4Z8UIsdTHP/r0Y= -github.com/OpenIMSDK/tools v0.0.31 h1:fSrhcPTvHEMTSyrJZDupe730mL4nuhvSOUP/BaZiHaY= -github.com/OpenIMSDK/tools v0.0.31/go.mod h1:wBfR5CYmEyvxl03QJbTkhz1CluK6J4/lX0lviu8JAjE= +github.com/OpenIMSDK/tools v0.0.32 h1:b8KwtxXKZTsyyHUcZ4OtSo6s/vVXx4HjMuPxH7Kb7Gg= +github.com/OpenIMSDK/tools v0.0.32/go.mod h1:wBfR5CYmEyvxl03QJbTkhz1CluK6J4/lX0lviu8JAjE= github.com/QcloudApi/qcloud_sign_golang v0.0.0-20141224014652-e4130a326409/go.mod h1:1pk82RBxDY/JZnPQrtqHlUFfCctgdorsd9M06fMynOM= github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7 h1:uSoVVbwJiQipAclBbw+8quDsfcvFjOpI5iCf4p/cqCs= github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs= diff --git a/pkg/common/db/cache/init_redis.go b/pkg/common/db/cache/init_redis.go index c593089e6d..3cec73be54 100644 --- a/pkg/common/db/cache/init_redis.go +++ b/pkg/common/db/cache/init_redis.go @@ -77,9 +77,10 @@ func NewRedis() (redis.UniversalClient, error) { defer cancel() err = rdb.Ping(ctx).Err() if err != nil { - return nil, errs.Wrap(fmt.Errorf("redis ping %w", err)) + uriFormat := "address:%s, username:%s, password:%s, clusterMode:%t, enablePipeline:%t" + errMsg := fmt.Sprintf(uriFormat, config.Config.Redis.Address, config.Config.Redis.Username, config.Config.Redis.Password, config.Config.Redis.ClusterMode, config.Config.Redis.EnablePipeline) + return nil, errs.Wrap(err, errMsg) } - redisClient = rdb return rdb, err } diff --git a/pkg/common/db/unrelation/mongo.go b/pkg/common/db/unrelation/mongo.go index e07c5b7f43..fe89c6b8a2 100644 --- a/pkg/common/db/unrelation/mongo.go +++ b/pkg/common/db/unrelation/mongo.go @@ -61,9 +61,9 @@ func NewMongo() (*Mongo, error) { time.Sleep(time.Second) // exponential backoff could be implemented here continue } - return nil, errs.Wrap(err) + return nil, errs.Wrap(err, uri) } - return nil, errs.Wrap(err) + return nil, errs.Wrap(err, uri) } func buildMongoURI() string { diff --git a/pkg/common/discoveryregister/zookeeper/zookeeper.go b/pkg/common/discoveryregister/zookeeper/zookeeper.go index db1a5c6c49..0082e9833d 100644 --- a/pkg/common/discoveryregister/zookeeper/zookeeper.go +++ b/pkg/common/discoveryregister/zookeeper/zookeeper.go @@ -15,6 +15,8 @@ package zookeeper import ( + "fmt" + "github.com/OpenIMSDK/tools/errs" "os" "strings" "time" @@ -33,7 +35,7 @@ func NewZookeeperDiscoveryRegister() (discoveryregistry.SvcDiscoveryRegistry, er username := getEnv("ZOOKEEPER_USERNAME", config.Config.Zookeeper.Username) password := getEnv("ZOOKEEPER_PASSWORD", config.Config.Zookeeper.Password) - return openkeeper.NewClient( + zk, err := openkeeper.NewClient( zkAddr, schema, openkeeper.WithFreq(time.Hour), @@ -42,6 +44,16 @@ func NewZookeeperDiscoveryRegister() (discoveryregistry.SvcDiscoveryRegistry, er openkeeper.WithTimeout(10), openkeeper.WithLogger(log.NewZkLogger()), ) + if err != nil { + uriFormat := "address:%s, username :%s, password :%s, schema:%s." + errInfo := fmt.Sprintf(uriFormat, + config.Config.Zookeeper.ZkAddr, + config.Config.Zookeeper.Username, + config.Config.Zookeeper.Password, + config.Config.Zookeeper.Schema) + return nil, errs.Wrap(err, errInfo) + } + return zk, nil } // getEnv returns the value of an environment variable if it exists, otherwise it returns the fallback value. diff --git a/pkg/common/kafka/consumer_group.go b/pkg/common/kafka/consumer_group.go index 05006f582c..87e6d56866 100644 --- a/pkg/common/kafka/consumer_group.go +++ b/pkg/common/kafka/consumer_group.go @@ -51,7 +51,7 @@ func NewMConsumerGroup(consumerConfig *MConsumerGroupConfig, topics, addrs []str SetupTLSConfig(consumerGroupConfig) consumerGroup, err := sarama.NewConsumerGroup(addrs, groupID, consumerGroupConfig) if err != nil { - return nil, errs.Wrap(err, strings.Join(topics, ","), strings.Join(addrs, ","), groupID) + return nil, errs.Wrap(err, strings.Join(topics, ","), strings.Join(addrs, ","), groupID, config.Config.Kafka.Username, config.Config.Kafka.Password) } return &MConsumerGroup{ consumerGroup, diff --git a/tools/component/component.go b/tools/component/component.go index 823d8174bb..787ca8af68 100644 --- a/tools/component/component.go +++ b/tools/component/component.go @@ -15,9 +15,13 @@ package main import ( - "errors" "flag" "fmt" + "github.com/IBM/sarama" + "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" + "github.com/openimsdk/open-im-server/v3/pkg/common/db/unrelation" + "github.com/openimsdk/open-im-server/v3/pkg/common/discoveryregister/zookeeper" + "github.com/openimsdk/open-im-server/v3/pkg/common/kafka" "os" "strings" "time" @@ -32,16 +36,12 @@ import ( const ( // defaultCfgPath is the default path of the configuration file. - defaultCfgPath = "../../../../../config/config.yaml" - maxRetry = 300 - componentStartErrCode = 6000 - configErrCode = 6001 + defaultCfgPath = "../../../../../config/config.yaml" + maxRetry = 300 ) var ( - cfgPath = flag.String("c", defaultCfgPath, "Path to the configuration file") - ErrComponentStart = errs.NewCodeError(componentStartErrCode, "ComponentStartErr") - ErrConfig = errs.NewCodeError(configErrCode, "Config file is incorrect") + cfgPath = flag.String("c", defaultCfgPath, "Path to the configuration file") ) func initCfg() error { @@ -55,7 +55,7 @@ func initCfg() error { type checkFunc struct { name string - function func() (string, error) + function func() error } func main() { @@ -67,11 +67,13 @@ func main() { return } + configGetEnv() + checks := []checkFunc{ //{name: "Mysql", function: checkMysql}, {name: "Mongo", function: checkMongo}, - {name: "Minio", function: checkMinio}, {name: "Redis", function: checkRedis}, + {name: "Minio", function: checkMinio}, {name: "Zookeeper", function: checkZookeeper}, {name: "Kafka", function: checkKafka}, } @@ -82,165 +84,81 @@ func main() { } fmt.Printf("Checking components Round %v...\n", i+1) + var err error allSuccess := true for _, check := range checks { - str, err := check.function() + err = check.function() if err != nil { - component.ErrorPrint(fmt.Sprintf("Starting %s failed, %v", check.name, err)) + component.ErrorPrint(fmt.Sprintf("Starting %s failed:%v.", check.name, err)) allSuccess = false - break } else { - component.SuccessPrint(fmt.Sprintf("%s connected successfully, %s", check.name, str)) + component.SuccessPrint(fmt.Sprintf("%s connected successfully", check.name)) } } if allSuccess { component.SuccessPrint("All components started successfully!") - return } } - os.Exit(1) -} - -// Helper function to get environment variable or default value -func getEnv(key, fallback string) string { - if value, exists := os.LookupEnv(key); exists { - return value - } - return fallback } // checkMongo checks the MongoDB connection without retries -func checkMongo() (string, error) { - mongo := &component.Mongo{ - Address: config.Config.Mongo.Address, - Database: config.Config.Mongo.Database, - Username: config.Config.Mongo.Username, - Password: config.Config.Mongo.Password, - MaxPoolSize: config.Config.Mongo.MaxPoolSize, - } - uri, uriExist := os.LookupEnv("MONGO_URI") - if uriExist { - mongo.URL = uri - } +func checkMongo() error { + _, err := unrelation.NewMongo() + return err +} - str, err := component.CheckMongo(mongo) - if err != nil { - return "", err - } - return str, nil +// checkRedis checks the Redis connection +func checkRedis() error { + _, err := cache.NewRedis() + return err } // checkMinio checks the MinIO connection -func checkMinio() (string, error) { +func checkMinio() error { + // Check if MinIO is enabled if config.Config.Object.Enable != "minio" { - return "", nil + return nil } - - endpoint, err := getMinioAddr("MINIO_ENDPOINT", "MINIO_ADDRESS", "MINIO_PORT", config.Config.Object.Minio.Endpoint) - if err != nil { - return "", err - } - minio := &component.Minio{ ApiURL: config.Config.Object.ApiURL, - Endpoint: endpoint, - AccessKeyID: getEnv("MINIO_ACCESS_KEY_ID", config.Config.Object.Minio.AccessKeyID), - SecretAccessKey: getEnv("MINIO_SECRET_ACCESS_KEY", config.Config.Object.Minio.SecretAccessKey), + Endpoint: config.Config.Object.Minio.Endpoint, + AccessKeyID: config.Config.Object.Minio.AccessKeyID, + SecretAccessKey: config.Config.Object.Minio.SecretAccessKey, SignEndpoint: config.Config.Object.Minio.SignEndpoint, UseSSL: getEnv("MINIO_USE_SSL", "false"), } - - str, err := component.CheckMinio(minio) - if err != nil { - return "", err - } - return str, nil -} - -// checkRedis checks the Redis connection -func checkRedis() (string, error) { - // Prioritize environment variables - address := getEnv("REDIS_ADDRESS", strings.Join(config.Config.Redis.Address, ",")) - username := getEnv("REDIS_USERNAME", config.Config.Redis.Username) - password := getEnv("REDIS_PASSWORD", config.Config.Redis.Password) - - redis := &component.Redis{ - Address: strings.Split(address, ","), - Username: username, - Password: password, - } - - addresses, err := getAddress("REDIS_ADDRESS", "REDIS_PORT", config.Config.Redis.Address) - if err != nil { - return "", err - } - redis.Address = addresses - - str, err := component.CheckRedis(redis) - if err != nil { - return "", err - } - return str, nil + _, err := component.CheckMinio(minio) + return err } // checkZookeeper checks the Zookeeper connection -func checkZookeeper() (string, error) { - // Prioritize environment variables - - address := getEnv("ZOOKEEPER_ADDRESS", strings.Join(config.Config.Zookeeper.ZkAddr, ",")) - - zk := &component.Zookeeper{ - Schema: getEnv("ZOOKEEPER_SCHEMA", "digest"), - ZkAddr: strings.Split(address, ","), - Username: getEnv("ZOOKEEPER_USERNAME", config.Config.Zookeeper.Username), - Password: getEnv("ZOOKEEPER_PASSWORD", config.Config.Zookeeper.Password), - } - - addresses, err := getAddress("ZOOKEEPER_ADDRESS", "ZOOKEEPER_PORT", config.Config.Zookeeper.ZkAddr) - if err != nil { - return "", nil - } - zk.ZkAddr = addresses - - str, err := component.CheckZookeeper(zk) - if err != nil { - return "", err - } - return str, nil +func checkZookeeper() error { + _, err := zookeeper.NewZookeeperDiscoveryRegister() + return err } // checkKafka checks the Kafka connection -func checkKafka() (string, error) { +func checkKafka() error { // Prioritize environment variables - username := getEnv("KAFKA_USERNAME", config.Config.Kafka.Username) - password := getEnv("KAFKA_PASSWORD", config.Config.Kafka.Password) - address := getEnv("KAFKA_ADDRESS", strings.Join(config.Config.Kafka.Addr, ",")) - - kafka := &component.Kafka{ - Username: username, - Password: password, - Addr: strings.Split(address, ","), + kafkaStu := &component.Kafka{ + Username: config.Config.Kafka.Username, + Password: config.Config.Kafka.Password, + Addr: config.Config.Kafka.Addr, } - addresses, err := getAddress("KAFKA_ADDRESS", "KAFKA_PORT", config.Config.Kafka.Addr) + _, kafkaClient, err := component.CheckKafka(kafkaStu) if err != nil { - return "", nil - } - kafka.Addr = addresses - - str, kafkaClient, err := component.CheckKafka(kafka) - if err != nil { - return "", err + return err } defer kafkaClient.Close() // Verify if necessary topics exist topics, err := kafkaClient.Topics() if err != nil { - return "", errs.Wrap(err) + return errs.Wrap(err) } requiredTopics := []string{ @@ -251,11 +169,38 @@ func checkKafka() (string, error) { for _, requiredTopic := range requiredTopics { if !isTopicPresent(requiredTopic, topics) { - return "", ErrComponentStart.Wrap(fmt.Sprintf("Kafka doesn't contain topic: %v", requiredTopic)) + return errs.Wrap(err, fmt.Sprintf("Kafka doesn't contain topic: %v", requiredTopic)) } } - return str, nil + _, err = kafka.NewMConsumerGroup(&kafka.MConsumerGroupConfig{ + KafkaVersion: sarama.V2_0_0_0, + OffsetsInitial: sarama.OffsetNewest, IsReturnErr: false, + }, []string{config.Config.Kafka.LatestMsgToRedis.Topic}, + config.Config.Kafka.Addr, config.Config.Kafka.ConsumerGroupID.MsgToRedis) + if err != nil { + return err + } + + _, err = kafka.NewMConsumerGroup(&kafka.MConsumerGroupConfig{ + KafkaVersion: sarama.V2_0_0_0, + OffsetsInitial: sarama.OffsetNewest, IsReturnErr: false, + }, []string{config.Config.Kafka.MsgToPush.Topic}, + config.Config.Kafka.Addr, config.Config.Kafka.ConsumerGroupID.MsgToMongo) + if err != nil { + return err + } + + kafka.NewMConsumerGroup(&kafka.MConsumerGroupConfig{ + KafkaVersion: sarama.V2_0_0_0, + OffsetsInitial: sarama.OffsetNewest, IsReturnErr: false, + }, []string{config.Config.Kafka.MsgToPush.Topic}, config.Config.Kafka.Addr, + config.Config.Kafka.ConsumerGroupID.MsgToPush) + if err != nil { + return err + } + + return nil } // isTopicPresent checks if a topic is present in the list of topics @@ -268,42 +213,34 @@ func isTopicPresent(topic string, topics []string) bool { return false } -func getAddress(key1, key2 string, fallback []string) ([]string, error) { - address, addrExist := os.LookupEnv(key1) - port, portExist := os.LookupEnv(key2) - - if addrExist && portExist { - addresses := strings.Split(address, ",") - for i, addr := range addresses { - addresses[i] = addr + ":" + port - } - return addresses, nil - } else if !addrExist && portExist { - result := make([]string, len(config.Config.Redis.Address)) - for i, addr := range config.Config.Redis.Address { - add := strings.Split(addr, ":") - result[i] = add[0] + ":" + port - } - return result, nil - } else if addrExist && !portExist { - return nil, errs.Wrap(errors.New("the ZOOKEEPER_PORT of minio is empty")) - } - return fallback, nil +func configGetEnv() { + config.Config.Object.Minio.AccessKeyID = getEnv("MINIO_ACCESS_KEY_ID", config.Config.Object.Minio.AccessKeyID) + config.Config.Object.Minio.SecretAccessKey = getEnv("MINIO_SECRET_ACCESS_KEY", config.Config.Object.Minio.SecretAccessKey) + config.Config.Mongo.Uri = getEnv("MONGO_URI", config.Config.Mongo.Uri) + config.Config.Mongo.Username = getEnv("MONGO_OPENIM_USERNAME", config.Config.Mongo.Username) + config.Config.Mongo.Password = getEnv("MONGO_OPENIM_PASSWORD", config.Config.Mongo.Password) + config.Config.Kafka.Username = getEnv("KAFKA_USERNAME", config.Config.Kafka.Username) + config.Config.Kafka.Password = getEnv("KAFKA_PASSWORD", config.Config.Kafka.Password) + config.Config.Kafka.Addr = strings.Split(getEnv("KAFKA_ADDRESS", strings.Join(config.Config.Kafka.Addr, ",")), ",") + config.Config.Object.Minio.Endpoint = getMinioAddr("MINIO_ENDPOINT", "MINIO_ADDRESS", "MINIO_PORT", config.Config.Object.Minio.Endpoint) } -func getMinioAddr(key1, key2, key3, fallback string) (string, error) { +func getMinioAddr(key1, key2, key3, fallback string) string { // Prioritize environment variables endpoint := getEnv(key1, fallback) address, addressExist := os.LookupEnv(key2) port, portExist := os.LookupEnv(key3) if portExist && addressExist { endpoint = "http://" + address + ":" + port - } else if !portExist && addressExist { - return "", errs.Wrap(errors.New("the MINIO_PORT of minio is empty")) - } else if portExist && !addressExist { - arr := strings.Split(config.Config.Object.Minio.Endpoint, ":") - arr[2] = port - endpoint = strings.Join(arr, ":") + return endpoint } - return endpoint, nil + return endpoint +} + +// Helper function to get environment variable or default value +func getEnv(key, fallback string) string { + if value, exists := os.LookupEnv(key); exists { + return value + } + return fallback } From af878a96cfca897906a57363c0754efe117dbeea Mon Sep 17 00:00:00 2001 From: Xinwei Xiong <3293172751NSS@gmail.com> Date: Fri, 2 Feb 2024 19:47:16 +0800 Subject: [PATCH 023/188] feat: add architecture layers (#1860) * feat: add architecture layers * feat: add architecture layers * feat: add architecture layers * feat: add .gitignore file * feat: add .gitignore file * feat: fix openim logs and ci * feat: fix openim logs and ci * feat: support openim readme docs Signed-off-by: Xinwei Xiong (cubxxw) <3293172751nss@gmail.com> * Update main.go --------- Signed-off-by: Xinwei Xiong (cubxxw) <3293172751nss@gmail.com> --- CONTRIBUTING-zh_CN.md | 33 ++++ CONTRIBUTING.md | 211 +++++++++++++++++----- README-zh_CN.md | 58 ++++-- README.md | 39 +++- docs/README.md | 1 - docs/README_ar.md | 67 ------- docs/README_cs.md | 67 ------- docs/README_da.md | 67 ------- docs/README_de.md | 66 ------- docs/README_el.md | 67 ------- docs/README_eo.md | 67 ------- docs/README_es.md | 67 ------- docs/README_fa.md | 67 ------- docs/README_fi.md | 67 ------- docs/README_fr.md | 66 ------- docs/README_hu.md | 67 ------- docs/README_id.md | 67 ------- docs/README_it.md | 67 ------- docs/README_ja.md | 67 ------- docs/README_ko.md | 67 ------- docs/README_ml.md | 67 ------- docs/README_nl.md | 67 ------- docs/README_pl.md | 67 ------- docs/README_pt_BR.md | 67 ------- docs/README_ru.md | 67 ------- docs/README_tr.md | 67 ------- docs/README_ua.md | 67 ------- docs/README_vi.md | 67 ------- docs/README_zh_CN.md | 67 ------- docs/README_zh_TW.md | 67 ------- docs/contributing/CONTRIBUTING-JP.md | 33 ++++ docs/contributing/CONTRIBUTING-PL.md | 33 ++++ docs/images/Open-IM-Servers-on-System.png | Bin 21614 -> 0 bytes docs/images/Open-IM-Servers-on-docker.png | Bin 10172 -> 0 bytes docs/images/architecture-layers.png | Bin 0 -> 293222 bytes docs/images/build.png | Bin 62555 -> 0 bytes docs/images/docker_build.png | Bin 58699 -> 0 bytes docs/readme/README-UA.md | 7 + 38 files changed, 346 insertions(+), 1742 deletions(-) create mode 100644 CONTRIBUTING-zh_CN.md delete mode 100644 docs/README_ar.md delete mode 100644 docs/README_cs.md delete mode 100644 docs/README_da.md delete mode 100644 docs/README_de.md delete mode 100644 docs/README_el.md delete mode 100644 docs/README_eo.md delete mode 100644 docs/README_es.md delete mode 100644 docs/README_fa.md delete mode 100644 docs/README_fi.md delete mode 100644 docs/README_fr.md delete mode 100644 docs/README_hu.md delete mode 100644 docs/README_id.md delete mode 100644 docs/README_it.md delete mode 100644 docs/README_ja.md delete mode 100644 docs/README_ko.md delete mode 100644 docs/README_ml.md delete mode 100644 docs/README_nl.md delete mode 100644 docs/README_pl.md delete mode 100644 docs/README_pt_BR.md delete mode 100644 docs/README_ru.md delete mode 100644 docs/README_tr.md delete mode 100644 docs/README_ua.md delete mode 100644 docs/README_vi.md delete mode 100644 docs/README_zh_CN.md delete mode 100644 docs/README_zh_TW.md create mode 100644 docs/contributing/CONTRIBUTING-JP.md create mode 100644 docs/contributing/CONTRIBUTING-PL.md delete mode 100644 docs/images/Open-IM-Servers-on-System.png delete mode 100644 docs/images/Open-IM-Servers-on-docker.png create mode 100644 docs/images/architecture-layers.png delete mode 100644 docs/images/build.png delete mode 100644 docs/images/docker_build.png create mode 100644 docs/readme/README-UA.md diff --git a/CONTRIBUTING-zh_CN.md b/CONTRIBUTING-zh_CN.md new file mode 100644 index 0000000000..ee3c0b8f85 --- /dev/null +++ b/CONTRIBUTING-zh_CN.md @@ -0,0 +1,33 @@ +# How do I contribute code to OpenIM + +

+ Englist · + 中文 · + Українська · + Česky · + Magyar · + Español · + فارسی · + Français · + Deutsch · + Polski · + Indonesian · + Suomi · + മലയാളം · + 日本語 · + Nederlands · + Italiano · + Русский · + Português (Brasil) · + Esperanto · + 한국어 · + العربي · + Tiếng Việt · + Dansk · + Ελληνικά · + Türkçe +

+ + + +

diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ee275e7ada..f7d2c07492 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,6 +1,38 @@ -# Contributing to Open-IM-Server - -So, you want to hack on Open-IM-Server? Yay! +# How do I contribute code to OpenIM + +

+ Englist · + 中文 · + Українська · + Česky · + Magyar · + Español · + فارسی · + Français · + Deutsch · + Polski · + Indonesian · + Suomi · + മലയാളം · + 日本語 · + Nederlands · + Italiano · + Русский · + Português (Brasil) · + Esperanto · + 한국어 · + العربي · + Tiếng Việt · + Dansk · + Ελληνικά · + Türkçe +

+ + + +

+ +So, you want to hack on open-im-server? Yay! First of all, thank you for considering contributing to our project! We appreciate your time and effort, and we value any contribution, whether it's reporting a bug, suggesting a new feature, or submitting a pull request. @@ -12,7 +44,7 @@ This document provides guidelines and best practices to help you contribute effe ## 📇Topics -- [Contributing to Open-IM-Server](#contributing-to-open-im-server) +- [How do I contribute code to OpenIM](#how-do-i-contribute-code-to-openim) - [📇Topics](#topics) - [What we expect of you](#what-we-expect-of-you) - [Code of ConductCode of Conduct](#code-of-conductcode-of-conduct) @@ -32,13 +64,13 @@ This document provides guidelines and best practices to help you contribute effe ## What we expect of you -We hope that anyone can join Open-IM-Server , even if you are a student, writer, translator +We hope that anyone can join open-im-server , even if you are a student, writer, translator -Please meet the minimum version of the Go language published in [go.mod](./go.mod). If you want to manage the Go language version, we provide tools to install [gvm](https://github.com/moovweb/gvm) in our [Makefile](./Makefile) +Please meet the minimum version of the Go language published in [go.mod](./go.mod). If you want to manage the Go language version, we provide tools tHow do I contribute code to OpenIMo install [gvm](https://github.com/moovweb/gvm) in our [Makefile](./Makefile) -You'd better use Linux OR WSL as the development environment, Linux with [Makefile](./Makefile) can help you quickly build and test Open-IM-Server project. +You'd better use Linux OR WSL as the development environment, Linux with [Makefile](./Makefile) can help you quickly build and test open-im-server project. -If you are familiar with [Makefile](./Makefile) , you can easily see the clever design of the Open-IM-Server Makefile. Storing the necessary tools such as golangci in the `/tools` directory can avoid some tool version issues. +If you are familiar with [Makefile](./Makefile) , you can easily see the clever design of the open-im-server Makefile. Storing the necessary tools such as golangci in the `/tools` directory can avoid some tool version issues. The [Makefile](./Makefile) is for every developer, even if you don't know how to use the Makefile tool, don't worry, we provide two great commands to get you up to speed with the Makefile architecture, `make help` and `make help-all`, it can reduce problems of the developing environment. @@ -52,7 +84,7 @@ In accordance with the naming conventions adopted by OpenIM and drawing referenc #### Code and doc contribution -Every action to make project Open-IM-Server better is encouraged. On GitHub, every improvement for Open-IM-Server could be via a [PR](https://github.com/openimsdk/open-im-server/pulls) (short for pull request). +Every action to make project open-im-server better is encouraged. On GitHub, every improvement for open-im-server could be via a [PR](https://github.com/openimsdk/open-im-server/pulls) (short for pull request). + If you find a typo, try to fix it! + If you find a bug, try to fix it! @@ -67,8 +99,8 @@ Every action to make project Open-IM-Server better is encouraged. On GitHub, eve #### Where should I start? -+ If you are new to the project, don't know how to contribute Open-IM-Server, please check out the [good first issue](https://github.com/openimsdk/open-im-server/issues?q=is%3Aopen+label%3A"good+first+issue"+sort%3Aupdated-desc) label. -+ You should be good at filtering the Open-IM-Server issue tags and finding the ones you like, such as [RFC](https://github.com/openimsdk/open-im-server/issues?q=is%3Aissue+is%3Aopen+RFC+label%3ARFC) for big initiatives, features for [feature](https://github.com/openimsdk/open-im-server/issues?q=is%3Aissue+label%3Afeature) proposals, and [bug](https://github.com/openimsdk/open-im-server/issues?q=is%3Aissue+label%3Abug+) fixes. ++ If you are new to the project, don't know how to contribute open-im-server, please check out the [good first issue](https://github.com/openimsdk/open-im-server/issues?q=is%3Aopen+label%3A"good+first+issue"+sort%3Aupdated-desc) label. ++ You should be good at filtering the open-im-server issue tags and finding the ones you like, such as [RFC](https://github.com/openimsdk/open-im-server/issues?q=is%3Aissue+is%3Aopen+RFC+label%3ARFC) for big initiatives, features for [feature](https://github.com/openimsdk/open-im-server/issues?q=is%3Aissue+label%3Afeature) proposals, and [bug](https://github.com/openimsdk/open-im-server/issues?q=is%3Aissue+label%3Abug+) fixes. + If you are looking for something to work on, check out our [open issues](https://github.com/openimsdk/open-im-server/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc). + If you have an idea for a new feature, please [open an issue](https://github.com/openimsdk/open-im-server/issues/new/choose), and we can discuss it. @@ -85,7 +117,7 @@ When documenting a new design, we recommend a 2-step approach: 1. Use the short-form RFC template to outline your ideas and get early feedback. 2. Once you have received sufficient feedback and consensus, you may use the longer-form design doc template to specify and discuss your design in more details. -In order to contribute a feature to Open-IM-Server you'll need to go through the following steps: +In order to contribute a feature to open-im-server you'll need to go through the following steps: + Discuss your idea with the appropriate [working groups](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q) on the working group's Slack channel. + Once there is general agreement that the feature is useful, create a GitHub issue to track the discussion. The issue should include information about the requirements and use cases that it is trying to address. @@ -95,13 +127,27 @@ But keep in mind that there is no guarantee of it being accepted and so it is us ## Getting Started -To propose PR for the Open-IM-Server item, we assume you have registered a GitHub ID. Then you could finish the preparation in the following steps: +To propose PR for the open-im-server item, we assume you have registered a GitHub ID. Then you could finish the preparation in the following steps: + +1. Fork the repository(open-im-server) + +2. **CLONE** your own repository to main locally. Use `git clone https://github.com//open-im-server.git` to clone repository to your local machine. Then you can create new branches to finish the change you wish to make. + +3. **Initialize Git Hooks with `make init-githooks`** + + After cloning the repository, it's recommended to set up Git hooks to streamline your workflow and ensure your contributions adhere to OpenIM's community standards. Git hooks are scripts that run automatically every time a particular event occurs in a Git repository, such as before a commit or push. To initialize Git hooks for the OpenIM server repository, use the `make init-githooks` command. -1. Fork the repository(Open-IM-Server) + - **Enabling Git Hooks Mode**: By running `make init-githooks` and entering `1` when prompted, you enable Git hooks mode. This action will generate a series of hooks within the `.git/hooks/` directory. These hooks impose certain checks on your commits and pushes, ensuring they meet the quality and standards expected by the OpenIM community. For instance, commit hooks might enforce a specific commit message format, while push hooks could check for code style or linting issues. -2. **CLONE** your own repository to main locally. Use `git clone https://github.com//Open-IM-Server.git` to clone repository to your local machine. Then you can create new branches to finish the change you wish to make. + - **Benefits for First-Time Contributors**: This setup is especially beneficial for new contributors. It guides you to make professional, community-standard-compliant Pull Requests (PRs) and PR descriptions right from your first contribution. By automating checks and balances, it reduces the chances of common mistakes and speeds up the review process. -3. **Set Remote** upstream to be `https://github.com/openimsdk/open-im-server.git` using the following two commands: + - **Disabling Git Hooks**: If for any reason you wish to remove the Git hooks, simply run `make init-githooks` again and enter `2` when prompted. This will delete the existing Git hooks, removing the automatic checks and constraints from your Git operations. However, keep in mind that manually ensuring your contributions adhere to community standards without the aid of Git hooks requires diligence. + + > [!NOTE] Utilizing Git hooks through the `make init-githooks` command is a straightforward yet powerful way to ensure your contributions are consistent and high-quality. It's a step towards fostering a professional and efficient development environment in the OpenIM project. + + + +4. **Set Remote** upstream to be `https://github.com/openimsdk/open-im-server.git` using the following two commands: ```bash ❯ git remote add upstream https://github.com/openimsdk/open-im-server.git @@ -112,18 +158,18 @@ To propose PR for the Open-IM-Server item, we assume you have registered a GitHu ```bash ❯ git remote -v - origin https://github.com//Open-IM-Server.git (fetch) - origin https://github.com//Open-IM-Server.git (push) + origin https://github.com//open-im-server.git (fetch) + origin https://github.com//open-im-server.git (push) upstream https://github.com/openimsdk/open-im-server.git (fetch) upstream no-pushing (push) ``` Adding this, we can easily synchronize local branches with upstream branches. -4. Create a new branch for your changes (use a descriptive name, such as `fix-bug-123` or `add-new-feature`). +5. Create a new branch for your changes (use a descriptive name, such as `fix-bug-123` or `add-new-feature`). ```bash - ❯ cd Open-IM-Server + ❯ cd open-im-server ❯ git fetch upstream ❯ git checkout upstream/main ``` @@ -136,7 +182,8 @@ To propose PR for the Open-IM-Server item, we assume you have registered a GitHu Make any change on the `new-branch` then use [Makefile](./Makefile) build and test your codes. -5. **Commit your changes** to your local branch, lint before committing and commit with sign-off + +6. **Commit your changes** to your local branch, lint before committing and commit with sign-off ```bash ❯ git rebase upstream/main @@ -145,7 +192,7 @@ To propose PR for the Open-IM-Server item, we assume you have registered a GitHu ❯ git commit -a -s -m "message for your changes" # -s adds a Signed-off-by trailer ``` -6. **Push your branch** to your forked repository, it is recommended to have only one commit for a PR. +7. **Push your branch** to your forked repository, it is recommended to have only one commit for a PR. ```bash # sync up with upstream @@ -177,12 +224,78 @@ To propose PR for the Open-IM-Server item, we assume you have registered a GitHu ❯ git rebase upstream/main # rebase the current branch to upstream/main branch ❯ git add -A ❯ git commit -m -s "feat: feature two" - # then create pull request, and merge ``` -7. **Open a pull request** to `openimsdk/open-im-server:main` + **Verifying Your Pull Request with `make all` Command** + + Before verifying, you may need to complete the basic deployment of OpenIM to get familiar with the deployment status of OpenIM. Please read [this deployment document](https://docs.openim.io/zh-Hans/guides/gettingStarted/imSourceCodeDeployment), which will tell you how to deploy OpenIM middleware and OpenIM services in detail + + Before submitting your Pull Request (PR), it's crucial to ensure that it passes all the necessary checks and verifications to maintain the quality and integrity of the OpenIM server project. To facilitate this process, we have encapsulated a series of validation steps into the `make all` command. + + - **Purpose of `make all` Command**: The `make all` command serves as a comprehensive pre-PR verification tool. It sequentially executes a variety of tasks designed to scrutinize your changes from multiple angles, ensuring they are ready for submission. + + - **Included Commands**: + - `tidy`: Cleans up the module by removing unused dependencies. + - `gen`: Generates necessary files from templates or specifications, ensuring that your codebase is up-to-date with its dependencies. + - `add-copyright`: Checks for and adds copyright notices to files, ensuring compliance with legal requirements. + - `verify`: Verifies the integrity and consistency of the code, dependencies, and various checks. + - `test-api`: Runs API tests to ensure that your changes do not break any existing functionality and adhere to the expected behaviors. + - `lint`: Analyzes the code for potential stylistic or programming errors, enforcing the project's coding standards. + - `cover`: Measures the code coverage of tests, helping you understand how much of the code is being tested. + - `restart`: (Optionally) restarts services or applications to ensure that changes are correctly applied and functioning in a live environment. + + - **Executing the Command**: To run the `make all` command, simply navigate to the root directory of your cloned repository in your terminal and execute: + ```bash + make all + ``` + This command will sequentially perform all the listed actions, outputting any warnings or errors encountered during the process. It's a vital step to catch any issues early and ensure your contribution meets the quality standards set by the OpenIM community. + + - **Benefits**: By using `make all` for pre-PR verification, you significantly increase the likelihood of your PR being accepted on the first review. It not only demonstrates your commitment to quality but also streamlines the review process by minimizing back-and-forth due to common issues that can be caught automatically. + + + **Troubleshooting Git Push Failures** + + When working with Git, encountering errors during push operations is not uncommon. Two primary reasons you might face push failures are due to firewall restrictions or authentication issues. Here’s how you can troubleshoot and resolve these problems. + + **Firewall Errors** + + If you're behind a corporate firewall or your network restricts certain types of traffic, you might encounter issues when trying to push your changes via HTTPS. This is because firewalls can block the ports used by the HTTPS protocol. To resolve this issue, you can configure Git to use a proxy. + + If you have a local proxy server set up, you can direct Git to use it by setting the `https_proxy` and `http_proxy` environment variables. Open your terminal or command prompt and run the following commands: + + ```bash + export https_proxy="http://127.0.0.1:7890" + export http_proxy="http://127.0.0.1:7890" + ``` + + Replace `127.0.0.1:7890` with the address and port of your proxy server. These commands set the proxy for the current session. If you want to make these changes permanent, add them to your `.bashrc`, `.bash_profile`, or equivalent shell configuration file. + + **Using SSH Instead of HTTPS** + + An alternative to using HTTPS is to set up an SSH connection for Git operations. SSH connections are often not blocked by firewalls and do not require proxy settings. Additionally, SSH provides a secure channel and can simplify the authentication process since it relies on SSH keys rather than username and password credentials. + + To use SSH with Git, you first need to generate an SSH key pair and add the public key to your GitHub account (or another Git hosting service). + + 1. **Generate SSH Key Pair**: Open your terminal and run `ssh-keygen -t rsa -b 4096 -C "your_email@example.com"`, replacing `your_email@example.com` with your email. Press enter to accept the default file location and passphrase prompts. + + 2. **Add SSH Key to SSH-Agent**: Ensure the ssh-agent is running with `eval "$(ssh-agent -s)"` and then add your SSH private key to the ssh-agent using `ssh-add ~/.ssh/id_rsa`. + + 3. **Add SSH Key to GitHub**: Copy your SSH public key to your clipboard with `cat ~/.ssh/id_rsa.pub | clip` (Windows) or `pbcopy < ~/.ssh/id_rsa.pub` (Mac). Go to GitHub, navigate to Settings > SSH and GPG keys, and add a new SSH key, pasting your key into the field provided. + + 4. **Switch to SSH in Your Repository**: Change your repository's remote URL from HTTPS to SSH. You can find the SSH URL in your repository settings on GitHub and use `git remote set-url origin git@github.com:username/repository.git` to switch. + + **Authentication Errors** + + If you're experiencing authentication errors, it might be due to missing or incorrect credentials. Ensure you have added your SSH key to your Git hosting service. You can test your SSH connection with `ssh -T git@github.com` (replace `github.com` with your Git hosting service's domain). If successful, you'll receive a welcome message. + + For HTTPS users, check that your username and password (or personal access token for services like GitHub that no longer accept password authentication for Git operations) are correct. + +8. **Open a pull request** to `openimsdk/open-im-server:main` It is recommended to review your changes before filing a pull request. Check if your code doesn't conflict with the main branch and no redundant code is included. + + > [!TIP] There is a [good blog post documenting](https://nsddd.top/posts/participating-in-this-project/) the entire push contribution process. + ## Style and Specification @@ -190,15 +303,15 @@ We divide the problem into security and general problems: #### Reporting security issues -Security issues are always treated seriously. As our usual principle, we discourage anyone to spread security issues. If you find a security issue of Open-IM-Server, please do not discuss it in public and even do not open a public issue. +Security issues are always treated seriously. As our usual principle, we discourage anyone to spread security issues. If you find a security issue of open-im-server, please do not discuss it in public and even do not open a public issue. Instead we encourage you to send us a private email to info@openim.io to report this. #### Reporting general issues -To be honest, we regard every user of Open-IM-Serveras a very kind contributor. After experiencing Open-IM-Server, you may have some feedback for the project. Then feel free to open an issue via [NEW ISSUE](https://github.com/openimsdk/open-im-server/issues/new/choose). +To be honest, we regard every user of open-im-serveras a very kind contributor. After experiencing open-im-server, you may have some feedback for the project. Then feel free to open an issue via [NEW ISSUE](https://github.com/openimsdk/open-im-server/issues/new/choose). -Since we collaborate project Open-IM-Server in a distributed way, we appreciate **WELL-WRITTEN**, **DETAILED**, **EXPLICIT** issue reports. To make the communication more efficient, we wish everyone could search if your issue is an existing one in the searching list. If you find it existing, please add your details in comments under the existing issue instead of opening a brand new one. +Since we collaborate project open-im-server in a distributed way, we appreciate **WELL-WRITTEN**, **DETAILED**, **EXPLICIT** issue reports. To make the communication more efficient, we wish everyone could search if your issue is an existing one in the searching list. If you find it existing, please add your details in comments under the existing issue instead of opening a brand new one. To make the issue details as standard as possible, we setup an [ISSUE TEMPLATE](https://github.com/OpenIMSDK/.github/tree/main/.github/ISSUE_TEMPLATE) for issue reporters. You can find three kinds of issue templates there: question, bug report and feature request. Please **BE SURE** to follow the instructions to fill fields in template. @@ -206,20 +319,20 @@ To make the issue details as standard as possible, we setup an [ISSUE TEMPLATE]( + bug report + feature request -+ Open-IM-Server performance issues ++ open-im-server performance issues + feature proposal + feature design + help wanted + doc incomplete + test improvement -+ any questions on Open-IM-Server project ++ any questions on open-im-server project + and so on -Also, we must be reminded when submitting a new question about Open-IM-Server, please remember to remove the sensitive data from your post. Sensitive data could be password, secret key, network locations, private business data and so on. +Also, we must be reminded when submitting a new question about open-im-server, please remember to remove the sensitive data from your post. Sensitive data could be password, secret key, network locations, private business data and so on. #### Commit Rules -Actually in Open-IM-Server, we take two rules serious when committing: +Actually in open-im-server, we take two rules serious when committing: **🥇 Commit Message:** @@ -262,7 +375,7 @@ An example for this could be: #### PR Description -PR is the only way to make change to Open-IM-Server project files. To help reviewers better get your purpose, PR description could not be too detailed. We encourage contributors to follow the [PR template](https://github.com/OpenIMSDK/.github/tree/main/.github/PULL_REQUEST_TEMPLATE.md) to finish the pull request. +PR is the only way to make change to open-im-server project files. To help reviewers better get your purpose, PR description could not be too detailed. We encourage contributors to follow the [PR template](https://github.com/OpenIMSDK/.github/tree/main/.github/PULL_REQUEST_TEMPLATE.md) to finish the pull request. You can find some very formal PR in [RFC](https://github.com/openimsdk/open-im-server/issues?q=is%3Aissue+is%3Aopen+RFC+label%3ARFC) issues and learn about them. @@ -311,11 +424,11 @@ git() { #### Docs Contribution -The documentation for Open-IM-Server includes: +The documentation for open-im-server includes: -+ [README.md](https://github.com/openimsdk/open-im-server/blob/main/README.md): This file includes the basic information and instructions for getting started with Open-IM-Server. -+ [CONTRIBUTING.md](https://github.com/openimsdk/open-im-server/blob/main/CONTRIBUTING.md): This file contains guidelines for contributing to Open-IM-Server's codebase, such as how to submit issues, pull requests, and code reviews. -+ [Official Documentation](https://doc.rentsoft.cn/): This is the official documentation for Open-IM-Server, which includes comprehensive information on all of its features, configuration options, and troubleshooting tips. ++ [README.md](https://github.com/openimsdk/open-im-server/blob/main/README.md): This file includes the basic information and instructions for getting started with open-im-server. ++ [CONTRIBUTING.md](https://github.com/openimsdk/open-im-server/blob/main/CONTRIBUTING.md): This file contains guidelines for contributing to open-im-server's codebase, such as how to submit issues, pull requests, and code reviews. ++ [Official Documentation](https://doc.rentsoft.cn/): This is the official documentation for open-im-server, which includes comprehensive information on all of its features, configuration options, and troubleshooting tips. Please obey the following rules to better format the docs, which would greatly improve the reading experience. @@ -328,20 +441,20 @@ Please obey the following rules to better format the docs, which would greatly i ## Engage to help anything -We choose GitHub as the primary place for Open-IM-Server to collaborate. So the latest updates of Open-IM-Server are always here. Although contributions via PR is an explicit way to help, we still call for any other ways. +We choose GitHub as the primary place for open-im-server to collaborate. So the latest updates of open-im-server are always here. Although contributions via PR is an explicit way to help, we still call for any other ways. + reply to other's [issues](https://github.com/openimsdk/open-im-server/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc) if you could; + help solve other user's problems; + help review other's [PR](https://github.com/openimsdk/open-im-server/pulls?q=is%3Apr+is%3Aopen+sort%3Aupdated-desc) design; -+ discuss about Open-IM-Server to make things clearer; -+ advocate [Open-IM-Server](https://google.com/search?q=Open-IM-Server) technology beyond GitHub; -+ write blogs on Open-IM-Server and so on. ++ discuss about open-im-server to make things clearer; ++ advocate [open-im-server](https://google.com/search?q=open-im-server) technology beyond GitHub; ++ write blogs on open-im-server and so on. In a word, **ANY HELP IS CONTRIBUTION.** ## Release version -Releases of Open-IM-Server are done using [Release Please](https://github.com/googleapis/release-please) and [GoReleaser](https://goreleaser.com/). The workflow looks like this: +Releases of open-im-server are done using [Release Please](https://github.com/googleapis/release-please) and [GoReleaser](https://goreleaser.com/). The workflow looks like this: 🎯 A PR is merged to the `main` branch: @@ -366,17 +479,23 @@ Such a commit can get produced as follows: ❯ git commit --allow-empty -m "chore: release 0.0.3" -m "Release-As: 0.0.3 ```` +For the complex release process, in fact, and encapsulation as CICD, you only need to tag locally, and then publish the tag to OpenIM github to complete the entire OpenIM release process. + +In addition to CICD, we also do a complex release command locally, which can help you complete the full platform compilation, testing, and release to Minio, just by using the `make release` command. +Please [read the detailed documents](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/release.md) + + ## Contact Us -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. +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. +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. ++ : 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](info@openim.io). 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. ++ : 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. Whether you're looking to join our community or have any questions or suggestions, we welcome you to get in touch with us. diff --git a/README-zh_CN.md b/README-zh_CN.md index 12a56d4f67..e337688812 100644 --- a/README-zh_CN.md +++ b/README-zh_CN.md @@ -4,29 +4,51 @@

-

- ⭐️ Open source Instant Messaging Server ⭐️
-

- - -

-A+ -good first - - - - -

+
+ +[![Stars](https://img.shields.io/github/stars/openimsdk/open-im-server?style=for-the-badge&logo=github&colorB=ff69b4)](https://github.com/openimsdk/open-im-server/stargazers) +[![Forks](https://img.shields.io/github/forks/openimsdk/open-im-server?style=for-the-badge&logo=github&colorB=blue)](https://github.com/openimsdk/open-im-server/network/members) +[![Codecov](https://img.shields.io/codecov/c/github/openimsdk/open-im-server?style=for-the-badge&logo=codecov&colorB=orange)](https://app.codecov.io/gh/openimsdk/open-im-server) +[![Go Report Card](https://goreportcard.com/badge/github.com/openimsdk/open-im-server?style=for-the-badge)](https://goreportcard.com/report/github.com/openimsdk/open-im-server) +[![Go Reference](https://img.shields.io/badge/Go%20Reference-blue.svg?style=for-the-badge&logo=go&logoColor=white)](https://pkg.go.dev/github.com/openimsdk/open-im-server/v3) +[![License](https://img.shields.io/badge/license-Apache--2.0-green?style=for-the-badge)](https://github.com/openimsdk/open-im-server/blob/main/LICENSE) +[![Slack](https://img.shields.io/badge/Slack-500%2B-blueviolet?style=for-the-badge&logo=slack&logoColor=white)](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q) +[![Best Practices](https://img.shields.io/badge/Best%20Practices-purple?style=for-the-badge)](https://www.bestpractices.dev/projects/8045) +[![Good First Issues](https://img.shields.io/github/issues/openimsdk/open-im-server/good%20first%20issue?style=for-the-badge&logo=github)](https://github.com/openimsdk/open-im-server/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc+label%3A%22good+first+issue%22) +[![Language](https://img.shields.io/badge/Language-Go-blue.svg?style=for-the-badge&logo=go&logoColor=white)](https://golang.org/) -

- English • - 简体中文 • - Docs + Englist · + 中文 · + Українська · + Česky · + Magyar · + Español · + فارسی · + Français · + Deutsch · + Polski · + Indonesian · + Suomi · + മലയാളം · + 日本語 · + Nederlands · + Italiano · + Русский · + Português (Brasil) · + Esperanto · + 한국어 · + العربي · + Tiếng Việt · + Dansk · + Ελληνικά · + Türkçe

+
+

## 🟢 扫描微信进群交流 @@ -39,8 +61,6 @@ OpenIM 是一个专门设计用于在应用程序中集成聊天、音视频通 - - ![App-OpenIM 关系](./docs/images/oepnim-design.png) ## 🚀 关于 OpenIMSDK diff --git a/README.md b/README.md index 3876fcd7ad..8721bf2cee 100644 --- a/README.md +++ b/README.md @@ -17,9 +17,35 @@ [![Good First Issues](https://img.shields.io/github/issues/openimsdk/open-im-server/good%20first%20issue?style=for-the-badge&logo=github)](https://github.com/openimsdk/open-im-server/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc+label%3A%22good+first+issue%22) [![Language](https://img.shields.io/badge/Language-Go-blue.svg?style=for-the-badge&logo=go&logoColor=white)](https://golang.org/) -[**English**](./README.md) • -[**简体中文**](./README-zh_CN.md) • -[**Docs**](https://openim.io/en) + +

+ Englist · + 中文 · + Українська · + Česky · + Magyar · + Español · + فارسی · + Français · + Deutsch · + Polski · + Indonesian · + Suomi · + മലയാളം · + 日本語 · + Nederlands · + Italiano · + Русский · + Português (Brasil) · + Esperanto · + 한국어 · + العربي · + Tiếng Việt · + Dansk · + Ελληνικά · + Türkçe +

+ @@ -68,6 +94,13 @@ It is built using Golang and supports cross-platform deployment, ensuring a cons 👉 **[Learn more](https://docs.openim.io/guides/introduction/product)** +## :building_construction: Overall Architecture + +Delve into the heart of Open-IM-Server's functionality with our architecture diagram. + +![Overall Architecture](./docs/images/architecture-layers.png) + + ## :rocket: Quick Start We support many platforms. Here are the addresses for quick experience on the web side: diff --git a/docs/README.md b/docs/README.md index 32fc8d015e..92ba2c6201 100644 --- a/docs/README.md +++ b/docs/README.md @@ -7,7 +7,6 @@ Welcome to the OpenIM Documentation hub! This center provides a comprehensive ra 1. [Contrib](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib) - Guidance on contributing and configurations for developers 2. [Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib) - Coding conventions, logging policies, and other transformation tools ------- ## Contrib diff --git a/docs/README_ar.md b/docs/README_ar.md deleted file mode 100644 index bdd616e6a6..0000000000 --- a/docs/README_ar.md +++ /dev/null @@ -1,67 +0,0 @@ -# وثائق OpenIM Server - -مرحبًا بكم في مركز وثائق OpenIM! يوفر هذا المركز مجموعة شاملة من الأدلة والكتيبات التي صُممت لمساعدتك في الاستفادة القصوى من تجربة OpenIM الخاصة بك. - -## جدول المحتويات - -1. [Contrib](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib) - إرشادات حول المساهمة والتكوينات للمطورين -2. [Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib) - اتفاقيات الكود، سياسات التسجيل، وأدوات التحويل الأخرى - ------- - -## مساهمة - -هذا القسم يقدم للمطورين دليلاً مفصلاً حول كيفية المساهمة في الكود، إعداد بيئتهم، واتباع العمليات المرتبطة. - -- [Code Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/code-conventions.md) - قواعد واتفاقيات لكتابة الكود في OpenIM. -- [Development Guide](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/development.md) - دليل حول كيفية القيام بالتطوير داخل OpenIM. -- [Git Cherry Pick](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/gitcherry-pick.md) - إرشادات حول عمليات اختيار الجيت. -- [Git Workflow](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/git-workflow.md) - سير عمل الجيت في OpenIM. -- [Initialization Configurations](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/init-config.md) - إرشادات حول إعداد وتهيئة OpenIM. -- [Docker Installation](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/install-docker.md) - كيفية تثبيت الدوكر على جهازك. -- [Linux Development Environment](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/linux-development.md) - دليل لإعداد بيئة التطوير على لينكس. -- [Local Actions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/local-actions.md) - إرشادات حول كيفية القيام ببعض الأعمال الشائعة محليًا. -- [Offline Deployment](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/offline-deployment.md) - طرق توظيف OpenIM دون اتصال. -- [Protoc Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/protoc-tools.md) - دليل حول استخدام أدوات بروتوك. -- [Go Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-go.md) - أدوات ومكتبات في OpenIM للغة Go. -- [Makefile Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-makefile.md) - أفضل الممارسات والأدوات لملفات الصيانة. -- [Script Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-scripts.md) - أفضل الممارسات والأدوات للسكربتات. - -## التحويلات - -يقدم هذا القسم مختلف الاتفاقيات والسياسات داخل OpenIM، التي تشمل الكود، السجلات، الإصدارات، والمزيد. - -- [API Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/api.md) - إرشادات وطرق لتحويلات API. -- [Logging Policy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/bash-log.md) - سياسات واتفاقيات التسجيل في OpenIM. -- [CI/CD Actions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/cicd-actions.md) - إجراءات واتفاقيات لـ CI/CD. -- [Commit Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/commit.md) - اتفاقيات لالتزامات الكود في OpenIM. -- [Directory Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/directory.md) - هيكل الدليل واتفاقياته داخل OpenIM. -- [Error Codes](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/error-code.md) - قائمة وأوصاف رموز الخطأ. -- [Go Code Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/go-code.md) - اتفاقيات وتحويلات لكود Go. -- [Docker Image Strategy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/images.md) - استراتيجيات إدارة صور الدوكر في OpenIM، تشمل عدة معماريات ومستودعات الصور. -- [Logging Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/logging.md) - اتفاقيات أكثر تفصيلاً حول التسجيل. -- [Version Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/version.md) - استراتيجيات التسمية والإدارة لإصدارات OpenIM. - - -## للمطورين والمساهمين ومشرفي المجتمع - -### المطورون والمساهمون - -إذا كنت مطورًا أو شخصًا حريصًا على المساهمة: - -- تعرف على [Code Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/code-conventions.md) و[Git Workflow](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/git-workflow.md) لضمان سلاسة المساهمات. -- اغمر نفسك في [Development Guide](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/development.md) للتعرف على ممارسات التطوير في OpenIM. - -### مشرفو المجتمع - -كمشرف على المجتمع: - -- تأكد من أن المساهمات تتوافق مع المعايير الموضحة في وثائقنا. -- راجع بانتظام [Logging Policy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/bash-log.md) و[Error Codes](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/error-code.md) للبقاء على اطلاع. - -## للمستخدمين - -يجب أن يولي المستخدمون اهتمامًا خاصًا لـ: - -- [Docker Installation](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/install-docker.md) - ضروري إذا كنت تخطط لاستخدام صور الدوكر لـ OpenIM. -- [Docker Image Strategy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/images.md) - لفهم الصور المختلفة المتاحة وكيفية اختيار ال diff --git a/docs/README_cs.md b/docs/README_cs.md deleted file mode 100644 index 0c40b63b11..0000000000 --- a/docs/README_cs.md +++ /dev/null @@ -1,67 +0,0 @@ -# Dokumenty serveru OpenIM - -Vítejte v centru dokumentace OpenIM! Toto centrum poskytuje komplexní řadu průvodců a manuálů navržených tak, aby vám pomohly co nejlépe využít vaše zkušenosti s OpenIM. - -## Obsah - -1. [Contrib](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib) - Pokyny pro přispívání a konfigurace pro vývojáře -2. [Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib) - Konvence kódování, zásady protokolování a další transformační nástroje - ------- - -## Contrib - -Tato část nabízí vývojářům podrobný návod, jak přispívat kódem, nastavovat prostředí a sledovat související procesy. - -- [Code Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/code-conventions.md) - Pravidla a konvence pro psaní kódu v OpenIM. -- [Development Guide](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/development.md) - Návod, jak provádět vývoj v rámci OpenIM. -- [Git Cherry Pick](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/gitcherry-pick.md) - Pokyny pro operace sběru třešní. -- [Git Workflow](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/git-workflow.md) - Pracovní postup git v OpenIM. -- [Initialization Configurations](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/init-config.md) - Pokyny k nastavení a inicializaci OpenIM. -- [Docker Installation](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/install-docker.md) - Jak nainstalovat Docker na váš počítač. -- [Linux Development Environment](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/linux-development.md) - Průvodce nastavením vývojového prostředí na Linuxu. -- [Local Actions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/local-actions.md) - Pokyny k provádění určitých společných akcí na místní úrovni. -- [Offline Deployment](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/offline-deployment.md) - Metody nasazení OpenIM offline. -- [Protoc Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/protoc-tools.md) - Průvodce používáním protokolových nástrojů. -- [Go Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-go.md) - Nástroje a knihovny v OpenIM for Go. -- [Makefile Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-makefile.md) - Osvědčené postupy a nástroje pro Makefile. -- [Script Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-scripts.md) - Doporučené postupy a nástroje pro skripty. - -## Konverze - -Tato část představuje různé konvence a zásady v rámci OpenIM, zahrnující kód, protokoly, verze a další. - -- [API Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/api.md) - Pokyny a metody pro konverze API. -- [Logging Policy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/bash-log.md) - Zásady a konvence protokolování v OpenIM. -- [CI/CD Actions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/cicd-actions.md) - Postupy a konvence pro CI/CD. -- [Commit Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/commit.md) - Konvence pro odevzdání kódu v OpenIM. -- [Directory Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/directory.md) - Struktura adresářů a konvence v rámci OpenIM. -- [Error Codes](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/error-code.md) - Seznam a popisy chybových kódů. -- [Go Code Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/go-code.md) - Konvence a převody pro kód Go. -- [Docker Image Strategy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/images.md) - Strategie správy pro obrazy OpenIM Docker, zahrnující různé architektury a úložiště obrazů. -- [Logging Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/logging.md) - Další podrobné konvence o protokolování. -- [Version Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/version.md) - Strategie pojmenování a správy verzí OpenIM. - - -## Pro vývojáře, přispěvatele a správce komunity - -### Vývojáři a přispěvatelé - -Pokud jste vývojář nebo někdo, kdo má zájem přispívat: - -- Seznamte se s našimi [Code Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/code-conventions.md) a [Git Workflow](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/git-workflow.md), abyste zajistili hladké příspěvky. -- Ponořte se do [Development Guide](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/development.md), abyste se seznámili s vývojovými postupy v OpenIM. - -### Správci komunity - -Jako správce komunity: - -- Zajistěte, aby příspěvky odpovídaly standardům uvedeným v naší dokumentaci. -- Pravidelně kontrolujte [Logging Policy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/bash-log.md) a [Error Codes](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/error-code.md) , abyste zůstali aktuální. - -## Pro uživatele - -Uživatelé by měli věnovat zvláštní pozornost: - -- [Docker Installation](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/install-docker.md) - Nezbytné, pokud plánujete používat obrazy OpenIM Docker. -- [Docker Image Strategy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/images.md) - Chcete-li porozumět různým dostupným obrázkům a jak vybrat ten správný pro vaši architekturu. \ No newline at end of file diff --git a/docs/README_da.md b/docs/README_da.md deleted file mode 100644 index d14c6adb5d..0000000000 --- a/docs/README_da.md +++ /dev/null @@ -1,67 +0,0 @@ -# OpenIM Server Dokumentation - -Velkommen til OpenIM Dokumentationscentret! Dette center indeholder en omfattende række vejledninger og manualer, der er designet til at hjælpe dig med at få mest muligt ud af din OpenIM-oplevelse. - -## Indholdsfortegnelse - -1. [Contrib](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib) - Vejledning om bidrag og konfigurationer for udviklere -2. [Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib) - Kodningskonventioner, logningspolitikker og andre transformationsværktøjer - ------- - -## Bidrag - -Denne sektion tilbyder udviklere en detaljeret vejledning om, hvordan de kan bidrage med kode, konfigurere deres miljø og følge de tilknyttede processer. - -- [Kodekonventioner](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/code-conventions.md) - Regler og konventioner for at skrive kode i OpenIM. -- [Udviklingsguide](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/development.md) - En guide om, hvordan man udfører udvikling inden for OpenIM. -- [Git Cherry Pick](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/gitcherry-pick.md) - Retningslinjer for cherry-picking-operationer. -- [Git Workflow](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/git-workflow.md) - Git-workflowen i OpenIM. -- [Initialiseringskonfigurationer](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/init-config.md) - Vejledning om opsætning og initialisering af OpenIM. -- [Docker Installation](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/install-docker.md) - Sådan installeres Docker på din maskine. -- [Linux Udviklingsmiljø](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/linux-development.md) - Guide til opsætning af udviklingsmiljøet på Linux. -- [Lokale handlinger](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/local-actions.md) - Retningslinjer for, hvordan man udfører visse almindelige handlinger lokalt. -- [Offline-deploering](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/offline-deployment.md) - Metoder til at udrulle OpenIM offline. -- [Protoc-værktøjer](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/protoc-tools.md) - Guide til brug af protoc-værktøjer. -- [Go-værktøjer](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-go.md) - Værktøjer og biblioteker i OpenIM til Go. -- [Makefile-værktøjer](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-makefile.md) - Bedste praksis og værktøjer til Makefile. -- [Scriptværktøjer](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-scripts.md) - Bedste praksis og værktøjer til scripts. - -## Konverteringer - -Denne sektion introducerer forskellige konventioner og politikker inden for OpenIM, herunder kode, logfiler, versioner og meget mere. - -- [API-konverteringer](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/api.md) - Retningslinjer og metoder til API-konverteringer. -- [Logningspolitik](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/bash-log.md) - Politikker og konventioner for logning i OpenIM. -- [CI/CD-handlinger](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/cicd-actions.md) - Procedurer og konventioner for CI/CD. -- [Commit-konventioner](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/commit.md) - Konventioner for kodeforpligtelser i OpenIM. -- [Mappekonventioner](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/directory.md) - Mappens struktur og konventioner inden for OpenIM. -- [Fejlkoder](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/error-code.md) - Liste og beskrivelser af fejlkoder. -- [Go-kodekonverteringer](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/go-code.md) - Konventioner og konverteringer for Go-kode. -- [Docker Image-strategi](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/images.md) - Styringsstrategier for OpenIM Docker-billeder, der dækker flere arkitekturer og billedarkiver. -- [Logningskonventioner](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/logging.md) - Yderligere detaljerede konventioner om logning. -- [Versionkonventioner](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/version.md) - Navngivnings- og styringsstrategier for OpenIM-versioner. - - -## For udviklere, bidragsydere og samfundsvedligeholdere - -### Udviklere og bidragsydere - -Hvis du er en udvikler eller nogen, der gerne vil bidrage: - -- Gør dig fortrolig med vores [Kodekonventioner](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/code-conventions.md) og [Git Workflow](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/git-workflow.md) for at sikre en problemfri bidragelse. -- Dyk ned i [Udviklingsguiden](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/development.md) for at få en idé om udviklingspraksis i OpenIM. - -### Samfundsvedligeholdere - -Som samfundsvedligeholder: - -- Sørg for, at bidrag stemmer overens med standarderne beskrevet i vores dokumentation. -- Gennemgå regelmæssigt [Logningspolitikken](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/bash-log.md) og [Fejlkoderne](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/error-code.md) for at holde dig opdateret. - -## For brugere - -Brugere bør være opmærksomme på følgende: - -- [Docker Installation](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/install-docker.md) - Nødvendigt, hvis du planlægger at bruge Docker-billeder af OpenIM. -- [Docker Image-strategi](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/images.md) - For at forstå de forskellige tilgængelige billeder og hvordan man vælger det rigtige for din arkitektur. diff --git a/docs/README_de.md b/docs/README_de.md deleted file mode 100644 index 101eba41b3..0000000000 --- a/docs/README_de.md +++ /dev/null @@ -1,66 +0,0 @@ -# OpenIM-Serverdokumente - -Willkommen im OpenIM-Dokumentationshub! Dieses Zentrum bietet eine umfassende Auswahl an Leitfäden und Handbüchern, die Ihnen dabei helfen sollen, das Beste aus Ihrem OpenIM-Erlebnis herauszuholen. - -## Inhaltsverzeichnis - -1. [Contrib](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib) - Anleitung zu Beiträgen und Konfigurationen für Entwickler -2. [Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib) - Codierungskonventionen, Protokollierungsrichtlinien und andere Transformationstools - ------- - -## Beitrag - -Dieser Abschnitt bietet Entwicklern eine detaillierte Anleitung zum Beitragen von Code, zum Einrichten ihrer Umgebung und zum Befolgen der zugehörigen Prozesse. - -- [Code Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/code-conventions.md) - Regeln und Konventionen zum Schreiben von Code in OpenIM. -- [Development Guide](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/development.md) - Eine Anleitung zur Durchführung der Entwicklung innerhalb von OpenIM. -- [Git Cherry Pick](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/gitcherry-pick.md) - Richtlinien zur Rosinenpickerei. -- [Git Workflow](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/git-workflow.md) - Der Git-Workflow in OpenIM. -- [Initialization Configurations](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/init-config.md) - Anleitung zum Einrichten und Initialisieren von OpenIM. -- [Docker Installation](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/install-docker.md) - So installieren Sie Docker auf Ihrem Computer. -- [Linux Development Environment](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/linux-development.md) - Anleitung zum Einrichten der Entwicklungsumgebung unter Linux. -- [Local Actions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/local-actions.md) - Richtlinien zur Durchführung bestimmter allgemeiner Aktionen vor Ort. -- [Offline Deployment](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/offline-deployment.md) - Methoden zur Offline-Bereitstellung von OpenIM. -- [Protoc Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/protoc-tools.md) - Anleitung zur Verwendung von Protokolltools. -- [Go Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-go.md) - Tools und Bibliotheken in OpenIM für Go. -- [Makefile Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-makefile.md) - Best Practices und Tools für Makefile. -- [Script Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-scripts.md) - Best Practices und Tools für Skripte. - -## Konvertierungen - -In diesem Abschnitt werden verschiedene Konventionen und Richtlinien innerhalb von OpenIM vorgestellt, die Code, Protokolle, Versionen und mehr umfassen. - -- [API Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/api.md) - Richtlinien und Methoden für API-Konvertierungen. -- [Logging Policy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/bash-log.md) - Protokollierungsrichtlinien und -konventionen in OpenIM. -- [CI/CD Actions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/cicd-actions.md) - Verfahren und Konventionen für CI/CD. -- [Commit Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/commit.md) - Konventionen für Code-Commits in OpenIM. -- [Directory Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/directory.md) - Verzeichnisstruktur und Konventionen innerhalb von OpenIM. -- [Error Codes](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/error-code.md) - Liste und Beschreibungen der Fehlercodes. -- [Go Code Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/go-code.md) - Konventionen und Konvertierungen für Go-Code. -- [Docker Image Strategy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/images.md) - Verwaltungsstrategien für OpenIM-Docker-Images, die mehrere Architekturen und Image-Repositorys umfassen. -- [Logging Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/logging.md) - Weitere detaillierte Konventionen zur Protokollierung. -- [Version Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/version.md) - Benennungs- und Verwaltungsstrategien für OpenIM-Versionen. - - -## Für Entwickler, Mitwirkende und Community-Betreuer - -### Entwickler und Mitwirkende - -Wenn Sie Entwickler sind oder gerne einen Beitrag leisten möchten: -- Machen Sie sich mit unseren [Code Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/code-conventions.md) und unserem [Git Workflow](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/git-workflow.md) vertraut, um reibungslose Beiträge zu gewährleisten. -- Tauchen Sie ein in den [Development Guide](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/development.md), um sich mit den Entwicklungspraktiken in OpenIM vertraut zu machen. - -### Community-Betreuer - -Als Community-Betreuer: - -- Stellen Sie sicher, dass die Beiträge den in unserer Dokumentation dargelegten Standards entsprechen. -- Überprüfen Sie regelmäßig die [Logging Policy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/bash-log.md) und die [Error Codes](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/error-code.md), um auf dem Laufenden zu bleiben. - -## Für Benutzer - -Benutzer sollten besonders auf Folgendes achten: - -- [Docker Installation](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/install-docker.md) - Erforderlich, wenn Sie Docker-Images von OpenIM verwenden möchten. -- [Docker Image Strategy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/images.md) - Um die verschiedenen verfügbaren Bilder zu verstehen und wie Sie das richtige für Ihre Architektur auswählen. \ No newline at end of file diff --git a/docs/README_el.md b/docs/README_el.md deleted file mode 100644 index 68438628fd..0000000000 --- a/docs/README_el.md +++ /dev/null @@ -1,67 +0,0 @@ -# Έγγραφα διακομιστή OpenIM - -Καλώς ήρθατε στο κέντρο τεκμηρίωσης OpenIM! Αυτό το κέντρο παρέχει μια ολοκληρωμένη σειρά οδηγών και εγχειριδίων που έχουν σχεδιαστεί για να σας βοηθήσουν να αξιοποιήσετε στο έπακρο την εμπειρία σας στο OpenIM. - -## Πίνακας περιεχομένων - -1. [Contrib](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib) - Οδηγίες για τη συνεισφορά και τις διαμορφώσεις για προγραμματιστές -2. [Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib) - Συμβάσεις κωδικοποίησης, πολιτικές καταγραφής και άλλα εργαλεία μετασχηματισμού - ------- - -## Συνεισφορά - -Αυτή η ενότητα προσφέρει στους προγραμματιστές έναν λεπτομερή οδηγό για το πώς να συνεισφέρουν κώδικα, να ρυθμίσουν το περιβάλλον τους και να ακολουθήσουν τις σχετικές διαδικασίες. - -- [Code Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/code-conventions.md) - Κανόνες και συμβάσεις για τη σύνταξη κώδικα στο OpenIM. -- [Development Guide](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/development.md) - Ένας οδηγός για το πώς να πραγματοποιήσετε ανάπτυξη στο OpenIM. -- [Git Cherry Pick](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/gitcherry-pick.md) - Οδηγίες για τις εργασίες συλλογής κερασιών. -- [Git Workflow](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/git-workflow.md) - Η ροή εργασίας git στο OpenIM. -- [Initialization Configurations](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/init-config.md) - Οδηγίες για τη ρύθμιση και την προετοιμασία του OpenIM. -- [Docker Installation](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/install-docker.md) - Πώς να εγκαταστήσετε το Docker στο μηχάνημά σας. -- [Linux Development Environment](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/linux-development.md) - Οδηγός για τη ρύθμιση του περιβάλλοντος ανάπτυξης στο Linux. -- [Local Actions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/local-actions.md) - Οδηγίες για τον τρόπο εκτέλεσης ορισμένων κοινών ενεργειών σε τοπικό επίπεδο. -- [Offline Deployment](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/offline-deployment.md) - Μέθοδοι ανάπτυξης OpenIM εκτός σύνδεσης. -- [Protoc Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/protoc-tools.md) - Οδηγός χρήσης εργαλείων πρωτοκόλλου. -- [Go Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-go.md) - Εργαλεία και βιβλιοθήκες στο OpenIM for Go. -- [Makefile Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-makefile.md) - Βέλτιστες πρακτικές και εργαλεία για το Makefile. -- [Script Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-scripts.md) - Βέλτιστες πρακτικές και εργαλεία για σενάρια. - -## Μετατροπές - -Αυτή η ενότητα εισάγει διάφορες συμβάσεις και πολιτικές στο OpenIM, που περιλαμβάνουν κώδικα, αρχεία καταγραφής, εκδόσεις και άλλα. - -- [API Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/api.md) - Οδηγίες και μέθοδοι για μετατροπές API. -- [Logging Policy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/bash-log.md) - Πολιτικές και συμβάσεις καταγραφής στο OpenIM. -- [CI/CD Actions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/cicd-actions.md) - Διαδικασίες και συμβάσεις για CI/CD. -- [Commit Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/commit.md) - Συμβάσεις για δεσμεύσεις κώδικα στο OpenIM. -- [Directory Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/directory.md) - Δομή καταλόγου και συμβάσεις στο OpenIM. -- [Error Codes](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/error-code.md) - Λίστα και περιγραφές κωδικών σφαλμάτων. -- [Go Code Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/go-code.md) - Συμβάσεις και μετατροπές για τον κώδικα Go. -- [Docker Image Strategy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/images.md) - Στρατηγικές διαχείρισης για εικόνες OpenIM Docker, που εκτείνονται σε πολλαπλές αρχιτεκτονικές και αποθετήρια εικόνων. -- [Logging Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/logging.md) - Περαιτέρω λεπτομερείς συμβάσεις για την υλοτομία. -- [Version Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/version.md) - Στρατηγικές ονομασίας και διαχείρισης για εκδόσεις OpenIM. - - -## Για προγραμματιστές, συνεισφέροντες και συντηρητές κοινότητας - -### Προγραμματιστές & Συνεισφέροντες - -Εάν είστε προγραμματιστής ή κάποιος που επιθυμεί να συνεισφέρει: - -- Εξοικειωθείτε με τις [Code Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/code-conventions.md) και [Git Workflow](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/git-workflow.md) για να εξασφαλίσετε ομαλή συνεισφορά. -- Βουτήξτε στον [Development Guide](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/development.md) για να δείτε τις πρακτικές ανάπτυξης στο OpenIM. - -### Συντηρητές της Κοινότητας - -Ως συντηρητής κοινότητας: - -- Βεβαιωθείτε ότι οι συνεισφορές ευθυγραμμίζονται με τα πρότυπα που περιγράφονται στην τεκμηρίωσή μας. -- Να ελέγχετε τακτικά την [Logging Policy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/bash-log.md) και τους [Error Codes](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/error-code.md) για να ενημερώνεστε. - -## Για Χρήστες - -Οι χρήστες θα πρέπει να δώσουν ιδιαίτερη προσοχή: - -- [Docker Installation](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/install-docker.md) - Απαραίτητο εάν σκοπεύετε να χρησιμοποιήσετε εικόνες Docker του OpenIM. -- [Docker Image Strategy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/images.md) - Για να κατανοήσετε τις διάφορες διαθέσιμες εικόνες και πώς να επιλέξετε τη σωστή για την αρχιτεκτονική σας. \ No newline at end of file diff --git a/docs/README_eo.md b/docs/README_eo.md deleted file mode 100644 index d7ae8c08cb..0000000000 --- a/docs/README_eo.md +++ /dev/null @@ -1,67 +0,0 @@ -# OpenIM Server Docs - -Bonvenon al la OpenIM Dokumenta nabo! Ĉi tiu centro disponigas ampleksan gamon da gvidiloj kaj manlibroj desegnitaj por helpi vin eltiri la plej grandan parton de via OpenIM-sperto. - -## Enhavtabelo - -1. [Contrib](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib) - Gvidilo pri kontribuado kaj agordoj por programistoj -2. [Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib) - Kodigaj konvencioj, registradaj politikoj kaj aliaj transformaj iloj - ------- - -## Kontribui - -Ĉi tiu sekcio ofertas al programistoj detalan gvidilon pri kiel kontribui kodon, agordi sian medion kaj sekvi la rilatajn procezojn. - -- [Code Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/code-conventions.md) - Reguloj kaj konvencioj por skribi kodon en OpenIM. -- [Development Guide](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/development.md) - Gvidilo pri kiel efektivigi disvolviĝon ene de OpenIM. -- [Git Cherry Pick](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/gitcherry-pick.md) - Gvidlinioj pri ĉeriz-plukaj operacioj. -- [Git Workflow](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/git-workflow.md) - La git-laborfluo en OpenIM. -- [Initialization Configurations](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/init-config.md) - Gvidilo pri agordo kaj pravalorigo de OpenIM. -- [Docker Installation](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/install-docker.md) - Kiel instali Docker sur via maŝino. -- [Linux Development Environment](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/linux-development.md) - Gvidilo por agordi la evolumedion en Linukso. -- [Local Actions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/local-actions.md) - Gvidlinioj pri kiel efektivigi certajn komunajn agojn loke. -- [Offline Deployment](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/offline-deployment.md) - Metodoj por disfaldi OpenIM eksterrete. -- [Protoc Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/protoc-tools.md) - Gvidilo pri uzado de protokaj iloj. -- [Go Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-go.md) - Iloj kaj bibliotekoj en OpenIM for Go. -- [Makefile Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-makefile.md) - Plej bonaj praktikoj kaj iloj por Makefile. -- [Script Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-scripts.md) - Plej bonaj praktikoj kaj iloj por skriptoj. - -## Konvertiĝoj - -Ĉi tiu sekcio enkondukas diversajn konvenciojn kaj politikojn ene de OpenIM, ampleksante kodon, protokolojn, versiojn kaj pli. - -- [API Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/api.md) - Gvidlinioj kaj metodoj por API-konvertoj. -- [Logging Policy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/bash-log.md) - Registrado de politikoj kaj konvencioj en OpenIM. -- [CI/CD Actions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/cicd-actions.md) - Proceduroj kaj konvencioj por CI/CD. -- [Commit Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/commit.md) - Konvencioj por kodoj en OpenIM. -- [Directory Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/directory.md) - Dosierujo-strukturo kaj konvencioj ene de OpenIM. -- [Error Codes](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/error-code.md) - Listo kaj priskriboj de erarkodoj. -- [Go Code Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/go-code.md) - Konvencioj kaj konvertiĝoj por Go-kodo. -- [Docker Image Strategy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/images.md) - Administradstrategioj por OpenIM Docker-bildoj, ampleksante plurajn arkitekturojn kaj bilddeponejojn. -- [Logging Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/logging.md) - Pliaj detalaj konvencioj pri arbohakado. -- [Version Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/version.md) - Strategioj pri nomado kaj administrado por OpenIM-versioj. - - -## Por Programistoj, Kontribuantoj kaj Komunumaj Prizorgantoj - -### Programistoj kaj Kontribuantoj - -Se vi estas programisto aŭ iu fervora kontribui: - -- Familiariĝu kun niaj [Code Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/code-conventions.md) [Git Workflow](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/git-workflow.md) por certigi glatajn kontribuojn. -- Plonĝu en la[Development Guide](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/development.md) por ekkompreni la evolupraktikojn en OpenIM. - -### Komunumaj Prizorgantoj - -Kiel komunuma prizorganto: - -- Certigu, ke kontribuoj kongruas kun la normoj skizitaj en nia dokumentaro. -- Regule reviziu la [Logging Policy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/bash-log.md) kaj [Error Codes](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/error-code.md) por resti ĝisdatigita. - -## Por Uzantoj - -Uzantoj devas aparte atenti: - -- [Docker Installation](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/install-docker.md) - Necesas se vi planas uzi Docker-bildojn de OpenIM. -- [Docker Image Strategy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/images.md) - Por kompreni la malsamajn bildojn disponeblajn kaj kiel elekti la ĝustan por via arkitekturo. \ No newline at end of file diff --git a/docs/README_es.md b/docs/README_es.md deleted file mode 100644 index 96523120ab..0000000000 --- a/docs/README_es.md +++ /dev/null @@ -1,67 +0,0 @@ -# Documentos del servidor OpenIM - -¡Bienvenido al centro de documentación de OpenIM! Este centro proporciona una amplia gama de guías y manuales diseñados para ayudarle a aprovechar al máximo su experiencia OpenIM. - -## Tabla de contenido - -1. [Contrib](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib) - Orientación sobre contribuciones y configuraciones para desarrolladores -2. [Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib) - Convenciones de codificación, políticas de registro y otras herramientas de transformación - ------- - -## Contribuir - -Esta sección ofrece a los desarrolladores una guía detallada sobre cómo contribuir con código, configurar su entorno y seguir los procesos asociados. - -- [Code Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/code-conventions.md) - Reglas y convenciones para escribir código en OpenIM. -- [Development Guide](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/development.md) - Una guía sobre cómo realizar el desarrollo dentro de OpenIM. -- [Git Cherry Pick](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/gitcherry-pick.md) - Directrices sobre operaciones de selección selectiva. -- [Git Workflow](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/git-workflow.md) - El flujo de trabajo de git en OpenIM. -- [Initialization Configurations](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/init-config.md) - Orientación sobre la configuración e inicialización de OpenIM. -- [Docker Installation](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/install-docker.md) - Cómo instalar Docker en su máquina. -- [Linux Development Environment](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/linux-development.md) - Guía para configurar el entorno de desarrollo en Linux. -- [Local Actions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/local-actions.md) - Lineamientos sobre cómo llevar a cabo determinadas acciones comunes a nivel local. -- [Offline Deployment](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/offline-deployment.md) - Métodos de implementación de OpenIM sin conexión. -- [Protoc Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/protoc-tools.md) - Guía sobre el uso de herramientas de protocolo. -- [Go Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-go.md) - Herramientas y bibliotecas en OpenIM for Go. -- [Makefile Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-makefile.md) - Mejores prácticas y herramientas para Makefile. -- [Script Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-scripts.md) - Mejores prácticas y herramientas para scripts. - -## Conversiones - -Esta sección presenta varias convenciones y políticas dentro de OpenIM, que abarcan código, registros, versiones y más. - -- [API Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/api.md) - Directrices y métodos para conversiones de API. -- [Logging Policy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/bash-log.md) - Políticas y convenciones de registro en OpenIM. -- [CI/CD Actions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/cicd-actions.md) - Procedimientos y convenciones para CI/CD. -- [Commit Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/commit.md) - Convenciones para confirmaciones de código en OpenIM. -- [Directory Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/directory.md) - Estructura de directorios y convenciones dentro de OpenIM. -- [Error Codes](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/error-code.md) - Lista y descripciones de códigos de error. -- [Go Code Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/go-code.md) - Convenciones y conversiones para código Go. -- [Docker Image Strategy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/images.md) - Estrategias de gestión para imágenes OpenIM Docker, que abarcan múltiples arquitecturas y repositorios de imágenes. -- [Logging Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/logging.md) - Convenciones más detalladas sobre el registro. -- [Version Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/version.md) - Estrategias de nomenclatura y gestión de versiones OpenIM. - - -## Para desarrolladores, contribuyentes y mantenedores de la comunidad - -### Desarrolladores y colaboradores - -Si eres desarrollador o alguien interesado en contribuir: - -- Familiarícese con nuestras [Code Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/code-conventions.md) y [Git Workflow](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/git-workflow.md) to ensure smooth contributions. -- Sumérgete en la [Development Guide](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/development.md) para familiarizarte con las prácticas de desarrollo en OpenIM. - -### Mantenedores de la comunidad - -Como mantenedor de la comunidad: - -- Asegúrese de que las contribuciones se alineen con los estándares descritos en nuestra documentación. -- Revise periódicamente la [Logging Policy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/bash-log.md) y los [Error Codes](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/error-code.md) para mantenerse actualizado. - -## Para usuarios - -Los usuarios deben prestar especial atención a: - -- [Docker Installation](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/install-docker.md) - Necesario si planea utilizar imágenes Docker de OpenIM. -- [Docker Image Strategy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/images.md) - Comprender las diferentes imágenes disponibles y cómo elegir la adecuada para su arquitectura. \ No newline at end of file diff --git a/docs/README_fa.md b/docs/README_fa.md deleted file mode 100644 index 43056647a7..0000000000 --- a/docs/README_fa.md +++ /dev/null @@ -1,67 +0,0 @@ -# اسناد سرور OpenIM - -به مرکز اسناد OpenIM خوش آمدید! این مرکز طیف گسترده ای از راهنماها و راهنماها را ارائه می دهد که به شما کمک می کند تا از تجربه OpenIM خود بیشترین بهره را ببرید. - -## فهرست مطالب - -1. [Contrib](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib) - راهنمایی در مورد مشارکت و تنظیمات برای توسعه دهندگان -2. [Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib) - کنوانسیون های کدگذاری، سیاست های ورود به سیستم و سایر ابزارهای تبدیل - ------- - -## مشارکت - -این بخش به توسعه دهندگان راهنمای دقیقی در مورد نحوه مشارکت کد، تنظیم محیط خود و پیروی از فرآیندهای مرتبط ارائه می دهد. - -- [Code Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/code-conventions.md) - قوانین و مقررات برای نوشتن کد در OpenIM. -- [Development Guide](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/development.md) - راهنمای نحوه انجام توسعه در OpenIM. -- [Git Cherry Pick](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/gitcherry-pick.md) - دستورالعمل عملیات چیدن گیلاس -- [Git Workflow](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/git-workflow.md) - گردش کار git در OpenIM. -- [Initialization Configurations](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/init-config.md) - راهنمایی در مورد راه اندازی و مقداردهی اولیه OpenIM. -- [Docker Installation](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/install-docker.md) - چگونه داکر را روی دستگاه خود نصب کنیم. -- [Linux Development Environment](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/linux-development.md) - راهنمای راه اندازی محیط توسعه در لینوکس. -- [Local Actions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/local-actions.md) - رهنمودهایی در مورد نحوه انجام برخی از اقدامات مشترک به صورت محلی. -- [Offline Deployment](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/offline-deployment.md) - روش های استقرار OpenIM به صورت آفلاین -- [Protoc Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/protoc-tools.md) - راهنمای استفاده از ابزار پروتک -- [Go Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-go.md) - ابزارها و کتابخانه ها در OpenIM for Go. -- [Makefile Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-makefile.md) - بهترین روش ها و ابزارها برای Makefile. -- [Script Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-scripts.md) - بهترین روش ها و ابزارها برای اسکریپت ها. - -## تبدیل ها - -این بخش قراردادها و سیاست‌های مختلفی را در OpenIM معرفی می‌کند که شامل کد، گزارش‌ها، نسخه‌ها و موارد دیگر می‌شود. - -- [API Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/api.md) - دستورالعمل ها و روش های تبدیل API. -- [Logging Policy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/bash-log.md) - سیاست‌های ورود به سیستم و قراردادها در OpenIM. -- [CI/CD Actions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/cicd-actions.md) - رویه ها و قراردادها برای CI/CD. -- [Commit Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/commit.md) - کنوانسیون‌ها برای تعهدات کد در OpenIM. -- [Directory Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/directory.md) - ساختار دایرکتوری و قراردادها در OpenIM. -- [Error Codes](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/error-code.md) - لیست و توضیحات کدهای خطا -- [Go Code Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/go-code.md) - کنوانسیون ها و تبدیل ها برای کد Go. -- [Docker Image Strategy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/images.md) - استراتژی های مدیریتی برای تصاویر OpenIM Docker، شامل چندین معماری و مخازن تصویر. -- [Logging Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/logging.md) - کنوانسیون های دقیق تر در مورد ورود به سیستم. -- [Version Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/version.md) - استراتژی های نامگذاری و مدیریت برای نسخه های OpenIM. - - -## برای توسعه‌دهندگان، مشارکت‌کنندگان و نگهبانان انجمن - -### توسعه دهندگان و مشارکت کنندگان - -اگر توسعه‌دهنده هستید یا کسی که مشتاق مشارکت است: - -- - برای اطمینان از مشارکت های روان، با [Code Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/code-conventions.md) و [Git Workflow](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/git-workflow.md) ما آشنا شوید. -- - در [Development Guide](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/development.md) شیرجه بزنید تا از شیوه های توسعه در OpenIM مطلع شوید. - -### نگهبانان جامعه - -به عنوان یک نگهدارنده جامعه: - -- اطمینان حاصل کنید که مشارکت ها با استانداردهای ذکر شده در اسناد ما مطابقت دارند. -- [Logging Policy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/bash-log.md) و [Error Codes](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/error-code.md) را به‌طور مرتب مرور کنید تا به‌روز بمانید. - -## برای کاربران - -کاربران باید توجه ویژه ای به موارد زیر داشته باشند: - -- [Docker Installation](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/install-docker.md) - اگر قصد دارید از تصاویر Docker OpenIM استفاده کنید، ضروری است. -- [Docker Image Strategy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/images.md) - برای درک تصاویر مختلف موجود و نحوه انتخاب تصویر مناسب برای معماری خود. \ No newline at end of file diff --git a/docs/README_fi.md b/docs/README_fi.md deleted file mode 100644 index 9678763d97..0000000000 --- a/docs/README_fi.md +++ /dev/null @@ -1,67 +0,0 @@ -# OpenIM Server Docs - -Tervetuloa OpenIM-dokumentaatiokeskukseen! Tämä keskus tarjoaa kattavan valikoiman oppaita ja oppaita, jotka on suunniteltu auttamaan sinua saamaan kaiken irti OpenIM-kokemuksestasi. - -## Sisällysluettelo - -1. [Contrib](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib) - Ohjeita kehittäjille osallistumiseen ja määrityksiin -2. [Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib) - Koodauskäytännöt, lokikäytännöt ja muut muunnostyökalut - ------- - -## Contrib - -Tämä osio tarjoaa kehittäjille yksityiskohtaisen oppaan koodin lisäämisestä, ympäristön määrittämisestä ja siihen liittyvien prosessien seuraamisesta. - -- [Code Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/code-conventions.md) - Säännöt ja käytännöt koodin kirjoittamiselle OpenIM:ssä. -- [Development Guide](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/development.md) - Opas kehitystyön toteuttamiseen OpenIM:ssä. -- [Git Cherry Pick](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/gitcherry-pick.md) - Kirsikoiden poimimista koskevat ohjeet. -- [Git Workflow](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/git-workflow.md) - Git-työnkulku OpenIM:ssä. -- [Initialization Configurations](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/init-config.md) - Ohjeita OpenIM:n käyttöönottoon ja alustamiseen. -- [Docker Installation](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/install-docker.md) - Kuinka asentaa Docker koneellesi. -- [Linux Development Environment](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/linux-development.md) - Ohje kehitysympäristön määrittämiseen Linuxissa. -- [Local Actions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/local-actions.md) - Ohjeita tiettyjen yhteisten toimien toteuttamiseen paikallisesti. -- [Offline Deployment](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/offline-deployment.md) - OpenIM:n offline-käyttöönottomenetelmät. -- [Protoc Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/protoc-tools.md) - Opas protokollatyökalujen käyttöön. -- [Go Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-go.md) - OpenIM for Go -työkalut ja kirjastot. -- [Makefile Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-makefile.md) - Makefilen parhaat käytännöt ja työkalut. -- [Script Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-scripts.md) - Skriptien parhaat käytännöt ja työkalut. - -## Tulokset - -Tässä osiossa esitellään erilaisia OpenIM:n käytäntöjä ja käytäntöjä, jotka kattavat koodin, lokit, versiot ja paljon muuta. - -- [API Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/api.md) - Ohjeita ja menetelmiä API-muunnoksille. -- [Logging Policy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/bash-log.md) - Kirjauskäytännöt ja käytännöt OpenIM:ssä. -- [CI/CD Actions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/cicd-actions.md) - CI/CD:n menettelyt ja käytännöt. -- [Commit Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/commit.md) - OpenIM:n koodisitoumusten käytännöt. -- [Directory Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/directory.md) - Hakemistorakenne ja käytännöt OpenIM:ssä. -- [Error Codes](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/error-code.md) - Luettelo ja kuvaukset virhekoodeista. -- [Go Code Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/go-code.md) - Go-koodin sopimukset ja muunnokset. -- [Docker Image Strategy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/images.md) - Hallintastrategiat OpenIM Docker -kuville, jotka kattavat useita arkkitehtuureja ja kuvavarastoja. -- [Logging Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/logging.md) - Tarkemmat hakkuiden käytännöt. -- [Version Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/version.md) - Nimeämis- ja hallintastrategiat OpenIM-versioille. - - -## Kehittäjille, avustajille ja yhteisön ylläpitäjille - -### Kehittäjät ja avustajat - -Jos olet kehittäjä tai joku, joka haluaa osallistua: - -- Tutustu [Code Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/code-conventions.md)- ja [Git Workflow](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/git-workflow.md) -käytäntöihimme varmistaaksesi sujuvan osallistumisen. -- Sukella [Development Guide](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/development.md) saadaksesi tietoa OpenIM:n kehityskäytännöistä. - -### Yhteisön ylläpitäjät - -Yhteisön ylläpitäjänä: - -- Varmista, että osallistumiset ovat asiakirjoissamme esitettyjen standardien mukaisia. -- Tarkista säännöllisesti [Logging Policy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/bash-log.md) ja [Error Codes](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/error-code.md) pysyäksesi ajan tasalla. - -## Käyttäjille - -Käyttäjien tulee kiinnittää erityistä huomiota: - -- [Docker Installation](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/install-docker.md) - Välttämätön, jos aiot käyttää OpenIM:n Docker-kuvia. -- [Docker Image Strategy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/images.md) - Ymmärtääksesi saatavilla olevat erilaiset kuvat ja kuinka valita oikea arkkitehtuuriisi. \ No newline at end of file diff --git a/docs/README_fr.md b/docs/README_fr.md deleted file mode 100644 index 747ef5349b..0000000000 --- a/docs/README_fr.md +++ /dev/null @@ -1,66 +0,0 @@ -# Documentation du serveur OpenIM - -Bienvenue dans le hub de documentation OpenIM ! Ce centre propose une gamme complète de guides et de manuels conçus pour vous aider à tirer le meilleur parti de votre expérience OpenIM. - -## Table des matières - -1. [Contrib](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib) - Conseils sur la contribution et les configurations pour les développeurs -2. [Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib) - Conventions de codage, politiques de journalisation et autres outils de transformation - ------- - -## Contribuer - -Cette section propose aux développeurs un guide détaillé sur la façon de contribuer au code, de configurer leur environnement et de suivre les processus associés. - -- [Code Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/code-conventions.md) - Règles et conventions pour écrire du code dans OpenIM. -- [Development Guide](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/development.md) - Un guide sur la façon de réaliser du développement au sein d'OpenIM. -- [Git Cherry Pick](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/gitcherry-pick.md) - Lignes directrices sur les opérations de triage. -- [Git Workflow](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/git-workflow.md) - Le flux de travail git dans OpenIM. -- [Initialization Configurations](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/init-config.md) - Conseils sur la configuration et l’initialisation d’OpenIM. -- [Docker Installation](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/install-docker.md) - Comment installer Docker sur votre machine. -- [Linux Development Environment](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/linux-development.md) - Guide pour configurer l'environnement de développement sous Linux. -- [Local Actions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/local-actions.md) - Des lignes directrices pour mener localement certaines actions communes. -- [Offline Deployment](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/offline-deployment.md) - Méthodes de déploiement d'OpenIM hors ligne. -- [Protoc Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/protoc-tools.md) - Guide sur l'utilisation des outils de protocole. -- [Go Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-go.md) - Outils et bibliothèques dans OpenIM for Go. -- [Makefile Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-makefile.md) - Meilleures pratiques et outils pour Makefile. -- [Script Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-scripts.md) - Meilleures pratiques et outils pour les scripts. - -## Conversions - -Cette section présente diverses conventions et politiques au sein d'OpenIM, englobant le code, les journaux, les versions, etc. - -- [API Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/api.md) - Lignes directrices et méthodes pour les conversions API. -- [Logging Policy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/bash-log.md) - Politiques et conventions de journalisation dans OpenIM. -- [CI/CD Actions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/cicd-actions.md) - Politiques et conventions de journalisation dans OpenIM. -- [Commit Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/commit.md) - Politiques et conventions de journalisation dans OpenIM. -- [Directory Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/directory.md) - Structure de répertoire et conventions au sein d'OpenIM. -- [Error Codes](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/error-code.md) - Liste et descriptions des codes d'erreur. -- [Go Code Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/go-code.md) - Conventions et conversions pour le code Go. -- [Docker Image Strategy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/images.md) - Stratégies de gestion des images OpenIM Docker, couvrant plusieurs architectures et référentiels d'images. -- [Logging Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/logging.md) - Conventions plus détaillées sur la journalisation. -- [Version Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/version.md) - Stratégies de nommage et de gestion pour les versions OpenIM. - - -## Pour les développeurs, les contributeurs et les responsables de la communauté - -### Développeurs et contributeurs - -Si vous êtes un développeur ou quelqu'un désireux de contribuer : -- Familiarisez-vous avec nos [Code Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/code-conventions.md) et notre [Git Workflow](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/git-workflow.md) pour garantir des contributions fluides. -- Plongez dans le [Development Guide](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/development.md) pour vous familiariser avec les pratiques de développement dans OpenIM. - -### Responsables de la communauté - -En tant que responsable de la communauté : - -- EAssurez-vous que les contributions sont conformes aux normes décrites dans notre documentation. -- onsultez régulièrement la [Logging Policy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/bash-log.md) et les [Error Codes](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/error-code.md) pour rester à jour. - -## Pour les utilisateurs - -Les utilisateurs doivent prêter une attention particulière à : - -- [Docker Installation](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/install-docker.md) - Nécessaire si vous prévoyez d'utiliser des images Docker d'OpenIM. -- [Docker Image Strategy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/images.md) - Pour comprendre les différentes images disponibles et comment choisir celle qui convient à votre architecture. \ No newline at end of file diff --git a/docs/README_hu.md b/docs/README_hu.md deleted file mode 100644 index 62cb54bb23..0000000000 --- a/docs/README_hu.md +++ /dev/null @@ -1,67 +0,0 @@ -# OpenIM Server Docs - -Üdvözöljük az OpenIM dokumentációs központjában! Ez a központ útmutatók és kézikönyvek átfogó választékát kínálja, amelyek célja, hogy a legtöbbet hozza ki az OpenIM-élményből. - -## Tartalomjegyzék - -1. [Contrib](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib) - Útmutató a fejlesztőknek a hozzájáruláshoz és a konfigurációkhoz -2. [Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib) - Kódolási konvenciók, naplózási szabályzatok és egyéb átalakítási eszközök - ------- - -## Contrib - -Ez a rész részletes útmutatót nyújt a fejlesztőknek a kód hozzáadásával, a környezet beállításával és a kapcsolódó folyamatok követésével kapcsolatban. - -- [Code Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/code-conventions.md) - Az OpenIM kódírásának szabályai és konvenciói. -- [Development Guide](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/development.md) - Útmutató az OpenIM-en belüli fejlesztés végrehajtásához. -- [Git Cherry Pick](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/gitcherry-pick.md) - Útmutató a cseresznyeszedési műveletekhez. -- [Git Workflow](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/git-workflow.md) - A git munkafolyamat az OpenIM-ben. -- [Initialization Configurations](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/init-config.md) - Útmutató az OpenIM beállításához és inicializálásához. -- [Docker Installation](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/install-docker.md) - A Docker telepítése a gépére. -- [Linux Development Environment](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/linux-development.md) - Guide to set up the development environment on Linux. -- [Local Actions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/local-actions.md) - Útmutató a fejlesztői környezet beállításához Linuxon. -- [Offline Deployment](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/offline-deployment.md) - Az OpenIM offline üzembe helyezésének módszerei. -- [Protoc Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/protoc-tools.md) - Útmutató a protokolleszközök használatához. -- [Go Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-go.md) - Eszközök és könyvtárak az OpenIM for Go-ban. -- [Makefile Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-makefile.md) - A Makefile legjobb gyakorlatai és eszközei. -- [Script Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-scripts.md) - Bevált módszerek és eszközök a szkriptekhez. - -## Conversions - -Ez a rész az OpenIM különféle konvencióit és szabályzatait mutatja be, beleértve a kódot, a naplókat, a verziókat és egyebeket. - -- [API Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/api.md) - Irányelvek és módszerek az API-konverziókhoz. -- [Logging Policy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/bash-log.md) - Naplózási szabályzatok és konvenciók az OpenIM-ben. -- [CI/CD Actions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/cicd-actions.md) - CI/CD eljárások és konvenciók. -- [Commit Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/commit.md) - A kód véglegesítésének konvenciói az OpenIM-ben. -- [Directory Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/directory.md) - Címtárszerkezet és konvenciók az OpenIM-en belül. -- [Error Codes](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/error-code.md) - A hibakódok listája és leírása. -- [Go Code Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/go-code.md) - Konvenciók és átalakítások a Go kódhoz. -- [Docker Image Strategy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/images.md) - Kezelési stratégiák az OpenIM Docker-képekhez, amelyek több architektúrára és képtárra is kiterjednek. -- [Logging Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/logging.md) - További részletes egyezmények a fakitermelésről. -- [Version Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/version.md) - Elnevezési és kezelési stratégiák az OpenIM verziókhoz. - - -## Fejlesztőknek, közreműködőknek és közösségi fenntartóknak - -### Fejlesztők és közreműködők - -Ha Ön fejlesztő vagy valaki, aki szeretne hozzájárulni: - -- A zökkenőmentes hozzájárulás érdekében ismerkedjen meg [Code Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/code-conventions.md) és [Git Workflow](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/git-workflow.md)-val. -- Merüljön el a [Development Guide](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/development.md), hogy megismerje az OpenIM fejlesztési gyakorlatát. - -### Közösségfenntartók - -Közösségfenntartóként: - -- Győződjön meg arról, hogy a hozzájárulások megfelelnek a dokumentációnkban felvázolt szabványoknak. -- Rendszeresen tekintse át a [Logging Policy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/bash-log.md) és a [Error Codes](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/error-code.md), hogy naprakész maradjon. - -## Felhasználóknak - -A felhasználóknak különös figyelmet kell fordítaniuk a következőkre: - -- [Docker Installation](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/install-docker.md) - Szükséges, ha az OpenIM Docker-képeit szeretné használni. -- [Docker Image Strategy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/images.md) - Hogy megértse a rendelkezésre álló különböző képeket, és hogyan válassza ki a megfelelőt az építészetéhez. \ No newline at end of file diff --git a/docs/README_id.md b/docs/README_id.md deleted file mode 100644 index 988e25efe9..0000000000 --- a/docs/README_id.md +++ /dev/null @@ -1,67 +0,0 @@ -# Dokumen Server OpenIM - -Selamat datang di pusat Dokumentasi OpenIM! Pusat ini menyediakan berbagai panduan dan manual yang komprehensif untuk membantu Anda memaksimalkan pengalaman Anda dengan OpenIM. - -## Daftar Isi - -1. [Contrib](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib) - Panduan tentang kontribusi dan konfigurasi untuk pengembang -2. [Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib) - Konvensi pengkodean, kebijakan logging, dan alat transformasi lainnya - ------- - -## Contrib - -Bagian ini menawarkan panduan rinci bagi pengembang tentang cara berkontribusi kode, menyiapkan lingkungan mereka, dan mengikuti proses yang terkait. - -- [Code Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/code-conventions.md) - Aturan dan konvensi untuk menulis kode di OpenIM. -- [Development Guide](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/development.md) - Panduan tentang cara melakukan pengembangan di dalam OpenIM. -- [Git Cherry Pick](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/gitcherry-pick.md) - Pedoman tentang operasi cherry-picking. -- [Git Workflow](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/git-workflow.md) - Alur kerja git di OpenIM. -- [Initialization Configurations](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/init-config.md) - Panduan untuk mengatur dan menginisialisasi OpenIM. -- [Docker Installation](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/install-docker.md) - Cara memasang Docker di mesin Anda. -- [Linux Development Environment](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/linux-development.md) - Panduan untuk menyiapkan lingkungan pengembangan di Linux. -- [Local Actions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/local-actions.md) - Pedoman tentang cara melakukan beberapa tindakan umum secara lokal. -- [Offline Deployment](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/offline-deployment.md) - Metode penyebaran OpenIM secara offline. -- [Protoc Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/protoc-tools.md) - Panduan tentang menggunakan alat protoc. -- [Go Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-go.md) - Alat dan perpustakaan di OpenIM untuk Go. -- [Makefile Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-makefile.md) - Praktik terbaik dan alat untuk Makefile. -- [Script Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-scripts.md) - Praktik terbaik dan alat untuk skrip. - -## Conversions - -Bagian ini memperkenalkan berbagai konvensi dan kebijakan dalam OpenIM, meliputi kode, log, versi, dan lainnya. - -- [API Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/api.md) - Pedoman dan metode untuk konversi API. -- [Logging Policy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/bash-log.md) - Kebijakan dan konvensi logging di OpenIM. -- [CI/CD Actions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/cicd-actions.md) - Prosedur dan konvensi untuk CI/CD. -- [Commit Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/commit.md) - Konvensi untuk commit kode di OpenIM. -- [Directory Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/directory.md) - Struktur direktori dan konvensi dalam OpenIM. -- [Error Codes](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/error-code.md) - Daftar dan deskripsi kode kesalahan. -- [Go Code Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/go-code.md) - Konvensi dan konversi untuk kode Go. -- [Docker Image Strategy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/images.md) - Strategi manajemen gambar Docker OpenIM, mencakup berbagai arsitektur dan repositori gambar. -- [Logging Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/logging.md) - Konvensi logging yang lebih detail. -- [Version Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/version.md) - Strategi penamaan dan manajemen versi OpenIM. - - -## Untuk Pengembang, Kontributor, dan Pemelihara Komunitas - -### Pengembang & Kontributor - -Jika Anda seorang pengembang atau seseorang yang ingin berkontribusi: - -- Kenali [Code Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/code-conventions.md) dan [Git Workflow](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/git-workflow.md) kami untuk memastikan kontribusi yang lancar. -- Pelajari [Development Guide](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/development.md) untuk memahami praktik pengembangan di OpenIM. - -### Pemelihara Komunitas - -Sebagai pemelihara komunitas: - -- Pastikan kontribusi sesuai dengan standar yang diuraikan dalam dokumentasi kami. -- Tinjau secara teratur [Logging Policy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/bash-log.md) dan [Error Codes](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/error-code.md) untuk tetap terupdate. - -## Untuk Pengguna - -Pengguna harus memberikan perhatian khusus kepada: - -- [Docker Installation](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/install-docker.md) - Diperlukan jika Anda berencana menggunakan gambar Docker dari OpenIM. -- [Docker Image Strategy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/images.md) - Untuk memahami gambar yang tersedia dan bagaimana memilih yang tepat untuk arsitektur Anda. diff --git a/docs/README_it.md b/docs/README_it.md deleted file mode 100644 index 76e41b5e7b..0000000000 --- a/docs/README_it.md +++ /dev/null @@ -1,67 +0,0 @@ -# Documentazione del Server OpenIM - -Benvenuti al centro documentazione di OpenIM! Questo centro offre una gamma completa di guide e manuali progettati per aiutarvi a ottenere il massimo dalla vostra esperienza con OpenIM. - -## Indice dei Contenuti - -1. [Contrib](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib) - Guida al contributo e alle configurazioni per gli sviluppatori -2. [Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib) - Convenzioni di codifica, politiche di registrazione e altri strumenti di trasformazione - ------- - -## Contrib - -Questa sezione offre agli sviluppatori una guida dettagliata su come contribuire al codice, configurare il loro ambiente e seguire i processi associati. - -- [Code Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/code-conventions.md) - Regole e convenzioni per scrivere codice in OpenIM. -- [Development Guide](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/development.md) - Una guida su come svolgere lo sviluppo all'interno di OpenIM. -- [Git Cherry Pick](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/gitcherry-pick.md) - Linee guida sulle operazioni di cherry-picking. -- [Git Workflow](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/git-workflow.md) - Il flusso di lavoro git in OpenIM. -- [Initialization Configurations](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/init-config.md) - Guida per configurare e inizializzare OpenIM. -- [Docker Installation](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/install-docker.md) - Come installare Docker sul tuo dispositivo. -- [Linux Development Environment](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/linux-development.md) - Guida per configurare l'ambiente di sviluppo su Linux. -- [Local Actions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/local-actions.md) - Linee guida su come eseguire determinate azioni comuni localmente. -- [Offline Deployment](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/offline-deployment.md) - Metodi per distribuire OpenIM offline. -- [Protoc Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/protoc-tools.md) - Guida all'uso degli strumenti protoc. -- [Go Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-go.md) - Strumenti e librerie in OpenIM per Go. -- [Makefile Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-makefile.md) - Migliori pratiche e strumenti per Makefile. -- [Script Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-scripts.md) - Migliori pratiche e strumenti per gli script. - -## Conversions - -Questa sezione introduce varie convenzioni e politiche all'interno di OpenIM, che comprendono codice, registrazioni, versioni e altro. - -- [API Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/api.md) - Linee guida e metodi per le conversioni API. -- [Logging Policy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/bash-log.md) - Politiche e convenzioni di registrazione in OpenIM. -- [CI/CD Actions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/cicd-actions.md) - Procedure e convenzioni per CI/CD. -- [Commit Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/commit.md) - Convenzioni per i commit di codice in OpenIM. -- [Directory Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/directory.md) - Struttura delle directory e convenzioni all'interno di OpenIM. -- [Error Codes](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/error-code.md) - Elenco e descrizioni dei codici di errore. -- [Go Code Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/go-code.md) - Convenzioni e conversioni per il codice Go. -- [Docker Image Strategy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/images.md) - Strategie di gestione delle immagini Docker di OpenIM, che coprono più architetture e repository di immagini. -- [Logging Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/logging.md) - Ulteriori dettagliate convenzioni sulla registrazione. -- [Version Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/version.md) - Strategie di denominazione e gestione delle versioni di OpenIM. - - -## Per Sviluppatori, Contributori e Manutentori della Comunità - -### Sviluppatori & Contributori - -Se sei uno sviluppatore o qualcuno interessato a contribuire: - -- Familiarizza con le nostre [Code Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/code-conventions.md) e [Git Workflow](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/git-workflow.md) per garantire contributi fluidi. -- Approfondisci la [Development Guide](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/development.md) per ottenere una conoscenza delle pratiche di sviluppo in OpenIM. - -### Manutentori della Comunità - -Come manutentore della comunità: - -- Assicurati che i contributi siano in linea con gli standard delineati nella nostra documentazione. -- Rivedi regolarmente la [Logging Policy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/bash-log.md) e [Error Codes](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/error-code.md) per rimanere aggiornato. - -## Per gli Utenti - -Gli utenti dovrebbero prestare particolare attenzione a: - -- [Docker Installation](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/install-docker.md) - Necessario se si prevede di utilizzare le immagini Docker di OpenIM. -- [Docker Image Strategy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/images.md) - Per comprendere le diverse immagini disponibili e come scegliere quella giusta per la propria architettura. diff --git a/docs/README_ja.md b/docs/README_ja.md deleted file mode 100644 index 3971037fb6..0000000000 --- a/docs/README_ja.md +++ /dev/null @@ -1,67 +0,0 @@ -# OpenIMサーバードキュメンテーション - -OpenIMドキュメンテーションハブへようこそ!このセンターでは、OpenIM体験を最大限に活用するための包括的なガイドとマニュアルを提供しています。 - -## 目次 - -1. [Contrib](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib) - 開発者向けの貢献と設定に関するガイダンス -2. [Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib) - コーディング規約、ログポリシー、その他の変換ツール - ------- - -## 投稿 - -このセクションでは、開発者がコードを貢献し、環境を設定し、関連するプロセスに従う方法についての詳細なガイドを提供します。 - -- [Code Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/code-conventions.md) - OpenIMでのコード記述のルールと規約。 -- [Development Guide](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/development.md) - OpenIM内での開発を行うためのガイド。 -- [Git Cherry Pick](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/gitcherry-pick.md) - チェリーピッキング操作のガイドライン。 -- [Git Workflow](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/git-workflow.md) - OpenIMにおけるGitのワークフロー。 -- [Initialization Configurations](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/init-config.md) - OpenIMの設定と初期化に関するガイダンス。 -- [Docker Installation](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/install-docker.md) - マシンにDockerをインストールする方法。 -- [Linux Development Environment](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/linux-development.md) - Linux上での開発環境の設定ガイド。 -- [Local Actions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/local-actions.md) - ローカルで一般的なアクションを実行する方法に関するガイドライン。 -- [Offline Deployment](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/offline-deployment.md) - OpenIMをオフラインでデプロイする方法。 -- [Protoc Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/protoc-tools.md) - protocツールの使用ガイド。 -- [Go Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-go.md) - GoのためのOpenIM内のツールとライブラリ。 -- [Makefile Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-makefile.md) - Makefileのベストプラクティスとツール。 -- [Script Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-scripts.md) - スクリプトのベストプラクティスとツール。 - -## Conversions - -このセクションでは、OpenIM内のさまざまな規約とポリシーを紹介します。これには、コード、ログ、バージョンなどが含まれます。 - -- [API Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/api.md) - API変換のためのガイドラインと方法。 -- [Logging Policy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/bash-log.md) - OpenIMにおけるログポリシーと規約。 -- [CI/CD Actions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/cicd-actions.md) - CI/CDの手順と規約。 -- [Commit Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/commit.md) - OpenIMでのコードコミットのための規約。 -- [Directory Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/directory.md) - OpenIM内のディレクトリ構造と規約。 -- [Error Codes](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/error-code.md) - エラーコードのリストと説明。 -- [Go Code Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/go-code.md) - Goコードのための規約と変換。 -- [Docker Image Strategy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/images.md) - 複数のアーキテクチャとイメージリポジトリにまたがるOpenIM Dockerイメージの管理戦略。 -- [Logging Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/logging.md) - ロギングに関するさらに詳細な規約。 -- [Version Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/version.md) - OpenIMバージョンの命名と管理戦略。 - - -## 開発者、コントリビューター、コミュニティメンテナー向け - -### 開発者およびコントリビューター - -開発者または貢献に熱心な方へ: - -- スムーズな貢献を確実にするために、私たちの[Code Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/code-conventions.md)と[Git Workflow](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/git-workflow.md)に慣れ親しみましょう。 -- OpenIMの開発実践に慣れるために、[Development Guide](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/development.md)をご覧ください。 - -### コミュニティメンテナー - -コミュニティメンテナーとして: - -- 貢献が私たちのドキュメンテーションで概説された基準に沿っていることを確認してください。 -- 最新の情報を得るために、定期的に[Logging Policy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/bash-log.md)と[Error Codes](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/error-code.md)をレビューしてください。 - -## ユーザー向け - -ユーザーは特に以下の点に注意してください: - -- [Docker Installation](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/install-docker.md) - OpenIMのDockerイメージを使用する予定の場合に必要です。 -- [Docker Image Strategy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/images.md) - 利用可能なさまざまなイメージを理解し、アーキテクチャに適したものを選択する方法。 diff --git a/docs/README_ko.md b/docs/README_ko.md deleted file mode 100644 index 9cd728c5d9..0000000000 --- a/docs/README_ko.md +++ /dev/null @@ -1,67 +0,0 @@ -# OpenIM 서버 문서 - -OpenIM 문서 허브에 오신 것을 환영합니다! 이 센터는 OpenIM 경험을 최대한 활용하는 데 도움이 되도록 다양한 가이드와 매뉴얼을 제공합니다. - -## 목차 - -1. [Contrib](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib) - 개발자를 위한 기여 및 구성에 대한 안내 -2. [Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib) - 코딩 규칙, 로깅 정책 및 기타 변환 도구 - ------- - -## 기여 - -이 섹션은 개발자들에게 코드를 기여하는 방법, 환경을 설정하는 방법 및 관련 프로세스를 따르는 방법에 대한 자세한 가이드를 제공합니다. - -- [Code Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/code-conventions.md) - OpenIM에서 코드를 작성하기 위한 규칙 및 규약. -- [Development Guide](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/development.md) - OpenIM 내에서 개발을 수행하는 방법에 대한 가이드. -- [Git Cherry Pick](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/gitcherry-pick.md) - 체리피킹 작업에 대한 지침. -- [Git Workflow](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/git-workflow.md) - OpenIM에서의 깃 워크플로우. -- [Initialization Configurations](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/init-config.md) - OpenIM 설정 및 초기화에 대한 안내. -- [Docker Installation](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/install-docker.md) - 컴퓨터에 도커를 설치하는 방법. -- [Linux Development Environment](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/linux-development.md) - 리눅스에서 개발 환경을 설정하는 가이드. -- [Local Actions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/local-actions.md) - 일부 일반적인 작업을 로컬에서 수행하는 방법에 대한 지침. -- [Offline Deployment](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/offline-deployment.md) - 오프라인에서 OpenIM을 배포하는 방법. -- [Protoc Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/protoc-tools.md) - 프로토콜 도구 사용에 대한 가이드. -- [Go Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-go.md) - Go용 OpenIM 도구 및 라이브러리. -- [Makefile Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-makefile.md) - 메이크파일을 위한 모범 사례 및 도구. -- [Script Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-scripts.md) - 스크립트를 위한 모범 사례 및 도구. - -## 전환 - -이 섹션에서는 코드, 로그, 버전 등을 포함하는 OpenIM 내의 다양한 규칙과 정책을 소개합니다. - -- [API Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/api.md) - API 변환을 위한 지침 및 방법. -- [Logging Policy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/bash-log.md) - OpenIM의 로깅 정책 및 관습. -- [CI/CD Actions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/cicd-actions.md) - CI/CD 절차 및 관습. -- [Commit Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/commit.md) - OpenIM에서 코드 커밋을 위한 관습. -- [Directory Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/directory.md) - OpenIM 내의 디렉토리 구조 및 관습. -- [Error Codes](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/error-code.md) - 오류 코드 목록 및 설명. -- [Go Code Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/go-code.md) - Go 코드를 위한 관습 및 변환. -- [Docker Image Strategy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/images.md) - 다양한 아키텍처 및 이미지 저장소를 아우르는 OpenIM Docker 이미지 관리 전략. -- [Logging Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/logging.md) - 로깅에 대한 추가적인 상세한 관습. -- [Version Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/version.md) - OpenIM 버전의 명명 및 관리 전략. - - -## 개발자, 기여자 및 커뮤니티 관리자를 위한 정보 - -### 개발자 및 기여자 - -개발자이거나 기여에 관심이 있다면: - -- 원활한 기여를 위해 [Code Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/code-conventions.md) 및 [Git Workflow](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/git-workflow.md)에 익숙해지십시오. -- OpenIM에서의 개발 관행을 파악하려면 [Development Guide](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/development.md)를 참조하십시오. - -### 커뮤니티 관리자 - -커뮤니티 관리자로서: - -- 기여가 우리 문서에 명시된 표준에 부합하는지 확인하십시오. -- [Logging Policy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/bash-log.md) 및 [Error Codes](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/error-code.md)를 정기적으로 검토하여 최신 정보를 유지하십시오. - -## 사용자를 위한 정보 - -사용자는 특히 다음 사항에 주의를 기울여야 합니다: - -- [Docker Installation](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/install-docker.md) - OpenIM의 Docker 이미지를 사용할 계획이라면 필요합니다. -- [Docker Image Strategy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/images.md) - 사용 가능한 다양한 이미지를 이해하고 아키텍처에 적합한 이미지를 선택하는 방법. diff --git a/docs/README_ml.md b/docs/README_ml.md deleted file mode 100644 index 7f3aa8c0df..0000000000 --- a/docs/README_ml.md +++ /dev/null @@ -1,67 +0,0 @@ -# OpenIM സെർവർ ഡോക്യുമെന്റേഷൻ - -OpenIM ഡോക്യുമെന്റേഷൻ ഹബ്ബിലേക്ക് സ്വാഗതം! ഈ കേന്ദ്രം OpenIM അനുഭവത്തിൽ നിന്ന് പരമാവധി ഉപയോഗം നേടാൻ സഹായിക്കുന്ന വ്യാപകമായ നിർദേശങ്ങളുടെയും മാനുവലുകളുടെയും ശ്രേണി നൽകുന്നു. - -## ഉള്ളടക്കം - -1. [Contrib](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib) - ഡെവലപ്പർമാർക്കുള്ള സംഭാവനകൾ നൽകുന്നതിനും കോൺഫിഗറേഷനുകൾക്കുള്ള നിർദേശങ്ങൾ -2. [Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib) - കോഡിംഗ് കൺവെൻഷനുകൾ, ലോഗ്ഗിംഗ് നയങ്ങൾ, മറ്റ് പരിവർത്തന ഉപകരണങ്ങൾ - ------- - -## Contrib - -ഈ ഭാഗം ഡെവലപ്പർമാർക്ക് കോഡ് സംഭാവന നൽകുന്നതിന്റെയും അവരുടെ പരിസ്ഥിതി സജ്ജമാക്കുന്നതിന്റെയും ബന്ധപ്പെട്ട പ്രക്രിയകൾ പിന്തുടരുന്നതിന്റെയും വിശദമായ ഗൈഡ് നൽകുന്നു. - -- [Code Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/code-conventions.md) - OpenIM-ൽ കോഡ് എഴുതുന്നതിന്റെ നിയമങ്ങൾ കൺവെൻഷനുകൾ. -- [Development Guide](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/development.md) - OpenIM-ൽ വികസനം നടത്തുന്നതിന്റെ ഗൈഡ്. -- [Git Cherry Pick](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/gitcherry-pick.md) - ചെറി-പിക്കിംഗ് ഓപ്പറേഷനുകൾക്കുള്ള മാർഗ്ഗനിർദേശങ്ങൾ. -- [Git Workflow](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/git-workflow.md) - OpenIM-ൽ ഗിറ്റിന്റെ വർക്ക്ഫ്ലോ. -- [Initialization Configurations](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/init-config.md) - OpenIM സജ്ജമാക്കുന്നതിനും ആരംഭിക്കുന്നതിനും നിർദേശങ്ങൾ. -- [Docker Installation](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/install-docker.md) - നിങ്ങളുടെ യന്ത്രത്തിൽ ഡോക്കർ ഇൻസ്റ്റാൾ ചെയ്യുന്ന രീതി. -- [Linux Development Environment](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/linux-development.md) - ലിനക്സിൽ വികസന പരിസ്ഥിതി സജ്ജമാക്കുന്നതിന്റെ ഗൈഡ്. -- [Local Actions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/local-actions.md) - ചില പൊതുവായ നടപടികൾ പ്രദേശികമായി നടത്തുന്നതിന്റെ മാർഗ്ഗനിർദേശങ്ങൾ. -- [Offline Deployment](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/offline-deployment.md) - OpenIM ഓഫ്‌ലൈൻ ഡിപ്ലോയ് ചെയ്യുന്ന രീതികൾ. -- [Protoc Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/protoc-tools.md) - പ്രോട്ടോക് ഉപകരണങ്ങൾ ഉപയോഗിക്കുന്ന ഗൈഡ്. -- [Go Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-go.md) - Go വേണ്ടി OpenIM-ൽ ഉള്ള ഉപകരണങ്ങളും ലൈബ്രറികളും. -- [Makefile Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-makefile.md) - Makefile ഉപകരണങ്ങളുടെയും മികച്ച പ്രാക്ടീസുകളുടെയും ഗൈഡ്. -- [Script Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-scripts.md) - സ്ക്രിപ്റ്റുകൾക്കുള്ള മികച്ച പ്രാക്ടീസുകളും ഉപകരണങ്ങളും. - -## Conversions - -ഈ ഭാഗം OpenIM-ൽ ഉള്ള വിവിധ കൺവെൻഷനുകളെയും നയങ്ങളെയും ആവിഷ്കരിക്കുന്നു, ഇതിൽ കോഡ്, ലോഗുകൾ, പതിപ്പുകൾ എന്നിവ ഉൾപ്പെടുന്നു. - -- [API Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/api.md) - API കൺവെർഷനുകൾക്കുള്ള നിർദേശങ്ങൾ രീതികൾ. -- [Logging Policy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/bash-log.md) - OpenIM-ൽ ലോഗ്ഗിംഗ് നയങ്ങൾ കൺവെൻഷനുകൾ. -- [CI/CD Actions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/cicd-actions.md) - CI/CD പ്രക്രിയകൾ കൺവെൻഷനുകൾ. -- [Commit Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/commit.md) - OpenIM-ൽ കോഡ് കമ്മിറ്റുകൾക്കുള്ള കൺവെൻഷനുകൾ. -- [Directory Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/directory.md) - OpenIM-ൽ ഡയറക്ടറി ഘടന കൺവെൻഷനുകൾ. -- [Error Codes](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/error-code.md) - പിശക് കോഡുകളുടെ പട്ടിക വിവരണങ്ങൾ. -- [Go Code Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/go-code.md) - Go കോഡിനുള്ള കൺവെൻഷനുകൾ പരിവർത്തനങ്ങൾ. -- [Docker Image Strategy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/images.md) - വിവിധ ആർക്കിടെക്ചറുകൾ ഇമേജ് റെപ്പോസിറ്ററികൾ ഉൾപ്പെടുന്ന OpenIM Docker ഇമേജുകളുടെ മാനേജ്മെന്റ് സ്ട്രാറ്റജീസ്. -- [Logging Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/logging.md) - ലോഗ്ഗിംഗിന്റെ കൂടുതൽ വിശദമായ കൺവെൻഷനുകൾ. -- [Version Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/version.md) - OpenIM പതിപ്പുകൾക്കുള്ള നാമകരണ മാനേജ്മെന്റ് സ്ട്രാറ്റജീസ്. - - -## ഡെവലപ്പർമാർക്കും, സംഭാവനകൾ നൽകുന്നവർക്കും, കമ്മ്യൂണിറ്റി മെയിന്റെയിനർമാർക്കും - -### ഡെവലപ്പർമാർ & സംഭാവനകൾ നൽകുന്നവർ - -നിങ്ങൾ ഒരു ഡെവലപ്പർ അല്ലെങ്കിൽ സംഭാവനകൾ നൽകാൻ ആഗ്രഹിക്കുന്ന ആളാണെങ്കിൽ: - -- നിരവധി സംഭാവനകൾ ഉറപ്പാക്കാൻ ഞങ്ങളുടെ [Code Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/code-conventions.md) എന്നിവയുമായി പരിചിതരാകുക. -- OpenIM-ൽ വികസന പ്രാക്ടീസുകൾ ലഭ്യമാക്കാൻ [Development Guide](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/development.md) അന്വേഷിക്കുക. - -### കമ്മ്യൂണിറ്റി മെയിന്റെയിനർമാർ - -ഒരു കമ്മ്യൂണിറ്റി മെയിന്റെയിനറായി: - -- സംഭാവനകൾ ഞങ്ങളുടെ ഡോക്യുമെന്റേഷനിൽ വിവരിച്ച മാനദണ്ഡങ്ങൾക്ക് അനുസൃതമാണെന്ന് ഉറപ്പാക്കുക. -- [Logging Policy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/bash-log.md) എന്നിവ പുതുക്കി വായിക്കുക. - -## ഉപയോക്താക്കൾക്ക് - -ഉപയോക്താക്കൾ പ്രത്യേകം ശ്രദ്ധിക്കേണ്ട കാര്യങ്ങൾ: - -- [Docker Installation](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/install-docker.md) - OpenIM-ന്റെ ഡോക്കർ ഇമേജുകൾ ഉപയോഗിക്കാൻ പദ്ധതിയിടുന്നെങ്കിൽ ആവശ്യമാണ്. -- [Docker Image Strategy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/images.md) - ലഭ്യമായ വിവിധ ഇമേജുകൾ മനസ്സിലാക്കുകയും നിങ്ങളുടെ ആർക്കിടെക്ചറിന് അനുയോജ്യമായത് എങ്ങനെ തിരഞ്ഞെടുക്കണം എന്ന് അറിയുക. diff --git a/docs/README_nl.md b/docs/README_nl.md deleted file mode 100644 index 755145e6f4..0000000000 --- a/docs/README_nl.md +++ /dev/null @@ -1,67 +0,0 @@ -# OpenIM Server-documenten - -Welkom bij de OpenIM-documentatiehub! Dit centrum biedt een uitgebreide reeks handleidingen en handleidingen die zijn ontworpen om u te helpen het meeste uit uw OpenIM-ervaring te halen. - -## Inhoudsopgave - -1. [Contrib](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib) - Richtlijnen voor bijdragen en configuraties voor ontwikkelaars -2. [Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib) - Codeerconventies, logboekbeleid en andere transformatietools - ------- - -## Draag bij - -Deze sectie biedt ontwikkelaars een gedetailleerde handleiding over hoe ze code kunnen bijdragen, hun omgeving kunnen instellen en de bijbehorende processen kunnen volgen. - -- [Code Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/code-conventions.md) - Regels en conventies voor het schrijven van code in OpenIM. -- [Development Guide](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/development.md) - Een handleiding voor het uitvoeren van ontwikkelingen binnen OpenIM. -- [Git Cherry Pick](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/gitcherry-pick.md) - Richtlijnen voor kersenplukoperaties. -- [Git Workflow](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/git-workflow.md) - De git-workflow in OpenIM. -- [Initialization Configurations](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/init-config.md) - Begeleiding bij het instellen en initialiseren van OpenIM. -- [Docker Installation](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/install-docker.md) - Hoe Docker op uw machine te installeren. -- [Linux Development Environment](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/linux-development.md) - Handleiding voor het opzetten van de ontwikkelomgeving op Linux. -- [Local Actions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/local-actions.md) - Richtlijnen voor het lokaal uitvoeren van bepaalde gemeenschappelijke acties. -- [Offline Deployment](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/offline-deployment.md) - Methoden voor het offline inzetten van OpenIM. -- [Protoc Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/protoc-tools.md) - Handleiding voor het gebruik van protocoltools. -- [Go Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-go.md) - Tools en bibliotheken in OpenIM for Go. -- [Makefile Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-makefile.md) - Best practices en tools voor Makefile. -- [Script Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-scripts.md) - Best practices en tools voor scripts. - -## Conversies - -In deze sectie worden verschillende conventies en beleidsregels binnen OpenIM geïntroduceerd, waaronder code, logs, versies en meer. - -- [API Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/api.md) - Richtlijnen en methoden voor API-conversies. -- [Logging Policy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/bash-log.md) - Logboekbeleid en -conventies in OpenIM. -- [CI/CD Actions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/cicd-actions.md) - Procedures en conventies voor CI/CD. -- [Commit Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/commit.md) - Conventies voor code-commits in OpenIM. -- [Directory Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/directory.md) - Directorystructuur en conventies binnen OpenIM. -- [Error Codes](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/error-code.md) - Lijst en beschrijvingen van foutcodes. -- [Go Code Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/go-code.md) - Conventies en conversies voor Go-code. -- [Docker Image Strategy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/images.md) - Beheerstrategieën voor OpenIM Docker-images, verspreid over meerdere architecturen en image-opslagplaatsen. -- [Logging Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/logging.md) - Verdere gedetailleerde conventies over houtkap. -- [Version Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/version.md) - Naamgevings- en beheerstrategieën voor OpenIM-versies. - - -## Voor ontwikkelaars, bijdragers en communitybeheerders - -### Ontwikkelaars en bijdragers - -Als u een ontwikkelaar bent of iemand die graag een bijdrage wil leveren: - -- Maak uzelf vertrouwd met onze [Code Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/code-conventions.md) en [Git Workflow](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/git-workflow.md) om soepele bijdragen te garanderen. -- Duik in de [Development Guide](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/development.md) om de ontwikkelpraktijken in OpenIM onder de knie te krijgen. - -### Gemeenschapsbeheerders - -Als gemeenschapsbeheerder: - -- Zorg ervoor dat bijdragen in overeenstemming zijn met de normen die in onze documentatie worden beschreven. -- Controleer regelmatig het [Logging Policy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/bash-log.md) en de [Error Codes](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/error-code.md) om op de hoogte te blijven. - -## Voor gebruikers - -Gebruikers moeten bijzondere aandacht besteden aan: - -- [Docker Installation](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/install-docker.md) - Noodzakelijk als u van plan bent Docker-images van OpenIM te gebruiken. -- [Docker Image Strategy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/images.md) - Om de verschillende beschikbare afbeeldingen te begrijpen en hoe u de juiste voor uw architectuur kiest. \ No newline at end of file diff --git a/docs/README_pl.md b/docs/README_pl.md deleted file mode 100644 index 9e89c9dae3..0000000000 --- a/docs/README_pl.md +++ /dev/null @@ -1,67 +0,0 @@ -# Dokumentacja serwera OpenIM - -Witamy w centrum dokumentacji OpenIM! Centrum to zapewnia kompleksową gamę przewodników i podręczników zaprojektowanych, aby pomóc Ci w pełni wykorzystać możliwości OpenIM. - -## Spis treści - -1. [Contrib](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib) - Wskazówki dotyczące współtworzenia i konfiguracji dla programistów -2. [Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib) - Konwencje kodowania, zasady rejestrowania i inne narzędzia do transformacji - ------- - -## Wkład - -W tej sekcji deweloperzy mogą znaleźć szczegółowy przewodnik dotyczący udostępniania kodu, konfigurowania środowiska i wykonywania powiązanych procesów. - -- [Code Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/code-conventions.md) - Zasady i konwencje pisania kodu w OpenIM. -- [Development Guide](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/development.md) - Poradnik dotyczący programowania w OpenIM. -- [Git Cherry Pick](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/gitcherry-pick.md) - Wytyczne dotyczące operacji zbierania wiśni. -- [Git Workflow](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/git-workflow.md) - Przepływ pracy git w OpenIM. -- [Initialization Configurations](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/init-config.md) - Wskazówki dotyczące konfigurowania i inicjowania OpenIM. -- [Docker Installation](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/install-docker.md) - Jak zainstalować Docker na swoim komputerze. -- [Linux Development Environment](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/linux-development.md) - Przewodnik po konfigurowaniu środowiska programistycznego w systemie Linux. -- [Local Actions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/local-actions.md) - Wytyczne dotyczące sposobu przeprowadzania niektórych typowych działań lokalnie. -- [Offline Deployment](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/offline-deployment.md) - Metody wdrażania OpenIM offline. -- [Protoc Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/protoc-tools.md) - Przewodnik dotyczący korzystania z narzędzi protoc. -- [Go Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-go.md) - Narzędzia i biblioteki w OpenIM for Go. -- [Makefile Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-makefile.md) - Najlepsze praktyki i narzędzia dla Makefile. -- [Script Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-scripts.md) - Najlepsze praktyki i narzędzia dotyczące skryptów. - -## Konwersje - -W tej sekcji przedstawiono różne konwencje i zasady w OpenIM, obejmujące kod, dzienniki, wersje i nie tylko. - -- [API Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/api.md) - Wytyczne i metody konwersji API. -- [Logging Policy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/bash-log.md) - Zasady i konwencje rejestrowania w OpenIM. -- [CI/CD Actions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/cicd-actions.md) - Procedury i konwencje dotyczące CI/CD. -- [Commit Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/commit.md) - Konwencje dotyczące zatwierdzania kodu w OpenIM. -- [Directory Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/directory.md) - Struktura katalogów i konwencje w OpenIM. -- [Error Codes](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/error-code.md) - Lista i opisy kodów błędów. -- [Go Code Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/go-code.md) - Konwencje i konwersje dla kodu Go. -- [Docker Image Strategy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/images.md) - Strategie zarządzania obrazami Dockera OpenIM obejmujące wiele architektur i repozytoriów obrazów. -- [Logging Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/logging.md) - Dalsze szczegółowe konwencje dotyczące pozyskiwania drewna. -- [Version Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/version.md) - Strategie nazewnictwa i zarządzania wersjami OpenIM. - - -## Dla programistów, współpracowników i opiekunów społeczności - -### Programiści i współpracownicy - -Jeśli jesteś programistą lub osobą, która chce wnieść swój wkład: - -- Zapoznaj się z naszymi [Code Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/code-conventions.md) i [Git Workflow](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/git-workflow.md), aby zapewnić płynną współpracę. -- Zajrzyj do [Development Guide](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/development.md), aby zapoznać się z praktykami programistycznymi w OpenIM. - -### Opiekunowie społeczności - -Jako opiekun społeczności: - -- Upewnij się, że wkład jest zgodny ze standardami określonymi w naszej dokumentacji. -- Regularnie przeglądaj [Logging Policy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/bash-log.md) i [Error Codes](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/error-code.md), aby być na bieżąco. - -## Dla Użytkowników - -Użytkownicy powinni zwrócić szczególną uwagę na: - -- [Docker Installation](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/install-docker.md) - Niezbędne, jeśli planujesz używać obrazów Dockera OpenIM. -- [Docker Image Strategy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/images.md) - Aby zrozumieć różne dostępne obrazy i dowiedzieć się, jak wybrać odpowiedni dla swojej architektury. \ No newline at end of file diff --git a/docs/README_pt_BR.md b/docs/README_pt_BR.md deleted file mode 100644 index e28db74a61..0000000000 --- a/docs/README_pt_BR.md +++ /dev/null @@ -1,67 +0,0 @@ -# Documentação do Servidor OpenIM - -Bem-vindo ao centro de documentação do OpenIM! Este centro oferece uma ampla gama de guias e manuais projetados para ajudá-lo a aproveitar ao máximo sua experiência com o OpenIM. - -## Índice de Conteúdos - -1. [Contrib](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib) - Orientações sobre contribuições e configurações para desenvolvedores -2. [Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib) - Convenções de codificação, políticas de registro e outras ferramentas de transformação - ------- - -## Contrib - -Esta seção oferece aos desenvolvedores um guia detalhado sobre como contribuir com código, configurar seu ambiente e seguir os processos associados. - -- [Code Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/code-conventions.md) - Regras e convenções para escrever código no OpenIM. -- [Development Guide](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/development.md) - Um guia sobre como realizar o desenvolvimento dentro do OpenIM. -- [Git Cherry Pick](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/gitcherry-pick.md) - Diretrizes sobre operações de cherry-picking. -- [Git Workflow](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/git-workflow.md) - O fluxo de trabalho git no OpenIM. -- [Initialization Configurations](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/init-config.md) - Orientações sobre configuração e inicialização do OpenIM. -- [Docker Installation](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/install-docker.md) - Como instalar o Docker em sua máquina. -- [Linux Development Environment](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/linux-development.md) - Guia para configurar o ambiente de desenvolvimento no Linux. -- [Local Actions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/local-actions.md) - Diretrizes sobre como realizar certas ações comuns localmente. -- [Offline Deployment](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/offline-deployment.md) - Métodos para implantar o OpenIM offline. -- [Protoc Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/protoc-tools.md) - Guia sobre o uso de ferramentas protoc. -- [Go Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-go.md) - Ferramentas e bibliotecas no OpenIM para Go. -- [Makefile Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-makefile.md) - Melhores práticas e ferramentas para Makefile. -- [Script Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-scripts.md) - Melhores práticas e ferramentas para scripts. - -## Conversions - -Esta seção apresenta várias convenções e políticas dentro do OpenIM, abrangendo código, logs, versões e mais. - -- [API Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/api.md) - Diretrizes e métodos para conversões de API. -- [Logging Policy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/bash-log.md) - Políticas e convenções de registro no OpenIM. -- [CI/CD Actions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/cicd-actions.md) - Procedimentos e convenções para CI/CD. -- [Commit Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/commit.md) - Convenções para commits de código no OpenIM. -- [Directory Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/directory.md) - Estrutura de diretórios e convenções dentro do OpenIM. -- [Error Codes](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/error-code.md) - Lista e descrições de códigos de erro. -- [Go Code Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/go-code.md) - Convenções e conversões para código Go. -- [Docker Image Strategy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/images.md) - Estratégias de gerenciamento para imagens Docker do OpenIM, abrangendo várias arquiteturas e repositórios de imagens. -- [Logging Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/logging.md) - Convenções mais detalhadas sobre registro. -- [Version Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/version.md) - Estratégias de nomeação e gerenciamento para versões do OpenIM. - - -## Para Desenvolvedores, Contribuidores e Mantenedores da Comunidade - -### Desenvolvedores & Contribuidores - -Se você é um desenvolvedor ou alguém interessado em contribuir: - -- Familiarize-se com nossas [Code Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/code-conventions.md) e [Git Workflow](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/git-workflow.md) para garantir contribuições suaves. -- Mergulhe no [Development Guide](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/development.md) para se familiarizar com as práticas de desenvolvimento no OpenIM. - -### Mantenedores da Comunidade - -Como mantenedor da comunidade: - -- Garanta que as contribuições estejam alinhadas com os padrões descritos em nossa documentação. -- Reveja regularmente a [Logging Policy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/bash-log.md) e [Error Codes](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/error-code.md) para se manter atualizado. - -## Para Usuários - -Os usuários devem prestar atenção especial a: - -- [Docker Installation](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/install-docker.md) - Necessário se você planeja usar imagens Docker do OpenIM. -- [Docker Image Strategy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/images.md) - Para entender as diferentes imagens disponíveis e como escolher a certa para a sua arquitetura. diff --git a/docs/README_ru.md b/docs/README_ru.md deleted file mode 100644 index 0e89df7c77..0000000000 --- a/docs/README_ru.md +++ /dev/null @@ -1,67 +0,0 @@ -# Документация по серверу OpenIM - -Добро пожаловать в центр документации OpenIM! Этот центр предоставляет широкий спектр руководств и руководств, призванных помочь вам максимально эффективно использовать возможности OpenIM. - -## Оглавление - -1. [Contrib](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib) - Руководство по участию и настройке для разработчиков -2. [Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib) - Соглашения по кодированию, политики ведения журналов и другие инструменты преобразования. - ------- - -## Вклад - -В этом разделе разработчикам предлагается подробное руководство о том, как добавлять код, настраивать среду и следовать соответствующим процессам. - -- [Code Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/code-conventions.md) - Правила и соглашения по написанию кода в OpenIM. -- [Development Guide](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/development.md) - Руководство о том, как вести разработку в OpenIM. -- [Git Cherry Pick](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/gitcherry-pick.md) - Руководство по сбору урожая. -- [Git Workflow](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/git-workflow.md) - Рабочий процесс git в OpenIM. -- [Initialization Configurations](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/init-config.md) - Руководство по настройке и инициализации OpenIM. -- [Docker Installation](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/install-docker.md) - Как установить Docker на свой компьютер. -- [Linux Development Environment](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/linux-development.md) - Руководство по настройке среды разработки в Linux. -- [Local Actions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/local-actions.md) - Рекомендации о том, как выполнять определенные общие действия на местном уровне. -- [Offline Deployment](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/offline-deployment.md) - Способы развертывания OpenIM в автономном режиме. -- [Protoc Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/protoc-tools.md) - Руководство по использованию инструментов протокола. -- [Go Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-go.md) - Инструменты и библиотеки в OpenIM для Go. -- [Makefile Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-makefile.md) - Лучшие практики и инструменты для Makefile. -- [Script Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-scripts.md) - Лучшие практики и инструменты для сценариев. - -## Конверсии - -В этом разделе представлены различные соглашения и политики OpenIM, включая код, журналы, версии и многое другое. - -- [API Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/api.md) - Рекомендации и методы преобразования API. -- [Logging Policy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/bash-log.md) - Политики и соглашения ведения журналов в OpenIM. -- [CI/CD Actions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/cicd-actions.md) - Процедуры и соглашения для CI/CD. -- [Commit Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/commit.md) - Соглашения о фиксации кода в OpenIM. -- [Directory Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/directory.md) - Структура каталогов и соглашения в OpenIM. -- [Error Codes](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/error-code.md) - Список и описание кодов ошибок. -- [Go Code Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/go-code.md) - Соглашения и преобразования для кода Go. -- [Docker Image Strategy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/images.md) - Стратегии управления образами OpenIM Docker, охватывающими несколько архитектур и репозиториев изображений. -- [Logging Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/logging.md) - Дальнейшие подробные соглашения о ведении журнала. -- [Version Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/version.md) - Стратегии именования и управления версиями OpenIM. - - -## Для разработчиков, участников и сопровождающих сообщества - -### Разработчики и участники - -Если вы разработчик или кто-то хочет внести свой вклад: - -- Ознакомьтесь с нашими [Code Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/code-conventions.md) и [Git Workflow](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/git-workflow.md), чтобы обеспечить бесперебойную работу. -- Погрузитесь в [Development Guide](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/development.md), чтобы ознакомиться с методами разработки в OpenIM. - -### Сопровождающие сообщества - -Как администратор сообщества: - -- Убедитесь, что вклады соответствуют стандартам, изложенным в нашей документации. -- Регулярно просматривайте [Logging Policy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/bash-log.md) и [Error Codes](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/error-code.md), чтобы оставаться в курсе событий. - -## Для пользователей - -Пользователям следует обратить особое внимание на: - -- [Docker Installation](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/install-docker.md) - Необходимо, если вы планируете использовать Docker-образы OpenIM. -- [Docker Image Strategy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/images.md) - Чтобы понять различные доступные изображения и как выбрать подходящее для вашей архитектуры. \ No newline at end of file diff --git a/docs/README_tr.md b/docs/README_tr.md deleted file mode 100644 index d2bd119e4e..0000000000 --- a/docs/README_tr.md +++ /dev/null @@ -1,67 +0,0 @@ -# OpenIM Sunucu Belgeleri - -OpenIM Belgeleri merkezine hoş geldiniz! Bu merkez, OpenIM deneyiminizden en iyi şekilde faydalanmanıza yardımcı olmak için tasarlanmış kapsamlı bir rehber ve kılavuzlar koleksiyonu sunar. - -## İçindekiler - -1. [Katılım](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib) - Geliştiriciler için katkıda bulunma ve yapılandırma rehberi -2. [Dönüşümler](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib) - Kodlama kuralları, günlükleme politikaları ve diğer dönüşüm araçları - ------- - -## Katılım - -Bu bölüm, geliştiricilere kod katkısında bulunma, çevrelerini kurma ve ilişkilendirilmiş süreçleri takip etme konusunda detaylı bir rehber sunar. - -- [Kod Kuralları](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/code-conventions.md) - OpenIM'de kod yazma kuralları ve gelenekleri. -- [Geliştirme Rehberi](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/development.md) - OpenIM içinde geliştirme nasıl yapılır konusunda bir rehber. -- [Git Cherry Pick](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/gitcherry-pick.md) - Cherry-pick işlemleri için yönergeler. -- [Git Çalışma Akışı](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/git-workflow.md) - OpenIM'deki git çalışma akışı. -- [Başlangıç Yapılandırmaları](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/init-config.md) - OpenIM'i kurma ve başlatma konusunda rehberlik. -- [Docker Kurulumu](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/install-docker.md) - Makinenize Docker nasıl kurulur. -- [Linux Geliştirme Ortamı](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/linux-development.md) - Linux üzerinde geliştirme ortamını kurma kılavuzu. -- [Yerel İşlemler](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/local-actions.md) - Yerelde belirli yaygın işlemleri nasıl gerçekleştireceğiniz hakkında yönergeler. -- [Çevrimdışı Dağıtım](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/offline-deployment.md) - OpenIM'in çevrimdışı nasıl dağıtılacağı yöntemleri. -- [Protoc Araçları](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/protoc-tools.md) - Protoc araçlarını kullanma rehberi. -- [Go Araçları](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-go.md) - Go için OpenIM'deki araçlar ve kütüphaneler. -- [Makefile Araçları](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-makefile.md) - Makefile için en iyi uygulamalar ve araçlar. -- [Betik Araçları](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-scripts.md) - Betikler için en iyi uygulamalar ve araçlar. - -## Dönüşümler - -Bu bölüm, kod, günlükler, sürümler ve daha fazlasını içeren çeşitli OpenIM içindeki kuralları ve politikaları tanıtır. - -- [API Dönüşümleri](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/api.md) - API dönüşümleri için yönergeler ve yöntemler. -- [Günlükleme Politikası](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/bash-log.md) - OpenIM'deki günlükleme politikaları ve gelenekleri. -- [CI/CD İşlemleri](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/cicd-actions.md) - CI/CD için prosedürler ve gelenekler. -- [Taahhüt Kuralları](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/commit.md) - OpenIM'deki kod taahhütleri için kurallar. -- [Dizin Kuralları](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/directory.md) - OpenIM içindeki dizin yapısı ve kurallar. -- [Hata Kodları](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/error-code.md) - Hata kodlarının listesi ve açıklamaları. -- [Go Kod Dönüşümleri](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/go-code.md) - Go kodu için kurallar ve dönüşümler. -- [Docker İmaj Stratejisi](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/images.md) - OpenIM Docker imajlarının yönetim stratejileri, birden fazla mimariyi ve imaj depolarını kapsar. -- [Günlükleme Kuralları](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/logging.md) - Günlükleme hakkında daha fazla ayrıntılı kurallar. -- [Sürüm Kuralları](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/version.md) - OpenIM sürümleri için adlandırma ve yönetim stratejileri. - - -## Geliştiriciler, Katkıda Bulunanlar ve Topluluk Bakımı - -### Geliştiriciler & Katkıda Bulunanlar - -Eğer bir geliştirici veya katkıda bulunmaya hevesli biriyseniz: - -- Katkılarınızı düzgün bir şekilde yapmak için [Kod Kuralları](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/code-conventions.md) ve [Git Çalışma Akışı](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/git-workflow.md) ile tanışın. -- OpenIM'deki geliştirme uygulamalarını anlamak için [Geliştirme Rehberi'ne](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/development.md) göz atın. - -### Topluluk Bakımı - -Topluluk bakımı olarak: - -- Katkıların belirtilen standartlarla uyumlu olduğundan emin olun. -- [Günlükleme Politikası](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/bash-log.md) ve [Hata Kodları](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/error-code.md) sık sık gözden geçirerek güncel kalın. - -## Kullanıcılar İçin - -Kullanıcılar, özellikle dikkat etmelidir: - -- [Docker Kurulumu](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/install-docker.md) - OpenIM Docker imajlarını kullanmayı planlıyorsanız gereklidir. -- [Docker İmaj Stratejisi](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/images.md) - Mevcut farklı imajları anlamak ve mimarinize uygun olanı nasıl seçeceğinizi öğrenmek için. diff --git a/docs/README_ua.md b/docs/README_ua.md deleted file mode 100644 index 1eaf6b5d1b..0000000000 --- a/docs/README_ua.md +++ /dev/null @@ -1,67 +0,0 @@ -# OpenIM Server документ - -Ласкаво просимо до Центру документації OpenIM! Цей центр надає вичерпні посібники та посібники, розроблені, щоб допомогти вам отримати максимальну віддачу від роботи з OpenIM. - -## Зміст - -1. [Contrib](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib) - Посібник із внесків і налаштування для розробників -2. [Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib) - Інструкції з кодування, політики журналювання та інші інструменти перетворення - ------- - -## Посібник із внесків - -Цей розділ надає розробникам докладні вказівки щодо того, як додати код, налаштувати своє середовище та дотримуватися пов’язаних процесів. - -- [Code Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/code-conventions.md) - Правила та умовності для написання коду в OpenIM. -- [Development Guide](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/development.md) - Посібник з розробки в OpenIM. -- [Git Cherry Pick](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/gitcherry-pick.md) - Ретельно підібрані інструкції. -- [Git Workflow](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/git-workflow.md) - робочий процес git у OpenIM. -- [Initialization Configurations](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/init-config.md) - Посібник із налаштування та ініціалізації OpenIM. -- [Docker Installation](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/install-docker.md) - Як встановити Docker на вашу машину. -- [Linux Development Environment](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/linux-development.md) - Посібник із налаштування середовища розробки в Linux. -- [Local Actions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/local-actions.md) - Посібник із виконання деяких типових операцій локально. -- [Offline Deployment](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/offline-deployment.md) - Як розгорнути OpenIM офлайн. -- [Protoc Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/protoc-tools.md) - Посібник із використання інструменту protoc. -- [Go Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-go.md) - Інструменти та бібліотеки для Go в OpenIM. -- [Makefile Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-makefile.md) - Найкращі практики та інструменти для Makefiles. -- [Script Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-scripts.md) - Найкращі практики та інструменти для створення сценаріїв. - -## Методи внеску - -У цьому розділі описано різні практики та політики в OpenIM, зокрема код, журнали, версії тощо. - -- [API Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/api.md) - Рекомендації та методи перетворення API. -- [Logging Policy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/bash-log.md) - Політика та практика журналювання в OpenIM. -- [CI/CD Actions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/cicd-actions.md) - Процедури та практики CI/CD. -- [Commit Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/commit.md) - Конвенції для подання коду в OpenIM. -- [Directory Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/directory.md) - Конвенції для подання коду в OpenIM. -- [Error Codes](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/error-code.md) - Перелік і опис кодів помилок. -- [Go Code Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/go-code.md) - Конвенції та перетворення коду Go. -- [Docker Image Strategy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/images.md) - Стратегія керування зображеннями OpenIM Docker, що охоплює кілька архітектур і сховищ зображень. -- [Logging Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/logging.md) - Більш детальні умови для журналювання. -- [Version Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/version.md) - Стратегії іменування та керування для версій OpenIM. - - -## Для розробників, співавторів і супроводжувачів спільноти - -### Розробники та учасники - -Якщо ви розробник або бажаєте зробити внесок: - -- знайомі з нами [Code Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/code-conventions.md) і [Git Workflow](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/git-workflow.md), щоб забезпечити плавний внесок. -- зрозуміти глибше [Development Guide](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/development.md), освоїти практики розробки OpenIM. - -### супроводжувач спільноти - -Як супроводжувач спільноти: - -- Переконайтеся, що внески відповідають стандартам, викладеним у нашій документації. -- Регулярно перевіряйте [Logging Policy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/bash-log.md) i [Error Codes](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/error-code.md), щоб бути в курсі подій. - -## Для користувачів - -Користувачам слід звернути особливу увагу на: - -- [Docker Installation](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/install-docker.md) - Це буде необхідно, якщо ви плануєте використовувати образ Docker OpenIM. -- [Docker Image Strategy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/images.md) - Дізнайтеся про доступні зображення та про те, як вибрати правильний для вашої архітектури. diff --git a/docs/README_vi.md b/docs/README_vi.md deleted file mode 100644 index 55a99b8e5a..0000000000 --- a/docs/README_vi.md +++ /dev/null @@ -1,67 +0,0 @@ -# Tài liệu Máy chủ OpenIM - -Chào mừng bạn đến với trung tâm tài liệu OpenIM! Trung tâm này cung cấp một loạt các hướng dẫn và hướng dẫn chi tiết được thiết kế để giúp bạn tận dụng tối đa trải nghiệm OpenIM của mình. - -## Mục lục - -1. [Contrib](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib) - Hướng dẫn về đóng góp và cấu hình cho các nhà phát triển -2. [Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib) - Quy ước mã hóa, chính sách ghi nhật ký và các công cụ chuyển đổi khác - ------- - -## Đóng góp - -Phần này cung cấp cho các nhà phát triển một hướng dẫn chi tiết về cách đóng góp mã, thiết lập môi trường của họ và tuân theo các quy trình liên quan. - -- [Code Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/code-conventions.md) - Quy tắc và quy ước viết mã trong OpenIM. -- [Development Guide](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/development.md) - Hướng dẫn về cách thực hiện phát triển trong OpenIM. -- [Git Cherry Pick](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/gitcherry-pick.md) - Hướng dẫn về các hoạt động chọn lọc. -- [Git Workflow](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/git-workflow.md) - Quy trình làm việc git trong OpenIM. -- [Initialization Configurations](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/init-config.md) - Hướng dẫn về thiết lập và khởi tạo OpenIM. -- [Docker Installation](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/install-docker.md) - Cách cài đặt Docker trên máy của bạn. -- [Linux Development Environment](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/linux-development.md) - Hướng dẫn thiết lập môi trường phát triển trên Linux. -- [Local Actions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/local-actions.md) - Hướng dẫn về cách thực hiện một số hành động phổ biến ở cấp địa phương. -- [Offline Deployment](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/offline-deployment.md) - Các phương pháp triển khai OpenIM ngoại tuyến. -- [Protoc Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/protoc-tools.md) - Hướng dẫn sử dụng công cụ protoc. -- [Go Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-go.md) - Công cụ và thư viện trong OpenIM cho Go. -- [Makefile Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-makefile.md) - Thực hành tốt nhất và công cụ cho Makefile. -- [Script Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-scripts.md) - Thực hành tốt nhất và công cụ cho kịch bản. - -## Chuyển đổi - -Phần này giới thiệu các quy ước và chính sách khác nhau trong OpenIM, bao gồm mã, nhật ký, phiên bản và hơn thế nữa. - -- [API Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/api.md) - Hướng dẫn và phương pháp chuyển đổi API. -- [Logging Policy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/bash-log.md) - Chính sách và quy ước ghi nhật ký trong OpenIM. -- [CI/CD Actions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/cicd-actions.md) - Quy trình và quy ước cho CI/CD. -- [Commit Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/commit.md) - Quy ước cho các cam kết mã trong OpenIM. -- [Directory Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/directory.md) - Cấu trúc thư mục và quy ước trong OpenIM. -- [Error Codes](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/error-code.md) - Danh sách và mô tả các mã lỗi. -- [Go Code Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/go-code.md) - Quy ước và chuyển đổi cho mã Go. -- [Docker Image Strategy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/images.md) - Chiến lược quản lý hình ảnh Docker của OpenIM, bao gồm nhiều kiến trúc và kho lưu trữ hình ảnh. -- [Logging Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/logging.md) - Quy ước chi tiết hơn về ghi nhật ký. -- [Version Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/version.md) - Chiến lược đặt tên và quản lý phiên bản OpenIM. - - -## Dành cho Nhà phát triển, Người đóng góp và Người duy trì Cộng đồng - -### Nhà phát triển & Người đóng góp - -Nếu bạn là nhà phát triển hoặc ai đó muốn đóng góp: - -- Làm quen với [Code Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/code-conventions.md) và [Git Workflow](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/git-workflow.md) của chúng tôi để đảm bảo đóng góp trôi chảy. -- Tìm hiểu [Development Guide](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/development.md) để nắm bắt các thực hành phát triển trong OpenIM. - -### Người duy trì Cộng đồng - -Là người duy trì cộng đồng: - -- Đảm bảo rằng các đóng góp phù hợp với các tiêu chuẩn được nêu trong tài liệu của chúng tôi. -- Thường xuyên xem lại [Logging Policy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/bash-log.md) và [Error Codes](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/error-code.md) để cập nhật thông tin. - -## Dành cho Người dùng - -Người dùng nên chú ý đặc biệt đến: - -- [Docker Installation](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/install-docker.md) - Cần thiết nếu bạn dự định sử dụng hình ảnh Docker của OpenIM. -- [Docker Image Strategy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/images.md) - Để hiểu các hình ảnh khác nhau có sẵn và cách chọn hình ảnh phù hợp cho kiến trúc của bạn. diff --git a/docs/README_zh_CN.md b/docs/README_zh_CN.md deleted file mode 100644 index 413d5dfa18..0000000000 --- a/docs/README_zh_CN.md +++ /dev/null @@ -1,67 +0,0 @@ -# OpenIM Server 文档 - -欢迎来到 OpenIM 文档中心!本中心提供全面的指南和手册,旨在帮助您最大限度地利用 OpenIM 体验。 - -## 目录 - -1. [Contrib](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib) - 为开发者提供的贡献指南和配置 -2. [Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib) - 编码规范、日志策略和其他转换工具 - ------- - -## 贡献指南 - -本节为开发人员提供了如何贡献代码、设置环境以及遵循相关流程的详细指南。 - -- [Code Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/code-conventions.md) - OpenIM 中编写代码的规则和惯例。 -- [Development Guide](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/development.md) - 关于如何在 OpenIM 内进行开发的指南。 -- [Git Cherry Pick](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/gitcherry-pick.md) - 精挑细选的操作指南。 -- [Git Workflow](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/git-workflow.md) - OpenIM 中的 git 工作流程。 -- [Initialization Configurations](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/init-config.md) - 设置和初始化 OpenIM 的指南。 -- [Docker Installation](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/install-docker.md) - 如何在您的机器上安装 Docker。 -- [Linux Development Environment](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/linux-development.md) - 在 Linux 上设置开发环境的指南。 -- [Local Actions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/local-actions.md) - 关于如何在本地执行某些常见操作的指南。 -- [Offline Deployment](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/offline-deployment.md) - 离线部署 OpenIM 的方法。 -- [Protoc Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/protoc-tools.md) - 使用 protoc 工具的指南。 -- [Go Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-go.md) - OpenIM 中 Go 的工具和库。 -- [Makefile Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-makefile.md) - Makefile 的最佳实践和工具。 -- [Script Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-scripts.md) - 脚本的最佳实践和工具。 - -## 贡献方法 - -本节介绍 OpenIM 内的各种惯例和政策,包括代码、日志、版本等。 - -- [API Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/api.md) - API 转换的指南和方法。 -- [Logging Policy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/bash-log.md) - OpenIM 中的日志策略和惯例。 -- [CI/CD Actions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/cicd-actions.md) - CI/CD 的程序和惯例。 -- [Commit Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/commit.md) - OpenIM 中代码提交的惯例。 -- [Directory Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/directory.md) - OpenIM 内的目录结构和惯例。 -- [Error Codes](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/error-code.md) - 错误代码的列表和描述。 -- [Go Code Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/go-code.md) - Go 代码的惯例和转换。 -- [Docker Image Strategy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/images.md) - OpenIM Docker 镜像的管理策略,涵盖多个架构和镜像仓库。 -- [Logging Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/logging.md) - 有关日志的更详细的惯例。 -- [Version Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/version.md) - OpenIM 版本的命名和管理策略。 - - -## 对于开发者、贡献者和社区维护者 - -### 开发者和贡献者 - -如果您是一名开发者或热衷于贡献: - -- 熟悉我们的 [Code Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/code-conventions.md) 和 [Git Workflow](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/git-workflow.md),以确保顺利贡献。 -- 深入了解 [Development Guide](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/development.md),掌握 OpenIM 的开发实践。 - -### 社区维护者 - -作为社区维护者: - -- 确保贡献符合我们文档中概述的标准。 -- 定期查看 [Logging Policy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/bash-log.md) 和 [Error Codes](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/error-code.md),以保持最新状态。 - -## 对于用户 - -用户应特别注意: - -- [Docker Installation](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/install-docker.md) - 如果您计划使用 OpenIM 的 Docker 镜像,那么这个将会是必须的。 -- [Docker Image Strategy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/images.md) - 了解可用的镜像以及如何为您的架构选择正确的镜像。 diff --git a/docs/README_zh_TW.md b/docs/README_zh_TW.md deleted file mode 100644 index 8ca00ba17d..0000000000 --- a/docs/README_zh_TW.md +++ /dev/null @@ -1,67 +0,0 @@ -# OpenIM 伺服器文檔 - -歡迎來到 OpenIM 文件中心! 該中心提供全面的指南和手冊,旨在幫助您充分利用 OpenIM 體驗。 - -## 目錄 - -1. [Contrib](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib) - 開發人員貢獻和配置指南 -2. [Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib) - 編碼約定、日誌記錄策略和其他轉換工具 - ------- - -## 貢獻 - -本節為開發人員提供了有關如何貢獻程式碼、設定環境以及遵循相關流程的詳細指南。 - -- [Code Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/code-conventions.md) - 在 OpenIM 中編寫程式碼的規則和約定。 -- [Development Guide](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/development.md) - 有關如何在 OpenIM 中進行開發的指南。 -- [Git Cherry Pick](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/gitcherry-pick.md) - 精挑細選操作指南。 -- [Git Workflow](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/git-workflow.md) - OpenIM 中的 git 工作流程。 -- [Initialization Configurations](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/init-config.md) - 設定和初始化 OpenIM 的指南。 -- [Docker Installation](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/install-docker.md) - 如何在您的電腦上安裝 Docker。 -- [Linux Development Environment](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/linux-development.md) - Linux 上的開發環境設定指南。 -- [Local Actions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/local-actions.md) - 關於如何在當地進行某些共同行動的指南。 -- [Offline Deployment](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/offline-deployment.md) - 離線部署OpenIM的方法。 -- [Protoc Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/protoc-tools.md) - 協議工具使用指南。 -- [Go Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-go.md) - OpenIM 在 Go 中的工具和函式庫。 -- [Makefile Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-makefile.md) - Makefile 的最佳實務和工具。 -- [Script Tools](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/util-scripts.md) - 腳本的最佳實踐和工具。 - -## 轉換 - -本節介紹 OpenIM 中的各種約定和策略,包括程式碼、日誌、版本等。 - -- [API Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/api.md) - API 轉換的指南和方法。 -- [Logging Policy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/bash-log.md) - OpenIM 中的日誌記錄策略和約定。 -- [CI/CD Actions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/cicd-actions.md) - CI/CD 的程序和約定。 -- [Commit Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/commit.md) - OpenIM 中程式碼提交的約定。 -- [Directory Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/directory.md) - OpenIM 中的目錄結構和約定。 -- [Error Codes](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/error-code.md) - 錯誤代碼的清單和描述。 -- [Go Code Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/go-code.md) - Go 程式碼的約定和轉換。 -- [Docker Image Strategy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/images.md) - OpenIM Docker 映像的管理策略,跨越多種架構和映像儲存庫。 -- [Logging Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/logging.md) - 有關日誌記錄的更詳細約定。 -- [Version Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/version.md) - OpenIM 版本的命名與管理策略。 - - -## 對於開發者、貢獻者和社區維護者 - -### 開發者和貢獻者 - -如果您是開發人員或熱衷於做出貢獻的人: - -- 熟悉我們的 [Code Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/code-conventions.md) 和 [Git Workflow](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/git-workflow.md) 以確保順利貢獻。 -- 深入閱讀 [Development Guide](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/development.md) ,掌握 OpenIM 的開發實務。 - -### 社區維護者 - -作為社區維護者: - -- 確保貢獻符合我們文件中概述的標準。 -- 定期查看 [Logging Policy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/bash-log.md) 和 [Error Codes](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/error-code.md) 以保持更新。 - -## 對於用戶 - -使用者應特別注意: - -- [Docker Installation](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/install-docker.md) - 如果您打算使用 OpenIM 的 Docker 映像,則這是必要的。 -- [Docker Image Strategy](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/images.md) - 了解可用的不同影像以及如何為您的架構選擇正確的影像。 \ No newline at end of file diff --git a/docs/contributing/CONTRIBUTING-JP.md b/docs/contributing/CONTRIBUTING-JP.md new file mode 100644 index 0000000000..86bbfefcd7 --- /dev/null +++ b/docs/contributing/CONTRIBUTING-JP.md @@ -0,0 +1,33 @@ +# How do I contribute code to OpenIM + +

+ Englist · + 中文 · + Українська · + Česky · + Magyar · + Español · + فارسی · + Français · + Deutsch · + Polski · + Indonesian · + Suomi · + മലയാളം · + 日本語 · + Nederlands · + Italiano · + Русский · + Português (Brasil) · + Esperanto · + 한국어 · + العربي · + Tiếng Việt · + Dansk · + Ελληνικά · + Türkçe +

+ + + +

\ No newline at end of file diff --git a/docs/contributing/CONTRIBUTING-PL.md b/docs/contributing/CONTRIBUTING-PL.md new file mode 100644 index 0000000000..86bbfefcd7 --- /dev/null +++ b/docs/contributing/CONTRIBUTING-PL.md @@ -0,0 +1,33 @@ +# How do I contribute code to OpenIM + +

+ Englist · + 中文 · + Українська · + Česky · + Magyar · + Español · + فارسی · + Français · + Deutsch · + Polski · + Indonesian · + Suomi · + മലയാളം · + 日本語 · + Nederlands · + Italiano · + Русский · + Português (Brasil) · + Esperanto · + 한국어 · + العربي · + Tiếng Việt · + Dansk · + Ελληνικά · + Türkçe +

+ + + +

\ No newline at end of file diff --git a/docs/images/Open-IM-Servers-on-System.png b/docs/images/Open-IM-Servers-on-System.png deleted file mode 100644 index 3c8a1020214a2cfcb9e5cc6c5beb339b7e2be67d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 21614 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 Z7iVs2wPSi}fqg{rG*ony3lwkr{y(Ud)0qGO diff --git a/docs/images/Open-IM-Servers-on-docker.png b/docs/images/Open-IM-Servers-on-docker.png deleted file mode 100644 index c66f7fb095e862e64eaab2a9dbc1ac1c3c73977b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10172 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

Ul4l+_q-iF9P^FloHd81J@_?< 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

m+-H`IeBmCUU{1v4gb(;8fSe)oiB@Myr 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�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.|E?p#$-*f^W>vqcD{I zw8;i3byoOkl6J}UX4(Sc?Rw_+p0=AsCZtbbEpxh9H2-wDLA7HmD1_@^zi~}13 z$_!k!j@k7lk};9j?~B7*ttIQi^0 z?28!xIfKuC|C|8Ad{pxDeMCWWvc<9i!QeckFzhM-Bq;p=HQ(K-7C20UK~yyJcF0-4 z)I(i1YVl$!<<&7F!8h4PKO^HHje#mTH{0=^<>&VMdU*>c*$k@?w0IYxS^hmCRNN

`W{JVLM(s9>JC39zFIRIbt`tM22~W3VyclDIuzHzaZ`}L|8%IaX{Rk%%dO!ro zT8=x}W`0mF_cV0;=U($X(+9*7UYv8d3pu0PVgIB@@Zjsb7JhXJ?l%arvcw>hetJ(x z)K6V2{x;U?<>?IBk# zIjwZJEl!Cl=fY2i=bgcx03-DgN#Cp~Xu5{IP3og5X1KFWQ40_ zS1%%R{)MSl>Mt=lYo>98*Doj*ob$aJY>FFH8_ziujQ&hbwBl>Ru}F}yn=Tjk4X42j zJ7@-Nzpu6%-Bcr{dp7R609_IA;)Hi>^Xg@>HES!UzdOGpxl?m14zr-Zk5HGW?z{2e zs2u=T!K^7Sh+<@s%jUAuR4AM(HXVNau_iEnmfN#`*J&0v`d^?iAlW}3U~M(UJ>hd9eYxgxv8!BAT8gjfCTrajlKKItH5Ua$>(SLB zTZT?>7wW|K>=`K*FSpgAy>fC#!eX(6!|{p~Qavoi(pgX=$=5cbHgonojH3j#L_J>! zThh=~G&GZwoWKv-)6A1H&I9oms;#RiL2#6sHOHP+(RSMdh6`>ABZ}NtqRO`QyW*o@ zmu>E2pE%DzwK05a+Hfn0=XN~_R=A7~Ue+f2=Y@-xvrms#LhYKbH5IJAZ+B=5N=ooR zP#}kxV$N-XHUtD9Mz#XH2aMfD`9heNH!NI|apwwQLvvh2xfB}RAjxt$-SpduiJw94 zL`~Ik)+w1sJHBeXSH*+5&2M6;lMAiV(&uGR+fjD+%5xyj4Hl?AqjyL$$VNj=xebF> zXGxrQODg8#xccm;7YMVw&S9 zIl&c2563T8@#!81rF%Z#>fd}gNwSmbFr7-lco%xegY+iIM9=J1il6&fN%?Z?M-FGx zp1K>aJ+Mt0U-u>JRs_PQ(#U@2$7eg6HKUl_rPx!u)VY=~t-grDH1esmjBp zrsLza+lw{<obet*GFZhjKp0-t+zS_)MbIb1x2$%lz4Hv+uI;aI*S zaDF)~%pgf=q%vXn@&jv*(?d6^s65<3%^neG!@H_>v(zux7MWE#)yy~-5py9v!KalV zs#`)NZqVW(#gB857XIfb?Jy9bM<^X*i?ilz;7?|+Xg^QZPVwr zO!LL~LUt+qQp`G)l~f8?t&TF!U6)M*vRoWxz-q=-%4IlNj~oO&JXX#Na-6pLOoyJg zDR2-pukU5G2PTTR3VTgH{VF$iMUHl&(O%2T5kiRn0bs>Tv#QegyXUbAUsk}{6TglHT`YxSz4Lp30$ns{Kk# z5KKU9xy)M@=n(okRqAzv-VcTSkgjdx$rdN^m47ss>=!w=1wpa%C+aGZ8eQu^xnu8u z3hQQ1`qWtup)BiWzPri!yRpMx&W9+s#_JxFCXhw}Jz2|KXDX=X)IVu=lED32G;cPF2N};=( zHF`CiZM7)9KEjv=#J@c*_MK7UF_Lsnpd}8u=KJq&eLb%BWK*-7r6B0XEpDsHw4FE3 zr1O{|>YEPPKT%xIt|J70bHI_2f)KDr^CrL@l`ta4^EEbNZ|_$ZeV`vA(h%9P$tW`A zQ)xY3vSPRfHr;fcEmCUnsBm9EC25&#=;Ws?}Ea7zfL${jlbJ-4-Ohjyb06XoB zDY$A5&hVrx#b0LNzfD{0za89{xzTeQ-%CZu)?q#l*qJLFo8O#Oy+d|ATWgeiDU2w5 zI*KFk-Xn!zEl~hjhsG2dF(!uzK>%U!$EA2=w#qdw#c_W4<#)fD?^oeE9hlmZI_G3c zT|y5tyb+!G4e4X9b*M0!deRCOoDI%RSOrE3*;H(U(5Qd+*ZFOusH#S+-Btc`q=R^u zYlGi6CX(l89(cP^4-lXcEA6m%D1}88?%S6~*HatqOD5|n!bdIVzYWK>RA~hn4<#2} zk?!$GEGE?p-D&U8j{=|_nkW^2U?UY}n>Ov@ozfJ5>pElNCvHDHG7^^T1po|h>VxeE zK)Hl==0#qHFNWsYVJ%lbX_|@Vm0Kgc~w4|Pj^!jP2iR9HF zXdiSxt7b@I(`|ltz!bi(6oDZ8kwPugG%oz5k>`B^~k4i zBfRluGnU&9Ey+RG-ES6}|7h-L^ z&b~_ch6G|YUstb@LHhwHpDSLqXNukIKl&x`Yfh#aZ_nh4dwgkPJYuV4-Q?K!Gx>Vx zKaFMxNhO-p`++~6wobZ%{rViazs7t~(S?V2uJU^FwH^5(0)bKumP`$qdq!@aB(kj` zVI~2%0t2L`IO27v#CoX8D$>E@S^&CDU+m9T!CqO>p0w(WeEaL@Pi^8Aq46^52xpLw zf%1{zay#`08|3s~q&7pL989^LKb1y7CU-36V>Kv?iw!tmmhcO_`=jyWYUj*2Y!}Pn zc-HDmfmE}gpwMi%N&NgEWR}yVUB91^?)>f};mS9xm2;ga8!TCP3|maetviQuoY5p%dC8-%PaoGU)y6nio~Z~)I7ILdj+1pMuj@M^5#29fYU7}od#qge>G>*) z1Dr;2qWWcPceyh`2 z*D|)Ww@vD{=$kMp=luhB6x6>IJT`mxKH!AywZoFQ0_G6b3hNAMp!2vXYZ0gEN(yo| zc`xR)p!Bcq@cIpnIC1{TF46GBZU~WQtn(1T@{}c}h>Az!rs*$Fu>0-GX z+_6^}Kws?ij;lSK^t(J1%Hx{#m7!*_Sf%+qg^1w_*@i*j8@|%f#N>b{SrV-s!SL#v zc^azPsz19yUZ)rtVzt=D0+%jIJ>-<4rI2nVdrZ$Glw#JgnCuat7y zU-%xjoa^>6Qpi8rgg@q_9iW2ODPoj&mC2D8!8&QrpK;cZ`knFlM7$JF(n&Je+n zFc~SvbhTIlZ;L;scqpl~Qm6R13Z4pfI<^}S+7>Lzq$J%fU!IKZhvXQb9r54 z`b<9EAc+ebRw?yM5{_!Xk`#Lhdny`(xGTIkj>0N{uI87exXn=q@*Wm_Tqj&y-CT#c zz2`uvZ^5O;IkZ>Ld@|Ht8R~p!LdDDcI~|sC1>?7o5+w~q z{4pm+n5qcStiTs3fkl$;Laxodysz7Q>{v$nm|+>=u+NES=Aj8#Z6cTkZmkPc=qS7G z_VmCh#LB~;#w?Xc>4>BdM!3MRQ#2&B%>G&xv(j56rvXVDiMk3lDe#%=yrKRe%2Kt{ z-s6rLQ_yEZrGqle2zS+QF$0^m;$8+aanJE4*Hb6vPm^a|Bl^Na!- zXwuh3m*T+r}WK_BVu0z7f`%f+(7^ z-2j*)d=$3#_x^C~@@?{+3Wiq~!9709!<^B)d0L@XmRIS2Q|`CjwQP4-k37ATD-sdi z+jGgm+Kwe$wl8fe4{9?P0y2nTltY%Ne@)LZ4;Vl)bGYAA#gY2XQPwT0pzH4&ygu0& z^FHlmFMoqW=po_WpSKA#sCs*kl_>7^iKu?Jt(DHtNcq6~Z2xDwxsjehR@Ia*QGdgx zARNg-OXn#)ld5Pd#XR=LJNr|VH8qTg=F2{Z22id^YIhwUO1Ss#L{Hvy9!A#HP;H{; zIz_rSpQ9OV3O)mb+DUY8(e4w*3Vf!EV(rjwz9q3u^+oh%q?-K~2+n+WE9vE{X+oW3 zJxJ!4kGsi1Mi?Yt)sj^MMke4#*Ig<}I5`*_{0ONzK39T5y9Sm0YPw}X2HPReyG3k( zk<^)Re_|-q^uUa!3&M9Qur*|jOcN&61Wf055x=zRey^x9kPg8qKkCsPxwV!G$8I6z z(%C6*h*5TV_?g5pg`!NJp$D85a8M~AxELgzqYCbVebD|mZtNAkK3oWTOa!H11XCb0 zMFQ%#qD>z^&h1YqM>`FKwke$8DreMb6u z?2skGi{uLHC5$7ruG26yH=r)Ow0zk1+h*|;3_v#m2&O1T5|oP@M`f_8#&P>Li^N@D z?8~Hkk|lFVb|O>_czqqoBeJM(W5S>ur!5ZX((p0M_4mMop#+i+p^z}a0tDR4_05R( zZH>_zN`l?~wu(F@qWTYaA+EGXA3YRY{rE3VJ2F^08x*<++XdcM{1hb$5ZHbHH8LE( zS;WTck>ANX4TbVuT}3mn5(*&nwG9fc!Qdl7De^br6rC?b&FvvXSvsmYJ7m0D^pu*N znS>`N!U|-XOx2KsAXgw)Rf4b)f?&W-o zyNJ%V^3%hA{6j-A!g7|D>wp2{9;60{Zoj0ZA-?=d@^|;05#EBsoG_9Iq5V7E>O=5& zc$CAWfL_5)R(Ue6aRc;US^$wG88lVXnG)=V_6(#@^0sn{aLuUXDwftayM|vlx96U5 zcwlMAQh)>ha}%3^6cP)oCk;I${U(B*Ng`yJ>Ra1s9_#&9)oeq577Z48z@yA_`v)0( zTgD$jf;kXE|LKe*k&TnIJ+&+FHm1o=S04bwbpKjVH10ixmk$V0lO}`%gWCEyH|a3w zkiz4RYB-J4eI=t$$@Zxs)q`IC9u1C1E6fIyNDz1IH+?nj126L%v!N;u{I*3+jaY5% zd>UhX`SSoE5u)tP_?1MB7C^hE)wmOK&#F83QJ#&K`$`hOQ-Dh85N2y;k6eLOS6a9M z>53&wNjhGB$rdwV1&9g6XZ^81o%^a`N9&Vg*Kd(Gd6xsHzZrr9r|?D}D|ivXM7k7k zNo_c9Qa)FNh^E86?JZwGWc#!tU|`r*5UQ0$fb@DaC^O>^SJr5^gWd`&kI*a%YE}Pf zeJS!1T?Fn*Z$+>!Q9laX_p*?e5i%?`cVA~ezzm)1Z=@YTNgv}d&pxoeYtj))6EG!) zVC$vn)a#9Cx?Ks6=rymGvqyv-Uu^BXfJ^H9hKL%Rk-NN(z0&lwO6z!+d=<1jZ_sTK z7u=p4E$886Q0 zi7?5FjPt~b1xX@nNVM?Dc4(m<{(2THObHS}f?4Ha#>lsLJ6_tAecY*DJk0w!E$hPU zq>j4;8TQtVlR2x*~oM-+7mQw4v92oSx$PbC``*lx^{-tC)?|1K~Y z1T=jU50;bDhbR$vdeYtn)h=+CmjIK%#vwADMgGdd-k=94LB?o4OOO5r^{AGs)EDd= zro||{V|5-*-QwM`6?bIHyuCIhT-0N`wsp{7URh#cJToh$b#ICoM6de`3cJD*@8Qh6 zHx&YSf;(BPM#T75OnHL#Ff2m?nHHwZG6)3ZOBCE3v`}^?mwY%NYyu7h!3s%9QEsEspi$7De#{7<;QN!c}*G@4YgW4YM z+A^FGs-)ZU#UFSqvv?Me*Wn1IoI5Q4M?l_L0+=@B@CPdBT9c7mp;Oymls<0dTZ7mT znVgW4$T8~J+3%YHEu`l9-1iV-brWe>+=r!%s~$Hh?XjBL{Hw}pWB{rC&NWxoMR&dXR^tv*dV^&5Adh~Sgt3?k1 zr;HMS_2ArbB^0Ph|9+^JB=aJxXc~_ZI?pncdFB*a{uMoD8U@frxjRuz{F%E?D1$J} z%B3#=_7lKt7k?1THPj#dhnxCa67g34MRsw!lln9umZ|Iq6y#r~v=VMFTsR$u`RzA1 z3qNt)UQFu(uc*iHlVLpf$ncu3merz_dj#6uOpcBU3q71i@oz5LW3IOafnJRBHMe2# z>&1W0#l7L=C|tnc1?BNKm5d&d3AlcFyf^YS85YQ|hZi1qQWg}5&=G!4S<{NUI4w<( z0T!Hr-zO)DArsJyobMiDyBjNE3Dj}vR$U3@v)n?d@D~&IUpc{G#(THaSG1;XrqSo# zZ^EjJ7;DH3>MSX&(e|hjZ7Fe#1LglGFgz?xSRhcth}=t+Gs;9o~s zgbTLr=sz+6eM#UZZ_lf!Kxeg5j0i)}XRJ~mu3DdPo5U+{H)~p2QWzK*I7eG4?yJq z6sp3V;(^EG=#i`)NY|F&Z_AOw+{Agc6eNRLRI&Bf;vPV;yak_3^j_i$|1cEz?#ZEF zs|hd5MNJK__4ufTVDu+GHb35-TA};!Z)XizklX2q=g7Z@{HJSwQ!?(4dOjhJ$GaZu zJJj|cp{^+WR+!-gDZCP!8`XQ5U?ic1*ETUg!NWchIWPk$j3hlld&m!$%h)#|NW4$}9IIwF?E~C_nahgBnntoM#KwjXj zR2`1RzxDaQ%8Reh%8QV9w}*8Yo1a-$ocAuZCo`<@8ycNxe~;hDKPVZKcQ?J$*;=_L zTlJwVr!xV9)Z77aWkkkgXE;vAuo&?7Z4v!b?R z1#b-;7ScrRDcQ3!!Bp=ZVptORxQ0#b|43b|0Y{^?&H1Zn63`82d%hAE87R91xGM5=LP%88TmM7z#j(3q z!PS(k<1<(N{}k9fOKL{*;Nqe@`3!2@rE@(7$-phnui!9ZB+Gc8{jdV$Z29St!FN|L zbjsWNLD_|(+#QH8o&sw+v}G1ma62~@3m)VB9Sh!E0^f=cydwDgt!hmWSCaU=MLxbd zZWXvU_+R?P_p(UG@ee(qp5-v}VUpydPg-t(9PL>QO!}cH1}J8DN;jP59$g5I zK7YakufJS#)YTRSWWd|@sH}DtfD)kbN~5FcJjQ_I^lc>4%*E5@bR>^4U>4iqhPzu;6^h+_R$-8G}mYfETr275!|ENU~zW?y7 zeBaM|UoCaroOs^zS6TE=n9E{FoeBiGVYvBHKSe2n0sk}w3S-b?Ups7zdh^O^m6zyl z>RI-oFf6O{;i;|>t=e?nA1|9FGr95VG~DRF>(T&a8Z9s6hIGsAsVNujFCc1}>OVzh zKumYLY4(?!hcQ^;yzrordDJ~6xP;4bVs#+)vI362jufF#DRXaq{Kjim9=5JxpAQir(uooHA}FLYWeMT9aID{io(g9OMLeJFCut0C zgJ0KvVM4qA=SFrGqTdJV5Z{!zGXNF^j^x3Oe;#~7PyAQyi)zc{_vM<n4-g2;~Spo`6Gcpv2(RK&U8d2Oy?c?0#P?{vm`wo2-kY7GvQW2zVjI-PwN zBiWoszIh^8!9pMS4k%a}StXid?zfo{=D|+p1f6@6+5Gty>>C z%+OCR;3!{t-|p$r<#v9zgVWP=kqWj~tGr)bP6_rBa%#%w@5W_zBjd3ZPU?yCV^>UZ zjbSRC?8rpARML=6xNeanKkmpeL1F49+ zmjxDO@Mnh=v_o;yJQSx>(DXeFP&5MMY+pb1i?a0vw7Wh!My1!?JXN~j9V?K|lb5!r z`qX^Ty_;)szk9UOMPocXEa_TYOom66wGAYI@wK49q(r6^{Xo&4jCVx=a1KxR#_@@> zjgf{fN5(E3Uj?rmj)nzXj1LDF`jS|oNwf8S41e-ugz)M6!ptU&>4M$q9EP4Od&X(y z;tR4e$+W!2Ut`b+@Ukaq)Eu-O*4N7^j#KK^z2}J$bY6g`A?=q>MAufkb*=p&&ATD< ztMK=DU^qc>me?vl0rSa_3vf}B_r?}#MP*}<@PGUns6UynDHkKCKS@ACda7*k$7HAZ z4(;=J`i9fN81N=0al8V{hQ%M7!SP1NqwL;PaDwon$Cbg3Um&XLIOTGg8DmV??HV^a zofRF1)wK7hJPqkpLbc_TLuuc~b>rKMA=x$gx1iRSDz_)76qL)tjLx{ZqPwR5|isaY*v z+Wiz~fwtVSDlktzJn`+%>?fV3q?G$kDJ3=cU@p=ZZ+)hn)(kOX!YbT|hLv(Y8tn{e zRA(QTVQwy+6IO=w%Owi>WpkT9()tPUv&xOQNo<-7PHs-5Ny)s#qu9z2mkH?~iC^y< z-{Z8D74cwS*$TpC1b&pvotkZMkNC0-TNvi3z-!qb1+SvY+=*y>_<-;jE21s#eyyv) zT_s;VyvAlRqY48Q!*;Vd5HrClF0J5i?(~Aa$x|LL79VDyKbjHQQ>{e$(;PvW&QGM7 z%~LASiN=ArxO7aeB5onu+o3Zgwe?e~ypxNQbfJC~{j<>4Wg;5yHcS?b7u{zkx|IRa zF{RStGOASMsi@!=AAWC&yP}o(v+2~mcRSUn*62fWcpHn9wRvN+fGLbyFqNVEL?^bb zl!AWUw<%87Wqw#(w@cj!~KmzgZGo5cB@zN_{2o$4}z@b-%8`-<8(AM z{)$RUZjttQo|KzhYhgm8+)1rstv5-PL`$~UeoYa%NgG8+9v+`C$Nl@=@bqeQnAW|& z!*F{sX!)v?o+{!UQr=xMptv(#=N5ouD~0AOyB@RpfWpsL`Z}uj7!Ct9r14Gjoqf{0 zhxjb&DcRwq(44Fu3DT^o11AvDOYRXQ6Li}EWPogWlQ0(#3swdy{nU16qT!Ot-EUM^ zLAf@FZBo+Tb6Es#%iPg%`^7!Y|JeL~z75424r^*u4&v_{VLp7nuo@#TEhD+*VB6T|v z>~XtHs%L7p&fI#fkz1@*KAv~KP|pids`SD!9_l*t6(>1Wfwto|}jS#wFksNv{8@ zRtB=oKxf!#5p4O!=6{12^G-{U;U1!x+FSOPhIEP(1n!bneLdEIVh~-MOV*}d8`l51 zpdB>4`-kw1rG=EGRT5*xG7Yd|V>YNOMW6eDRn&}jR9jIlD1kecsf4wyvCb~2hKD#% z#Sbx-nfeY4O$$BBk^zrOsjr`K{WO893w?kXEH>Ql`w=VF{zSyK{Cj>^f@}e%mE_x? zqH$;Y9+zF}8VIRGtyf87RqZP9cgi9`Va6i#@PD*4vEE7Q-nwE~;Yi*O^JZk=q?PpQ->PTXP3 z_6=D+>$vx`9qwu6HO+XkU<4;<^R3wX+jD5u+Imj}pfQnNY@Pxi1AOET{X|`Zg`T{~MBdfq3a@O;2nhtb_N7+e?a(7&*#HaG_ikhkVKq>qQ1r37%uNj|-%&C||9 z-E?A6)v0n@m%!FGb1eB7aLNlzl}qRSK%n1Xbf3HqG-y+t_z%lxEZcPUU(ikc`!_G~ z#_nN;zBV<*JE0o7YGyL&klT@v z1${$_#&BQ^!hxg=`%9~mV||v8l)y|wWiom%Lwt@fqFZ$=!dGPsqz=(cZQy08SFTJ_bCqpViSio9*e*?UV5eJu?&iopXOKE#;j(hQX=!%lu zke`pkO0G!7>juRLQ0Ur&)VZHDRxSr>O>G zP{ip#@|JoxXRB;iY@;5f+{82BrC)qg!%6ra^bmiO^91EEpqR-2Rl3z zd-}TEtD4U_kZtWxC^(Q5WOMj4a9G1Pkm#$fj_x>*W~_Gcouf65Zi3Bi>fdKiYp10) z4Uf^vjFiDmf9MeC6~-G`QQv4k6IemPwZ5yKxBjLvYxniH_rlSV`cxgCnI!{>x@nkCvW{%ok)(QpJvVeQYH(%N*#+0D z)z-v%83QlWUY{8JKG`0lcE3KRL@^wkxK{s+XoP97_XfoQ=SLIt*2KfW;$6kiPSO*Qhm@ax(vub!s%A zn7-_td(`p}&~kHY!EkI$JDe-IgR-a=A!{1e_r=>=m^Vz&|?$=oH=kGX3P`UVcg4Kt3j>vHAhh zu_j5?8C?9R-RPB!h)ODz>~Ws`C?+AVb&u7p4K`Rs-MT!Ox5Q_#d_%Lu;q=h&hlD{_ zX|PhJucW)nJgwjS4G=R5Uv8>&>fLsK-=7Lm}B-ONIHG zP}%c=5upiu-LJAYg4Ylo?*}LM&1lsMN8!untJ87X)cZuA6qaP($kJ(s{B!Wn@%8<6 zwJF_4(((%eVPUgmr}V0~RZjEf@u~3Om_1x??HO^_DX&2gIt6+du_SbC=U3o3HZ8s{ zN%47QC3Hk-H4>LVl3uZZ3gK|kq)ofb|9U8qo3PF8_B_Ac(;#Up8lP1M6Wxy3E~R_q zkZd9!h&VqNeKaEC_!3#1_NtGfJ4TKl8dpT=b$Aej>>=na)4hADB)wbK#|SqY&+Z>w#+Td%RBuev2rKO3 zj|dka^deibqkJj+Qd;TnQ3DiVD!1`OE8qMjiH>oGoYUFq`XrEnGbniS0kWQCmHP)i z{qc1+Lf9Sy@>_?i)6<;D%|gXHfXwV1gGaUtVXDB8l*C#{6nxyKPE?fbcR*GCy#2*a!d}}k;sYy8n9=QTf8svCsEB8R zkT9V)w<9}q^ftT?bmF2(S{dFJ*{Q&Fl0l5%5PqR9Iq;~L_RsYC1cKevR$h~ZWro5K zo8C4v6yv7SR-(t2=@W>ES%NQrD$F%vF(2J{2^ zX)x#C1M*!@1;@~>yYbkP%K#hFVtbIqDu8j_&(sFf=~j`;o80Oot+BcRORB~A@DVmi z>#b`NjBqcn#$}IhZK4X!H+V3%>4)qq@F)93;iIOrunrg!NK#GlQ`T!jM-7I1^di)L zp7)QWs|FPGlqpjs+A^6Ep_$Q)8;9;q+9U@|z&cx;CjM~vK1G1|7O_f!{0bc{tMbZ5 z`uqBtd!5RydKhd{M47Edl_dh7udmpjhK#OOz<>|DAw!4Tn7x^k1HShIRzF2|Nj+wG zSV$U>y+(!CVvzm_jp;8-L$#T&`uTXV8ibuqwa zD|m~cWcncU$(4X7ubNfO2KVuB+1y@Na7mGid3Ne1T^p8&Olv#!f)L(_m%hl26)Fu*x5*g1t0@eKVGv}HXjSPfU#F#W-1__EZi$Q4ro-wWz^_g zbXV}@r=ZH}k|!HrMj(s_dfv*?ryamGbeowGXQeC2+n064mBhvt0L?-VecumwPgmxpJ92942K3zh~Ia7i*ViP|-L0q5>b!W=+l?T$UA{ zV~Eque#L>UA=A!L$}0Un{l+5|8W`E(K~n6MjgO6di(gp>op_Y5&S*E6lakEu2K%44 z)8f39WxtoJY4ya`_VI3C;uFQNF0^)HN0NOwjE7Wuz(Zrl1bgKJB(v{Z`eqNs8P|PB z#vgb}7}-Mw#0`Co)>0h(%>4H!Yg{l)%n9$_&9GlNp0dGquG(2vfjit^u;@Yf#Dibu zu6 zZ2=^@S`(nT%{WBGmZF$*|?^r(9lmzEllA@xdyf| z=#(OJU(U1aD5_15v7&(qTjk~BSX`gN!YBj*=R136{Eum3cL$Hl6}!OPbVP~P9IaC` z$@o?E_{i(FzI5~mLRPUd1a+| z4$tisz2diO*4w~={>r^4?a_wt0oCFT=M3PL9c~&LvY!S6FiaVpg0aB4;qC1xt5JbT z!nY90@%ZVvy^uV><-=@3wv?SH2^~MX&>fvfHrn|eYM8i@nCQeTv!wlO`ALv%H;@is z4TS$%hH2eAo7t)#K`{lwPY=~}ZtlD)6k2v7`J3+`pFWI|oobXPm3f{YQ~Kq*gdd)F z;it~Smw~a{U>5pfS;?I&m&1IWk0w9b^|Q1Qa_T`~_%Xl0m%u1TA{b%Fr)$r1y-CIK zqlH7aqfn@oB{iQc^C3GolW%Py8wGx04A7KwD>JBa-J}RKxG3E!SXTB&GZ1F{k|8-c%=3|VoqfNO zFj;$I;K8z`!C6*}`nYXA#DC5%QYVHo9kw0&#R}))M50soOR^?+tk30n&sKo0h#IhL z_GcWx<)Wt#r!)1YJ3w8Kx$_m<*(%mFj}A={@|L|iTF%{@E>&`OZvdiL=NNH$Id{4u>u7;lwI#&%r-!cj=Z8zqp=BpI8)MVg1=&_9&4@5&SWr(2T?F3S9{%# zfNFH+f(;|PGoBsKN3?-Al$u*bX~=If^f@J-%c#O0g93#`uNNaCP>e(keB!7R!{4~H z4CirSCaT5MB~F^v*m%$p&oX^#>8w}Q5cm?m-ary!l3V>GIV(&yA?yDxOVXe zX`yQF`H;{!VBOS{OL?^4FL97?16lLrEs+=098!7Ji)FrCteMl(;CcJ#PfO09hS1XT z>+4mCF?sMv7^!qKm29d?KhMoErE;NiFmo>vrUWX_Wr+R6`jr&n@o^Te)+Up;+FbGR{^mK8sQQr|O0;mi9QMN2 zb+P64R3=D(Af4{4hG>9l6qET&$mVjcsvH6Zr}gA$8Vhv*n)2avk-AvDZlUofnq~{= zuyjK?`=lAc)t5WJJoSk;(q!L5J2op&Y^w@nEI(%{3L)yit99%#q=*A===2+IdQvEr zT5HpkDo_V7UKOYo=49DuwW>(b6vLbz4XZkYt!(xYs!3U<=1?=Aq0}!7K|OGXN0aUEV}y8lvOlmQ?VWa%=5< z@(s8=*6R&SSihoyfoWcaD;B=Qu0

U_`CNd-;Rgi&+Oro2Ad=H=dfwCM>!olW1u_ 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 U3~aATNr2CTdzz}ncg_9&AJJ5H6951J literal 0 HcmV?d00001 diff --git a/docs/images/build.png b/docs/images/build.png deleted file mode 100644 index 7c5914c82597681eaeedbec895967d8794eada01..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 62555 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 diff --git a/docs/images/docker_build.png b/docs/images/docker_build.png deleted file mode 100644 index f4be10f6894b79a586b725cb463b5333690b5e48..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 58699 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 diff --git a/docs/readme/README-UA.md b/docs/readme/README-UA.md new file mode 100644 index 0000000000..892e16d19f --- /dev/null +++ b/docs/readme/README-UA.md @@ -0,0 +1,7 @@ +

+ + + +

+ +
\ No newline at end of file From 854f8dbd2f80cf71a16c5a3a3a4db5d38ac65da7 Mon Sep 17 00:00:00 2001 From: Xinwei Xiong <3293172751NSS@gmail.com> Date: Fri, 2 Feb 2024 21:59:12 +0800 Subject: [PATCH 024/188] feat: Optimize openim scripts and standard output logs (#1866) * feat: add component check func * fix: fix the outpu error * fix: fix the stderr outpu * fix: fix the component check func * fix: fix the error * fix: fix the output error * fix: del the disruptions code * fix the log output format * fix: fix the tools version * fix: fix the cycle detection * fix: fix the error * fix: fix the flag * fix: add mongo ping detection * fix: fix the tools pkg version * fix: del the err * feat: support openim readme docs Signed-off-by: Xinwei Xiong (cubxxw) <3293172751nss@gmail.com> * feat: support openim readme docs Signed-off-by: Xinwei Xiong (cubxxw) <3293172751nss@gmail.com> * feat: support openim readme docs Signed-off-by: Xinwei Xiong (cubxxw) <3293172751nss@gmail.com> * fix: fix the minio nil error * fix: del the repeated wrap and add err print * fix: fix this bug scripts * Revert "Check" --------- Signed-off-by: Xinwei Xiong (cubxxw) <3293172751nss@gmail.com> Co-authored-by: luhaoling <2198702716@qq.com> --- cmd/openim-api/main.go | 3 ++- cmd/openim-cmdutils/main.go | 5 +++- cmd/openim-crontask/main.go | 5 +++- cmd/openim-msggateway/main.go | 5 +++- cmd/openim-msgtransfer/main.go | 5 +++- cmd/openim-push/main.go | 5 +++- cmd/openim-rpc/openim-rpc-auth/main.go | 5 +++- .../openim-rpc-conversation/main.go | 5 +++- cmd/openim-rpc/openim-rpc-friend/main.go | 5 +++- cmd/openim-rpc/openim-rpc-group/main.go | 5 +++- cmd/openim-rpc/openim-rpc-msg/main.go | 5 +++- cmd/openim-rpc/openim-rpc-third/main.go | 5 +++- cmd/openim-rpc/openim-rpc-user/main.go | 5 +++- go.mod | 2 +- go.sum | 4 +-- pkg/common/cmd/root.go | 1 - pkg/common/db/unrelation/mongo.go | 5 ++-- .../discoveryregister/zookeeper/zookeeper.go | 2 +- pkg/common/startrpc/start.go | 7 ++--- scripts/check-all.sh | 10 +++++++ scripts/install/openim-api.sh | 10 ++++--- scripts/install/openim-crontask.sh | 7 ++++- scripts/install/openim-msggateway.sh | 5 +++- scripts/install/openim-msgtransfer.sh | 5 +++- scripts/install/openim-push.sh | 7 +++-- scripts/install/openim-rpc.sh | 5 +++- scripts/lib/logging.sh | 4 +++ scripts/lib/util.sh | 27 +++++++++++++------ tools/component/component.go | 26 +++++++++++------- tools/ncpu/ncpu.go | 23 +++++----------- 30 files changed, 146 insertions(+), 67 deletions(-) diff --git a/cmd/openim-api/main.go b/cmd/openim-api/main.go index 59e0b7f9e3..755b355916 100644 --- a/cmd/openim-api/main.go +++ b/cmd/openim-api/main.go @@ -43,7 +43,8 @@ func main() { apiCmd.AddPortFlag() apiCmd.AddApi(run) if err := apiCmd.Execute(); err != nil { - panic(err.Error()) + fmt.Fprintf(os.Stderr, "\n\nexit -1: \n%+v\n\n", err) + os.Exit(-1) } } diff --git a/cmd/openim-cmdutils/main.go b/cmd/openim-cmdutils/main.go index 058aa2e29c..a13bc4f338 100644 --- a/cmd/openim-cmdutils/main.go +++ b/cmd/openim-cmdutils/main.go @@ -15,7 +15,9 @@ package main import ( + "fmt" "github.com/openimsdk/open-im-server/v3/pkg/common/cmd" + "os" ) func main() { @@ -54,6 +56,7 @@ func main() { // openIM clear msg --clearAll msgUtilsCmd.AddCommand(&getCmd.Command, &fixCmd.Command, &clearCmd.Command) if err := msgUtilsCmd.Execute(); err != nil { - panic(err) + fmt.Fprintf(os.Stderr, "\n\nexit -1: \n%+v\n\n", err) + os.Exit(-1) } } diff --git a/cmd/openim-crontask/main.go b/cmd/openim-crontask/main.go index 3bd0d882bc..5061c54088 100644 --- a/cmd/openim-crontask/main.go +++ b/cmd/openim-crontask/main.go @@ -15,13 +15,16 @@ package main import ( + "fmt" "github.com/openimsdk/open-im-server/v3/internal/tools" "github.com/openimsdk/open-im-server/v3/pkg/common/cmd" + "os" ) func main() { cronTaskCmd := cmd.NewCronTaskCmd() if err := cronTaskCmd.Exec(tools.StartTask); err != nil { - panic(err.Error()) + fmt.Fprintf(os.Stderr, "\n\nexit -1: \n%+v\n\n", err) + os.Exit(-1) } } diff --git a/cmd/openim-msggateway/main.go b/cmd/openim-msggateway/main.go index 6d212e4671..25cfe5fa87 100644 --- a/cmd/openim-msggateway/main.go +++ b/cmd/openim-msggateway/main.go @@ -15,7 +15,9 @@ package main import ( + "fmt" "github.com/openimsdk/open-im-server/v3/pkg/common/cmd" + "os" ) func main() { @@ -25,6 +27,7 @@ func main() { msgGatewayCmd.AddPrometheusPortFlag() if err := msgGatewayCmd.Exec(); err != nil { - panic(err.Error()) + fmt.Fprintf(os.Stderr, "\n\nexit -1: \n%+v\n\n", err) + os.Exit(-1) } } diff --git a/cmd/openim-msgtransfer/main.go b/cmd/openim-msgtransfer/main.go index 6895bcecc8..e3c2f374f2 100644 --- a/cmd/openim-msgtransfer/main.go +++ b/cmd/openim-msgtransfer/main.go @@ -15,7 +15,9 @@ package main import ( + "fmt" "github.com/openimsdk/open-im-server/v3/pkg/common/cmd" + "os" ) func main() { @@ -23,6 +25,7 @@ func main() { msgTransferCmd.AddPrometheusPortFlag() msgTransferCmd.AddTransferProgressFlag() if err := msgTransferCmd.Exec(); err != nil { - panic(err.Error()) + fmt.Fprintf(os.Stderr, "\n\nexit -1: \n%+v\n\n", err) + os.Exit(-1) } } diff --git a/cmd/openim-push/main.go b/cmd/openim-push/main.go index c19cfda60c..79152f9453 100644 --- a/cmd/openim-push/main.go +++ b/cmd/openim-push/main.go @@ -15,9 +15,11 @@ package main import ( + "fmt" "github.com/openimsdk/open-im-server/v3/internal/push" "github.com/openimsdk/open-im-server/v3/pkg/common/cmd" "github.com/openimsdk/open-im-server/v3/pkg/common/config" + "os" ) func main() { @@ -28,6 +30,7 @@ func main() { panic(err.Error()) } if err := pushCmd.StartSvr(config.Config.RpcRegisterName.OpenImPushName, push.Start); err != nil { - panic(err.Error()) + fmt.Fprintf(os.Stderr, "\n\nexit -1: \n%+v\n\n", err) + os.Exit(-1) } } diff --git a/cmd/openim-rpc/openim-rpc-auth/main.go b/cmd/openim-rpc/openim-rpc-auth/main.go index 645d8cab89..8ee7053f3f 100644 --- a/cmd/openim-rpc/openim-rpc-auth/main.go +++ b/cmd/openim-rpc/openim-rpc-auth/main.go @@ -15,9 +15,11 @@ package main import ( + "fmt" "github.com/openimsdk/open-im-server/v3/internal/rpc/auth" "github.com/openimsdk/open-im-server/v3/pkg/common/cmd" "github.com/openimsdk/open-im-server/v3/pkg/common/config" + "os" ) func main() { @@ -28,6 +30,7 @@ func main() { panic(err.Error()) } if err := authCmd.StartSvr(config.Config.RpcRegisterName.OpenImAuthName, auth.Start); err != nil { - panic(err.Error()) + fmt.Fprintf(os.Stderr, "\n\nexit -1: \n%+v\n\n", err) + os.Exit(-1) } } diff --git a/cmd/openim-rpc/openim-rpc-conversation/main.go b/cmd/openim-rpc/openim-rpc-conversation/main.go index 13d7db605c..259d79abf3 100644 --- a/cmd/openim-rpc/openim-rpc-conversation/main.go +++ b/cmd/openim-rpc/openim-rpc-conversation/main.go @@ -15,9 +15,11 @@ package main import ( + "fmt" "github.com/openimsdk/open-im-server/v3/internal/rpc/conversation" "github.com/openimsdk/open-im-server/v3/pkg/common/cmd" "github.com/openimsdk/open-im-server/v3/pkg/common/config" + "os" ) func main() { @@ -28,6 +30,7 @@ func main() { panic(err.Error()) } if err := rpcCmd.StartSvr(config.Config.RpcRegisterName.OpenImConversationName, conversation.Start); err != nil { - panic(err.Error()) + fmt.Fprintf(os.Stderr, "\n\nexit -1: \n%+v\n\n", err) + os.Exit(-1) } } diff --git a/cmd/openim-rpc/openim-rpc-friend/main.go b/cmd/openim-rpc/openim-rpc-friend/main.go index ec18306a2c..bd85da7b09 100644 --- a/cmd/openim-rpc/openim-rpc-friend/main.go +++ b/cmd/openim-rpc/openim-rpc-friend/main.go @@ -15,9 +15,11 @@ package main import ( + "fmt" "github.com/openimsdk/open-im-server/v3/internal/rpc/friend" "github.com/openimsdk/open-im-server/v3/pkg/common/cmd" "github.com/openimsdk/open-im-server/v3/pkg/common/config" + "os" ) func main() { @@ -28,6 +30,7 @@ func main() { panic(err.Error()) } if err := rpcCmd.StartSvr(config.Config.RpcRegisterName.OpenImFriendName, friend.Start); err != nil { - panic(err.Error()) + fmt.Fprintf(os.Stderr, "\n\nexit -1: \n%+v\n\n", err) + os.Exit(-1) } } diff --git a/cmd/openim-rpc/openim-rpc-group/main.go b/cmd/openim-rpc/openim-rpc-group/main.go index 8873299262..e40c04d19d 100644 --- a/cmd/openim-rpc/openim-rpc-group/main.go +++ b/cmd/openim-rpc/openim-rpc-group/main.go @@ -15,9 +15,11 @@ package main import ( + "fmt" "github.com/openimsdk/open-im-server/v3/internal/rpc/group" "github.com/openimsdk/open-im-server/v3/pkg/common/cmd" "github.com/openimsdk/open-im-server/v3/pkg/common/config" + "os" ) func main() { @@ -28,6 +30,7 @@ func main() { panic(err.Error()) } if err := rpcCmd.StartSvr(config.Config.RpcRegisterName.OpenImGroupName, group.Start); err != nil { - panic(err.Error()) + fmt.Fprintf(os.Stderr, "\n\nexit -1: \n%+v\n\n", err) + os.Exit(-1) } } diff --git a/cmd/openim-rpc/openim-rpc-msg/main.go b/cmd/openim-rpc/openim-rpc-msg/main.go index dcc3abef5e..989746dc7f 100644 --- a/cmd/openim-rpc/openim-rpc-msg/main.go +++ b/cmd/openim-rpc/openim-rpc-msg/main.go @@ -15,9 +15,11 @@ package main import ( + "fmt" "github.com/openimsdk/open-im-server/v3/internal/rpc/msg" "github.com/openimsdk/open-im-server/v3/pkg/common/cmd" "github.com/openimsdk/open-im-server/v3/pkg/common/config" + "os" ) func main() { @@ -28,6 +30,7 @@ func main() { panic(err.Error()) } if err := rpcCmd.StartSvr(config.Config.RpcRegisterName.OpenImMsgName, msg.Start); err != nil { - panic(err.Error()) + fmt.Fprintf(os.Stderr, "\n\nexit -1: \n%+v\n\n", err) + os.Exit(-1) } } diff --git a/cmd/openim-rpc/openim-rpc-third/main.go b/cmd/openim-rpc/openim-rpc-third/main.go index cf0bf4b703..fbd3869468 100644 --- a/cmd/openim-rpc/openim-rpc-third/main.go +++ b/cmd/openim-rpc/openim-rpc-third/main.go @@ -15,9 +15,11 @@ package main import ( + "fmt" "github.com/openimsdk/open-im-server/v3/internal/rpc/third" "github.com/openimsdk/open-im-server/v3/pkg/common/cmd" "github.com/openimsdk/open-im-server/v3/pkg/common/config" + "os" ) func main() { @@ -28,6 +30,7 @@ func main() { panic(err.Error()) } if err := rpcCmd.StartSvr(config.Config.RpcRegisterName.OpenImThirdName, third.Start); err != nil { - panic(err.Error()) + fmt.Fprintf(os.Stderr, "\n\nexit -1: \n%+v\n\n", err) + os.Exit(-1) } } diff --git a/cmd/openim-rpc/openim-rpc-user/main.go b/cmd/openim-rpc/openim-rpc-user/main.go index cbf2a8fc3a..160bbe311e 100644 --- a/cmd/openim-rpc/openim-rpc-user/main.go +++ b/cmd/openim-rpc/openim-rpc-user/main.go @@ -15,9 +15,11 @@ package main import ( + "fmt" "github.com/openimsdk/open-im-server/v3/internal/rpc/user" "github.com/openimsdk/open-im-server/v3/pkg/common/cmd" "github.com/openimsdk/open-im-server/v3/pkg/common/config" + "os" ) func main() { @@ -28,6 +30,7 @@ func main() { panic(err.Error()) } if err := rpcCmd.StartSvr(config.Config.RpcRegisterName.OpenImUserName, user.Start); err != nil { - panic(err.Error()) + fmt.Fprintf(os.Stderr, "\n\nexit -1: \n%+v\n\n", err) + os.Exit(-1) } } diff --git a/go.mod b/go.mod index 16a10a945e..d82d3390b6 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.19 require ( firebase.google.com/go v3.13.0+incompatible github.com/OpenIMSDK/protocol v0.0.48 - github.com/OpenIMSDK/tools v0.0.32 + github.com/OpenIMSDK/tools v0.0.33 github.com/bwmarrin/snowflake v0.3.0 // indirect github.com/dtm-labs/rockscache v0.1.1 github.com/gin-gonic/gin v1.9.1 diff --git a/go.sum b/go.sum index 136035cef0..fb047dfdc4 100644 --- a/go.sum +++ b/go.sum @@ -20,8 +20,8 @@ github.com/IBM/sarama v1.41.3 h1:MWBEJ12vHC8coMjdEXFq/6ftO6DUZnQlFYcxtOJFa7c= github.com/IBM/sarama v1.41.3/go.mod h1:Xxho9HkHd4K/MDUo/T/sOqwtX/17D33++E9Wib6hUdQ= github.com/OpenIMSDK/protocol v0.0.48 h1:8MIMjyzJRsruYhVv2ZKArFiOveroaofDOb3dlAdgjsw= github.com/OpenIMSDK/protocol v0.0.48/go.mod h1:F25dFrwrIx3lkNoiuf6FkCfxuwf8L4Z8UIsdTHP/r0Y= -github.com/OpenIMSDK/tools v0.0.32 h1:b8KwtxXKZTsyyHUcZ4OtSo6s/vVXx4HjMuPxH7Kb7Gg= -github.com/OpenIMSDK/tools v0.0.32/go.mod h1:wBfR5CYmEyvxl03QJbTkhz1CluK6J4/lX0lviu8JAjE= +github.com/OpenIMSDK/tools v0.0.33 h1:rvFCxXaXxLv1MJFC4qcoWRGwKBnV+hR68UN2N0/zZhE= +github.com/OpenIMSDK/tools v0.0.33/go.mod h1:wBfR5CYmEyvxl03QJbTkhz1CluK6J4/lX0lviu8JAjE= github.com/QcloudApi/qcloud_sign_golang v0.0.0-20141224014652-e4130a326409/go.mod h1:1pk82RBxDY/JZnPQrtqHlUFfCctgdorsd9M06fMynOM= github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7 h1:uSoVVbwJiQipAclBbw+8quDsfcvFjOpI5iCf4p/cqCs= github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs= diff --git a/pkg/common/cmd/root.go b/pkg/common/cmd/root.go index 66bec61a79..98ca8f892a 100644 --- a/pkg/common/cmd/root.go +++ b/pkg/common/cmd/root.go @@ -20,7 +20,6 @@ import ( config2 "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/spf13/cobra" - _ "go.uber.org/automaxprocs" "github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/tools/log" diff --git a/pkg/common/db/unrelation/mongo.go b/pkg/common/db/unrelation/mongo.go index fe89c6b8a2..2bade9a624 100644 --- a/pkg/common/db/unrelation/mongo.go +++ b/pkg/common/db/unrelation/mongo.go @@ -54,14 +54,15 @@ func NewMongo() (*Mongo, error) { defer cancel() mongoClient, err = mongo.Connect(ctx, options.Client().ApplyURI(uri)) if err == nil { + if err = mongoClient.Ping(ctx, nil); err != nil { + return nil, errs.Wrap(err, uri) + } return &Mongo{db: mongoClient}, nil } if shouldRetry(err) { - fmt.Printf("Failed to connect to MongoDB, retrying: %s\n", err) time.Sleep(time.Second) // exponential backoff could be implemented here continue } - return nil, errs.Wrap(err, uri) } return nil, errs.Wrap(err, uri) } diff --git a/pkg/common/discoveryregister/zookeeper/zookeeper.go b/pkg/common/discoveryregister/zookeeper/zookeeper.go index 0082e9833d..9c58807c1d 100644 --- a/pkg/common/discoveryregister/zookeeper/zookeeper.go +++ b/pkg/common/discoveryregister/zookeeper/zookeeper.go @@ -45,7 +45,7 @@ func NewZookeeperDiscoveryRegister() (discoveryregistry.SvcDiscoveryRegistry, er openkeeper.WithLogger(log.NewZkLogger()), ) if err != nil { - uriFormat := "address:%s, username :%s, password :%s, schema:%s." + uriFormat := "address:%s, username:%s, password:%s, schema:%s." errInfo := fmt.Sprintf(uriFormat, config.Config.Zookeeper.ZkAddr, config.Config.Zookeeper.Username, diff --git a/pkg/common/startrpc/start.go b/pkg/common/startrpc/start.go index 31fe4fdd56..f7b5478345 100644 --- a/pkg/common/startrpc/start.go +++ b/pkg/common/startrpc/start.go @@ -17,7 +17,6 @@ package startrpc import ( "errors" "fmt" - "github.com/OpenIMSDK/tools/errs" "log" "net" "net/http" @@ -28,6 +27,8 @@ import ( "syscall" "time" + "github.com/OpenIMSDK/tools/errs" + "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promhttp" "golang.org/x/sync/errgroup" @@ -96,7 +97,7 @@ func Start( err = rpcFn(client, srv) if err != nil { - return errs.Wrap(err) + return err } err = client.Register( rpcRegisterName, @@ -116,7 +117,7 @@ func Start( // Create a HTTP server for prometheus. httpServer := &http.Server{Handler: promhttp.HandlerFor(reg, promhttp.HandlerOpts{}), Addr: fmt.Sprintf("0.0.0.0:%d", prometheusPort)} if err := httpServer.ListenAndServe(); err != nil { - log.Fatal("Unable to start a http server.") + log.Fatal("Unable to start a http server. ", err.Error(), "PrometheusPort:", prometheusPort) } } return nil diff --git a/scripts/check-all.sh b/scripts/check-all.sh index 1f6b740e61..062605ae11 100755 --- a/scripts/check-all.sh +++ b/scripts/check-all.sh @@ -49,6 +49,14 @@ print_services_and_ports() { echo "+-------------------------+----------+" } +handle_error() { + echo "An error occurred. Printing ${STDERR_LOG_FILE} contents:" + cat "${STDERR_LOG_FILE}" + exit 1 +} + +trap handle_error ERR + # Assuming OPENIM_SERVER_NAME_TARGETS and OPENIM_SERVER_PORT_TARGETS are defined # Similarly for OPENIM_DEPENDENCY_TARGETS and OPENIM_DEPENDENCY_PORT_TARGETS @@ -94,3 +102,5 @@ else fi set -e + +trap - ERR \ No newline at end of file diff --git a/scripts/install/openim-api.sh b/scripts/install/openim-api.sh index 2c3c19afb5..c81dfcd0d6 100755 --- a/scripts/install/openim-api.sh +++ b/scripts/install/openim-api.sh @@ -34,12 +34,15 @@ readonly OPENIM_API_SERVICE_TARGETS=( readonly OPENIM_API_SERVICE_LISTARIES=("${OPENIM_API_SERVICE_TARGETS[@]##*/}") function openim::api::start() { + + rm -rf "$TMP_LOG_FILE" + echo "++ OPENIM_API_SERVICE_LISTARIES: ${OPENIM_API_SERVICE_LISTARIES[@]}" echo "++ OPENIM_API_PORT_LISTARIES: ${OPENIM_API_PORT_LISTARIES[@]}" echo "++ OpenIM API config path: ${OPENIM_API_CONFIG}" - + openim::log::info "Starting ${SERVER_NAME} ..." - + printf "+------------------------+--------------+\n" printf "| Service Name | Port |\n" printf "+------------------------+--------------+\n" @@ -80,8 +83,7 @@ function openim::api::start_service() { local prometheus_port="$3" local cmd="${OPENIM_OUTPUT_HOSTBIN}/${binary_name} --port ${service_port} -c ${OPENIM_API_CONFIG}" - - nohup ${cmd} >> "${LOG_FILE}" 2>&1 & + nohup ${cmd} >> "${LOG_FILE}" 2> >(tee -a "${STDERR_LOG_FILE}" "$TMP_LOG_FILE") & if [ $? -ne 0 ]; then openim::log::error_exit "Failed to start ${binary_name} on port ${service_port}." diff --git a/scripts/install/openim-crontask.sh b/scripts/install/openim-crontask.sh index cc9e686ffe..6068e97d5a 100755 --- a/scripts/install/openim-crontask.sh +++ b/scripts/install/openim-crontask.sh @@ -44,14 +44,19 @@ OPENIM_ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")"/../.. && pwd -P) SERVER_NAME="openim-crontask" function openim::crontask::start() { + + rm -rf "$TMP_LOG_FILE" + openim::log::info "Start OpenIM Cron, binary root: ${SERVER_NAME}" openim::log::status "Start OpenIM Cron, path: ${OPENIM_CRONTASK_BINARY}" openim::util::stop_services_with_name ${OPENIM_CRONTASK_BINARY} openim::log::status "start cron_task process, path: ${OPENIM_CRONTASK_BINARY}" - nohup ${OPENIM_CRONTASK_BINARY} -c ${OPENIM_PUSH_CONFIG} >> ${LOG_FILE} 2>&1 & + + nohup ${OPENIM_CRONTASK_BINARY} -c ${OPENIM_PUSH_CONFIG} >> ${LOG_FILE} 2> >(tee -a "${STDERR_LOG_FILE}" "$TMP_LOG_FILE") & openim::util::check_process_names ${SERVER_NAME} + } ###################################### Linux Systemd ###################################### diff --git a/scripts/install/openim-msggateway.sh b/scripts/install/openim-msggateway.sh index d9fec4928c..4e591decae 100755 --- a/scripts/install/openim-msggateway.sh +++ b/scripts/install/openim-msggateway.sh @@ -26,6 +26,9 @@ openim::util::set_max_fd 200000 SERVER_NAME="openim-msggateway" function openim::msggateway::start() { + + rm -rf "$TMP_LOG_FILE" + openim::log::info "Start OpenIM Msggateway, binary root: ${SERVER_NAME}" openim::log::status "Start OpenIM Msggateway, path: ${OPENIM_MSGGATEWAY_BINARY}" @@ -61,7 +64,7 @@ function openim::msggateway::start() { PROMETHEUS_PORT_OPTION="--prometheus_port ${MSG_GATEWAY_PROM_PORTS_ARRAY[$i]}" fi - nohup ${OPENIM_MSGGATEWAY_BINARY} --port ${OPENIM_MSGGATEWAY_PORTS_ARRAY[$i]} --ws_port ${OPENIM_WS_PORTS_ARRAY[$i]} $PROMETHEUS_PORT_OPTION -c ${OPENIM_MSGGATEWAY_CONFIG} >> ${LOG_FILE} 2>&1 & + nohup ${OPENIM_MSGGATEWAY_BINARY} --port ${OPENIM_MSGGATEWAY_PORTS_ARRAY[$i]} --ws_port ${OPENIM_WS_PORTS_ARRAY[$i]} $PROMETHEUS_PORT_OPTION -c ${OPENIM_MSGGATEWAY_CONFIG} >> ${LOG_FILE} 2> >(tee -a "${STDERR_LOG_FILE}" "$TMP_LOG_FILE") & done openim::util::check_process_names ${SERVER_NAME} diff --git a/scripts/install/openim-msgtransfer.sh b/scripts/install/openim-msgtransfer.sh index 1cead3a9af..def22c38b2 100755 --- a/scripts/install/openim-msgtransfer.sh +++ b/scripts/install/openim-msgtransfer.sh @@ -28,6 +28,9 @@ openim::util::set_max_fd 200000 SERVER_NAME="openim-msgtransfer" function openim::msgtransfer::start() { + + rm -rf "$TMP_LOG_FILE" + openim::log::info "Start OpenIM Msggateway, binary root: ${SERVER_NAME}" openim::log::status "Start OpenIM Msggateway, path: ${OPENIM_MSGTRANSFER_BINARY}" @@ -56,7 +59,7 @@ function openim::msgtransfer::start() { if [[ -n "${OPENIM_PROMETHEUS_PORTS[$i]}" ]]; then PROMETHEUS_PORT_OPTION="--prometheus_port ${OPENIM_PROMETHEUS_PORTS[$i]}" fi - nohup ${OPENIM_MSGTRANSFER_BINARY} ${PROMETHEUS_PORT_OPTION} -c ${OPENIM_MSGTRANSFER_CONFIG} -n ${i}>> ${LOG_FILE} 2>&1 & + nohup ${OPENIM_MSGTRANSFER_BINARY} ${PROMETHEUS_PORT_OPTION} -c ${OPENIM_MSGTRANSFER_CONFIG} -n ${i} >> ${LOG_FILE} 2> >(tee -a "${STDERR_LOG_FILE}" "$TMP_LOG_FILE") & done openim::util::check_process_names "${OPENIM_OUTPUT_HOSTBIN}/${SERVER_NAME}" diff --git a/scripts/install/openim-push.sh b/scripts/install/openim-push.sh index d43743e4f9..4d14ca6752 100755 --- a/scripts/install/openim-push.sh +++ b/scripts/install/openim-push.sh @@ -50,6 +50,9 @@ OPENIM_ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")"/../.. && pwd -P) SERVER_NAME="openim-push" function openim::push::start() { + + rm -rf "$TMP_LOG_FILE" + openim::log::status "Start OpenIM Push, binary root: ${SERVER_NAME}" openim::log::info "Start OpenIM Push, path: ${OPENIM_PUSH_BINARY}" @@ -70,9 +73,9 @@ function openim::push::start() { for (( i=0; i<${#OPENIM_PUSH_PORTS_ARRAY[@]}; i++ )); do openim::log::info "start push process, port: ${OPENIM_PUSH_PORTS_ARRAY[$i]}, prometheus port: ${PUSH_PROM_PORTS_ARRAY[$i]}" - nohup ${OPENIM_PUSH_BINARY} --port ${OPENIM_PUSH_PORTS_ARRAY[$i]} -c ${OPENIM_PUSH_CONFIG} --prometheus_port ${PUSH_PROM_PORTS_ARRAY[$i]} >> ${LOG_FILE} 2>&1 & + nohup ${OPENIM_PUSH_BINARY} --port ${OPENIM_PUSH_PORTS_ARRAY[$i]} -c ${OPENIM_PUSH_CONFIG} --prometheus_port ${PUSH_PROM_PORTS_ARRAY[$i]} >${LOG_FILE} 2> >(tee -a "${STDERR_LOG_FILE}" "$TMP_LOG_FILE") & done - + openim::util::check_process_names ${SERVER_NAME} } diff --git a/scripts/install/openim-rpc.sh b/scripts/install/openim-rpc.sh index 966eef928d..00031f211f 100755 --- a/scripts/install/openim-rpc.sh +++ b/scripts/install/openim-rpc.sh @@ -102,6 +102,8 @@ readonly OPENIM_RPC_PROM_PORT_TARGETS readonly OPENIM_RPC_PROM_PORT_LISTARIES=("${OPENIM_RPC_PROM_PORT_TARGETS[@]##*/}") function openim::rpc::start() { + rm -rf "$TMP_LOG_FILE" + echo "OPENIM_RPC_SERVICE_LISTARIES: ${OPENIM_RPC_SERVICE_LISTARIES[@]}" echo "OPENIM_RPC_PROM_PORT_LISTARIES: ${OPENIM_RPC_PROM_PORT_LISTARIES[@]}" echo "OPENIM_RPC_PORT_LISTARIES: ${OPENIM_RPC_PORT_LISTARIES[@]}" @@ -123,6 +125,7 @@ function openim::rpc::start() { for ((i = 0; i < ${#OPENIM_RPC_SERVICE_LISTARIES[*]}; i++)); do # openim::util::stop_services_with_name ${OPENIM_RPC_SERVICE_LISTARIES openim::util::stop_services_on_ports ${OPENIM_RPC_PORT_LISTARIES[$i]} + openim::util::stop_services_on_ports ${OPENIM_RPC_PROM_PORT_LISTARIES[$i]} openim::log::info "OpenIM ${OPENIM_RPC_SERVICE_LISTARIES[$i]} config path: ${OPENIM_RPC_CONFIG}" @@ -157,7 +160,7 @@ function openim::rpc::start_service() { printf "Specifying prometheus port: %s\n" "${prometheus_port}" cmd="${cmd} --prometheus_port ${prometheus_port}" fi - nohup ${cmd} >> "${LOG_FILE}" 2>&1 & + nohup ${cmd} >> "${LOG_FILE}" 2> >(tee -a "${STDERR_LOG_FILE}" "$TMP_LOG_FILE") & } ###################################### Linux Systemd ###################################### diff --git a/scripts/lib/logging.sh b/scripts/lib/logging.sh index c520850e8f..2fa77dd83c 100755 --- a/scripts/lib/logging.sh +++ b/scripts/lib/logging.sh @@ -26,10 +26,14 @@ fi # Set the log file path LOG_FILE="${OPENIM_OUTPUT}/logs/openim_$(date '+%Y%m%d').log" +STDERR_LOG_FILE="${OPENIM_OUTPUT}/logs/openim_error_$(date '+%Y%m%d').log" +TMP_LOG_FILE="${OPENIM_OUTPUT}/logs/openim_tmp_$(date '+%Y%m%d').log" if [[ ! -d "${OPENIM_OUTPUT}/logs" ]]; then mkdir -p "${OPENIM_OUTPUT}/logs" touch "$LOG_FILE" + touch "$STDERR_LOG_FILE" + touch "$TMP_LOG_FILE" fi # Define the logging function diff --git a/scripts/lib/util.sh b/scripts/lib/util.sh index a40668d70e..b93f45205b 100755 --- a/scripts/lib/util.sh +++ b/scripts/lib/util.sh @@ -360,7 +360,9 @@ openim::util::check_ports() { # If any of the processes is not running, return a status of 1. if [[ ${#not_started[@]} -ne 0 ]]; then - echo "++++ OpenIM Log >> cat ${LOG_FILE}" + openim::color::echo $COLOR_RED " OpenIM Stdout Log >> cat ${LOG_FILE}" + openim::color::echo $COLOR_RED " OpenIM Stderr Log >> cat ${STDERR_LOG_FILE}" + cat "$TMP_LOG_FILE" | awk '{print "\033[31m" $0 "\033[0m"}' return 1 else openim::log::success "All specified processes are running." @@ -444,9 +446,12 @@ openim::util::check_process_names() { # Return status if [[ ${#not_started[@]} -ne 0 ]]; then - echo "++++ OpenIM Log >> cat ${LOG_FILE}" + openim::color::echo $COLOR_RED " OpenIM Stdout Log >> cat ${LOG_FILE}" + openim::color::echo $COLOR_RED " OpenIM Stderr Log >> cat ${STDERR_LOG_FILE}" + cat "$TMP_LOG_FILE" | awk '{print "\033[31m" $0 "\033[0m"}' return 1 else + echo "" openim::log::success "All processes are running." return 0 fi @@ -1536,12 +1541,12 @@ openim::util::check_ports() { if [[ "$OSTYPE" == "linux-gnu"* ]]; then if command -v ss > /dev/null 2>&1; then info=$(ss -ltnp | grep ":$port" || true) - echo "!!!!!!!!!!! port=$port" - echo "!!!!!!!!!!! info=$info" + openim::color::echo $COLOR_RED "!!!!!!!! port=$port" + openim::color::echo $COLOR_RED "!!!!!!!! info=$info" else info=$(netstat -ltnp | grep ":$port" || true) - echo "!!!!!!!!!!! port=$port" - echo "!!!!!!!!!!! info=$info" + openim::color::echo $COLOR_RED "!!!!!!!! port=$port" + openim::color::echo $COLOR_RED "!!!!!!!! info=$info" fi elif [[ "$OSTYPE" == "darwin"* ]]; then # For macOS, use lsof @@ -1594,7 +1599,10 @@ openim::util::check_ports() { # If any of the processes is not running, return a status of 1. if [[ ${#not_started[@]} -ne 0 ]]; then - echo "++++ OpenIM Log >> cat ${LOG_FILE}" + openim::color::echo $COLOR_RED " OpenIM Stdout Log >> cat ${LOG_FILE}" + openim::color::echo $COLOR_RED " OpenIM Stderr Log >> cat ${STDERR_LOG_FILE}" + echo "" + cat "$TMP_LOG_FILE" | awk '{print "\033[31m" $0 "\033[0m"}' return 1 else openim::log::success "All specified processes are running." @@ -1678,9 +1686,12 @@ openim::util::check_process_names() { # Return status if [[ ${#not_started[@]} -ne 0 ]]; then - echo "++++ OpenIM Log >> cat ${LOG_FILE}" + openim::color::echo $COLOR_RED " OpenIM Stdout Log >> cat ${LOG_FILE}" + openim::color::echo $COLOR_RED " OpenIM Stderr Log >> cat ${STDERR_LOG_FILE}" + cat "$TMP_LOG_FILE" | awk '{print "\033[31m" $0 "\033[0m"}' return 1 else + echo "" openim::log::success "All processes are running." return 0 fi diff --git a/tools/component/component.go b/tools/component/component.go index 787ca8af68..bd60070157 100644 --- a/tools/component/component.go +++ b/tools/component/component.go @@ -15,6 +15,7 @@ package main import ( + "errors" "flag" "fmt" "github.com/IBM/sarama" @@ -56,6 +57,7 @@ func initCfg() error { type checkFunc struct { name string function func() error + flag bool } func main() { @@ -86,13 +88,17 @@ func main() { var err error allSuccess := true - for _, check := range checks { - err = check.function() - if err != nil { - component.ErrorPrint(fmt.Sprintf("Starting %s failed:%v.", check.name, err)) - allSuccess = false - } else { - component.SuccessPrint(fmt.Sprintf("%s connected successfully", check.name)) + for index, check := range checks { + if !check.flag { + err = check.function() + if err != nil { + component.ErrorPrint(fmt.Sprintf("Starting %s failed:%v.", check.name, err)) + allSuccess = false + + } else { + checks[index].flag = true + component.SuccessPrint(fmt.Sprintf("%s connected successfully", check.name)) + } } } @@ -120,7 +126,7 @@ func checkMinio() error { // Check if MinIO is enabled if config.Config.Object.Enable != "minio" { - return nil + return errs.Wrap(errors.New("minio.Enable is empty")) } minio := &component.Minio{ ApiURL: config.Config.Object.ApiURL, @@ -130,7 +136,7 @@ func checkMinio() error { SignEndpoint: config.Config.Object.Minio.SignEndpoint, UseSSL: getEnv("MINIO_USE_SSL", "false"), } - _, err := component.CheckMinio(minio) + err := component.CheckMinio(minio) return err } @@ -149,7 +155,7 @@ func checkKafka() error { Addr: config.Config.Kafka.Addr, } - _, kafkaClient, err := component.CheckKafka(kafkaStu) + kafkaClient, err := component.CheckKafka(kafkaStu) if err != nil { return err } diff --git a/tools/ncpu/ncpu.go b/tools/ncpu/ncpu.go index 7ca3dff5e5..ca2409a6fe 100644 --- a/tools/ncpu/ncpu.go +++ b/tools/ncpu/ncpu.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 main import ( @@ -22,6 +8,11 @@ import ( ) func main() { - maxprocs.Set() - fmt.Print(runtime.GOMAXPROCS(0)) + // Set maxprocs with a custom logger that does nothing to ignore logs. + maxprocs.Set(maxprocs.Logger(func(string, ...interface{}) { + // Intentionally left blank to suppress all log output from automaxprocs. + })) + + // Now this will print the GOMAXPROCS value without printing the automaxprocs log message. + fmt.Println(runtime.GOMAXPROCS(0)) } From 8729f90d0293347763b57961b9aeb8a1f14e855f Mon Sep 17 00:00:00 2001 From: OpenIM Bot <124379614+kubbot@users.noreply.github.com> Date: Sun, 4 Feb 2024 10:40:26 +0800 Subject: [PATCH 025/188] cicd: bump League Patch (#1874) --- cmd/openim-api/main.go | 4 +++- cmd/openim-cmdutils/main.go | 3 ++- cmd/openim-crontask/main.go | 3 ++- cmd/openim-msggateway/main.go | 3 ++- cmd/openim-msgtransfer/main.go | 3 ++- cmd/openim-push/main.go | 3 ++- cmd/openim-rpc/openim-rpc-auth/main.go | 3 ++- cmd/openim-rpc/openim-rpc-conversation/main.go | 3 ++- cmd/openim-rpc/openim-rpc-friend/main.go | 3 ++- cmd/openim-rpc/openim-rpc-group/main.go | 3 ++- cmd/openim-rpc/openim-rpc-msg/main.go | 3 ++- cmd/openim-rpc/openim-rpc-third/main.go | 3 ++- cmd/openim-rpc/openim-rpc-user/main.go | 3 ++- go.mod | 1 - go.sum | 3 --- internal/msgtransfer/init.go | 3 ++- internal/tools/cron_task.go | 3 ++- pkg/common/db/mgo/conversation.go | 3 ++- pkg/common/db/mgo/group.go | 3 ++- pkg/common/db/mgo/group_member.go | 1 + pkg/common/db/mgo/group_request.go | 1 + pkg/common/db/unrelation/mongo.go | 1 + .../discoveryregister/zookeeper/zookeeper.go | 3 ++- pkg/common/kafka/consumer_group.go | 3 ++- pkg/common/kafka/producer.go | 3 ++- tools/component/component.go | 8 +++++--- tools/ncpu/ncpu.go | 14 ++++++++++++++ 27 files changed, 63 insertions(+), 27 deletions(-) diff --git a/cmd/openim-api/main.go b/cmd/openim-api/main.go index 755b355916..a45bcbdd82 100644 --- a/cmd/openim-api/main.go +++ b/cmd/openim-api/main.go @@ -17,7 +17,6 @@ package main import ( "context" "fmt" - "github.com/OpenIMSDK/tools/errs" "net" "net/http" _ "net/http/pprof" @@ -27,8 +26,11 @@ import ( "syscall" "time" + "github.com/OpenIMSDK/tools/errs" + "github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/tools/discoveryregistry" + "github.com/openimsdk/open-im-server/v3/internal/api" "github.com/openimsdk/open-im-server/v3/pkg/common/cmd" "github.com/openimsdk/open-im-server/v3/pkg/common/config" diff --git a/cmd/openim-cmdutils/main.go b/cmd/openim-cmdutils/main.go index a13bc4f338..45b324766f 100644 --- a/cmd/openim-cmdutils/main.go +++ b/cmd/openim-cmdutils/main.go @@ -16,8 +16,9 @@ package main import ( "fmt" - "github.com/openimsdk/open-im-server/v3/pkg/common/cmd" "os" + + "github.com/openimsdk/open-im-server/v3/pkg/common/cmd" ) func main() { diff --git a/cmd/openim-crontask/main.go b/cmd/openim-crontask/main.go index 5061c54088..324001690a 100644 --- a/cmd/openim-crontask/main.go +++ b/cmd/openim-crontask/main.go @@ -16,9 +16,10 @@ package main import ( "fmt" + "os" + "github.com/openimsdk/open-im-server/v3/internal/tools" "github.com/openimsdk/open-im-server/v3/pkg/common/cmd" - "os" ) func main() { diff --git a/cmd/openim-msggateway/main.go b/cmd/openim-msggateway/main.go index 25cfe5fa87..5339891c88 100644 --- a/cmd/openim-msggateway/main.go +++ b/cmd/openim-msggateway/main.go @@ -16,8 +16,9 @@ package main import ( "fmt" - "github.com/openimsdk/open-im-server/v3/pkg/common/cmd" "os" + + "github.com/openimsdk/open-im-server/v3/pkg/common/cmd" ) func main() { diff --git a/cmd/openim-msgtransfer/main.go b/cmd/openim-msgtransfer/main.go index e3c2f374f2..cf1b44a55f 100644 --- a/cmd/openim-msgtransfer/main.go +++ b/cmd/openim-msgtransfer/main.go @@ -16,8 +16,9 @@ package main import ( "fmt" - "github.com/openimsdk/open-im-server/v3/pkg/common/cmd" "os" + + "github.com/openimsdk/open-im-server/v3/pkg/common/cmd" ) func main() { diff --git a/cmd/openim-push/main.go b/cmd/openim-push/main.go index 79152f9453..77f75cb4e2 100644 --- a/cmd/openim-push/main.go +++ b/cmd/openim-push/main.go @@ -16,10 +16,11 @@ package main import ( "fmt" + "os" + "github.com/openimsdk/open-im-server/v3/internal/push" "github.com/openimsdk/open-im-server/v3/pkg/common/cmd" "github.com/openimsdk/open-im-server/v3/pkg/common/config" - "os" ) func main() { diff --git a/cmd/openim-rpc/openim-rpc-auth/main.go b/cmd/openim-rpc/openim-rpc-auth/main.go index 8ee7053f3f..b29efd484f 100644 --- a/cmd/openim-rpc/openim-rpc-auth/main.go +++ b/cmd/openim-rpc/openim-rpc-auth/main.go @@ -16,10 +16,11 @@ package main import ( "fmt" + "os" + "github.com/openimsdk/open-im-server/v3/internal/rpc/auth" "github.com/openimsdk/open-im-server/v3/pkg/common/cmd" "github.com/openimsdk/open-im-server/v3/pkg/common/config" - "os" ) func main() { diff --git a/cmd/openim-rpc/openim-rpc-conversation/main.go b/cmd/openim-rpc/openim-rpc-conversation/main.go index 259d79abf3..f9ac8cd279 100644 --- a/cmd/openim-rpc/openim-rpc-conversation/main.go +++ b/cmd/openim-rpc/openim-rpc-conversation/main.go @@ -16,10 +16,11 @@ package main import ( "fmt" + "os" + "github.com/openimsdk/open-im-server/v3/internal/rpc/conversation" "github.com/openimsdk/open-im-server/v3/pkg/common/cmd" "github.com/openimsdk/open-im-server/v3/pkg/common/config" - "os" ) func main() { diff --git a/cmd/openim-rpc/openim-rpc-friend/main.go b/cmd/openim-rpc/openim-rpc-friend/main.go index bd85da7b09..82d71d522f 100644 --- a/cmd/openim-rpc/openim-rpc-friend/main.go +++ b/cmd/openim-rpc/openim-rpc-friend/main.go @@ -16,10 +16,11 @@ package main import ( "fmt" + "os" + "github.com/openimsdk/open-im-server/v3/internal/rpc/friend" "github.com/openimsdk/open-im-server/v3/pkg/common/cmd" "github.com/openimsdk/open-im-server/v3/pkg/common/config" - "os" ) func main() { diff --git a/cmd/openim-rpc/openim-rpc-group/main.go b/cmd/openim-rpc/openim-rpc-group/main.go index e40c04d19d..360042f849 100644 --- a/cmd/openim-rpc/openim-rpc-group/main.go +++ b/cmd/openim-rpc/openim-rpc-group/main.go @@ -16,10 +16,11 @@ package main import ( "fmt" + "os" + "github.com/openimsdk/open-im-server/v3/internal/rpc/group" "github.com/openimsdk/open-im-server/v3/pkg/common/cmd" "github.com/openimsdk/open-im-server/v3/pkg/common/config" - "os" ) func main() { diff --git a/cmd/openim-rpc/openim-rpc-msg/main.go b/cmd/openim-rpc/openim-rpc-msg/main.go index 989746dc7f..bed57f5224 100644 --- a/cmd/openim-rpc/openim-rpc-msg/main.go +++ b/cmd/openim-rpc/openim-rpc-msg/main.go @@ -16,10 +16,11 @@ package main import ( "fmt" + "os" + "github.com/openimsdk/open-im-server/v3/internal/rpc/msg" "github.com/openimsdk/open-im-server/v3/pkg/common/cmd" "github.com/openimsdk/open-im-server/v3/pkg/common/config" - "os" ) func main() { diff --git a/cmd/openim-rpc/openim-rpc-third/main.go b/cmd/openim-rpc/openim-rpc-third/main.go index fbd3869468..4868ce149e 100644 --- a/cmd/openim-rpc/openim-rpc-third/main.go +++ b/cmd/openim-rpc/openim-rpc-third/main.go @@ -16,10 +16,11 @@ package main import ( "fmt" + "os" + "github.com/openimsdk/open-im-server/v3/internal/rpc/third" "github.com/openimsdk/open-im-server/v3/pkg/common/cmd" "github.com/openimsdk/open-im-server/v3/pkg/common/config" - "os" ) func main() { diff --git a/cmd/openim-rpc/openim-rpc-user/main.go b/cmd/openim-rpc/openim-rpc-user/main.go index 160bbe311e..a77a2f768d 100644 --- a/cmd/openim-rpc/openim-rpc-user/main.go +++ b/cmd/openim-rpc/openim-rpc-user/main.go @@ -16,10 +16,11 @@ package main import ( "fmt" + "os" + "github.com/openimsdk/open-im-server/v3/internal/rpc/user" "github.com/openimsdk/open-im-server/v3/pkg/common/cmd" "github.com/openimsdk/open-im-server/v3/pkg/common/config" - "os" ) func main() { diff --git a/go.mod b/go.mod index d82d3390b6..3da7c3ecde 100644 --- a/go.mod +++ b/go.mod @@ -41,7 +41,6 @@ require ( github.com/spf13/pflag v1.0.5 github.com/stathat/consistent v1.0.0 github.com/tencentyun/cos-go-sdk-v5 v0.7.45 - go.uber.org/automaxprocs v1.5.3 golang.org/x/sync v0.4.0 gopkg.in/src-d/go-git.v4 v4.13.1 gotest.tools v2.2.0+incompatible diff --git a/go.sum b/go.sum index fb047dfdc4..84620fe7dd 100644 --- a/go.sum +++ b/go.sum @@ -277,7 +277,6 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g= github.com/prometheus/client_golang v1.17.0 h1:rl2sfwZMtSthVU752MqfjQozy7blglC+1SOtjMAMh+Q= github.com/prometheus/client_golang v1.17.0/go.mod h1:VeL+gMmOAxkS2IqfCq0ZmHSL+LjWfWDUmp1mBz9JgUY= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= @@ -352,8 +351,6 @@ go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/automaxprocs v1.5.3 h1:kWazyxZUrS3Gs4qUpbwo5kEIMGe/DAvi5Z4tl2NW4j8= -go.uber.org/automaxprocs v1.5.3/go.mod h1:eRbA25aqJrxAbsLO0xy5jVwPt7FQnRgjW+efnwa1WM0= go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= diff --git a/internal/msgtransfer/init.go b/internal/msgtransfer/init.go index 969761a9d6..83ec00749b 100644 --- a/internal/msgtransfer/init.go +++ b/internal/msgtransfer/init.go @@ -18,11 +18,12 @@ import ( "context" "errors" "fmt" - "github.com/OpenIMSDK/tools/errs" "log" "net/http" "sync" + "github.com/OpenIMSDK/tools/errs" + "github.com/OpenIMSDK/tools/mw" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/collectors" diff --git a/internal/tools/cron_task.go b/internal/tools/cron_task.go index cf2068d8ec..40e1c0a874 100644 --- a/internal/tools/cron_task.go +++ b/internal/tools/cron_task.go @@ -17,12 +17,13 @@ package tools import ( "context" "fmt" - "github.com/OpenIMSDK/tools/errs" "os" "os/signal" "syscall" "time" + "github.com/OpenIMSDK/tools/errs" + "github.com/redis/go-redis/v9" "github.com/robfig/cron/v3" diff --git a/pkg/common/db/mgo/conversation.go b/pkg/common/db/mgo/conversation.go index 0b8d597dcf..d0a46ae47c 100644 --- a/pkg/common/db/mgo/conversation.go +++ b/pkg/common/db/mgo/conversation.go @@ -16,9 +16,10 @@ package mgo import ( "context" - "github.com/OpenIMSDK/tools/errs" "time" + "github.com/OpenIMSDK/tools/errs" + "github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/tools/mgoutil" "github.com/OpenIMSDK/tools/pagination" diff --git a/pkg/common/db/mgo/group.go b/pkg/common/db/mgo/group.go index 9a4c660a60..922bfd4240 100644 --- a/pkg/common/db/mgo/group.go +++ b/pkg/common/db/mgo/group.go @@ -16,9 +16,10 @@ package mgo import ( "context" - "github.com/OpenIMSDK/tools/errs" "time" + "github.com/OpenIMSDK/tools/errs" + "github.com/OpenIMSDK/tools/mgoutil" "github.com/OpenIMSDK/tools/pagination" "go.mongodb.org/mongo-driver/bson" diff --git a/pkg/common/db/mgo/group_member.go b/pkg/common/db/mgo/group_member.go index fce79830e2..e28432b118 100644 --- a/pkg/common/db/mgo/group_member.go +++ b/pkg/common/db/mgo/group_member.go @@ -16,6 +16,7 @@ package mgo import ( "context" + "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/protocol/constant" diff --git a/pkg/common/db/mgo/group_request.go b/pkg/common/db/mgo/group_request.go index dce0878ee7..d206822399 100644 --- a/pkg/common/db/mgo/group_request.go +++ b/pkg/common/db/mgo/group_request.go @@ -16,6 +16,7 @@ package mgo import ( "context" + "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/mgoutil" diff --git a/pkg/common/db/unrelation/mongo.go b/pkg/common/db/unrelation/mongo.go index 2bade9a624..4c093b3c36 100644 --- a/pkg/common/db/unrelation/mongo.go +++ b/pkg/common/db/unrelation/mongo.go @@ -27,6 +27,7 @@ import ( "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/mw/specialerror" + "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/unrelation" ) diff --git a/pkg/common/discoveryregister/zookeeper/zookeeper.go b/pkg/common/discoveryregister/zookeeper/zookeeper.go index 9c58807c1d..6e55b6b8b4 100644 --- a/pkg/common/discoveryregister/zookeeper/zookeeper.go +++ b/pkg/common/discoveryregister/zookeeper/zookeeper.go @@ -16,11 +16,12 @@ package zookeeper import ( "fmt" - "github.com/OpenIMSDK/tools/errs" "os" "strings" "time" + "github.com/OpenIMSDK/tools/errs" + "github.com/OpenIMSDK/tools/discoveryregistry" openkeeper "github.com/OpenIMSDK/tools/discoveryregistry/zookeeper" "github.com/OpenIMSDK/tools/log" diff --git a/pkg/common/kafka/consumer_group.go b/pkg/common/kafka/consumer_group.go index 87e6d56866..6e6f83fcaa 100644 --- a/pkg/common/kafka/consumer_group.go +++ b/pkg/common/kafka/consumer_group.go @@ -16,9 +16,10 @@ package kafka import ( "context" - "github.com/OpenIMSDK/tools/errs" "strings" + "github.com/OpenIMSDK/tools/errs" + "github.com/OpenIMSDK/tools/log" "github.com/openimsdk/open-im-server/v3/pkg/common/config" diff --git a/pkg/common/kafka/producer.go b/pkg/common/kafka/producer.go index b9f0b46568..417aadb542 100644 --- a/pkg/common/kafka/producer.go +++ b/pkg/common/kafka/producer.go @@ -18,10 +18,11 @@ import ( "bytes" "context" "errors" - "github.com/OpenIMSDK/tools/errs" "strings" "time" + "github.com/OpenIMSDK/tools/errs" + "github.com/IBM/sarama" "github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/tools/log" diff --git a/tools/component/component.go b/tools/component/component.go index bd60070157..6b879d7f8b 100644 --- a/tools/component/component.go +++ b/tools/component/component.go @@ -18,14 +18,16 @@ import ( "errors" "flag" "fmt" + "os" + "strings" + "time" + "github.com/IBM/sarama" + "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" "github.com/openimsdk/open-im-server/v3/pkg/common/db/unrelation" "github.com/openimsdk/open-im-server/v3/pkg/common/discoveryregister/zookeeper" "github.com/openimsdk/open-im-server/v3/pkg/common/kafka" - "os" - "strings" - "time" "github.com/OpenIMSDK/tools/component" "github.com/OpenIMSDK/tools/errs" diff --git a/tools/ncpu/ncpu.go b/tools/ncpu/ncpu.go index ca2409a6fe..062618b279 100644 --- a/tools/ncpu/ncpu.go +++ b/tools/ncpu/ncpu.go @@ -1,3 +1,17 @@ +// 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 main import ( From 9610da9123fea0fb3954553be7ebd138a7beb8d7 Mon Sep 17 00:00:00 2001 From: Xinwei Xiong <3293172751NSS@gmail.com> Date: Sun, 4 Feb 2024 20:05:53 +0800 Subject: [PATCH 026/188] fix(main): fix openim scripts start rpc log (#1877) * Update start.go * Update start.go --- pkg/common/startrpc/start.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/common/startrpc/start.go b/pkg/common/startrpc/start.go index f7b5478345..f6cda2ffb3 100644 --- a/pkg/common/startrpc/start.go +++ b/pkg/common/startrpc/start.go @@ -17,7 +17,6 @@ package startrpc import ( "errors" "fmt" - "log" "net" "net/http" "os" @@ -117,7 +116,8 @@ func Start( // Create a HTTP server for prometheus. httpServer := &http.Server{Handler: promhttp.HandlerFor(reg, promhttp.HandlerOpts{}), Addr: fmt.Sprintf("0.0.0.0:%d", prometheusPort)} if err := httpServer.ListenAndServe(); err != nil { - log.Fatal("Unable to start a http server. ", err.Error(), "PrometheusPort:", prometheusPort) + fmt.Fprintf(os.Stderr, "\n\nexit -1: \n%+v PrometheusPort: %d \n\n", err, prometheusPort) + os.Exit(-1) } } return nil From 311d42283b2a0a022f8827fb0927ca30601fbb73 Mon Sep 17 00:00:00 2001 From: Xinwei Xiong <3293172751NSS@gmail.com> Date: Sun, 4 Feb 2024 20:06:34 +0800 Subject: [PATCH 027/188] feat: fix openim logs and ci (#1878) --- scripts/lib/logging.sh | 14 +++++++++++--- scripts/lib/util.sh | 4 ---- scripts/start-all.sh | 2 +- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/scripts/lib/logging.sh b/scripts/lib/logging.sh index 2fa77dd83c..8f2bb33cf7 100755 --- a/scripts/lib/logging.sh +++ b/scripts/lib/logging.sh @@ -131,16 +131,24 @@ openim::log::error_exit() { exit "${code}" } -# Log an error but keep going. Don't dump the stack or exit. +# Log an error but keep going. Don't dump the stack or exit. openim::log::error() { + # Define red color + red='\033[0;31m' + # No color (reset) + nc='\033[0m' # No Color + timestamp=$(date +"[%Y-%m-%d %H:%M:%S %Z]") - echo_log "!!! ${timestamp} ${1-}" >&2 + # Apply red color for error message + echo_log "${red}!!! ${timestamp} ${1-}${nc}" >&2 shift for message; do - echo_log " ${message}" >&2 + # Apply red color for subsequent lines of the error message + echo_log "${red} ${message}${nc}" >&2 done } + # Print an usage message to stderr. The arguments are printed directly. openim::log::usage() { echo_log >&2 diff --git a/scripts/lib/util.sh b/scripts/lib/util.sh index b93f45205b..eaefaf22ad 100755 --- a/scripts/lib/util.sh +++ b/scripts/lib/util.sh @@ -1541,12 +1541,8 @@ openim::util::check_ports() { if [[ "$OSTYPE" == "linux-gnu"* ]]; then if command -v ss > /dev/null 2>&1; then info=$(ss -ltnp | grep ":$port" || true) - openim::color::echo $COLOR_RED "!!!!!!!! port=$port" - openim::color::echo $COLOR_RED "!!!!!!!! info=$info" else info=$(netstat -ltnp | grep ":$port" || true) - openim::color::echo $COLOR_RED "!!!!!!!! port=$port" - openim::color::echo $COLOR_RED "!!!!!!!! info=$info" fi elif [[ "$OSTYPE" == "darwin"* ]]; then # For macOS, use lsof diff --git a/scripts/start-all.sh b/scripts/start-all.sh index 5f34cbdbee..ca03f0c3ce 100755 --- a/scripts/start-all.sh +++ b/scripts/start-all.sh @@ -82,4 +82,4 @@ execute_scripts openim::log::info "\n## Post Starting OpenIM services" ${TOOLS_START_SCRIPTS_PATH} openim::tools::post-start -openim::log::success "✨ All OpenIM services have been successfully started!" \ No newline at end of file +openim::color::echo $COLOR_BLUE "✨ All OpenIM services have been successfully started!" \ No newline at end of file From ee245157614af085525b88888daae0c51826276b Mon Sep 17 00:00:00 2001 From: Brabem <69128477+luhaoling@users.noreply.github.com> Date: Sun, 4 Feb 2024 20:13:17 +0800 Subject: [PATCH 028/188] feat: add getUserToken api and add ex field in getSortedConversationListResp (#1880) * fix: del the manager config and manger init statement * fix: fix the Manger judge condition * fix: fix revokeMsg error * fix: find erors * fix: find error * fix: fix the AdminAccount error * fix: del the debug statement * fix: fix the component check func * fix: fix the get zkAddress error * fix: fix the kafka client close error * fix: add env in minio connected * fix: del the minio env * fix: fix the go.mod tools version * fix: del get env in minio conneted * feat: add GetUserToken api and add ex field in GetSortedConversationList resp * fix: fix the go.mod version * fix: add lack method * fix: add a method * fix: add lack implement * fix: fix the tools pkg version * fix: del the unuser pkg * fix: add Limiting judgement of get admin token --- go.mod | 4 +--- go.sum | 4 ++-- internal/api/auth.go | 4 ++++ internal/api/route.go | 1 + internal/rpc/auth/auth.go | 22 ++++++++++++++++++++++ internal/rpc/conversation/conversaion.go | 5 +++++ internal/rpc/group/group.go | 5 +++++ internal/rpc/user/user.go | 5 +++++ pkg/authverify/token.go | 3 +-- 9 files changed, 46 insertions(+), 7 deletions(-) diff --git a/go.mod b/go.mod index 3da7c3ecde..ab138e68cb 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.19 require ( firebase.google.com/go v3.13.0+incompatible - github.com/OpenIMSDK/protocol v0.0.48 + github.com/OpenIMSDK/protocol v0.0.55 github.com/OpenIMSDK/tools v0.0.33 github.com/bwmarrin/snowflake v0.3.0 // indirect github.com/dtm-labs/rockscache v0.1.1 @@ -155,5 +155,3 @@ require ( golang.org/x/crypto v0.17.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect ) - -replace github.com/OpenIMSDK/protocol v0.0.47 => github.com/AndrewZuo01/protocol v0.0.0-20240112093520-fd9c53e27b94 diff --git a/go.sum b/go.sum index 84620fe7dd..94a516366c 100644 --- a/go.sum +++ b/go.sum @@ -18,8 +18,8 @@ firebase.google.com/go v3.13.0+incompatible/go.mod h1:xlah6XbEyW6tbfSklcfe5FHJIw github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/IBM/sarama v1.41.3 h1:MWBEJ12vHC8coMjdEXFq/6ftO6DUZnQlFYcxtOJFa7c= github.com/IBM/sarama v1.41.3/go.mod h1:Xxho9HkHd4K/MDUo/T/sOqwtX/17D33++E9Wib6hUdQ= -github.com/OpenIMSDK/protocol v0.0.48 h1:8MIMjyzJRsruYhVv2ZKArFiOveroaofDOb3dlAdgjsw= -github.com/OpenIMSDK/protocol v0.0.48/go.mod h1:F25dFrwrIx3lkNoiuf6FkCfxuwf8L4Z8UIsdTHP/r0Y= +github.com/OpenIMSDK/protocol v0.0.55 h1:eBjg8DyuhxGmuCUjpoZjg6MJJJXU/xJ3xJwFhrn34yA= +github.com/OpenIMSDK/protocol v0.0.55/go.mod h1:F25dFrwrIx3lkNoiuf6FkCfxuwf8L4Z8UIsdTHP/r0Y= github.com/OpenIMSDK/tools v0.0.33 h1:rvFCxXaXxLv1MJFC4qcoWRGwKBnV+hR68UN2N0/zZhE= github.com/OpenIMSDK/tools v0.0.33/go.mod h1:wBfR5CYmEyvxl03QJbTkhz1CluK6J4/lX0lviu8JAjE= github.com/QcloudApi/qcloud_sign_golang v0.0.0-20141224014652-e4130a326409/go.mod h1:1pk82RBxDY/JZnPQrtqHlUFfCctgdorsd9M06fMynOM= diff --git a/internal/api/auth.go b/internal/api/auth.go index 44a97a013a..88539f63a7 100644 --- a/internal/api/auth.go +++ b/internal/api/auth.go @@ -33,6 +33,10 @@ func (o *AuthApi) UserToken(c *gin.Context) { a2r.Call(auth.AuthClient.UserToken, o.Client, c) } +func (o *AuthApi) GetUserToken(c *gin.Context) { + a2r.Call(auth.AuthClient.GetUserToken, o.Client, c) +} + func (o *AuthApi) ParseToken(c *gin.Context) { a2r.Call(auth.AuthClient.ParseToken, o.Client, c) } diff --git a/internal/api/route.go b/internal/api/route.go index 10907d086d..24ed5f6bb4 100644 --- a/internal/api/route.go +++ b/internal/api/route.go @@ -150,6 +150,7 @@ func NewGinRouter(discov discoveryregistry.SvcDiscoveryRegistry, rdb redis.Unive { a := NewAuthApi(*authRpc) authRouterGroup.POST("/user_token", a.UserToken) + authRouterGroup.POST("/get_user_token", ParseToken, a.GetUserToken) authRouterGroup.POST("/parse_token", a.ParseToken) authRouterGroup.POST("/force_logout", ParseToken, a.ForceLogout) } diff --git a/internal/rpc/auth/auth.go b/internal/rpc/auth/auth.go index ee8ead194d..eaf63f868d 100644 --- a/internal/rpc/auth/auth.go +++ b/internal/rpc/auth/auth.go @@ -80,6 +80,28 @@ func (s *authServer) UserToken(ctx context.Context, req *pbauth.UserTokenReq) (* return &resp, nil } +func (s *authServer) GetUserToken(ctx context.Context, req *pbauth.GetUserTokenReq) (*pbauth.GetUserTokenResp, error) { + if err := authverify.CheckAdmin(ctx); err != nil { + return nil, err + } + resp := pbauth.GetUserTokenResp{} + + if authverify.IsManagerUserID(req.UserID) { + return nil, errs.ErrNoPermission.Wrap("don't get Admin token") + } + + if _, err := s.userRpcClient.GetUserInfo(ctx, req.UserID); err != nil { + return nil, err + } + token, err := s.authDatabase.CreateToken(ctx, req.UserID, int(req.PlatformID)) + if err != nil { + return nil, err + } + resp.Token = token + resp.ExpireTimeSeconds = config.Config.TokenPolicy.Expire * 24 * 60 * 60 + return &resp, nil +} + func (s *authServer) parseToken(ctx context.Context, tokensString string) (claims *tokenverify.Claims, err error) { claims, err = tokenverify.GetClaimFromToken(tokensString, authverify.Secret()) if err != nil { diff --git a/internal/rpc/conversation/conversaion.go b/internal/rpc/conversation/conversaion.go index 40803089ca..3317359e51 100644 --- a/internal/rpc/conversation/conversaion.go +++ b/internal/rpc/conversation/conversaion.go @@ -51,6 +51,11 @@ type conversationServer struct { conversationNotificationSender *notification.ConversationNotificationSender } +func (c *conversationServer) GetConversationNotReceiveMessageUserIDs(ctx context.Context, req *pbconversation.GetConversationNotReceiveMessageUserIDsReq) (*pbconversation.GetConversationNotReceiveMessageUserIDsResp, error) { + //TODO implement me + panic("implement me") +} + func Start(client discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) error { rdb, err := cache.NewRedis() if err != nil { diff --git a/internal/rpc/group/group.go b/internal/rpc/group/group.go index abc271651f..1d068b1b2c 100644 --- a/internal/rpc/group/group.go +++ b/internal/rpc/group/group.go @@ -108,6 +108,11 @@ type groupServer struct { msgRpcClient rpcclient.MessageRpcClient } +func (s *groupServer) GetJoinedGroupIDs(ctx context.Context, req *pbgroup.GetJoinedGroupIDsReq) (*pbgroup.GetJoinedGroupIDsResp, error) { + //TODO implement me + panic("implement me") +} + func (s *groupServer) NotificationUserInfoUpdate(ctx context.Context, req *pbgroup.NotificationUserInfoUpdateReq) (*pbgroup.NotificationUserInfoUpdateResp, error) { defer log.ZDebug(ctx, "NotificationUserInfoUpdate return") members, err := s.db.FindGroupMemberUser(ctx, nil, req.UserID) diff --git a/internal/rpc/user/user.go b/internal/rpc/user/user.go index e5567f436b..6f9e2949f3 100644 --- a/internal/rpc/user/user.go +++ b/internal/rpc/user/user.go @@ -61,6 +61,11 @@ type userServer struct { RegisterCenter registry.SvcDiscoveryRegistry } +func (s *userServer) GetGroupOnlineUser(ctx context.Context, req *pbuser.GetGroupOnlineUserReq) (*pbuser.GetGroupOnlineUserResp, error) { + //TODO implement me + panic("implement me") +} + func Start(client registry.SvcDiscoveryRegistry, server *grpc.Server) error { rdb, err := cache.NewRedis() if err != nil { diff --git a/pkg/authverify/token.go b/pkg/authverify/token.go index 97bb033916..b951bf219c 100644 --- a/pkg/authverify/token.go +++ b/pkg/authverify/token.go @@ -48,8 +48,7 @@ func CheckAccessV3(ctx context.Context, ownerUserID string) (err error) { } func IsAppManagerUid(ctx context.Context) bool { - return (len(config.Config.Manager.UserID) > 0 && utils.IsContain(mcontext.GetOpUserID(ctx), config.Config.Manager.UserID)) || - utils.IsContain(mcontext.GetOpUserID(ctx), config.Config.IMAdmin.UserID) + return (len(config.Config.Manager.UserID) > 0 && utils.IsContain(mcontext.GetOpUserID(ctx), config.Config.Manager.UserID)) || utils.IsContain(mcontext.GetOpUserID(ctx), config.Config.IMAdmin.UserID) } func CheckAdmin(ctx context.Context) error { From 0865eb65b1eaed0b5a699c8571255b3fd6fb09a3 Mon Sep 17 00:00:00 2001 From: Xinwei Xiong <3293172751NSS@gmail.com> Date: Mon, 5 Feb 2024 10:08:55 +0800 Subject: [PATCH 029/188] fix: kill 10 process optimization (#1883) --- scripts/lib/util.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/lib/util.sh b/scripts/lib/util.sh index eaefaf22ad..cace536456 100755 --- a/scripts/lib/util.sh +++ b/scripts/lib/util.sh @@ -486,7 +486,7 @@ openim::util::stop_services_on_ports() { local pid=$(echo $line | awk '{print $2}') # Try to stop the service by killing its process. - if kill -TERM $pid; then + if kill -10 $pid; then stopped+=($port) else not_stopped+=($port) @@ -563,7 +563,7 @@ openim::util::stop_services_with_name() { # If there's a Process ID, it means the service with the name is running. if [[ -n $pid ]]; then # Try to stop the service by killing its process. - if kill -TERM $pid 2>/dev/null; then + if kill -10 $pid 2>/dev/null; then stopped_this_time=true fi fi @@ -1722,7 +1722,7 @@ openim::util::stop_services_on_ports() { local pid=$(echo $line | awk '{print $2}') # Try to stop the service by killing its process. - if kill -TERM $pid; then + if kill -10 $pid; then stopped+=($port) else not_stopped+=($port) @@ -1799,7 +1799,7 @@ openim::util::stop_services_with_name() { # If there's a Process ID, it means the service with the name is running. if [[ -n $pid ]]; then # Try to stop the service by killing its process. - if kill -TERM $pid 2>/dev/null; then + if kill -10 $pid 2>/dev/null; then stopped_this_time=true fi fi From 31381935f188210bc905d8cbe5c0959b8584fb61 Mon Sep 17 00:00:00 2001 From: "fengyun.rui" Date: Mon, 5 Feb 2024 10:37:53 +0800 Subject: [PATCH 030/188] fix: graceful exit for kafka consumer of msgtransfer (#1483) * fix: graceful exit for kafka consumer of msgtransfer Signed-off-by: rfyiamcool * Update init.go * Update init.go --------- Signed-off-by: rfyiamcool Co-authored-by: OpenIM-Gordon <46924906+FGadvancer@users.noreply.github.com> --- internal/msgtransfer/init.go | 74 +++++++++++++++---- .../msgtransfer/online_history_msg_handler.go | 58 +++++++++++---- pkg/common/kafka/consumer_group.go | 27 +++++-- 3 files changed, 124 insertions(+), 35 deletions(-) diff --git a/internal/msgtransfer/init.go b/internal/msgtransfer/init.go index 83ec00749b..65a6b1935f 100644 --- a/internal/msgtransfer/init.go +++ b/internal/msgtransfer/init.go @@ -18,7 +18,10 @@ import ( "context" "errors" "fmt" - "log" + "os" + "os/signal" + "syscall" + "time" "net/http" "sync" @@ -30,7 +33,7 @@ import ( "github.com/prometheus/client_golang/prometheus/promhttp" "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" - + "github.com/OpenIMSDK/tools/log" "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" @@ -51,11 +54,13 @@ func StartTransfer(prometheusPort int) error { if err != nil { return err } + mongo, err := unrelation.NewMongo() if err != nil { return err } - if err := mongo.CreateMsgIndex(); err != nil { + + if err = mongo.CreateMsgIndex(); err != nil { return err } client, err := kdisc.NewDiscoveryRegister(config.Config.Envs.Discovery) @@ -66,6 +71,7 @@ func StartTransfer(prometheusPort int) error { if err != nil { return err } + if err := client.CreateRpcRootNodes(config.Config.GetServiceNames()); err != nil { return err } @@ -103,26 +109,62 @@ func NewMsgTransfer(msgDatabase controller.CommonMsgDatabase, conversationRpcCli func (m *MsgTransfer) Start(prometheusPort int) error { ctx := context.Background() - var wg sync.WaitGroup - wg.Add(1) fmt.Println("start msg transfer", "prometheusPort:", prometheusPort) if prometheusPort <= 0 { return errs.Wrap(errors.New("prometheusPort not correct")) } - go m.historyCH.historyConsumerGroup.RegisterHandleAndConsumer(ctx, m.historyCH) - go m.historyMongoCH.historyConsumerGroup.RegisterHandleAndConsumer(ctx, m.historyMongoCH) + var wg sync.WaitGroup + + wg.Add(1) + go func() { + defer wg.Done() + + m.historyCH.historyConsumerGroup.RegisterHandleAndConsumer(ctx, m.historyCH) + }() + + wg.Add(1) + go func() { + defer wg.Done() + + m.historyMongoCH.historyConsumerGroup.RegisterHandleAndConsumer(ctx, m.historyMongoCH) + }() if config.Config.Prometheus.Enable { - reg := prometheus.NewRegistry() - reg.MustRegister( - collectors.NewGoCollector(), - ) - reg.MustRegister(prommetrics.GetGrpcCusMetrics("Transfer")...) - http.Handle("/metrics", promhttp.HandlerFor(reg, promhttp.HandlerOpts{Registry: reg})) - log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", prometheusPort), nil)) + go func() { + proreg := prometheus.NewRegistry() + proreg.MustRegister( + collectors.NewGoCollector(), + ) + proreg.MustRegister(prommetrics.GetGrpcCusMetrics("Transfer")...) + http.Handle("/metrics", promhttp.HandlerFor(proreg, promhttp.HandlerOpts{Registry: proreg})) + err := http.ListenAndServe(fmt.Sprintf(":%d", prometheusPort), nil) + if err != nil && err != http.ErrServerClosed { + panic(err) + } + }() } - //////////////////////////////////////// - wg.Wait() + + sigs := make(chan os.Signal, 1) + signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT) + <-sigs + + // graceful close kafka client. + go m.historyCH.historyConsumerGroup.Close() + go m.historyMongoCH.historyConsumerGroup.Close() + + done := make(chan struct{}, 1) + go func() { + wg.Wait() + close(done) + }() + + select { + case <-done: + log.ZInfo(context.Background(), "msgtrasfer exit successfully") + case <-time.After(15 * time.Second): + log.ZError(context.Background(), "msgtransfer force to exit, timeout 15s", nil) + } + return nil } diff --git a/internal/msgtransfer/online_history_msg_handler.go b/internal/msgtransfer/online_history_msg_handler.go index 35af330c95..6678715d4b 100644 --- a/internal/msgtransfer/online_history_msg_handler.go +++ b/internal/msgtransfer/online_history_msg_handler.go @@ -19,6 +19,7 @@ import ( "strconv" "strings" "sync" + "sync/atomic" "time" "github.com/openimsdk/open-im-server/v3/pkg/msgprocessor" @@ -431,16 +432,29 @@ func (och *OnlineHistoryRedisConsumerHandler) ConsumeClaim( log.ZDebug(context.Background(), "online new session msg come", "highWaterMarkOffset", claim.HighWaterMarkOffset(), "topic", claim.Topic(), "partition", claim.Partition()) - split := 1000 - rwLock := new(sync.RWMutex) - messages := make([]*sarama.ConsumerMessage, 0, 1000) - ticker := time.NewTicker(time.Millisecond * 100) + var ( + split = 1000 + rwLock = new(sync.RWMutex) + messages = make([]*sarama.ConsumerMessage, 0, 1000) + ticker = time.NewTicker(time.Millisecond * 100) + wg = sync.WaitGroup{} + running = new(atomic.Bool) + ) + + wg.Add(1) go func() { + defer wg.Done() + for { select { case <-ticker.C: + // if the buffer is empty and running is false, return loop. if len(messages) == 0 { + if !running.Load() { + return + } + continue } @@ -473,17 +487,35 @@ func (och *OnlineHistoryRedisConsumerHandler) ConsumeClaim( } }() - for msg := range claim.Messages() { - if len(msg.Value) == 0 { - continue - } + wg.Add(1) + go func() { + defer wg.Done() - rwLock.Lock() - messages = append(messages, msg) - rwLock.Unlock() + for running.Load() { + select { + case msg, ok := <-claim.Messages(): + if !ok { + running.Store(false) + return + } - sess.MarkMessage(msg, "") - } + if len(msg.Value) == 0 { + continue + } + + rwLock.Lock() + messages = append(messages, msg) + rwLock.Unlock() + + sess.MarkMessage(msg, "") + + case <-sess.Context().Done(): + running.Store(false) + return + } + } + }() + wg.Wait() return nil } diff --git a/pkg/common/kafka/consumer_group.go b/pkg/common/kafka/consumer_group.go index 6e6f83fcaa..3f444cc1f2 100644 --- a/pkg/common/kafka/consumer_group.go +++ b/pkg/common/kafka/consumer_group.go @@ -16,18 +16,18 @@ package kafka import ( "context" + "errors" + "github.com/IBM/sarama" "strings" - "github.com/OpenIMSDK/tools/errs" - "github.com/OpenIMSDK/tools/log" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" - - "github.com/IBM/sarama" ) type MConsumerGroup struct { + ctx context.Context + cancel context.CancelFunc + sarama.ConsumerGroup groupID string topics []string @@ -54,7 +54,10 @@ func NewMConsumerGroup(consumerConfig *MConsumerGroupConfig, topics, addrs []str if err != nil { return nil, errs.Wrap(err, strings.Join(topics, ","), strings.Join(addrs, ","), groupID, config.Config.Kafka.Username, config.Config.Kafka.Password) } + + ctx, cancel := context.WithCancel(context.Background()) return &MConsumerGroup{ + ctx, cancel, consumerGroup, groupID, topics, @@ -68,7 +71,14 @@ func (mc *MConsumerGroup) GetContextFromMsg(cMsg *sarama.ConsumerMessage) contex func (mc *MConsumerGroup) RegisterHandleAndConsumer(ctx context.Context, handler sarama.ConsumerGroupHandler) { log.ZDebug(context.Background(), "register consumer group", "groupID", mc.groupID) for { - err := mc.ConsumerGroup.Consume(ctx, mc.topics, handler) + err := mc.ConsumerGroup.Consume(mc.ctx, mc.topics, handler) + if errors.Is(err, sarama.ErrClosedConsumerGroup) { + return + } + if mc.ctx.Err() != nil { + return + } + if err != nil { log.ZWarn(ctx, "consume err", err, "topic", mc.topics, "groupID", mc.groupID) } @@ -77,3 +87,8 @@ func (mc *MConsumerGroup) RegisterHandleAndConsumer(ctx context.Context, handler } } } + +func (mc *MConsumerGroup) Close() { + mc.cancel() + mc.ConsumerGroup.Close() +} From 6c7b94f03f271451e7e7348ab998928deb17861a Mon Sep 17 00:00:00 2001 From: OpenIM Bot <124379614+kubbot@users.noreply.github.com> Date: Mon, 5 Feb 2024 17:45:45 +0800 Subject: [PATCH 031/188] =?UTF-8?q?[Auto=20PR=20=F0=9F=A4=96]=20Bump=20Lea?= =?UTF-8?q?gue=20Patch=20auto=20PR=20(#1884)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * cicd: bump League Patch * Update project-progress.yml --------- Co-authored-by: Xinwei Xiong <3293172751NSS@gmail.com> --- .github/workflows/project-progress.yml | 5 ++++- internal/rpc/conversation/conversaion.go | 5 ++++- pkg/authverify/token.go | 3 ++- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/.github/workflows/project-progress.yml b/.github/workflows/project-progress.yml index 3ec8b7b1f8..0b071b3a8e 100644 --- a/.github/workflows/project-progress.yml +++ b/.github/workflows/project-progress.yml @@ -24,6 +24,9 @@ on: pull_request: types: - assigned + branches-ignore: + - 'asf-auto-updates' + - 'ignore' jobs: move-assigned-card: @@ -33,4 +36,4 @@ jobs: with: project: openim-powerful column: In Progress - repo-token: ${{ secrets.BOT_GITHUB_TOKEN }} \ No newline at end of file + repo-token: ${{ secrets.BOT_GITHUB_TOKEN }} diff --git a/internal/rpc/conversation/conversaion.go b/internal/rpc/conversation/conversaion.go index 3317359e51..8558a23ea4 100644 --- a/internal/rpc/conversation/conversaion.go +++ b/internal/rpc/conversation/conversaion.go @@ -51,7 +51,10 @@ type conversationServer struct { conversationNotificationSender *notification.ConversationNotificationSender } -func (c *conversationServer) GetConversationNotReceiveMessageUserIDs(ctx context.Context, req *pbconversation.GetConversationNotReceiveMessageUserIDsReq) (*pbconversation.GetConversationNotReceiveMessageUserIDsResp, error) { +func (c *conversationServer) GetConversationNotReceiveMessageUserIDs( + ctx context.Context, + req *pbconversation.GetConversationNotReceiveMessageUserIDsReq, +) (*pbconversation.GetConversationNotReceiveMessageUserIDsResp, error) { //TODO implement me panic("implement me") } diff --git a/pkg/authverify/token.go b/pkg/authverify/token.go index b951bf219c..97bb033916 100644 --- a/pkg/authverify/token.go +++ b/pkg/authverify/token.go @@ -48,7 +48,8 @@ func CheckAccessV3(ctx context.Context, ownerUserID string) (err error) { } func IsAppManagerUid(ctx context.Context) bool { - return (len(config.Config.Manager.UserID) > 0 && utils.IsContain(mcontext.GetOpUserID(ctx), config.Config.Manager.UserID)) || utils.IsContain(mcontext.GetOpUserID(ctx), config.Config.IMAdmin.UserID) + return (len(config.Config.Manager.UserID) > 0 && utils.IsContain(mcontext.GetOpUserID(ctx), config.Config.Manager.UserID)) || + utils.IsContain(mcontext.GetOpUserID(ctx), config.Config.IMAdmin.UserID) } func CheckAdmin(ctx context.Context) error { From 7862fa50038e4c4737f1ca50a0aa9b77da3b842f Mon Sep 17 00:00:00 2001 From: xuan <146319162+wxuanF@users.noreply.github.com> Date: Tue, 6 Feb 2024 14:11:27 +0800 Subject: [PATCH 032/188] docs: add README.md JP (#1891) * docs: README JP Signed-off-by: wxuanF <2569456943@qq.com> * Update openimci.yml * Update golangci-lint.yml * docs: README JP Signed-off-by: wxuanF <2569456943@qq.com> * docs: README JP Signed-off-by: wxuanF <2569456943@qq.com> * docs: README JP Signed-off-by: wxuanF <2569456943@qq.com> --------- Signed-off-by: wxuanF <2569456943@qq.com> Co-authored-by: Xinwei Xiong <3293172751NSS@gmail.com> --- .github/workflows/golangci-lint.yml | 4 +- .github/workflows/openimci.yml | 3 - docs/readme/README-JP.md | 190 ++++++++++++++++++++++++++++ 3 files changed, 193 insertions(+), 4 deletions(-) create mode 100644 docs/readme/README-JP.md diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml index 67dc5a6b8e..250cb96cb1 100644 --- a/.github/workflows/golangci-lint.yml +++ b/.github/workflows/golangci-lint.yml @@ -28,6 +28,8 @@ jobs: with: go-version: '1.21' cache: false + - name: OpenIM Scripts Verification(make verify) + run: sudo make verify - name: golangci-lint uses: golangci/golangci-lint-action@v3.7.0 with: @@ -47,4 +49,4 @@ jobs: only-new-issues: true # Optional:The mode to install golangci-lint. It can be 'binary' or 'goinstall'. - # install-mode: "goinstall" \ No newline at end of file + # install-mode: "goinstall" diff --git a/.github/workflows/openimci.yml b/.github/workflows/openimci.yml index 8aa38d941c..2d42e31555 100644 --- a/.github/workflows/openimci.yml +++ b/.github/workflows/openimci.yml @@ -70,9 +70,6 @@ jobs: version: '3.x' # If available, use the latest major version that's compatible repo-token: ${{ secrets.GITHUB_TOKEN }} - - name: OpenIM Scripts Verification(make verify) - run: sudo make verify - - name: Module Operations run: | sudo make tidy diff --git a/docs/readme/README-JP.md b/docs/readme/README-JP.md new file mode 100644 index 0000000000..c1b0eabf55 --- /dev/null +++ b/docs/readme/README-JP.md @@ -0,0 +1,190 @@ +

+ + + +

+ +
+ +[![Stars](https://img.shields.io/github/stars/openimsdk/open-im-server?style=for-the-badge&logo=github&colorB=ff69b4)](https://github.com/openimsdk/open-im-server/stargazers) +[![Forks](https://img.shields.io/github/forks/openimsdk/open-im-server?style=for-the-badge&logo=github&colorB=blue)](https://github.com/openimsdk/open-im-server/network/members) +[![Codecov](https://img.shields.io/codecov/c/github/openimsdk/open-im-server?style=for-the-badge&logo=codecov&colorB=orange)](https://app.codecov.io/gh/openimsdk/open-im-server) +[![Go Report Card](https://goreportcard.com/badge/github.com/openimsdk/open-im-server?style=for-the-badge)](https://goreportcard.com/report/github.com/openimsdk/open-im-server) +[![Go Reference](https://img.shields.io/badge/Go%20Reference-blue.svg?style=for-the-badge&logo=go&logoColor=white)](https://pkg.go.dev/github.com/openimsdk/open-im-server/v3) +[![License](https://img.shields.io/badge/license-Apache--2.0-green?style=for-the-badge)](https://github.com/openimsdk/open-im-server/blob/main/LICENSE) +[![Slack](https://img.shields.io/badge/Slack-500%2B-blueviolet?style=for-the-badge&logo=slack&logoColor=white)](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q) +[![Best Practices](https://img.shields.io/badge/Best%20Practices-purple?style=for-the-badge)](https://www.bestpractices.dev/projects/8045) +[![Good First Issues](https://img.shields.io/github/issues/openimsdk/open-im-server/good%20first%20issue?style=for-the-badge&logo=github)](https://github.com/openimsdk/open-im-server/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc+label%3A%22good+first+issue%22) +[![Language](https://img.shields.io/badge/Language-Go-blue.svg?style=for-the-badge&logo=go&logoColor=white)](https://golang.org/) + + +

+ Englist · + 中文 · + Українська · + Česky · + Magyar · + Español · + فارسی · + Français · + Deutsch · + Polski · + Indonesian · + Suomi · + മലയാളം · + 日本語 · + Nederlands · + Italiano · + Русский · + Português (Brasil) · + Esperanto · + 한국어 · + العربي · + Tiếng Việt · + Dansk · + Ελληνικά · + Türkçe +

+ + +
+ +

+ + +## Ⓜ️ OpenIMについて + +OpenIMは、アプリケーション内でチャット、音声通話、通知、AIチャットボットなどの通信機能を統合するために特別に設計されたサービスプラットフォームです。一連の強力なAPIとWebhooksを提供することで、開発者はアプリケーションに簡単にこれらの通信機能を統合できます。OpenIM自体は独立したチャットアプリではなく、アプリケーションにサポートを提供し、豊富な通信機能を実現するプラットフォームです。以下の図は、AppServer、AppClient、OpenIMServer、OpenIMSDK間の相互作用を示しています。 + + + +![App-OpenIM Relationship](../images/oepnim-design.png) + +## 🚀 OpenIMSDKについて + + **OpenIMSDK**は、**OpenIMServer**用に設計されたIM SDKで、クライアントアプリケーションに組み込むためのものです。主な機能とモジュールは以下の通りです: + ++ 🌟 主な機能: + + - 📦 ローカルストレージ + - 🔔 リスナーコールバック + - 🛡️ APIのラッピング + - 🌐 接続管理 + + ## 📚 主なモジュール: + + 1. 🚀 初初期化とログイン + 2. 👤 ユーザー管理 + 3. 👫 友達管理 + 4. 🤖 グループ機能 + 5. 💬 会話処理 + +Golangを使用して構築され、クロスプラットフォームの導入をサポートし、すべてのプラットフォームで一貫したアクセス体験を提供します。 + +👉 **[GO SDKを探索する](https://github.com/openimsdk/openim-sdk-core)** + +## 🌐 OpenIMServerについて + ++ **OpenIMServer** には以下の特徴があります: + - 🌐 マイクロサービスアーキテクチャ:クラスターモードをサポートし、ゲートウェイ(gateway)と複数のrpcサービスを含みます。 + - 🚀 多様なデプロイメント方法:ソースコード、kubernetes、またはdockerでのデプロイメントをサポートします。 + - 海量ユーザーサポート:十万人規模の超大型グループ、千万人のユーザー、および百億のメッセージ + +### 強化されたビジネス機能: + ++ **REST API**:OpenIMServerは、ビジネスシステム用のREST APIを提供しており、ビジネスにさらに多くの機能を提供することを目指しています。たとえば、バックエンドインターフェースを通じてグループを作成したり、プッシュメッセージを送信したりするなどです。 ++ **Webhooks**:OpenIMServerは、より多くのビジネス形態を拡張するためのコールバック機能を提供しています。コールバックとは、特定のイベントが発生する前後に、OpenIMServerがビジネスサーバーにリクエストを送信することを意味します。例えば、メッセージ送信の前後のコールバックなどです。 + +👉 **[もっと詳しく知る](https://docs.openim.io/guides/introduction/product)** + +## :building_construction: 全体のアーキテクチャ + +Open-IM-Serverの機能の核心に迫るために、アーキテクチャダイアグラムをご覧ください。 + +![Overall Architecture](../images/architecture-layers.png) + +## :rocket: クイックスタート + +iOS/Android/H5/PC/Webでのオンライン体験: + +👉 **[OpenIM online demo](https://www.openim.io/zh/commercial)** + +🤲 ユーザー体験を容易にするために、私たちは様々なデプロイメントソリューションを提供しています。以下のリストから、ご自身のデプロイメント方法を選択できます: + ++ **[ソースコードデプロイメントガイド](https://docs.openim.io/guides/gettingStarted/imSourceCodeDeployment)** ++ **[Docker デプロイメントガイド](https://docs.openim.io/guides/gettingStarted/dockerCompose)** ++ **[Kubernetes デプロイメントガイド](https://docs.openim.io/guides/gettingStarted/k8s-deployment)** ++ **[Mac 開発者向けデプロイメントガイド](https://docs.openim.io/guides/gettingstarted/mac-deployment-guide)** + +## :hammer_and_wrench: OpenIMの開発を始める + +[![Open in Dev Container](https://img.shields.io/static/v1?label=Dev%20Container&message=Open&color=blue&logo=visualstudiocode)](https://vscode.dev/github/openimsdk/open-im-server) + +OpenIM 私たちの目標は、トップレベルのオープンソースコミュニティを構築することです。[コミュニティリポジトリ](https://github.com/OpenIMSDK/community)には一連の基準があります。 + +このOpen-IM-Serverリポジトリに貢献したい場合は、[貢献者ドキュメントをお読みください](https://github.com/openimsdk/open-im-server/blob/main/CONTRIBUTING.md)。 + +始める前に、変更に必要があることを確認してください。最良の方法は、[新しいディスカッション](https://github.com/openimsdk/open-im-server/discussions/new/choose)や[Slack](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q)での通信を作成すること、または問題を発見した場合は、まずそれを[報告](https://github.com/openimsdk/open-im-server/issues/new/choose)することです。 + +- [OpenIM APIリファレンス](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/api.md) +- [OpenIM Bash ロギング](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/bash-log.md) +- [OpenIM CI/CD アクション](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/cicd-actions.md) +- [OpenIM コード規約](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/code-conventions.md) +- [OpenIM コミットガイドライン](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/commit.md) +- [OpenIM 開発ガイド](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/development.md) +- [OpenIM ディレクトリ構造](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/directory.md) +- [OpenIM 環境設定](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/environment.md) +- [OpenIM エラーコードリファレンス](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/error-code.md) +- [OpenIM Git ワークフロー](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/git-workflow.md) +- [OpenIM Git チェリーピックガイド](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/gitcherry-pick.md) +- [OpenIM GitHub ワークフロー](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/github-workflow.md) +- [OpenIM Go コード基準](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/go-code.md) +- [OpenIM 画像ガイドライン](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/images.md) +- [OpenIM 初期設定](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/init-config.md) +- [OpenIM Docker インストールガイド](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/install-docker.md) +- [OpenIM Linux システムインストール](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/install-openim-linux-system.md) +- [OpenIM Linux 開発ガイド](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/linux-development.md) +- [OpenIM ローカルアクションガイド](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/local-actions.md) +- [OpenIM ロギング規約](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/logging.md) +- [OpenIM オフラインデプロイメント](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/offline-deployment.md) +- [OpenIM Protoc ツール](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/protoc-tools.md) +- [OpenIM テスティングガイド](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/test.md) +- [OpenIM ユーティリティGo](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/util-go.md) +- [OpenIM Makefile ユーティリティ](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/util-makefile.md) +- [OpenIM スクリプトユーティリティ](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/util-scripts.md) +- [OpenIM バージョニング](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/version.md) +- [バックエンド管理とモニターデプロイメント](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/prometheus-grafana.md) +- [OpenIM用Mac開発者デプロイメントガイド](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/mac-developer-deployment-guide.md) + + +## :busts_in_silhouette: コミュニティ + ++ 📚 [OpenIM コミュニティ](https://github.com/OpenIMSDK/community) ++ 💕 [OpenIM 興味グループ](https://github.com/Openim-sigs) ++ 🚀 [私たちのSlackコミュニティに参加する](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q) ++ :eyes: [私たちのWeChat(微信群)に参加する](https://openim-1253691595.cos.ap-nanjing.myqcloud.com/WechatIMG20.jpeg) + +## :calendar: コミュニティミーティング + +私たちは、誰もがコミュニティに参加し、コードに貢献してもらいたいと考えています。私たちは、ギフトや報酬を提供し、毎週木曜日の夜に参加していただくことを歓迎します。 + +私たちの会議は[OpenIM Slack](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q)🎯で行われます。そこでOpen-IM-Serverパイプラインを検索して参加できます。 + + +私たちは[隔週の会議](https://github.com/orgs/OpenIMSDK/discussions/categories/meeting)のメモを[GitHubディスカッション](https://github.com/openimsdk/open-im-server/discussions/categories/meeting)に記録しています。歴史的な会議のメモや会議のリプレイは[Google Docs📑](https://docs.google.com/document/d/1nx8MDpuG74NASx081JcCpxPgDITNTpIIos0DS6Vr9GU/edit?usp=sharing)で利用可能です。 + +## :eyes: OpenIMを使用している人たち + +プロジェクトユーザーのリストについては、[ユーザーケーススタディ](https://github.com/OpenIMSDK/community/blob/main/ADOPTERS.md)ページをご覧ください。[コメント📝](https://github.com/openimsdk/open-im-server/issues/379)を残して、あなたの使用例を共有することを躊躇しないでください。 + +## :page_facing_up: ライセンス + +OpenIMはApache 2.0ライセンスの下でライセンスされています。完全なライセンステキストについては、[LICENSE](https://github.com/openimsdk/open-im-server/tree/main/LICENSE)を参照してください。 + +このリポジトリに表示される[OpenIM](https://github.com/openimsdk/open-im-server)ロゴ、そのバリエーション、およびアニメーションバージョン([assets/logo](./assets/logo)および[assets/logo-gif](assets/logo-gif)ディレクトリ内)は、著作権法によって保護されています。 + +## 🔮 貢献者の皆様に感謝します! + + + + \ No newline at end of file From 5cb69b874207713338e66af8c4a410fcee10cd47 Mon Sep 17 00:00:00 2001 From: OpenIM Bot <124379614+kubbot@users.noreply.github.com> Date: Tue, 6 Feb 2024 15:51:25 +0800 Subject: [PATCH 033/188] cicd: bump League Patch (#1892) --- internal/msgtransfer/init.go | 7 ++++--- pkg/common/kafka/consumer_group.go | 4 +++- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/internal/msgtransfer/init.go b/internal/msgtransfer/init.go index 65a6b1935f..65518c3246 100644 --- a/internal/msgtransfer/init.go +++ b/internal/msgtransfer/init.go @@ -18,22 +18,23 @@ import ( "context" "errors" "fmt" + "net/http" "os" "os/signal" + "sync" "syscall" "time" - "net/http" - "sync" "github.com/OpenIMSDK/tools/errs" + "github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/mw" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/collectors" "github.com/prometheus/client_golang/prometheus/promhttp" "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" - "github.com/OpenIMSDK/tools/log" + "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" diff --git a/pkg/common/kafka/consumer_group.go b/pkg/common/kafka/consumer_group.go index 3f444cc1f2..5bff50d880 100644 --- a/pkg/common/kafka/consumer_group.go +++ b/pkg/common/kafka/consumer_group.go @@ -17,10 +17,12 @@ package kafka import ( "context" "errors" - "github.com/IBM/sarama" "strings" + + "github.com/IBM/sarama" "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/log" + "github.com/openimsdk/open-im-server/v3/pkg/common/config" ) From 49610b56040ca57e334a55774037b47b118c7eb0 Mon Sep 17 00:00:00 2001 From: Xinwei Xiong <3293172751NSS@gmail.com> Date: Tue, 6 Feb 2024 15:53:03 +0800 Subject: [PATCH 034/188] Fix Script Error and Enhance Code Robustness and Details (#1890) * feat: add openim deployment tactics Signed-off-by: Xinwei Xiong (cubxxw) <3293172751nss@gmail.com> * feat: add openim deployment tactics Signed-off-by: Xinwei Xiong (cubxxw) <3293172751nss@gmail.com> * fix: set openim admin chat code Signed-off-by: Xinwei Xiong (cubxxw) <3293172751nss@gmail.com> * fix: set openim admin chat code Signed-off-by: Xinwei Xiong (cubxxw) <3293172751nss@gmail.com> * fix: fix openim msgtransfer code * fix: fix openim msgtransfer code --------- Signed-off-by: Xinwei Xiong (cubxxw) <3293172751nss@gmail.com> --- .devcontainer/README.md | 140 -------------------------- .devcontainer/devcontainer.json | 72 ------------- cmd/openim-api/main.go | 1 + pkg/common/cmd/api.go | 3 - pkg/common/cmd/msg_transfer.go | 3 +- pkg/common/cmd/root.go | 5 +- pkg/common/config/parse.go | 2 +- scripts/install/openim-api.sh | 46 ++++----- scripts/install/openim-crontask.sh | 2 +- scripts/install/openim-msggateway.sh | 2 +- scripts/install/openim-msgtransfer.sh | 16 +-- scripts/install/openim-push.sh | 2 +- scripts/install/openim-rpc.sh | 2 +- scripts/lib/util.sh | 6 +- scripts/stop-all.sh | 9 +- 15 files changed, 43 insertions(+), 268 deletions(-) delete mode 100644 .devcontainer/README.md delete mode 100644 .devcontainer/devcontainer.json diff --git a/.devcontainer/README.md b/.devcontainer/README.md deleted file mode 100644 index 24778f8ee5..0000000000 --- a/.devcontainer/README.md +++ /dev/null @@ -1,140 +0,0 @@ -# OpenIM - OSS Development Container - -[![Open in Dev Containers](https://img.shields.io/static/v1?label=Dev%20Containers&message=Open&color=blue&logo=visualstudiocode)](https://vscode.dev/redirect?url=vscode://ms-vscode-remote.remote-containers/cloneInVolume?url=https://github.com/openimsdk/open-im-server) - -This repository includes configuration for a development container for working with OpenIM - OSS in a local container or using [GitHub Codespaces](https://github.com/features/codespaces). - -> **Tip:** The default VNC password is `openIM123`. The VNC server runs on port `5901` and a web client is available on port `11001`, openim-admin on port `11002`. - -## Quick start - local - -If you already have VS Code and Docker installed, you can click the badge above or [here](https://vscode.dev/redirect?url=vscode://ms-vscode-remote.remote-containers/cloneInVolume?url=https://github.com/openimsdk/open-im-server) to get started. Clicking these links will cause VS Code to automatically install the Dev Containers extension if needed, clone the source code into a container volume, and spin up a dev container for use. - -1. Install Docker Desktop or Docker for Linux on your local machine. (See [docs](https://aka.ms/vscode-remote/containers/getting-started) for additional details.) - -2. **Important**: Docker needs at least **4 Cores and 8 GB of RAM** to run a full build with **9 GB of RAM** being recommended. If you are on macOS, or are using the old Hyper-V engine for Windows, update these values for Docker Desktop by right-clicking on the Docker status bar item and going to **Preferences/Settings > Resources > Advanced**. - - > **Note:** The [Resource Monitor](https://marketplace.visualstudio.com/items?itemName=mutantdino.resourcemonitor) extension is included in the container so you can keep an eye on CPU/Memory in the status bar. - -3. Install [Visual Studio Code Stable](https://code.visualstudio.com/) or [Insiders](https://code.visualstudio.com/insiders/) and the [Dev Containers](https://aka.ms/vscode-remote/download/containers) extension. - - ![Image of Dev Containers extension](https://microsoft.github.io/vscode-remote-release/images/dev-containers-extn.png) - - > **Note:** The Dev Containers extension requires the Visual Studio Code distribution of OpenIM - OSS. See the [FAQ](https://aka.ms/vscode-remote/faq/license) for details. - -4. Press Ctrl/Cmd + Shift + P or F1 and select **Dev Containers: Clone Repository in Container Volume...**. - - > **Tip:** While you can use your local source tree instead, operations like `yarn install` can be slow on macOS or when using the Hyper-V engine on Windows. We recommend using the WSL filesystem on Windows or the "clone repository in container" approach on Windows and macOS instead since it uses "named volume" rather than the local filesystem. - -5. Type `https://github.com/openimsdk/open-im-server` (or a branch or PR URL) in the input box and press Enter. - -6. After the container is running: - 1. If you have the `DISPLAY` or `WAYLAND_DISPLAY` environment variables set locally (or in WSL on Windows), desktop apps in the container will be shown in local windows. - 2. If these are not set, open a web browser and go to [http://localhost:11001](http://localhost:11001), or use a [VNC Viewer][def] to connect to `localhost:11001` and enter `vscode` as the password. Anything you start in VS Code, or the integrated terminal, will appear here. - -Next: **[Try it out!](#try-it)** - -## Quick start - GitHub Codespaces - -1. From the [openimsdk/open-im-server GitHub repository](https://github.com/openimsdk/open-im-server), click on the **Code** dropdown, select **Open with Codespaces**, and then click on **New codespace**. If prompted, select the **Standard** machine size (which is also the default). - - > **Note:** You will not see these options within GitHub if you are not in the Codespaces beta. - -2. After the codespace is up and running in your browser, press Ctrl/Cmd + Shift + P or F1 and select **Ports: Focus on Ports View**. - -3. You should see **VNC web client (11001)** under in the list of ports. Select the line and click on the globe icon to open it in a browser tab. - - > **Tip:** If you do not see the port, Ctrl/Cmd + Shift + P or F1, select **Forward a Port** and enter port `11001`. - -4. In the new tab, you should see noVNC. Click **Connect** and enter `vscode` as the password. - -Anything you start in VS Code, or the integrated terminal, will appear here. - -Next: **[Try it out!](#try-it)** - -### Using VS Code with GitHub Codespaces - -You may see improved VNC responsiveness when accessing a codespace from VS Code client since you can use a [VNC Viewer][def]. Here's how to do it. - -1. Install [Visual Studio Code Stable](https://code.visualstudio.com/) or [Insiders](https://code.visualstudio.com/insiders/) and the the [GitHub Codespaces extension](https://marketplace.visualstudio.com/items?itemName=GitHub.codespaces). - - > **Note:** The GitHub Codespaces extension requires the Visual Studio Code distribution of OpenIM - OSS. - -2. After the VS Code is up and running, press Ctrl/Cmd + Shift + P or F1, choose **Codespaces: Create New Codespace**, and use the following settings: - -- `openimsdk/open-im-server` for the repository. -- Select any branch (e.g. **main**) - you can select a different one later. -- Choose **Standard** (4-core, 8GB) as the size. - -3. After you have connected to the codespace, you can use a [VNC Viewer][def] to connect to `localhost:5901` and enter `vscode` as the password. - - > **Tip:** You may also need change your VNC client's **Picture Quality** setting to **High** to get a full color desktop. - -4. Anything you start in VS Code, or the integrated terminal, will appear here. - -Next: **[Try it out!](#try-it)** - -## Try it - -This container uses the [Fluxbox](http://fluxbox.org/) window manager to keep things lean. **Right-click on the desktop** to see menu options. It works with GNOME and GTK applications, so other tools can be installed if needed. - - > **Note:** You can also set the resolution from the command line by typing `set-resolution`. - -To start working with OpenIM - OSS, follow these steps: - -1. In your local VS Code client, open a terminal (Ctrl/Cmd + Shift + \`) and type the following commands: - - ```bash - yarn install - bash scripts/code.sh - ``` - -2. After the build is complete, open a web browser or a [VNC Viewer][def] to connect to the desktop environment as described in the quick start and enter `vscode` as the password. - -3. You should now see OpenIM - OSS! - -Next, let's try debugging. - -1. Shut down OpenIM - OSS by clicking the box in the upper right corner of the OpenIM - OSS window through your browser or VNC viewer. - -2. Go to your local VS Code client, and use the **Run / Debug** view to launch the **VS Code** configuration. (Typically the default, so you can likely just press F5). - - > **Note:** If launching times out, you can increase the value of `timeout` in the "VS Code", "Attach Main Process", "Attach Extension Host", and "Attach to Shared Process" configurations in [launch.json](../../.vscode/launch.json). However, running `./scripts/code.sh` first will set up Electron which will usually solve timeout issues. - -3. After a bit, OpenIM - OSS will appear with the debugger attached! - -Enjoy! - - -### Dotfiles - -Dotfiles are files and folders on Unix-like systems starting with `.` that control the configuration of applications and shells on your system. You can store and manage your dotfiles in a repository on GitHub. For advice and tutorials about what to include in your dotfiles repository, see [GitHub does dotfiles](https://dotfiles.github.io/). - -Your dotfiles repository might include your shell aliases and preferences, any tools you want to install, or any other codespace personalization you want to make. - -You can configure GitHub Codespaces to use dotfiles from any repository you own by selecting that repository in your [personal GitHub Codespaces settings](https://github.com/settings/codespaces). - -When you create a new codespace, GitHub clones your selected dotfiles repository to the codespace environment, and looks for one of the following files to set up the environment. - -- *install.sh* -- *install* -- *bootstrap.sh* -- *bootstrap* -- *script/bootstrap* -- *setup.sh* -- *setup* -- *script/setup* - -If none of these files are found, then any files or folders in your selected dotfiles repository starting with `.` are symlinked to the codespace's `~` or `$HOME` directory. - -Any changes to your selected dotfiles repository will apply only to each new codespace, and do not affect any existing codespace. - -**Note:** Currently, Codespaces does not support personalizing the User-scoped settings for VS Code with your `dotfiles` repository. You can set default Workspace and Remote [Codespaces] settings for a specific project in the project's repository. For more information, see "[Introduction to dev containers](https://docs.github.com/en/codespaces/setting-up-your-project-for-codespaces/adding-a-dev-container-configuration/introduction-to-dev-containers#creating-a-custom-dev-container-configuration)." - -In addition, you can also configure Codespaces secrets on your personal profile page at [github.com/settings/codespaces](https://github.com/settings/codespaces). Development environment secrets are environment variables that are encrypted, and they are accessible to any codespace you create using repositories that have access to these secrets. - -### Notes - -The container comes with VS Code Insiders installed. To run it from an Integrated Terminal use `VSCODE_IPC_HOOK_CLI= /usr/bin/code-insiders .`. - -[def]: https://www.realvnc.com/en/connect/download/viewer/ diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json deleted file mode 100644 index 69a35f66ac..0000000000 --- a/.devcontainer/devcontainer.json +++ /dev/null @@ -1,72 +0,0 @@ -{ - // Reference Doc: https://code.visualstudio.com/remote/advancedcontainers/overview - "name": "OpenIM Dev Environment", - // Update the container version when you publish dev-container - "build": { "dockerfile": "Dockerfile" }, - // Replace with uncommented line below to build your own local copy of the image - // "dockerFile": "../docker/Dockerfile-dev", - "remoteEnv": { - "GO111MODULE": "on", - "GOPROXY": "https://goproxy.cn", - "GOSUMDB": "sum.golang.org", - "GONOPROXY": "github.com/openimsdk", - "GONOSUMDB": "github.com/openimsdk", - "GOPRIVATE": "github.com/openimsdk" - }, - "customizations": { - "vscode": { - "extensions": [ - "davidanson.vscode-markdownlint", - "golang.go", - "ms-azuretools.vscode-dapr", - "ms-azuretools.vscode-docker", - "ms-kubernetes-tools.vscode-kubernetes-tools" - ], - "settings": { - "go.toolsManagement.checkForUpdates": "local", - "go.useLanguageServer": true, - "go.gopath": "/go" - } - } - }, - "mounts": [ - // Mount docker-in-docker library volume - "type=volume,source=dind-var-lib-docker,target=/var/lib/docker", - - // Bind mount docker socket under an alias to support docker-from-docker - "type=bind,source=/var/run/docker.sock,target=/var/run/docker-host.sock", - - // Bind mount docker socket under an alias to support docker-from-docker - // "type=bind,source=${env:HOME}${env:USERPROFILE}/.minikube/cache,target=/home/openim/.minikube/cache", - - // Uncomment to clone local .kube/config into devcontainer - "type=bind,source=${env:HOME}${env:USERPROFILE}/.kube,target=/home/openim/.kube-localhost" - - // Uncomment to additionally clone minikube certs into devcontainer for use with .kube/config - // "type=bind,source=${env:HOME}${env:USERPROFILE}/.minikube,target=/home/openim/.minikube-localhost" - ], - // Always run image-defined default command - "overrideCommand": false, - // On Linux, this will prevent new files getting created as root, but you - // may need to update the USER_UID and USER_GID in docker/Dockerfile-dev - // to match your user if not 1000. - // "remoteUser": "openimsdk", - "runArgs": [ - // Enable ptrace-based debugging for go - "--cap-add=SYS_PTRACE", - "--security-opt", - "seccomp=unconfined", - - // Uncomment to bind to host network for local devcontainer; this is necessary if using the - // bind-mounted /var/run/docker-host.sock directly. - "--net=host", - - // Enable docker-in-docker configuration. Comment out if not using for better security. - "--privileged", - - // Run the entrypoint defined in container image. - "--init" - ], - "workspaceFolder": "/workspaces/openim", - "workspaceMount": "type=bind,source=${localWorkspaceFolder},target=/workspaces/openim" -} diff --git a/cmd/openim-api/main.go b/cmd/openim-api/main.go index a45bcbdd82..bbb5eb9687 100644 --- a/cmd/openim-api/main.go +++ b/cmd/openim-api/main.go @@ -43,6 +43,7 @@ import ( func main() { apiCmd := cmd.NewApiCmd() apiCmd.AddPortFlag() + apiCmd.AddPrometheusPortFlag() apiCmd.AddApi(run) if err := apiCmd.Execute(); err != nil { fmt.Fprintf(os.Stderr, "\n\nexit -1: \n%+v\n\n", err) diff --git a/pkg/common/cmd/api.go b/pkg/common/cmd/api.go index 00c6cb2418..db1f488ad8 100644 --- a/pkg/common/cmd/api.go +++ b/pkg/common/cmd/api.go @@ -15,8 +15,6 @@ package cmd import ( - "fmt" - "github.com/OpenIMSDK/protocol/constant" "github.com/spf13/cobra" @@ -41,7 +39,6 @@ func (a *ApiCmd) AddApi(f func(port int, promPort int) error) { } func (a *ApiCmd) GetPortFromConfig(portType string) int { - fmt.Println("GetPortFromConfig:", portType) if portType == constant.FlagPort { return config2.Config.Api.OpenImApiPort[0] } else if portType == constant.FlagPrometheusPort { diff --git a/pkg/common/cmd/msg_transfer.go b/pkg/common/cmd/msg_transfer.go index f99b625c70..e57bab89d5 100644 --- a/pkg/common/cmd/msg_transfer.go +++ b/pkg/common/cmd/msg_transfer.go @@ -47,7 +47,6 @@ func (m *MsgTransferCmd) Exec() error { } func (m *MsgTransferCmd) GetPortFromConfig(portType string) int { - fmt.Println("GetPortFromConfig:", portType) if portType == constant.FlagPort { return 0 } else if portType == constant.FlagPrometheusPort { @@ -56,9 +55,11 @@ func (m *MsgTransferCmd) GetPortFromConfig(portType string) int { } return 0 } + func (m *MsgTransferCmd) AddTransferProgressFlag() { m.Command.Flags().IntP(constant.FlagTransferProgressIndex, "n", 0, "transfer progress index") } + func (m *MsgTransferCmd) getTransferProgressFlagValue() int { nindex, err := m.Command.Flags().GetInt(constant.FlagTransferProgressIndex) if err != nil { diff --git a/pkg/common/cmd/root.go b/pkg/common/cmd/root.go index 98ca8f892a..eab4a32bc9 100644 --- a/pkg/common/cmd/root.go +++ b/pkg/common/cmd/root.go @@ -163,7 +163,7 @@ func (r *RootCmd) GetPrometheusPortFlag() int { func (r *RootCmd) getConfFromCmdAndInit(cmdLines *cobra.Command) error { configFolderPath, _ := cmdLines.Flags().GetString(constant.FlagConf) - fmt.Println("configFolderPath:", configFolderPath) + fmt.Println("The directory of the configuration file to start the process:", configFolderPath) return config2.InitConfig(configFolderPath) } @@ -176,10 +176,9 @@ func (r *RootCmd) AddCommand(cmds ...*cobra.Command) { } func (r *RootCmd) GetPortFromConfig(portType string) int { - fmt.Println("RootCmd.GetPortFromConfig:", portType) return 0 } + func (r *RootCmd) PortFromConfig(portType string) int { - fmt.Println("PortFromConfig:", portType) return r.cmdItf.GetPortFromConfig(portType) } diff --git a/pkg/common/config/parse.go b/pkg/common/config/parse.go index 64719d6a1b..4037429e34 100644 --- a/pkg/common/config/parse.go +++ b/pkg/common/config/parse.go @@ -101,7 +101,7 @@ func initConfig(config any, configName, configFolderPath string) error { if err = yaml.Unmarshal(data, config); err != nil { return fmt.Errorf("unmarshal yaml error: %w", err) } - fmt.Println("use config", configFolderPath) + fmt.Println("The path of the configuration file to start the process:", configFolderPath) return nil } diff --git a/scripts/install/openim-api.sh b/scripts/install/openim-api.sh index c81dfcd0d6..be2a2d33b3 100755 --- a/scripts/install/openim-api.sh +++ b/scripts/install/openim-api.sh @@ -33,8 +33,12 @@ readonly OPENIM_API_SERVICE_TARGETS=( ) readonly OPENIM_API_SERVICE_LISTARIES=("${OPENIM_API_SERVICE_TARGETS[@]##*/}") -function openim::api::start() { +readonly OPENIM_API_PROMETHEUS_PORT_TARGETS=( + ${API_PROM_PORT} +) +readonly OPENIM_API_PROMETHEUS_PORT_LISTARIES=("${OPENIM_API_PROMETHEUS_PORT_TARGETS[@]##*/}") +function openim::api::start() { rm -rf "$TMP_LOG_FILE" echo "++ OPENIM_API_SERVICE_LISTARIES: ${OPENIM_API_SERVICE_LISTARIES[@]}" @@ -47,34 +51,20 @@ function openim::api::start() { printf "| Service Name | Port |\n" printf "+------------------------+--------------+\n" - length=${#OPENIM_API_SERVICE_LISTARIES[@]} + local length=${#OPENIM_API_SERVICE_LISTARIES[@]} - for ((i=0; i<$length; i++)); do + for ((i=0; i> "${LOG_FILE}" 2> >(tee -a "${STDERR_LOG_FILE}" "$TMP_LOG_FILE") & + + # Append Prometheus port argument if specified + if [ -n "${prometheus_port}" ]; then + cmd+=" --prometheus_port ${prometheus_port}" + fi + + echo "Starting service with command: $cmd" + + nohup $cmd >> "${LOG_FILE}" 2> >(tee -a "${STDERR_LOG_FILE}" "$TMP_LOG_FILE" >&2) & if [ $? -ne 0 ]; then openim::log::error_exit "Failed to start ${binary_name} on port ${service_port}." diff --git a/scripts/install/openim-crontask.sh b/scripts/install/openim-crontask.sh index 6068e97d5a..395b27cd1b 100755 --- a/scripts/install/openim-crontask.sh +++ b/scripts/install/openim-crontask.sh @@ -54,7 +54,7 @@ function openim::crontask::start() { openim::log::status "start cron_task process, path: ${OPENIM_CRONTASK_BINARY}" - nohup ${OPENIM_CRONTASK_BINARY} -c ${OPENIM_PUSH_CONFIG} >> ${LOG_FILE} 2> >(tee -a "${STDERR_LOG_FILE}" "$TMP_LOG_FILE") & + nohup ${OPENIM_CRONTASK_BINARY} -c ${OPENIM_PUSH_CONFIG} >> ${LOG_FILE} 2> >(tee -a "${STDERR_LOG_FILE}" "$TMP_LOG_FILE" >&2) & openim::util::check_process_names ${SERVER_NAME} } diff --git a/scripts/install/openim-msggateway.sh b/scripts/install/openim-msggateway.sh index 4e591decae..a2316c784d 100755 --- a/scripts/install/openim-msggateway.sh +++ b/scripts/install/openim-msggateway.sh @@ -64,7 +64,7 @@ function openim::msggateway::start() { PROMETHEUS_PORT_OPTION="--prometheus_port ${MSG_GATEWAY_PROM_PORTS_ARRAY[$i]}" fi - nohup ${OPENIM_MSGGATEWAY_BINARY} --port ${OPENIM_MSGGATEWAY_PORTS_ARRAY[$i]} --ws_port ${OPENIM_WS_PORTS_ARRAY[$i]} $PROMETHEUS_PORT_OPTION -c ${OPENIM_MSGGATEWAY_CONFIG} >> ${LOG_FILE} 2> >(tee -a "${STDERR_LOG_FILE}" "$TMP_LOG_FILE") & + nohup ${OPENIM_MSGGATEWAY_BINARY} --port ${OPENIM_MSGGATEWAY_PORTS_ARRAY[$i]} --ws_port ${OPENIM_WS_PORTS_ARRAY[$i]} $PROMETHEUS_PORT_OPTION -c ${OPENIM_MSGGATEWAY_CONFIG} >> ${LOG_FILE} 2> >(tee -a "${STDERR_LOG_FILE}" "$TMP_LOG_FILE" >&2) & done openim::util::check_process_names ${SERVER_NAME} diff --git a/scripts/install/openim-msgtransfer.sh b/scripts/install/openim-msgtransfer.sh index def22c38b2..783e067297 100755 --- a/scripts/install/openim-msgtransfer.sh +++ b/scripts/install/openim-msgtransfer.sh @@ -38,7 +38,7 @@ function openim::msgtransfer::start() { # Message Transfer Prometheus port list MSG_TRANSFER_PROM_PORTS=(openim::util::list-to-string ${MSG_TRANSFER_PROM_PORT} ) - + openim::log::status "OpenIM Prometheus ports: ${MSG_TRANSFER_PROM_PORTS[*]}" openim::log::status "OpenIM Msggateway config path: ${OPENIM_MSGTRANSFER_CONFIG}" @@ -54,12 +54,14 @@ function openim::msgtransfer::start() { fi for (( i=0; i<$OPENIM_MSGGATEWAY_NUM; i++ )) do - openim::log::info "prometheus port: ${MSG_TRANSFER_PROM_PORTS[$i]}" - PROMETHEUS_PORT_OPTION="" - if [[ -n "${OPENIM_PROMETHEUS_PORTS[$i]}" ]]; then - PROMETHEUS_PORT_OPTION="--prometheus_port ${OPENIM_PROMETHEUS_PORTS[$i]}" - fi - nohup ${OPENIM_MSGTRANSFER_BINARY} ${PROMETHEUS_PORT_OPTION} -c ${OPENIM_MSGTRANSFER_CONFIG} -n ${i} >> ${LOG_FILE} 2> >(tee -a "${STDERR_LOG_FILE}" "$TMP_LOG_FILE") & + openim::log::info "prometheus port: ${MSG_TRANSFER_PROM_PORTS[$i]}" + PROMETHEUS_PORT_OPTION="" + if [[ -n "${MSG_TRANSFER_PROM_PORTS[$i+1]}" ]]; then + PROMETHEUS_MSG_TRANSFER_PORT="${MSG_TRANSFER_PROM_PORTS[$i+1]%,}" + openim::util::stop_services_on_ports ${PROMETHEUS_MSG_TRANSFER_PORT} + PROMETHEUS_PORT_OPTION="--prometheus_port ${PROMETHEUS_MSG_TRANSFER_PORT}" + fi + nohup ${OPENIM_MSGTRANSFER_BINARY} ${PROMETHEUS_PORT_OPTION} -c ${OPENIM_MSGTRANSFER_CONFIG} -n ${i} >> ${LOG_FILE} 2> >(tee -a "${STDERR_LOG_FILE}" "$TMP_LOG_FILE" >&2) & done openim::util::check_process_names "${OPENIM_OUTPUT_HOSTBIN}/${SERVER_NAME}" diff --git a/scripts/install/openim-push.sh b/scripts/install/openim-push.sh index 4d14ca6752..ab12735c10 100755 --- a/scripts/install/openim-push.sh +++ b/scripts/install/openim-push.sh @@ -73,7 +73,7 @@ function openim::push::start() { for (( i=0; i<${#OPENIM_PUSH_PORTS_ARRAY[@]}; i++ )); do openim::log::info "start push process, port: ${OPENIM_PUSH_PORTS_ARRAY[$i]}, prometheus port: ${PUSH_PROM_PORTS_ARRAY[$i]}" - nohup ${OPENIM_PUSH_BINARY} --port ${OPENIM_PUSH_PORTS_ARRAY[$i]} -c ${OPENIM_PUSH_CONFIG} --prometheus_port ${PUSH_PROM_PORTS_ARRAY[$i]} >${LOG_FILE} 2> >(tee -a "${STDERR_LOG_FILE}" "$TMP_LOG_FILE") & + nohup ${OPENIM_PUSH_BINARY} --port ${OPENIM_PUSH_PORTS_ARRAY[$i]} -c ${OPENIM_PUSH_CONFIG} --prometheus_port ${PUSH_PROM_PORTS_ARRAY[$i]} >${LOG_FILE} 2> >(tee -a "${STDERR_LOG_FILE}" "$TMP_LOG_FILE" >&2) & done openim::util::check_process_names ${SERVER_NAME} diff --git a/scripts/install/openim-rpc.sh b/scripts/install/openim-rpc.sh index 00031f211f..f8feaaa572 100755 --- a/scripts/install/openim-rpc.sh +++ b/scripts/install/openim-rpc.sh @@ -160,7 +160,7 @@ function openim::rpc::start_service() { printf "Specifying prometheus port: %s\n" "${prometheus_port}" cmd="${cmd} --prometheus_port ${prometheus_port}" fi - nohup ${cmd} >> "${LOG_FILE}" 2> >(tee -a "${STDERR_LOG_FILE}" "$TMP_LOG_FILE") & + nohup ${cmd} >> "${LOG_FILE}" 2> >(tee -a "${STDERR_LOG_FILE}" "$TMP_LOG_FILE" >&2) & } ###################################### Linux Systemd ###################################### diff --git a/scripts/lib/util.sh b/scripts/lib/util.sh index cace536456..7acb1fcddd 100755 --- a/scripts/lib/util.sh +++ b/scripts/lib/util.sh @@ -505,8 +505,6 @@ openim::util::stop_services_on_ports() { # Print information about ports whose processes were successfully stopped. if [[ ${#stopped[@]} -ne 0 ]]; then - echo - openim::log::info "Stopped services on ports:" for port in "${stopped[@]}"; do openim::log::info "Successfully stopped service on port $port." done @@ -1741,8 +1739,6 @@ openim::util::stop_services_on_ports() { # Print information about ports whose processes were successfully stopped. if [[ ${#stopped[@]} -ne 0 ]]; then - echo - openim::log::info "Stopped services on ports:" for port in "${stopped[@]}"; do openim::log::info "Successfully stopped service on port $port." done @@ -2828,4 +2824,4 @@ function openim::util::gen_os_arch() { if [[ "$*" =~ openim::util:: ]];then eval $* -fi +fi \ No newline at end of file diff --git a/scripts/stop-all.sh b/scripts/stop-all.sh index 1d2eddd78b..2acb9cdc52 100755 --- a/scripts/stop-all.sh +++ b/scripts/stop-all.sh @@ -36,11 +36,4 @@ echo -e "\n++ Stop all processes in the path ${OPENIM_OUTPUT_HOSTBIN}" openim::util::stop_services_with_name "${OPENIM_OUTPUT_HOSTBIN}" -echo -n "Stopping services 15 seconds." -for i in {1..15}; do - echo -n "." - sleep 1 -done -echo -e "\nServices stopped." - -openim::log::success "✨ Wait 15 seconds for all processes to be killed" \ No newline at end of file +openim::log::success "✨ All processes to be killed" \ No newline at end of file From 51faa9190d3c98ac6245b93a29f73b1a6e29944a Mon Sep 17 00:00:00 2001 From: xuan <146319162+wxuanF@users.noreply.github.com> Date: Wed, 7 Feb 2024 21:50:17 +0800 Subject: [PATCH 035/188] docs: add README.md-TR (#1900) Signed-off-by: wxuanF <2569456943@qq.com> --- docs/readme/README-TR.md | 189 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 189 insertions(+) create mode 100644 docs/readme/README-TR.md diff --git a/docs/readme/README-TR.md b/docs/readme/README-TR.md new file mode 100644 index 0000000000..ff545e6441 --- /dev/null +++ b/docs/readme/README-TR.md @@ -0,0 +1,189 @@ +

+ + + +

+ +
+ +[![Stars](https://img.shields.io/github/stars/openimsdk/open-im-server?style=for-the-badge&logo=github&colorB=ff69b4)](https://github.com/openimsdk/open-im-server/stargazers) +[![Forks](https://img.shields.io/github/forks/openimsdk/open-im-server?style=for-the-badge&logo=github&colorB=blue)](https://github.com/openimsdk/open-im-server/network/members) +[![Codecov](https://img.shields.io/codecov/c/github/openimsdk/open-im-server?style=for-the-badge&logo=codecov&colorB=orange)](https://app.codecov.io/gh/openimsdk/open-im-server) +[![Go Report Card](https://goreportcard.com/badge/github.com/openimsdk/open-im-server?style=for-the-badge)](https://goreportcard.com/report/github.com/openimsdk/open-im-server) +[![Go Reference](https://img.shields.io/badge/Go%20Reference-blue.svg?style=for-the-badge&logo=go&logoColor=white)](https://pkg.go.dev/github.com/openimsdk/open-im-server/v3) +[![License](https://img.shields.io/badge/license-Apache--2.0-green?style=for-the-badge)](https://github.com/openimsdk/open-im-server/blob/main/LICENSE) +[![Slack](https://img.shields.io/badge/Slack-500%2B-blueviolet?style=for-the-badge&logo=slack&logoColor=white)](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q) +[![Best Practices](https://img.shields.io/badge/Best%20Practices-purple?style=for-the-badge)](https://www.bestpractices.dev/projects/8045) +[![Good First Issues](https://img.shields.io/github/issues/openimsdk/open-im-server/good%20first%20issue?style=for-the-badge&logo=github)](https://github.com/openimsdk/open-im-server/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc+label%3A%22good+first+issue%22) +[![Language](https://img.shields.io/badge/Language-Go-blue.svg?style=for-the-badge&logo=go&logoColor=white)](https://golang.org/) + + +

+ Englist · + 中文 · + Українська · + Česky · + Magyar · + Español · + فارسی · + Français · + Deutsch · + Polski · + Indonesian · + Suomi · + മലയാളം · + 日本語 · + Nederlands · + Italiano · + Русский · + Português (Brasil) · + Esperanto · + 한국어 · + العربي · + Tiếng Việt · + Dansk · + Ελληνικά · + Türkçe +

+ + +
+ +

+ + +## Ⓜ️ OpenIM Hakkında + +OpenIM, uygulamalara sohbet, sesli-görüntülü aramalar, bildirimler ve AI sohbet robotları entegre etmek için özel olarak tasarlanmış bir hizmet platformudur. Güçlü API'ler ve Webhook'lar sunarak, geliştiricilerin bu etkileşimli özellikleri uygulamalarına kolayca dahil etmelerini sağlar. OpenIM bağımsız bir sohbet uygulaması değildir, ancak zengin iletişim işlevselliği sağlama amacıyla diğer uygulamaları destekleyen bir platform olarak hizmet verir. Aşağıdaki diyagram, AppServer, AppClient, OpenIMServer ve OpenIMSDK arasındaki etkileşimi detaylandırmak için açıklar. + + + +![App-OpenIM Relationship](../images/oepnim-design.png) + +## 🚀 OpenIMSDK Hakkında + + **OpenIMSDK**, müşteri uygulamalarına gömülmek üzere özel olarak oluşturulan **OpenIMServer** için tasarlanmış bir IM SDK'sıdır. Ana özellikleri ve modülleri aşağıdaki gibidir: + ++ 🌟 Ana Özellikler: + + - 📦 Yerel depolama + - 🔔 Dinleyici geri çağırmaları + - 🛡️ API sarımı + - 🌐 Bağlantı yönetimi + + ## 📚 Ana Modüller: + + 1. 🚀 Başlatma ve Giriş + 2. 👤 Kullanıcı Yönetimi + 3. 👫 Arkadaş Yönetimi + 4. 🤖 Grup Fonksiyonları + 5. 💬 Konuşma Yönetimi + +Golang kullanılarak inşa edilmiş ve tüm platformlarda tutarlı bir erişim deneyimi sağlayacak şekilde çapraz platform dağıtımını destekler. + +👉 **[GO SDK Keşfet](https://github.com/openimsdk/openim-sdk-core)** + +## 🌐 OpenIMServer Hakkında + ++ **OpenIMServer** aşağıdaki özelliklere sahiptir: + - 🌐 Mikroservis mimarisi: Bir kapı ve çoklu rpc servisleri içeren küme modunu destekler. + - 🚀 Çeşitli dağıtım yöntemleri: Kaynak kodu, Kubernetes veya Docker aracılığıyla dağıtımı destekler. + - Büyük kullanıcı tabanı desteği: Yüz binlerce kullanıcısı olan süper büyük gruplar, on milyonlarca kullanıcı ve milyarlarca mesaj. + +### Geliştirilmiş İşlevsellik: + ++ **REST API**:OpenIMServer, işletmeleri gruplar oluşturma ve arka plan arayüzleri aracılığıyla itme mesajları gönderme gibi daha fazla işlevsellikle güçlendirmeyi amaçlayan iş sistemleri için REST API'leri sunar. ++ **Webhooks**:OpenIMServer, daha fazla iş formunu genişletme yetenekleri sağlayan geri çağırma özellikleri sunar. Geri çağırma, OpenIMServer'ın belirli bir olaydan önce veya sonra, örneğin bir mesaj göndermeden önce veya sonra iş sunucusuna bir istek göndermesi anlamına gelir. + +👉 **[Daha fazla bilgi edinin](https://docs.openim.io/guides/introduction/product)** + +## :building_construction: Genel Mimarisi + +Mimari diyagramımızla Open-IM-Server'ın işlevselliğinin kalbine dalın. + +![Overall Architecture](../images/architecture-layers.png) + +## :rocket: Hızlı Başlangıç + +Birçok platformu destekliyoruz. Web tarafında hızlı deneyim için adresler şunlardır: + +👉 **[OpenIM online demo](https://www.openim.io/zh/commercial)** + +🤲 Kullanıcı deneyimini kolaylaştırmak için çeşitli dağıtım çözümleri sunuyoruz. Aşağıdaki listeden dağıtım yönteminizi seçebilirsiniz: + ++ **[Kaynak Kodu Dağıtım Kılavuzu](https://docs.openim.io/guides/gettingStarted/imSourceCodeDeployment)** ++ **[Docker Dağıtım Kılavuzu](https://docs.openim.io/guides/gettingStarted/dockerCompose)** ++ **[Kubernetes Dağıtım Kılavuzu](https://docs.openim.io/guides/gettingStarted/k8s-deployment)** ++ **[Mac Geliştirici Dağıtım Kılavuzu](https://docs.openim.io/guides/gettingstarted/mac-deployment-guide)** + +## :hammer_and_wrench: OpenIM Geliştirmeye Başlamak + +[![Open in Dev Container](https://img.shields.io/static/v1?label=Dev%20Container&message=Open&color=blue&logo=visualstudiocode)](https://vscode.dev/github/openimsdk/open-im-server) + +OpenIM Amacımız, üst düzey bir açık kaynak topluluğu oluşturmaktır. [Topluluk deposunda](https://github.com/OpenIMSDK/community) bir dizi standartımız var. + +Bu Open-IM-Server deposuna katkıda bulunmak istiyorsanız, lütfen katkıda bulunanlar için [dokümantasyonumuzu](https://github.com/openimsdk/open-im-server/blob/main/CONTRIBUTING.md) okuyun. + +Başlamadan önce, lütfen değişikliklerinizin talep edildiğinden emin olun. Bunun için en iyisi, [yeni bir tartışma OLUŞTURMAK](https://github.com/openimsdk/open-im-server/discussions/new/choose) veya [Slack İletişimi](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q) kurmak, ya da bir sorun bulursanız, önce bunu [rapor](https://github.com/openimsdk/open-im-server/issues/new/choose) etmektir. + +- [OpenIM API Referansı](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/api.md) +- [OpenIM Bash Günlüğü](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/bash-log.md) +- [OpenIM CI/CD İşlemleri](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/cicd-actions.md) +- [OpenIM Kod Kuralları](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/code-conventions.md) +- [OpenIM Taahhüt Kuralları](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/commit.md) +- [OpenIM Geliştirme Kılavuzu](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/development.md) +- [OpenIM Dizin Yapısı](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/directory.md) +- [OpenIM Ortam Kurulumu](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/environment.md) +- [OpenIM Hata Kodu Referansı](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/error-code.md) +- [OpenIM Git İş Akışı](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/git-workflow.md) +- [OpenIM Git Cherry Pick Kılavuzu](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/gitcherry-pick.md) +- [OpenIM GitHub İş Akışı](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/github-workflow.md) +- [OpenIM Go Kod Standartları](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/go-code.md) +- [OpenIM Görüntü Kuralları](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/images.md) +- [OpenIM İlk Yapılandırma](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/init-config.md) +- [OpenIM Docker Kurulum Kılavuzu](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/install-docker.md) +- [OpenIM Linux Sistem Kurulumu](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/install-openim-linux-system.md) +- [OpenIM Linux Geliştirme Kılavuzu](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/linux-development.md) +- [OpenIM Yerel İşlemler Kılavuzu](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/local-actions.md) +- [OpenIM Günlük Kuralları](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/logging.md) +- [OpenIM Çevrimdışı Dağıtım](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/offline-deployment.md) +- [OpenIM Protoc Araçları](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/protoc-tools.md) +- [OpenIM Test Kılavuzu](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/test.md) +- [OpenIM Yardımcı Go](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/util-go.md) +- [OpenIM Makefile Yardımcı Programları](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/util-makefile.md) +- [OOpenIM Betik Yardımcı Programları](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/util-scripts.md) +- [OpenIM Sürümleme](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/version.md) +- [Arka uç yönetimi ve izleme dağıtımı](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/prometheus-grafana.md) +- [Mac Geliştirici Dağıtım Kılavuzu for OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/mac-developer-deployment-guide.md) + + +## :busts_in_silhouette: Topluluk + ++ 📚 [OpenIM Topluluğu](https://github.com/OpenIMSDK/community) ++ 💕 [OpenIM İlgi Grubu](https://github.com/Openim-sigs) ++ 🚀 [Slack topluluğumuza katılın](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q) ++ :eyes: [Wechat grubumuza katılın (微信群)](https://openim-1253691595.cos.ap-nanjing.myqcloud.com/WechatIMG20.jpeg) + +## :calendar: Topluluk Toplantıları + +Topluluğumuza herkesin katılmasını ve kod katkısında bulunmasını istiyoruz, hediyeler ve ödüller sunuyoruz ve sizi her Perşembe gecesi bize katılmaya davet ediyoruz. + +Konferansımız [OpenIM Slack'te](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q) 🎯, ardından Open-IM-Server boru hattını arayıp katılabilirsiniz. + +İki haftada bir yapılan toplantının [notlarını](https://github.com/orgs/OpenIMSDK/discussions/categories/meeting) [GitHub tartışmalarında alıyoruz](https://github.com/openimsdk/open-im-server/discussions/categories/meeting), Tarihi toplantı notlarımız ve toplantıların tekrarları [Google Docs'ta](https://docs.google.com/document/d/1nx8MDpuG74NASx081JcCpxPgDITNTpIIos0DS6Vr9GU/edit?usp=sharing) 📑 mevcut. + +## :eyes: Kimler OpenIM Kullanıyor + +Proje kullanıcılarının bir listesi için [kullanıcı vaka çalışmaları](https://github.com/OpenIMSDK/community/blob/main/ADOPTERS.md) sayfamıza göz atın. Bir 📝[yorum](https://github.com/openimsdk/open-im-server/issues/379) bırakmaktan ve kullanım durumunuzu paylaşmaktan çekinmeyin. + +## :page_facing_up: Lisans + +OpenIM, Apache 2.0 lisansı altında lisanslanmıştır. Tam lisans metni için [LICENSE'ı](https://github.com/openimsdk/open-im-server/tree/main/LICENSE) görün. + +Bu depoda, [assets/logo](../../assets/logo) ve [assets/logo-gif](../../assets/logo-gif) dizinlerinde görüntülenen [OpenIM](https://github.com/openimsdk/open-im-server) logosu, çeşitleri ve animasyonlu versiyonları, telif hakkı yasaları tarafından korunmaktadır. + +## 🔮 Katkıda bulunanlarımıza teşekkürler! + + + + \ No newline at end of file From 9dd44a75d0015474cbe295e106ecbe7465f3d3ab Mon Sep 17 00:00:00 2001 From: xuan <146319162+wxuanF@users.noreply.github.com> Date: Wed, 7 Feb 2024 21:51:45 +0800 Subject: [PATCH 036/188] docs: README KR (#1895) Signed-off-by: wxuanF <2569456943@qq.com> --- docs/readme/README-KR.md | 192 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 192 insertions(+) create mode 100644 docs/readme/README-KR.md diff --git a/docs/readme/README-KR.md b/docs/readme/README-KR.md new file mode 100644 index 0000000000..f7efc71a57 --- /dev/null +++ b/docs/readme/README-KR.md @@ -0,0 +1,192 @@ +

+ + + +

+ +
+ +[![Stars](https://img.shields.io/github/stars/openimsdk/open-im-server?style=for-the-badge&logo=github&colorB=ff69b4)](https://github.com/openimsdk/open-im-server/stargazers) +[![Forks](https://img.shields.io/github/forks/openimsdk/open-im-server?style=for-the-badge&logo=github&colorB=blue)](https://github.com/openimsdk/open-im-server/network/members) +[![Codecov](https://img.shields.io/codecov/c/github/openimsdk/open-im-server?style=for-the-badge&logo=codecov&colorB=orange)](https://app.codecov.io/gh/openimsdk/open-im-server) +[![Go Report Card](https://goreportcard.com/badge/github.com/openimsdk/open-im-server?style=for-the-badge)](https://goreportcard.com/report/github.com/openimsdk/open-im-server) +[![Go Reference](https://img.shields.io/badge/Go%20Reference-blue.svg?style=for-the-badge&logo=go&logoColor=white)](https://pkg.go.dev/github.com/openimsdk/open-im-server/v3) +[![License](https://img.shields.io/badge/license-Apache--2.0-green?style=for-the-badge)](https://github.com/openimsdk/open-im-server/blob/main/LICENSE) +[![Slack](https://img.shields.io/badge/Slack-500%2B-blueviolet?style=for-the-badge&logo=slack&logoColor=white)](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q) +[![Best Practices](https://img.shields.io/badge/Best%20Practices-purple?style=for-the-badge)](https://www.bestpractices.dev/projects/8045) +[![Good First Issues](https://img.shields.io/github/issues/openimsdk/open-im-server/good%20first%20issue?style=for-the-badge&logo=github)](https://github.com/openimsdk/open-im-server/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc+label%3A%22good+first+issue%22) +[![Language](https://img.shields.io/badge/Language-Go-blue.svg?style=for-the-badge&logo=go&logoColor=white)](https://golang.org/) + + +

+ Englist · + 中文 · + Українська · + Česky · + Magyar · + Español · + فارسی · + Français · + Deutsch · + Polski · + Indonesian · + Suomi · + മലയാളം · + 日本語 · + Nederlands · + Italiano · + Русский · + Português (Brasil) · + Esperanto · + 한국어 · + العربي · + Tiếng Việt · + Dansk · + Ελληνικά · + Türkçe +

+ + +
+ +

+ + +## Ⓜ️ OpenIM에 대하여 + +OpenIM은 채팅, 오디오-비디오 통화, 알림 및 AI 챗봇을 애플리케이션에 통합하기 위해 특별히 설계된 서비스 플랫폼입니다. 이 플랫폼은 강력한 API와 웹훅을 제공하여 개발자가 이러한 상호작용 기능을 애플리케이션에 쉽게 통합할 수 있게 합니다. OpenIM은 독립 실행형 채팅 애플리케이션이 아니라, 다른 애플리케이션들이 풍부한 커뮤니케이션 기능을 달성할 수 있도록 지원하는 플랫폼으로서의 역할을 합니다. 다음 다이어그램은 AppServer, AppClient, OpenIMServer, 및 OpenIMSDK 간의 상호작용을 자세히 설명하기 위해 제시되었습니다. + + + +![App-OpenIM Relationship](../images/oepnim-design.png) + +## 🚀 OpenIMSDK에 대하여 + + **OpenIMSDK**는**OpenIMServer**를 위해 특별히 제작된 IM SDK로, 클라이언트 애플리케이션 내에 내장하기 위해 설계되었습니다. 그 주요 기능 및 모듈은 다음과 같습니다: + + ++ 🌟 주요 기능: + + - 📦 로컬 스토리지 + - 🔔 리스너 콜백 + - 🛡️ API 래핑 + - 🌐 연결 관리 + + ## 📚 주요 모듈: + + 1. 🚀 초기화 및 로그인 + 2. 👤 사용자 관리 + 3. 👫 친구 관리 + 4. 🤖 그룹 기능 + 5. 💬 대화 처리 + +이는 Golang을 사용하여 구축되었으며, 모든 플랫폼에서 일관된 접근 경험을 보장하는 크로스 플랫폼 배포를 지원합니다. + +👉 **[GO SDK 탐색하기](https://github.com/openimsdk/openim-sdk-core)** + +## 🌐 OpenIMServer에 대하여 + ++ **OpenIMServer** 는 다음과 같은 특성을 가지고 있습니다: + - 🌐 마이크로서비스 아키텍처: 게이트웨이 및 다수의 rpc 서비스를 포함하는 클러스터 모드를 지원합니다. + - 🚀 다양한 배포 방법: 소스 코드, 쿠버네티스 또는 도커를 통한 배포를 지원합니다. + - 대규모 사용자 기반 지원: 수십만 명의 사용자를 포함하는 초대형 그룹, 수천만 명의 사용자 및 수십억 건의 메시지를 지원합니다. + +### 강화된 비즈니스 기능: + ++ **REST API**:OpenIMServer는 비즈니스 시스템을 위한 REST API를 제공하여, 백엔드 인터페이스를 통해 그룹 생성 및 푸시 메시지 전송과 같은 더 많은 기능을 비즈니스에 제공하기 위해 설계되었습니다. ++ **Webhooks**:OpenIMServer는 더 많은 비즈니스 형태를 확장할 수 있는 콜백 기능을 제공합니다. 콜백이란 메시지 전송 전후와 같은 특정 이벤트 전후에 OpenIMServer가 비즈니스 서버로 요청을 보내는 것을 의미합니다. + +👉 **[더 알아보기](https://docs.openim.io/guides/introduction/product)** + +## :building_construction: 전체 아키텍처 + +Open-IM-Server의 기능의 핵심으로 들어가 우리의 아키텍처 다이어그램을 자세히 살펴보세요. + +![Overall Architecture](../images/architecture-layers.png) + +## :rocket: 빠른 시작 + +우리는 많은 플랫폼을 지원합니다. 웹 측에서 빠른 체험을 위한 주소는 다음과 같습니다: + +👉 **[OpenIM online demo](https://www.openim.io/zh/commercial)** + +🤲 사용자 경험을 용이하게 하기 위해, 다양한 배포 솔루션을 제공합니다. 아래 목록에서 배포 방법을 선택할 수 있습니다: + ++ **[소스 코드 배포 가이드](https://docs.openim.io/guides/gettingStarted/imSourceCodeDeployment)** ++ **[docker 배포 가이드](https://docs.openim.io/guides/gettingStarted/dockerCompose)** ++ **[Kubernetes 배포 가이드](https://docs.openim.io/guides/gettingStarted/k8s-deployment)** ++ **[Mac 개발자 배포 가이드](https://docs.openim.io/guides/gettingstarted/mac-deployment-guide)** + +## :hammer_and_wrench: OpenIM 개발 시작하기 + +[![Open in Dev Container](https://img.shields.io/static/v1?label=Dev%20Container&message=Open&color=blue&logo=visualstudiocode)](https://vscode.dev/github/openimsdk/open-im-server) + +OpenIM의 목표는 최상위 수준의 오픈 소스 커뮤니티를 구축하는 것입니다. 우리는 [커뮤니티 리포지토리에서](https://github.com/OpenIMSDK/community) 일련의 표준을 가지고 있습니다. + +이 Open-IM-Server 리포지토리에 기여하고 싶다면, 우리의 [기여자 문서](https://github.com/openimsdk/open-im-server/blob/main/CONTRIBUTING.md)를 읽어주세요. + +시작하기 전에, 변경 사항이 필요한지 확인해 주세요. 가장 좋은 방법은 [새로운 토론](https://github.com/openimsdk/open-im-server/discussions/new/choose)을 생성하거나 [Slack 통신을](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q) 하거나, 문제를 발견했다면 먼저 [보고](https://github.com/openimsdk/open-im-server/issues/new/choose)하는 것입니다. + +- [OpenIM API 참조](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/api.md) +- [OpenIM Bash 로깅](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/bash-log.md) +- [OpenIM CI/CD 액션](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/cicd-actions.md) +- [OpenIM 코드 규칙](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/code-conventions.md) +- [OpenIM 커밋 가이드라인](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/commit.md) +- [OpenIM 개발 가이드](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/development.md) +- [OpenIM 디렉토리 구조](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/directory.md) +- [OpenIM 환경 설정](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/environment.md) +- [OpenIM 오류 코드 참조](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/error-code.md) +- [OpenIM Git 작업 흐름](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/git-workflow.md) +- [OpenIM Git 체리 픽 가이드](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/gitcherry-pick.md) +- [OpenIM GitHub 작업 흐름](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/github-workflow.md) +- [OpenIM Go 코드 표준](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/go-code.md) +- [OpenIM 이미지 가이드라인](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/images.md) +- [OpenIM 초기 구성](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/init-config.md) +- [OpenIM docker 설치 가이드](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/install-docker.md) +- [OpenIM OpenIM Linux 설치](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/install-openim-linux-system.md) +- [OpenIM Linux 개발 가이드](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/linux-development.md) +- [OpenIM 로컬 액션 가이드](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/local-actions.md) +- [OpenIM 로깅 규칙](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/logging.md) +- [OpenIM 오프라인 배포](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/offline-deployment.md) +- [OpenIM Protoc 도구](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/protoc-tools.md) +- [OpenIM 테스트 가이드](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/test.md) +- [OpenIM 유틸리티 Go](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/util-go.md) +- [OpenIM 메이크파일 유틸리티](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/util-makefile.md) +- [OpenIM 스크립트 유틸리티](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/util-scripts.md) +- [OpenIM 버전 관리](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/version.md) +- [백엔드 관리 및 모니터 배포](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/prometheus-grafana.md) +- [맥 개발자 배포 가이드 for OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/mac-developer-deployment-guide.md) + + +## :busts_in_silhouette: 커뮤니티 + ++ 📚 [OpenIM 커뮤니티](https://github.com/OpenIMSDK/community) ++ 💕 [OpenIM 관심 그룹](https://github.com/Openim-sigs) ++ 🚀 [우리의 Slack 커뮤니티에 가입하기](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q) ++ :eyes: [우리의 위챗(微信群)에 가입하기](https://openim-1253691595.cos.ap-nanjing.myqcloud.com/WechatIMG20.jpeg) + +## :calendar: 커뮤니티 미팅 + +우리는 누구나 커뮤니티에 참여하고 코드를 기여할 수 있도록 하며, 선물과 보상을 제공하며, 매주 목요일 밤에 여러분을 환영합니다. + +우리의 회의는 [OpenIM Slack](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q) 🎯에서 이루어지며, Open-IM-Server 파이프라인을 검색하여 참여할 수 있습니다. + +우리는 격주 회의의 메모를 [GitHub 토론](https://github.com/openimsdk/open-im-server/discussions/categories/meeting)에서 기록하며, 우리의 역사적 [회의](https://github.com/orgs/OpenIMSDK/discussions/categories/meeting) 노트와 회의 재생은 [Google Docs 📑](https://docs.google.com/document/d/1nx8MDpuG74NASx081JcCpxPgDITNTpIIos0DS6Vr9GU/edit?usp=sharing)에서 이용할 수 있습니다. + + +## :eyes: OpenIM을 사용하는 사람들 + +프로젝트 사용자 목록을 위한 우리의 [사용자 사례 연구](https://github.com/OpenIMSDK/community/blob/main/ADOPTERS.md) 페이지를 확인하세요. 사용 사례를 공유하고 싶다면 주저하지 말고 [📝코멘트](https://github.com/openimsdk/open-im-server/issues/379)를 남겨주세요. + +## :page_facing_up: 라이선스 + +OpenIM은 Apache 2.0 라이선스에 따라 라이선스가 부여됩니다. 전체 라이선스 텍스트는 [LICENSE](https://github.com/openimsdk/open-im-server/tree/main/LICENSE)에서 확인할 수 있습니다. + +이 리포지토리 [OpenIM](https://github.com/openimsdk/open-im-server)에 표시된 OpenIM 로고, 그 변형 및 애니메이션 버전은 [assets/logo](../../assets/logo) 및 [assets/logo-gif](../../assets/logo-gif) 디렉토리 아래에 있으며, 저작권 법에 의해 보호됩니다. + + +## 🔮 우리의 기여자들에게 감사합니다! + + + + \ No newline at end of file From 5046b3f6cec2804c4e240918b1f262c4b3988271 Mon Sep 17 00:00:00 2001 From: Seal Bell Date: Wed, 7 Feb 2024 21:52:38 +0800 Subject: [PATCH 037/188] docs:Modified the language naming of files and changed some error paths (#1898) * Add Simplified Chinese README.md * Add Ukrainian README.md * Add Traditional Chinese README.md * Add Czech README.md * Add Hungarian README.md * Add spanish README.md * Add Persian README.md * Add French README.md * Add German README.md * Add Japanese README.md * Add Polish README.md * Add Indonesian README.md * Add Finnish README.md * Add Malayalam README.md * Add Dutch README.md * Add Italian README.md * Add Russian README.md * Added Brazilian Portuguese README.md * Add Esperanto README.md * Add Korean README.md * Add Vietnamese README.md * Add Arabic README.md * Add Danish README.md * Add Greek README.md * Add Turkish README.md * Correct document suffix to distinguish language versions * Improve path and file naming corrections * Correct document suffix to distinguish language versions * Improve path and file naming corrections * Add Ukrainian README_uk.md --- README-zh_CN.md | 48 +++--- README.md | 48 +++--- docs/readme/README-UA.md | 7 - docs/readme/{README-JP.md => README_ja.md} | 48 +++--- docs/readme/README_uk.md | 187 +++++++++++++++++++++ 5 files changed, 259 insertions(+), 79 deletions(-) delete mode 100644 docs/readme/README-UA.md rename docs/readme/{README-JP.md => README_ja.md} (92%) create mode 100644 docs/readme/README_uk.md diff --git a/README-zh_CN.md b/README-zh_CN.md index e337688812..7eabfa509b 100644 --- a/README-zh_CN.md +++ b/README-zh_CN.md @@ -20,30 +20,30 @@

Englist · - 中文 · - Українська · - Česky · - Magyar · - Español · - فارسی · - Français · - Deutsch · - Polski · - Indonesian · - Suomi · - മലയാളം · - 日本語 · - Nederlands · - Italiano · - Русский · - Português (Brasil) · - Esperanto · - 한국어 · - العربي · - Tiếng Việt · - Dansk · - Ελληνικά · - Türkçe + 中文 · + Українська · + Česky · + Magyar · + Español · + فارسی · + Français · + Deutsch · + Polski · + Indonesian · + Suomi · + മലയാളം · + 日本語 · + Nederlands · + Italiano · + Русский · + Português (Brasil) · + Esperanto · + 한국어 · + العربي · + Tiếng Việt · + Dansk · + Ελληνικά · + Türkçe

diff --git a/README.md b/README.md index 8721bf2cee..a91024e492 100644 --- a/README.md +++ b/README.md @@ -20,30 +20,30 @@

Englist · - 中文 · - Українська · - Česky · - Magyar · - Español · - فارسی · - Français · - Deutsch · - Polski · - Indonesian · - Suomi · - മലയാളം · - 日本語 · - Nederlands · - Italiano · - Русский · - Português (Brasil) · - Esperanto · - 한국어 · - العربي · - Tiếng Việt · - Dansk · - Ελληνικά · - Türkçe + 中文 · + Українська · + Česky · + Magyar · + Español · + فارسی · + Français · + Deutsch · + Polski · + Indonesian · + Suomi · + മലയാളം · + 日本語 · + Nederlands · + Italiano · + Русский · + Português (Brasil) · + Esperanto · + 한국어 · + العربي · + Tiếng Việt · + Dansk · + Ελληνικά · + Türkçe

diff --git a/docs/readme/README-UA.md b/docs/readme/README-UA.md deleted file mode 100644 index 892e16d19f..0000000000 --- a/docs/readme/README-UA.md +++ /dev/null @@ -1,7 +0,0 @@ -

- - - -

- -
\ No newline at end of file diff --git a/docs/readme/README-JP.md b/docs/readme/README_ja.md similarity index 92% rename from docs/readme/README-JP.md rename to docs/readme/README_ja.md index c1b0eabf55..bd94b11538 100644 --- a/docs/readme/README-JP.md +++ b/docs/readme/README_ja.md @@ -20,30 +20,30 @@

Englist · - 中文 · - Українська · - Česky · - Magyar · - Español · - فارسی · - Français · - Deutsch · - Polski · - Indonesian · - Suomi · - മലയാളം · - 日本語 · - Nederlands · - Italiano · - Русский · - Português (Brasil) · - Esperanto · - 한국어 · - العربي · - Tiếng Việt · - Dansk · - Ελληνικά · - Türkçe + 中文 · + Українська · + Česky · + Magyar · + Español · + فارسی · + Français · + Deutsch · + Polski · + Indonesian · + Suomi · + മലയാളം · + 日本語 · + Nederlands · + Italiano · + Русский · + Português (Brasil) · + Esperanto · + 한국어 · + العربي · + Tiếng Việt · + Dansk · + Ελληνικά · + Türkçe

diff --git a/docs/readme/README_uk.md b/docs/readme/README_uk.md new file mode 100644 index 0000000000..30bc767305 --- /dev/null +++ b/docs/readme/README_uk.md @@ -0,0 +1,187 @@ +

+ + + +

+ +
+ +[![Stars](https://img.shields.io/github/stars/openimsdk/open-im-server?style=for-the-badge&logo=github&colorB=ff69b4)](https://github.com/openimsdk/open-im-server/stargazers) +[![Forks](https://img.shields.io/github/forks/openimsdk/open-im-server?style=for-the-badge&logo=github&colorB=blue)](https://github.com/openimsdk/open-im-server/network/members) +[![Codecov](https://img.shields.io/codecov/c/github/openimsdk/open-im-server?style=for-the-badge&logo=codecov&colorB=orange)](https://app.codecov.io/gh/openimsdk/open-im-server) +[![Go Report Card](https://goreportcard.com/badge/github.com/openimsdk/open-im-server?style=for-the-badge)](https://goreportcard.com/report/github.com/openimsdk/open-im-server) +[![Go Reference](https://img.shields.io/badge/Go%20Reference-blue.svg?style=for-the-badge&logo=go&logoColor=white)](https://pkg.go.dev/github.com/openimsdk/open-im-server/v3) +[![License](https://img.shields.io/badge/license-Apache--2.0-green?style=for-the-badge)](https://github.com/openimsdk/open-im-server/blob/main/LICENSE) +[![Slack](https://img.shields.io/badge/Slack-500%2B-blueviolet?style=for-the-badge&logo=slack&logoColor=white)](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q) +[![Best Practices](https://img.shields.io/badge/Best%20Practices-purple?style=for-the-badge)](https://www.bestpractices.dev/projects/8045) +[![Good First Issues](https://img.shields.io/github/issues/openimsdk/open-im-server/good%20first%20issue?style=for-the-badge&logo=github)](https://github.com/openimsdk/open-im-server/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc+label%3A%22good+first+issue%22) +[![Language](https://img.shields.io/badge/Language-Go-blue.svg?style=for-the-badge&logo=go&logoColor=white)](https://golang.org/) + + +

+ Englist · + 中文 · + Українська · + Česky · + Magyar · + Español · + فارسی · + Français · + Deutsch · + Polski · + Indonesian · + Suomi · + മലയാളം · + 日本語 · + Nederlands · + Italiano · + Русский · + Português (Brasil) · + Esperanto · + 한국어 · + العربي · + Tiếng Việt · + Dansk · + Ελληνικά · + Türkçe +

+ + +
+ +

+ +## Ⓜ️ Про OpenIM + +OpenIM — це сервісна платформа, спеціально розроблена для інтеграції чату, аудіо-відеодзвінків, сповіщень і чат-ботів штучного інтелекту в програми. Він надає ряд потужних API і веб-хуків, що дозволяє розробникам легко включати ці інтерактивні функції у свої програми. OpenIM не є окремою програмою для чату, а скоріше служить платформою для підтримки інших програм у досягненні широких можливостей спілкування. На наступній діаграмі детально показано взаємодію між AppServer, AppClient, OpenIMServer і OpenIMSDK. + +![App-OpenIM Relationship](../images/oepnim-design.png) + +## 🚀 Про OpenIMSDK + +**OpenIMSDK** – це пакет IM SDK, розроблений для **OpenIMServer**, створений спеціально для вбудовування в клієнтські програми. Його основні функції та модулі такі: + ++ 🌟 Основні характеристики: + + - 📦 Локальне сховище + - 🔔 Зворотні виклики слухача + - 🛡️ Обгортка API + - 🌐 Керування підключенням + ++ 📚 Основні модулі: + + 1. 🚀 Ініціалізація та вхід + 2. 👤 Керування користувачами + 3. 👫 Керування друзями + 4. 🤖 Групові функції + 5. 💬 Ведення розмови + +Він створений за допомогою Golang і підтримує кросплатформне розгортання, забезпечуючи послідовний доступ на всіх платформах. + +👉 **[Дослідити GO SDK](https://github.com/openimsdk/openim-sdk-core)** + +## 🌐 Про OpenIMServer + ++ **OpenIMServer** має такі характеристики: + - 🌐 Архітектура мікросервісу: підтримує режим кластера, включаючи шлюз і кілька служб rpc. + - 🚀 Різноманітні методи розгортання: підтримує розгортання через вихідний код, Kubernetes або Docker. + - Підтримка величезної бази користувачів: надвеликі групи із сотнями тисяч користувачів, десятками мільйонів користувачів і мільярдами повідомлень. + +### Розширена бізнес-функціональність: + ++ **REST API**: OpenIMServer пропонує REST API для бізнес-систем, спрямованих на надання компаніям додаткових можливостей, таких як створення груп і надсилання push-повідомлень через серверні інтерфейси. ++ **Веб-перехоплення**: OpenIMServer надає можливості зворотного виклику, щоб розширити більше бізнес-форм. Зворотний виклик означає, що OpenIMServer надсилає запит на бізнес-сервер до або після певної події, як зворотні виклики до або після надсилання повідомлення. + +👉 **[Докладніше](https://docs.openim.io/guides/introduction/product)** + +## :building_construction: Загальна архітектура + +Пориньте в серце функціональності Open-IM-Server за допомогою нашої діаграми архітектури. + +![Overall Architecture](../images/architecture-layers.png) + + +## :rocket: Швидкий початок + +Ми підтримуємо багато платформ. Ось адреси для швидкого використання веб-сайту: + +👉 **[Онлайн-демонстрація OpenIM](https://web-enterprise.rentsoft.cn/)** + +🤲 Щоб полегшити роботу користувача, ми пропонуємо різні рішення для розгортання. Ви можете вибрати спосіб розгортання зі списку нижче: + ++ **[Посібник із розгортання вихідного коду](https://docs.openim.io/guides/gettingStarted/imSourceCodeDeployment)** ++ **[Посібник із розгортання Docker](https://docs.openim.io/guides/gettingStarted/dockerCompose)** ++ **[Посібник із розгортання Kubernetes](https://docs.openim.io/guides/gettingStarted/k8s-deployment)** ++ **[Посібник із розгортання розробника Mac](https://docs.openim.io/guides/gettingstarted/mac-deployment-guide)** + +## :hammer_and_wrench: Щоб розпочати розробку OpenIM + +[![Відкрити в контейнері для розробників](https://img.shields.io/static/v1?label=Dev%20Container&message=Open&color=blue&logo=visualstudiocode)](https://vscode.dev/github/openimsdk/open-im-server) + +OpenIM. Наша мета — побудувати спільноту з відкритим кодом найвищого рівня. У нас є набір стандартів у [репозиторії спільноти](https://github.com/OpenIMSDK/community). + +Якщо ви хочете внести свій внесок у це сховище Open-IM-Server, прочитайте нашу [документацію для учасників](https://github.com/openimsdk/open-im-server/blob/main/CONTRIBUTING.md). + +Перш ніж почати, переконайтеся, що ваші зміни затребувані. Найкраще для цього створити [нове обговорення](https://github.com/openimsdk/open-im-server/discussions/new/choose) АБО [Нездійснене спілкування](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q)або, якщо ви виявите проблему, спершу [повідомити про неї](https://github.com/openimsdk/open-im-server/issues/new/choose). + +- [Довідка щодо API OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/api.md) +- [Ведення журналу OpenIM Bash](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/bash-log.md) +- [Дії OpenIM CI/CD](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/cicd-actions.md) +- [Положення про код OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/code-conventions.md) +- [Інструкції щодо фіксації OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/commit.md) +- [Посібник з розробки OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/development.md) +- [Структура каталогу OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/directory.md) +- [Налаштування середовища OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/environment.md) +- [Довідка про код помилки OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/error-code.md) +- [Робочий процес OpenIM Git](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/git-workflow.md) +- [Посібник із вибору OpenIM Git Cherry](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/gitcherry-pick.md) +- [Робочий процес OpenIM GitHub](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/github-workflow.md) +- [Стандарти коду OpenIM Go](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/go-code.md) +- [Інструкції щодо зображення OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/images.md) +- [Початкова конфігурація OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/init-config.md) +- [Посібник із встановлення OpenIM Docker](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/install-docker.md) +- [Встановлення системи OpenIM OpenIM Linux](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/install-openim-linux-system.md) +- [Посібник із розробки OpenIM Linux](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/linux-development.md) +- [Локальний посібник із дій OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/local-actions.md) +- [Положення про протоколювання OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/logging.md) +- [Офлайн-розгортання OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/offline-deployment.md) +- [Інструменти OpenIM Protoc](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/protoc-tools.md) +- [Посібник з тестування OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/test.md) +- [Утиліта OpenIM Go](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/util-go.md) +- [Утиліти OpenIM Makefile](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/util-makefile.md) +- [Утиліти сценарію OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/util-scripts.md) +- [Версії OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/version.md) +- [Керування серверною частиною та моніторинг розгортання](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/prometheus-grafana.md) +- [Посібник із розгортання розробника Mac для OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/mac-developer-deployment-guide.md) + + +## :busts_in_silhouette: Спільнота + ++ 📚 [Спільнота OpenIM](https://github.com/OpenIMSDK/community) ++ 💕 [Група інтересів OpenIM](https://github.com/Openim-sigs) ++ 🚀 [Приєднайтеся до нашої спільноти Slack](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q) ++ :eyes: [Приєднайтеся до нашого wechat](https://openim-1253691595.cos.ap-nanjing.myqcloud.com/WechatIMG20.jpeg) + +## :calendar: Збори громади + +Ми хочемо, щоб будь-хто долучився до нашої спільноти та додав код, ми пропонуємо подарунки та нагороди, і ми запрошуємо вас приєднатися до нас щочетверга ввечері. + +Наша конференція знаходиться в [OpenIM Slack](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q) 🎯, тоді ви можете шукати конвеєр Open-IM-Server, щоб приєднатися. + +Ми робимо нотатки про кожну [двотижневу зустріч](https://github.com/orgs/OpenIMSDK/discussions/categories/meeting)в [обговореннях GitHub](https://github.com/openimsdk/open-im-server/discussions/categories/meeting). Наші історичні нотатки зустрічей, а також повтори зустрічей доступні в[Google Docs :bookmark_tabs:](https://docs.google.com/document/d/1nx8MDpuG74NASx081JcCpxPgDITNTpIIos0DS6Vr9GU/edit?usp=sharing). + +## :eyes: Хто використовує OpenIM + +Перегляньте нашу сторінку [тематичні дослідження користувачів](https://github.com/OpenIMSDK/community/blob/main/ADOPTERS.md), щоб отримати список користувачів проекту. Не соромтеся залишити [📝коментар](https://github.com/openimsdk/open-im-server/issues/379)і поділитися своїм випадком використання. + +## :page_facing_up: Ліцензія + +OpenIM ліцензовано за ліцензією Apache 2.0. Див. [ЛІЦЕНЗІЯ](https://github.com/openimsdk/open-im-server/tree/main/LICENSE) для повного тексту ліцензії. + +Логотип OpenIM, включаючи його варіації та анімовані версії, що відображаються в цьому сховищі[OpenIM](https://github.com/openimsdk/open-im-server)у каталогах [assets/logo](./assets/logo)і [assets/logo-gif](assets/logo-gif) , захищені законами про авторське право. + +## 🔮 Дякуємо нашим дописувачам! + + + + From 90bd53b7dd1048d65d405b319dd6f76a833ffc8e Mon Sep 17 00:00:00 2001 From: xuan <146319162+wxuanF@users.noreply.github.com> Date: Sun, 18 Feb 2024 17:23:22 +0800 Subject: [PATCH 038/188] docs: renmae README files about other languages (#1915) Signed-off-by: wxuanF <2569456943@qq.com> --- README-zh_CN.md => README_zh_CN.md | 0 docs/readme/{README-KR.md => README_ko.md} | 0 docs/readme/{README-TR.md => README_tr.md} | 48 +++++++++++----------- 3 files changed, 24 insertions(+), 24 deletions(-) rename README-zh_CN.md => README_zh_CN.md (100%) rename docs/readme/{README-KR.md => README_ko.md} (100%) rename docs/readme/{README-TR.md => README_tr.md} (91%) diff --git a/README-zh_CN.md b/README_zh_CN.md similarity index 100% rename from README-zh_CN.md rename to README_zh_CN.md diff --git a/docs/readme/README-KR.md b/docs/readme/README_ko.md similarity index 100% rename from docs/readme/README-KR.md rename to docs/readme/README_ko.md diff --git a/docs/readme/README-TR.md b/docs/readme/README_tr.md similarity index 91% rename from docs/readme/README-TR.md rename to docs/readme/README_tr.md index ff545e6441..ca2a816db0 100644 --- a/docs/readme/README-TR.md +++ b/docs/readme/README_tr.md @@ -20,30 +20,30 @@

Englist · - 中文 · - Українська · - Česky · - Magyar · - Español · - فارسی · - Français · - Deutsch · - Polski · - Indonesian · - Suomi · - മലയാളം · - 日本語 · - Nederlands · - Italiano · - Русский · - Português (Brasil) · - Esperanto · - 한국어 · - العربي · - Tiếng Việt · - Dansk · - Ελληνικά · - Türkçe + 中文 · + Українська · + Česky · + Magyar · + Español · + فارسی · + Français · + Deutsch · + Polski · + Indonesian · + Suomi · + മലയാളം · + 日本語 · + Nederlands · + Italiano · + Русский · + Português (Brasil) · + Esperanto · + 한국어 · + العربي · + Tiếng Việt · + Dansk · + Ελληνικά · + Türkçe

From 5e7138034cb63ea407a19ecc2babd26ae6388a97 Mon Sep 17 00:00:00 2001 From: Seal Bell Date: Sun, 18 Feb 2024 17:36:15 +0800 Subject: [PATCH 039/188] Docs: Modify the wrong file name (#1914) --- docs/readme/README_ko.md | 48 ++++++++++++++++++++-------------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/docs/readme/README_ko.md b/docs/readme/README_ko.md index f7efc71a57..bd7a1aed37 100644 --- a/docs/readme/README_ko.md +++ b/docs/readme/README_ko.md @@ -20,30 +20,30 @@

Englist · - 中文 · - Українська · - Česky · - Magyar · - Español · - فارسی · - Français · - Deutsch · - Polski · - Indonesian · - Suomi · - മലയാളം · - 日本語 · - Nederlands · - Italiano · - Русский · - Português (Brasil) · - Esperanto · - 한국어 · - العربي · - Tiếng Việt · - Dansk · - Ελληνικά · - Türkçe + 中文 · + Українська · + Česky · + Magyar · + Español · + فارسی · + Français · + Deutsch · + Polski · + Indonesian · + Suomi · + മലയാളം · + 日本語 · + Nederlands · + Italiano · + Русский · + Português (Brasil) · + Esperanto · + 한국어 · + العربي · + Tiếng Việt · + Dansk · + Ελληνικά · + Türkçe

From 6186d657e2ef807c65999ae40d2626949bd21c26 Mon Sep 17 00:00:00 2001 From: Brabem <69128477+luhaoling@users.noreply.github.com> Date: Sun, 18 Feb 2024 18:42:56 +0800 Subject: [PATCH 040/188] feat: add docker-compse-1.yml and cancel the openim-admin annotate in docker-compose.yml (#1881) * fix: del the manager config and manger init statement * fix: fix the Manger judge condition * fix: fix revokeMsg error * fix: find erors * fix: find error * fix: fix the AdminAccount error * fix: del the debug statement * fix: fix the component check func * fix: fix the get zkAddress error * fix: fix the kafka client close error * fix: add env in minio connected * fix: del the minio env * fix: fix the go.mod tools version * fix: del get env in minio conneted * feat: add GetUserToken api and add ex field in GetSortedConversationList resp * fix: fix the go.mod version * fix: add lack method * fix: add a method * fix: add lack implement * fix: fix the tools pkg version * fix: del the unuser pkg * fix: add Limiting judgement of get admin token * feat: add a yml of docker-compose-1.yml * fix: add the lack content in docker-compose-1.yml * fix: add the tips in docker-compose.yml --------- Co-authored-by: OpenIM-Gordon <46924906+FGadvancer@users.noreply.github.com> --- docker-compose-1.yml | 298 +++++++++++++++++++++++ docker-compose.yml | 25 +- internal/rpc/conversation/conversaion.go | 1 - pkg/authverify/token.go | 3 +- 4 files changed, 312 insertions(+), 15 deletions(-) create mode 100644 docker-compose-1.yml diff --git a/docker-compose-1.yml b/docker-compose-1.yml new file mode 100644 index 0000000000..39fc944ce2 --- /dev/null +++ b/docker-compose-1.yml @@ -0,0 +1,298 @@ +#fixme Clone openIM Server project before using docker-compose,project address:https://github.com/OpenIMSDK/Open-IM-Server.git +# The command that triggers this file to pull the image is "docker compose up -f" +version: '3' + +networks: + server: + driver: bridge + ipam: + driver: default + config: + - subnet: '${DOCKER_BRIDGE_SUBNET:-172.28.0.0/16}' + gateway: '${DOCKER_BRIDGE_GATEWAY:-172.28.0.1}' + +services: + mongodb: + image: mongo:${MONGODB_IMAGE_VERSION-6.0.2} + ports: + - "${MONGO_PORT:-37017}:27017" + container_name: mongo + command: ["/bin/bash", "-c", "/docker-entrypoint-initdb.d/mongo-init.sh || true; docker-entrypoint.sh mongod --wiredTigerCacheSizeGB 1 --auth"] + volumes: + - "${DATA_DIR:-./}/components/mongodb/data/db:/data/db" + - "${DATA_DIR:-./}/components/mongodb/data/logs:/data/logs" + - "${DATA_DIR:-./}/components/mongodb/data/conf:/etc/mongo" + - "./scripts/mongo-init.sh:/docker-entrypoint-initdb.d/mongo-init.sh:ro" + environment: + - TZ=Asia/Shanghai + - wiredTigerCacheSizeGB=1 + - MONGO_INITDB_ROOT_USERNAME=${MONGO_USERNAME:-root} + - MONGO_INITDB_ROOT_PASSWORD=${MONGO_PASSWORD:-openIM123} + - MONGO_INITDB_DATABASE=${MONGO_DATABASE:-openim_v3} + - MONGO_OPENIM_USERNAME=${MONGO_OPENIM_USERNAME:-openIM} # Non-root username + - MONGO_OPENIM_PASSWORD=${MONGO_OPENIM_PASSWORD:-openIM123456} # Non-root password + restart: always + networks: + server: + ipv4_address: ${MONGO_NETWORK_ADDRESS:-172.28.0.2} + + redis: + image: redis:${REDIS_IMAGE_VERSION:-7.0.0} + container_name: redis + ports: + - "${REDIS_PORT:-16379}:6379" + volumes: + - "${DATA_DIR:-./}/components/redis/data:/data" + - "${DATA_DIR:-./}/components/redis/config/redis.conf:/usr/local/redis/config/redis.conf" + environment: + TZ: Asia/Shanghai + restart: always + sysctls: + net.core.somaxconn: 1024 + command: redis-server --requirepass ${REDIS_PASSWORD:-openIM123} --appendonly yes + networks: + server: + ipv4_address: ${REDIS_NETWORK_ADDRESS:-172.28.0.3} + + zookeeper: + image: bitnami/zookeeper:${ZOOKEEPER_IMAGE_VERSION:-3.8} + container_name: zookeeper + ports: + - "${ZOOKEEPER_PORT:-12181}:2181" + volumes: + - "/etc/localtime:/etc/localtime" + environment: + - ALLOW_ANONYMOUS_LOGIN=yes + - TZ="Asia/Shanghai" + restart: always + networks: + server: + ipv4_address: ${ZOOKEEPER_NETWORK_ADDRESS:-172.28.0.5} + + kafka: + image: 'bitnami/kafka:${KAFKA_IMAGE_VERSION:-3.5.1}' + container_name: kafka + restart: always + user: ${KAFKA_USER:-root} + ports: + - "${KAFKA_PORT:-19094}:9094" + volumes: + - ./scripts/create-topic.sh:/opt/bitnami/kafka/create-topic.sh + - "${DATA_DIR:-./}/components/kafka:/bitnami/kafka" + command: > + bash -c "/opt/bitnami/scripts/kafka/run.sh & sleep 5; /opt/bitnami/kafka/create-topic.sh; wait" + environment: + - TZ=Asia/Shanghai + - KAFKA_CFG_NODE_ID=0 + - KAFKA_CFG_PROCESS_ROLES=controller,broker + - KAFKA_CFG_CONTROLLER_QUORUM_VOTERS=0@:9093 + - KAFKA_CFG_LISTENERS=PLAINTEXT://:9092,CONTROLLER://:9093,EXTERNAL://:9094 + - KAFKA_CFG_ADVERTISED_LISTENERS=PLAINTEXT://kafka:9092,EXTERNAL://${DOCKER_BRIDGE_GATEWAY:-172.28.0.1}:${KAFKA_PORT:-19094} + # - KAFKA_CFG_ADVERTISED_LISTENERS=PLAINTEXT://kafka:9092,EXTERNAL://127.0.0.1:${KAFKA_PORT:-19094} # Mac Deployment + - KAFKA_CFG_LISTENER_SECURITY_PROTOCOL_MAP=CONTROLLER:PLAINTEXT,EXTERNAL:PLAINTEXT,PLAINTEXT:PLAINTEXT + - KAFKA_CFG_CONTROLLER_LISTENER_NAMES=CONTROLLER + networks: + server: + ipv4_address: ${KAFKA_NETWORK_ADDRESS:-172.28.0.4} + + minio: + image: minio/minio:${MINIO_IMAGE_VERSION:-RELEASE.2024-01-11T07-46-16Z} + ports: + - "${MINIO_PORT:-10005}:9000" + - "9090:9090" + container_name: minio + volumes: + - "${DATA_DIR:-./}/components/mnt/data:/data" + - "${DATA_DIR:-./}/components/mnt/config:/root/.minio" + environment: + MINIO_ROOT_USER: "${MINIO_ACCESS_KEY:-root}" + MINIO_ROOT_PASSWORD: "${MINIO_SECRET_KEY:-openIM123}" + restart: always + command: minio server /data --console-address ':9090' + networks: + server: + ipv4_address: ${MINIO_NETWORK_ADDRESS:-172.28.0.6} + + openim-web: + image: ${IMAGE_REGISTRY:-ghcr.io/openimsdk}/openim-web:${OPENIM_WEB_IMAGE_VERSION:-v3.5.0-docker} + container_name: openim-web + platform: linux/amd64 + restart: always + ports: + - "${OPENIM_WEB_PORT:-11001}:80" + networks: + server: + ipv4_address: ${OPENIM_WEB_NETWORK_ADDRESS:-172.28.0.7} + + openim-admin: + # https://github.com/openimsdk/open-im-server/issues/1662 + image: ${IMAGE_REGISTRY:-ghcr.io/openimsdk}/openim-admin:${ADMIN_FRONT_VERSION:-toc-base-open-docker.35} + container_name: openim-admin + platform: linux/amd64 + restart: always + ports: + - "${OPENIM_ADMIN_FRONT_PORT:-11002}:80" + networks: + server: + ipv4_address: ${OPENIM_ADMIN_FRONT_NETWORK_ADDRESS:-172.28.0.13} + + prometheus: + image: prom/prometheus + container_name: prometheus + hostname: prometheus + restart: always + volumes: + - "${DATA_DIR:-./}/config/instance-down-rules.yml:/etc/prometheus/instance-down-rules.yml" + - "${DATA_DIR:-./}/config/prometheus.yml:/etc/prometheus/prometheus.yml" + ports: + - "${PROMETHEUS_PORT:-19090}:9090" + networks: + server: + ipv4_address: ${PROMETHEUS_NETWORK_ADDRESS:-172.28.0.10} + + alertmanager: + image: prom/alertmanager + container_name: alertmanager + hostname: alertmanager + restart: always + volumes: + - ${DATA_DIR:-./}/config/alertmanager.yml:/etc/alertmanager/alertmanager.yml + - ${DATA_DIR:-./}/config/email.tmpl:/etc/alertmanager/email.tmpl + ports: + - "${ALERT_MANAGER_PORT:-19093}:9093" + networks: + server: + ipv4_address: ${ALERT_MANAGER_NETWORK_ADDRESS:-172.28.0.14} + + grafana: + image: grafana/grafana + container_name: grafana + hostname: grafana + user: root + restart: always + ports: + - "${GRAFANA_PORT:-13000}:3000" + volumes: + - "${DATA_DIR:-./}/components/grafana:/var/lib/grafana" + networks: + server: + ipv4_address: ${GRAFANA_NETWORK_ADDRESS:-172.28.0.11} + + node-exporter: + image: quay.io/prometheus/node-exporter + container_name: node-exporter + hostname: node-exporter + restart: always + ports: + - "${NODE_EXPORTER_PORT:-19100}:9100" + networks: + server: + ipv4_address: ${NODE_EXPORTER_NETWORK_ADDRESS:-172.28.0.12} + +### Source code deployment does not require pulling the following mirrors + + # openim-server: + # image: ${IMAGE_REGISTRY:-ghcr.io/openimsdk}/openim-server:${SERVER_IMAGE_VERSION:-main} + # container_name: openim-server + # ports: + # - "${OPENIM_WS_PORT:-10001}:${OPENIM_WS_PORT:-10001}" + # - "${API_OPENIM_PORT:-10002}:${API_OPENIM_PORT:-10002}" + # - "${API_PROM_PORT:-20100}:${API_PROM_PORT:-20100}" + # - "${USER_PROM_PORT:-20110}:${USER_PROM_PORT:-20110}" + # - "${FRIEND_PROM_PORT:-20120}:${FRIEND_PROM_PORT:-20120}" + # - "${MESSAGE_PROM_PORT:-20130}:${MESSAGE_PROM_PORT:-20130}" + # - "${MSG_GATEWAY_PROM_PORT:-20140}:${MSG_GATEWAY_PROM_PORT:-20140}" + # - "${GROUP_PROM_PORT:-20150}:${GROUP_PROM_PORT:-20150}" + # - "${AUTH_PROM_PORT:-20160}:${AUTH_PROM_PORT:-20160}" + # - "${PUSH_PROM_PORT:-20170}:${PUSH_PROM_PORT:-20170}" + # - "${CONVERSATION_PROM_PORT:-20230}:${CONVERSATION_PROM_PORT:-20230}" + # - "${RTC_PROM_PORT:-21300}:${RTC_PROM_PORT:-21300}" + # - "${THIRD_PROM_PORT:-21301}:${THIRD_PROM_PORT:-21301}" + # - "21400-21403:21400-21403" + # healthcheck: + # test: ["CMD", "/openim/openim-server/scripts/check-all.sh"] + # interval: 120s + # timeout: 30s + # retries: 5 + # env_file: + # - .env + # environment: + # - OPENIM_IP=${OPENIM_IP:-127.0.0.1} + # volumes: + # - "${DATA_DIR:-./}/openim-server/logs:/openim/openim-server/logs" + # - "${DATA_DIR:-./}/openim-server/_output/logs:/openim/openim-server/_output/logs" + # - "${DATA_DIR:-./}/openim-server/config:/openim/openim-server/config" + # restart: always + # depends_on: + # - kafka + # - mysql + # - mongodb + # - redis + # - minio + # logging: + # driver: json-file + # options: + # max-size: "1g" + # max-file: "2" + # networks: + # server: + # ipv4_address: ${OPENIM_SERVER_NETWORK_ADDRESS:-172.28.0.8} + + ### TODO: mysql is required to deploy the openim-chat component + # mysql: + # image: mysql:${MYSQL_IMAGE_VERSION:-5.7} + # platform: linux/amd64 + # ports: + # - "${MYSQL_PORT:-13306}:3306" + # container_name: mysql + # volumes: + # - "${DATA_DIR:-./}/components/mysql/data:/var/lib/mysql" + # - "/etc/localtime:/etc/localtime" + # environment: + # MYSQL_ROOT_PASSWORD: "${MYSQL_PASSWORD:-openIM123}" + # restart: always + # networks: + # server: + # ipv4_address: ${MYSQL_NETWORK_ADDRESS:-172.28.0.15} + + # openim-chat: + # image: ${IMAGE_REGISTRY:-ghcr.io/openimsdk}/openim-chat:${CHAT_IMAGE_VERSION:-main} + # container_name: openim-chat + # healthcheck: + # test: ["CMD", "/openim/openim-chat/scripts/check_all.sh"] + # interval: 60s + # timeout: 30s + # retries: 5 + # env_file: + # - .env + # environment: + # - ZOOKEEPER_ADDRESS=${DOCKER_BRIDGE_GATEWAY:-172.28.0.1} + # - ZOOKEEPER_PORT=${ZOOKEEPER_PORT:-12181} + # - OPENIM_SERVER_ADDRESS=http://${OPENIM_SERVER_ADDRESS:-172.28.0.1} + # - API_OPENIM_PORT=${API_OPENIM_PORT:-10002} + # - MYSQL_ADDRESS=${DOCKER_BRIDGE_GATEWAY:-172.28.0.1} + # - MYSQL_PORT=${MYSQL_PORT:-13306} + # - REDIS_ADDRESS=${DOCKER_BRIDGE_GATEWAY:-172.28.0.1} + # - REDIS_PORT=${REDIS_PORT:-16379} + # ports: + # - "${OPENIM_CHAT_API_PORT:-10008}:10008" + # - "${OPENIM_ADMIN_API_PORT:-10009}:10009" + # volumes: + # - "${DATA_DIR:-./}/components/openim-chat/logs:/openim/openim-chat/logs" + # - "${DATA_DIR:-./}/components/openim-chat/_output/logs:/openim/openim-chat/_output/logs" + # - "${DATA_DIR:-./}/components/openim-chat/config:/openim/openim-chat/config" + # restart: always + # # user: root:root + # depends_on: + # - mysql + # - kafka + # - redis + # - zookeeper + # logging: + # driver: json-file + # options: + # max-size: "1g" + # max-file: "2" + # networks: + # server: + # ipv4_address: ${OPENIM_CHAT_NETWORK_ADDRESS:-172.28.0.9} diff --git a/docker-compose.yml b/docker-compose.yml index dcf7518e21..8538eec832 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,4 +1,5 @@ #fixme Clone openIM Server project before using docker-compose,project address:https://github.com/OpenIMSDK/Open-IM-Server.git +# The command that triggers this file to pull the image is "docker compose up -d". version: '3' networks: @@ -123,6 +124,18 @@ services: server: ipv4_address: ${OPENIM_WEB_NETWORK_ADDRESS:-172.28.0.7} + openim-admin: + # https://github.com/openimsdk/open-im-server/issues/1662 + image: ${IMAGE_REGISTRY:-ghcr.io/openimsdk}/openim-admin:${ADMIN_FRONT_VERSION:-toc-base-open-docker.35} + container_name: openim-admin + platform: linux/amd64 + restart: always + ports: + - "${OPENIM_ADMIN_FRONT_PORT:-11002}:80" + networks: + server: + ipv4_address: ${OPENIM_ADMIN_FRONT_NETWORK_ADDRESS:-172.28.0.13} + ### TODO: Uncomment, or deploy using openim docker: https://github.com/openimsdk/openim-docker ### Uncomment and configure the following services as needed @@ -232,18 +245,6 @@ services: # server: # ipv4_address: ${OPENIM_CHAT_NETWORK_ADDRESS:-172.28.0.9} - # openim-admin: - # # https://github.com/openimsdk/open-im-server/issues/1662 - # image: ${IMAGE_REGISTRY:-ghcr.io/openimsdk}/openim-admin:${ADMIN_FRONT_VERSION:-toc-base-open-docker.35} - # container_name: openim-admin - # platform: linux/amd64 - # restart: always - # ports: - # - "${OPENIM_ADMIN_FRONT_PORT:-11002}:80" - # networks: - # server: - # ipv4_address: ${OPENIM_ADMIN_FRONT_NETWORK_ADDRESS:-172.28.0.13} - # prometheus: # image: prom/prometheus # container_name: prometheus diff --git a/internal/rpc/conversation/conversaion.go b/internal/rpc/conversation/conversaion.go index 8558a23ea4..903ecbb188 100644 --- a/internal/rpc/conversation/conversaion.go +++ b/internal/rpc/conversation/conversaion.go @@ -50,7 +50,6 @@ type conversationServer struct { conversationDatabase controller.ConversationDatabase conversationNotificationSender *notification.ConversationNotificationSender } - func (c *conversationServer) GetConversationNotReceiveMessageUserIDs( ctx context.Context, req *pbconversation.GetConversationNotReceiveMessageUserIDsReq, diff --git a/pkg/authverify/token.go b/pkg/authverify/token.go index 97bb033916..b951bf219c 100644 --- a/pkg/authverify/token.go +++ b/pkg/authverify/token.go @@ -48,8 +48,7 @@ func CheckAccessV3(ctx context.Context, ownerUserID string) (err error) { } func IsAppManagerUid(ctx context.Context) bool { - return (len(config.Config.Manager.UserID) > 0 && utils.IsContain(mcontext.GetOpUserID(ctx), config.Config.Manager.UserID)) || - utils.IsContain(mcontext.GetOpUserID(ctx), config.Config.IMAdmin.UserID) + return (len(config.Config.Manager.UserID) > 0 && utils.IsContain(mcontext.GetOpUserID(ctx), config.Config.Manager.UserID)) || utils.IsContain(mcontext.GetOpUserID(ctx), config.Config.IMAdmin.UserID) } func CheckAdmin(ctx context.Context) error { From bd354f9a629fc38a18277f78a7c879a49fa2e55e Mon Sep 17 00:00:00 2001 From: longyuqing112 <105913803+longyuqing112@users.noreply.github.com> Date: Sun, 18 Feb 2024 18:43:23 +0800 Subject: [PATCH 041/188] docs: add README-ES (#1896) Signed-off-by: kubbot & kubecub <3293172751ysy@gmail.com> Co-authored-by: kubbot & kubecub <3293172751ysy@gmail.com> --- docs/readme/README-ES.md | 193 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 193 insertions(+) create mode 100644 docs/readme/README-ES.md diff --git a/docs/readme/README-ES.md b/docs/readme/README-ES.md new file mode 100644 index 0000000000..f058617a09 --- /dev/null +++ b/docs/readme/README-ES.md @@ -0,0 +1,193 @@ +

+ + + +

+ +
+ +[![Stars](https://img.shields.io/github/stars/openimsdk/open-im-server?style=for-the-badge&logo=github&colorB=ff69b4)](https://github.com/openimsdk/open-im-server/stargazers) +[![Forks](https://img.shields.io/github/forks/openimsdk/open-im-server?style=for-the-badge&logo=github&colorB=blue)](https://github.com/openimsdk/open-im-server/network/members) +[![Codecov](https://img.shields.io/codecov/c/github/openimsdk/open-im-server?style=for-the-badge&logo=codecov&colorB=orange)](https://app.codecov.io/gh/openimsdk/open-im-server) +[![Go Report Card](https://goreportcard.com/badge/github.com/openimsdk/open-im-server?style=for-the-badge)](https://goreportcard.com/report/github.com/openimsdk/open-im-server) +[![Go Reference](https://img.shields.io/badge/Go%20Reference-blue.svg?style=for-the-badge&logo=go&logoColor=white)](https://pkg.go.dev/github.com/openimsdk/open-im-server/v3) +[![License](https://img.shields.io/badge/license-Apache--2.0-green?style=for-the-badge)](https://github.com/openimsdk/open-im-server/blob/main/LICENSE) +[![Slack](https://img.shields.io/badge/Slack-500%2B-blueviolet?style=for-the-badge&logo=slack&logoColor=white)](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q) +[![Best Practices](https://img.shields.io/badge/Best%20Practices-purple?style=for-the-badge)](https://www.bestpractices.dev/projects/8045) +[![Good First Issues](https://img.shields.io/github/issues/openimsdk/open-im-server/good%20first%20issue?style=for-the-badge&logo=github)](https://github.com/openimsdk/open-im-server/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc+label%3A%22good+first+issue%22) +[![Language](https://img.shields.io/badge/Language-Go-blue.svg?style=for-the-badge&logo=go&logoColor=white)](https://golang.org/) + + +

+ Englist · + 中文 · + Українська · + Česky · + Magyar · + Español · + فارسی · + Français · + Deutsch · + Polski · + Indonesian · + Suomi · + മലയാളം · + 日本語 · + Nederlands · + Italiano · + Русский · + Português (Brasil) · + Esperanto · + 한국어 · + العربي · + Tiếng Việt · + Dansk · + Ελληνικά · + Türkçe +

+ + +
+ +

+ +## Ⓜ️ Acerca de OpenIM + +OpenIM es una plataforma de servicio diseñada específicamente para integrar chat, llamadas de audio y video, notificaciones y chatbots de IA en aplicaciones. Proporciona una gama de potentes API y Webhooks, lo que permite a los desarrolladores incorporar fácilmente estas características interactivas en sus aplicaciones. OpenIM no es una aplicación de chat independiente, sino que sirve como una plataforma para apoyar a otras aplicaciones en lograr funcionalidades de comunicación enriquecidas. El siguiente diagrama ilustra la interacción entre AppServer, AppClient, OpenIMServer y OpenIMSDK para explicar en detalle. + +![Relación App-OpenIM](./docs/images/oepnim-design.png) + +## 🚀 Acerca de OpenIMSDK + +**OpenIMSDK** es un SDK de mensajería instantánea diseñado para **OpenIMServer**, creado específicamente para su incorporación en aplicaciones cliente. Sus principales características y módulos son los siguientes: + ++ 🌟 Características Principales: + + - 📦 Almacenamiento local + - 🔔 Callbacks de escuchas + - 🛡️ Envoltura de API + - 🌐 Gestión de conexiones + ++ 📚 Módulos Principales: + + 1. 🚀 Inicialización y acceso + 2. 👤 Gestión de usuarios + 3. 👫 Gestión de amigos + 4. 🤖 Funciones de grupo + 5. 💬 Manejo de conversaciones + +Está construido con Golang y soporta despliegue multiplataforma, asegurando una experiencia de acceso consistente en todas las plataformas. + +👉 **[Explora el SDK de GO](https://github.com/openimsdk/openim-sdk-core)** + +## 🌐 Acerca de OpenIMServer + ++ **OpenIMServer** tiene las siguientes características: + - 🌐 Arquitectura de microservicios: Soporta modo cluster, incluyendo un gateway y múltiples servicios rpc. + - 🚀 Métodos de despliegue diversos: Soporta el despliegue a través de código fuente, Kubernetes o Docker. + - Soporte para una base de usuarios masiva: Grupos super grandes con cientos de miles de usuarios, decenas de millones de usuarios y miles de millones de mensajes. + + + +### Funcionalidad Empresarial Mejorada: + ++ **API REST**: OpenIMServer ofrece APIs REST para sistemas empresariales, destinadas a empoderar a las empresas con más funcionalidades, como la creación de grupos y el envío de mensajes push a través de interfaces de backend. ++ **Webhooks**: OpenIMServer proporciona capacidades de callback para extender más formas de negocio. Un callback significa que OpenIMServer envía una solicitud al servidor empresarial antes o después de un cierto evento, como callbacks antes o después de enviar un mensaje. + +👉 **[Aprende más](https://docs.openim.io/guides/introduction/product)** + +## :building_construction: Arquitectura General + +Adéntrate en el corazón de la funcionalidad de Open-IM-Server con nuestro diagrama de arquitectura. + +![Arquitectura General](./docs/images/architecture-layers.png) + + +## :rocket: Inicio Rápido + + +:rocket: Inicio Rápido +Apoyamos muchas plataformas. Aquí están las direcciones para una experiencia rápida en el lado web: + +👉 **[ Demostración web en línea de OpenIM](https://web-enterprise.rentsoft.cn/)** + +🤲 Para facilitar la experiencia del usuario, ofrecemos varias soluciones de despliegue. Puedes elegir tu método de despliegue de la lista a continuación: + ++ **[Guía de Despliegue de Código Fuente](https://docs.openim.io/guides/gettingStarted/imSourceCodeDeployment)** ++ **[Guía de Despliegue con Docker](https://docs.openim.io/guides/gettingStarted/dockerCompose)** ++ **[Guía de Despliegue con Kubernetes](https://docs.openim.io/guides/gettingStarted/k8s-deployment)** ++ **[Guía de Despliegue para Desarrolladores en Mac](https://docs.openim.io/guides/gettingstarted/mac-deployment-guide)** + +## :hammer_and_wrench: Para Comenzar a Desarrollar en OpenIM + +[![Abrir en Contenedor de Desarrollo](https://img.shields.io/static/v1?label=Dev%20Container&message=Open&color=blue&logo=visualstudiocode)](https://vscode.dev/github/openimsdk/open-im-server) + +Nuestro objetivo en OpenIM es construir una comunidad de código abierto de nivel superior. Tenemos un conjunto de estándares, +en el [repositorio de la Comunidad.](https://github.com/OpenIMSDK/community). + +Si te gustaría contribuir a este repositorio de Open-IM-Server, por favor lee nuestra [documentación para colaboradores](https://github.com/openimsdk/open-im-server/blob/main/CONTRIBUTING.md). + + +Antes de comenzar, asegúrate de que tus cambios sean demandados. Lo mejor para eso es crear una [nueva discusión](https://github.com/openimsdk/open-im-server/discussions/new/choose) O [Comunicación en Slack](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q), o si encuentras un problema, [repórtalo](https://github.com/openimsdk/open-im-server/issues/new/choose) primero. + +- [Referencia de API de OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/api.md) +- [Registro de Bash de OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/bash-log.md) +- [Acciones de CI/CD de OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/cicd-actions.md) +- [Convenciones de Código de OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/code-conventions.md) +- [Guías de Commit de OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/commit.md) +- [Guía de Desarrollo de OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/development.md) +- [Estructura de Directorios de OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/directory.md) +- [Configuración de Entorno de OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/environment.md) +- [Referencia de Códigos de Error de OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/error-code.md) +- [Flujo de Trabajo de Git de OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/git-workflow.md) +- [Guía de Cherry Pick de Git de OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/gitcherry-pick.md) +- [Flujo de Trabajo de GitHub de OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/github-workflow.md) +- [Estándares de Código Go de OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/go-code.md) +- [Guías de Imágenes de OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/images.md) +- [Configuración Inicial de OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/init-config.md) +- [Guía de Instalación de Docker de OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/install-docker.md) +- [Instalación del Sistema Linux de OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/install-openim-linux-system.md) +- [Guía de Desarrollo Linux de OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/linux-development.md) +- [Guía de Acciones Locales de OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/local-actions.md) +- [Convenciones de Registro de OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/logging.md) +- [Despliegue sin Conexión de OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/offline-deployment.md) +- [Herramientas Protoc de OpenIMM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/protoc-tools.md) +- [Guía de Pruebas de OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/test.md) +- [Utilidades Go de OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/util-go.md) +- [Utilidades de Makefile de OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/util-makefile.md) +- [Utilidades de Script de OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/util-scripts.md) +- [Versionado de OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/version.md) +- [Gestión de backend y despliegue de monitoreo](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/prometheus-grafana.md) +- [Guía de Despliegue para Desarrolladores Mac de OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/mac-developer-deployment-guide.md) + + +## :busts_in_silhouette: Comunidad + ++ 📚 [Comunidad de OpenIM](https://github.com/OpenIMSDK/community) ++ 💕 [Grupo de Interés de OpenIM](https://github.com/Openim-sigs) ++ 🚀 [Únete a nuestra comunidad de Slack](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q) ++ :eyes: [Únete a nuestro wechat (微信群)](https://openim-1253691595.cos.ap-nanjing.myqcloud.com/WechatIMG20.jpeg) + +## :calendar: Reuniones de la Comunidad + +Queremos que cualquiera se involucre en nuestra comunidad y contribuya con código, ofrecemos regalos y recompensas, y te damos la bienvenida para que te unas a nosotros cada jueves por la noche. + +Nuestra conferencia está en [OpenIM Slack](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q) 🎯, luego puedes buscar el pipeline de Open-IM-Server para unirte + +Tomamos notas de cada [reunión quincenal](https://github.com/orgs/OpenIMSDK/discussions/categories/meeting) en [discusiones de GitHub](https://github.com/openimsdk/open-im-server/discussions/categories/meeting), Nuestras notas de reuniones históricas, así como las repeticiones de las reuniones están disponibles en [Google Docs :bookmark_tabs:](https://docs.google.com/document/d/1nx8MDpuG74NASx081JcCpxPgDITNTpIIos0DS6Vr9GU/edit?usp=sharing). + +## :eyes: Quiénes Están Usando OpenIM + +Consulta nuestros [estudios de caso de usuarios](https://github.com/OpenIMSDK/community/blob/main/ADOPTERS.md) página para obtener una lista de los usuarios del proyecto. No dudes en dejar un [📝comentario](https://github.com/openimsdk/open-im-server/issues/379) y compartir tu caso de uso. +## :page_facing_up: Licencia + + +OpenIM está bajo la licencia Apache 2.0. Consulta [LICENSE](https://github.com/openimsdk/open-im-server/tree/main/LICENSE) para ver el texto completo de la licencia. + + +El logotipo de OpenIM, incluyendo sus variaciones y versiones animadas, que se muestran en este repositorio [OpenIM](https://github.com/openimsdk/open-im-server) en los directorios [assets/logo](./assets/logo) y [assets/logo-gif](assets/logo-gif) están protegidos por las leyes de derechos de autor. +## 🔮 iGracias a nuestros colaboradores! + + + + From c63ea386afbcb6753f301b773e0c8b00adee2df4 Mon Sep 17 00:00:00 2001 From: longyuqing112 <105913803+longyuqing112@users.noreply.github.com> Date: Sun, 18 Feb 2024 18:44:49 +0800 Subject: [PATCH 042/188] docs: add README.md -FR (#1901) * docs: add README-FR Signed-off-by: Your Name <2631918708@qq.com> * docs: add README-FR Signed-off-by: longyuqing112 <2631918708@qq.com> --------- Signed-off-by: Your Name <2631918708@qq.com> Signed-off-by: longyuqing112 <2631918708@qq.com> --- docs/readme/README-FR.md | 178 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 178 insertions(+) create mode 100644 docs/readme/README-FR.md diff --git a/docs/readme/README-FR.md b/docs/readme/README-FR.md new file mode 100644 index 0000000000..5b72fc2b8f --- /dev/null +++ b/docs/readme/README-FR.md @@ -0,0 +1,178 @@ +

+ + + +

+ +
+ +[![Stars](https://img.shields.io/github/stars/openimsdk/open-im-server?style=for-the-badge&logo=github&colorB=ff69b4)](https://github.com/openimsdk/open-im-server/stargazers) +[![Forks](https://img.shields.io/github/forks/openimsdk/open-im-server?style=for-the-badge&logo=github&colorB=blue)](https://github.com/openimsdk/open-im-server/network/members) +[![Codecov](https://img.shields.io/codecov/c/github/openimsdk/open-im-server?style=for-the-badge&logo=codecov&colorB=orange)](https://app.codecov.io/gh/openimsdk/open-im-server) +[![Go Report Card](https://goreportcard.com/badge/github.com/openimsdk/open-im-server?style=for-the-badge)](https://goreportcard.com/report/github.com/openimsdk/open-im-server) +[![Go Reference](https://img.shields.io/badge/Go%20Reference-blue.svg?style=for-the-badge&logo=go&logoColor=white)](https://pkg.go.dev/github.com/openimsdk/open-im-server/v3) +[![License](https://img.shields.io/badge/license-Apache--2.0-green?style=for-the-badge)](https://github.com/openimsdk/open-im-server/blob/main/LICENSE) +[![Slack](https://img.shields.io/badge/Slack-500%2B-blueviolet?style=for-the-badge&logo=slack&logoColor=white)](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q) +[![Best Practices](https://img.shields.io/badge/Best%20Practices-purple?style=for-the-badge)](https://www.bestpractices.dev/projects/8045) +[![Good First Issues](https://img.shields.io/github/issues/openimsdk/open-im-server/good%20first%20issue?style=for-the-badge&logo=github)](https://github.com/openimsdk/open-im-server/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc+label%3A%22good+first+issue%22) +[![Language](https://img.shields.io/badge/Language-Go-blue.svg?style=for-the-badge&logo=go&logoColor=white)](https://golang.org/) + + +

+ Englist · + 中文 · + Українська · + Česky · + Magyar · + Español · + فارسی · + Français · + Deutsch · + Polski · + Indonesian · + Suomi · + മലയാളം · + 日本語 · + Nederlands · + Italiano · + Русский · + Português (Brasil) · + Esperanto · + 한국어 · + العربي · + Tiếng Việt · + Dansk · + Ελληνικά · + Türkçe +

+ + +
+ +

+ + +## Ⓜ️ À propos de OpenIM + +OpenIM est une plateforme de services conçue spécifiquement pour intégrer des fonctionnalités de communication telles que le chat, les appels audio et vidéo, les notifications, ainsi que les robots de chat IA dans les applications. Elle offre une série d'API puissantes et de Webhooks, permettant aux développeurs d'incorporer facilement ces caractéristiques interactives dans leurs applications. OpenIM n'est pas en soi une application de chat autonome, mais sert de plateforme supportant d'autres applications pour réaliser des fonctionnalités de communication enrichies. L'image ci-dessous montre les relations d'interaction entre AppServer, AppClient, OpenIMServer et OpenIMSDK pour illustrer spécifiquement. + + + +![Relation App-OpenIM](../images/oepnim-design.png) + +## 🚀 À propos de OpenIMSDK + +**OpenIMSDK** est un SDK IM conçu pour **OpenIMServer** spécialement créé pour être intégré dans les applications clientes. Ses principales fonctionnalités et modules comprennent : + ++ 🌟 Fonctionnalités clés : + + - 📦 Stockage local + - 🔔 Rappels de l'écouteur + - 🛡️ Encapsulation d'API + - 🌐 Gestion de la connexion + + ## 📚 Modules principaux : + + 1. 🚀 Initialisation et connexion + 2. 👤 Gestion des utilisateurs + 3. 👫 Gestion des amis + 4. 🤖 Fonctionnalités de groupe + 5. 💬 Traitement des conversations + +Il est construit avec Golang et supporte le déploiement multiplateforme, assurant une expérience d'accès cohérente sur toutes les plateformes。 + +👉 **[Explorer le SDK GO](https://github.com/openimsdk/openim-sdk-core)** + +## 🌐 À propos de OpenIMServer + ++ **OpenIMServer** présente les caractéristiques suivantes : + - 🌐 Architecture microservices : prend en charge le mode cluster, incluant le gateway (passerelle) et plusieurs services rpc。 + - 🚀 Divers modes de déploiement : supporte le déploiement via le code source, Kubernetes ou Docker。 + - Support d'une masse d'utilisateurs : plus de cent mille pour les super grands groupes, des millions d'utilisateurs, et des milliards de messages。 + +### Fonctionnalités commerciales améliorées : + ++ **REST API**:OpenIMServer fournit une REST API pour les systèmes commerciaux, visant à accorder plus de fonctionnalités, telles que la création de groupes via l'interface backend, l'envoi de messages push, etc。 ++ **Webhooks**:OpenIMServer offre des capacités de rappel pour étendre davantage les formes d'entreprise. Un rappel signifie que OpenIMServer enverra une requête au serveur d'entreprise avant ou après qu'un événement se soit produit, comme un rappel avant ou après l'envoi d'un message。 + +👉 **[En savoir plus](https://docs.openim.io/guides/introduction/product)** + +## :building_construction: Architecture globale + +Plongez dans le cœur de la fonctionnalité d'Open-IM-Server avec notre diagramme d'architecture. + +![Architecture globale](../images/architecture-layers.png) + + +## :rocket: Démarrage rapide + +Nous prenons en charge de nombreuses plateformes. Voici les adresses pour une expérience rapide du côté web : + +👉 **[Démo web en ligne OpenIM](https://www.openim.io/zh/commercial)** + +🤲 Pour faciliter l'expérience utilisateur, nous proposons plusieurs solutions de déploiement. Vous pouvez choisir votre méthode de déploiement selon la liste ci-dessous : + ++ **[Guide de déploiement du code source](https://docs.openim.io/guides/gettingStarted/imSourceCodeDeployment)** ++ **[Guide de déploiement Docker](https://docs.openim.io/guides/gettingStarted/dockerCompose)** ++ **[Guide de déploiement Kubernetes](https://docs.openim.io/guides/gettingStarted/k8s-deployment)** ++ **[Guide de déploiement pour développeur Mac](https://docs.openim.io/guides/gettingstarted/mac-deployment-guide)** + +## :hammer_and_wrench: Commencer à développer avec OpenIM + +Chez OpenIM, notre objectif est de construire une communauté open source de premier plan. Nous avons un ensemble de standards, disponibles dans le[ dépôt communautaire](https://github.com/OpenIMSDK/community)。 +Si vous souhaitez contribuer à ce dépôt Open-IM-Server, veuillez lire notre[ document pour les contributeurs](https://github.com/openimsdk/open-im-server/blob/main/CONTRIBUTING.md)。 + +Avant de commencer, assurez-vous que vos modifications sont nécessaires. La meilleure manière est de créer une[ nouvelle discussion ](https://github.com/openimsdk/open-im-server/discussions/new/choose) ou une [ communication Slack,](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q),ou si vous identifiez un problème, de[ signaler d'abord ](https://github.com/openimsdk/open-im-server/issues/new/choose)。 +- [Référence de l'API OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/api.md) +- [Journalisation Bash OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/bash-log.md) +- [Actions CI/CD OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/cicd-actions.md) +- [Conventions de code OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/code-conventions.md) +- [Directives de commit OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/commit.md) +- [Guide de développement OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/development.md) +- [Structure de répertoire OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/directory.md) +- [Configuration de l'environnement OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/environment.md) +- [Référence des codes d'erreur OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/error-code.md) +- [Workflow Git OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/git-workflow.md) +- [Guide Cherry Pick Git OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/gitcherry-pick.md) +- [Workflow GitHub OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/github-workflow.md) +- [Normes de code Go OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/go-code.md) +- [Directives d'image OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/images.md) +- [Configuration initiale OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/init-config.md) +- [Guide d'installation Docker OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/install-docker.md) +- [Installation du système Linux OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/install-openim-linux-system.md) +- [Guide de développement Linux OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/linux-development.md) +- [Guide des actions locales OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/local-actions.md) +- [Conventions de journalisation OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/logging.md) +- [Déploiement hors ligne OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/offline-deployment.md) +- [Outils Protoc OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/protoc-tools.md) +- [Guide de test OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/test.md) +- [Utilitaire Go OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/util-go.md) +- [Utilitaires Makefile OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/util-makefile.md) +- [Utilitaires de script OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/util-scripts.md) +- [Versionnement OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/version.md) +- [Gérer le déploiement du backend et la surveillance](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/prometheus-grafana.md) +- [Guide de déploiement pour développeur Mac pour OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/mac-developer-deployment-guide.md) + + +>## :calendar: Réunions de la Communauté + +Nous voulons que tout le monde s'implique dans notre communauté et contribue au code, nous offrons des cadeaux et des récompenses, et nous vous invitons à nous rejoindre chaque jeudi soir. +Notre conférence se trouve dans le [ Slack OpenIM ](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q) 🎯, ensuite vous pouvez rechercher le pipeline Open-IM-Server pour rejoindre + +Nous prenons des notes de chaque [réunion bihebdomadaire ](https://github.com/orgs/OpenIMSDK/discussions/categories/meeting) dans les [discussions GitHub](https://github.com/openimsdk/open-im-server/discussions/categories/meeting), Nos notes de réunion historiques, ainsi que les rediffusions des réunions sont disponibles sur [ Google Docs :bookmark_tabs:](https://docs.google.com/document/d/1nx8MDpuG74NASx081JcCpxPgDITNTpIIos0DS6Vr9GU/edit?usp=sharing). + +## :eyes: Qui Utilise OpenIM + +Consultez notre page [ études de cas d'utilisateurs ](https://github.com/OpenIMSDK/community/blob/main/ADOPTERS.md) pour une liste des utilisateurs du projet. N'hésitez pas à laisser un [📝commentaire](https://github.com/openimsdk/open-im-server/issues/379) et partager votre cas d'utilisation. + +## :page_facing_up: License + +OpenIM est sous licence Apache 2.0. Voir [LICENSE](https://github.com/openimsdk/open-im-server/tree/main/LICENSE) pour le texte complet de la licence. + +Le logo OpenIM, y compris ses variations et versions animées, affiché dans ce dépôt[OpenIM](https://github.com/openimsdk/open-im-server) sous les répertoires [assets/logo](./assets/logo) et [assets/logo-gif](assets/logo-gif) sont protégés par les lois sur le droit d'auteur. + +## 🔮 Merci à nos contributeurs ! + + + + From 760fbc95e6e1587b3424596f0e9cd07eb6b0a474 Mon Sep 17 00:00:00 2001 From: Seal Bell Date: Sun, 18 Feb 2024 18:44:59 +0800 Subject: [PATCH 043/188] docs:add README_cs.md (#1917) * docs:add README_cs.md * Update .spelling_failures * Update .spelling_failures * Update .spelling_failures --------- Co-authored-by: Xinwei Xiong <3293172751NSS@gmail.com> --- docs/readme/README_cs.md | 187 +++++++++++++++++++++++++++++++++++++ scripts/.spelling_failures | 25 ++++- 2 files changed, 211 insertions(+), 1 deletion(-) create mode 100644 docs/readme/README_cs.md diff --git a/docs/readme/README_cs.md b/docs/readme/README_cs.md new file mode 100644 index 0000000000..5a9eeb2324 --- /dev/null +++ b/docs/readme/README_cs.md @@ -0,0 +1,187 @@ +

+ + + +

+ +
+ +[![Stars](https://img.shields.io/github/stars/openimsdk/open-im-server?style=for-the-badge&logo=github&colorB=ff69b4)](https://github.com/openimsdk/open-im-server/stargazers) +[![Forks](https://img.shields.io/github/forks/openimsdk/open-im-server?style=for-the-badge&logo=github&colorB=blue)](https://github.com/openimsdk/open-im-server/network/members) +[![Codecov](https://img.shields.io/codecov/c/github/openimsdk/open-im-server?style=for-the-badge&logo=codecov&colorB=orange)](https://app.codecov.io/gh/openimsdk/open-im-server) +[![Go Report Card](https://goreportcard.com/badge/github.com/openimsdk/open-im-server?style=for-the-badge)](https://goreportcard.com/report/github.com/openimsdk/open-im-server) +[![Go Reference](https://img.shields.io/badge/Go%20Reference-blue.svg?style=for-the-badge&logo=go&logoColor=white)](https://pkg.go.dev/github.com/openimsdk/open-im-server/v3) +[![License](https://img.shields.io/badge/license-Apache--2.0-green?style=for-the-badge)](https://github.com/openimsdk/open-im-server/blob/main/LICENSE) +[![Slack](https://img.shields.io/badge/Slack-500%2B-blueviolet?style=for-the-badge&logo=slack&logoColor=white)](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q) +[![Best Practices](https://img.shields.io/badge/Best%20Practices-purple?style=for-the-badge)](https://www.bestpractices.dev/projects/8045) +[![Good First Issues](https://img.shields.io/github/issues/openimsdk/open-im-server/good%20first%20issue?style=for-the-badge&logo=github)](https://github.com/openimsdk/open-im-server/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc+label%3A%22good+first+issue%22) +[![Language](https://img.shields.io/badge/Language-Go-blue.svg?style=for-the-badge&logo=go&logoColor=white)](https://golang.org/) + + +

+ Englist · + 中文 · + Українська · + Česky · + Magyar · + Español · + فارسی · + Français · + Deutsch · + Polski · + Indonesian · + Suomi · + മലയാളം · + 日本語 · + Nederlands · + Italiano · + Русский · + Português (Brasil) · + Esperanto · + 한국어 · + العربي · + Tiếng Việt · + Dansk · + Ελληνικά · + Türkçe +

+ + +
+ +

+ +## Ⓜ️ O OpenIM + +OpenIM je platforma služeb speciálně navržená pro integraci chatu, audio-video hovorů, upozornění a chatbotů AI do aplikací. Poskytuje řadu výkonných rozhraní API a webhooků, které vývojářům umožňují snadno začlenit tyto interaktivní funkce do svých aplikací. OpenIM není samostatná chatovací aplikace, ale spíše slouží jako platforma pro podporu jiných aplikací při dosahování bohatých komunikačních funkcí. Následující diagram ilustruje interakci mezi AppServer, AppClient, OpenIMServer a OpenIMSDK pro podrobné vysvětlení. + +![App-OpenIM Relationship](../images/oepnim-design.png) + +## 🚀 O OpenIMSDK + +**OpenIMSDK** je IM SDK navržený pro**OpenIMServer**, vytvořený speciálně pro vkládání do klientských aplikací. Jeho hlavní vlastnosti a moduly jsou následující: + ++ 🌟 Hlavní vlastnosti: + + - 📦 Místní úložiště + - 🔔 Zpětná volání posluchačů + - 🛡️ API obalování + - 🌐 Správa připojení + ++ 📚 hlavní moduly: + + 1. 🚀 Inicializace a přihlášení + 2. 👤 Správa uživatelů + 3. 👫 Správa přátel + 4. 🤖 Skupinové funkce + 5. 💬 Zpracování konverzace + +Je postaven pomocí Golang a podporuje nasazení napříč platformami, což zajišťuje konzistentní přístup na všech platformách. + +👉 **[Prozkoumat GO SDK](https://github.com/openimsdk/openim-sdk-core)** + +## 🌐 O OpenIMServeru + ++ **OpenIMServer** má následující vlastnosti: + - 🌐 Architektura mikroslužeb: Podporuje režim clusteru, včetně brány a více služeb RPC. + - 🚀 Různé metody nasazení: Podporuje nasazení prostřednictvím zdrojového kódu, Kubernetes nebo Docker. + - Podpora masivní uživatelské základny: Super velké skupiny se stovkami tisíc uživatelů, desítkami milionů uživatelů a miliardami zpráv. + +### Vylepšené obchodní funkce: + ++ **REST API**: OpenIMServer nabízí REST API pro podnikové systémy, jejichž cílem je poskytnout podnikům více funkcí, jako je vytváření skupin a odesílání push zpráv přes backendová rozhraní. ++ **Webhooks**: OpenIMServer poskytuje možnosti zpětného volání pro rozšíření více obchodních formulářů. Zpětné volání znamená, že OpenIMServer odešle požadavek na obchodní server před nebo po určité události, jako jsou zpětná volání před nebo po odeslání zprávy. + +👉 **[Další informace](https://docs.openim.io/guides/introduction/product)** + +## :building_construction: Celková architektura + +Ponořte se do srdce funkčnosti Open-IM-Server s naším diagramem architektury. + +![Overall Architecture](../images/architecture-layers.png) + + +## :rocket: Rychlý start + +Podporujeme mnoho platforem. Zde jsou adresy pro rychlou práci na webové stránce: + +👉 **[Online webová ukázka OpenIM](https://web-enterprise.rentsoft.cn/)** + +🤲 Pro usnadnění uživatelské zkušenosti nabízíme různá řešení nasazení. Způsob nasazení si můžete vybrat ze seznamu níže: + ++ **[Průvodce nasazením zdrojového kódu](https://docs.openim.io/guides/gettingStarted/imSourceCodeDeployment)** ++ **[Docker Deployment Guide](https://docs.openim.io/guides/gettingStarted/dockerCompose)** ++ **[Průvodce nasazením Kubernetes](https://docs.openim.io/guides/gettingStarted/k8s-deployment)** ++ **[Průvodce nasazením pro vývojáře Mac](https://docs.openim.io/guides/gettingstarted/mac-deployment-guide)** + +## :hammer_and_wrench: Chcete-li začít vyvíjet OpenIM + +[![Open in Dev Container](https://img.shields.io/static/v1?label=Dev%20Container&message=Open&color=blue&logo=visualstudiocode)](https://vscode.dev/github/openimsdk/open-im-server) + +OpenIM Naším cílem je vybudovat špičkovou open source komunitu. Máme soubor standardů v [komunitním repozitáři](https://github.com/OpenIMSDK/community). + +Pokud byste chtěli přispět do tohoto úložiště Open-IM-Server, přečtěte si naši [dokumentaci pro přispěvatele](https://github.com/openimsdk/open-im-server/blob/main/CONTRIBUTING.md). + +Než začnete, ujistěte se, že jsou vaše změny vyžadovány. Nejlepší pro to je vytvořit [nová diskuze](https://github.com/openimsdk/open-im-server/discussions/new/choose) NEBO [Slack Communication](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q), nebo pokud narazíte na problém, [nahlásit jej](https://github.com/openimsdk/open-im-server/issues/new/choose) jako první. + +- [OpenIM API Reference](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/api.md) +- [Protokolování OpenIM Bash](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/bash-log.md) +- [Akce OpenIM CI/CD](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/cicd-actions.md) +- [Konvence kódu OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/code-conventions.md) +- [Pokyny k zavázání OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/commit.md) +- [Průvodce vývojem OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/development.md) +- [Struktura adresáře OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/directory.md) +- [Nastavení prostředí OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/environment.md) +- [Referenční kód chybového kódu OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/error-code.md) +- [Pracovní postup OpenIM Git](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/git-workflow.md) +- [OpenIM Git Cherry Pick Guide](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/gitcherry-pick.md) +- [Pracovní postup OpenIM GitHub](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/github-workflow.md) +- [standardy kódu OpenIM Go](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/go-code.md) +- [Pokyny pro obrázky OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/images.md) +- [Počáteční konfigurace OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/init-config.md) +- [Průvodce instalací OpenIM Docker](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/install-docker.md) +- [nstalace systému OpenIM OpenIM Linux](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/install-openim-linux-system.md) +- [OpenIM Linux Development Guide](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/linux-development.md) +- [Průvodce místními akcemi OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/local-actions.md) +- [Konvence protokolování OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/logging.md) +- [Offline nasazení OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/offline-deployment.md) +- [Nástroje protokolu OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/protoc-tools.md) +- [Příručka testování OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/test.md) +- [OpenIM Utility Go](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/util-go.md) +- [OpenIM Makefile Utilities](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/util-makefile.md) +- [OpenIM Script Utilities](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/util-scripts.md) +- [OpenIM Versioning](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/version.md) +- [Spravovat backend a monitorovat nasazení](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/prometheus-grafana.md) +- [Průvodce nasazením pro vývojáře Mac pro OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/mac-developer-deployment-guide.md) + + +## :busts_in_silhouette: Společenství + ++ 📚 [Komunita OpenIM](https://github.com/OpenIMSDK/community) ++ 💕 [Zájmová skupina OpenIM](https://github.com/Openim-sigs) ++ 🚀 [Připojte se k naší komunitě Slack](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q) ++ :eyes: [Připojte se k našemu wechatu](https://openim-1253691595.cos.ap-nanjing.myqcloud.com/WechatIMG20.jpeg) + +## :calendar: Komunitní setkání + +Chceme, aby se do naší komunity a přispívání kódu zapojil kdokoli, nabízíme dárky a odměny a vítáme vás, abyste se k nám připojili každý čtvrtek večer. + +Naše konference je v [OpenIM Slack](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q) 🎯, pak můžete vyhledat kanál Open-IM-Server a připojit se + +Zaznamenáváme si každou [dvoutýdenní schůzku](https://github.com/orgs/OpenIMSDK/discussions/categories/meeting)do [diskuzí na GitHubu](https://github.com/openimsdk/open-im-server/discussions/categories/meeting), naše historické poznámky ze schůzek a také záznamy schůzek jsou k dispozici na [Dokumenty Google :bookmark_tabs:](https://docs.google.com/document/d/1nx8MDpuG74NASx081JcCpxPgDITNTpIIos0DS6Vr9GU/edit?usp=sharing). + +## :eyes: Kdo používá OpenIM + +Podívejte se na naši stránku [případové studie uživatelů](https://github.com/OpenIMSDK/community/blob/main/ADOPTERS.md), kde najdete seznam uživatelů projektu. Neváhejte zanechat[📝komentář](https://github.com/openimsdk/open-im-server/issues/379) a podělte se o svůj případ použití. + +## :page_facing_up: License + +OpenIM je licencován pod licencí Apache 2.0. Úplný text licence naleznete v [LICENCE](https://github.com/openimsdk/open-im-server/tree/main/LICENSE). + +Logo OpenIM, včetně jeho variací a animovaných verzí, zobrazené v tomto úložišti [OpenIM](https://github.com/openimsdk/open-im-server)v adresářích [assets/logo](./assets/logo) a [assets/logo-gif](assets/logo-gif) je chráněno autorským právem. + +## 🔮 Děkujeme našim přispěvatelům! + + + + diff --git a/scripts/.spelling_failures b/scripts/.spelling_failures index 149d314ba4..347246f2e0 100644 --- a/scripts/.spelling_failures +++ b/scripts/.spelling_failures @@ -5,4 +5,27 @@ third_party/ translations/ logs .git -.golangci.yml \ No newline at end of file +.golangci.yml +docs/readme/README_uk.md +docs/readme/README_cs.md +docs/readme/README_hu.md +docs/readme/README_es.md +docs/readme/README_fa.md +docs/readme/README_fr.md +docs/readme/README_de.md +docs/readme/README_pl.md +docs/readme/README_id.md +docs/readme/README_fi.md +docs/readme/README_ml.md +docs/readme/README_ja.md +docs/readme/README_nl.md +docs/readme/README_it.md +docs/readme/README_ru.md +docs/readme/README_pt_BR +docs/readme/README_eo.md +docs/readme/README_ko.md +docs/readme/README_ar.md +docs/readme/README_vi.md +docs/readme/README_da.md +docs/readme/README_el.md +docs/readme/README_tr.md From 79217972944ed5d24e5c60af1da4182c921ee974 Mon Sep 17 00:00:00 2001 From: Xinwei Xiong <3293172751NSS@gmail.com> Date: Sun, 18 Feb 2024 19:09:49 +0800 Subject: [PATCH 044/188] Update and rename README-ES.md to README-e.md (#1918) * Update and rename README-ES.md to README-e.md * Rename README-e.md to README-es.md * Update and rename README-FR.md to README-fr.md * Update README-fr.md * Rename README-es.md to README_es.md * Rename README-fr.md to README_fr.md --- docs/readme/{README-ES.md => README_es.md} | 58 +++++++++++----------- docs/readme/{README-FR.md => README_fr.md} | 56 ++++++++++----------- 2 files changed, 57 insertions(+), 57 deletions(-) rename docs/readme/{README-ES.md => README_es.md} (89%) rename docs/readme/{README-FR.md => README_fr.md} (88%) diff --git a/docs/readme/README-ES.md b/docs/readme/README_es.md similarity index 89% rename from docs/readme/README-ES.md rename to docs/readme/README_es.md index f058617a09..cd1b7290ee 100644 --- a/docs/readme/README-ES.md +++ b/docs/readme/README_es.md @@ -1,6 +1,6 @@

- +

@@ -19,31 +19,31 @@

- Englist · - 中文 · - Українська · - Česky · - Magyar · - Español · - فارسی · - Français · - Deutsch · - Polski · - Indonesian · - Suomi · - മലയാളം · - 日本語 · - Nederlands · - Italiano · - Русский · - Português (Brasil) · - Esperanto · - 한국어 · - العربي · - Tiếng Việt · - Dansk · - Ελληνικά · - Türkçe + Englist · + 中文 · + Українська · + Česky · + Magyar · + Español · + فارسی · + Français · + Deutsch · + Polski · + Indonesian · + Suomi · + മലയാളം · + 日本語 · + Nederlands · + Italiano · + Русский · + Português (Brasil) · + Esperanto · + 한국어 · + العربي · + Tiếng Việt · + Dansk · + Ελληνικά · + Türkçe

@@ -55,7 +55,7 @@ OpenIM es una plataforma de servicio diseñada específicamente para integrar chat, llamadas de audio y video, notificaciones y chatbots de IA en aplicaciones. Proporciona una gama de potentes API y Webhooks, lo que permite a los desarrolladores incorporar fácilmente estas características interactivas en sus aplicaciones. OpenIM no es una aplicación de chat independiente, sino que sirve como una plataforma para apoyar a otras aplicaciones en lograr funcionalidades de comunicación enriquecidas. El siguiente diagrama ilustra la interacción entre AppServer, AppClient, OpenIMServer y OpenIMSDK para explicar en detalle. -![Relación App-OpenIM](./docs/images/oepnim-design.png) +![Relación App-OpenIM](../../docs/images/oepnim-design.png) ## 🚀 Acerca de OpenIMSDK @@ -100,7 +100,7 @@ Está construido con Golang y soporta despliegue multiplataforma, asegurando una Adéntrate en el corazón de la funcionalidad de Open-IM-Server con nuestro diagrama de arquitectura. -![Arquitectura General](./docs/images/architecture-layers.png) +![Arquitectura General](../../docs/images/architecture-layers.png) ## :rocket: Inicio Rápido @@ -185,7 +185,7 @@ Consulta nuestros [estudios de caso de usuarios](https://github.com/OpenIMSDK/co OpenIM está bajo la licencia Apache 2.0. Consulta [LICENSE](https://github.com/openimsdk/open-im-server/tree/main/LICENSE) para ver el texto completo de la licencia. -El logotipo de OpenIM, incluyendo sus variaciones y versiones animadas, que se muestran en este repositorio [OpenIM](https://github.com/openimsdk/open-im-server) en los directorios [assets/logo](./assets/logo) y [assets/logo-gif](assets/logo-gif) están protegidos por las leyes de derechos de autor. +El logotipo de OpenIM, incluyendo sus variaciones y versiones animadas, que se muestran en este repositorio [OpenIM](https://github.com/openimsdk/open-im-server) en los directorios [assets/logo](../../assets/logo) y [assets/logo-gif](assets/logo-gif) están protegidos por las leyes de derechos de autor. ## 🔮 iGracias a nuestros colaboradores! diff --git a/docs/readme/README-FR.md b/docs/readme/README_fr.md similarity index 88% rename from docs/readme/README-FR.md rename to docs/readme/README_fr.md index 5b72fc2b8f..e707fc59b7 100644 --- a/docs/readme/README-FR.md +++ b/docs/readme/README_fr.md @@ -1,6 +1,6 @@

- +

@@ -20,30 +20,30 @@

Englist · - 中文 · - Українська · - Česky · - Magyar · - Español · - فارسی · - Français · - Deutsch · - Polski · - Indonesian · - Suomi · - മലയാളം · - 日本語 · - Nederlands · - Italiano · - Русский · - Português (Brasil) · - Esperanto · - 한국어 · - العربي · - Tiếng Việt · - Dansk · - Ελληνικά · - Türkçe + 中文 · + Українська · + Česky · + Magyar · + Español · + فارسی · + Français · + Deutsch · + Polski · + Indonesian · + Suomi · + മലയാളം · + 日本語 · + Nederlands · + Italiano · + Русский · + Português (Brasil) · + Esperanto · + 한국어 · + العربي · + Tiếng Việt · + Dansk · + Ελληνικά · + Türkçe

@@ -58,7 +58,7 @@ OpenIM est une plateforme de services conçue spécifiquement pour intégrer des -![Relation App-OpenIM](../images/oepnim-design.png) +![Relation App-OpenIM](../../images/oepnim-design.png) ## 🚀 À propos de OpenIMSDK @@ -101,7 +101,7 @@ Il est construit avec Golang et supporte le déploiement multiplateforme, assura Plongez dans le cœur de la fonctionnalité d'Open-IM-Server avec notre diagramme d'architecture. -![Architecture globale](../images/architecture-layers.png) +![Architecture globale](../../images/architecture-layers.png) ## :rocket: Démarrage rapide @@ -169,7 +169,7 @@ Consultez notre page [ études de cas d'utilisateurs ](https://github.com/OpenIM OpenIM est sous licence Apache 2.0. Voir [LICENSE](https://github.com/openimsdk/open-im-server/tree/main/LICENSE) pour le texte complet de la licence. -Le logo OpenIM, y compris ses variations et versions animées, affiché dans ce dépôt[OpenIM](https://github.com/openimsdk/open-im-server) sous les répertoires [assets/logo](./assets/logo) et [assets/logo-gif](assets/logo-gif) sont protégés par les lois sur le droit d'auteur. +Le logo OpenIM, y compris ses variations et versions animées, affiché dans ce dépôt[OpenIM](https://github.com/openimsdk/open-im-server) sous les répertoires [assets/logo](../../assets/logo) et [assets/logo-gif](assets/logo-gif) sont protégés par les lois sur le droit d'auteur. ## 🔮 Merci à nos contributeurs ! From cbce4dae879b61ac0f1a23384ce3826f1c09463a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 18 Feb 2024 19:19:54 +0800 Subject: [PATCH 045/188] feat(deps): bump the gomod-deps group with 17 updates (#1913) Bumps the gomod-deps group with 17 updates: | Package | From | To | | --- | --- | --- | | [github.com/OpenIMSDK/tools](https://github.com/OpenIMSDK/tools) | `0.0.33` | `0.0.35` | | [github.com/go-playground/validator/v10](https://github.com/go-playground/validator) | `10.15.5` | `10.18.0` | | [github.com/gorilla/websocket](https://github.com/gorilla/websocket) | `1.5.0` | `1.5.1` | | [github.com/minio/minio-go/v7](https://github.com/minio/minio-go) | `7.0.63` | `7.0.67` | | [github.com/prometheus/client_golang](https://github.com/prometheus/client_golang) | `1.17.0` | `1.18.0` | | [go.mongodb.org/mongo-driver](https://github.com/mongodb/mongo-go-driver) | `1.12.1` | `1.14.0` | | [golang.org/x/image](https://github.com/golang/image) | `0.13.0` | `0.15.0` | | [google.golang.org/api](https://github.com/googleapis/google-api-go-client) | `0.148.0` | `0.165.0` | | [google.golang.org/grpc](https://github.com/grpc/grpc-go) | `1.59.0` | `1.61.0` | | google.golang.org/protobuf | `1.31.0` | `1.32.0` | | [github.com/google/uuid](https://github.com/google/uuid) | `1.5.0` | `1.6.0` | | [github.com/IBM/sarama](https://github.com/IBM/sarama) | `1.41.3` | `1.42.2` | | [github.com/aliyun/aliyun-oss-go-sdk](https://github.com/aliyun/aliyun-oss-go-sdk) | `2.2.9+incompatible` | `3.0.2+incompatible` | | [github.com/redis/go-redis/v9](https://github.com/redis/go-redis) | `9.2.1` | `9.4.0` | | [github.com/tencentyun/cos-go-sdk-v5](https://github.com/tencentyun/cos-go-sdk-v5) | `0.7.45` | `0.7.46` | | [golang.org/x/sync](https://github.com/golang/sync) | `0.4.0` | `0.6.0` | | [github.com/spf13/cobra](https://github.com/spf13/cobra) | `1.7.0` | `1.8.0` | Updates `github.com/OpenIMSDK/tools` from 0.0.33 to 0.0.35 - [Release notes](https://github.com/OpenIMSDK/tools/releases) - [Commits](https://github.com/OpenIMSDK/tools/compare/v0.0.33...v0.0.35) Updates `github.com/go-playground/validator/v10` from 10.15.5 to 10.18.0 - [Release notes](https://github.com/go-playground/validator/releases) - [Commits](https://github.com/go-playground/validator/compare/v10.15.5...v10.18.0) Updates `github.com/gorilla/websocket` from 1.5.0 to 1.5.1 - [Release notes](https://github.com/gorilla/websocket/releases) - [Commits](https://github.com/gorilla/websocket/compare/v1.5.0...v1.5.1) Updates `github.com/minio/minio-go/v7` from 7.0.63 to 7.0.67 - [Release notes](https://github.com/minio/minio-go/releases) - [Commits](https://github.com/minio/minio-go/compare/v7.0.63...v7.0.67) Updates `github.com/prometheus/client_golang` from 1.17.0 to 1.18.0 - [Release notes](https://github.com/prometheus/client_golang/releases) - [Changelog](https://github.com/prometheus/client_golang/blob/main/CHANGELOG.md) - [Commits](https://github.com/prometheus/client_golang/compare/v1.17.0...v1.18.0) Updates `go.mongodb.org/mongo-driver` from 1.12.1 to 1.14.0 - [Release notes](https://github.com/mongodb/mongo-go-driver/releases) - [Commits](https://github.com/mongodb/mongo-go-driver/compare/v1.12.1...v1.14.0) Updates `golang.org/x/image` from 0.13.0 to 0.15.0 - [Commits](https://github.com/golang/image/compare/v0.13.0...v0.15.0) Updates `google.golang.org/api` from 0.148.0 to 0.165.0 - [Release notes](https://github.com/googleapis/google-api-go-client/releases) - [Changelog](https://github.com/googleapis/google-api-go-client/blob/main/CHANGES.md) - [Commits](https://github.com/googleapis/google-api-go-client/compare/v0.148.0...v0.165.0) Updates `google.golang.org/grpc` from 1.59.0 to 1.61.0 - [Release notes](https://github.com/grpc/grpc-go/releases) - [Commits](https://github.com/grpc/grpc-go/compare/v1.59.0...v1.61.0) Updates `google.golang.org/protobuf` from 1.31.0 to 1.32.0 Updates `github.com/google/uuid` from 1.5.0 to 1.6.0 - [Release notes](https://github.com/google/uuid/releases) - [Changelog](https://github.com/google/uuid/blob/master/CHANGELOG.md) - [Commits](https://github.com/google/uuid/compare/v1.5.0...v1.6.0) Updates `github.com/IBM/sarama` from 1.41.3 to 1.42.2 - [Release notes](https://github.com/IBM/sarama/releases) - [Changelog](https://github.com/IBM/sarama/blob/main/CHANGELOG.md) - [Commits](https://github.com/IBM/sarama/compare/v1.41.3...v1.42.2) Updates `github.com/aliyun/aliyun-oss-go-sdk` from 2.2.9+incompatible to 3.0.2+incompatible - [Release notes](https://github.com/aliyun/aliyun-oss-go-sdk/releases) - [Changelog](https://github.com/aliyun/aliyun-oss-go-sdk/blob/master/CHANGELOG.md) - [Commits](https://github.com/aliyun/aliyun-oss-go-sdk/compare/v2.2.9...v3.0.2) Updates `github.com/redis/go-redis/v9` from 9.2.1 to 9.4.0 - [Release notes](https://github.com/redis/go-redis/releases) - [Changelog](https://github.com/redis/go-redis/blob/master/CHANGELOG.md) - [Commits](https://github.com/redis/go-redis/compare/v9.2.1...v9.4.0) Updates `github.com/tencentyun/cos-go-sdk-v5` from 0.7.45 to 0.7.46 - [Release notes](https://github.com/tencentyun/cos-go-sdk-v5/releases) - [Changelog](https://github.com/tencentyun/cos-go-sdk-v5/blob/master/CHANGELOG.md) - [Commits](https://github.com/tencentyun/cos-go-sdk-v5/compare/v0.7.45...v0.7.46) Updates `golang.org/x/sync` from 0.4.0 to 0.6.0 - [Commits](https://github.com/golang/sync/compare/v0.4.0...v0.6.0) Updates `github.com/spf13/cobra` from 1.7.0 to 1.8.0 - [Release notes](https://github.com/spf13/cobra/releases) - [Commits](https://github.com/spf13/cobra/compare/v1.7.0...v1.8.0) --- updated-dependencies: - dependency-name: github.com/OpenIMSDK/tools dependency-type: direct:production update-type: version-update:semver-patch dependency-group: gomod-deps - dependency-name: github.com/go-playground/validator/v10 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: gomod-deps - dependency-name: github.com/gorilla/websocket dependency-type: direct:production update-type: version-update:semver-patch dependency-group: gomod-deps - dependency-name: github.com/minio/minio-go/v7 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: gomod-deps - dependency-name: github.com/prometheus/client_golang dependency-type: direct:production update-type: version-update:semver-minor dependency-group: gomod-deps - dependency-name: go.mongodb.org/mongo-driver dependency-type: direct:production update-type: version-update:semver-minor dependency-group: gomod-deps - dependency-name: golang.org/x/image dependency-type: direct:production update-type: version-update:semver-minor dependency-group: gomod-deps - dependency-name: google.golang.org/api dependency-type: direct:production update-type: version-update:semver-minor dependency-group: gomod-deps - dependency-name: google.golang.org/grpc dependency-type: direct:production update-type: version-update:semver-minor dependency-group: gomod-deps - dependency-name: google.golang.org/protobuf dependency-type: direct:production update-type: version-update:semver-minor dependency-group: gomod-deps - dependency-name: github.com/google/uuid dependency-type: direct:production update-type: version-update:semver-minor dependency-group: gomod-deps - dependency-name: github.com/IBM/sarama dependency-type: direct:production update-type: version-update:semver-minor dependency-group: gomod-deps - dependency-name: github.com/aliyun/aliyun-oss-go-sdk dependency-type: direct:production update-type: version-update:semver-major dependency-group: gomod-deps - dependency-name: github.com/redis/go-redis/v9 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: gomod-deps - dependency-name: github.com/tencentyun/cos-go-sdk-v5 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: gomod-deps - dependency-name: golang.org/x/sync dependency-type: direct:production update-type: version-update:semver-minor dependency-group: gomod-deps - dependency-name: github.com/spf13/cobra dependency-type: direct:production update-type: version-update:semver-minor dependency-group: gomod-deps ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 89 ++++++++++++++------------ go.sum | 193 ++++++++++++++++++++++++++++++--------------------------- 2 files changed, 150 insertions(+), 132 deletions(-) diff --git a/go.mod b/go.mod index ab138e68cb..be835c0a41 100644 --- a/go.mod +++ b/go.mod @@ -5,55 +5,55 @@ go 1.19 require ( firebase.google.com/go v3.13.0+incompatible github.com/OpenIMSDK/protocol v0.0.55 - github.com/OpenIMSDK/tools v0.0.33 + github.com/OpenIMSDK/tools v0.0.35 github.com/bwmarrin/snowflake v0.3.0 // indirect github.com/dtm-labs/rockscache v0.1.1 github.com/gin-gonic/gin v1.9.1 - github.com/go-playground/validator/v10 v10.15.5 + github.com/go-playground/validator/v10 v10.18.0 github.com/gogo/protobuf v1.3.2 github.com/golang-jwt/jwt/v4 v4.5.0 - github.com/gorilla/websocket v1.5.0 + github.com/gorilla/websocket v1.5.1 github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible // indirect - github.com/minio/minio-go/v7 v7.0.63 + github.com/minio/minio-go/v7 v7.0.67 github.com/mitchellh/mapstructure v1.5.0 github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 // indirect github.com/pkg/errors v0.9.1 // indirect - github.com/prometheus/client_golang v1.17.0 + github.com/prometheus/client_golang v1.18.0 github.com/robfig/cron/v3 v3.0.1 github.com/sirupsen/logrus v1.9.3 // indirect github.com/stretchr/testify v1.8.4 - go.mongodb.org/mongo-driver v1.12.1 - golang.org/x/image v0.13.0 - google.golang.org/api v0.148.0 - google.golang.org/grpc v1.59.0 - google.golang.org/protobuf v1.31.0 + go.mongodb.org/mongo-driver v1.14.0 + golang.org/x/image v0.15.0 + google.golang.org/api v0.165.0 + google.golang.org/grpc v1.61.0 + google.golang.org/protobuf v1.32.0 gopkg.in/yaml.v3 v3.0.1 ) -require github.com/google/uuid v1.5.0 +require github.com/google/uuid v1.6.0 require ( - github.com/IBM/sarama v1.41.3 - github.com/aliyun/aliyun-oss-go-sdk v2.2.9+incompatible + github.com/IBM/sarama v1.42.2 + github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible github.com/go-redis/redis v6.15.9+incompatible - github.com/redis/go-redis/v9 v9.2.1 + github.com/redis/go-redis/v9 v9.4.0 github.com/spf13/pflag v1.0.5 github.com/stathat/consistent v1.0.0 - github.com/tencentyun/cos-go-sdk-v5 v0.7.45 - golang.org/x/sync v0.4.0 + github.com/tencentyun/cos-go-sdk-v5 v0.7.46 + golang.org/x/sync v0.6.0 gopkg.in/src-d/go-git.v4 v4.13.1 gotest.tools v2.2.0+incompatible ) require ( - cloud.google.com/go v0.110.8 // indirect - cloud.google.com/go/compute v1.23.0 // indirect + cloud.google.com/go v0.112.0 // indirect + cloud.google.com/go/compute v1.23.3 // indirect cloud.google.com/go/compute/metadata v0.2.3 // indirect - cloud.google.com/go/firestore v1.13.0 // indirect - cloud.google.com/go/iam v1.1.2 // indirect - cloud.google.com/go/longrunning v0.5.1 // indirect - cloud.google.com/go/storage v1.30.1 // indirect + cloud.google.com/go/firestore v1.14.0 // indirect + cloud.google.com/go/iam v1.1.5 // indirect + cloud.google.com/go/longrunning v0.5.4 // indirect + cloud.google.com/go/storage v1.36.0 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bytedance/sonic v1.9.1 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect @@ -62,12 +62,15 @@ require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/dustin/go-humanize v1.0.1 // indirect - github.com/eapache/go-resiliency v1.4.0 // indirect + github.com/eapache/go-resiliency v1.5.0 // indirect github.com/eapache/go-xerial-snappy v0.0.0-20230731223053-c322873962e3 // indirect github.com/eapache/queue v1.1.0 // indirect github.com/emirpasic/gods v1.12.0 // indirect - github.com/gabriel-vasile/mimetype v1.4.2 // indirect + github.com/felixge/httpsnoop v1.0.4 // indirect + github.com/gabriel-vasile/mimetype v1.4.3 // indirect github.com/gin-contrib/sse v0.1.0 // indirect + github.com/go-logr/logr v1.4.1 // indirect + github.com/go-logr/stdr v1.2.2 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-zookeeper/zk v1.0.3 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect @@ -76,7 +79,7 @@ require ( github.com/google/go-cmp v0.6.0 // indirect github.com/google/go-querystring v1.1.0 // indirect github.com/google/s2a-go v0.1.7 // indirect - github.com/googleapis/enterprise-certificate-proxy v0.3.1 // indirect + github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect github.com/googleapis/gax-go/v2 v2.12.0 // indirect github.com/hashicorp/errwrap v1.0.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect @@ -95,9 +98,9 @@ require ( github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd // indirect github.com/klauspost/compress v1.17.4 // indirect github.com/klauspost/cpuid/v2 v2.2.6 // indirect - github.com/leodido/go-urn v1.2.4 // indirect + github.com/leodido/go-urn v1.4.0 // indirect github.com/lithammer/shortuuid v3.0.0+incompatible // indirect - github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect + github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect github.com/minio/md5-simd v1.1.2 // indirect github.com/minio/sha256-simd v1.0.1 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect @@ -108,11 +111,11 @@ require ( github.com/onsi/ginkgo v1.16.5 // indirect github.com/onsi/gomega v1.18.1 // indirect github.com/pelletier/go-toml/v2 v2.0.8 // indirect - github.com/pierrec/lz4/v4 v4.1.18 // indirect + github.com/pierrec/lz4/v4 v4.1.21 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16 // indirect - github.com/prometheus/common v0.44.0 // indirect - github.com/prometheus/procfs v0.11.1 // indirect + github.com/prometheus/client_model v0.5.0 // indirect + github.com/prometheus/common v0.45.0 // indirect + github.com/prometheus/procfs v0.12.0 // indirect github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect github.com/rs/xid v1.5.0 // indirect github.com/sergi/go-diff v1.0.0 // indirect @@ -125,19 +128,23 @@ require ( github.com/xdg-go/stringprep v1.0.4 // indirect github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect go.opencensus.io v0.24.0 // indirect + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.47.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.47.0 // indirect + go.opentelemetry.io/otel v1.23.0 // indirect + go.opentelemetry.io/otel/metric v1.23.0 // indirect + go.opentelemetry.io/otel/trace v1.23.0 // indirect go.uber.org/atomic v1.7.0 // indirect go.uber.org/multierr v1.11.0 // indirect golang.org/x/arch v0.3.0 // indirect - golang.org/x/net v0.19.0 // indirect - golang.org/x/oauth2 v0.13.0 // indirect - golang.org/x/sys v0.15.0 // indirect + golang.org/x/net v0.21.0 // indirect + golang.org/x/oauth2 v0.17.0 // indirect + golang.org/x/sys v0.17.0 // indirect golang.org/x/text v0.14.0 // indirect golang.org/x/time v0.5.0 // indirect - golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect - google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto v0.0.0-20231002182017-d307bd883b97 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20231002182017-d307bd883b97 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20231012201019-e917dd12ba7a // indirect + google.golang.org/appengine v1.6.8 // indirect + google.golang.org/genproto v0.0.0-20240125205218-1f4bbc51befe // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20240116215550-a9fa1716bcac // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240205150955-31a09d347014 // indirect gopkg.in/src-d/go-billy.v4 v4.3.2 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect gorm.io/gorm v1.25.4 // indirect @@ -149,9 +156,9 @@ require ( github.com/goccy/go-json v0.10.2 // indirect github.com/lestrrat-go/strftime v1.0.6 // indirect github.com/mattn/go-isatty v0.0.19 // indirect - github.com/spf13/cobra v1.7.0 + github.com/spf13/cobra v1.8.0 github.com/ugorji/go/codec v1.2.11 // indirect go.uber.org/zap v1.24.0 // indirect - golang.org/x/crypto v0.17.0 // indirect + golang.org/x/crypto v0.19.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect ) diff --git a/go.sum b/go.sum index 94a516366c..c4b661f1c2 100644 --- a/go.sum +++ b/go.sum @@ -1,32 +1,32 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.110.8 h1:tyNdfIxjzaWctIiLYOTalaLKZ17SI44SKFW26QbOhME= -cloud.google.com/go v0.110.8/go.mod h1:Iz8AkXJf1qmxC3Oxoep8R1T36w8B92yU29PcBhHO5fk= -cloud.google.com/go/compute v1.23.0 h1:tP41Zoavr8ptEqaW6j+LQOnyBBhO7OkOMAGrgLopTwY= -cloud.google.com/go/compute v1.23.0/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM= +cloud.google.com/go v0.112.0 h1:tpFCD7hpHFlQ8yPwT3x+QeXqc2T6+n6T+hmABHfDUSM= +cloud.google.com/go v0.112.0/go.mod h1:3jEEVwZ/MHU4djK5t5RHuKOA/GbLddgTdVubX1qnPD4= +cloud.google.com/go/compute v1.23.3 h1:6sVlXXBmbd7jNX0Ipq0trII3e4n1/MsADLK6a+aiVlk= +cloud.google.com/go/compute v1.23.3/go.mod h1:VCgBUoMnIVIR0CscqQiPJLAG25E3ZRZMzcFZeQ+h8CI= cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= -cloud.google.com/go/firestore v1.13.0 h1:/3S4RssUV4GO/kvgJZB+tayjhOfyAHs+KcpJgRVu/Qk= -cloud.google.com/go/firestore v1.13.0/go.mod h1:QojqqOh8IntInDUSTAh0c8ZsPYAr68Ma8c5DWOy8xb8= -cloud.google.com/go/iam v1.1.2 h1:gacbrBdWcoVmGLozRuStX45YKvJtzIjJdAolzUs1sm4= -cloud.google.com/go/iam v1.1.2/go.mod h1:A5avdyVL2tCppe4unb0951eI9jreack+RJ0/d+KUZOU= -cloud.google.com/go/longrunning v0.5.1 h1:Fr7TXftcqTudoyRJa113hyaqlGdiBQkp0Gq7tErFDWI= -cloud.google.com/go/longrunning v0.5.1/go.mod h1:spvimkwdz6SPWKEt/XBij79E9fiTkHSQl/fRUUQJYJc= -cloud.google.com/go/storage v1.30.1 h1:uOdMxAs8HExqBlnLtnQyP0YkvbiDpdGShGKtx6U/oNM= -cloud.google.com/go/storage v1.30.1/go.mod h1:NfxhC0UJE1aXSx7CIIbCf7y9HKT7BiccwkR7+P7gN8E= +cloud.google.com/go/firestore v1.14.0 h1:8aLcKnMPoldYU3YHgu4t2exrKhLQkqaXAGqT0ljrFVw= +cloud.google.com/go/firestore v1.14.0/go.mod h1:96MVaHLsEhbvkBEdZgfN+AS/GIkco1LRpH9Xp9YZfzQ= +cloud.google.com/go/iam v1.1.5 h1:1jTsCu4bcsNsE4iiqNT5SHwrDRCfRmIaaaVFhRveTJI= +cloud.google.com/go/iam v1.1.5/go.mod h1:rB6P/Ic3mykPbFio+vo7403drjlgvoWfYpJhMXEbzv8= +cloud.google.com/go/longrunning v0.5.4 h1:w8xEcbZodnA2BbW6sVirkkoC+1gP8wS57EUUgGS0GVg= +cloud.google.com/go/longrunning v0.5.4/go.mod h1:zqNVncI0BOP8ST6XQD1+VcvuShMmq7+xFSzOL++V0dI= +cloud.google.com/go/storage v1.36.0 h1:P0mOkAcaJxhCTvAkMhxMfrTKiNcub4YmmPBtlhAyTr8= +cloud.google.com/go/storage v1.36.0/go.mod h1:M6M/3V/D3KpzMTJyPOR/HU6n2Si5QdaXYEsng2xgOs8= firebase.google.com/go v3.13.0+incompatible h1:3TdYC3DDi6aHn20qoRkxwGqNgdjtblwVAyRLQwGn/+4= firebase.google.com/go v3.13.0+incompatible/go.mod h1:xlah6XbEyW6tbfSklcfe5FHJIwjt8toICdV5Wh9ptHs= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/IBM/sarama v1.41.3 h1:MWBEJ12vHC8coMjdEXFq/6ftO6DUZnQlFYcxtOJFa7c= -github.com/IBM/sarama v1.41.3/go.mod h1:Xxho9HkHd4K/MDUo/T/sOqwtX/17D33++E9Wib6hUdQ= +github.com/IBM/sarama v1.42.2 h1:VoY4hVIZ+WQJ8G9KNY/SQlWguBQXQ9uvFPOnrcu8hEw= +github.com/IBM/sarama v1.42.2/go.mod h1:FLPGUGwYqEs62hq2bVG6Io2+5n+pS6s/WOXVKWSLFtE= github.com/OpenIMSDK/protocol v0.0.55 h1:eBjg8DyuhxGmuCUjpoZjg6MJJJXU/xJ3xJwFhrn34yA= github.com/OpenIMSDK/protocol v0.0.55/go.mod h1:F25dFrwrIx3lkNoiuf6FkCfxuwf8L4Z8UIsdTHP/r0Y= -github.com/OpenIMSDK/tools v0.0.33 h1:rvFCxXaXxLv1MJFC4qcoWRGwKBnV+hR68UN2N0/zZhE= -github.com/OpenIMSDK/tools v0.0.33/go.mod h1:wBfR5CYmEyvxl03QJbTkhz1CluK6J4/lX0lviu8JAjE= +github.com/OpenIMSDK/tools v0.0.35 h1:YH8UYoaErXqfNrwpUvQxe8nhL++gFH6qCisQPyzk0w8= +github.com/OpenIMSDK/tools v0.0.35/go.mod h1:wBfR5CYmEyvxl03QJbTkhz1CluK6J4/lX0lviu8JAjE= github.com/QcloudApi/qcloud_sign_golang v0.0.0-20141224014652-e4130a326409/go.mod h1:1pk82RBxDY/JZnPQrtqHlUFfCctgdorsd9M06fMynOM= github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7 h1:uSoVVbwJiQipAclBbw+8quDsfcvFjOpI5iCf4p/cqCs= github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs= -github.com/aliyun/aliyun-oss-go-sdk v2.2.9+incompatible h1:Sg/2xHwDrioHpxTN6WMiwbXTpUEinBpHsN7mG21Rc2k= -github.com/aliyun/aliyun-oss-go-sdk v2.2.9+incompatible/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8= +github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible h1:8psS8a+wKfiLt1iVDX79F7Y6wUM49Lcha2FMXt4UM8g= +github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8= github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA= github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= @@ -54,7 +54,8 @@ github.com/clbanning/mxj v1.8.4 h1:HuhwZtbyvyOw+3Z1AowPkU87JkJUSv751ELWaiTpj8I= github.com/clbanning/mxj v1.8.4/go.mod h1:BVjHeAH+rl9rs6f+QIpeRl0tfu10SXn1pUSa5PVGJng= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= -github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/cncf/xds/go v0.0.0-20231109132714-523115ebc101 h1:7To3pQ+pZo0i3dsWEbinPNFs5gPSBOsJtx3wTT94VBY= +github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= @@ -66,8 +67,8 @@ github.com/dtm-labs/rockscache v0.1.1 h1:6S1vgaHvGqrLd8Ka4hRTKeKPV7v+tT0MSkTIX81 github.com/dtm-labs/rockscache v0.1.1/go.mod h1:c76WX0kyIibmQ2ACxUXvDvaLykoPakivMqIxt+UzE7A= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= -github.com/eapache/go-resiliency v1.4.0 h1:3OK9bWpPk5q6pbFAaYSEwD9CLUSHG8bnZuqX2yMt3B0= -github.com/eapache/go-resiliency v1.4.0/go.mod h1:5yPzW0MIvSe0JDsv0v+DvcjEv2FyD6iZYSs1ZI+iQho= +github.com/eapache/go-resiliency v1.5.0 h1:dRsaR00whmQD+SgVKlq/vCRFNgtEb5yppyeVos3Yce0= +github.com/eapache/go-resiliency v1.5.0/go.mod h1:5yPzW0MIvSe0JDsv0v+DvcjEv2FyD6iZYSs1ZI+iQho= github.com/eapache/go-xerial-snappy v0.0.0-20230731223053-c322873962e3 h1:Oy0F4ALJ04o5Qqpdz8XLIpNA3WM/iSIXqxtqo7UGVws= github.com/eapache/go-xerial-snappy v0.0.0-20230731223053-c322873962e3/go.mod h1:YvSRo5mw33fLEx1+DlK6L2VV43tJt5Eyel9n9XBcR+0= github.com/eapache/queue v1.1.0 h1:YOEu7KNc61ntiQlcEeUIoDTJ2o8mQznoNvUhiigpIqc= @@ -78,26 +79,34 @@ github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymF github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/envoyproxy/protoc-gen-validate v1.0.2 h1:QkIBuU5k+x7/QXPvPPnWXWlCdaBFApVqftFV6k087DA= +github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= +github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= -github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= -github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= +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/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= 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/gliderlabs/ssh v0.2.2 h1:6zsha5zo/TWhRhwqCD3+EarCAgZ2yN28ipRnGPnwkI0= github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +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/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= -github.com/go-playground/validator/v10 v10.15.5 h1:LEBecTWb/1j5TNY1YYG2RcOUN3R7NLylN+x8TTueE24= -github.com/go-playground/validator/v10 v10.15.5/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= +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-redis/redis v6.15.9+incompatible h1:K0pv1D7EQUjfyoMql+r/jZqCLizCGKFlFgcHWWmHQjg= github.com/go-redis/redis v6.15.9+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= @@ -115,7 +124,6 @@ github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= @@ -129,7 +137,6 @@ github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaS github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= @@ -152,16 +159,16 @@ github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o= github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU= -github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/enterprise-certificate-proxy v0.3.1 h1:SBWmZhjUDRorQxrN0nwzf+AHBxnbFjViHQS4P0yVpmQ= -github.com/googleapis/enterprise-certificate-proxy v0.3.1/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs= +github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= github.com/googleapis/gax-go/v2 v2.12.0 h1:A+gCJKdRfqXkr+BIRGtZLibNXf0m1f9E4HG56etFpas= github.com/googleapis/gax-go/v2 v2.12.0/go.mod h1:y+aIqrI5eb1YGMVJfuV3185Ts/D7qKpsEkdD5+I6QGU= github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= -github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= -github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY= +github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= @@ -203,7 +210,6 @@ github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd h1:Coekwdh0v github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/klauspost/compress v1.17.4 h1:Ej5ixsIri7BrIjBkRZLTo6ghwrEtHFk7ijlczPW4fZ4= github.com/klauspost/compress v1.17.4/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM= github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= @@ -216,8 +222,8 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= -github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q= -github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= +github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= +github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= github.com/lestrrat-go/envload v0.0.0-20180220234015-a3eb8ddeffcc h1:RKf14vYWi2ttpEmkA4aQ3j4u9dStX2t4M8UM6qqNsG8= github.com/lestrrat-go/envload v0.0.0-20180220234015-a3eb8ddeffcc/go.mod h1:kopuH9ugFRkIXf3YoqHKyrJ9YfUFsckUU9S7B+XP+is= github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible h1:Y6sqxHMyB1D2YSzWkLibYKgg+SwmyFU9dF2hn6MdTj4= @@ -228,12 +234,12 @@ github.com/lithammer/shortuuid v3.0.0+incompatible h1:NcD0xWW/MZYXEHa6ITy6kaXN5n github.com/lithammer/shortuuid v3.0.0+incompatible/go.mod h1:FR74pbAuElzOUuenUHTK2Tciko1/vKuIKS9dSkDrA4w= 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/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= -github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg= +github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k= github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34= github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM= -github.com/minio/minio-go/v7 v7.0.63 h1:GbZ2oCvaUdgT5640WJOpyDhhDxvknAJU2/T3yurwcbQ= -github.com/minio/minio-go/v7 v7.0.63/go.mod h1:Q6X7Qjb7WMhvG65qKf4gUgA5XaiSox74kR1uAEjxRS4= +github.com/minio/minio-go/v7 v7.0.67 h1:BeBvZWAS+kRJm1vGTMJYVjKUNoo0FoEt/wUWdUtfmh8= +github.com/minio/minio-go/v7 v7.0.67/go.mod h1:+UXocnUeZ3wHvVh5s95gcrA4YjMIbccT6ubB+1m054A= github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dzMM= github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= @@ -270,26 +276,26 @@ github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5h github.com/pelletier/go-buffruneio v0.2.0/go.mod h1:JkE26KsDizTr40EUHkXVtNPvgGtbSNq5BcowyYOWdKo= github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ= github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4= -github.com/pierrec/lz4/v4 v4.1.18 h1:xaKrnTkyoqfh1YItXl56+6KJNVYWlEEPuAQW9xsplYQ= -github.com/pierrec/lz4/v4 v4.1.18/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= +github.com/pierrec/lz4/v4 v4.1.21 h1:yOVMLb6qSIDP67pl/5F7RepeKYu/VmTyEXvuMI5d9mQ= +github.com/pierrec/lz4/v4 v4.1.21/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_golang v1.17.0 h1:rl2sfwZMtSthVU752MqfjQozy7blglC+1SOtjMAMh+Q= -github.com/prometheus/client_golang v1.17.0/go.mod h1:VeL+gMmOAxkS2IqfCq0ZmHSL+LjWfWDUmp1mBz9JgUY= +github.com/prometheus/client_golang v1.18.0 h1:HzFfmkOzH5Q8L8G+kSJKUx5dtG87sewO+FoDDqP5Tbk= +github.com/prometheus/client_golang v1.18.0/go.mod h1:T+GXkCk5wSJyOqMIzVgvvjFDlkOQntgjkJWKrN5txjA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16 h1:v7DLqVdK4VrYkVD5diGdl4sxJurKJEMnODWRJlxV9oM= -github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= -github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY= -github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY= -github.com/prometheus/procfs v0.11.1 h1:xRC8Iq1yyca5ypa9n1EZnWZkt7dwcoRPQwX/5gwaUuI= -github.com/prometheus/procfs v0.11.1/go.mod h1:eesXgaPo1q7lBpVMoMy0ZOFTth9hBn4W/y0/p/ScXhY= +github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw= +github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI= +github.com/prometheus/common v0.45.0 h1:2BGz0eBc2hdMDLnO/8n0jeB3oPrt2D08CekT0lneoxM= +github.com/prometheus/common v0.45.0/go.mod h1:YJmSTw9BoKxJplESWWxlbyttQR4uaEcGyv9MZjVOJsY= +github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= +github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 h1:N/ElC8H3+5XpJzTSTfLsJV/mx9Q9g7kxmchpfZyxgzM= github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= -github.com/redis/go-redis/v9 v9.2.1 h1:WlYJg71ODF0dVspZZCpYmoF1+U1Jjk9Rwd7pq6QmlCg= -github.com/redis/go-redis/v9 v9.2.1/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0b/CLO2V2M= +github.com/redis/go-redis/v9 v9.4.0 h1:Yzoz33UZw9I/mFhx4MNrB6Fk+XHO1VukNcCa1+lwyKk= +github.com/redis/go-redis/v9 v9.4.0/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0b/CLO2V2M= github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= @@ -300,8 +306,8 @@ github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= -github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I= -github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= +github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= +github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/src-d/gcfg v1.4.0 h1:xXbNR5AlLSA315x2UO+fTSSAXCDf+Ar38/6oyGbDKQ4= @@ -320,14 +326,13 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.563/go.mod h1:7sCQWVkxcsR38nffDW057DRGk8mUjK1Ing/EFOK8s8Y= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/kms v1.0.563/go.mod h1:uom4Nvi9W+Qkom0exYiJ9VWJjXwyxtPYTkKkaLMlfE0= -github.com/tencentyun/cos-go-sdk-v5 v0.7.45 h1:5/ZGOv846tP6+2X7w//8QjLgH2KcUK+HciFbfjWquFU= -github.com/tencentyun/cos-go-sdk-v5 v0.7.45/go.mod h1:DH9US8nB+AJXqwu/AMOrCFN1COv3dpytXuJWHgdg7kE= +github.com/tencentyun/cos-go-sdk-v5 v0.7.46 h1:IeTiMR8qZ7iQWhAGb1niw5vt0T1TfAwPeB8Gn/oTkuk= +github.com/tencentyun/cos-go-sdk-v5 v0.7.46/go.mod h1:DH9US8nB+AJXqwu/AMOrCFN1COv3dpytXuJWHgdg7kE= github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= 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= @@ -345,10 +350,21 @@ github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7Jul github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -go.mongodb.org/mongo-driver v1.12.1 h1:nLkghSU8fQNaK7oUmDhQFsnrtcoNy7Z6LVFKsEecqgE= -go.mongodb.org/mongo-driver v1.12.1/go.mod h1:/rGBTebI3XYboVmgz+Wv3Bcbl3aD0QF9zl6kDDw18rQ= +go.mongodb.org/mongo-driver v1.14.0 h1:P98w8egYRjYe3XDjxhYJagTokP/H6HzlsnojRgZRd80= +go.mongodb.org/mongo-driver v1.14.0/go.mod h1:Vzb0Mk/pa7e6cWw85R4F/endUC3u0U9jGcNU603k65c= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.47.0 h1:UNQQKPfTDe1J81ViolILjTKPr9WetKW6uei2hFgJmFs= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.47.0/go.mod h1:r9vWsPS/3AQItv3OSlEJ/E4mbrhUbbw18meOjArPtKQ= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.47.0 h1:sv9kVfal0MK0wBMCOGr+HeJm9v803BkJxGrk2au7j08= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.47.0/go.mod h1:SK2UL73Zy1quvRPonmOmRDiWk1KBV3LyIeeIxcEApWw= +go.opentelemetry.io/otel v1.23.0 h1:Df0pqjqExIywbMCMTxkAwzjLZtRf+bBKLbUcpxO2C9E= +go.opentelemetry.io/otel v1.23.0/go.mod h1:YCycw9ZeKhcJFrb34iVSkyT0iczq/zYDtZYFufObyB0= +go.opentelemetry.io/otel/metric v1.23.0 h1:pazkx7ss4LFVVYSxYew7L5I6qvLXHA0Ap2pwV+9Cnpo= +go.opentelemetry.io/otel/metric v1.23.0/go.mod h1:MqUW2X2a6Q8RN96E2/nqNoT+z9BSms20Jb7Bbp+HiTo= +go.opentelemetry.io/otel/sdk v1.21.0 h1:FTt8qirL1EysG6sTQRZ5TokkU8d0ugCj8htOgThZXQ8= +go.opentelemetry.io/otel/trace v1.23.0 h1:37Ik5Ib7xfYVb4V1UtnT97T1jI+AoIYkJyPkuL4iJgI= +go.opentelemetry.io/otel/trace v1.23.0/go.mod h1:GSGTbIClEsuZrGIzoEHqsVfxgn5UkggkflQwDScNUsk= go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= @@ -365,13 +381,12 @@ golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= -golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= -golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= +golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo= +golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/image v0.13.0 h1:3cge/F/QTkNLauhf2QoE9zp+7sr+ZcL4HnoZmdwg9sg= -golang.org/x/image v0.13.0/go.mod h1:6mmbMOeV28HuMTgA6OSRkdXKYw/t5W9Uwn2Yv1r3Yxk= +golang.org/x/image v0.15.0 h1:kOELfmgrmJlw4Cdb7g/QGuB3CvDrXbqEIww/pNtNBm8= +golang.org/x/image v0.15.0/go.mod h1:HUYqC05R2ZcZ3ejNQsIHQDQiwWM4JBqmm6MKANTp4LE= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= @@ -384,7 +399,6 @@ golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -394,24 +408,22 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= -golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c= -golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= +golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4= +golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.13.0 h1:jDDenyj+WgFtmV3zYVoi8aE2BwtXFLWOA67ZfNWftiY= -golang.org/x/oauth2 v0.13.0/go.mod h1:/JMhi4ZRXAf4HG9LiNmxvk+45+96RUlVThiH8FzNBn0= +golang.org/x/oauth2 v0.17.0 h1:6m3ZPmLEFdVxKKWnKq4VqZ60gutO35zm+zrAHVmHyDQ= +golang.org/x/oauth2 v0.17.0/go.mod h1:OzPDGQiuQMguemayvdylqddI7qcD9lnSDb+1FiwQ5HA= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 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-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.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ= -golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +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/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -434,12 +446,12 @@ golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= -golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y= +golang.org/x/sys v0.17.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= -golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4= +golang.org/x/term v0.17.0 h1:mkTF7LCd6WGJNL3K1Ad7kwxNfYAW6a8a8QqtMblp/4U= 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= @@ -467,29 +479,28 @@ golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8T 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= golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk= -golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= -google.golang.org/api v0.148.0 h1:HBq4TZlN4/1pNcu0geJZ/Q50vIwIXT532UIMYoo0vOs= -google.golang.org/api v0.148.0/go.mod h1:8/TBgwaKjfqTdacOJrOv2+2Q6fBDU1uHKK06oGSkxzU= +google.golang.org/api v0.165.0 h1:zd5d4JIIIaYYsfVy1HzoXYZ9rWCSBxxAglbczzo7Bgc= +google.golang.org/api v0.165.0/go.mod h1:2OatzO7ZDQsoS7IFf3rvsE17/TldiU3F/zxFHeqUB5o= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= -google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= +google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto v0.0.0-20231002182017-d307bd883b97 h1:SeZZZx0cP0fqUyA+oRzP9k7cSwJlvDFiROO72uwD6i0= -google.golang.org/genproto v0.0.0-20231002182017-d307bd883b97/go.mod h1:t1VqOqqvce95G3hIDCT5FeO3YUc6Q4Oe24L/+rNMxRk= -google.golang.org/genproto/googleapis/api v0.0.0-20231002182017-d307bd883b97 h1:W18sezcAYs+3tDZX4F80yctqa12jcP1PUS2gQu1zTPU= -google.golang.org/genproto/googleapis/api v0.0.0-20231002182017-d307bd883b97/go.mod h1:iargEX0SFPm3xcfMI0d1domjg0ZF4Aa0p2awqyxhvF0= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231012201019-e917dd12ba7a h1:a2MQQVoTo96JC9PMGtGBymLp7+/RzpFc2yX/9WfFg1c= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231012201019-e917dd12ba7a/go.mod h1:4cYg8o5yUbm77w8ZX00LhMVNl/YVBFJRYWDc0uYWMs0= +google.golang.org/genproto v0.0.0-20240125205218-1f4bbc51befe h1:USL2DhxfgRchafRvt/wYyyQNzwgL7ZiURcozOE/Pkvo= +google.golang.org/genproto v0.0.0-20240125205218-1f4bbc51befe/go.mod h1:cc8bqMqtv9gMOr0zHg2Vzff5ULhhL2IXP4sbcn32Dro= +google.golang.org/genproto/googleapis/api v0.0.0-20240116215550-a9fa1716bcac h1:OZkkudMUu9LVQMCoRUbI/1p5VCo9BOrlvkqMvWtqa6s= +google.golang.org/genproto/googleapis/api v0.0.0-20240116215550-a9fa1716bcac/go.mod h1:B5xPO//w8qmBDjGReYLpR6UJPnkldGkCSMoH/2vxJeg= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240205150955-31a09d347014 h1:FSL3lRCkhaPFxqi0s9o+V4UI2WTzAVOvkgbd4kVV4Wg= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240205150955-31a09d347014/go.mod h1:SaPjaZGWb0lPqs6Ittu0spdfrOArqji4ZdeP5IC/9N4= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= -google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk= -google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98= +google.golang.org/grpc v1.61.0 h1:TOvOcuXn30kRao+gfcvsebNEa5iZIiLkisYEkf7R7o0= +google.golang.org/grpc v1.61.0/go.mod h1:VUbo7IFqmF1QtCAstipjG0GIoq49KvMe9+h1jFLBNJs= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -501,8 +512,8 @@ google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpAD google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= -google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I= +google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= From c754ec6e97e457540375109158bff93fc5a70f14 Mon Sep 17 00:00:00 2001 From: Brabem <69128477+luhaoling@users.noreply.github.com> Date: Sun, 18 Feb 2024 20:16:47 +0800 Subject: [PATCH 046/188] fix: refactoring code of graceful exits (#1885) * fix: plant a layer * fix: print chanal * fix: print sigs * fix: print the sigs * fix: reconstruct exit gracefully * fix: fix the timeout * fix: fix the netDone * fix: fix the process exit * fix: refactor the elegant startup code * fix: fix the Signal.Notify * fix: fix the code * fix: remove not used header import. * Update init.go * fix: fix the InitConfig error * fix: fix branch name * fix: fix the signal value * fix: replace the signal with SIGTERM * fix: fix the script * fix: fix the unsolve error * fix: return the SIGTERM received,shutting down * fix: fix the tranfer exit error * fix: fix the error * fix: replace the SIGnal * fix: del the error return in tranfer * fix: fix SIGTERM error * fix: del the unreachalbe code * fix: fix the make stop print error --------- Co-authored-by: OpenIM-Gordon <46924906+FGadvancer@users.noreply.github.com> Co-authored-by: Xinwei Xiong (cubxxw) <3293172751nss@gmail.com> --- cmd/openim-api/main.go | 44 ++++++--- cmd/openim-cmdutils/main.go | 7 +- cmd/openim-crontask/main.go | 7 +- cmd/openim-msggateway/main.go | 7 +- cmd/openim-msgtransfer/main.go | 7 +- cmd/openim-push/main.go | 7 +- cmd/openim-rpc/openim-rpc-auth/main.go | 8 +- .../openim-rpc-conversation/main.go | 7 +- cmd/openim-rpc/openim-rpc-friend/main.go | 7 +- cmd/openim-rpc/openim-rpc-group/main.go | 7 +- cmd/openim-rpc/openim-rpc-msg/main.go | 7 +- cmd/openim-rpc/openim-rpc-third/main.go | 7 +- cmd/openim-rpc/openim-rpc-user/main.go | 7 +- internal/msggateway/init.go | 21 +---- internal/msggateway/n_ws_server.go | 67 ++++++-------- internal/msgtransfer/init.go | 91 ++++++++----------- internal/push/callback.go | 2 +- internal/push/consumer_init.go | 10 +- internal/push/push_rpc_server.go | 23 ++--- internal/tools/cron_task.go | 2 +- pkg/common/ginprometheus/ginprometheus.go | 22 +++-- pkg/common/kafka/consumer_group.go | 31 ++----- pkg/common/startrpc/start.go | 88 +++++++++++------- pkg/util/genutil/genutil.go | 15 +++ scripts/githooks/pre-commit.sh | 2 +- scripts/install/openim-push.sh | 2 +- scripts/lib/util.sh | 4 +- 27 files changed, 241 insertions(+), 268 deletions(-) diff --git a/cmd/openim-api/main.go b/cmd/openim-api/main.go index bbb5eb9687..c8746bc20b 100644 --- a/cmd/openim-api/main.go +++ b/cmd/openim-api/main.go @@ -17,6 +17,7 @@ package main import ( "context" "fmt" + util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" "net" "net/http" _ "net/http/pprof" @@ -46,8 +47,7 @@ func main() { apiCmd.AddPrometheusPortFlag() apiCmd.AddApi(run) if err := apiCmd.Execute(); err != nil { - fmt.Fprintf(os.Stderr, "\n\nexit -1: \n%+v\n\n", err) - os.Exit(-1) + util.ExitWithError(err) } } @@ -76,12 +76,21 @@ func run(port int, proPort int) error { if err = client.RegisterConf2Registry(constant.OpenIMCommonConfigKey, config.Config.EncodeConfig()); err != nil { return err } - + var ( + netDone = make(chan struct{}, 1) + netErr error + ) router := api.NewGinRouter(client, rdb) if config.Config.Prometheus.Enable { - p := ginprom.NewPrometheus("app", prommetrics.GetGinCusMetrics("Api")) - p.SetListenAddress(fmt.Sprintf(":%d", proPort)) - p.Use(router) + go func() { + p := ginprom.NewPrometheus("app", prommetrics.GetGinCusMetrics("Api")) + p.SetListenAddress(fmt.Sprintf(":%d", proPort)) + if err = p.Use(router); err != nil && err != http.ErrServerClosed { + netErr = errs.Wrap(err, fmt.Sprintf("prometheus start err: %d", proPort)) + netDone <- struct{}{} + } + }() + } var address string @@ -92,24 +101,31 @@ func run(port int, proPort int) error { } server := http.Server{Addr: address, Handler: router} + go func() { err = server.ListenAndServe() if err != nil && err != http.ErrServerClosed { - os.Exit(1) + netErr = errs.Wrap(err, fmt.Sprintf("api start err: %s", server.Addr)) + netDone <- struct{}{} + } }() sigs := make(chan os.Signal, 1) - signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT) - <-sigs + signal.Notify(sigs, syscall.SIGTERM) ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) defer cancel() - - // graceful shutdown operation. - if err := server.Shutdown(ctx); err != nil { - return err + select { + case <-sigs: + util.SIGUSR1Exit() + err := server.Shutdown(ctx) + if err != nil { + return errs.Wrap(err, "shutdown err") + } + case <-netDone: + close(netDone) + return netErr } - return nil } diff --git a/cmd/openim-cmdutils/main.go b/cmd/openim-cmdutils/main.go index 45b324766f..f6b7889331 100644 --- a/cmd/openim-cmdutils/main.go +++ b/cmd/openim-cmdutils/main.go @@ -15,10 +15,8 @@ package main import ( - "fmt" - "os" - "github.com/openimsdk/open-im-server/v3/pkg/common/cmd" + util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" ) func main() { @@ -57,7 +55,6 @@ func main() { // openIM clear msg --clearAll msgUtilsCmd.AddCommand(&getCmd.Command, &fixCmd.Command, &clearCmd.Command) if err := msgUtilsCmd.Execute(); err != nil { - fmt.Fprintf(os.Stderr, "\n\nexit -1: \n%+v\n\n", err) - os.Exit(-1) + util.ExitWithError(err) } } diff --git a/cmd/openim-crontask/main.go b/cmd/openim-crontask/main.go index 324001690a..b284fd7739 100644 --- a/cmd/openim-crontask/main.go +++ b/cmd/openim-crontask/main.go @@ -15,17 +15,14 @@ package main import ( - "fmt" - "os" - "github.com/openimsdk/open-im-server/v3/internal/tools" "github.com/openimsdk/open-im-server/v3/pkg/common/cmd" + util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" ) func main() { cronTaskCmd := cmd.NewCronTaskCmd() if err := cronTaskCmd.Exec(tools.StartTask); err != nil { - fmt.Fprintf(os.Stderr, "\n\nexit -1: \n%+v\n\n", err) - os.Exit(-1) + util.ExitWithError(err) } } diff --git a/cmd/openim-msggateway/main.go b/cmd/openim-msggateway/main.go index 5339891c88..ed67b8f5d1 100644 --- a/cmd/openim-msggateway/main.go +++ b/cmd/openim-msggateway/main.go @@ -15,10 +15,8 @@ package main import ( - "fmt" - "os" - "github.com/openimsdk/open-im-server/v3/pkg/common/cmd" + util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" ) func main() { @@ -28,7 +26,6 @@ func main() { msgGatewayCmd.AddPrometheusPortFlag() if err := msgGatewayCmd.Exec(); err != nil { - fmt.Fprintf(os.Stderr, "\n\nexit -1: \n%+v\n\n", err) - os.Exit(-1) + util.ExitWithError(err) } } diff --git a/cmd/openim-msgtransfer/main.go b/cmd/openim-msgtransfer/main.go index cf1b44a55f..84fbbd2ea1 100644 --- a/cmd/openim-msgtransfer/main.go +++ b/cmd/openim-msgtransfer/main.go @@ -15,10 +15,8 @@ package main import ( - "fmt" - "os" - "github.com/openimsdk/open-im-server/v3/pkg/common/cmd" + util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" ) func main() { @@ -26,7 +24,6 @@ func main() { msgTransferCmd.AddPrometheusPortFlag() msgTransferCmd.AddTransferProgressFlag() if err := msgTransferCmd.Exec(); err != nil { - fmt.Fprintf(os.Stderr, "\n\nexit -1: \n%+v\n\n", err) - os.Exit(-1) + util.ExitWithError(err) } } diff --git a/cmd/openim-push/main.go b/cmd/openim-push/main.go index 77f75cb4e2..e0539fa52c 100644 --- a/cmd/openim-push/main.go +++ b/cmd/openim-push/main.go @@ -15,12 +15,10 @@ package main import ( - "fmt" - "os" - "github.com/openimsdk/open-im-server/v3/internal/push" "github.com/openimsdk/open-im-server/v3/pkg/common/cmd" "github.com/openimsdk/open-im-server/v3/pkg/common/config" + util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" ) func main() { @@ -31,7 +29,6 @@ func main() { panic(err.Error()) } if err := pushCmd.StartSvr(config.Config.RpcRegisterName.OpenImPushName, push.Start); err != nil { - fmt.Fprintf(os.Stderr, "\n\nexit -1: \n%+v\n\n", err) - os.Exit(-1) + util.ExitWithError(err) } } diff --git a/cmd/openim-rpc/openim-rpc-auth/main.go b/cmd/openim-rpc/openim-rpc-auth/main.go index b29efd484f..b526c3b86e 100644 --- a/cmd/openim-rpc/openim-rpc-auth/main.go +++ b/cmd/openim-rpc/openim-rpc-auth/main.go @@ -15,12 +15,10 @@ package main import ( - "fmt" - "os" - "github.com/openimsdk/open-im-server/v3/internal/rpc/auth" "github.com/openimsdk/open-im-server/v3/pkg/common/cmd" "github.com/openimsdk/open-im-server/v3/pkg/common/config" + util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" ) func main() { @@ -31,7 +29,7 @@ func main() { panic(err.Error()) } if err := authCmd.StartSvr(config.Config.RpcRegisterName.OpenImAuthName, auth.Start); err != nil { - fmt.Fprintf(os.Stderr, "\n\nexit -1: \n%+v\n\n", err) - os.Exit(-1) + util.ExitWithError(err) } + } diff --git a/cmd/openim-rpc/openim-rpc-conversation/main.go b/cmd/openim-rpc/openim-rpc-conversation/main.go index f9ac8cd279..bde191c518 100644 --- a/cmd/openim-rpc/openim-rpc-conversation/main.go +++ b/cmd/openim-rpc/openim-rpc-conversation/main.go @@ -15,12 +15,10 @@ package main import ( - "fmt" - "os" - "github.com/openimsdk/open-im-server/v3/internal/rpc/conversation" "github.com/openimsdk/open-im-server/v3/pkg/common/cmd" "github.com/openimsdk/open-im-server/v3/pkg/common/config" + util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" ) func main() { @@ -31,7 +29,6 @@ func main() { panic(err.Error()) } if err := rpcCmd.StartSvr(config.Config.RpcRegisterName.OpenImConversationName, conversation.Start); err != nil { - fmt.Fprintf(os.Stderr, "\n\nexit -1: \n%+v\n\n", err) - os.Exit(-1) + util.ExitWithError(err) } } diff --git a/cmd/openim-rpc/openim-rpc-friend/main.go b/cmd/openim-rpc/openim-rpc-friend/main.go index 82d71d522f..8eeb9c8e13 100644 --- a/cmd/openim-rpc/openim-rpc-friend/main.go +++ b/cmd/openim-rpc/openim-rpc-friend/main.go @@ -15,12 +15,10 @@ package main import ( - "fmt" - "os" - "github.com/openimsdk/open-im-server/v3/internal/rpc/friend" "github.com/openimsdk/open-im-server/v3/pkg/common/cmd" "github.com/openimsdk/open-im-server/v3/pkg/common/config" + util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" ) func main() { @@ -31,7 +29,6 @@ func main() { panic(err.Error()) } if err := rpcCmd.StartSvr(config.Config.RpcRegisterName.OpenImFriendName, friend.Start); err != nil { - fmt.Fprintf(os.Stderr, "\n\nexit -1: \n%+v\n\n", err) - os.Exit(-1) + util.ExitWithError(err) } } diff --git a/cmd/openim-rpc/openim-rpc-group/main.go b/cmd/openim-rpc/openim-rpc-group/main.go index 360042f849..a5842ffd13 100644 --- a/cmd/openim-rpc/openim-rpc-group/main.go +++ b/cmd/openim-rpc/openim-rpc-group/main.go @@ -15,12 +15,10 @@ package main import ( - "fmt" - "os" - "github.com/openimsdk/open-im-server/v3/internal/rpc/group" "github.com/openimsdk/open-im-server/v3/pkg/common/cmd" "github.com/openimsdk/open-im-server/v3/pkg/common/config" + util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" ) func main() { @@ -31,7 +29,6 @@ func main() { panic(err.Error()) } if err := rpcCmd.StartSvr(config.Config.RpcRegisterName.OpenImGroupName, group.Start); err != nil { - fmt.Fprintf(os.Stderr, "\n\nexit -1: \n%+v\n\n", err) - os.Exit(-1) + util.ExitWithError(err) } } diff --git a/cmd/openim-rpc/openim-rpc-msg/main.go b/cmd/openim-rpc/openim-rpc-msg/main.go index bed57f5224..b3895a5027 100644 --- a/cmd/openim-rpc/openim-rpc-msg/main.go +++ b/cmd/openim-rpc/openim-rpc-msg/main.go @@ -15,12 +15,10 @@ package main import ( - "fmt" - "os" - "github.com/openimsdk/open-im-server/v3/internal/rpc/msg" "github.com/openimsdk/open-im-server/v3/pkg/common/cmd" "github.com/openimsdk/open-im-server/v3/pkg/common/config" + util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" ) func main() { @@ -31,7 +29,6 @@ func main() { panic(err.Error()) } if err := rpcCmd.StartSvr(config.Config.RpcRegisterName.OpenImMsgName, msg.Start); err != nil { - fmt.Fprintf(os.Stderr, "\n\nexit -1: \n%+v\n\n", err) - os.Exit(-1) + util.ExitWithError(err) } } diff --git a/cmd/openim-rpc/openim-rpc-third/main.go b/cmd/openim-rpc/openim-rpc-third/main.go index 4868ce149e..8f390bb6a4 100644 --- a/cmd/openim-rpc/openim-rpc-third/main.go +++ b/cmd/openim-rpc/openim-rpc-third/main.go @@ -15,12 +15,10 @@ package main import ( - "fmt" - "os" - "github.com/openimsdk/open-im-server/v3/internal/rpc/third" "github.com/openimsdk/open-im-server/v3/pkg/common/cmd" "github.com/openimsdk/open-im-server/v3/pkg/common/config" + util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" ) func main() { @@ -31,7 +29,6 @@ func main() { panic(err.Error()) } if err := rpcCmd.StartSvr(config.Config.RpcRegisterName.OpenImThirdName, third.Start); err != nil { - fmt.Fprintf(os.Stderr, "\n\nexit -1: \n%+v\n\n", err) - os.Exit(-1) + util.ExitWithError(err) } } diff --git a/cmd/openim-rpc/openim-rpc-user/main.go b/cmd/openim-rpc/openim-rpc-user/main.go index a77a2f768d..6994ea2b15 100644 --- a/cmd/openim-rpc/openim-rpc-user/main.go +++ b/cmd/openim-rpc/openim-rpc-user/main.go @@ -15,12 +15,10 @@ package main import ( - "fmt" - "os" - "github.com/openimsdk/open-im-server/v3/internal/rpc/user" "github.com/openimsdk/open-im-server/v3/pkg/common/cmd" "github.com/openimsdk/open-im-server/v3/pkg/common/config" + util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" ) func main() { @@ -31,7 +29,6 @@ func main() { panic(err.Error()) } if err := rpcCmd.StartSvr(config.Config.RpcRegisterName.OpenImUserName, user.Start); err != nil { - fmt.Fprintf(os.Stderr, "\n\nexit -1: \n%+v\n\n", err) - os.Exit(-1) + util.ExitWithError(err) } } diff --git a/internal/msggateway/init.go b/internal/msggateway/init.go index aeba0a24a7..321407f7ee 100644 --- a/internal/msggateway/init.go +++ b/internal/msggateway/init.go @@ -18,9 +18,6 @@ import ( "fmt" "time" - "github.com/OpenIMSDK/tools/utils" - "golang.org/x/sync/errgroup" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" ) @@ -46,20 +43,12 @@ func RunWsAndServer(rpcPort, wsPort, prometheusPort int) error { } hubServer := NewServer(rpcPort, prometheusPort, longServer) - - wg := errgroup.Group{} - wg.Go(func() error { + netDone := make(chan error) + go func() { err = hubServer.Start() if err != nil { - return utils.Wrap1(err) + netDone <- err } - return err - }) - - wg.Go(func() error { - return hubServer.LongConnServer.Run() - }) - - err = wg.Wait() - return err + }() + return hubServer.LongConnServer.Run(netDone) } diff --git a/internal/msggateway/n_ws_server.go b/internal/msggateway/n_ws_server.go index 01d92b92ac..c16da7c647 100644 --- a/internal/msggateway/n_ws_server.go +++ b/internal/msggateway/n_ws_server.go @@ -20,12 +20,9 @@ import ( "errors" "fmt" "net/http" - "os" - "os/signal" "strconv" "sync" "sync/atomic" - "syscall" "time" "github.com/OpenIMSDK/tools/apiresp" @@ -49,7 +46,7 @@ import ( ) type LongConnServer interface { - Run() error + Run(done chan error) error wsHandler(w http.ResponseWriter, r *http.Request) GetUserAllCons(userID string) ([]*Client, bool) GetUserPlatformCons(userID string, platform int) ([]*Client, bool, bool) @@ -169,23 +166,20 @@ func NewWsServer(opts ...Option) (*WsServer, error) { }, nil } -func (ws *WsServer) Run() error { +func (ws *WsServer) Run(done chan error) error { var ( - client *Client - wg errgroup.Group - - sigs = make(chan os.Signal, 1) - done = make(chan struct{}, 1) + client *Client + netErr error + shutdownDone = make(chan struct{}, 1) ) server := http.Server{Addr: ":" + utils.IntToString(ws.port), Handler: nil} - wg.Go(func() error { + go func() { for { select { - case <-done: - return nil - + case <-shutdownDone: + return case client = <-ws.registerChan: ws.registerClient(client) case client = <-ws.unregisterChan: @@ -194,33 +188,32 @@ func (ws *WsServer) Run() error { ws.multiTerminalLoginChecker(onlineInfo.clientOK, onlineInfo.oldClients, onlineInfo.newClient) } } - }) - - wg.Go(func() error { - http.HandleFunc("/", ws.wsHandler) - return server.ListenAndServe() - }) - - signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT) - <-sigs - + }() + netDone := make(chan struct{}, 1) go func() { - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) - defer cancel() - - // graceful exit operation for server - _ = server.Shutdown(ctx) - _ = wg.Wait() - close(done) + http.HandleFunc("/", ws.wsHandler) + err := server.ListenAndServe() + if err != nil && err != http.ErrServerClosed { + netErr = errs.Wrap(err, "ws start err", server.Addr) + close(netDone) + } }() - + ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) + defer cancel() + var err error select { - case <-done: - return nil - - case <-time.After(15 * time.Second): - return utils.Wrap1(errors.New("timeout exit")) + case err = <-done: + sErr := server.Shutdown(ctx) + if sErr != nil { + return errs.Wrap(sErr, "shutdown err") + } + close(shutdownDone) + if err != nil { + return err + } + case <-netDone: } + return netErr } diff --git a/internal/msgtransfer/init.go b/internal/msgtransfer/init.go index 65518c3246..062017f448 100644 --- a/internal/msgtransfer/init.go +++ b/internal/msgtransfer/init.go @@ -18,23 +18,11 @@ import ( "context" "errors" "fmt" - "net/http" - "os" - "os/signal" - "sync" - "syscall" - "time" - "github.com/OpenIMSDK/tools/errs" - "github.com/OpenIMSDK/tools/log" - "github.com/OpenIMSDK/tools/mw" - "github.com/prometheus/client_golang/prometheus" - "github.com/prometheus/client_golang/prometheus/collectors" - "github.com/prometheus/client_golang/prometheus/promhttp" - "google.golang.org/grpc" - "google.golang.org/grpc/credentials/insecure" + util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" + "github.com/OpenIMSDK/tools/mw" "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" @@ -42,12 +30,22 @@ import ( kdisc "github.com/openimsdk/open-im-server/v3/pkg/common/discoveryregister" "github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/collectors" + "github.com/prometheus/client_golang/prometheus/promhttp" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" + "net/http" + "os" + "os/signal" + "syscall" ) type MsgTransfer struct { historyCH *OnlineHistoryRedisConsumerHandler // 这个消费者聚合消息, 订阅的topic:ws2ms_chat, 修改通知发往msg_to_modify topic, 消息存入redis后Incr Redis, 再发消息到ms2pschat topic推送, 发消息到msg_to_mongo topic持久化 historyMongoCH *OnlineHistoryMongoConsumerHandler // mongoDB批量插入, 成功后删除redis中消息,以及处理删除通知消息删除的 订阅的topic: msg_to_mongo - // modifyCH *ModifyMsgConsumerHandler // 负责消费修改消息通知的consumer, 订阅的topic: msg_to_modify + ctx context.Context + cancel context.CancelFunc } func StartTransfer(prometheusPort int) error { @@ -65,10 +63,6 @@ func StartTransfer(prometheusPort int) error { return err } client, err := kdisc.NewDiscoveryRegister(config.Config.Envs.Discovery) - /* - client, err := openkeeper.NewClient(config.Config.Zookeeper.ZkAddr, config.Config.Zookeeper.Schema, - openkeeper.WithFreq(time.Hour), openkeeper.WithRoundRobin(), openkeeper.WithUserNameAndPassword(config.Config.Zookeeper.Username, - config.Config.Zookeeper.Password), openkeeper.WithTimeout(10), openkeeper.WithLogger(log.NewZkLogger()))*/ if err != nil { return err } @@ -109,27 +103,22 @@ func NewMsgTransfer(msgDatabase controller.CommonMsgDatabase, conversationRpcCli } func (m *MsgTransfer) Start(prometheusPort int) error { - ctx := context.Background() fmt.Println("start msg transfer", "prometheusPort:", prometheusPort) if prometheusPort <= 0 { return errs.Wrap(errors.New("prometheusPort not correct")) } + m.ctx, m.cancel = context.WithCancel(context.Background()) - var wg sync.WaitGroup + var ( + netDone = make(chan struct{}, 1) + netErr error + ) - wg.Add(1) - go func() { - defer wg.Done() - - m.historyCH.historyConsumerGroup.RegisterHandleAndConsumer(ctx, m.historyCH) - }() - - wg.Add(1) - go func() { - defer wg.Done() - - m.historyMongoCH.historyConsumerGroup.RegisterHandleAndConsumer(ctx, m.historyMongoCH) - }() + onError := func(ctx context.Context, err error, errInfo string) { + log.ZWarn(ctx, errInfo, err) + } + go m.historyCH.historyConsumerGroup.RegisterHandleAndConsumer(m.ctx, m.historyCH, onError) + go m.historyMongoCH.historyConsumerGroup.RegisterHandleAndConsumer(m.ctx, m.historyMongoCH, onError) if config.Config.Prometheus.Enable { go func() { @@ -141,30 +130,28 @@ func (m *MsgTransfer) Start(prometheusPort int) error { http.Handle("/metrics", promhttp.HandlerFor(proreg, promhttp.HandlerOpts{Registry: proreg})) err := http.ListenAndServe(fmt.Sprintf(":%d", prometheusPort), nil) if err != nil && err != http.ErrServerClosed { - panic(err) + netErr = errs.Wrap(err, fmt.Sprintf("prometheus start err: %d", prometheusPort)) + netDone <- struct{}{} } }() } sigs := make(chan os.Signal, 1) - signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT) - <-sigs - - // graceful close kafka client. - go m.historyCH.historyConsumerGroup.Close() - go m.historyMongoCH.historyConsumerGroup.Close() - - done := make(chan struct{}, 1) - go func() { - wg.Wait() - close(done) - }() - + signal.Notify(sigs, syscall.SIGTERM) select { - case <-done: - log.ZInfo(context.Background(), "msgtrasfer exit successfully") - case <-time.After(15 * time.Second): - log.ZError(context.Background(), "msgtransfer force to exit, timeout 15s", nil) + case <-sigs: + util.SIGUSR1Exit() + // graceful close kafka client. + m.cancel() + m.historyCH.historyConsumerGroup.Close() + m.historyMongoCH.historyConsumerGroup.Close() + + case <-netDone: + m.cancel() + m.historyCH.historyConsumerGroup.Close() + m.historyMongoCH.historyConsumerGroup.Close() + close(netDone) + return netErr } return nil diff --git a/internal/push/callback.go b/internal/push/callback.go index 99a58fb07f..a572fa572c 100644 --- a/internal/push/callback.go +++ b/internal/push/callback.go @@ -130,7 +130,7 @@ func callbackBeforeSuperGroupOnlinePush( if err := http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, req, resp, config.Config.Callback.CallbackBeforeSuperGroupOnlinePush); err != nil { return err } - return nil + if len(resp.UserIDs) != 0 { *pushToUserIDs = resp.UserIDs } diff --git a/internal/push/consumer_init.go b/internal/push/consumer_init.go index ceab861653..80478de99d 100644 --- a/internal/push/consumer_init.go +++ b/internal/push/consumer_init.go @@ -14,7 +14,10 @@ package push -import "context" +import ( + "context" + "github.com/OpenIMSDK/tools/log" +) type Consumer struct { pushCh ConsumerHandler @@ -32,6 +35,9 @@ func NewConsumer(pusher *Pusher) (*Consumer, error) { } func (c *Consumer) Start() { + onError := func(ctx context.Context, err error, errInfo string) { + log.ZWarn(ctx, errInfo, err) + } + go c.pushCh.pushConsumerGroup.RegisterHandleAndConsumer(context.Background(), &c.pushCh, onError) - go c.pushCh.pushConsumerGroup.RegisterHandleAndConsumer(context.Background(), &c.pushCh) } diff --git a/internal/push/push_rpc_server.go b/internal/push/push_rpc_server.go index c1226ce6bc..caaf955259 100644 --- a/internal/push/push_rpc_server.go +++ b/internal/push/push_rpc_server.go @@ -16,8 +16,6 @@ package push import ( "context" - "sync" - "github.com/OpenIMSDK/tools/utils" "google.golang.org/grpc" @@ -58,23 +56,18 @@ func Start(client discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) e &groupRpcClient, &msgRpcClient, ) - var wg sync.WaitGroup - wg.Add(2) - go func() { - defer wg.Done() - pbpush.RegisterPushMsgServiceServer(server, &pushServer{ - pusher: pusher, - }) - }() + + pbpush.RegisterPushMsgServiceServer(server, &pushServer{ + pusher: pusher, + }) + consumer, err := NewConsumer(pusher) if err != nil { return err } - go func() { - defer wg.Done() - consumer.Start() - }() - wg.Wait() + + consumer.Start() + return nil } diff --git a/internal/tools/cron_task.go b/internal/tools/cron_task.go index 40e1c0a874..decc1aa826 100644 --- a/internal/tools/cron_task.go +++ b/internal/tools/cron_task.go @@ -64,7 +64,7 @@ func StartTask() error { crontab.Start() sigs := make(chan os.Signal, 1) - signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT) + signal.Notify(sigs, syscall.SIGTERM) <-sigs // stop crontab, Wait for the running task to exit. diff --git a/pkg/common/ginprometheus/ginprometheus.go b/pkg/common/ginprometheus/ginprometheus.go index 1ee8f8e34f..c2e6bdcca0 100644 --- a/pkg/common/ginprometheus/ginprometheus.go +++ b/pkg/common/ginprometheus/ginprometheus.go @@ -197,30 +197,32 @@ func (p *Prometheus) SetListenAddressWithRouter(listenAddress string, r *gin.Eng } // SetMetricsPath set metrics paths. -func (p *Prometheus) SetMetricsPath(e *gin.Engine) { +func (p *Prometheus) SetMetricsPath(e *gin.Engine) error { if p.listenAddress != "" { p.router.GET(p.MetricsPath, prometheusHandler()) - p.runServer() + return p.runServer() } else { e.GET(p.MetricsPath, prometheusHandler()) + return nil } } // SetMetricsPathWithAuth set metrics paths with authentication. -func (p *Prometheus) SetMetricsPathWithAuth(e *gin.Engine, accounts gin.Accounts) { +func (p *Prometheus) SetMetricsPathWithAuth(e *gin.Engine, accounts gin.Accounts) error { if p.listenAddress != "" { p.router.GET(p.MetricsPath, gin.BasicAuth(accounts), prometheusHandler()) - p.runServer() + return p.runServer() } else { e.GET(p.MetricsPath, gin.BasicAuth(accounts), prometheusHandler()) + return nil } } -func (p *Prometheus) runServer() { - go p.router.Run(p.listenAddress) +func (p *Prometheus) runServer() error { + return p.router.Run(p.listenAddress) } func (p *Prometheus) getMetrics() []byte { @@ -366,15 +368,15 @@ func (p *Prometheus) registerMetrics(subsystem string) { } // Use adds the middleware to a gin engine. -func (p *Prometheus) Use(e *gin.Engine) { +func (p *Prometheus) Use(e *gin.Engine) error { e.Use(p.HandlerFunc()) - p.SetMetricsPath(e) + return p.SetMetricsPath(e) } // UseWithAuth adds the middleware to a gin engine with BasicAuth. -func (p *Prometheus) UseWithAuth(e *gin.Engine, accounts gin.Accounts) { +func (p *Prometheus) UseWithAuth(e *gin.Engine, accounts gin.Accounts) error { e.Use(p.HandlerFunc()) - p.SetMetricsPathWithAuth(e, accounts) + return p.SetMetricsPathWithAuth(e, accounts) } // HandlerFunc defines handler function for middleware. diff --git a/pkg/common/kafka/consumer_group.go b/pkg/common/kafka/consumer_group.go index 5bff50d880..908b8f088b 100644 --- a/pkg/common/kafka/consumer_group.go +++ b/pkg/common/kafka/consumer_group.go @@ -17,19 +17,16 @@ package kafka import ( "context" "errors" - "strings" - + "fmt" "github.com/IBM/sarama" "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/log" "github.com/openimsdk/open-im-server/v3/pkg/common/config" + "strings" ) type MConsumerGroup struct { - ctx context.Context - cancel context.CancelFunc - sarama.ConsumerGroup groupID string topics []string @@ -57,9 +54,7 @@ func NewMConsumerGroup(consumerConfig *MConsumerGroupConfig, topics, addrs []str return nil, errs.Wrap(err, strings.Join(topics, ","), strings.Join(addrs, ","), groupID, config.Config.Kafka.Username, config.Config.Kafka.Password) } - ctx, cancel := context.WithCancel(context.Background()) return &MConsumerGroup{ - ctx, cancel, consumerGroup, groupID, topics, @@ -70,27 +65,21 @@ func (mc *MConsumerGroup) GetContextFromMsg(cMsg *sarama.ConsumerMessage) contex return GetContextWithMQHeader(cMsg.Headers) } -func (mc *MConsumerGroup) RegisterHandleAndConsumer(ctx context.Context, handler sarama.ConsumerGroupHandler) { - log.ZDebug(context.Background(), "register consumer group", "groupID", mc.groupID) +func (mc *MConsumerGroup) RegisterHandleAndConsumer(ctx context.Context, handler sarama.ConsumerGroupHandler, onError func(context.Context, error, string)) { + log.ZDebug(ctx, "register consumer group", "groupID", mc.groupID) for { - err := mc.ConsumerGroup.Consume(mc.ctx, mc.topics, handler) - if errors.Is(err, sarama.ErrClosedConsumerGroup) { + err := mc.ConsumerGroup.Consume(ctx, mc.topics, handler) + if errors.Is(err, sarama.ErrClosedConsumerGroup) || errors.Is(err, context.Canceled) { return } - if mc.ctx.Err() != nil { - return - } - if err != nil { - log.ZWarn(ctx, "consume err", err, "topic", mc.topics, "groupID", mc.groupID) - } - if ctx.Err() != nil { + errInfo := fmt.Sprintf("consume err: %v, topic: %v, groupID: %s", err, strings.Join(mc.topics, ", "), mc.groupID) + onError(ctx, err, errInfo) // 调用回调函数处理错误 return } } } -func (mc *MConsumerGroup) Close() { - mc.cancel() - mc.ConsumerGroup.Close() +func (mc *MConsumerGroup) Close() error { + return mc.ConsumerGroup.Close() } diff --git a/pkg/common/startrpc/start.go b/pkg/common/startrpc/start.go index f6cda2ffb3..4b032e9d6b 100644 --- a/pkg/common/startrpc/start.go +++ b/pkg/common/startrpc/start.go @@ -15,8 +15,11 @@ package startrpc import ( + "context" "errors" "fmt" + "github.com/OpenIMSDK/tools/errs" + util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" "net" "net/http" "os" @@ -26,14 +29,10 @@ import ( "syscall" "time" - "github.com/OpenIMSDK/tools/errs" - - "github.com/prometheus/client_golang/prometheus" - "github.com/prometheus/client_golang/prometheus/promhttp" - "golang.org/x/sync/errgroup" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics" + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/promhttp" grpcprometheus "github.com/grpc-ecosystem/go-grpc-prometheus" "google.golang.org/grpc" @@ -56,12 +55,13 @@ func Start( ) error { fmt.Printf("start %s server, port: %d, prometheusPort: %d, OpenIM version: %s\n", rpcRegisterName, rpcPort, prometheusPort, config.Version) + rpcTcpAddr := net.JoinHostPort(network.GetListenIP(config.Config.Rpc.ListenIP), strconv.Itoa(rpcPort)) listener, err := net.Listen( "tcp", - net.JoinHostPort(network.GetListenIP(config.Config.Rpc.ListenIP), strconv.Itoa(rpcPort)), + rpcTcpAddr, ) if err != nil { - return errs.Wrap(err, network.GetListenIP(config.Config.Rpc.ListenIP), strconv.Itoa(rpcPort)) + return errs.Wrap(err, "rpc start err", rpcTcpAddr) } defer listener.Close() @@ -108,46 +108,64 @@ func Start( return errs.Wrap(err) } - var wg errgroup.Group - - wg.Go(func() error { + var ( + netDone = make(chan struct{}, 2) + netErr error + httpServer *http.Server + ) + go func() { if config.Config.Prometheus.Enable && prometheusPort != 0 { metric.InitializeMetrics(srv) // Create a HTTP server for prometheus. - httpServer := &http.Server{Handler: promhttp.HandlerFor(reg, promhttp.HandlerOpts{}), Addr: fmt.Sprintf("0.0.0.0:%d", prometheusPort)} - if err := httpServer.ListenAndServe(); err != nil { - fmt.Fprintf(os.Stderr, "\n\nexit -1: \n%+v PrometheusPort: %d \n\n", err, prometheusPort) - os.Exit(-1) + httpServer = &http.Server{Handler: promhttp.HandlerFor(reg, promhttp.HandlerOpts{}), Addr: fmt.Sprintf("0.0.0.0:%d", prometheusPort)} + if err := httpServer.ListenAndServe(); err != nil && err != http.ErrServerClosed { + netErr = errs.Wrap(err, "prometheus start err", httpServer.Addr) + netDone <- struct{}{} } } - return nil - }) + }() - wg.Go(func() error { - return errs.Wrap(srv.Serve(listener)) - }) + go func() { + err := srv.Serve(listener) + if err != nil { + netErr = errs.Wrap(err, "rpc start err: ", rpcTcpAddr) + netDone <- struct{}{} + } + }() sigs := make(chan os.Signal, 1) - signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT) - <-sigs - - var ( - done = make(chan struct{}, 1) - gerr error - ) + signal.Notify(sigs, syscall.SIGTERM) + select { + case <-sigs: + util.SIGUSR1Exit() + ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) + defer cancel() + if err := gracefulStopWithCtx(ctx, srv.GracefulStop); err != nil { + return err + } + ctx, cancel = context.WithTimeout(context.Background(), 15*time.Second) + defer cancel() + err := httpServer.Shutdown(ctx) + if err != nil { + return errs.Wrap(err, "shutdown err") + } + return errors.New("SIGTERM EXIT") + case <-netDone: + close(netDone) + return netErr + } +} +func gracefulStopWithCtx(ctx context.Context, f func()) error { + done := make(chan struct{}, 1) go func() { - once.Do(srv.GracefulStop) - gerr = wg.Wait() + f() close(done) }() - select { + case <-ctx.Done(): + return errs.Wrap(errors.New("timeout, ctx graceful stop")) case <-done: - return gerr - - case <-time.After(15 * time.Second): - return errs.Wrap(errors.New("timeout exit")) + return nil } - } diff --git a/pkg/util/genutil/genutil.go b/pkg/util/genutil/genutil.go index 0948a7c49b..f97b803f66 100644 --- a/pkg/util/genutil/genutil.go +++ b/pkg/util/genutil/genutil.go @@ -15,6 +15,7 @@ package genutil import ( + "errors" "fmt" "os" "path/filepath" @@ -39,3 +40,17 @@ func OutDir(path string) (string, error) { outDir += "/" return outDir, nil } + +func ExitWithError(err error) { + if errors.Is(err, errors.New("SIGTERM EXIT")) { + os.Exit(-1) + } + progName := filepath.Base(os.Args[0]) + fmt.Fprintf(os.Stderr, "\n\n%s exit -1: \n%+v\n\n", progName, err) + os.Exit(-1) +} + +func SIGUSR1Exit() { + progName := filepath.Base(os.Args[0]) + fmt.Printf("\n\n%s receive process terminal SIGTERM exit 0\n\n", progName) +} diff --git a/scripts/githooks/pre-commit.sh b/scripts/githooks/pre-commit.sh index cc756c9ad1..d8396b5605 100644 --- a/scripts/githooks/pre-commit.sh +++ b/scripts/githooks/pre-commit.sh @@ -105,7 +105,7 @@ fi if [[ ! $local_branch =~ $valid_branch_regex ]] then printError "There is something wrong with your branch name. Branch names in this project must adhere to this contract: $valid_branch_regex. -Your commit will be rejected. You should rename your branch to a valid name(feat/name OR bug/name) and try again." +Your commit will be rejected. You should rename your branch to a valid name(feat/name OR fix/name) and try again." printError "For more on this, read on: https://gist.github.com/cubxxw/126b72104ac0b0ca484c9db09c3e5694" exit 1 fi \ No newline at end of file diff --git a/scripts/install/openim-push.sh b/scripts/install/openim-push.sh index ab12735c10..95da16c8a9 100755 --- a/scripts/install/openim-push.sh +++ b/scripts/install/openim-push.sh @@ -73,7 +73,7 @@ function openim::push::start() { for (( i=0; i<${#OPENIM_PUSH_PORTS_ARRAY[@]}; i++ )); do openim::log::info "start push process, port: ${OPENIM_PUSH_PORTS_ARRAY[$i]}, prometheus port: ${PUSH_PROM_PORTS_ARRAY[$i]}" - nohup ${OPENIM_PUSH_BINARY} --port ${OPENIM_PUSH_PORTS_ARRAY[$i]} -c ${OPENIM_PUSH_CONFIG} --prometheus_port ${PUSH_PROM_PORTS_ARRAY[$i]} >${LOG_FILE} 2> >(tee -a "${STDERR_LOG_FILE}" "$TMP_LOG_FILE" >&2) & + nohup ${OPENIM_PUSH_BINARY} --port ${OPENIM_PUSH_PORTS_ARRAY[$i]} -c ${OPENIM_PUSH_CONFIG} --prometheus_port ${PUSH_PROM_PORTS_ARRAY[$i]} >> ${LOG_FILE} 2> >(tee -a "${STDERR_LOG_FILE}" "$TMP_LOG_FILE" >&2) & done openim::util::check_process_names ${SERVER_NAME} diff --git a/scripts/lib/util.sh b/scripts/lib/util.sh index 7acb1fcddd..1bdb7f6404 100755 --- a/scripts/lib/util.sh +++ b/scripts/lib/util.sh @@ -486,7 +486,7 @@ openim::util::stop_services_on_ports() { local pid=$(echo $line | awk '{print $2}') # Try to stop the service by killing its process. - if kill -10 $pid; then + if kill -15 $pid; then stopped+=($port) else not_stopped+=($port) @@ -561,7 +561,7 @@ openim::util::stop_services_with_name() { # If there's a Process ID, it means the service with the name is running. if [[ -n $pid ]]; then # Try to stop the service by killing its process. - if kill -10 $pid 2>/dev/null; then + if kill -15 $pid 2>/dev/null; then stopped_this_time=true fi fi From abdb4941c665894d540dc387910e798e96ded47c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 18 Feb 2024 20:19:25 +0800 Subject: [PATCH 047/188] chore(deps): bump the github-actions group with 20 updates (#1907) Bumps the github-actions group with 20 updates: | Package | From | To | | --- | --- | --- | | [actions/checkout](https://github.com/actions/checkout) | `2` | `4` | | [peter-evans/create-or-update-comment](https://github.com/peter-evans/create-or-update-comment) | `3` | `4` | | [actions/github-script](https://github.com/actions/github-script) | `6` | `7` | | [docker/metadata-action](https://github.com/docker/metadata-action) | `5.0.0` | `5.5.1` | | [codecov/codecov-action](https://github.com/codecov/codecov-action) | `3` | `4` | | [github/codeql-action](https://github.com/github/codeql-action) | `2` | `3` | | [ad-m/github-push-action](https://github.com/ad-m/github-push-action) | `0.6.0` | `0.8.0` | | [actions/dependency-review-action](https://github.com/actions/dependency-review-action) | `3` | `4` | | [actions/cache](https://github.com/actions/cache) | `3` | `4` | | [actions/setup-go](https://github.com/actions/setup-go) | `4` | `5` | | [golangci/golangci-lint-action](https://github.com/golangci/golangci-lint-action) | `3.7.0` | `4.0.0` | | [actions/first-interaction](https://github.com/actions/first-interaction) | `1.2.0` | `1.3.0` | | [lycheeverse/lychee-action](https://github.com/lycheeverse/lychee-action) | `1.8.0` | `1.9.3` | | [peter-evans/create-issue-from-file](https://github.com/peter-evans/create-issue-from-file) | `4` | `5` | | [dessant/lock-threads](https://github.com/dessant/lock-threads) | `4` | `5` | | [actions/setup-node](https://github.com/actions/setup-node) | `2` | `4` | | [alex-page/github-project-automation-plus](https://github.com/alex-page/github-project-automation-plus) | `0.8.3` | `0.9.0` | | [peter-evans/create-pull-request](https://github.com/peter-evans/create-pull-request) | `5` | `6` | | [release-drafter/release-drafter](https://github.com/release-drafter/release-drafter) | `5` | `6` | | [actions/stale](https://github.com/actions/stale) | `8` | `9` | Updates `actions/checkout` from 2 to 4 - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v2...v4) Updates `peter-evans/create-or-update-comment` from 3 to 4 - [Release notes](https://github.com/peter-evans/create-or-update-comment/releases) - [Commits](https://github.com/peter-evans/create-or-update-comment/compare/v3...v4) Updates `actions/github-script` from 6 to 7 - [Release notes](https://github.com/actions/github-script/releases) - [Commits](https://github.com/actions/github-script/compare/v6...v7) Updates `docker/metadata-action` from 5.0.0 to 5.5.1 - [Release notes](https://github.com/docker/metadata-action/releases) - [Commits](https://github.com/docker/metadata-action/compare/v5.0.0...v5.5.1) Updates `codecov/codecov-action` from 3 to 4 - [Release notes](https://github.com/codecov/codecov-action/releases) - [Changelog](https://github.com/codecov/codecov-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/codecov/codecov-action/compare/v3...v4) Updates `github/codeql-action` from 2 to 3 - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/v2...v3) Updates `ad-m/github-push-action` from 0.6.0 to 0.8.0 - [Release notes](https://github.com/ad-m/github-push-action/releases) - [Commits](https://github.com/ad-m/github-push-action/compare/v0.6.0...v0.8.0) Updates `actions/dependency-review-action` from 3 to 4 - [Release notes](https://github.com/actions/dependency-review-action/releases) - [Commits](https://github.com/actions/dependency-review-action/compare/v3...v4) Updates `actions/cache` from 3 to 4 - [Release notes](https://github.com/actions/cache/releases) - [Commits](https://github.com/actions/cache/compare/v3...v4) Updates `actions/setup-go` from 4 to 5 - [Release notes](https://github.com/actions/setup-go/releases) - [Commits](https://github.com/actions/setup-go/compare/v4...v5) Updates `golangci/golangci-lint-action` from 3.7.0 to 4.0.0 - [Release notes](https://github.com/golangci/golangci-lint-action/releases) - [Commits](https://github.com/golangci/golangci-lint-action/compare/v3.7.0...v4.0.0) Updates `actions/first-interaction` from 1.2.0 to 1.3.0 - [Release notes](https://github.com/actions/first-interaction/releases) - [Commits](https://github.com/actions/first-interaction/compare/v1.2.0...v1.3.0) Updates `lycheeverse/lychee-action` from 1.8.0 to 1.9.3 - [Release notes](https://github.com/lycheeverse/lychee-action/releases) - [Commits](https://github.com/lycheeverse/lychee-action/compare/v1.8.0...v1.9.3) Updates `peter-evans/create-issue-from-file` from 4 to 5 - [Release notes](https://github.com/peter-evans/create-issue-from-file/releases) - [Commits](https://github.com/peter-evans/create-issue-from-file/compare/v4...v5) Updates `dessant/lock-threads` from 4 to 5 - [Release notes](https://github.com/dessant/lock-threads/releases) - [Changelog](https://github.com/dessant/lock-threads/blob/main/CHANGELOG.md) - [Commits](https://github.com/dessant/lock-threads/compare/v4...v5) Updates `actions/setup-node` from 2 to 4 - [Release notes](https://github.com/actions/setup-node/releases) - [Commits](https://github.com/actions/setup-node/compare/v2...v4) Updates `alex-page/github-project-automation-plus` from 0.8.3 to 0.9.0 - [Release notes](https://github.com/alex-page/github-project-automation-plus/releases) - [Commits](https://github.com/alex-page/github-project-automation-plus/compare/v0.8.3...v0.9.0) Updates `peter-evans/create-pull-request` from 5 to 6 - [Release notes](https://github.com/peter-evans/create-pull-request/releases) - [Commits](https://github.com/peter-evans/create-pull-request/compare/v5...v6) Updates `release-drafter/release-drafter` from 5 to 6 - [Release notes](https://github.com/release-drafter/release-drafter/releases) - [Commits](https://github.com/release-drafter/release-drafter/compare/v5...v6) Updates `actions/stale` from 8 to 9 - [Release notes](https://github.com/actions/stale/releases) - [Changelog](https://github.com/actions/stale/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/stale/compare/v8...v9) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-major dependency-group: github-actions - dependency-name: peter-evans/create-or-update-comment dependency-type: direct:production update-type: version-update:semver-major dependency-group: github-actions - dependency-name: actions/github-script dependency-type: direct:production update-type: version-update:semver-major dependency-group: github-actions - dependency-name: docker/metadata-action dependency-type: direct:production update-type: version-update:semver-minor dependency-group: github-actions - dependency-name: codecov/codecov-action dependency-type: direct:production update-type: version-update:semver-major dependency-group: github-actions - dependency-name: github/codeql-action dependency-type: direct:production update-type: version-update:semver-major dependency-group: github-actions - dependency-name: ad-m/github-push-action dependency-type: direct:production update-type: version-update:semver-minor dependency-group: github-actions - dependency-name: actions/dependency-review-action dependency-type: direct:production update-type: version-update:semver-major dependency-group: github-actions - dependency-name: actions/cache dependency-type: direct:production update-type: version-update:semver-major dependency-group: github-actions - dependency-name: actions/setup-go dependency-type: direct:production update-type: version-update:semver-major dependency-group: github-actions - dependency-name: golangci/golangci-lint-action dependency-type: direct:production update-type: version-update:semver-major dependency-group: github-actions - dependency-name: actions/first-interaction dependency-type: direct:production update-type: version-update:semver-minor dependency-group: github-actions - dependency-name: lycheeverse/lychee-action dependency-type: direct:production update-type: version-update:semver-minor dependency-group: github-actions - dependency-name: peter-evans/create-issue-from-file dependency-type: direct:production update-type: version-update:semver-major dependency-group: github-actions - dependency-name: dessant/lock-threads dependency-type: direct:production update-type: version-update:semver-major dependency-group: github-actions - dependency-name: actions/setup-node dependency-type: direct:production update-type: version-update:semver-major dependency-group: github-actions - dependency-name: alex-page/github-project-automation-plus dependency-type: direct:production update-type: version-update:semver-minor dependency-group: github-actions - dependency-name: peter-evans/create-pull-request dependency-type: direct:production update-type: version-update:semver-major dependency-group: github-actions - dependency-name: release-drafter/release-drafter dependency-type: direct:production update-type: version-update:semver-major dependency-group: github-actions - dependency-name: actions/stale dependency-type: direct:production update-type: version-update:semver-major dependency-group: github-actions ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/auto-gh-pr.yml | 2 +- .github/workflows/auto-invite.yml | 2 +- .github/workflows/bot-auto-cherry-pick.yml | 2 +- .github/workflows/build-docker-image.yml | 6 ++--- .github/workflows/check-coverage.yml | 2 +- .github/workflows/codeql-analysis.yml | 6 ++--- .github/workflows/create-branch-on-tag.yml | 2 +- .github/workflows/depsreview.yaml | 2 +- .github/workflows/docker-buildx.yml | 28 +++++++++++----------- .github/workflows/e2e-test.yml | 4 ++-- .github/workflows/golangci-lint.yml | 4 ++-- .github/workflows/greetings.yml | 2 +- .github/workflows/help-comment-issue.yml | 2 +- .github/workflows/link-pr.yml | 4 ++-- .github/workflows/lock-issue.yml | 2 +- .github/workflows/milestone.yml | 2 +- .github/workflows/opencommit.yml | 4 ++-- .github/workflows/openimci.yml | 6 ++--- .github/workflows/project-progress.yml | 2 +- .github/workflows/pull-request.yml | 4 ++-- .github/workflows/release-drafter.yml | 2 +- .github/workflows/release.yml | 4 ++-- .github/workflows/stale.yml | 2 +- 23 files changed, 48 insertions(+), 48 deletions(-) diff --git a/.github/workflows/auto-gh-pr.yml b/.github/workflows/auto-gh-pr.yml index d58f355107..45454275ed 100644 --- a/.github/workflows/auto-gh-pr.yml +++ b/.github/workflows/auto-gh-pr.yml @@ -28,7 +28,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout code - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Sync Issue to PR if: github.event_name == 'pull_request' && github.event.pull_request.base.ref == 'main' diff --git a/.github/workflows/auto-invite.yml b/.github/workflows/auto-invite.yml index 0276a33a4e..350de30abc 100644 --- a/.github/workflows/auto-invite.yml +++ b/.github/workflows/auto-invite.yml @@ -27,7 +27,7 @@ jobs: steps: - name: Invite user to join our group - uses: peter-evans/create-or-update-comment@v3 + uses: peter-evans/create-or-update-comment@v4 with: token: ${{ secrets.BOT_GITHUB_TOKEN }} issue-number: ${{ github.event.issue.number }} diff --git a/.github/workflows/bot-auto-cherry-pick.yml b/.github/workflows/bot-auto-cherry-pick.yml index 7c2ad49caa..baafecad72 100644 --- a/.github/workflows/bot-auto-cherry-pick.yml +++ b/.github/workflows/bot-auto-cherry-pick.yml @@ -23,7 +23,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Comment cherry-pick command - uses: actions/github-script@v6 + uses: actions/github-script@v7 with: script: | const pr = context.payload.pull_request; diff --git a/.github/workflows/build-docker-image.yml b/.github/workflows/build-docker-image.yml index 6197449878..1e9711d2c9 100644 --- a/.github/workflows/build-docker-image.yml +++ b/.github/workflows/build-docker-image.yml @@ -43,7 +43,7 @@ jobs: # docker.io/openim/openim-server:latest - name: Extract metadata (tags, labels) for Docker id: meta - uses: docker/metadata-action@v5.0.0 + uses: docker/metadata-action@v5.5.1 with: images: openim/openim-server # generate Docker tags based on the following events/attributes @@ -86,7 +86,7 @@ jobs: # registry.cn-hangzhou.aliyuncs.com/openimsdk/openim-server:latest - name: Extract metadata (tags, labels) for Docker id: meta2 - uses: docker/metadata-action@v5.0.0 + uses: docker/metadata-action@v5.5.1 with: images: registry.cn-hangzhou.aliyuncs.com/openimsdk/openim-server # generate Docker tags based on the following events/attributes @@ -130,7 +130,7 @@ jobs: # ghcr.io/openimsdk/openim-server:latest - name: Extract metadata (tags, labels) for Docker id: meta3 - uses: docker/metadata-action@v5.0.0 + uses: docker/metadata-action@v5.5.1 with: images: ghcr.io/openimsdk/openim-server # generate Docker tags based on the following events/attributes diff --git a/.github/workflows/check-coverage.yml b/.github/workflows/check-coverage.yml index 7b3935730d..09d43d7cdf 100644 --- a/.github/workflows/check-coverage.yml +++ b/.github/workflows/check-coverage.yml @@ -56,4 +56,4 @@ jobs: continue-on-error: true - name: Upload Coverage to Codecov - uses: codecov/codecov-action@v3 + uses: codecov/codecov-action@v4 diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index d6ff39371c..29f9382ccc 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -51,7 +51,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@v2 + uses: github/codeql-action/init@v3 # Override language selection by uncommenting this and choosing your languages with: languages: go @@ -59,7 +59,7 @@ jobs: # 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 + 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 @@ -73,4 +73,4 @@ jobs: # make release - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 \ No newline at end of file + uses: github/codeql-action/analyze@v3 \ No newline at end of file diff --git a/.github/workflows/create-branch-on-tag.yml b/.github/workflows/create-branch-on-tag.yml index b6b9eb8e8f..fbacd261b1 100644 --- a/.github/workflows/create-branch-on-tag.yml +++ b/.github/workflows/create-branch-on-tag.yml @@ -70,7 +70,7 @@ jobs: - name: Push CHANGELOG to Main if: steps.create-and-commit-changelog.outputs.changes == 'true' - uses: ad-m/github-push-action@v0.6.0 + uses: ad-m/github-push-action@v0.8.0 with: github_token: ${{ secrets.BOT_GITHUB_TOKEN }} branch: main diff --git a/.github/workflows/depsreview.yaml b/.github/workflows/depsreview.yaml index c80929c8c1..aff7e3d9e0 100644 --- a/.github/workflows/depsreview.yaml +++ b/.github/workflows/depsreview.yaml @@ -15,4 +15,4 @@ jobs: - name: 'Checkout Repository' uses: actions/checkout@v4 - name: 'Dependency Review' - uses: actions/dependency-review-action@v3 \ No newline at end of file + uses: actions/dependency-review-action@v4 \ No newline at end of file diff --git a/.github/workflows/docker-buildx.yml b/.github/workflows/docker-buildx.yml index b3b0b56835..7e7b8229ca 100644 --- a/.github/workflows/docker-buildx.yml +++ b/.github/workflows/docker-buildx.yml @@ -40,7 +40,7 @@ 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 }} @@ -100,7 +100,7 @@ jobs: - name: Extract metadata (tags, labels) for Docker openim-api id: meta1 - uses: docker/metadata-action@v5.0.0 + uses: docker/metadata-action@v5.5.1 with: images: | ghcr.io/openimsdk/openim-api @@ -131,7 +131,7 @@ jobs: - name: Extract metadata (tags, labels) for Docker openim-cmdutils id: meta2 - uses: docker/metadata-action@v5.0.0 + uses: docker/metadata-action@v5.5.1 with: images: | ghcr.io/openimsdk/openim-cmdutils @@ -162,7 +162,7 @@ jobs: - name: Extract metadata (tags, labels) for Docker openim-crontask id: meta3 - uses: docker/metadata-action@v5.0.0 + uses: docker/metadata-action@v5.5.1 with: images: | ghcr.io/openimsdk/openim-crontask @@ -193,7 +193,7 @@ jobs: - name: Extract metadata (tags, labels) for Docker openim-msggateway id: meta4 - uses: docker/metadata-action@v5.0.0 + uses: docker/metadata-action@v5.5.1 with: images: | ghcr.io/openimsdk/openim-msggateway @@ -224,7 +224,7 @@ jobs: - name: Extract metadata (tags, labels) for Docker openim-msgtransfer id: meta5 - uses: docker/metadata-action@v5.0.0 + uses: docker/metadata-action@v5.5.1 with: images: | ghcr.io/openimsdk/openim-msgtransfer @@ -255,7 +255,7 @@ jobs: - name: Extract metadata (tags, labels) for Docker openim-push id: meta6 - uses: docker/metadata-action@v5.0.0 + uses: docker/metadata-action@v5.5.1 with: images: | ghcr.io/openimsdk/openim-push @@ -286,7 +286,7 @@ jobs: - name: Extract metadata (tags, labels) for Docker openim-rpc-auth id: meta7 - uses: docker/metadata-action@v5.0.0 + uses: docker/metadata-action@v5.5.1 with: images: | ghcr.io/openimsdk/openim-rpc-auth @@ -317,7 +317,7 @@ jobs: - name: Extract metadata (tags, labels) for Docker openim-rpc-conversation id: meta8 - uses: docker/metadata-action@v5.0.0 + uses: docker/metadata-action@v5.5.1 with: images: | ghcr.io/openimsdk/openim-rpc-conversation @@ -348,7 +348,7 @@ jobs: - name: Extract metadata (tags, labels) for Docker openim-rpc-friend id: meta9 - uses: docker/metadata-action@v5.0.0 + uses: docker/metadata-action@v5.5.1 with: images: | ghcr.io/openimsdk/openim-rpc-friend @@ -379,7 +379,7 @@ jobs: - name: Extract metadata (tags, labels) for Docker openim-rpc-group id: meta10 - uses: docker/metadata-action@v5.0.0 + uses: docker/metadata-action@v5.5.1 with: images: | ghcr.io/openimsdk/openim-rpc-group @@ -410,7 +410,7 @@ jobs: - name: Extract metadata (tags, labels) for Docker openim-rpc-msg id: meta11 - uses: docker/metadata-action@v5.0.0 + uses: docker/metadata-action@v5.5.1 with: images: | ghcr.io/openimsdk/openim-rpc-msg @@ -441,7 +441,7 @@ jobs: - name: Extract metadata (tags, labels) for Docker openim-rpc-third id: meta12 - uses: docker/metadata-action@v5.0.0 + uses: docker/metadata-action@v5.5.1 with: images: | ghcr.io/openimsdk/openim-rpc-third @@ -472,7 +472,7 @@ jobs: - name: Extract metadata (tags, labels) for Docker openim-rpc-user id: meta13 - uses: docker/metadata-action@v5.0.0 + uses: docker/metadata-action@v5.5.1 with: images: | ghcr.io/openimsdk/openim-rpc-user diff --git a/.github/workflows/e2e-test.yml b/.github/workflows/e2e-test.yml index 21bb4986e9..6970e7d9c7 100644 --- a/.github/workflows/e2e-test.yml +++ b/.github/workflows/e2e-test.yml @@ -34,7 +34,7 @@ jobs: steps: - name: Set up Go 1.21 - uses: actions/setup-go@v4 + uses: actions/setup-go@v5 with: go-version: 1.21 id: go @@ -60,7 +60,7 @@ jobs: uses: actions/checkout@v4 - name: Set up Go ${{ matrix.go_version }} - uses: actions/setup-go@v4 + uses: actions/setup-go@v5 with: go-version: ${{ matrix.go_version }} id: go diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml index 250cb96cb1..31e491d6b6 100644 --- a/.github/workflows/golangci-lint.yml +++ b/.github/workflows/golangci-lint.yml @@ -24,14 +24,14 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: actions/setup-go@v4 + - uses: actions/setup-go@v5 with: go-version: '1.21' cache: false - name: OpenIM Scripts Verification(make verify) run: sudo make verify - name: golangci-lint - uses: golangci/golangci-lint-action@v3.7.0 + uses: golangci/golangci-lint-action@v4.0.0 with: # Require: version of golangci-lint to use in form of v1.2 or v1.2.3 or `latest` to use the latest version version: v1.54 diff --git a/.github/workflows/greetings.yml b/.github/workflows/greetings.yml index a92ed40ad9..b1c85ee375 100644 --- a/.github/workflows/greetings.yml +++ b/.github/workflows/greetings.yml @@ -26,7 +26,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: actions/first-interaction@v1.2.0 + - uses: actions/first-interaction@v1.3.0 with: repo-token: ${{ secrets.BOT_GITHUB_TOKEN }} pr-message: | diff --git a/.github/workflows/help-comment-issue.yml b/.github/workflows/help-comment-issue.yml index dce8581978..c4e72ffc67 100644 --- a/.github/workflows/help-comment-issue.yml +++ b/.github/workflows/help-comment-issue.yml @@ -26,7 +26,7 @@ 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 }} diff --git a/.github/workflows/link-pr.yml b/.github/workflows/link-pr.yml index 768742eee9..6c5ff6c5b9 100644 --- a/.github/workflows/link-pr.yml +++ b/.github/workflows/link-pr.yml @@ -27,7 +27,7 @@ jobs: - name: Link Checker id: lychee - uses: lycheeverse/lychee-action@v1.8.0 + uses: lycheeverse/lychee-action@v1.9.3 with: # For parameter description, see https://github.com/lycheeverse/lychee#commandline-parameters # Actions Link address -> https://github.com/lycheeverse/lychee-action @@ -45,7 +45,7 @@ jobs: - name: Create Issue From File if: env.lychee_exit_code != 0 - uses: peter-evans/create-issue-from-file@v4 + uses: peter-evans/create-issue-from-file@v5 with: title: Bug reports for links in OpenIM docs content-filepath: ./lychee/out.md diff --git a/.github/workflows/lock-issue.yml b/.github/workflows/lock-issue.yml index 6a9aed9baf..edf2809653 100644 --- a/.github/workflows/lock-issue.yml +++ b/.github/workflows/lock-issue.yml @@ -30,7 +30,7 @@ jobs: action: runs-on: ubuntu-latest steps: - - uses: dessant/lock-threads@v4 + - uses: dessant/lock-threads@v5 with: github-token: ${{ secrets.BOT_GITHUB_TOKEN }} issue-inactive-days: '365' diff --git a/.github/workflows/milestone.yml b/.github/workflows/milestone.yml index e0731b25f1..ecd64656af 100644 --- a/.github/workflows/milestone.yml +++ b/.github/workflows/milestone.yml @@ -39,7 +39,7 @@ jobs: statuses: none steps: - - uses: actions/github-script@v6 # v6 + - uses: actions/github-script@v7 # v6 with: script: | if (!context.payload.pull_request.merged) { diff --git a/.github/workflows/opencommit.yml b/.github/workflows/opencommit.yml index 629a67aae0..d483ef1f65 100644 --- a/.github/workflows/opencommit.yml +++ b/.github/workflows/opencommit.yml @@ -28,10 +28,10 @@ jobs: permissions: write-all steps: - name: Setup Node.js Environment - uses: actions/setup-node@v2 + uses: actions/setup-node@v4 with: node-version: '16' - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 0 - uses: di-sukharev/opencommit@github-action-v1.0.4 diff --git a/.github/workflows/openimci.yml b/.github/workflows/openimci.yml index 2d42e31555..d10033a1c4 100644 --- a/.github/workflows/openimci.yml +++ b/.github/workflows/openimci.yml @@ -59,7 +59,7 @@ jobs: uses: actions/checkout@v4 - name: Set up Go ${{ matrix.go_version }} - uses: actions/setup-go@v4 + uses: actions/setup-go@v5 with: go-version: ${{ matrix.go_version }} id: go @@ -191,7 +191,7 @@ jobs: uses: actions/checkout@v4 - name: Set up Go ${{ matrix.go_version }} - uses: actions/setup-go@v4 + uses: actions/setup-go@v5 with: go-version: ${{ matrix.go_version }} id: go @@ -276,7 +276,7 @@ jobs: - name: Checkout code uses: actions/checkout@v4 - name: Set up Go ${{ matrix.go_version }} - uses: actions/setup-go@v4 + uses: actions/setup-go@v5 with: go-version: ${{ matrix.go_version }} id: go diff --git a/.github/workflows/project-progress.yml b/.github/workflows/project-progress.yml index 0b071b3a8e..87a4c13810 100644 --- a/.github/workflows/project-progress.yml +++ b/.github/workflows/project-progress.yml @@ -32,7 +32,7 @@ jobs: move-assigned-card: runs-on: ubuntu-latest steps: - - uses: alex-page/github-project-automation-plus@v0.8.3 + - uses: alex-page/github-project-automation-plus@v0.9.0 with: project: openim-powerful column: In Progress diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index 6f39c93b28..bc1b094bf8 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -33,7 +33,7 @@ jobs: - uses: actions/setup-node@v4 - name: Setup Go - uses: actions/setup-go@v4 + uses: actions/setup-go@v5 - name: Run go modules tidy run: | sudo apt-get install jq @@ -87,7 +87,7 @@ jobs: continue-on-error: true - name: Create Pull Request - uses: peter-evans/create-pull-request@v5 + uses: peter-evans/create-pull-request@v6 with: token: ${{ secrets.BOT_GITHUB_TOKEN }} commit-message: "cicd: bump League Patch" diff --git a/.github/workflows/release-drafter.yml b/.github/workflows/release-drafter.yml index 0eed809114..251f558764 100644 --- a/.github/workflows/release-drafter.yml +++ b/.github/workflows/release-drafter.yml @@ -46,7 +46,7 @@ jobs: # echo "GHE_HOST=${GITHUB_SERVER_URL##https:\/\/}" >> $GITHUB_ENV # Drafts your next Release notes as Pull Requests are merged into "master" - - uses: release-drafter/release-drafter@v5 + - uses: release-drafter/release-drafter@v6 # (Optional) specify config name to use, relative to .github/. Default: release-drafter.yml # with: # config-name: my-config.yml diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index f2147c865f..9950bdabb8 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -33,7 +33,7 @@ jobs: with: fetch-depth: 0 - run: git fetch --force --tags - - uses: actions/setup-go@v4 + - uses: actions/setup-go@v5 with: go-version: stable # More assembly might be required: Docker logins, GPG, etc. It all depends @@ -71,7 +71,7 @@ jobs: version: 3.x repo-token: ${{ secrets.GITHUB_TOKEN }} - uses: docker/setup-qemu-action@326560df218a7ea9cf6ab49bbc88b8b306bb437e # v2 - - uses: actions/cache@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8 # v3 + - uses: actions/cache@a2ed59d39b352305bdd2f628719a53b2cc4f9613 # v3 with: path: | ./_output/dist/*.deb diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index ba767f1674..da44cb7f30 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -32,7 +32,7 @@ jobs: pull-requests: write steps: - - uses: actions/stale@v8 + - uses: actions/stale@v9 with: repo-token: ${{ secrets.BOT_GITHUB_TOKEN }} days-before-stale: 60 From 60c446b69408a2c96aef9c5b72c376a7b6efb9b9 Mon Sep 17 00:00:00 2001 From: Seal Bell Date: Mon, 19 Feb 2024 09:35:39 +0800 Subject: [PATCH 048/188] docs:add README_hu.md (#1919) --- docs/readme/README_hu.md | 187 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 187 insertions(+) create mode 100644 docs/readme/README_hu.md diff --git a/docs/readme/README_hu.md b/docs/readme/README_hu.md new file mode 100644 index 0000000000..57f0066928 --- /dev/null +++ b/docs/readme/README_hu.md @@ -0,0 +1,187 @@ +

+ + + +

+ +
+ +[![Stars](https://img.shields.io/github/stars/openimsdk/open-im-server?style=for-the-badge&logo=github&colorB=ff69b4)](https://github.com/openimsdk/open-im-server/stargazers) +[![Forks](https://img.shields.io/github/forks/openimsdk/open-im-server?style=for-the-badge&logo=github&colorB=blue)](https://github.com/openimsdk/open-im-server/network/members) +[![Codecov](https://img.shields.io/codecov/c/github/openimsdk/open-im-server?style=for-the-badge&logo=codecov&colorB=orange)](https://app.codecov.io/gh/openimsdk/open-im-server) +[![Go Report Card](https://goreportcard.com/badge/github.com/openimsdk/open-im-server?style=for-the-badge)](https://goreportcard.com/report/github.com/openimsdk/open-im-server) +[![Go Reference](https://img.shields.io/badge/Go%20Reference-blue.svg?style=for-the-badge&logo=go&logoColor=white)](https://pkg.go.dev/github.com/openimsdk/open-im-server/v3) +[![License](https://img.shields.io/badge/license-Apache--2.0-green?style=for-the-badge)](https://github.com/openimsdk/open-im-server/blob/main/LICENSE) +[![Slack](https://img.shields.io/badge/Slack-500%2B-blueviolet?style=for-the-badge&logo=slack&logoColor=white)](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q) +[![Best Practices](https://img.shields.io/badge/Best%20Practices-purple?style=for-the-badge)](https://www.bestpractices.dev/projects/8045) +[![Good First Issues](https://img.shields.io/github/issues/openimsdk/open-im-server/good%20first%20issue?style=for-the-badge&logo=github)](https://github.com/openimsdk/open-im-server/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc+label%3A%22good+first+issue%22) +[![Language](https://img.shields.io/badge/Language-Go-blue.svg?style=for-the-badge&logo=go&logoColor=white)](https://golang.org/) + + +

+ Englist · + 中文 · + Українська · + Česky · + Magyar · + Español · + فارسی · + Français · + Deutsch · + Polski · + Indonesian · + Suomi · + മലയാളം · + 日本語 · + Nederlands · + Italiano · + Русский · + Português (Brasil) · + Esperanto · + 한국어 · + العربي · + Tiếng Việt · + Dansk · + Ελληνικά · + Türkçe +

+ + +
+ +

+ +## Ⓜ️ Az OpenIM-ről + +Az OpenIM egy szolgáltatási platform, amelyet kifejezetten a csevegés, az audio-video hívások, az értesítések és az AI chatbotok alkalmazásokba történő integrálására terveztek. Számos hatékony API-t és Webhookot kínál, lehetővé téve a fejlesztők számára, hogy ezeket az interaktív szolgáltatásokat könnyen beépítsék alkalmazásaikba. Az OpenIM nem egy önálló csevegőalkalmazás, hanem platformként szolgál más alkalmazások támogatására a gazdag kommunikációs funkciók elérésében. A következő diagram az AppServer, az AppClient, az OpenIMServer és az OpenIMSDK közötti interakciót szemlélteti részletesen. + +![App-OpenIM Relationship](../images/oepnim-design.png) + +## 🚀 Az OpenIMSDK-ról + +Az **OpenIMSDK** egy **OpenIMServer** számára készült azonnali üzenetküldő SDK, amelyet kifejezetten ügyfélalkalmazásokba való beágyazáshoz hoztak létre. Fő jellemzői és moduljai a következők: + ++ 🌟 Főbb jellemzők: + + - 📦 Helyi raktár + - 🔔 Hallgatói visszahívások + - 🛡️ API-csomagolás + - 🌐 Kapcsolatkezelés + ++ 📚 Fő modulok: + + 1. 🚀 Inicializálás és bejelentkezés + 2. 👤 Felhasználókezelés + 3. 👫 Barátkezelés + 4. 🤖 Csoportfunkciók + 5. 💬 Beszélgetéskezelés + +Golang használatával készült, és támogatja a többplatformos telepítést, biztosítva a konzisztens hozzáférési élményt minden platformon. + +👉 **[Fedezze fel a GO SDK-t](https://github.com/openimsdk/openim-sdk-core)** + +## 🌐 Az OpenIMServerről + ++ **OpenIMServer** a következő jellemzőkkel rendelkezik: + - 🌐 Mikroszolgáltatási architektúra: Támogatja a fürt módot, beleértve az átjárót és több rpc szolgáltatást. + - 🚀 Változatos telepítési módszerek: Támogatja a forráskódon, Kubernetesen vagy Dockeren keresztül történő telepítést. + - Hatalmas felhasználói bázis támogatása: Szuper nagy csoportok több százezer felhasználóval, több tízmillió felhasználóval és több milliárd üzenettel. + +### Továbbfejlesztett üzleti funkcionalitás: + ++ **REST API**: Az OpenIMServer REST API-kat kínál az üzleti rendszerek számára, amelyek célja, hogy a vállalkozásokat több funkcióval ruházza fel, mint például csoportok létrehozása és push üzenetek küldése háttérfelületeken keresztül. ++ **Webhooks**: Az OpenIMServer visszahívási lehetőségeket biztosít több üzleti forma kiterjesztéséhez. A visszahívás azt jelenti, hogy az OpenIMServer kérelmet küld az üzleti szervernek egy bizonyos esemény előtt vagy után, például visszahívásokat üzenet küldése előtt vagy után. + +👉 **[Tudj meg többet](https://docs.openim.io/guides/introduction/product)** + +## :building_construction: Általános építészet + +Merüljön el az Open-IM-Server funkcióinak szívében az architektúra diagramunk segítségével. + +![Overall Architecture](../images/architecture-layers.png) + + +## :rocket: Gyors indítás + +Számos platformot támogatunk. Íme a címek a gyors weboldali használathoz: + +👉 **[OpenIM online webdemó](https://web-enterprise.rentsoft.cn/)** + +🤲 A felhasználói élmény megkönnyítése érdekében különféle telepítési megoldásokat kínálunk. Az alábbi listából választhatja ki a telepítési módot: + ++ **[Forráskód-telepítési útmutató](https://docs.openim.io/guides/gettingStarted/imSourceCodeDeployment)** ++ **[Docker telepítési útmutató](https://docs.openim.io/guides/gettingStarted/dockerCompose)** ++ **[Kubernetes telepítési útmutató](https://docs.openim.io/guides/gettingStarted/k8s-deployment)** ++ **[Mac fejlesztői telepítési útmutató](https://docs.openim.io/guides/gettingstarted/mac-deployment-guide)** + +## :hammer_and_wrench: Az OpenIM fejlesztésének megkezdéséhez + +[![Open in Dev Container](https://img.shields.io/static/v1?label=Dev%20Container&message=Open&color=blue&logo=visualstudiocode)](https://vscode.dev/github/openimsdk/open-im-server) + +OpenIM Célunk egy felső szintű nyílt forráskódú közösség felépítése. Van egy szabványkészletünk a [Közösségi adattárban](https://github.com/OpenIMSDK/community). + +Ha hozzá szeretne járulni ehhez az Open-IM-Server adattárhoz, kérjük, olvassa el [közreműködői dokumentációnkat](https://github.com/openimsdk/open-im-server/blob/main/CONTRIBUTING.md). + +Mielőtt elkezdené, győződjön meg arról, hogy a változtatásokra van-e igény. Erre a legjobb egy [új beszélgetés](https://github.com/openimsdk/open-im-server/discussions/new/choose) VAGY [Slack Communication](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q)létrehozása, vagy ha problémát talál, először [jelentse](https://github.com/openimsdk/open-im-server/issues/new/choose) first. + +- [OpenIM API referencia](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/api.md) +- [OpenIM Bash naplózás](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/bash-log.md) +- [OpenIM CI/CD műveletek](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/cicd-actions.md) +- [OpenIM Code-egyezmények](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/code-conventions.md) +- [OpenIM Commit Guidelines](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/commit.md) +- [OpenIM fejlesztési útmutató](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/development.md) +- [OpenIM címtárszerkezet](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/directory.md) +- [OpenIM környezet beállítása](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/environment.md) +- [OpenIM hibakód hivatkozás](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/error-code.md) +- [OpenIM Git Workflow](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/git-workflow.md) +- [OpenIM Git Cherry Pick Guide](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/gitcherry-pick.md) +- [OpenIM GitHub munkafolyamat](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/github-workflow.md) +- [OpenIM Go Code szabványok](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/go-code.md) +- [OpenIM képre vonatkozó irányelvek](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/images.md) +- [OpenIM kezdeti konfiguráció](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/init-config.md) +- [OpenIM Docker telepítési útmutató](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/install-docker.md) +- [OpenIM OpenIM Linux rendszertelepítés](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/install-openim-linux-system.md) +- [OpenIM Linux fejlesztési útmutató](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/linux-development.md) +- [OpenIM helyi műveletek útmutatója](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/local-actions.md) +- [OpenIM naplózási egyezmények](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/logging.md) +- [OpenIM offline telepítés](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/offline-deployment.md) +- [OpenIM Protoc Tools](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/protoc-tools.md) +- [OpenIM tesztelési útmutató](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/test.md) +- [OpenIM Utility Go](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/util-go.md) +- [OpenIM Makefile Utilities](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/util-makefile.md) +- [OpenIM Script Utilities](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/util-scripts.md) +- [OpenIM verzió](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/version.md) +- [A háttérrendszer kezelése és a telepítés figyelése](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/prometheus-grafana.md) +- [Mac Developer Deployment Guide for OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/mac-developer-deployment-guide.md) + + +## :busts_in_silhouette: Közösség + ++ 📚 [OpenIM közösség](https://github.com/OpenIMSDK/community) ++ 💕 [OpenIM érdeklődési csoport](https://github.com/Openim-sigs) ++ 🚀 [Csatlakozz a Slack közösségünkhöz](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q) ++ :eyes: [Csatlakozz a wechathez](https://openim-1253691595.cos.ap-nanjing.myqcloud.com/WechatIMG20.jpeg) + +## :calendar: Közösségi Találkozók + +Szeretnénk, ha bárki bekapcsolódna közösségünkbe és hozzájárulna kódunkhoz, ajándékokat és jutalmakat kínálunk, és szeretettel várjuk, hogy csatlakozzon hozzánk minden csütörtök este. + +Konferenciánk az [OpenIM Slack](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q) 🎯alatt van, akkor kereshet az Open-IM-Server folyamatban a csatlakozáshoz + +A [GitHub-beszélgetések](https://github.com/orgs/OpenIMSDK/discussions/categories/meeting)minden [kéthetente történő megbeszélésről](https://github.com/openimsdk/open-im-server/discussions/categories/meeting) jegyzeteket készítünk. A találkozók történeti feljegyzései, valamint az értekezletek visszajátszásai a [Google Dokumentumok :bookmark_tabs:](https://docs.google.com/document/d/1nx8MDpuG74NASx081JcCpxPgDITNTpIIos0DS6Vr9GU/edit?usp=sharing) webhelyen érhetők el. + +## :eyes: Kik használják az OpenIM-et + +Tekintse meg [felhasználói esettanulmányok](https://github.com/OpenIMSDK/community/blob/main/ADOPTERS.md) oldalunkat a projekt felhasználóinak listájáért. Ne habozzon, hagyjon [📝megjegyzést](https://github.com/openimsdk/open-im-server/issues/379), és ossza meg használati esetét. + +## :page_facing_up: Engedély + +Az OpenIM licence az Apache 2.0 licence alá tartozik. A teljes licencszövegért lásd: [LICENSE](https://github.com/openimsdk/open-im-server/tree/main/LICENSE). + +Az ebben az [OpenIM](https://github.com/openimsdk/open-im-server) tárolóban az [assets/logo](./assets/logo) és [assets/logo-gif](assets/logo-gif) könyvtárak alatt megjelenő OpenIM logót, beleértve annak változatait és animált változatait, szerzői jogi törvények védik. + +## 🔮 Köszönjük közreműködőinknek! + + + + From 7ebd88e345eba35d1b849e1ddb2c5a0c5ff474ef Mon Sep 17 00:00:00 2001 From: Seal Bell Date: Mon, 19 Feb 2024 09:35:43 +0800 Subject: [PATCH 049/188] docs:add README_fa.md (#1920) --- docs/readme/README_fa.md | 187 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 187 insertions(+) create mode 100644 docs/readme/README_fa.md diff --git a/docs/readme/README_fa.md b/docs/readme/README_fa.md new file mode 100644 index 0000000000..49f05cd4c3 --- /dev/null +++ b/docs/readme/README_fa.md @@ -0,0 +1,187 @@ +

+ + + +

+ +
+ +[![Stars](https://img.shields.io/github/stars/openimsdk/open-im-server?style=for-the-badge&logo=github&colorB=ff69b4)](https://github.com/openimsdk/open-im-server/stargazers) +[![Forks](https://img.shields.io/github/forks/openimsdk/open-im-server?style=for-the-badge&logo=github&colorB=blue)](https://github.com/openimsdk/open-im-server/network/members) +[![Codecov](https://img.shields.io/codecov/c/github/openimsdk/open-im-server?style=for-the-badge&logo=codecov&colorB=orange)](https://app.codecov.io/gh/openimsdk/open-im-server) +[![Go Report Card](https://goreportcard.com/badge/github.com/openimsdk/open-im-server?style=for-the-badge)](https://goreportcard.com/report/github.com/openimsdk/open-im-server) +[![Go Reference](https://img.shields.io/badge/Go%20Reference-blue.svg?style=for-the-badge&logo=go&logoColor=white)](https://pkg.go.dev/github.com/openimsdk/open-im-server/v3) +[![License](https://img.shields.io/badge/license-Apache--2.0-green?style=for-the-badge)](https://github.com/openimsdk/open-im-server/blob/main/LICENSE) +[![Slack](https://img.shields.io/badge/Slack-500%2B-blueviolet?style=for-the-badge&logo=slack&logoColor=white)](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q) +[![Best Practices](https://img.shields.io/badge/Best%20Practices-purple?style=for-the-badge)](https://www.bestpractices.dev/projects/8045) +[![Good First Issues](https://img.shields.io/github/issues/openimsdk/open-im-server/good%20first%20issue?style=for-the-badge&logo=github)](https://github.com/openimsdk/open-im-server/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc+label%3A%22good+first+issue%22) +[![Language](https://img.shields.io/badge/Language-Go-blue.svg?style=for-the-badge&logo=go&logoColor=white)](https://golang.org/) + + +

+ Englist · + 中文 · + Українська · + Česky · + Magyar · + Español · + فارسی · + Français · + Deutsch · + Polski · + Indonesian · + Suomi · + മലയാളം · + 日本語 · + Nederlands · + Italiano · + Русский · + Português (Brasil) · + Esperanto · + 한국어 · + العربي · + Tiếng Việt · + Dansk · + Ελληνικά · + Türkçe +

+ + +
+ +

+ +## درباره OpenIM Ⓜ️ + +OpenIM یک پلتفرم خدماتی است که به طور خاص برای ادغام چت، تماس های صوتی و تصویری، اعلان ها و چت ربات های هوش مصنوعی در برنامه ها طراحی شده است. این مجموعه ای از API ها و Webhook های قدرتمند را ارائه می دهد که به توسعه دهندگان این امکان را می دهد تا به راحتی این ویژگی های تعاملی را در برنامه های خود بگنجانند. OpenIM یک برنامه چت مستقل نیست، بلکه به عنوان یک پلتفرم برای پشتیبانی از برنامه های کاربردی دیگر در دستیابی به قابلیت های ارتباطی غنی عمل می کند. نمودار زیر تعامل بین AppServer، AppClient، OpenIMServer و OpenIMSDK را برای توضیح جزئیات نشان می دهد. + +![App-OpenIM Relationship](../images/oepnim-design.png) + +## 🚀 درباره OpenIMSDK + +**OpenIMSDK** یک IM SDK است که برای **OpenIMServer** طراحی شده است که به طور خاص برای جاسازی در برنامه های مشتری ایجاد شده است. ویژگی ها و ماژول های اصلی آن به شرح زیر است: + ++ 🌟 ویژگی های اصلی: + + - 📦 ذخیره سازی محلی + - 🔔 پاسخ تماس شنونده + - 🛡️ بسته بندی API + - 🌐 مدیریت اتصال + ++ 📚 ماژول های اصلی: + + 1. 🚀 مقداردهی اولیه و ورود + 2. 👤 مدیریت کاربر + 3. 👫 مدیریت دوست + 4. 🤖 توابع گروه + 5. 💬 مدیریت مکالمه + +این برنامه با استفاده از Golang ساخته شده است و از استقرار چند پلت فرم پشتیبانی می کند و تجربه دسترسی ثابت را در تمام پلتفرم ها تضمین می کند. + +👉 **[کاوش GO SDK](https://github.com/openimsdk/openim-sdk-core)** + +## 🌐 درباره OpenIMServer + ++ **OpenIMServer** دارای ویژگی های زیر است: + - 🌐 معماری Microservice: از حالت کلاستر، از جمله یک دروازه و چندین سرویس rpc پشتیبانی می کند. + - 🚀 روش‌های استقرار متنوع: از استقرار از طریق کد منبع، Kubernetes یا Docker پشتیبانی می‌کند. + - پشتیبانی از پایگاه عظیم کاربران: گروه های فوق العاده بزرگ با صدها هزار کاربر، ده ها میلیون کاربر و میلیاردها پیام. + +### عملکردهای تجاری پیشرفته: + ++ **REST API**: OpenIMServer APIهای REST را برای سیستم‌های تجاری ارائه می‌کند، با هدف توانمندسازی کسب‌وکارها با قابلیت‌های بیشتر، مانند ایجاد گروه‌ها و ارسال پیام‌های فشار از طریق رابط‌های باطنی. ++ **Webhooks**: OpenIMServer قابلیت های پاسخ به تماس را برای گسترش بیشتر فرم های تجاری ارائه می دهد. پاسخ به تماس به این معنی است که OpenIMServer درخواستی را قبل یا بعد از یک رویداد خاص به سرور تجاری ارسال می کند، مانند تماس های قبل یا بعد از ارسال یک پیام. + +👉 **[بیشتر بدانید](https://docs.openim.io/guides/introduction/product)** + +## :building_construction: معماری کلی + +با نمودار معماری ما به قلب عملکرد Open-IM-Server بپردازید. + +![Overall Architecture](../images/architecture-layers.png) + + +## :rocket: شروع سریع + +ما از بسیاری از پلتفرم ها پشتیبانی می کنیم. در اینجا آدرس هایی برای تجربه سریع در سمت وب آمده است: + +👉 **[نسخه نمایشی وب آنلاین OpenIM](https://web-enterprise.rentsoft.cn/)** + +🤲 برای تسهیل تجربه کاربر، ما راه حل های مختلف استقرار را ارائه می دهیم. می توانید روش استقرار خود را از لیست زیر انتخاب کنید: + ++ **[راهنمای استقرار کد منبع](https://docs.openim.io/guides/gettingStarted/imSourceCodeDeployment)** ++ **[راهنمای استقرار داکر](https://docs.openim.io/guides/gettingStarted/dockerCompose)** ++ **[راهنمای استقرار Kubernetes](https://docs.openim.io/guides/gettingStarted/k8s-deployment)** ++ **[راهنمای استقرار توسعه دهنده مک](https://docs.openim.io/guides/gettingstarted/mac-deployment-guide)** + +## :hammer_and_wrench: برای شروع توسعه OpenIM + +[![Open in Dev Container](https://img.shields.io/static/v1?label=Dev%20Container&message=Open&color=blue&logo=visualstudiocode)](https://vscode.dev/github/openimsdk/open-im-server) + +OpenIM هدف ما ایجاد یک جامعه منبع باز سطح بالا است. ما مجموعه ای از استانداردها را در [مخزن انجمن](https://github.com/OpenIMSDK/community) داریم.. + +اگر می‌خواهید در این مخزن Open-IM-Server مشارکت کنید، لطفاً [مستندات مشارکت‌کننده](https://github.com/openimsdk/open-im-server/blob/main/CONTRIBUTING.md) ما را بخوانید. + +قبل از شروع، لطفاً مطمئن شوید که تغییرات شما مورد تقاضا هستند. بهترین کار برای آن این است که یک [بحث جدید](https://github.com/openimsdk/open-im-server/discussions/new/choose) یا [ارتباط اسلک](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q) ایجاد کنید، یا اگر مشکلی پیدا کردید، ابتدا [آن را گزارش کنید](https://github.com/openimsdk/open-im-server/issues/new/choose). + +- [مرجع OpenIM API](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/api.md) +- [OpenIM Bash Logging](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/bash-log.md) +- [OpenIM CI/CD Actions](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/cicd-actions.md) +- [کنوانسیون کد OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/code-conventions.md) +- [دستورالعمل های تعهد OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/commit.md) +- [راهنمای توسعه OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/development.md) +- [ساختار دایرکتوری OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/directory.md) +- [تنظیم محیط OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/environment.md) +- [مرجع کد خطا OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/error-code.md) +- [OpenIM Git Workflow](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/git-workflow.md) +- [راهنمای انتخاب گیلاس OpenIM Git](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/gitcherry-pick.md) +- [OpenIM GitHub Workflow](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/github-workflow.md) +- [استانداردهای کد OpenIM Go](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/go-code.md) +- [دستورالعمل های تصویر OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/images.md) +- [پیکربندی اولیه OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/init-config.md) +- [راهنمای نصب OpenIM Docker](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/install-docker.md) +- [نصب سیستم OpenIM Linux OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/install-openim-linux-system.md) +- [راهنمای توسعه OpenIM Linux](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/linux-development.md) +- [راهنمای اقدامات محلی OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/local-actions.md) +- [OpenIM Logging Conventions](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/logging.md) +- [استقرار آفلاین OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/offline-deployment.md) +- [OpenIM Protoc Tools](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/protoc-tools.md) +- [راهنمای تست OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/test.md) +- [OpenIM Utility Go](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/util-go.md) +- [OpenIM Makefile Utilities](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/util-makefile.md) +- [ابزارهای OpenIM Script](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/util-scripts.md) +- [نسخه OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/version.md) +- [مدیریت استقرار باطن و نظارت](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/prometheus-grafana.md) +- [راهنمای استقرار توسعه دهنده مک برای OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/mac-developer-deployment-guide.md) + + +## :busts_in_silhouette: انجمن + ++ 📚 [انجمن OpenIM](https://github.com/OpenIMSDK/community) ++ 💕 [گروه علاقه OpenIM](https://github.com/Openim-sigs) ++ 🚀 [به انجمن Slack ما بپیوندید](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q) ++ :eyes: [به وی چت ما بپیوندید](https://openim-1253691595.cos.ap-nanjing.myqcloud.com/WechatIMG20.jpeg) + +## :calendar: جلسات جامعه + +ما می‌خواهیم هر کسی در انجمن ما مشارکت کند و در کد مشارکت کند، ما هدایا و جوایزی ارائه می‌کنیم، و از شما استقبال می‌کنیم که هر پنجشنبه شب به ما بپیوندید. + +کنفرانس ما در [OpenIM Slack](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q) 🎯 است، سپس می توانید خط لوله Open-IM-Server را برای پیوستن جستجو کنید. + +ما از هر [جلسه دو هفته‌ای](https://github.com/orgs/OpenIMSDK/discussions/categories/meeting) در [بحث‌های GitHub](https://github.com/openimsdk/open-im-server/discussions/categories/meeting) یادداشت‌برداری می‌کنیم، یادداشت‌های جلسه تاریخی ما، و همچنین بازپخش جلسات در [Google Docs :bookmark_tabs:](https://docs.google.com/document/d/1nx8MDpuG74NASx081JcCpxPgDITNTpIIos0DS6Vr9GU/edit?usp=sharing) موجود است. + +## :eyes: چه کسانی از OpenIM استفاده می کنند + +صفحه [مطالعات موردی کاربر](https://github.com/OpenIMSDK/community/blob/main/ADOPTERS.md) ما را برای لیستی از کاربران پروژه بررسی کنید. از گذاشتن [نظر📝](https://github.com/openimsdk/open-im-server/issues/379) و به اشتراک گذاری مورد استفاده خود دریغ نکنید. + +## :page_facing_up: مجوز + +OpenIM تحت مجوز Apache 2.0 مجوز دارد. برای متن کامل مجوز به [LICENSE](https://github.com/openimsdk/open-im-server/tree/main/LICENSE) مراجعه کنید. + +نشان‌واره OpenIM، شامل انواع و نسخه‌های متحرک آن، که در این مخزن [OpenIM](https://github.com/openimsdk/open-im-server) تحت فهرست‌های [assets/logo](./assets/logo) و [assets/logo-gif](assets/logo-gif) نمایش داده می‌شود، توسط قوانین حق چاپ محافظت می‌شود. + +## 🔮 با تشکر از همکاران ما! + + + + From 35ad4a9510e6f4d8140569286b89097c6eb833d0 Mon Sep 17 00:00:00 2001 From: OpenIM Bot <124379614+kubbot@users.noreply.github.com> Date: Mon, 19 Feb 2024 10:19:32 +0800 Subject: [PATCH 050/188] cicd: bump League Patch (#1921) --- cmd/openim-api/main.go | 3 ++- internal/msgtransfer/init.go | 22 +++++++++++++--------- internal/push/consumer_init.go | 1 + internal/push/push_rpc_server.go | 1 + internal/rpc/conversation/conversaion.go | 1 + pkg/authverify/token.go | 3 ++- pkg/common/kafka/consumer_group.go | 4 +++- pkg/common/startrpc/start.go | 11 +++++++---- 8 files changed, 30 insertions(+), 16 deletions(-) diff --git a/cmd/openim-api/main.go b/cmd/openim-api/main.go index c8746bc20b..7a7e062939 100644 --- a/cmd/openim-api/main.go +++ b/cmd/openim-api/main.go @@ -17,7 +17,6 @@ package main import ( "context" "fmt" - util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" "net" "net/http" _ "net/http/pprof" @@ -27,6 +26,8 @@ import ( "syscall" "time" + util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" + "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/protocol/constant" diff --git a/internal/msgtransfer/init.go b/internal/msgtransfer/init.go index 062017f448..16d8613dbf 100644 --- a/internal/msgtransfer/init.go +++ b/internal/msgtransfer/init.go @@ -18,11 +18,24 @@ import ( "context" "errors" "fmt" + "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/log" + util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" + "net/http" + "os" + "os/signal" + "syscall" + "github.com/OpenIMSDK/tools/mw" + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/collectors" + "github.com/prometheus/client_golang/prometheus/promhttp" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" + "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" @@ -30,15 +43,6 @@ import ( kdisc "github.com/openimsdk/open-im-server/v3/pkg/common/discoveryregister" "github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" - "github.com/prometheus/client_golang/prometheus" - "github.com/prometheus/client_golang/prometheus/collectors" - "github.com/prometheus/client_golang/prometheus/promhttp" - "google.golang.org/grpc" - "google.golang.org/grpc/credentials/insecure" - "net/http" - "os" - "os/signal" - "syscall" ) type MsgTransfer struct { diff --git a/internal/push/consumer_init.go b/internal/push/consumer_init.go index 80478de99d..572afe0eb1 100644 --- a/internal/push/consumer_init.go +++ b/internal/push/consumer_init.go @@ -16,6 +16,7 @@ package push import ( "context" + "github.com/OpenIMSDK/tools/log" ) diff --git a/internal/push/push_rpc_server.go b/internal/push/push_rpc_server.go index caaf955259..f558aeec3d 100644 --- a/internal/push/push_rpc_server.go +++ b/internal/push/push_rpc_server.go @@ -16,6 +16,7 @@ package push import ( "context" + "github.com/OpenIMSDK/tools/utils" "google.golang.org/grpc" diff --git a/internal/rpc/conversation/conversaion.go b/internal/rpc/conversation/conversaion.go index 903ecbb188..8558a23ea4 100644 --- a/internal/rpc/conversation/conversaion.go +++ b/internal/rpc/conversation/conversaion.go @@ -50,6 +50,7 @@ type conversationServer struct { conversationDatabase controller.ConversationDatabase conversationNotificationSender *notification.ConversationNotificationSender } + func (c *conversationServer) GetConversationNotReceiveMessageUserIDs( ctx context.Context, req *pbconversation.GetConversationNotReceiveMessageUserIDsReq, diff --git a/pkg/authverify/token.go b/pkg/authverify/token.go index b951bf219c..97bb033916 100644 --- a/pkg/authverify/token.go +++ b/pkg/authverify/token.go @@ -48,7 +48,8 @@ func CheckAccessV3(ctx context.Context, ownerUserID string) (err error) { } func IsAppManagerUid(ctx context.Context) bool { - return (len(config.Config.Manager.UserID) > 0 && utils.IsContain(mcontext.GetOpUserID(ctx), config.Config.Manager.UserID)) || utils.IsContain(mcontext.GetOpUserID(ctx), config.Config.IMAdmin.UserID) + return (len(config.Config.Manager.UserID) > 0 && utils.IsContain(mcontext.GetOpUserID(ctx), config.Config.Manager.UserID)) || + utils.IsContain(mcontext.GetOpUserID(ctx), config.Config.IMAdmin.UserID) } func CheckAdmin(ctx context.Context) error { diff --git a/pkg/common/kafka/consumer_group.go b/pkg/common/kafka/consumer_group.go index 908b8f088b..5245c6a6f7 100644 --- a/pkg/common/kafka/consumer_group.go +++ b/pkg/common/kafka/consumer_group.go @@ -18,12 +18,14 @@ import ( "context" "errors" "fmt" + "github.com/IBM/sarama" "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/log" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" "strings" + + "github.com/openimsdk/open-im-server/v3/pkg/common/config" ) type MConsumerGroup struct { diff --git a/pkg/common/startrpc/start.go b/pkg/common/startrpc/start.go index 4b032e9d6b..c5105ec513 100644 --- a/pkg/common/startrpc/start.go +++ b/pkg/common/startrpc/start.go @@ -18,8 +18,6 @@ import ( "context" "errors" "fmt" - "github.com/OpenIMSDK/tools/errs" - util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" "net" "net/http" "os" @@ -29,11 +27,16 @@ import ( "syscall" "time" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" - "github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics" + "github.com/OpenIMSDK/tools/errs" + + util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" + "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promhttp" + "github.com/openimsdk/open-im-server/v3/pkg/common/config" + "github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics" + grpcprometheus "github.com/grpc-ecosystem/go-grpc-prometheus" "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" From 026f5255c99336da6f1b8329e9f6627bb30cacaa Mon Sep 17 00:00:00 2001 From: xuan <146319162+wxuanF@users.noreply.github.com> Date: Mon, 19 Feb 2024 10:59:32 +0800 Subject: [PATCH 051/188] docs: README add community (#1922) Signed-off-by: wxuanF <2569456943@qq.com> --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index a91024e492..2614a1c75c 100644 --- a/README.md +++ b/README.md @@ -161,6 +161,8 @@ Before you start, please make sure your changes are in demand. The best for that + 💕 [OpenIM Interest Group](https://github.com/Openim-sigs) + 🚀 [Join our Slack community](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q) + :eyes: [Join our wechat (微信群)](https://openim-1253691595.cos.ap-nanjing.myqcloud.com/WechatIMG20.jpeg) ++ 👫 [Join our Reddit](https://www.reddit.com/r/OpenIMessaging) ++ 💬 [Follow our Twitter account](https://twitter.com/openimsdk) ## :calendar: Community Meetings From 35154321402621c2ff52a844b69ee871f0661a0b Mon Sep 17 00:00:00 2001 From: xuan <146319162+wxuanF@users.noreply.github.com> Date: Mon, 19 Feb 2024 20:27:00 +0800 Subject: [PATCH 052/188] docs: add README_da.md (#1927) Signed-off-by: wxuanF <2569456943@qq.com> --- docs/readme/README_da.md | 192 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 192 insertions(+) create mode 100644 docs/readme/README_da.md diff --git a/docs/readme/README_da.md b/docs/readme/README_da.md new file mode 100644 index 0000000000..1b776ddb8b --- /dev/null +++ b/docs/readme/README_da.md @@ -0,0 +1,192 @@ +

+ + + +

+ +
+ +[![Stars](https://img.shields.io/github/stars/openimsdk/open-im-server?style=for-the-badge&logo=github&colorB=ff69b4)](https://github.com/openimsdk/open-im-server/stargazers) +[![Forks](https://img.shields.io/github/forks/openimsdk/open-im-server?style=for-the-badge&logo=github&colorB=blue)](https://github.com/openimsdk/open-im-server/network/members) +[![Codecov](https://img.shields.io/codecov/c/github/openimsdk/open-im-server?style=for-the-badge&logo=codecov&colorB=orange)](https://app.codecov.io/gh/openimsdk/open-im-server) +[![Go Report Card](https://goreportcard.com/badge/github.com/openimsdk/open-im-server?style=for-the-badge)](https://goreportcard.com/report/github.com/openimsdk/open-im-server) +[![Go Reference](https://img.shields.io/badge/Go%20Reference-blue.svg?style=for-the-badge&logo=go&logoColor=white)](https://pkg.go.dev/github.com/openimsdk/open-im-server/v3) +[![License](https://img.shields.io/badge/license-Apache--2.0-green?style=for-the-badge)](https://github.com/openimsdk/open-im-server/blob/main/LICENSE) +[![Slack](https://img.shields.io/badge/Slack-500%2B-blueviolet?style=for-the-badge&logo=slack&logoColor=white)](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q) +[![Best Practices](https://img.shields.io/badge/Best%20Practices-purple?style=for-the-badge)](https://www.bestpractices.dev/projects/8045) +[![Good First Issues](https://img.shields.io/github/issues/openimsdk/open-im-server/good%20first%20issue?style=for-the-badge&logo=github)](https://github.com/openimsdk/open-im-server/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc+label%3A%22good+first+issue%22) +[![Language](https://img.shields.io/badge/Language-Go-blue.svg?style=for-the-badge&logo=go&logoColor=white)](https://golang.org/) + + +

+ Englist · + 中文 · + Українська · + Česky · + Magyar · + Español · + فارسی · + Français · + Deutsch · + Polski · + Indonesian · + Suomi · + മലയാളം · + 日本語 · + Nederlands · + Italiano · + Русский · + Português (Brasil) · + Esperanto · + 한국어 · + العربي · + Tiếng Việt · + Dansk · + Ελληνικά · + Türkçe +

+ + +
+ +

+ + +## :busts_in_silhouette: Fællesskab + ++ 📚 [OpenIM-fællesskab](https://github.com/OpenIMSDK/community) ++ 💕 [OpenIM-interessegruppe](https://github.com/Openim-sigs) ++ 🚀 [Deltag i vores Slack-fællesskab](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q) ++ :eyes: [Deltag i vores WeChat (微信群)](https://openim-1253691595.cos.ap-nanjing.myqcloud.com/WechatIMG20.jpeg) ++ 👫 [Deltag i vores Reddit](https://www.reddit.com/r/OpenIMessaging) ++ 💬 [Følg vores Twitter-konto](https://twitter.com/openimsdk) + + +## Ⓜ️ Om OpenIM + +OpenIM er en serviceplatform designet specifikt til integration af chat, lyd-videoopkald, notifikationer og AI-chatbots i applikationer. Den tilbyder en række kraftfulde API'er og Webhooks, som gør det let for udviklere at integrere disse interaktive funktioner i deres applikationer. OpenIM er ikke en selvstændig chatapplikation, men fungerer snarere som en platform, der understøtter andre applikationer i at opnå omfattende kommunikationsfunktionaliteter. Følgende diagram illustrerer interaktionen mellem AppServer, AppClient, OpenIMServer og OpenIMSDK for at forklare detaljeret. + + + +![App-OpenIM Relationship](../images/oepnim-design.png) + +## 🚀 Om OpenIMSDK + + **OpenIMSDK** er en IM SDK designet til **OpenIMServer**, skabt specifikt til indlejring i klientapplikationer. Dens vigtigste funktioner og moduler er som følger: + ++ 🌟 Hovedfunktioner: + + - 📦 Lokal lagring + - 🔔 Lytter-callbacks + - 🛡️ API-indkapsling + - 🌐 Forbindelsesstyring + + ## 📚 Hovedmoduler: + + 1. 🚀 Initialisering og login + 2. 👤 Brugerstyring + 3. 👫 Venstyring + 4. 🤖 Gruppefunktioner + 5. 💬 Håndtering af samtaler + +Det er bygget ved hjælp af Golang og understøtter tværplatformsudrulning, hvilket sikrer en konsekvent adgangsoplevelse på tværs af alle platforme. + +👉 **[Udforsk GO SDK](https://github.com/openimsdk/openim-sdk-core)** + +## 🌐 Om OpenIMServer + ++ **OpenIMServer** har følgende karakteristika: + - 🌐 Mikroservicarkitektur: Understøtter klyngetilstand, inklusive en gateway og flere rpc-tjenester. + - 🚀 Forskellige udrulningsmetoder: Understøtter udrulning via kildekode, Kubernetes eller Docker. + - Støtte til massiv brugerbase: Super store grupper med hundredtusinder af brugere, titusinder af brugere og milliarder af beskeder. + +### Forbedret forretningsfunktionalitet: + ++ **REST API**:OpenIMServer tilbyder REST API'er til forretningssystemer, med det formål at give virksomheder flere funktioner, såsom at oprette grupper og sende push-beskeder gennem backend-grænseflader. ++ **Webhooks**:OpenIMServer giver mulighed for callback-funktionalitet for at udvide flere forretningsformer. Et callback betyder, at OpenIMServer sender en anmodning til forretningsserveren før eller efter en bestemt begivenhed, som callbacks før eller efter at have sendt en besked. + +👉 **[Lær mere](https://docs.openim.io/guides/introduction/product)** + +## :building_construction: Samlet Arkitektur + +Dyk ned i hjertet af Open-IM-Servers funktionalitet med vores arkitekturdiagram. + +![Overall Architecture](../images/architecture-layers.png) + +## :rocket: Hurtig start + +Vi understøtter mange platforme. Her er adresserne for hurtig oplevelse på websiden: + +👉 **[OpenIM online demo](https://www.openim.io/zh/commercial)** + +🤲 For at lette brugeroplevelsen tilbyder vi forskellige udrulningsløsninger. Du kan vælge din udrulningsmetode fra listen nedenfor: + ++ **[Vejledning til udrulning af kildekode](https://docs.openim.io/guides/gettingStarted/imSourceCodeDeployment)** ++ **[Vejledning til Docker-udrulning](https://docs.openim.io/guides/gettingStarted/dockerCompose)** ++ **[Vejledning til Kubernetes-udrulning](https://docs.openim.io/guides/gettingStarted/k8s-deployment)** ++ **[Vejledning til Mac-udviklerudrulning](https://docs.openim.io/guides/gettingstarted/mac-deployment-guide)** + +## :hammer_and_wrench: For at starte udviklingen af OpenIM + +[![Open in Dev Container](https://img.shields.io/static/v1?label=Dev%20Container&message=Open&color=blue&logo=visualstudiocode)](https://vscode.dev/github/openimsdk/open-im-server) + +OpenIM Vores mål er at bygge et topniveau åben kildekode-fællesskab. Vi har et sæt standarder i [Community-repositoriet](https://github.com/OpenIMSDK/community). + +Hvis du gerne vil bidrage til dette Open-IM-Server-repositorium, bedes du læse vores [dokumentation for bidragydere](https://github.com/openimsdk/open-im-server/blob/main/CONTRIBUTING.md). + +Før du starter, skal du sikre dig, at dine ændringer er efterspurgte. Det bedste for det er at oprette en [ny diskussion](https://github.com/openimsdk/open-im-server/discussions/new/choose) ELLER [Slack-kommunikation](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q), eller hvis du finder et problem, [rapportere det](https://github.com/openimsdk/open-im-server/issues/new/choose) først. + +- [OpenIM API-referencer](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/api.md) +- [OpenIM Bash-logging](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/bash-log.md) +- [OpenIM CI/CD-handlinger](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/cicd-actions.md) +- [OpenIM kodekonventioner](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/code-conventions.md) +- [OpenIM commit-retningslinjer](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/commit.md) +- [OpenIM udviklingsguide](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/development.md) +- [OpenIM mappestruktur](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/directory.md) +- [OpenIM miljøopsætning](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/environment.md) +- [OpenIM fejlkode-reference](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/error-code.md) +- [OpenIM Git-arbejdsgang](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/git-workflow.md) +- [OpenIM Git Cherry Pick-guide](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/gitcherry-pick.md) +- [OpenIM GitHub-arbejdsgang](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/github-workflow.md) +- [OpenIM Go kode-standarder](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/go-code.md) +- [OpenIM billedretningslinjer](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/images.md) +- [OpenIM initialkonfiguration](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/init-config.md) +- [OpenIM Docker installationsguide](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/install-docker.md) +- [OpenIM OpenIM Linux-systeminstallation](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/install-openim-linux-system.md) +- [OpenIM Linux-udviklingsguide](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/linux-development.md) +- [OpenIM lokale handlingsguide](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/local-actions.md) +- [OpenIM logningskonventioner](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/logging.md) +- [OpenIM offline-udrulning](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/offline-deployment.md) +- [OpenIM Protoc-værktøjer](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/protoc-tools.md) +- [OpenIM testguide](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/test.md) +- [OpenIM Utility Go](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/util-go.md) +- [OpenIM Makefile-værktøjer](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/util-makefile.md) +- [OpenIM skriptværktøjer](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/util-scripts.md) +- [OpenIM versionsstyring](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/version.md) +- [Administrer backend og overvåg udrulning](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/prometheus-grafana.md) +- [Mac-udviklerudrulningsguide for OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/mac-developer-deployment-guide.md) + + +## :calendar: Fællesskabsmøder + +Vi ønsker, at alle involverer sig i vores fællesskab og bidrager med kode, vi tilbyder gaver og belønninger, og vi byder dig velkommen til at deltage hver torsdag aften. + +Vores konference er på [OpenIM Slack](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q) 🎯, derefter kan du søge Open-IM-Server pipeline for at deltage. + +Vi tager [notater](https://github.com/orgs/OpenIMSDK/discussions/categories/meeting) af hvert fjortendages møde i [GitHub-diskussioner](https://github.com/openimsdk/open-im-server/discussions/categories/meeting), Vores historiske mødenotater samt genudsendelser af møderne er tilgængelige på [Google Docs](https://docs.google.com/document/d/1nx8MDpuG74NASx081JcCpxPgDITNTpIIos0DS6Vr9GU/edit?usp=sharing) 📑. + +## :eyes: Hvem Bruger OpenIM + +Tjek vores side med [brugercasestudier](https://github.com/OpenIMSDK/community/blob/main/ADOPTERS.md) for en liste over projektbrugerne. Tøv ikke med at efterlade en 📝[kommentar](https://github.com/openimsdk/open-im-server/issues/379) og dele dit brugstilfælde. + +## :page_facing_up: Licens + +OpenIM er licenseret under Apache 2.0-licensen. Se [LICENSE](https://github.com/openimsdk/open-im-server/tree/main/LICENSE) for den fulde licens tekst. + +OpenIM-logoet, inklusive dets variationer og animerede versioner, vist i dette repositorium [OpenIM](https://github.com/openimsdk/open-im-server) under mapperne [assets/logo](../../assets/logo) og [assets/logo-gif](../../assets/logo-gif), er beskyttet af ophavsretslove. + +## 🔮 Tak til vores bidragydere! + + + + \ No newline at end of file From fe0116a811690bcfbf65744fe825a9cf39fd7f29 Mon Sep 17 00:00:00 2001 From: longyuqing112 <105913803+longyuqing112@users.noreply.github.com> Date: Mon, 19 Feb 2024 20:27:45 +0800 Subject: [PATCH 053/188] add Docs/readme vi (#1925) * docs/README_vi Signed-off-by: longyuqing112 <2631918708@qq.com> * docs/README_vi Signed-off-by: longyuqing112 <2631918708@qq.com> --------- Signed-off-by: longyuqing112 <2631918708@qq.com> --- docs/readme/README_vi.md | 188 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 188 insertions(+) create mode 100644 docs/readme/README_vi.md diff --git a/docs/readme/README_vi.md b/docs/readme/README_vi.md new file mode 100644 index 0000000000..e500da6d2d --- /dev/null +++ b/docs/readme/README_vi.md @@ -0,0 +1,188 @@ +

+ + + +

+ +
+ +[![Stars](https://img.shields.io/github/stars/openimsdk/open-im-server?style=for-the-badge&logo=github&colorB=ff69b4)](https://github.com/openimsdk/open-im-server/stargazers) +[![Forks](https://img.shields.io/github/forks/openimsdk/open-im-server?style=for-the-badge&logo=github&colorB=blue)](https://github.com/openimsdk/open-im-server/network/members) +[![Codecov](https://img.shields.io/codecov/c/github/openimsdk/open-im-server?style=for-the-badge&logo=codecov&colorB=orange)](https://app.codecov.io/gh/openimsdk/open-im-server) +[![Go Report Card](https://goreportcard.com/badge/github.com/openimsdk/open-im-server?style=for-the-badge)](https://goreportcard.com/report/github.com/openimsdk/open-im-server) +[![Go Reference](https://img.shields.io/badge/Go%20Reference-blue.svg?style=for-the-badge&logo=go&logoColor=white)](https://pkg.go.dev/github.com/openimsdk/open-im-server/v3) +[![License](https://img.shields.io/badge/license-Apache--2.0-green?style=for-the-badge)](https://github.com/openimsdk/open-im-server/blob/main/LICENSE) +[![Slack](https://img.shields.io/badge/Slack-500%2B-blueviolet?style=for-the-badge&logo=slack&logoColor=white)](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q) +[![Best Practices](https://img.shields.io/badge/Best%20Practices-purple?style=for-the-badge)](https://www.bestpractices.dev/projects/8045) +[![Good First Issues](https://img.shields.io/github/issues/openimsdk/open-im-server/good%20first%20issue?style=for-the-badge&logo=github)](https://github.com/openimsdk/open-im-server/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc+label%3A%22good+first+issue%22) +[![Language](https://img.shields.io/badge/Language-Go-blue.svg?style=for-the-badge&logo=go&logoColor=white)](https://golang.org/) + + +

+ Englist · + 中文 · + Українська · + Česky · + Magyar · + Español · + فارسی · + Français · + Deutsch · + Polski · + Indonesian · + Suomi · + മലയാളം · + 日本語 · + Nederlands · + Italiano · + Русский · + Português (Brasil) · + Esperanto · + 한국어 · + العربي · + Tiếng Việt · + Dansk · + Ελληνικά · + Türkçe +

+ + +
+ +

+ +## Ⓜ️ Về OpenIM + +OpenIM là một nền tảng dịch vụ được thiết kế đặc biệt cho việc tích hợp chat, cuộc gọi âm thanh-video, thông báo và chatbot AI vào các ứng dụng. Nó cung cấp một loạt các API mạnh mẽ và Webhooks, giúp các nhà phát triển dễ dàng tích hợp các tính năng tương tác này vào ứng dụng của mình. OpenIM không phải là một ứng dụng chat độc lập, mà là một nền tảng hỗ trợ các ứng dụng khác để đạt được các chức năng giao tiếp phong phú. Sơ đồ sau đây minh họa sự tương tác giữa AppServer, AppClient, OpenIMServer và OpenIMSDK để giải thích chi tiết. + +![App-OpenIM Relationship](../../docs/images/oepnim-design.png) + +## 🚀 Về OpenIMSDK + +**OpenIMSDK** là một SDK IM được thiết kế cho **OpenIMServer**, được tạo ra đặc biệt để nhúng vào các ứng dụng khách. Các tính năng chính và các mô-đun của nó như sau: + ++ 🌟 Các Tính Năng Chính: + + - 📦 Lưu trữ cục bộ + - 🔔 Gọi lại sự kiện (Listener callbacks) + - 🛡️ Bọc API + - 🌐 Quản lý kết nối + ++ 📚 Các Mô-đun Chính: + + 1. 🚀 Khởi tạo và Đăng nhập + 2. 👤 Quản lý Người dùng + 3. 👫 Quản lý Bạn bè + 4. 🤖 Chức năng Nhóm + 5. 💬 Xử lý Cuộc trò chuyện + +Nó được xây dựng bằng Golang và hỗ trợ triển khai đa nền tảng, đảm bảo trải nghiệm truy cập nhất quán trên tất cả các nền tảng + +👉 **[Khám phá GO SDK](https://github.com/openimsdk/openim-sdk-core)** + +## 🌐 Về OpenIMServer + ++ **OpenIMServer** có những đặc điểm sau: + - 🌐 Kiến trúc vi dịch vụ: Hỗ trợ chế độ cluster, bao gồm một gateway và nhiều dịch vụ rpc. + - 🚀 Phương pháp triển khai đa dạng: Hỗ trợ triển khai qua mã nguồn, Kubernetes hoặc Docker. + - Hỗ trợ cho cơ sở người dùng lớn: Nhóm siêu lớn với hàng trăm nghìn người dùng, hàng chục triệu người dùng và hàng tỷ tin nhắn. + +### Tăng cường Chức năng Kinh doanh: + ++ **REST API**: OpenIMServer cung cấp REST APIs cho các hệ thống kinh doanh, nhằm tăng cường khả năng cho doanh nghiệp với nhiều chức năng hơn, như tạo nhóm và gửi tin nhắn đẩy qua giao diện backend. ++ **Webhooks**: OpenIMServer cung cấp khả năng gọi lại để mở rộng thêm hình thức kinh doanh. Một gọi lại có nghĩa là OpenIMServer gửi một yêu cầu đến máy chủ kinh doanh trước hoặc sau một sự kiện nhất định, giống như gọi lại trước hoặc sau khi gửi một tin nhắn. + +👉 **[Learn more](https://docs.openim.io/guides/introduction/product)** + +## :building_construction: Kiến trúc tổng thể + + Làm sâu sắc vào trái tim của chức năng Open-IM-Server với sơ đồ kiến trúc của chúng tôi. + +![Overall Architecture](../../docs/images/architecture-layers.png) + + +## :rocket: Bắt đầu nhanh + +Chúng tôi hỗ trợ nhiều nền tảng. Dưới đây là các địa chỉ để trải nghiệm nhanh trên phía web: + +👉 **[Demo web trực tuyến OpenIM](https://web-enterprise.rentsoft.cn/)** + +🤲 Để tạo thuận lợi cho trải nghiệm người dùng, chúng tôi cung cấp các giải pháp triển khai đa dạng. Bạn có thể chọn phương thức triển khai từ danh sách dưới đây: + ++ **[Hướng dẫn Triển khai Mã Nguồn](https://docs.openim.io/guides/gettingStarted/imSourceCodeDeployment)** ++ **[Hướng dẫn Triển khai Docker](https://docs.openim.io/guides/gettingStarted/dockerCompose)** ++ **[Hướng dẫn Triển khai Kubernetes](https://docs.openim.io/guides/gettingStarted/k8s-deployment)** ++ **[Hướng dẫn Triển khai cho Nhà Phát Triển Mac](https://docs.openim.io/guides/gettingstarted/mac-deployment-guide)** + +## :hammer_and_wrench: Để Bắt Đầu Phát Triển OpenIM + +[![Mở trong Dev Contain](https://img.shields.io/static/v1?label=Dev%20Container&message=Open&color=blue&logo=visualstudiocode)](https://vscode.dev/github/openimsdk/open-im-server) + +Mục tiêu của OpenIM là xây dựng một cộng đồng mã nguồn mở cấp cao. Chúng tôi có một bộ tiêu chuẩn, Trong [kho lưu trữ Cộng đồng](https://github.com/OpenIMSDK/community). + +Nếu bạn muốn đóng góp cho kho lưu trữ Open-IM-Server này, vui lòng đọc [tài liệu hướng dẫn cho người đóng góp](https://github.com/openimsdk/open-im-server/blob/main/CONTRIBUTING.md). + + +Trước khi bạn bắt đầu, hãy chắc chắn rằng các thay đổi của bạn được yêu cầu. Cách tốt nhất là tạo một [cuộc thảo luận mới](https://github.com/openimsdk/open-im-server/discussions/new/choose) hoặc [Giao tiếp Slack](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q), hoặc nếu bạn tìm thấy một vấn đề, [báo cáo nó ](https://github.com/openimsdk/open-im-server/issues/new/choose) trước. + +- [Tham khảo API OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/api.md) +- [Nhật ký Bash OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/bash-log.md) +- [Hành động CI/CD OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/cicd-actions.md) +- [Quy ước Mã OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/code-conventions.md) +- [Hướng dẫn Commit OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/commit.md) +- [Hướng dẫn Phát triển OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/development.md) +- [Cấu trúc Thư mục OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/directory.md) +- [Cài đặt Môi trường OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/environment.md) +- [Tham khảo Mã Lỗi OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/error-code.md) +- [Quy trình Git OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/git-workflow.md) +- [Hướng dẫn Cherry Pick Git OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/gitcherry-pick.md) +- [Quy trình GitHub OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/github-workflow.md) +- [Tiêu chuẩn Mã Go OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/go-code.md) +- [Hướng dẫn Hình ảnh OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/images.md) +- [Cấu hình Ban đầu OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/init-config.md) +- [Hướng dẫn Cài đặt Docker OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/install-docker.md) +- [Hướng dẫn Cài đặt Hệ thống Linux OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/install-openim-linux-system.md) +- [Hướng dẫn Phát triển Linux OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/linux-development.md) +- [Hướng dẫn Hành động Địa phương OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/local-actions.md) +- [Quy ước Nhật ký OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/logging.md) +- [Triển khai Ngoại tuyến OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/offline-deployment.md) +- [Công cụ Protoc OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/protoc-tools.md) +- [Hướng dẫn Kiểm thử OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/test.md) +- [Utility Go OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/util-go.md) +- [Tiện ích Makefile OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/util-makefile.md) +- [Tiện ích Kịch bản OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/util-scripts.md) +- [Quản lý Phiên bản OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/version.md) +- [Quản lý triển khai và giám sát backend](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/prometheus-grafana.md) +- [Hướng dẫn Triển khai cho Nhà Phát triển Mac OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/mac-developer-deployment-guide.md) + + +## :busts_in_silhouette: Cộng đồng + ++ 📚 [Cộng đồng OpenIM](https://github.com/OpenIMSDK/community) ++ 💕 [Nhóm Quan tâm OpenIM](https://github.com/Openim-sigs) ++ 🚀 [Tham gia cộng đồng Slack của chúng tôi](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q) ++ :eyes: [Tham gia nhóm WeChat của chúng tôi (微信群)](https://openim-1253691595.cos.ap-nanjing.myqcloud.com/WechatIMG20.jpeg) + +## :calendar: Cuộc họp Cộng đồng + +Chúng tôi muốn bất kỳ ai cũng có thể tham gia cộng đồng và đóng góp mã nguồn, chúng tôi cung cấp quà tặng và phần thưởng, và chúng tôi chào đón bạn tham gia cùng chúng tôi mỗi tối thứ Năm. + +Hội nghị của chúng tôi được tổ chức trên Slack của [OpenIM Slack](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q) 🎯, sau đó bạn có thể tìm kiếm pipeline Open-IM-Server để tham gia + +Chúng tôi ghi chú mỗi [cuộc họp hai tuần một lần](https://github.com/orgs/OpenIMSDK/discussions/categories/meeting) trong [các cuộc thảo luận GitHub](https://github.com/openimsdk/open-im-server/discussions/categories/meeting), ghi chú cuộc họp lịch sử của chúng tôi cũng như các bản ghi lại của cuộc họp có sẵn tại [Google Docs :bookmark_tabs:](https://docs.google.com/document/d/1nx8MDpuG74NASx081JcCpxPgDITNTpIIos0DS6Vr9GU/edit?usp=sharing). + +## :eyes: Ai Đang Sử Dụng OpenIM + +Xem trangr [các nghiên cứu trường hợp người dùng](https://github.com/OpenIMSDK/community/blob/main/ADOPTERS.md) của chúng tôi để biết danh sách các người dùng dự án. Đừng ngần ngại để lại [📝bình luận](https://github.com/openimsdk/open-im-server/issues/379) và chia sẻ trường hợp sử dụng của bạn. + +## :page_facing_up: Giấy phép + +OpenIM được cấp phép theo giấy phép Apache 2.0. Xem [GIẤY PHÉP](https://github.com/openimsdk/open-im-server/tree/main/LICENSE) để biết toàn bộ nội dung giấy phép. + +Logo OpenIM, bao gồm các biến thể và phiên bản hoạt hình, được hiển thị trong kho lưu trữ này [OpenIM](https://github.com/openimsdk/open-im-server) dưới các thư mục [assets/logo](../../assets/logo) và [assets/logo-gif](assets/logo-gif) được bảo vệ bởi luật bản quyền. + +## 🔮 Cảm ơn các đóng góp của bạn! + + + + From 751497fe751797b6b8ec4e36ff1b1df00b331fa4 Mon Sep 17 00:00:00 2001 From: xuan <146319162+wxuanF@users.noreply.github.com> Date: Tue, 20 Feb 2024 20:18:43 +0800 Subject: [PATCH 054/188] Docs/readme modify oeder (#1924) * docs: README add community Signed-off-by: wxuanF <2569456943@qq.com> * docs: README modify order Signed-off-by: wxuanF <2569456943@qq.com> --------- Signed-off-by: wxuanF <2569456943@qq.com> --- README.md | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 2614a1c75c..d45c6b6fed 100644 --- a/README.md +++ b/README.md @@ -51,6 +51,15 @@

+## :busts_in_silhouette: Community + ++ 📚 [OpenIM Community](https://github.com/OpenIMSDK/community) ++ 💕 [OpenIM Interest Group](https://github.com/Openim-sigs) ++ 🚀 [Join our Slack community](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q) ++ :eyes: [Join our wechat (微信群)](https://openim-1253691595.cos.ap-nanjing.myqcloud.com/WechatIMG20.jpeg) ++ 👫 [Join our Reddit](https://www.reddit.com/r/OpenIMessaging) ++ 💬 [Follow our Twitter account](https://twitter.com/openimsdk) + ## Ⓜ️ About OpenIM OpenIM is a service platform specifically designed for integrating chat, audio-video calls, notifications, and AI chatbots into applications. It provides a range of powerful APIs and Webhooks, enabling developers to easily incorporate these interactive features into their applications. OpenIM is not a standalone chat application, but rather serves as a platform to support other applications in achieving rich communication functionalities. The following diagram illustrates the interaction between AppServer, AppClient, OpenIMServer, and OpenIMSDK to explain in detail. @@ -154,16 +163,6 @@ Before you start, please make sure your changes are in demand. The best for that - [Manage backend and monitor deployment](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/prometheus-grafana.md) - [Mac Developer Deployment Guide for OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/mac-developer-deployment-guide.md) - -## :busts_in_silhouette: Community - -+ 📚 [OpenIM Community](https://github.com/OpenIMSDK/community) -+ 💕 [OpenIM Interest Group](https://github.com/Openim-sigs) -+ 🚀 [Join our Slack community](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q) -+ :eyes: [Join our wechat (微信群)](https://openim-1253691595.cos.ap-nanjing.myqcloud.com/WechatIMG20.jpeg) -+ 👫 [Join our Reddit](https://www.reddit.com/r/OpenIMessaging) -+ 💬 [Follow our Twitter account](https://twitter.com/openimsdk) - ## :calendar: Community Meetings We want anyone to get involved in our community and contributing code, we offer gifts and rewards, and we welcome you to join us every Thursday night. From 01886eee06d6702130ff2714f25cf9751451d724 Mon Sep 17 00:00:00 2001 From: longyuqing112 <105913803+longyuqing112@users.noreply.github.com> Date: Tue, 20 Feb 2024 20:19:15 +0800 Subject: [PATCH 055/188] docs/README_el (#1929) Signed-off-by: longyuqing112 <2631918708@qq.com> --- docs/readme/README_el.md | 186 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 186 insertions(+) create mode 100644 docs/readme/README_el.md diff --git a/docs/readme/README_el.md b/docs/readme/README_el.md new file mode 100644 index 0000000000..252521f351 --- /dev/null +++ b/docs/readme/README_el.md @@ -0,0 +1,186 @@ +

+ + + +

+ +
+ +[![Stars](https://img.shields.io/github/stars/openimsdk/open-im-server?style=for-the-badge&logo=github&colorB=ff69b4)](https://github.com/openimsdk/open-im-server/stargazers) +[![Forks](https://img.shields.io/github/forks/openimsdk/open-im-server?style=for-the-badge&logo=github&colorB=blue)](https://github.com/openimsdk/open-im-server/network/members) +[![Codecov](https://img.shields.io/codecov/c/github/openimsdk/open-im-server?style=for-the-badge&logo=codecov&colorB=orange)](https://app.codecov.io/gh/openimsdk/open-im-server) +[![Go Report Card](https://goreportcard.com/badge/github.com/openimsdk/open-im-server?style=for-the-badge)](https://goreportcard.com/report/github.com/openimsdk/open-im-server) +[![Go Reference](https://img.shields.io/badge/Go%20Reference-blue.svg?style=for-the-badge&logo=go&logoColor=white)](https://pkg.go.dev/github.com/openimsdk/open-im-server/v3) +[![License](https://img.shields.io/badge/license-Apache--2.0-green?style=for-the-badge)](https://github.com/openimsdk/open-im-server/blob/main/LICENSE) +[![Slack](https://img.shields.io/badge/Slack-500%2B-blueviolet?style=for-the-badge&logo=slack&logoColor=white)](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q) +[![Best Practices](https://img.shields.io/badge/Best%20Practices-purple?style=for-the-badge)](https://www.bestpractices.dev/projects/8045) +[![Good First Issues](https://img.shields.io/github/issues/openimsdk/open-im-server/good%20first%20issue?style=for-the-badge&logo=github)](https://github.com/openimsdk/open-im-server/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc+label%3A%22good+first+issue%22) +[![Language](https://img.shields.io/badge/Language-Go-blue.svg?style=for-the-badge&logo=go&logoColor=white)](https://golang.org/) + + +

+ Englist · + 中文 · + Українська · + Česky · + Magyar · + Español · + فارسی · + Français · + Deutsch · + Polski · + Indonesian · + Suomi · + മലയാളം · + 日本語 · + Nederlands · + Italiano · + Русский · + Português (Brasil) · + Esperanto · + 한국어 · + العربي · + Tiếng Việt · + Dansk · + Ελληνικά · + Türkçe +

+ + +
+ +

+ +## Ⓜ️ Σχετικά με το OpenIM + +Το OpenIM είναι μια πλατφόρμα υπηρεσιών σχεδιασμένη ειδικά για την ενσωμάτωση συνομιλίας, κλήσεων ήχου-βίντεο, ειδοποιήσεων και chatbots AI σε εφαρμογές. Παρέχει μια σειρά από ισχυρά API και Webhooks, επιτρέποντας στους προγραμματιστές να ενσωματώσουν εύκολα αυτές τις αλληλεπιδραστικές λειτουργίες στις εφαρμογές τους. Το OpenIM δεν είναι μια αυτόνομη εφαρμογή συνομιλίας, αλλά λειτουργεί ως πλατφόρμα υποστήριξης άλλων εφαρμογών για την επίτευξη πλούσιων λειτουργιών επικοινωνίας. Το παρακάτω διάγραμμα απεικονίζει την αλληλεπίδραση μεταξύ AppServer, AppClient, OpenIMServer και OpenIMSDK για να εξηγήσει αναλυτικά. + +![App-OpenIM Relationship](../../docs/images/oepnim-design.png) + +## 🚀 Σχετικά με το OpenIMSDK + +Το **OpenIMSDK** είναι ένα SDK για αμεση ανταλλαγή μηνυμάτων σχεδιασμένο για το **OpenIMServer**, δημιουργήθηκε ειδικά για ενσωμάτωση σε εφαρμογές πελατών. Οι κύριες δυνατότητες και μονάδες του είναι οι εξής: + ++ 🌟 Κύριες Δυνατότητες: + + - 📦 Τοπική αποθήκευση + - 🔔 Callbacks ακροατών + - 🛡️ Περιτύλιγμα API + - 🌐 Διαχείριση σύνδεσης + ++ 📚 Κύριες Μονάδες: + + 1. 🚀 Αρχικοποίηση και Σύνδεση + 2. 👤 Διαχείριση Χρηστών + 3. 👫 Διαχείριση Φίλων + 4. 🤖 Λειτουργίες Ομάδας + 5. 💬 Διαχείριση Συνομιλιών + +Είναι κατασκευασμένο χρησιμοποιώντας Golang και υποστηρίζει διασταυρούμενη πλατφόρμα ανάπτυξης, διασφαλίζοντας μια συνεπή εμπειρία πρόσβασης σε όλες τις πλατφόρμες. + +👉 **[Εξερευνήστε το GO SDK](https://github.com/openimsdk/openim-sdk-core)** + +## 🌐 Σχετικά με το OpenIMServer + ++ Το **OpenIMServer** έχει τις ακόλουθες χαρακτηριστικές: + - 🌐 Αρχιτεκτονική μικροϋπηρεσιών: Υποστηρίζει λειτουργία σε σύμπλεγμα, περιλαμβάνοντας έναν πύλη και πολλαπλές υπηρεσίες rpc. + - 🚀 Διάφοροι τρόποι ανάπτυξης: Υποστηρίζει ανάπτυξη μέσω πηγαίου κώδικα, Kubernetes, ή Docker. + - Υποστήριξη για τεράστια βάση χρηστών: Πολύ μεγάλες ομάδες με εκατοντάδες χιλιάδες χρήστες, δεκάδες εκατομμύρια χρήστες και δισεκατομμύρια μηνύματα. + +### Ενισχυμένη Επιχειρηματική Λειτουργικότητα: + ++ **REST API**: Το OpenIMServer προσφέρει REST APIs για επιχειρηματικά συστήματα, με στόχο την ενδυνάμωση των επιχειρήσεων με περισσότερες λειτουργικότητες, όπως η δημιουργία ομάδων και η αποστολή μηνυμάτων push μέσω backend διεπαφών. ++ **Webhooks**: Το OpenIMServer παρέχει δυνατότητες επανάκλησης για την επέκταση περισσότερων επιχειρηματικών μορφών. Μια επανάκληση σημαίνει ότι το OpenIMServer στέλνει ένα αίτημα στον επιχειρηματικό διακομιστή πριν ή μετά από ένα συγκεκριμένο γεγονός, όπως επανακλήσεις πριν ή μετά την αποστολή ενός μηνύματος. + +👉 **[Μάθετε περισσότερα](https://docs.openim.io/guides/introduction/product)** + +## :building_construction: Συνολική Αρχιτεκτονική + +Εξερευνήστε σε βάθος τη λειτουργικότητα του Open-IM-Server με το διάγραμμα αρχιτεκτονικής μας. + +![Overall Architecture](../../docs/images/architecture-layers.png) + + +## :rocket: Γρήγορη Εκκίνηση + +Υποστηρίζουμε πολλές πλατφόρμες. Εδώ είναι οι διευθύνσεις για γρήγορη εμπειρία στην πλευρά του διαδικτύου: + +👉 **[Διαδικτυακή επίδειξη του OpenIM](https://web-enterprise.rentsoft.cn/)** + +🤲 Για να διευκολύνουμε την εμπειρία του χρήστη, προσφέρουμε διάφορες λύσεις ανάπτυξης. Μπορείτε να επιλέξετε τη μέθοδο ανάπτυξης σας από την παρακάτω λίστα: + ++ **[Οδηγός Ανάπτυξης Κώδικα Πηγής](https://docs.openim.io/guides/gettingStarted/imSourceCodeDeployment)** ++ **[δηγός Ανάπτυξης μέσω Docker](https://docs.openim.io/guides/gettingStarted/dockerCompose)** ++ **[Οδηγός Ανάπτυξης Kubernetes](https://docs.openim.io/guides/gettingStarted/k8s-deployment)** ++ **[Οδηγός Ανάπτυξης για Αναπτυξιακούς στο Mac](https://docs.openim.io/guides/gettingstarted/mac-deployment-guide)** + +## :hammer_and_wrench: Για να Αρχίσετε την Ανάπτυξη του OpenIM + +[![Άνοιγμα σε Dev Container](https://img.shields.io/static/v1?label=Dev%20Container&message=Open&color=blue&logo=visualstudiocode)](https://vscode.dev/github/openimsdk/open-im-server) + +OpenIM Στόχος μας είναι να δημιουργήσουμε μια κορυφαίου επιπέδου ανοιχτή πηγή κοινότητας. Διαθέτουμε ένα σύνολο προτύπων, στο [Αποθετήριο Κοινότητας](https://github.com/OpenIMSDK/community). + +Εάν θέλετε να συνεισφέρετε σε αυτό το αποθετήριο Open-IM-Server, παρακαλούμε διαβάστε την [τεκμηρίωση συνεισφέροντος](https://github.com/openimsdk/open-im-server/blob/main/CONTRIBUTING.md). + +Πριν ξεκινήσετε, παρακαλούμε βεβαιωθείτε ότι οι αλλαγές σας είναι ζητούμενες. Το καλύτερο για αυτό είναι να δημιουργήσετε ένα [νέα συζήτηση](https://github.com/openimsdk/open-im-server/discussions/new/choose) ή [Επικοινωνία Slack](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q), ή αν βρείτε ένα ζήτημα, [αναφέρετέ το](https://github.com/openimsdk/open-im-server/issues/new/choose) πρώτα. + +- [Αναφορά API του OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/api.md) +- [Καταγραφή Bash του OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/bash-log.md) +- [Ενέργειες CI/CD του OpenIMs](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/cicd-actions.md) +- [Συμβάσεις Κώδικα του OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/code-conventions.md) +- [Οδηγίες Commit του OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/commit.md) +- [Οδηγός Ανάπτυξης του OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/development.md) +- [Δομή Καταλόγου του OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/directory.md) +- [Ρύθμιση Περιβάλλοντος του OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/environment.md) +- [Αναφορά Κωδικών Σφάλματος του OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/error-code.md) +- [Ροή Εργασίας Git του OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/git-workflow.md) +- [Οδηγός Cherry Pick του Git του OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/gitcherry-pick.md) +- [Ροή Εργασίας GitHub του OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/github-workflow.md) +- [Πρότυπα Κώδικα Go του OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/go-code.md) +- [Οδηγίες Εικόνας του OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/images.md) +- [Αρχική Διαμόρφωση του OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/init-config.md) +- [Οδηγός Εγκατάστασης Docker του OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/install-docker.md) +- [Οδηγός Εγκατάστασης Συστήματος Linux του Open](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/install-openim-linux-system.md) +- [Οδηγός Ανάπτυξης Linux του OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/linux-development.md) +- [Οδηγός Τοπικών Δράσεων του OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/local-actions.md) +- [Συμβάσεις Καταγραφής του OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/logging.md) +- [Αποστολή Εκτός Σύνδεσης του OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/offline-deployment.md) +- [Εργαλεία Protoc του OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/protoc-tools.md) +- [Οδηγός Δοκιμών του OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/test.md) +- [Χρησιμότητα Go του OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/util-go.md) +- [Χρησιμότητες Makefile του OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/util-makefile.md) +- [Χρησιμότητες Σεναρίου του OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/util-scripts.md) +- [Έκδοση του OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/version.md) +- [Διαχείριση backend και παρακολούθηση ανάπτυξης](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/prometheus-grafana.md) +- [Οδηγός Ανάπτυξης για Προγραμματιστές Mac του OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/mac-developer-deployment-guide.md) + + +## :busts_in_silhouette: Κοινότητα + ++ 📚 [Κοινότητα OpenIM](https://github.com/OpenIMSDK/community) ++ 💕 [Ομάδα Ενδιαφέροντος OpenIM](https://github.com/Openim-sigs) ++ 🚀 [Εγγραφείτε στην κοινότητα Slack μας](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q) ++ :eyes: [γγραφείτε στην ομάδα μας wechat (微信群)](https://openim-1253691595.cos.ap-nanjing.myqcloud.com/WechatIMG20.jpeg) + +## :calendar: Συναντήσεις της κοινότητας + +Θέλουμε οποιονδήποτε να εμπλακεί στην κοινότητά μας και να συνεισφέρει κώδικα. Προσφέρουμε δώρα και ανταμοιβές και σας καλωσορίζουμε να μας ενταχθείτε κάθε Πέμπτη βράδυ. + +Η διάσκεψή μας είναι στο [OpenIM Slack](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q) 🎯, στη συνέχεια μπορείτε να αναζητήσετε τη διαδικασία Open-IM-Server για να συμμετάσχετε + +Κάνουμε σημειώσεις για κάθε μια [Σημειώνουμε κάθε διμηνιαία συνάντηση](https://github.com/orgs/OpenIMSDK/discussions/categories/meeting) στις [συζητήσεις του GitHub](https://github.com/openimsdk/open-im-server/discussions/categories/meeting), Οι ιστορικές μας σημειώσεις συναντήσεων, καθώς και οι επαναλήψεις των συναντήσεων είναι διαθέσιμες στο[Έγγραφα της Google :bookmark_tabs:](https://docs.google.com/document/d/1nx8MDpuG74NASx081JcCpxPgDITNTpIIos0DS6Vr9GU/edit?usp=sharing). + +## :eyes: Ποιοί Χρησιμοποιούν το OpenIM + +Ελέγξτε τη σελίδα με τις [μελέτες περίπτωσης χρήσης ](https://github.com/OpenIMSDK/community/blob/main/ADOPTERS.md) μας για μια λίστα των χρηστών του έργου. Μην διστάσετε να αφήσετε ένα[📝σχόλιο](https://github.com/openimsdk/open-im-server/issues/379) και να μοιραστείτε την περίπτωση χρήσης σας. +## :page_facing_up: Άδεια Χρήσης + +Το OpenIM διατίθεται υπό την άδεια Apache 2.0. Δείτε τη [ΑΔΕΙΑ ΧΡΗΣΗΣ](https://github.com/openimsdk/open-im-server/tree/main/LICENSE) για το πλήρες κείμενο της άδειας. + +Το λογότυπο του OpenIM, συμπεριλαμβανομένων των παραλλαγών και των κινούμενων εικόνων, που εμφανίζονται σε αυτό το αποθετήριο[OpenIM](https://github.com/openimsdk/open-im-server) υπό τις διευθύνσεις [assets/logo](../../assets/logo) και [assets/logo-gif](../../assets/logo-gif) προστατεύονται από τους νόμους περί πνευματικής ιδιοκτησίας. + +## 🔮 Ευχαριστούμε τους συνεισφέροντες μας! + + + + From d5d2803e76b44c4316417aad3fb78e99272e4bf5 Mon Sep 17 00:00:00 2001 From: chao <48119764+withchao@users.noreply.github.com> Date: Tue, 20 Feb 2024 20:56:29 +0800 Subject: [PATCH 056/188] feat: optimize server code (#1931) * fix: GroupApplicationAcceptedNotification * fix: GroupApplicationAcceptedNotification * fix: NotificationUserInfoUpdate * cicd: robot automated Change * utils.Wrap -> errs.Wrap * utils.Wrap -> errs.Wrap --------- Co-authored-by: withchao --- go.mod | 2 +- go.sum | 4 +- internal/msggateway/client.go | 15 ++--- internal/msggateway/compressor.go | 21 ++++--- internal/msggateway/encoder.go | 5 +- internal/push/offlinepush/getui/push.go | 4 +- internal/rpc/auth/auth.go | 6 +- internal/rpc/group/group.go | 2 +- pkg/common/db/cache/meta_cache.go | 4 +- pkg/common/db/cache/msg.go | 77 +++++++++++++++---------- pkg/common/db/controller/auth.go | 5 +- pkg/common/db/controller/msg.go | 2 +- pkg/common/db/unrelation/msg.go | 18 +++--- pkg/common/db/unrelation/user.go | 3 +- pkg/common/http/http_client.go | 20 +++---- pkg/common/kafka/producer.go | 11 ++-- 16 files changed, 101 insertions(+), 98 deletions(-) diff --git a/go.mod b/go.mod index be835c0a41..ac02683b42 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.19 require ( firebase.google.com/go v3.13.0+incompatible github.com/OpenIMSDK/protocol v0.0.55 - github.com/OpenIMSDK/tools v0.0.35 + github.com/OpenIMSDK/tools v0.0.36 github.com/bwmarrin/snowflake v0.3.0 // indirect github.com/dtm-labs/rockscache v0.1.1 github.com/gin-gonic/gin v1.9.1 diff --git a/go.sum b/go.sum index c4b661f1c2..38596d45e3 100644 --- a/go.sum +++ b/go.sum @@ -20,8 +20,8 @@ github.com/IBM/sarama v1.42.2 h1:VoY4hVIZ+WQJ8G9KNY/SQlWguBQXQ9uvFPOnrcu8hEw= github.com/IBM/sarama v1.42.2/go.mod h1:FLPGUGwYqEs62hq2bVG6Io2+5n+pS6s/WOXVKWSLFtE= github.com/OpenIMSDK/protocol v0.0.55 h1:eBjg8DyuhxGmuCUjpoZjg6MJJJXU/xJ3xJwFhrn34yA= github.com/OpenIMSDK/protocol v0.0.55/go.mod h1:F25dFrwrIx3lkNoiuf6FkCfxuwf8L4Z8UIsdTHP/r0Y= -github.com/OpenIMSDK/tools v0.0.35 h1:YH8UYoaErXqfNrwpUvQxe8nhL++gFH6qCisQPyzk0w8= -github.com/OpenIMSDK/tools v0.0.35/go.mod h1:wBfR5CYmEyvxl03QJbTkhz1CluK6J4/lX0lviu8JAjE= +github.com/OpenIMSDK/tools v0.0.36 h1:BT0q64l4f3QJDW16Rc0uJYt1gQFkiPoUQYQ33vo0EcE= +github.com/OpenIMSDK/tools v0.0.36/go.mod h1:wBfR5CYmEyvxl03QJbTkhz1CluK6J4/lX0lviu8JAjE= github.com/QcloudApi/qcloud_sign_golang v0.0.0-20141224014652-e4130a326409/go.mod h1:1pk82RBxDY/JZnPQrtqHlUFfCctgdorsd9M06fMynOM= github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7 h1:uSoVVbwJiQipAclBbw+8quDsfcvFjOpI5iCf4p/cqCs= github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs= diff --git a/internal/msggateway/client.go b/internal/msggateway/client.go index 43047fd735..dfd2b03d3e 100644 --- a/internal/msggateway/client.go +++ b/internal/msggateway/client.go @@ -18,6 +18,7 @@ import ( "context" "errors" "fmt" + "github.com/OpenIMSDK/tools/errs" "runtime/debug" "sync" "sync/atomic" @@ -173,7 +174,7 @@ func (c *Client) handleMessage(message []byte) error { var err error message, err = c.longConnServer.DecompressWithPool(message) if err != nil { - return utils.Wrap(err, "") + return errs.Wrap(err) } } @@ -182,15 +183,15 @@ func (c *Client) handleMessage(message []byte) error { err := c.longConnServer.Decode(message, binaryReq) if err != nil { - return utils.Wrap(err, "") + return errs.Wrap(err) } if err := c.longConnServer.Validate(binaryReq); err != nil { - return utils.Wrap(err, "") + return errs.Wrap(err) } if binaryReq.SendID != c.UserID { - return utils.Wrap(errors.New("exception conn userID not same to req userID"), binaryReq.String()) + return errs.Wrap(errors.New("exception conn userID not same to req userID"), binaryReq.String()) } ctx := mcontext.WithMustInfoCtx( @@ -313,7 +314,7 @@ func (c *Client) writeBinaryMsg(resp Resp) error { encodedBuf, err := c.longConnServer.Encode(resp) if err != nil { - return utils.Wrap(err, "") + return errs.Wrap(err) } c.w.Lock() @@ -323,7 +324,7 @@ func (c *Client) writeBinaryMsg(resp Resp) error { if c.IsCompress { resultBuf, compressErr := c.longConnServer.CompressWithPool(encodedBuf) if compressErr != nil { - return utils.Wrap(compressErr, "") + return errs.Wrap(compressErr) } return c.conn.WriteMessage(MessageBinary, resultBuf) } @@ -341,7 +342,7 @@ func (c *Client) writePongMsg() error { err := c.conn.SetWriteDeadline(writeWait) if err != nil { - return utils.Wrap(err, "") + return errs.Wrap(err) } return c.conn.WriteMessage(PongMessage, nil) diff --git a/internal/msggateway/compressor.go b/internal/msggateway/compressor.go index ae5e9cdd04..9bbec1ec9e 100644 --- a/internal/msggateway/compressor.go +++ b/internal/msggateway/compressor.go @@ -18,10 +18,9 @@ import ( "bytes" "compress/gzip" "errors" + "github.com/OpenIMSDK/tools/errs" "io" "sync" - - "github.com/OpenIMSDK/tools/utils" ) var ( @@ -47,10 +46,10 @@ func (g *GzipCompressor) Compress(rawData []byte) ([]byte, error) { gzipBuffer := bytes.Buffer{} gz := gzip.NewWriter(&gzipBuffer) if _, err := gz.Write(rawData); err != nil { - return nil, utils.Wrap(err, "") + return nil, errs.Wrap(err) } if err := gz.Close(); err != nil { - return nil, utils.Wrap(err, "") + return nil, errs.Wrap(err) } return gzipBuffer.Bytes(), nil } @@ -63,10 +62,10 @@ func (g *GzipCompressor) CompressWithPool(rawData []byte) ([]byte, error) { gz.Reset(&gzipBuffer) if _, err := gz.Write(rawData); err != nil { - return nil, utils.Wrap(err, "") + return nil, errs.Wrap(err) } if err := gz.Close(); err != nil { - return nil, utils.Wrap(err, "") + return nil, errs.Wrap(err) } return gzipBuffer.Bytes(), nil } @@ -75,11 +74,11 @@ func (g *GzipCompressor) DeCompress(compressedData []byte) ([]byte, error) { buff := bytes.NewBuffer(compressedData) reader, err := gzip.NewReader(buff) if err != nil { - return nil, utils.Wrap(err, "NewReader failed") + return nil, errs.Wrap(err, "NewReader failed") } compressedData, err = io.ReadAll(reader) if err != nil { - return nil, utils.Wrap(err, "ReadAll failed") + return nil, errs.Wrap(err, "ReadAll failed") } _ = reader.Close() return compressedData, nil @@ -88,18 +87,18 @@ func (g *GzipCompressor) DeCompress(compressedData []byte) ([]byte, error) { func (g *GzipCompressor) DecompressWithPool(compressedData []byte) ([]byte, error) { reader := gzipReaderPool.Get().(*gzip.Reader) if reader == nil { - return nil, errors.New("NewReader failed") + return nil, errs.Wrap(errors.New("NewReader failed")) } defer gzipReaderPool.Put(reader) err := reader.Reset(bytes.NewReader(compressedData)) if err != nil { - return nil, utils.Wrap(err, "NewReader failed") + return nil, errs.Wrap(err, "NewReader failed") } compressedData, err = io.ReadAll(reader) if err != nil { - return nil, utils.Wrap(err, "ReadAll failed") + return nil, errs.Wrap(err, "ReadAll failed") } _ = reader.Close() return compressedData, nil diff --git a/internal/msggateway/encoder.go b/internal/msggateway/encoder.go index c5f1d00a82..2c46a774bf 100644 --- a/internal/msggateway/encoder.go +++ b/internal/msggateway/encoder.go @@ -17,8 +17,7 @@ package msggateway import ( "bytes" "encoding/gob" - - "github.com/OpenIMSDK/tools/utils" + "github.com/OpenIMSDK/tools/errs" ) type Encoder interface { @@ -47,7 +46,7 @@ func (g *GobEncoder) Decode(encodeData []byte, decodeData any) error { dec := gob.NewDecoder(buff) err := dec.Decode(decodeData) if err != nil { - return utils.Wrap(err, "") + return errs.Wrap(err) } return nil } diff --git a/internal/push/offlinepush/getui/push.go b/internal/push/offlinepush/getui/push.go index b657c9c23c..8115e4efb9 100644 --- a/internal/push/offlinepush/getui/push.go +++ b/internal/push/offlinepush/getui/push.go @@ -34,8 +34,6 @@ import ( "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" http2 "github.com/openimsdk/open-im-server/v3/pkg/common/http" - - "github.com/OpenIMSDK/tools/utils" ) var ( @@ -137,7 +135,7 @@ func (g *Client) GetTaskID(ctx context.Context, token string, pushReq PushReq) ( pushReq.Settings = &Settings{TTL: &ttl} err := g.request(ctx, taskURL, pushReq, token, &respTask) if err != nil { - return "", utils.Wrap(err, "") + return "", errs.Wrap(err) } return respTask.TaskID, nil } diff --git a/internal/rpc/auth/auth.go b/internal/rpc/auth/auth.go index eaf63f868d..1b10ba06a7 100644 --- a/internal/rpc/auth/auth.go +++ b/internal/rpc/auth/auth.go @@ -29,8 +29,6 @@ import ( "github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/mcontext" "github.com/OpenIMSDK/tools/tokenverify" - "github.com/OpenIMSDK/tools/utils" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" @@ -105,7 +103,7 @@ func (s *authServer) GetUserToken(ctx context.Context, req *pbauth.GetUserTokenR func (s *authServer) parseToken(ctx context.Context, tokensString string) (claims *tokenverify.Claims, err error) { claims, err = tokenverify.GetClaimFromToken(tokensString, authverify.Secret()) if err != nil { - return nil, utils.Wrap(err, "") + return nil, errs.Wrap(err) } m, err := s.authDatabase.GetTokensWithoutError(ctx, claims.UserID, claims.PlatformID) if err != nil { @@ -121,7 +119,7 @@ func (s *authServer) parseToken(ctx context.Context, tokensString string) (claim case constant.KickedToken: return nil, errs.ErrTokenKicked.Wrap() default: - return nil, utils.Wrap(errs.ErrTokenUnknown, "") + return nil, errs.Wrap(errs.ErrTokenUnknown) } } return nil, errs.ErrTokenNotExist.Wrap() diff --git a/internal/rpc/group/group.go b/internal/rpc/group/group.go index 1d068b1b2c..95f82266f9 100644 --- a/internal/rpc/group/group.go +++ b/internal/rpc/group/group.go @@ -956,7 +956,7 @@ func (s *groupServer) SetGroupInfo(ctx context.Context, req *pbgroup.SetGroupInf return nil, err } if group.Status == constant.GroupStatusDismissed { - return nil, utils.Wrap(errs.ErrDismissedAlready, "") + return nil, errs.Wrap(errs.ErrDismissedAlready) } resp := &pbgroup.SetGroupInfoResp{} count, err := s.db.FindGroupMemberNum(ctx, group.GroupID) diff --git a/pkg/common/db/cache/meta_cache.go b/pkg/common/db/cache/meta_cache.go index 4bc2a046aa..7eb486c9ab 100644 --- a/pkg/common/db/cache/meta_cache.go +++ b/pkg/common/db/cache/meta_cache.go @@ -134,7 +134,7 @@ func getCache[T any](ctx context.Context, rcClient *rockscache.Client, key strin } bs, err := json.Marshal(t) if err != nil { - return "", utils.Wrap(err, "") + return "", errs.Wrap(err) } write = true @@ -153,7 +153,7 @@ func getCache[T any](ctx context.Context, rcClient *rockscache.Client, key strin if err != nil { log.ZError(ctx, "cache json.Unmarshal failed", err, "key", key, "value", v, "expire", expire) - return t, utils.Wrap(err, "") + return t, errs.Wrap(err) } return t, nil diff --git a/pkg/common/db/cache/msg.go b/pkg/common/db/cache/msg.go index 5cd3cb22c5..8a54e1a8b2 100644 --- a/pkg/common/db/cache/msg.go +++ b/pkg/common/db/cache/msg.go @@ -149,11 +149,15 @@ func (c *msgCache) getHasReadSeqKey(conversationID string, userID string) string } func (c *msgCache) setSeq(ctx context.Context, conversationID string, seq int64, getkey func(conversationID string) string) error { - return utils.Wrap1(c.rdb.Set(ctx, getkey(conversationID), seq, 0).Err()) + return errs.Wrap(c.rdb.Set(ctx, getkey(conversationID), seq, 0).Err()) } func (c *msgCache) getSeq(ctx context.Context, conversationID string, getkey func(conversationID string) string) (int64, error) { - return utils.Wrap2(c.rdb.Get(ctx, getkey(conversationID)).Int64()) + val, err := c.rdb.Get(ctx, getkey(conversationID)).Int64() + if err != nil { + return 0, errs.Wrap(err) + } + return val, nil } func (c *msgCache) getSeqs(ctx context.Context, items []string, getkey func(s string) string) (m map[string]int64, err error) { @@ -214,7 +218,11 @@ func (c *msgCache) getConversationUserMinSeqKey(conversationID, userID string) s } func (c *msgCache) GetConversationUserMinSeq(ctx context.Context, conversationID string, userID string) (int64, error) { - return utils.Wrap2(c.rdb.Get(ctx, c.getConversationUserMinSeqKey(conversationID, userID)).Int64()) + val, err := c.rdb.Get(ctx, c.getConversationUserMinSeqKey(conversationID, userID)).Int64() + if err != nil { + return 0, errs.Wrap(err) + } + return val, nil } func (c *msgCache) GetConversationUserMinSeqs(ctx context.Context, conversationID string, userIDs []string) (m map[string]int64, err error) { @@ -224,7 +232,7 @@ func (c *msgCache) GetConversationUserMinSeqs(ctx context.Context, conversationI } func (c *msgCache) SetConversationUserMinSeq(ctx context.Context, conversationID string, userID string, minSeq int64) error { - return utils.Wrap1(c.rdb.Set(ctx, c.getConversationUserMinSeqKey(conversationID, userID), minSeq, 0).Err()) + return errs.Wrap(c.rdb.Set(ctx, c.getConversationUserMinSeqKey(conversationID, userID), minSeq, 0).Err()) } func (c *msgCache) SetConversationUserMinSeqs(ctx context.Context, conversationID string, seqs map[string]int64) (err error) { @@ -240,7 +248,7 @@ func (c *msgCache) SetUserConversationsMinSeqs(ctx context.Context, userID strin } func (c *msgCache) SetHasReadSeq(ctx context.Context, userID string, conversationID string, hasReadSeq int64) error { - return utils.Wrap1(c.rdb.Set(ctx, c.getHasReadSeqKey(conversationID, userID), hasReadSeq, 0).Err()) + return errs.Wrap(c.rdb.Set(ctx, c.getHasReadSeqKey(conversationID, userID), hasReadSeq, 0).Err()) } func (c *msgCache) SetHasReadSeqs(ctx context.Context, conversationID string, hasReadSeqs map[string]int64) error { @@ -262,12 +270,15 @@ func (c *msgCache) GetHasReadSeqs(ctx context.Context, userID string, conversati } func (c *msgCache) GetHasReadSeq(ctx context.Context, userID string, conversationID string) (int64, error) { - return utils.Wrap2(c.rdb.Get(ctx, c.getHasReadSeqKey(conversationID, userID)).Int64()) + val, err := c.rdb.Get(ctx, c.getHasReadSeqKey(conversationID, userID)).Int64() + if err != nil { + return 0, err + } + return val, nil } func (c *msgCache) AddTokenFlag(ctx context.Context, userID string, platformID int, token string, flag int) error { key := uidPidToken + userID + ":" + constant.PlatformIDToName(platformID) - return errs.Wrap(c.rdb.HSet(ctx, key, token, flag).Err()) } @@ -694,7 +705,11 @@ func (c *msgCache) SetGetuiToken(ctx context.Context, token string, expireTime i } func (c *msgCache) GetGetuiToken(ctx context.Context) (string, error) { - return utils.Wrap2(c.rdb.Get(ctx, getuiToken).Result()) + val, err := c.rdb.Get(ctx, getuiToken).Result() + if err != nil { + return "", errs.Wrap(err) + } + return val, nil } func (c *msgCache) SetGetuiTaskID(ctx context.Context, taskID string, expireTime int64) error { @@ -702,7 +717,11 @@ func (c *msgCache) SetGetuiTaskID(ctx context.Context, taskID string, expireTime } func (c *msgCache) GetGetuiTaskID(ctx context.Context) (string, error) { - return utils.Wrap2(c.rdb.Get(ctx, getuiTaskID).Result()) + val, err := c.rdb.Get(ctx, getuiTaskID).Result() + if err != nil { + return "", errs.Wrap(err) + } + return val, nil } func (c *msgCache) SetSendMsgStatus(ctx context.Context, id string, status int32) error { @@ -720,7 +739,11 @@ func (c *msgCache) SetFcmToken(ctx context.Context, account string, platformID i } func (c *msgCache) GetFcmToken(ctx context.Context, account string, platformID int) (string, error) { - return utils.Wrap2(c.rdb.Get(ctx, FCM_TOKEN+account+":"+strconv.Itoa(platformID)).Result()) + val, err := c.rdb.Get(ctx, FCM_TOKEN+account+":"+strconv.Itoa(platformID)).Result() + if err != nil { + return "", errs.Wrap(err) + } + return val, nil } func (c *msgCache) DelFcmToken(ctx context.Context, account string, platformID int) error { @@ -738,7 +761,8 @@ func (c *msgCache) SetUserBadgeUnreadCountSum(ctx context.Context, userID string } func (c *msgCache) GetUserBadgeUnreadCountSum(ctx context.Context, userID string) (int, error) { - return utils.Wrap2(c.rdb.Get(ctx, userBadgeUnreadCountSum+userID).Int()) + val, err := c.rdb.Get(ctx, userBadgeUnreadCountSum+userID).Int() + return val, errs.Wrap(err) } func (c *msgCache) LockMessageTypeKey(ctx context.Context, clientMsgID string, TypeKey string) error { @@ -771,42 +795,31 @@ func (c *msgCache) getMessageReactionExPrefix(clientMsgID string, sessionType in func (c *msgCache) JudgeMessageReactionExist(ctx context.Context, clientMsgID string, sessionType int32) (bool, error) { n, err := c.rdb.Exists(ctx, c.getMessageReactionExPrefix(clientMsgID, sessionType)).Result() if err != nil { - return false, utils.Wrap(err, "") + return false, errs.Wrap(err) } return n > 0, nil } -func (c *msgCache) SetMessageTypeKeyValue( - ctx context.Context, - clientMsgID string, - sessionType int32, - typeKey, value string, -) error { +func (c *msgCache) SetMessageTypeKeyValue(ctx context.Context, clientMsgID string, sessionType int32, typeKey, value string) error { return errs.Wrap(c.rdb.HSet(ctx, c.getMessageReactionExPrefix(clientMsgID, sessionType), typeKey, value).Err()) } func (c *msgCache) SetMessageReactionExpire(ctx context.Context, clientMsgID string, sessionType int32, expiration time.Duration) (bool, error) { - return utils.Wrap2(c.rdb.Expire(ctx, c.getMessageReactionExPrefix(clientMsgID, sessionType), expiration).Result()) + val, err := c.rdb.Expire(ctx, c.getMessageReactionExPrefix(clientMsgID, sessionType), expiration).Result() + return val, errs.Wrap(err) } func (c *msgCache) GetMessageTypeKeyValue(ctx context.Context, clientMsgID string, sessionType int32, typeKey string) (string, error) { - return utils.Wrap2(c.rdb.HGet(ctx, c.getMessageReactionExPrefix(clientMsgID, sessionType), typeKey).Result()) + val, err := c.rdb.HGet(ctx, c.getMessageReactionExPrefix(clientMsgID, sessionType), typeKey).Result() + return val, errs.Wrap(err) } -func (c *msgCache) GetOneMessageAllReactionList( - ctx context.Context, - clientMsgID string, - sessionType int32, -) (map[string]string, error) { - return utils.Wrap2(c.rdb.HGetAll(ctx, c.getMessageReactionExPrefix(clientMsgID, sessionType)).Result()) +func (c *msgCache) GetOneMessageAllReactionList(ctx context.Context, clientMsgID string, sessionType int32) (map[string]string, error) { + val, err := c.rdb.HGetAll(ctx, c.getMessageReactionExPrefix(clientMsgID, sessionType)).Result() + return val, errs.Wrap(err) } -func (c *msgCache) DeleteOneMessageKey( - ctx context.Context, - clientMsgID string, - sessionType int32, - subKey string, -) error { +func (c *msgCache) DeleteOneMessageKey(ctx context.Context, clientMsgID string, sessionType int32, subKey string) error { return errs.Wrap(c.rdb.HDel(ctx, c.getMessageReactionExPrefix(clientMsgID, sessionType), subKey).Err()) } diff --git a/pkg/common/db/controller/auth.go b/pkg/common/db/controller/auth.go index 17b4a440d4..fe15198678 100644 --- a/pkg/common/db/controller/auth.go +++ b/pkg/common/db/controller/auth.go @@ -16,6 +16,7 @@ package controller import ( "context" + "github.com/OpenIMSDK/tools/errs" "github.com/openimsdk/open-im-server/v3/pkg/authverify" @@ -23,8 +24,6 @@ import ( "github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/tools/tokenverify" - "github.com/OpenIMSDK/tools/utils" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" ) @@ -78,7 +77,7 @@ func (a *authDatabase) CreateToken(ctx context.Context, userID string, platformI token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) tokenString, err := token.SignedString([]byte(a.accessSecret)) if err != nil { - return "", utils.Wrap(err, "") + return "", errs.Wrap(err) } return tokenString, a.cache.AddTokenFlag(ctx, userID, platformID, tokenString, constant.NormalToken) } diff --git a/pkg/common/db/controller/msg.go b/pkg/common/db/controller/msg.go index b841a7d310..d427cc3a16 100644 --- a/pkg/common/db/controller/msg.go +++ b/pkg/common/db/controller/msg.go @@ -408,7 +408,7 @@ func (db *commonMsgDatabase) BatchInsertChat2Cache(ctx context.Context, conversa log.ZError(ctx, "SetHasReadSeqs error", err2, "userSeqMap", userSeqMap, "conversationID", conversationID) prommetrics.SeqSetFailedCounter.Inc() } - return lastMaxSeq, isNew, utils.Wrap(err, "") + return lastMaxSeq, isNew, errs.Wrap(err) } func (db *commonMsgDatabase) getMsgBySeqs(ctx context.Context, userID, conversationID string, seqs []int64) (totalMsgs []*sdkws.MsgData, err error) { diff --git a/pkg/common/db/unrelation/msg.go b/pkg/common/db/unrelation/msg.go index 9b461dd1f0..0aa9fa58d0 100644 --- a/pkg/common/db/unrelation/msg.go +++ b/pkg/common/db/unrelation/msg.go @@ -35,8 +35,6 @@ import ( "github.com/OpenIMSDK/protocol/sdkws" "github.com/OpenIMSDK/tools/errs" - "github.com/OpenIMSDK/tools/utils" - table "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/unrelation" ) @@ -79,7 +77,7 @@ func (m *MsgMongoDriver) UpdateMsg( update := bson.M{"$set": bson.M{field: value}} res, err := m.MsgCollection.UpdateOne(ctx, filter, update) if err != nil { - return nil, utils.Wrap(err, "") + return nil, errs.Wrap(err) } return res, nil } @@ -106,7 +104,7 @@ func (m *MsgMongoDriver) PushUnique( } res, err := m.MsgCollection.UpdateOne(ctx, filter, update) if err != nil { - return nil, utils.Wrap(err, "") + return nil, errs.Wrap(err) } return res, nil } @@ -118,7 +116,7 @@ func (m *MsgMongoDriver) UpdateMsgContent(ctx context.Context, docID string, ind bson.M{"$set": bson.M{fmt.Sprintf("msgs.%d.msg", index): msg}}, ) if err != nil { - return utils.Wrap(err, "") + return errs.Wrap(err) } return nil } @@ -133,7 +131,7 @@ func (m *MsgMongoDriver) UpdateMsgStatusByIndexInOneDoc( msg.Status = status bytes, err := proto.Marshal(msg) if err != nil { - return utils.Wrap(err, "") + return errs.Wrap(err) } _, err = m.MsgCollection.UpdateOne( ctx, @@ -141,7 +139,7 @@ func (m *MsgMongoDriver) UpdateMsgStatusByIndexInOneDoc( bson.M{"$set": bson.M{fmt.Sprintf("msgs.%d.msg", seqIndex): bytes}}, ) if err != nil { - return utils.Wrap(err, "") + return errs.Wrap(err) } return nil } @@ -167,12 +165,12 @@ func (m *MsgMongoDriver) GetMsgDocModelByIndex( findOpts, ) if err != nil { - return nil, utils.Wrap(err, "") + return nil, errs.Wrap(err) } var msgs []table.MsgDocModel err = cursor.All(ctx, &msgs) if err != nil { - return nil, utils.Wrap(err, fmt.Sprintf("cursor is %s", cursor.Current.String())) + return nil, errs.Wrap(err, fmt.Sprintf("cursor is %s", cursor.Current.String())) } if len(msgs) > 0 { return &msgs[0], nil @@ -223,7 +221,7 @@ func (m *MsgMongoDriver) DeleteMsgsInOneDocByIndex(ctx context.Context, docID st } _, err := m.MsgCollection.UpdateMany(ctx, bson.M{"doc_id": docID}, updates) if err != nil { - return utils.Wrap(err, "") + return errs.Wrap(err) } return nil } diff --git a/pkg/common/db/unrelation/user.go b/pkg/common/db/unrelation/user.go index 4b4a78c795..f5595c4ebb 100644 --- a/pkg/common/db/unrelation/user.go +++ b/pkg/common/db/unrelation/user.go @@ -18,7 +18,6 @@ import ( "context" "github.com/OpenIMSDK/tools/errs" - "github.com/OpenIMSDK/tools/utils" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo/options" @@ -119,7 +118,7 @@ func (u *UserMongoDriver) AddSubscriptionList(ctx context.Context, userID string opts, ) if err != nil { - return utils.Wrap(err, "transaction failed") + return errs.Wrap(err, "transaction failed") } } return nil diff --git a/pkg/common/http/http_client.go b/pkg/common/http/http_client.go index a80d1c9a41..7fc456a1d0 100644 --- a/pkg/common/http/http_client.go +++ b/pkg/common/http/http_client.go @@ -106,31 +106,31 @@ func PostReturn(ctx context.Context, url string, header map[string]string, input } func callBackPostReturn(ctx context.Context, url, command string, input interface{}, output callbackstruct.CallbackResp, callbackConfig config.CallBackConfig) error { - defer log.ZDebug(ctx, "callback", "url", url, "command", command, "input", input, "output", output, "callbackConfig", callbackConfig) - // - //v := urllib.Values{} - //v.Set(constant.CallbackCommand, command) - //url = url + "/" + v.Encode() url = url + "/" + command + log.ZInfo(ctx, "callback", "url", url, "input", input, "config", callbackConfig) b, err := Post(ctx, url, nil, input, callbackConfig.CallbackTimeOut) if err != nil { if callbackConfig.CallbackFailedContinue != nil && *callbackConfig.CallbackFailedContinue { - log.ZWarn(ctx, "callback failed but continue", err, "url", url) + log.ZInfo(ctx, "callback failed but continue", err, "url", url) return nil } + log.ZWarn(ctx, "callback network failed", err, "url", url, "input", input) return errs.ErrNetwork.Wrap(err.Error()) } - defer log.ZDebug(ctx, "callback", "data", string(b)) - if err = json.Unmarshal(b, output); err != nil { if callbackConfig.CallbackFailedContinue != nil && *callbackConfig.CallbackFailedContinue { log.ZWarn(ctx, "callback failed but continue", err, "url", url) return nil } + log.ZWarn(ctx, "callback json unmarshal failed", err, "url", url, "input", input, "response", string(b)) return errs.ErrData.WithDetail(err.Error() + "response format error") } - - return output.Parse() + if err := output.Parse(); err != nil { + log.ZWarn(ctx, "callback parse failed", err, "url", url, "input", input, "response", string(b)) + return err + } + log.ZInfo(ctx, "callback success", "url", url, "input", input, "response", string(b)) + return nil } func CallBackPostReturn(ctx context.Context, url string, req callbackstruct.CallbackReq, resp callbackstruct.CallbackResp, callbackConfig config.CallBackConfig) error { diff --git a/pkg/common/kafka/producer.go b/pkg/common/kafka/producer.go index 417aadb542..c2e0f33dc2 100644 --- a/pkg/common/kafka/producer.go +++ b/pkg/common/kafka/producer.go @@ -27,7 +27,6 @@ import ( "github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/mcontext" - "github.com/OpenIMSDK/tools/utils" "google.golang.org/protobuf/proto" "github.com/openimsdk/open-im-server/v3/pkg/common/config" @@ -153,10 +152,10 @@ func (p *Producer) SendMessage(ctx context.Context, key string, msg proto.Messag // Marshal the protobuf message bMsg, err := proto.Marshal(msg) if err != nil { - return 0, 0, utils.Wrap(err, "kafka proto Marshal err") + return 0, 0, errs.Wrap(err, "kafka proto Marshal err") } if len(bMsg) == 0 { - return 0, 0, utils.Wrap(errEmptyMsg, "") + return 0, 0, errs.Wrap(errEmptyMsg, "") } // Prepare Kafka message @@ -168,13 +167,13 @@ func (p *Producer) SendMessage(ctx context.Context, key string, msg proto.Messag // Validate message key and value if kMsg.Key.Length() == 0 || kMsg.Value.Length() == 0 { - return 0, 0, utils.Wrap(errEmptyMsg, "") + return 0, 0, errs.Wrap(errEmptyMsg) } // Attach context metadata as headers header, err := GetMQHeaderWithContext(ctx) if err != nil { - return 0, 0, utils.Wrap(err, "") + return 0, 0, errs.Wrap(err) } kMsg.Headers = header @@ -182,7 +181,7 @@ func (p *Producer) SendMessage(ctx context.Context, key string, msg proto.Messag partition, offset, err := p.producer.SendMessage(kMsg) if err != nil { log.ZWarn(ctx, "p.producer.SendMessage error", err) - return 0, 0, utils.Wrap(err, "") + return 0, 0, errs.Wrap(err) } log.ZDebug(ctx, "ByteEncoder SendMessage end", "key", kMsg.Key, "key length", kMsg.Value.Length()) From 3c738c3b28af4f0380244b76048a8e9e24ba7f91 Mon Sep 17 00:00:00 2001 From: OpenIM Bot <124379614+kubbot@users.noreply.github.com> Date: Wed, 21 Feb 2024 11:30:48 +0800 Subject: [PATCH 057/188] cicd: bump League Patch (#1937) --- internal/msggateway/client.go | 3 ++- internal/msggateway/compressor.go | 3 ++- internal/msggateway/encoder.go | 1 + internal/rpc/auth/auth.go | 1 + pkg/common/db/controller/auth.go | 2 ++ pkg/common/db/unrelation/msg.go | 1 + 6 files changed, 9 insertions(+), 2 deletions(-) diff --git a/internal/msggateway/client.go b/internal/msggateway/client.go index dfd2b03d3e..d3b0e6a5f2 100644 --- a/internal/msggateway/client.go +++ b/internal/msggateway/client.go @@ -18,11 +18,12 @@ import ( "context" "errors" "fmt" - "github.com/OpenIMSDK/tools/errs" "runtime/debug" "sync" "sync/atomic" + "github.com/OpenIMSDK/tools/errs" + "github.com/openimsdk/open-im-server/v3/pkg/msgprocessor" "google.golang.org/protobuf/proto" diff --git a/internal/msggateway/compressor.go b/internal/msggateway/compressor.go index 9bbec1ec9e..d4789536e1 100644 --- a/internal/msggateway/compressor.go +++ b/internal/msggateway/compressor.go @@ -18,9 +18,10 @@ import ( "bytes" "compress/gzip" "errors" - "github.com/OpenIMSDK/tools/errs" "io" "sync" + + "github.com/OpenIMSDK/tools/errs" ) var ( diff --git a/internal/msggateway/encoder.go b/internal/msggateway/encoder.go index 2c46a774bf..69a899591a 100644 --- a/internal/msggateway/encoder.go +++ b/internal/msggateway/encoder.go @@ -17,6 +17,7 @@ package msggateway import ( "bytes" "encoding/gob" + "github.com/OpenIMSDK/tools/errs" ) diff --git a/internal/rpc/auth/auth.go b/internal/rpc/auth/auth.go index 1b10ba06a7..cde1e6ac5e 100644 --- a/internal/rpc/auth/auth.go +++ b/internal/rpc/auth/auth.go @@ -29,6 +29,7 @@ import ( "github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/mcontext" "github.com/OpenIMSDK/tools/tokenverify" + "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" diff --git a/pkg/common/db/controller/auth.go b/pkg/common/db/controller/auth.go index fe15198678..163a25c1cb 100644 --- a/pkg/common/db/controller/auth.go +++ b/pkg/common/db/controller/auth.go @@ -16,6 +16,7 @@ package controller import ( "context" + "github.com/OpenIMSDK/tools/errs" "github.com/openimsdk/open-im-server/v3/pkg/authverify" @@ -24,6 +25,7 @@ import ( "github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/tools/tokenverify" + "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" ) diff --git a/pkg/common/db/unrelation/msg.go b/pkg/common/db/unrelation/msg.go index 0aa9fa58d0..1c0686d285 100644 --- a/pkg/common/db/unrelation/msg.go +++ b/pkg/common/db/unrelation/msg.go @@ -35,6 +35,7 @@ import ( "github.com/OpenIMSDK/protocol/sdkws" "github.com/OpenIMSDK/tools/errs" + table "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/unrelation" ) From 6a5a2dcc17cfb8e2bc01bf68b72d796dda3fd8b0 Mon Sep 17 00:00:00 2001 From: cui fliter Date: Wed, 21 Feb 2024 20:41:15 +0800 Subject: [PATCH 058/188] fix function name on comment (#1940) Signed-off-by: cui fliter --- tools/formitychecker/checker/checker.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/formitychecker/checker/checker.go b/tools/formitychecker/checker/checker.go index 7a16433589..c9ad8239f5 100644 --- a/tools/formitychecker/checker/checker.go +++ b/tools/formitychecker/checker/checker.go @@ -29,7 +29,7 @@ var ( hyphenRegex = regexp.MustCompile(`^[a-zA-Z0-9\-]+\.[a-zA-Z0-9]+$`) ) -// CheckDirectoCheckDirectoryries initiates the checking process for the specified directories using configuration from config.Config. +// CheckDirectory initiates the checking process for the specified directories using configuration from config.Config. func CheckDirectory(cfg *config.Config) error { ignoreMap := make(map[string]struct{}) for _, dir := range cfg.IgnoreDirs { From 3c1d096e995fefc0ffde6cb4d7dd8399ade2c24c Mon Sep 17 00:00:00 2001 From: xuan <146319162+wxuanF@users.noreply.github.com> Date: Thu, 22 Feb 2024 10:57:22 +0800 Subject: [PATCH 059/188] docs:modify_README_Twitter (#1939) Signed-off-by: wxuanF <2569456943@qq.com> --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d45c6b6fed..90848124f3 100644 --- a/README.md +++ b/README.md @@ -58,7 +58,7 @@ + 🚀 [Join our Slack community](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q) + :eyes: [Join our wechat (微信群)](https://openim-1253691595.cos.ap-nanjing.myqcloud.com/WechatIMG20.jpeg) + 👫 [Join our Reddit](https://www.reddit.com/r/OpenIMessaging) -+ 💬 [Follow our Twitter account](https://twitter.com/openimsdk) ++ 💬 [Follow our Twitter account](https://twitter.com/founder_im63606) ## Ⓜ️ About OpenIM From b13f2614b880d6d0e73253514be882035cdfb3f5 Mon Sep 17 00:00:00 2001 From: xuan <146319162+wxuanF@users.noreply.github.com> Date: Sun, 25 Feb 2024 22:23:29 +0800 Subject: [PATCH 060/188] makelint internal/ (#1951) Signed-off-by: xuan <146319162+wxuanF@users.noreply.github.com> --- internal/msggateway/client.go | 21 ++-- internal/msggateway/long_conn.go | 10 +- internal/msggateway/n_ws_server.go | 11 +- internal/msggateway/user_map.go | 4 +- internal/msgtransfer/init.go | 2 +- .../msgtransfer/online_history_msg_handler.go | 107 +++++++++--------- 6 files changed, 78 insertions(+), 77 deletions(-) diff --git a/internal/msggateway/client.go b/internal/msggateway/client.go index d3b0e6a5f2..9a4005e6c0 100644 --- a/internal/msggateway/client.go +++ b/internal/msggateway/client.go @@ -78,16 +78,17 @@ type Client struct { token string } -func newClient(ctx *UserConnContext, conn LongConn, isCompress bool) *Client { - return &Client{ - w: new(sync.Mutex), - conn: conn, - PlatformID: utils.StringToInt(ctx.GetPlatformID()), - IsCompress: isCompress, - UserID: ctx.GetUserID(), - ctx: ctx, - } -} +// function not used +// func newClient(ctx *UserConnContext, conn LongConn, isCompress bool) *Client { +// return &Client{ +// w: new(sync.Mutex), +// conn: conn, +// PlatformID: utils.StringToInt(ctx.GetPlatformID()), +// IsCompress: isCompress, +// UserID: ctx.GetUserID(), +// ctx: ctx, +// } +// } // ResetClient updates the client's state with new connection and context information. func (c *Client) ResetClient( diff --git a/internal/msggateway/long_conn.go b/internal/msggateway/long_conn.go index 93e5cc33fc..a4251a50fe 100644 --- a/internal/msggateway/long_conn.go +++ b/internal/msggateway/long_conn.go @@ -108,10 +108,12 @@ func (d *GWebSocket) Dial(urlStr string, requestHeader http.Header) (*http.Respo } func (d *GWebSocket) IsNil() bool { - if d.conn != nil { - return false - } - return true + return d.conn == nil + // + // if d.conn != nil { + // return false + // } + // return true } func (d *GWebSocket) SetConnNil() { diff --git a/internal/msggateway/n_ws_server.go b/internal/msggateway/n_ws_server.go index c16da7c647..b734dee6d5 100644 --- a/internal/msggateway/n_ws_server.go +++ b/internal/msggateway/n_ws_server.go @@ -61,11 +61,12 @@ type LongConnServer interface { MessageHandler } -var bufferPool = sync.Pool{ - New: func() any { - return make([]byte, 1024) - }, -} +// bufferPool is unused +// var bufferPool = sync.Pool{ +// New: func() any { +// return make([]byte, 1024) +// }, +// } type WsServer struct { port int diff --git a/internal/msggateway/user_map.go b/internal/msggateway/user_map.go index 052d7de2d9..b4cec59fa9 100644 --- a/internal/msggateway/user_map.go +++ b/internal/msggateway/user_map.go @@ -58,12 +58,12 @@ func (u *UserMap) Get(key string, platformID int) ([]*Client, bool, bool) { func (u *UserMap) Set(key string, v *Client) { allClients, existed := u.m.Load(key) if existed { - log.ZDebug(context.Background(), "Set existed", "user_id", key, "client", *v) + log.ZDebug(context.Background(), "Set existed", "user_id", key, "client_user_id", v.UserID) oldClients := allClients.([]*Client) oldClients = append(oldClients, v) u.m.Store(key, oldClients) } else { - log.ZDebug(context.Background(), "Set not existed", "user_id", key, "client", *v) + log.ZDebug(context.Background(), "Set not existed", "user_id", key, "client_user_id", v.UserID) var clients []*Client clients = append(clients, v) u.m.Store(key, clients) diff --git a/internal/msgtransfer/init.go b/internal/msgtransfer/init.go index 16d8613dbf..8ef3efd83e 100644 --- a/internal/msgtransfer/init.go +++ b/internal/msgtransfer/init.go @@ -71,7 +71,7 @@ func StartTransfer(prometheusPort int) error { return err } - if err := client.CreateRpcRootNodes(config.Config.GetServiceNames()); err != nil { + if err2 := client.CreateRpcRootNodes(config.Config.GetServiceNames()); err2 != nil { return err } client.AddOption(mw.GrpcClient(), grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithDefaultServiceConfig(fmt.Sprintf(`{"LoadBalancingPolicy": "%s"}`, "round_robin"))) diff --git a/internal/msgtransfer/online_history_msg_handler.go b/internal/msgtransfer/online_history_msg_handler.go index 6678715d4b..6f0ee7706a 100644 --- a/internal/msgtransfer/online_history_msg_handler.go +++ b/internal/msgtransfer/online_history_msg_handler.go @@ -74,10 +74,10 @@ type OnlineHistoryRedisConsumerHandler struct { chArrays [ChannelNum]chan Cmd2Value msgDistributionCh chan Cmd2Value - singleMsgSuccessCount uint64 - singleMsgFailedCount uint64 - singleMsgSuccessCountMutex sync.Mutex - singleMsgFailedCountMutex sync.Mutex + // singleMsgSuccessCount uint64 + // singleMsgFailedCount uint64 + // singleMsgSuccessCountMutex sync.Mutex + // singleMsgFailedCountMutex sync.Mutex msgDatabase controller.CommonMsgDatabase conversationRpcClient *rpcclient.ConversationRpcClient @@ -111,62 +111,59 @@ func NewOnlineHistoryRedisConsumerHandler( } func (och *OnlineHistoryRedisConsumerHandler) Run(channelID int) { - for { - select { - case cmd := <-och.chArrays[channelID]: - switch cmd.Cmd { - case SourceMessages: - msgChannelValue := cmd.Value.(MsgChannelValue) - ctxMsgList := msgChannelValue.ctxMsgList - ctx := msgChannelValue.ctx - log.ZDebug( + for cmd := range och.chArrays[channelID] { + switch cmd.Cmd { + case SourceMessages: + msgChannelValue := cmd.Value.(MsgChannelValue) + ctxMsgList := msgChannelValue.ctxMsgList + ctx := msgChannelValue.ctx + log.ZDebug( + ctx, + "msg arrived channel", + "channel id", + channelID, + "msgList length", + len(ctxMsgList), + "uniqueKey", + msgChannelValue.uniqueKey, + ) + storageMsgList, notStorageMsgList, storageNotificationList, notStorageNotificationList, modifyMsgList := och.getPushStorageMsgList( + ctxMsgList, + ) + log.ZDebug( + ctx, + "msg lens", + "storageMsgList", + len(storageMsgList), + "notStorageMsgList", + len(notStorageMsgList), + "storageNotificationList", + len(storageNotificationList), + "notStorageNotificationList", + len(notStorageNotificationList), + "modifyMsgList", + len(modifyMsgList), + ) + conversationIDMsg := msgprocessor.GetChatConversationIDByMsg(ctxMsgList[0].message) + conversationIDNotification := msgprocessor.GetNotificationConversationIDByMsg(ctxMsgList[0].message) + och.handleMsg(ctx, msgChannelValue.uniqueKey, conversationIDMsg, storageMsgList, notStorageMsgList) + och.handleNotification( + ctx, + msgChannelValue.uniqueKey, + conversationIDNotification, + storageNotificationList, + notStorageNotificationList, + ) + if err := och.msgDatabase.MsgToModifyMQ(ctx, msgChannelValue.uniqueKey, conversationIDNotification, modifyMsgList); err != nil { + log.ZError( ctx, - "msg arrived channel", - "channel id", - channelID, - "msgList length", - len(ctxMsgList), + "msg to modify mq error", + err, "uniqueKey", msgChannelValue.uniqueKey, - ) - storageMsgList, notStorageMsgList, storageNotificationList, notStorageNotificationList, modifyMsgList := och.getPushStorageMsgList( - ctxMsgList, - ) - log.ZDebug( - ctx, - "msg lens", - "storageMsgList", - len(storageMsgList), - "notStorageMsgList", - len(notStorageMsgList), - "storageNotificationList", - len(storageNotificationList), - "notStorageNotificationList", - len(notStorageNotificationList), "modifyMsgList", - len(modifyMsgList), + modifyMsgList, ) - conversationIDMsg := msgprocessor.GetChatConversationIDByMsg(ctxMsgList[0].message) - conversationIDNotification := msgprocessor.GetNotificationConversationIDByMsg(ctxMsgList[0].message) - och.handleMsg(ctx, msgChannelValue.uniqueKey, conversationIDMsg, storageMsgList, notStorageMsgList) - och.handleNotification( - ctx, - msgChannelValue.uniqueKey, - conversationIDNotification, - storageNotificationList, - notStorageNotificationList, - ) - if err := och.msgDatabase.MsgToModifyMQ(ctx, msgChannelValue.uniqueKey, conversationIDNotification, modifyMsgList); err != nil { - log.ZError( - ctx, - "msg to modify mq error", - err, - "uniqueKey", - msgChannelValue.uniqueKey, - "modifyMsgList", - modifyMsgList, - ) - } } } } From ae6d21e4ea523a386aa081131accf22a3ee2df90 Mon Sep 17 00:00:00 2001 From: xuan <146319162+wxuanF@users.noreply.github.com> Date: Sun, 25 Feb 2024 23:01:22 +0800 Subject: [PATCH 061/188] docs:update README Community (#1943) Signed-off-by: wxuanF <2569456943@qq.com> --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 90848124f3..e83afe5aaa 100644 --- a/README.md +++ b/README.md @@ -53,12 +53,12 @@ ## :busts_in_silhouette: Community -+ 📚 [OpenIM Community](https://github.com/OpenIMSDK/community) -+ 💕 [OpenIM Interest Group](https://github.com/Openim-sigs) ++ 💬 [Follow our Twitter account](https://twitter.com/founder_im63606) ++ 👫 [Join our Reddit](https://www.reddit.com/r/OpenIMessaging) + 🚀 [Join our Slack community](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q) + :eyes: [Join our wechat (微信群)](https://openim-1253691595.cos.ap-nanjing.myqcloud.com/WechatIMG20.jpeg) -+ 👫 [Join our Reddit](https://www.reddit.com/r/OpenIMessaging) -+ 💬 [Follow our Twitter account](https://twitter.com/founder_im63606) ++ 📚 [OpenIM Community](https://github.com/OpenIMSDK/community) ++ 💕 [OpenIM Interest Group](https://github.com/Openim-sigs) ## Ⓜ️ About OpenIM From c8eed847113dc3badae45e77656b5641f246762f Mon Sep 17 00:00:00 2001 From: longyuqing112 <105913803+longyuqing112@users.noreply.github.com> Date: Mon, 26 Feb 2024 10:55:36 +0800 Subject: [PATCH 062/188] Fix lint errors in modified code (#1952) * pkg:makelint-#779 Signed-off-by: longyuqing112 <105913803+longyuqing112@users.noreply.github.com> * Update msg_utils.go * Update msg_utils.go * Update msg_utils.go * Update msg_utils.go * Update msg_utils.go * Update msg_utils.go * Update minio.go --------- Signed-off-by: longyuqing112 <105913803+longyuqing112@users.noreply.github.com> Co-authored-by: Xinwei Xiong <3293172751NSS@gmail.com> --- pkg/common/cmd/msg_utils.go | 18 ++++----- pkg/common/convert/friend.go | 12 +++++- pkg/common/db/cache/conversation.go | 49 ++++++++++++------------ pkg/common/db/controller/auth.go | 1 + pkg/common/db/controller/conversation.go | 2 +- pkg/common/db/controller/msg.go | 2 +- pkg/common/db/s3/cont/controller.go | 2 +- pkg/common/db/s3/cos/cos.go | 4 +- pkg/common/db/s3/minio/minio.go | 2 +- 9 files changed, 50 insertions(+), 42 deletions(-) diff --git a/pkg/common/cmd/msg_utils.go b/pkg/common/cmd/msg_utils.go index cfaf631ecd..8c5ffb16c3 100644 --- a/pkg/common/cmd/msg_utils.go +++ b/pkg/common/cmd/msg_utils.go @@ -22,7 +22,6 @@ import ( type MsgUtilsCmd struct { cobra.Command - msgTool *tools.MsgTool } func (m *MsgUtilsCmd) AddUserIDFlag() { @@ -38,19 +37,19 @@ func (m *MsgUtilsCmd) AddFixAllFlag() { m.Command.PersistentFlags().BoolP("fixAll", "f", false, "openIM fix all seqs") } -func (m *MsgUtilsCmd) getFixAllFlag(cmdLines *cobra.Command) bool { +/* func (m *MsgUtilsCmd) getFixAllFlag(cmdLines *cobra.Command) bool { fixAll, _ := cmdLines.Flags().GetBool("fixAll") return fixAll -} +} */ func (m *MsgUtilsCmd) AddClearAllFlag() { m.Command.PersistentFlags().BoolP("clearAll", "c", false, "openIM clear all seqs") } -func (m *MsgUtilsCmd) getClearAllFlag(cmdLines *cobra.Command) bool { +/* func (m *MsgUtilsCmd) getClearAllFlag(cmdLines *cobra.Command) bool { clearAll, _ := cmdLines.Flags().GetBool("clearAll") return clearAll -} +} */ func (m *MsgUtilsCmd) AddSuperGroupIDFlag() { m.Command.PersistentFlags().StringP("superGroupID", "g", "", "openIM superGroupID") @@ -65,19 +64,19 @@ func (m *MsgUtilsCmd) AddBeginSeqFlag() { m.Command.PersistentFlags().Int64P("beginSeq", "b", 0, "openIM beginSeq") } -func (m *MsgUtilsCmd) getBeginSeqFlag(cmdLines *cobra.Command) int64 { +/* func (m *MsgUtilsCmd) getBeginSeqFlag(cmdLines *cobra.Command) int64 { beginSeq, _ := cmdLines.Flags().GetInt64("beginSeq") return beginSeq -} +} */ func (m *MsgUtilsCmd) AddLimitFlag() { m.Command.PersistentFlags().Int64P("limit", "l", 0, "openIM limit") } -func (m *MsgUtilsCmd) getLimitFlag(cmdLines *cobra.Command) int64 { +/* func (m *MsgUtilsCmd) getLimitFlag(cmdLines *cobra.Command) int64 { limit, _ := cmdLines.Flags().GetInt64("limit") return limit -} +} */ func (m *MsgUtilsCmd) Execute() error { return m.Command.Execute() @@ -134,6 +133,7 @@ func NewSeqCmd() *SeqCmd { return seqCmd } + func (s *SeqCmd) GetSeqCmd() *cobra.Command { s.Command.Run = func(cmdLines *cobra.Command, args []string) { _, err := tools.InitMsgTool() diff --git a/pkg/common/convert/friend.go b/pkg/common/convert/friend.go index 27bd595ad5..f3a19e459c 100644 --- a/pkg/common/convert/friend.go +++ b/pkg/common/convert/friend.go @@ -26,7 +26,10 @@ import ( func FriendPb2DB(friend *sdkws.FriendInfo) *relation.FriendModel { dbFriend := &relation.FriendModel{} - utils.CopyStructFields(dbFriend, friend) + err := utils.CopyStructFields(dbFriend, friend) + if err != nil { + return nil + } dbFriend.FriendUserID = friend.FriendUser.UserID dbFriend.CreateTime = utils.UnixSecondToTime(friend.CreateTime) return dbFriend @@ -69,7 +72,11 @@ func FriendsDB2Pb( } for _, friend := range friendsDB { friendPb := &sdkws.FriendInfo{FriendUser: &sdkws.UserInfo{}} - utils.CopyStructFields(friendPb, friend) + err := utils.CopyStructFields(friendPb, friend) + if err != nil { + return nil, err + } + friendPb.FriendUser.UserID = users[friend.FriendUserID].UserID friendPb.FriendUser.Nickname = users[friend.FriendUserID].Nickname friendPb.FriendUser.FaceURL = users[friend.FriendUserID].FaceURL @@ -79,6 +86,7 @@ func FriendsDB2Pb( friendsPb = append(friendsPb, friendPb) } return friendsPb, nil + } func FriendRequestDB2Pb( diff --git a/pkg/common/db/cache/conversation.go b/pkg/common/db/cache/conversation.go index a7018bc18c..0471889472 100644 --- a/pkg/common/db/cache/conversation.go +++ b/pkg/common/db/cache/conversation.go @@ -16,7 +16,6 @@ package cache import ( "context" - "errors" "math/big" "strings" "time" @@ -220,16 +219,16 @@ func (c *ConversationRedisCache) DelConversations(ownerUserID string, conversati return cache } -func (c *ConversationRedisCache) getConversationIndex(convsation *relationtb.ConversationModel, keys []string) (int, error) { - key := c.getConversationKey(convsation.OwnerUserID, convsation.ConversationID) - for _i, _key := range keys { - if _key == key { - return _i, nil - } - } +// func (c *ConversationRedisCache) getConversationIndex(convsation *relationtb.ConversationModel, keys []string) (int, error) { +// key := c.getConversationKey(convsation.OwnerUserID, convsation.ConversationID) +// for _i, _key := range keys { +// if _key == key { +// return _i, nil +// } +// } - return 0, errors.New("not found key:" + key + " in keys") -} +// return 0, errors.New("not found key:" + key + " in keys") +// } func (c *ConversationRedisCache) GetConversations(ctx context.Context, ownerUserID string, conversationIDs []string) ([]*relationtb.ConversationModel, error) { //var keys []string @@ -333,7 +332,7 @@ func (c *ConversationRedisCache) DelSuperGroupRecvMsgNotNotifyUserIDsHash(groupI return cache } -func (c *ConversationRedisCache) getUserAllHasReadSeqsIndex(conversationID string, conversationIDs []string) (int, error) { +/* func (c *ConversationRedisCache) getUserAllHasReadSeqsIndex(conversationID string, conversationIDs []string) (int, error) { for _i, _conversationID := range conversationIDs { if _conversationID == conversationID { return _i, nil @@ -341,21 +340,21 @@ func (c *ConversationRedisCache) getUserAllHasReadSeqsIndex(conversationID strin } return 0, errors.New("not found key:" + conversationID + " in keys") -} +} */ -//func (c *ConversationRedisCache) GetUserAllHasReadSeqs(ctx context.Context, ownerUserID string) (map[string]int64, error) { -// conversationIDs, err := c.GetUserConversationIDs(ctx, ownerUserID) -// if err != nil { -// return nil, err -// } -// var keys []string -// for _, conversarionID := range conversationIDs { -// keys = append(keys, c.getConversationHasReadSeqKey(ownerUserID, conversarionID)) -// } -// return batchGetCacheMap(ctx, c.rcClient, keys, conversationIDs, c.expireTime, c.getUserAllHasReadSeqsIndex, func(ctx context.Context) (map[string]int64, error) { -// return c.conversationDB.GetUserAllHasReadSeqs(ctx, ownerUserID) -// }) -//} +/* func (c *ConversationRedisCache) GetUserAllHasReadSeqs(ctx context.Context, ownerUserID string) (map[string]int64, error) { + conversationIDs, err := c.GetUserConversationIDs(ctx, ownerUserID) + if err != nil { + return nil, err + } + var keys []string + for _, conversarionID := range conversationIDs { + keys = append(keys, c.getConversationHasReadSeqKey(ownerUserID, conversarionID)) + } + return batchGetCacheMap(ctx, c.rcClient, keys, conversationIDs, c.expireTime, c.getUserAllHasReadSeqsIndex, func(ctx context.Context) (map[string]int64, error) { + return c.conversationDB.GetUserAllHasReadSeqs(ctx, ownerUserID) + }) +} */ func (c *ConversationRedisCache) DelUserAllHasReadSeqs(ownerUserID string, conversationIDs ...string) ConversationCache { cache := c.NewCache() diff --git a/pkg/common/db/controller/auth.go b/pkg/common/db/controller/auth.go index 163a25c1cb..d3d5f7da93 100644 --- a/pkg/common/db/controller/auth.go +++ b/pkg/common/db/controller/auth.go @@ -75,6 +75,7 @@ func (a *authDatabase) CreateToken(ctx context.Context, userID string, platformI return "", err } } + claims := tokenverify.BuildClaims(userID, platformID, a.accessExpire) token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) tokenString, err := token.SignedString([]byte(a.accessSecret)) diff --git a/pkg/common/db/controller/conversation.go b/pkg/common/db/controller/conversation.go index c6629e9c8e..c53d4ab874 100644 --- a/pkg/common/db/controller/conversation.go +++ b/pkg/common/db/controller/conversation.go @@ -105,7 +105,7 @@ func (c *conversationDatabase) SetUsersConversationFiledTx(ctx context.Context, now := time.Now() for _, v := range NotUserIDs { temp := new(relationtb.ConversationModel) - if err := utils.CopyStructFields(temp, conversation); err != nil { + if err = utils.CopyStructFields(temp, conversation); err != nil { return err } temp.OwnerUserID = v diff --git a/pkg/common/db/controller/msg.go b/pkg/common/db/controller/msg.go index d427cc3a16..7eac624a74 100644 --- a/pkg/common/db/controller/msg.go +++ b/pkg/common/db/controller/msg.go @@ -846,7 +846,7 @@ func (db *commonMsgDatabase) deleteMsgRecursion(ctx context.Context, conversatio } } if len(delMsgIndexs) > 0 { - if err := db.msgDocDatabase.DeleteMsgsInOneDocByIndex(ctx, msgDocModel.DocID, delMsgIndexs); err != nil { + if err = db.msgDocDatabase.DeleteMsgsInOneDocByIndex(ctx, msgDocModel.DocID, delMsgIndexs); err != nil { log.ZError(ctx, "deleteMsgRecursion DeleteMsgsInOneDocByIndex failed", err, "conversationID", conversationID, "index", index) } delStruct.minSeq = int64(msgDocModel.Msg[delMsgIndexs[len(delMsgIndexs)-1]].Msg.Seq) diff --git a/pkg/common/db/s3/cont/controller.go b/pkg/common/db/s3/cont/controller.go index 82c27c1f21..2a66aeaf6e 100644 --- a/pkg/common/db/s3/cont/controller.go +++ b/pkg/common/db/s3/cont/controller.go @@ -106,7 +106,7 @@ func (c *Controller) InitiateUpload(ctx context.Context, hash string, size int64 partNumber++ } if maxParts > 0 && partNumber > 0 && partNumber < maxParts { - return nil, errors.New(fmt.Sprintf("too many parts: %d", partNumber)) + return nil, fmt.Errorf("too many parts: %d", partNumber) } if info, err := c.StatObject(ctx, c.HashPath(hash)); err == nil { return nil, &HashAlreadyExistsError{Object: info} diff --git a/pkg/common/db/s3/cos/cos.go b/pkg/common/db/s3/cos/cos.go index a82ffe6709..b302f1de6b 100644 --- a/pkg/common/db/s3/cos/cos.go +++ b/pkg/common/db/s3/cos/cos.go @@ -52,8 +52,8 @@ const ( const successCode = http.StatusOK const ( - videoSnapshotImagePng = "png" - videoSnapshotImageJpg = "jpg" +// videoSnapshotImagePng = "png" +// videoSnapshotImageJpg = "jpg" ) func NewCos() (s3.Interface, error) { diff --git a/pkg/common/db/s3/minio/minio.go b/pkg/common/db/s3/minio/minio.go index 5a615dcfd3..53a2864efc 100644 --- a/pkg/common/db/s3/minio/minio.go +++ b/pkg/common/db/s3/minio/minio.go @@ -140,7 +140,7 @@ func (m *Minio) initMinio(ctx context.Context) error { return fmt.Errorf("check bucket exists error: %w", err) } if !exists { - if err := m.core.Client.MakeBucket(ctx, conf.Bucket, minio.MakeBucketOptions{}); err != nil { + if err = m.core.Client.MakeBucket(ctx, conf.Bucket, minio.MakeBucketOptions{}); err != nil { return fmt.Errorf("make bucket error: %w", err) } } From 4803c8f004869f570c3e51c61369cb67c409dfda Mon Sep 17 00:00:00 2001 From: longyuqing112 <105913803+longyuqing112@users.noreply.github.com> Date: Mon, 26 Feb 2024 21:47:54 +0800 Subject: [PATCH 063/188] /pkg-make lint (#1956) Signed-off-by: longyuqing112 <105913803+longyuqing112@users.noreply.github.com> --- pkg/common/cmd/msg_utils.go | 1 - pkg/common/db/controller/auth.go | 2 +- pkg/common/db/s3/minio/minio.go | 2 +- pkg/common/db/s3/minio/thumbnail.go | 5 ++- pkg/common/db/s3/oss/oss.go | 4 +- pkg/common/db/unrelation/msg.go | 63 +++++++++++++---------------- pkg/rpcclient/notification/group.go | 4 +- pkg/rpcclient/third.go | 6 ++- pkg/statistics/statistics.go | 4 +- 9 files changed, 43 insertions(+), 48 deletions(-) diff --git a/pkg/common/cmd/msg_utils.go b/pkg/common/cmd/msg_utils.go index 8c5ffb16c3..dd6d645d71 100644 --- a/pkg/common/cmd/msg_utils.go +++ b/pkg/common/cmd/msg_utils.go @@ -133,7 +133,6 @@ func NewSeqCmd() *SeqCmd { return seqCmd } - func (s *SeqCmd) GetSeqCmd() *cobra.Command { s.Command.Run = func(cmdLines *cobra.Command, args []string) { _, err := tools.InitMsgTool() diff --git a/pkg/common/db/controller/auth.go b/pkg/common/db/controller/auth.go index d3d5f7da93..18c64ad8f4 100644 --- a/pkg/common/db/controller/auth.go +++ b/pkg/common/db/controller/auth.go @@ -70,7 +70,7 @@ func (a *authDatabase) CreateToken(ctx context.Context, userID string, platformI } } if len(deleteTokenKey) != 0 { - err := a.cache.DeleteTokenByUidPid(ctx, userID, platformID, deleteTokenKey) + err = a.cache.DeleteTokenByUidPid(ctx, userID, platformID, deleteTokenKey) if err != nil { return "", err } diff --git a/pkg/common/db/s3/minio/minio.go b/pkg/common/db/s3/minio/minio.go index 53a2864efc..81545ff1b7 100644 --- a/pkg/common/db/s3/minio/minio.go +++ b/pkg/common/db/s3/minio/minio.go @@ -149,7 +149,7 @@ func (m *Minio) initMinio(ctx context.Context) error { `{"Version": "2012-10-17","Statement": [{"Action": ["s3:GetObject","s3:PutObject"],"Effect": "Allow","Principal": {"AWS": ["*"]},"Resource": ["arn:aws:s3:::%s/*"],"Sid": ""}]}`, conf.Bucket, ) - if err := m.core.Client.SetBucketPolicy(ctx, conf.Bucket, policy); err != nil { + if err = m.core.Client.SetBucketPolicy(ctx, conf.Bucket, policy); err != nil { return err } } diff --git a/pkg/common/db/s3/minio/thumbnail.go b/pkg/common/db/s3/minio/thumbnail.go index 49c376c9f0..5dfdaee094 100644 --- a/pkg/common/db/s3/minio/thumbnail.go +++ b/pkg/common/db/s3/minio/thumbnail.go @@ -82,7 +82,8 @@ func (m *Minio) getImageThumbnailURL(ctx context.Context, name string, expire ti } key, err := m.cache.GetThumbnailKey(ctx, name, opt.Format, opt.Width, opt.Height, func(ctx context.Context) (string, error) { if img == nil { - reader, err := m.core.Client.GetObject(ctx, m.bucket, name, minio.GetObjectOptions{}) + var reader *minio.Object + reader, err = m.core.Client.GetObject(ctx, m.bucket, name, minio.GetObjectOptions{}) if err != nil { return "", err } @@ -103,7 +104,7 @@ func (m *Minio) getImageThumbnailURL(ctx context.Context, name string, expire ti err = gif.Encode(buf, thumbnail, nil) } cacheKey := filepath.Join(imageThumbnailPath, info.Etag, fmt.Sprintf("image_w%d_h%d.%s", opt.Width, opt.Height, opt.Format)) - if _, err := m.core.Client.PutObject(ctx, m.bucket, cacheKey, buf, int64(buf.Len()), minio.PutObjectOptions{}); err != nil { + if _, err = m.core.Client.PutObject(ctx, m.bucket, cacheKey, buf, int64(buf.Len()), minio.PutObjectOptions{}); err != nil { return "", err } return cacheKey, nil diff --git a/pkg/common/db/s3/oss/oss.go b/pkg/common/db/s3/oss/oss.go index 0bba97ee78..98473b87f2 100644 --- a/pkg/common/db/s3/oss/oss.go +++ b/pkg/common/db/s3/oss/oss.go @@ -52,10 +52,10 @@ const ( const successCode = http.StatusOK -const ( +/* const ( videoSnapshotImagePng = "png" videoSnapshotImageJpg = "jpg" -) +) */ func NewOSS() (s3.Interface, error) { conf := config.Config.Object.Oss diff --git a/pkg/common/db/unrelation/msg.go b/pkg/common/db/unrelation/msg.go index 1c0686d285..bc9118a9a2 100644 --- a/pkg/common/db/unrelation/msg.go +++ b/pkg/common/db/unrelation/msg.go @@ -246,47 +246,42 @@ func (m *MsgMongoDriver) GetMsgBySeqIndexIn1Doc( indexs = append(indexs, m.model.GetMsgIndex(seq)) } pipeline := mongo.Pipeline{ - { - {"$match", bson.D{ - {"doc_id", docID}, - }}, - }, - { - {"$project", bson.D{ - {"_id", 0}, - {"doc_id", 1}, - {"msgs", bson.D{ - {"$map", bson.D{ - {"input", indexs}, - {"as", "index"}, - {"in", bson.D{ - {"$let", bson.D{ - {"vars", bson.D{ - {"currentMsg", bson.D{ - {"$arrayElemAt", []string{"$msgs", "$$index"}}, - }}, + bson.D{{Key: "$match", Value: bson.D{ + {Key: "doc_id", Value: docID}, + }}}, + bson.D{{Key: "$project", Value: bson.D{ + {Key: "_id", Value: 0}, + {Key: "doc_id", Value: 1}, + {Key: "msgs", Value: bson.D{ + {Key: "$map", Value: bson.D{ + {Key: "input", Value: indexs}, + {Key: "as", Value: "index"}, + {Key: "in", Value: bson.D{ + {Key: "$let", Value: bson.D{ + {Key: "vars", Value: bson.D{ + {Key: "currentMsg", Value: bson.D{ + {Key: "$arrayElemAt", Value: bson.A{"$msgs", "$$index"}}, }}, - {"in", bson.D{ - {"$cond", bson.D{ - {"if", bson.D{ - {"$in", []string{userID, "$$currentMsg.del_list"}}, - }}, - {"then", nil}, - {"else", "$$currentMsg"}, + }}, + {Key: "in", Value: bson.D{ + {Key: "$cond", Value: bson.D{ + {Key: "if", Value: bson.D{ + {Key: "$in", Value: bson.A{userID, "$$currentMsg.del_list"}}, }}, + {Key: "then", Value: nil}, + {Key: "else", Value: "$$currentMsg"}, }}, }}, }}, }}, }}, }}, - }, - { - {"$project", bson.D{ - {"msgs.del_list", 0}, - }}, - }, + }}}, + bson.D{{Key: "$project", Value: bson.D{ + {Key: "msgs.del_list", Value: 0}, + }}}, } + cur, err := m.MsgCollection.Aggregate(ctx, pipeline) if err != nil { return nil, errs.Wrap(err) @@ -800,7 +795,7 @@ func (m *MsgMongoDriver) RangeUserSendCount( } defer cur.Close(ctx) var result []Result - if err := cur.All(ctx, &result); err != nil { + if err = cur.All(ctx, &result); err != nil { return 0, 0, nil, nil, errs.Wrap(err) } if len(result) == 0 { @@ -1049,7 +1044,7 @@ func (m *MsgMongoDriver) RangeGroupSendCount( } defer cur.Close(ctx) var result []Result - if err := cur.All(ctx, &result); err != nil { + if err = cur.All(ctx, &result); err != nil { return 0, 0, nil, nil, errs.Wrap(err) } if len(result) == 0 { diff --git a/pkg/rpcclient/notification/group.go b/pkg/rpcclient/notification/group.go index 8c3719b2c1..7f40326b76 100755 --- a/pkg/rpcclient/notification/group.go +++ b/pkg/rpcclient/notification/group.go @@ -410,7 +410,7 @@ func (g *GroupNotificationSender) GroupApplicationAcceptedNotification(ctx conte return err } tips := &sdkws.GroupApplicationAcceptedTips{Group: group, HandleMsg: req.HandledMsg} - if err := g.fillOpUser(ctx, &tips.OpUser, tips.Group.GroupID); err != nil { + if err = g.fillOpUser(ctx, &tips.OpUser, tips.Group.GroupID); err != nil { return err } for _, userID := range append(userIDs, req.FromUserID) { @@ -443,7 +443,7 @@ func (g *GroupNotificationSender) GroupApplicationRejectedNotification(ctx conte return err } tips := &sdkws.GroupApplicationRejectedTips{Group: group, HandleMsg: req.HandledMsg} - if err := g.fillOpUser(ctx, &tips.OpUser, tips.Group.GroupID); err != nil { + if err = g.fillOpUser(ctx, &tips.OpUser, tips.Group.GroupID); err != nil { return err } for _, userID := range append(userIDs, req.FromUserID) { diff --git a/pkg/rpcclient/third.go b/pkg/rpcclient/third.go index 73d8740051..b3557bf836 100755 --- a/pkg/rpcclient/third.go +++ b/pkg/rpcclient/third.go @@ -42,13 +42,15 @@ func NewThird(discov discoveryregistry.SvcDiscoveryRegistry) *Third { } client := third.NewThirdClient(conn) minioClient, err := minioInit() + if err != nil { + panic(err) + } return &Third{discov: discov, Client: client, conn: conn, MinioClient: minioClient} } func minioInit() (*minio.Client, error) { minioClient := &minio.Client{} - var initUrl string - initUrl = config.Config.Object.Minio.Endpoint + initUrl := config.Config.Object.Minio.Endpoint minioUrl, err := url.Parse(initUrl) if err != nil { return nil, err diff --git a/pkg/statistics/statistics.go b/pkg/statistics/statistics.go index de6d04fecc..6dfc8155c2 100644 --- a/pkg/statistics/statistics.go +++ b/pkg/statistics/statistics.go @@ -36,9 +36,7 @@ func (s *Statistics) output() { var timeIntervalNum uint64 for { sum = *s.AllCount - select { - case <-t.C: - } + <-t.C if *s.AllCount-sum <= 0 { intervalCount = 0 } else { From b6ded445108d70ca1b9fd32c963b9cbba7bdaad3 Mon Sep 17 00:00:00 2001 From: hanson-wen <419847644@qq.com> Date: Mon, 26 Feb 2024 22:47:01 +0800 Subject: [PATCH 064/188] add aws upload, but not complete, leave some todos (#1858) * add aws upload, but not complete, leave some todos * Update config.yaml * Update environment.sh * Update aws.go * Update aws.go * Update aws.go --------- Co-authored-by: Xinwei Xiong <3293172751NSS@gmail.com> --- config/templates/config.yaml.template | 7 + deployments/templates/config.yaml | 7 + go.mod | 10 +- pkg/common/config/config.go | 8 + pkg/common/db/s3/aws/aws.go | 275 ++++++++++++++++++++++++++ scripts/install/environment.sh | 8 + 6 files changed, 311 insertions(+), 4 deletions(-) create mode 100644 pkg/common/db/s3/aws/aws.go diff --git a/config/templates/config.yaml.template b/config/templates/config.yaml.template index 32ac14361c..03413c595c 100644 --- a/config/templates/config.yaml.template +++ b/config/templates/config.yaml.template @@ -153,6 +153,13 @@ object: accessKeySecret: '' sessionToken: '' publicRead: false + aws: + endpoint: "" + region: "" + bucket: "demo-9999999" + accessKeyID: '' + accessKeySecret: '' + publicRead: false ###################### RPC Port Configuration ###################### # RPC service ports diff --git a/deployments/templates/config.yaml b/deployments/templates/config.yaml index cc318adcde..0aa6e68d6b 100644 --- a/deployments/templates/config.yaml +++ b/deployments/templates/config.yaml @@ -153,6 +153,13 @@ object: accessKeySecret: ${KODO_ACCESS_KEY_SECRET} sessionToken: ${KODO_SESSION_TOKEN} publicRead: ${KODO_PUBLIC_READ} + aws: + endpoint: "${AWS_ENDPOINT}" # This might not be necessary unless you're using a custom endpoint + region: "${AWS_REGION}" + bucket: "${AWS_BUCKET}" + accessKeyID: ${AWS_ACCESS_KEY_ID} + accessKeySecret: ${AWS_SECRET_ACCESS_KEY} + publicRead: ${AWS_PUBLIC_READ} ###################### RPC Port Configuration ###################### # RPC service ports diff --git a/go.mod b/go.mod index ac02683b42..681d910993 100644 --- a/go.mod +++ b/go.mod @@ -50,10 +50,11 @@ require ( cloud.google.com/go v0.112.0 // indirect cloud.google.com/go/compute v1.23.3 // indirect cloud.google.com/go/compute/metadata v0.2.3 // indirect - cloud.google.com/go/firestore v1.14.0 // indirect - cloud.google.com/go/iam v1.1.5 // indirect - cloud.google.com/go/longrunning v0.5.4 // indirect - cloud.google.com/go/storage v1.36.0 // indirect + cloud.google.com/go/firestore v1.13.0 // indirect + cloud.google.com/go/iam v1.1.2 // indirect + cloud.google.com/go/longrunning v0.5.1 // indirect + cloud.google.com/go/storage v1.30.1 // indirect + github.com/aws/aws-sdk-go v1.49.21 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bytedance/sonic v1.9.1 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect @@ -94,6 +95,7 @@ require ( github.com/jinzhu/copier v0.3.5 // indirect github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/now v1.1.5 // indirect + github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd // indirect github.com/klauspost/compress v1.17.4 // indirect diff --git a/pkg/common/config/config.go b/pkg/common/config/config.go index 9696e9367e..7ee55d876b 100644 --- a/pkg/common/config/config.go +++ b/pkg/common/config/config.go @@ -164,6 +164,14 @@ type configStruct struct { SessionToken string `yaml:"sessionToken"` PublicRead bool `yaml:"publicRead"` } `yaml:"kodo"` + Aws struct { + Endpoint string `yaml:"endpoint"` + Region string `yaml:"region"` + Bucket string `yaml:"bucket"` + AccessKeyID string `yaml:"accessKeyID"` + AccessKeySecret string `yaml:"accessKeySecret"` + PublicRead bool `yaml:"publicRead"` + } `yaml:"aws"` } `yaml:"object"` RpcPort struct { diff --git a/pkg/common/db/s3/aws/aws.go b/pkg/common/db/s3/aws/aws.go new file mode 100644 index 0000000000..14fe0c0690 --- /dev/null +++ b/pkg/common/db/s3/aws/aws.go @@ -0,0 +1,275 @@ +// 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. + +// docURL: https://docs.aws.amazon.com/AmazonS3/latest/API/Welcome.html + +package aws + +import ( + "context" + "errors" + "fmt" + "time" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/awserr" + "github.com/aws/aws-sdk-go/aws/credentials" + "github.com/aws/aws-sdk-go/aws/session" + sdk "github.com/aws/aws-sdk-go/service/s3" + "github.com/openimsdk/open-im-server/v3/pkg/common/config" + "github.com/openimsdk/open-im-server/v3/pkg/common/db/s3" +) + +const ( + minPartSize int64 = 1024 * 1024 * 1 // 1MB + maxPartSize int64 = 1024 * 1024 * 1024 * 5 // 5GB + maxNumSize int64 = 10000 +) + +// const ( +// imagePng = "png" +// imageJpg = "jpg" +// imageJpeg = "jpeg" +// imageGif = "gif" +// imageWebp = "webp" +// ) + +// const successCode = http.StatusOK + +// const ( +// videoSnapshotImagePng = "png" +// videoSnapshotImageJpg = "jpg" +// ) + +func NewAWS() (s3.Interface, error) { + conf := config.Config.Object.Aws + credential := credentials.NewStaticCredentials( + conf.AccessKeyID, // accessKey + conf.AccessKeySecret, // secretKey + "") // sts的临时凭证 + + sess, err := session.NewSession(&aws.Config{ + Region: aws.String(conf.Region), // 桶所在的区域 + Credentials: credential, + }) + + if err != nil { + return nil, err + } + return &Aws{ + bucket: conf.Bucket, + client: sdk.New(sess), + credential: credential, + }, nil +} + +type Aws struct { + bucket string + client *sdk.S3 + credential *credentials.Credentials +} + +func (a *Aws) Engine() string { + return "aws" +} + +func (a *Aws) InitiateMultipartUpload(ctx context.Context, name string) (*s3.InitiateMultipartUploadResult, error) { + input := &sdk.CreateMultipartUploadInput{ + Bucket: aws.String(a.bucket), // TODO: To be verified whether it is required + Key: aws.String(name), + } + result, err := a.client.CreateMultipartUploadWithContext(ctx, input) + if err != nil { + return nil, err + } + return &s3.InitiateMultipartUploadResult{ + Bucket: *result.Bucket, + Key: *result.Key, + UploadID: *result.UploadId, + }, nil +} + +func (a *Aws) CompleteMultipartUpload(ctx context.Context, uploadID string, name string, parts []s3.Part) (*s3.CompleteMultipartUploadResult, error) { + sdkParts := make([]*sdk.CompletedPart, len(parts)) + for i, part := range parts { + sdkParts[i] = &sdk.CompletedPart{ + ETag: aws.String(part.ETag), + PartNumber: aws.Int64(int64(part.PartNumber)), + } + } + input := &sdk.CompleteMultipartUploadInput{ + Bucket: aws.String(a.bucket), // TODO: To be verified whether it is required + Key: aws.String(name), + UploadId: aws.String(uploadID), + MultipartUpload: &sdk.CompletedMultipartUpload{ + Parts: sdkParts, + }, + } + result, err := a.client.CompleteMultipartUploadWithContext(ctx, input) + if err != nil { + return nil, err + } + return &s3.CompleteMultipartUploadResult{ + Location: *result.Location, + Bucket: *result.Bucket, + Key: *result.Key, + ETag: *result.ETag, + }, nil +} + +func (a *Aws) PartSize(ctx context.Context, size int64) (int64, error) { + if size <= 0 { + return 0, errors.New("size must be greater than 0") + } + if size > maxPartSize*maxNumSize { + return 0, fmt.Errorf("AWS size must be less than the maximum allowed limit") + } + if size <= minPartSize*maxNumSize { + return minPartSize, nil + } + partSize := size / maxNumSize + if size%maxNumSize != 0 { + partSize++ + } + return partSize, nil +} + +func (a *Aws) DeleteObject(ctx context.Context, name string) error { + _, err := a.client.DeleteObjectWithContext(ctx, &sdk.DeleteObjectInput{ + Bucket: aws.String(a.bucket), + Key: aws.String(name), + }) + return err +} + +func (a *Aws) CopyObject(ctx context.Context, src string, dst string) (*s3.CopyObjectInfo, error) { + result, err := a.client.CopyObjectWithContext(ctx, &sdk.CopyObjectInput{ + Bucket: aws.String(a.bucket), + Key: aws.String(dst), + CopySource: aws.String(src), + }) + if err != nil { + return nil, err + } + return &s3.CopyObjectInfo{ + ETag: *result.CopyObjectResult.ETag, + Key: dst, + }, nil +} + +func (a *Aws) IsNotFound(err error) bool { + if err == nil { + return false + } + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + case sdk.ErrCodeNoSuchKey: + return true + default: + return false + } + } + return false +} + +func (a *Aws) AbortMultipartUpload(ctx context.Context, uploadID string, name string) error { + _, err := a.client.AbortMultipartUploadWithContext(ctx, &sdk.AbortMultipartUploadInput{ + Bucket: aws.String(a.bucket), + Key: aws.String(name), + UploadId: aws.String(uploadID), + }) + return err +} + +func (a *Aws) ListUploadedParts(ctx context.Context, uploadID string, name string, partNumberMarker int, maxParts int) (*s3.ListUploadedPartsResult, error) { + result, err := a.client.ListPartsWithContext(ctx, &sdk.ListPartsInput{ + Bucket: aws.String(a.bucket), + Key: aws.String(name), + UploadId: aws.String(uploadID), + MaxParts: aws.Int64(int64(maxParts)), + PartNumberMarker: aws.Int64(int64(partNumberMarker)), + }) + if err != nil { + return nil, err + } + parts := make([]s3.UploadedPart, len(result.Parts)) + for i, part := range result.Parts { + parts[i] = s3.UploadedPart{ + PartNumber: int(*part.PartNumber), + LastModified: *part.LastModified, + Size: *part.Size, + ETag: *part.ETag, + } + } + return &s3.ListUploadedPartsResult{ + Key: *result.Key, + UploadID: *result.UploadId, + NextPartNumberMarker: int(*result.NextPartNumberMarker), + MaxParts: int(*result.MaxParts), + UploadedParts: parts, + }, nil +} + +func (a *Aws) PartLimit() *s3.PartLimit { + return &s3.PartLimit{ + MinPartSize: minPartSize, + MaxPartSize: maxPartSize, + MaxNumSize: maxNumSize, + } +} + +func (a *Aws) PresignedPutObject(ctx context.Context, name string, expire time.Duration) (string, error) { + req, _ := a.client.PutObjectRequest(&sdk.PutObjectInput{ + Bucket: aws.String(a.bucket), + Key: aws.String(name), + }) + url, err := req.Presign(expire) + if err != nil { + return "", err + } + return url, nil +} + +func (a *Aws) StatObject(ctx context.Context, name string) (*s3.ObjectInfo, error) { + result, err := a.client.GetObjectWithContext(ctx, &sdk.GetObjectInput{ + Bucket: aws.String(a.bucket), + Key: aws.String(name), + }) + if err != nil { + return nil, err + } + res := &s3.ObjectInfo{ + Key: name, + ETag: *result.ETag, + Size: *result.ContentLength, + LastModified: *result.LastModified, + } + return res, nil +} + +// AccessURL todo +func (a *Aws) AccessURL(ctx context.Context, name string, expire time.Duration, opt *s3.AccessURLOption) (string, error) { + // todo + return "", nil +} + +func (a *Aws) FormData(ctx context.Context, name string, size int64, contentType string, duration time.Duration) (*s3.FormData, error) { + // todo + return nil, nil +} + +func (a *Aws) AuthSign(ctx context.Context, uploadID string, name string, expire time.Duration, partNumbers []int) (*s3.AuthSignResult, error) { + // todo + return nil, nil +} diff --git a/scripts/install/environment.sh b/scripts/install/environment.sh index b1d2354b94..8962887753 100755 --- a/scripts/install/environment.sh +++ b/scripts/install/environment.sh @@ -222,6 +222,14 @@ def "KODO_ACCESS_KEY_SECRET" # 七 def "KODO_SESSION_TOKEN" # 七牛云OSS的会话令牌 def "KODO_PUBLIC_READ" "false" # 公有读 +# AWS Configuration Information +def "AWS_ENDPOINT" "" # AWS endpoint, generally not needed unless using a specific service +def "AWS_REGION" "us-east-1" # AWS Region +def "AWS_BUCKET" "demo-9999999" # AWS S3 Bucket Name +def "AWS_ACCESS_KEY_ID" # AWS Access Key ID +def "AWS_SECRET_ACCESS_KEY" # AWS Secret Access Key +def "AWS_PUBLIC_READ" "false" # Public read access + ###################### Redis 配置信息 ###################### def "REDIS_PORT" "16379" # Redis的端口 def "REDIS_ADDRESS" "${DOCKER_BRIDGE_GATEWAY}" # Redis的地址 From 6c4334b7305fc376ae461f0b58bfb209c0becb60 Mon Sep 17 00:00:00 2001 From: OpenIM Bot <124379614+kubbot@users.noreply.github.com> Date: Tue, 27 Feb 2024 14:19:21 +0800 Subject: [PATCH 065/188] cicd: bump League Patch (#1958) --- go.mod | 10 +++++----- go.sum | 7 +++++++ pkg/common/db/s3/aws/aws.go | 1 + 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/go.mod b/go.mod index 681d910993..30bfcf146d 100644 --- a/go.mod +++ b/go.mod @@ -36,6 +36,7 @@ require github.com/google/uuid v1.6.0 require ( github.com/IBM/sarama v1.42.2 github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible + github.com/aws/aws-sdk-go v1.49.21 github.com/go-redis/redis v6.15.9+incompatible github.com/redis/go-redis/v9 v9.4.0 github.com/spf13/pflag v1.0.5 @@ -50,11 +51,10 @@ require ( cloud.google.com/go v0.112.0 // indirect cloud.google.com/go/compute v1.23.3 // indirect cloud.google.com/go/compute/metadata v0.2.3 // indirect - cloud.google.com/go/firestore v1.13.0 // indirect - cloud.google.com/go/iam v1.1.2 // indirect - cloud.google.com/go/longrunning v0.5.1 // indirect - cloud.google.com/go/storage v1.30.1 // indirect - github.com/aws/aws-sdk-go v1.49.21 // indirect + cloud.google.com/go/firestore v1.14.0 // indirect + cloud.google.com/go/iam v1.1.5 // indirect + cloud.google.com/go/longrunning v0.5.4 // indirect + cloud.google.com/go/storage v1.36.0 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bytedance/sonic v1.9.1 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect diff --git a/go.sum b/go.sum index 38596d45e3..6277afac39 100644 --- a/go.sum +++ b/go.sum @@ -31,6 +31,8 @@ github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= +github.com/aws/aws-sdk-go v1.49.21 h1:Rl8KW6HqkwzhATwvXhyr7vD4JFUMi7oXGAw9SrxxIFY= +github.com/aws/aws-sdk-go v1.49.21/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk= github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= @@ -203,6 +205,10 @@ github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= +github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= +github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= +github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= github.com/jonboulle/clockwork v0.4.0 h1:p4Cf1aMWXnXAUh8lVfewRBx1zaTSYKrKMF2g3ST4RZ4= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= @@ -532,6 +538,7 @@ gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= diff --git a/pkg/common/db/s3/aws/aws.go b/pkg/common/db/s3/aws/aws.go index 14fe0c0690..42d5cd14c1 100644 --- a/pkg/common/db/s3/aws/aws.go +++ b/pkg/common/db/s3/aws/aws.go @@ -27,6 +27,7 @@ import ( "github.com/aws/aws-sdk-go/aws/credentials" "github.com/aws/aws-sdk-go/aws/session" sdk "github.com/aws/aws-sdk-go/service/s3" + "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/db/s3" ) From 8e6c1d74c79846a9456cfcc5ab00dd1a51744d92 Mon Sep 17 00:00:00 2001 From: OpenIM-Gordon <46924906+FGadvancer@users.noreply.github.com> Date: Tue, 27 Feb 2024 16:44:51 +0800 Subject: [PATCH 066/188] fix: change consumer group receive messages avoid kafka consumer group always rebalanced. (#1942) --- internal/msgtransfer/init.go | 9 ++------- internal/msgtransfer/online_history_msg_handler.go | 1 + internal/push/consumer_init.go | 7 +------ pkg/common/kafka/consumer_group.go | 13 ++++++------- 4 files changed, 10 insertions(+), 20 deletions(-) diff --git a/internal/msgtransfer/init.go b/internal/msgtransfer/init.go index 8ef3efd83e..1766a54195 100644 --- a/internal/msgtransfer/init.go +++ b/internal/msgtransfer/init.go @@ -20,8 +20,6 @@ import ( "fmt" "github.com/OpenIMSDK/tools/errs" - "github.com/OpenIMSDK/tools/log" - util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" "net/http" @@ -118,11 +116,8 @@ func (m *MsgTransfer) Start(prometheusPort int) error { netErr error ) - onError := func(ctx context.Context, err error, errInfo string) { - log.ZWarn(ctx, errInfo, err) - } - go m.historyCH.historyConsumerGroup.RegisterHandleAndConsumer(m.ctx, m.historyCH, onError) - go m.historyMongoCH.historyConsumerGroup.RegisterHandleAndConsumer(m.ctx, m.historyMongoCH, onError) + go m.historyCH.historyConsumerGroup.RegisterHandleAndConsumer(m.ctx, m.historyCH) + go m.historyMongoCH.historyConsumerGroup.RegisterHandleAndConsumer(m.ctx, m.historyMongoCH) if config.Config.Prometheus.Enable { go func() { diff --git a/internal/msgtransfer/online_history_msg_handler.go b/internal/msgtransfer/online_history_msg_handler.go index 6f0ee7706a..393ec7a75f 100644 --- a/internal/msgtransfer/online_history_msg_handler.go +++ b/internal/msgtransfer/online_history_msg_handler.go @@ -438,6 +438,7 @@ func (och *OnlineHistoryRedisConsumerHandler) ConsumeClaim( wg = sync.WaitGroup{} running = new(atomic.Bool) ) + running.Store(true) wg.Add(1) go func() { diff --git a/internal/push/consumer_init.go b/internal/push/consumer_init.go index 572afe0eb1..daaa37e8a3 100644 --- a/internal/push/consumer_init.go +++ b/internal/push/consumer_init.go @@ -16,8 +16,6 @@ package push import ( "context" - - "github.com/OpenIMSDK/tools/log" ) type Consumer struct { @@ -36,9 +34,6 @@ func NewConsumer(pusher *Pusher) (*Consumer, error) { } func (c *Consumer) Start() { - onError := func(ctx context.Context, err error, errInfo string) { - log.ZWarn(ctx, errInfo, err) - } - go c.pushCh.pushConsumerGroup.RegisterHandleAndConsumer(context.Background(), &c.pushCh, onError) + go c.pushCh.pushConsumerGroup.RegisterHandleAndConsumer(context.Background(), &c.pushCh) } diff --git a/pkg/common/kafka/consumer_group.go b/pkg/common/kafka/consumer_group.go index 5245c6a6f7..d63527620b 100644 --- a/pkg/common/kafka/consumer_group.go +++ b/pkg/common/kafka/consumer_group.go @@ -17,8 +17,6 @@ package kafka import ( "context" "errors" - "fmt" - "github.com/IBM/sarama" "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/log" @@ -67,18 +65,19 @@ func (mc *MConsumerGroup) GetContextFromMsg(cMsg *sarama.ConsumerMessage) contex return GetContextWithMQHeader(cMsg.Headers) } -func (mc *MConsumerGroup) RegisterHandleAndConsumer(ctx context.Context, handler sarama.ConsumerGroupHandler, onError func(context.Context, error, string)) { +func (mc *MConsumerGroup) RegisterHandleAndConsumer(ctx context.Context, handler sarama.ConsumerGroupHandler) { log.ZDebug(ctx, "register consumer group", "groupID", mc.groupID) for { err := mc.ConsumerGroup.Consume(ctx, mc.topics, handler) - if errors.Is(err, sarama.ErrClosedConsumerGroup) || errors.Is(err, context.Canceled) { + if errors.Is(err, sarama.ErrClosedConsumerGroup) { return } - if err != nil { - errInfo := fmt.Sprintf("consume err: %v, topic: %v, groupID: %s", err, strings.Join(mc.topics, ", "), mc.groupID) - onError(ctx, err, errInfo) // 调用回调函数处理错误 + if errors.Is(err, context.Canceled) { return } + if err != nil { + log.ZWarn(ctx, "consume err", err, "topic", mc.topics, "groupID", mc.groupID) + } } } From ac8775827d1665ee8c0f67ebe9cc0181aab3cbcf Mon Sep 17 00:00:00 2001 From: Brabem <69128477+luhaoling@users.noreply.github.com> Date: Tue, 27 Feb 2024 17:58:54 +0800 Subject: [PATCH 067/188] fix: reconstruct the script of 'make start' 'make stop' and 'make check' (#1953) * fix: del the error world * fix: refactoring scripts * fix: del nounset * rm set error * rm set error * replace openim::log::info * replace openim::log::info * replace openim::log::info * log * log * log * log * log * log * log * log * log * log * log * log * log * log * log * log * log * log * log * log * log * log * log * log * log * log * log * log * log * log * fix: fix the error output format * log * fix: fix the error * log * log * fix: fi the code error * log * log * log * log * log * log * log * log * log * log * log * log * log * log * log * log * log * log * log * log * log * log * log * log * log * log * log * log * log * log * log * log * fix: use printf replace the echo --------- Co-authored-by: skiffer-git <44203734@qq.com> --- cmd/openim-api/main.go | 2 +- install.sh | 2 +- internal/msggateway/init.go | 4 +- internal/msgtransfer/init.go | 6 +- pkg/common/startrpc/start.go | 4 +- pkg/util/genutil/genutil.go | 10 +- scripts/advertise.sh | 2 +- scripts/build-all-service.sh | 6 +- scripts/check-all.sh | 43 +++--- scripts/cherry-pick.sh | 6 +- scripts/common.sh | 6 +- scripts/docker-start-all.sh | 6 +- scripts/gen-swagger-docs.sh | 6 +- scripts/init-config.sh | 6 +- scripts/init-env.sh | 4 +- scripts/install-im-server.sh | 6 +- scripts/install/common.sh | 22 ++- scripts/install/dependency.sh | 6 +- scripts/install/install.sh | 2 +- scripts/install/openim-api.sh | 29 ++-- scripts/install/openim-crontask.sh | 8 +- scripts/install/openim-man.sh | 2 +- scripts/install/openim-msggateway.sh | 15 +- scripts/install/openim-msgtransfer.sh | 62 +++++--- scripts/install/openim-push.sh | 16 +-- scripts/install/openim-rpc.sh | 36 +++-- scripts/install/openim-tools.sh | 8 +- scripts/lib/golang.sh | 51 +++++++ scripts/lib/init.sh | 6 +- scripts/lib/logging.sh | 18 ++- scripts/lib/util.sh | 195 ++++++++++++++++++-------- scripts/list-feature-tests.sh | 6 +- scripts/release.sh | 6 +- scripts/run-in-gopath.sh | 6 +- scripts/start-all.sh | 100 ++++++++----- scripts/stop-all.sh | 39 ++++-- scripts/update-generated-docs.sh | 6 +- scripts/update-yamlfmt.sh | 6 +- scripts/verify-pkg-names.sh | 6 +- scripts/verify-shellcheck.sh | 6 +- scripts/verify-spelling.sh | 6 +- scripts/verify-typecheck.sh | 6 +- scripts/verify-yamlfmt.sh | 6 +- 43 files changed, 513 insertions(+), 281 deletions(-) diff --git a/cmd/openim-api/main.go b/cmd/openim-api/main.go index 7a7e062939..34ada1d579 100644 --- a/cmd/openim-api/main.go +++ b/cmd/openim-api/main.go @@ -119,7 +119,7 @@ func run(port int, proPort int) error { defer cancel() select { case <-sigs: - util.SIGUSR1Exit() + util.SIGTERMExit() err := server.Shutdown(ctx) if err != nil { return errs.Wrap(err, "shutdown err") diff --git a/install.sh b/install.sh index 7ff0f87393..4b8e74c55e 100755 --- a/install.sh +++ b/install.sh @@ -18,7 +18,7 @@ # set -e -set -o pipefail + ############################## OpenIM Github ############################## # ... rest of the script ... diff --git a/internal/msggateway/init.go b/internal/msggateway/init.go index 321407f7ee..b18efcd50d 100644 --- a/internal/msggateway/init.go +++ b/internal/msggateway/init.go @@ -46,9 +46,7 @@ func RunWsAndServer(rpcPort, wsPort, prometheusPort int) error { netDone := make(chan error) go func() { err = hubServer.Start() - if err != nil { - netDone <- err - } + netDone <- err }() return hubServer.LongConnServer.Run(netDone) } diff --git a/internal/msgtransfer/init.go b/internal/msgtransfer/init.go index 1766a54195..df06ec0f92 100644 --- a/internal/msgtransfer/init.go +++ b/internal/msgtransfer/init.go @@ -139,12 +139,12 @@ func (m *MsgTransfer) Start(prometheusPort int) error { signal.Notify(sigs, syscall.SIGTERM) select { case <-sigs: - util.SIGUSR1Exit() + util.SIGTERMExit() // graceful close kafka client. m.cancel() m.historyCH.historyConsumerGroup.Close() m.historyMongoCH.historyConsumerGroup.Close() - + return nil case <-netDone: m.cancel() m.historyCH.historyConsumerGroup.Close() @@ -152,6 +152,4 @@ func (m *MsgTransfer) Start(prometheusPort int) error { close(netDone) return netErr } - - return nil } diff --git a/pkg/common/startrpc/start.go b/pkg/common/startrpc/start.go index c5105ec513..be9fbd25bf 100644 --- a/pkg/common/startrpc/start.go +++ b/pkg/common/startrpc/start.go @@ -140,7 +140,7 @@ func Start( signal.Notify(sigs, syscall.SIGTERM) select { case <-sigs: - util.SIGUSR1Exit() + util.SIGTERMExit() ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) defer cancel() if err := gracefulStopWithCtx(ctx, srv.GracefulStop); err != nil { @@ -152,7 +152,7 @@ func Start( if err != nil { return errs.Wrap(err, "shutdown err") } - return errors.New("SIGTERM EXIT") + return nil case <-netDone: close(netDone) return netErr diff --git a/pkg/util/genutil/genutil.go b/pkg/util/genutil/genutil.go index f97b803f66..bd9376d583 100644 --- a/pkg/util/genutil/genutil.go +++ b/pkg/util/genutil/genutil.go @@ -15,7 +15,6 @@ package genutil import ( - "errors" "fmt" "os" "path/filepath" @@ -42,15 +41,12 @@ func OutDir(path string) (string, error) { } func ExitWithError(err error) { - if errors.Is(err, errors.New("SIGTERM EXIT")) { - os.Exit(-1) - } progName := filepath.Base(os.Args[0]) - fmt.Fprintf(os.Stderr, "\n\n%s exit -1: \n%+v\n\n", progName, err) + fmt.Fprintf(os.Stderr, "%s exit -1: %+v\n", progName, err) os.Exit(-1) } -func SIGUSR1Exit() { +func SIGTERMExit() { progName := filepath.Base(os.Args[0]) - fmt.Printf("\n\n%s receive process terminal SIGTERM exit 0\n\n", progName) + fmt.Fprintf(os.Stderr, "Warning %s receive process terminal SIGTERM exit 0\n", progName) } diff --git a/scripts/advertise.sh b/scripts/advertise.sh index 3effc4f2bd..958b4e3ae6 100755 --- a/scripts/advertise.sh +++ b/scripts/advertise.sh @@ -14,7 +14,7 @@ # limitations under the License. set -e -set -o pipefail + . $(dirname ${BASH_SOURCE})/lib/init.sh diff --git a/scripts/build-all-service.sh b/scripts/build-all-service.sh index b5578fca63..6335b0e08d 100755 --- a/scripts/build-all-service.sh +++ b/scripts/build-all-service.sh @@ -22,9 +22,9 @@ # Usage: `scripts/build-all-service.sh`. # Example: `scripts/build-go.sh WHAT=cmd/kubelet`. -set -o errexit -set -o nounset -set -o pipefail + + + OPENIM_ROOT=$(dirname "${BASH_SOURCE[0]}")/.. source "${OPENIM_ROOT}/scripts/lib/init.sh" diff --git a/scripts/check-all.sh b/scripts/check-all.sh index 062605ae11..a9b07d65b3 100755 --- a/scripts/check-all.sh +++ b/scripts/check-all.sh @@ -19,9 +19,9 @@ # Encapsulated as: `make check`. # READ: https://github.com/openimsdk/open-im-server/tree/main/scripts/install/environment.sh -set -o errexit -set -o nounset -set -o pipefail + + + OPENIM_ROOT=$(dirname "${BASH_SOURCE[0]}")/.. source "${OPENIM_ROOT}/scripts/install/common.sh" @@ -49,13 +49,6 @@ print_services_and_ports() { echo "+-------------------------+----------+" } -handle_error() { - echo "An error occurred. Printing ${STDERR_LOG_FILE} contents:" - cat "${STDERR_LOG_FILE}" - exit 1 -} - -trap handle_error ERR # Assuming OPENIM_SERVER_NAME_TARGETS and OPENIM_SERVER_PORT_TARGETS are defined # Similarly for OPENIM_DEPENDENCY_TARGETS and OPENIM_DEPENDENCY_PORT_TARGETS @@ -71,7 +64,6 @@ echo "++ The port being checked: ${OPENIM_SERVER_PORT_LISTARIES[@]}" openim::log::info "\n## Check all dependent service ports" echo "++ The port being checked: ${OPENIM_DEPENDENCY_PORT_LISTARIES[@]}" -set +e # Later, after discarding Docker, the Docker keyword is unreliable, and Kubepods is used if grep -qE 'docker|kubepods' /proc/1/cgroup || [ -f /.dockerenv ]; then @@ -85,22 +77,29 @@ if [[ $? -ne 0 ]]; then openim::log::error_exit "The service does not start properly, please check the port, query variable definition!" echo "+++ https://github.com/openimsdk/open-im-server/tree/main/scripts/install/environment.sh +++" else - echo "++++ Check all dependent service ports successfully !" + openim::log::success "All components depended on by openim are running normally! " fi -openim::log::info "\n## Check OpenIM service name" -. $(dirname ${BASH_SOURCE})/install/openim-msgtransfer.sh openim::msgtransfer::check -openim::log::info "\n## Check all OpenIM service ports" -echo "+++ The port being checked: ${OPENIM_SERVER_PORT_LISTARIES[@]}" -openim::util::check_ports ${OPENIM_SERVER_PORT_LISTARIES[@]} +openim::log::info "\n## Check openim service name:\n${OPENIM_OUTPUT_HOSTBIN}/openim-msgtransfer" +result=$(. $(dirname ${BASH_SOURCE})/install/openim-msgtransfer.sh openim::msgtransfer::check) if [[ $? -ne 0 ]]; then echo "+++ cat openim log file >>> ${LOG_FILE}" - openim::log::error_exit "The service does not start properly, please check the port, query variable definition!" -else - echo "++++ Check all openim service ports successfully !" + openim::log::error "check process failed.\n $result" fi -set -e -trap - ERR \ No newline at end of file +echo "Check openim service name:" +for item in "${OPENIM_ALL_SERVICE_LIBRARIES_NO_TRANSFER[@]}"; do + echo "$item" +done + +result=$(openim::util::check_process_names ${OPENIM_ALL_SERVICE_LIBRARIES_NO_TRANSFER[@]}) +if [[ $? -ne 0 ]]; then + echo "+++ cat openim log file >>> ${LOG_FILE}" + openim::log::error "check process failed.\n " + echo "$result" +else + openim::log::success "All openim services are running normally! " +fi + diff --git a/scripts/cherry-pick.sh b/scripts/cherry-pick.sh index 8a1f8dd794..f8d7912f81 100755 --- a/scripts/cherry-pick.sh +++ b/scripts/cherry-pick.sh @@ -21,9 +21,9 @@ # checks them out to a branch named: # automated-cherry-pick-of--- -set -o errexit -set -o nounset -set -o pipefail + + + OPENIM_ROOT=$(dirname "${BASH_SOURCE[0]}")/.. source "${OPENIM_ROOT}/scripts/lib/init.sh" diff --git a/scripts/common.sh b/scripts/common.sh index d67389d56a..702f555885 100755 --- a/scripts/common.sh +++ b/scripts/common.sh @@ -18,9 +18,9 @@ # shellcheck disable=SC2034 # Variables sourced in other scripts. # Common utilities, variables and checks for all build scripts. -set -o errexit -set +o nounset -set -o pipefail + + + # Unset CDPATH, having it set messes up with script import paths unset CDPATH diff --git a/scripts/docker-start-all.sh b/scripts/docker-start-all.sh index 1626555536..c47069e3bf 100755 --- a/scripts/docker-start-all.sh +++ b/scripts/docker-start-all.sh @@ -14,9 +14,9 @@ # See the License for the specific language governing permissions and # limitations under the License. -set -o errexit -set -o nounset -set -o pipefail + + + #fixme This scripts is the total startup scripts #fixme The full name of the shell scripts that needs to be started is placed in the need_to_start_server_shell array diff --git a/scripts/gen-swagger-docs.sh b/scripts/gen-swagger-docs.sh index 68410e79c5..e768f9106c 100755 --- a/scripts/gen-swagger-docs.sh +++ b/scripts/gen-swagger-docs.sh @@ -15,9 +15,9 @@ # Script to generate docs from the latest swagger spec. -set -o errexit -set -o nounset -set -o pipefail + + + # The root of the build/dist directory OPENIM_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd -P)" diff --git a/scripts/init-config.sh b/scripts/init-config.sh index 82eefbb54d..c7cf163202 100755 --- a/scripts/init-config.sh +++ b/scripts/init-config.sh @@ -15,9 +15,9 @@ # This script automatically initializes various configuration files and can generate example files. -set -o errexit -set -o nounset -set -o pipefail + + + # Root directory of the OpenIM project OPENIM_ROOT=$(dirname "${BASH_SOURCE[0]}")/.. diff --git a/scripts/init-env.sh b/scripts/init-env.sh index 75b871b088..1e802c3be4 100755 --- a/scripts/init-env.sh +++ b/scripts/init-env.sh @@ -16,8 +16,8 @@ #FIXME This script is the startup script for multiple servers. #FIXME The full names of the shell scripts that need to be started are placed in the `need_to_start_server_shell` array. -set -o nounset -set -o pipefail + + OPENIM_ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")"/.. && pwd -P) source "${OPENIM_ROOT}/scripts/install/common.sh" diff --git a/scripts/install-im-server.sh b/scripts/install-im-server.sh index c1224e30c8..d11a49dc8d 100755 --- a/scripts/install-im-server.sh +++ b/scripts/install-im-server.sh @@ -27,9 +27,9 @@ # Usage: # SERVER_IMAGE_VERSION=latest IMAGE_REGISTRY=myregistry ./this_script.sh -set -o errexit -set -o nounset -set -o pipefail + + + OPENIM_ROOT=$(dirname "${BASH_SOURCE[0]}")/.. source "${OPENIM_ROOT}/scripts/lib/init.sh" diff --git a/scripts/install/common.sh b/scripts/install/common.sh index f6ee5d3ad2..ed1ba1a4bb 100755 --- a/scripts/install/common.sh +++ b/scripts/install/common.sh @@ -15,9 +15,9 @@ # Common utilities, variables and checks for all build scripts. -set -o errexit -set +o nounset -set -o pipefail + + + # Sourced flag COMMON_SOURCED=true @@ -99,6 +99,22 @@ IFS=" " read -ra OPENIM_SERVER_PORT_TARGETS <<< "$(openim::common::service_port) readonly OPENIM_SERVER_PORT_TARGETS readonly OPENIM_SERVER_PORT_LISTARIES=("${OPENIM_SERVER_PORT_TARGETS[@]##*/}") + +OPENIM_ALL_SERVICE_LIBRARIES_NO_TRANSFER=() + +for target in "${OPENIM_SERVER_BINARIES_NO_TRANSFER[@]}"; do + OPENIM_ALL_SERVICE_LIBRARIES_NO_TRANSFER+=("${OPENIM_OUTPUT_HOSTBIN}/${target}") +done +readonly OPENIM_ALL_SERVICE_LIBRARIES_NO_TRANSFER + + + +OPENIM_ALL_SERVICE_LIBRARIES=() +for target in "${OPENIM_SERVER_BINARIES_NO_CMDUTILS[@]}"; do + OPENIM_ALL_SERVICE_LIBRARIES+=("${OPENIM_OUTPUT_HOSTBIN}/${target}") +done +readonly OPENIM_ALL_SERVICE_LIBRARIES + openim::common::dependency_name() { local targets=( redis diff --git a/scripts/install/dependency.sh b/scripts/install/dependency.sh index e7c7eb426f..bad1cb6f92 100755 --- a/scripts/install/dependency.sh +++ b/scripts/install/dependency.sh @@ -15,9 +15,9 @@ # This script will install the dependencies required for openim -set -o errexit -set +o nounset -set -o pipefail + + + OPENIM_ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")"/../.. && pwd -P) [[ -z ${COMMON_SOURCED} ]] && source "${OPENIM_ROOT}"/scripts/install/common.sh diff --git a/scripts/install/install.sh b/scripts/install/install.sh index d5ec5b7f77..bb09675bfd 100755 --- a/scripts/install/install.sh +++ b/scripts/install/install.sh @@ -109,7 +109,7 @@ function openim::uninstall::uninstall_openim() { openim::common::sudo "systemctl stop openim.target" openim::common::sudo "systemctl disable openim.target" openim::common::sudo "rm -f /etc/systemd/system/openim.target" - set -o errexit + openim::log::success "openim uninstall success" } diff --git a/scripts/install/openim-api.sh b/scripts/install/openim-api.sh index be2a2d33b3..8a7b8d1f11 100755 --- a/scripts/install/openim-api.sh +++ b/scripts/install/openim-api.sh @@ -14,9 +14,9 @@ # See the License for the specific language governing permissions and # limitations under the License. -set -o errexit -set +o nounset -set -o pipefail + + + OPENIM_ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")"/../.. && pwd -P) [[ -z ${COMMON_SOURCED} ]] && source "${OPENIM_ROOT}"/scripts/install/common.sh @@ -47,24 +47,31 @@ function openim::api::start() { openim::log::info "Starting ${SERVER_NAME} ..." + readonly OPENIM_API_SERVER_LIBRARIES="${OPENIM_OUTPUT_HOSTBIN}/${SERVER_NAME}" + + printf "+------------------------+--------------+\n" printf "| Service Name | Port |\n" printf "+------------------------+--------------+\n" - + + local length=${#OPENIM_API_SERVICE_LISTARIES[@]} - for ((i=0; i> ${LOG_FILE} 2> >(tee -a "${STDERR_LOG_FILE}" "$TMP_LOG_FILE" >&2) & - openim::util::check_process_names ${SERVER_NAME} + return 0 } @@ -107,7 +105,7 @@ function openim::crontask::uninstall() { openim::common::sudo "rm -f ${OPENIM_INSTALL_DIR}/${SERVER_NAME}" openim::common::sudo "rm -f ${OPENIM_CONFIG_DIR}/${SERVER_NAME}.yaml" openim::common::sudo "rm -f /etc/systemd/system/${SERVER_NAME}.service" - set -o errexit + openim::log::info "uninstall ${SERVER_NAME} successfully" } diff --git a/scripts/install/openim-man.sh b/scripts/install/openim-man.sh index fac5cebea4..642588a287 100755 --- a/scripts/install/openim-man.sh +++ b/scripts/install/openim-man.sh @@ -76,7 +76,7 @@ function openim::man::uninstall() { # Turn off exit-on-error temporarily to handle non-existing files gracefully set +o errexit openim::common::sudo "rm -f /usr/share/man/man1/openim-*" - set -o errexit + openim::log::info "Uninstalled openim man pages successfully" } diff --git a/scripts/install/openim-msggateway.sh b/scripts/install/openim-msggateway.sh index a2316c784d..3eb9bb3495 100755 --- a/scripts/install/openim-msggateway.sh +++ b/scripts/install/openim-msggateway.sh @@ -14,14 +14,13 @@ # limitations under the License. # Common utilities, variables and checks for all build scripts. -set -o errexit -set +o nounset -set -o pipefail + + + OPENIM_ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")"/../.. && pwd -P) [[ -z ${COMMON_SOURCED} ]] && source "${OPENIM_ROOT}"/scripts/install/common.sh -openim::util::set_max_fd 200000 SERVER_NAME="openim-msggateway" @@ -31,8 +30,7 @@ function openim::msggateway::start() { openim::log::info "Start OpenIM Msggateway, binary root: ${SERVER_NAME}" openim::log::status "Start OpenIM Msggateway, path: ${OPENIM_MSGGATEWAY_BINARY}" - - openim::util::stop_services_with_name ${OPENIM_MSGGATEWAY_BINARY} + # OpenIM message gateway service port OPENIM_MESSAGE_GATEWAY_PORTS=$(openim::util::list-to-string ${OPENIM_MESSAGE_GATEWAY_PORT} ) @@ -66,8 +64,7 @@ function openim::msggateway::start() { nohup ${OPENIM_MSGGATEWAY_BINARY} --port ${OPENIM_MSGGATEWAY_PORTS_ARRAY[$i]} --ws_port ${OPENIM_WS_PORTS_ARRAY[$i]} $PROMETHEUS_PORT_OPTION -c ${OPENIM_MSGGATEWAY_CONFIG} >> ${LOG_FILE} 2> >(tee -a "${STDERR_LOG_FILE}" "$TMP_LOG_FILE" >&2) & done - - openim::util::check_process_names ${SERVER_NAME} + return 0 } ###################################### Linux Systemd ###################################### @@ -117,7 +114,7 @@ function openim::msggateway::uninstall() { openim::common::sudo "rm -f ${OPENIM_INSTALL_DIR}/${SERVER_NAME}" openim::common::sudo "rm -f ${OPENIM_CONFIG_DIR}/${SERVER_NAME}.yaml" openim::common::sudo "rm -f /etc/systemd/system/${SERVER_NAME}.service" - set -o errexit + openim::log::info "uninstall ${SERVER_NAME} successfully" } diff --git a/scripts/install/openim-msgtransfer.sh b/scripts/install/openim-msgtransfer.sh index 783e067297..9fdf07fe20 100755 --- a/scripts/install/openim-msgtransfer.sh +++ b/scripts/install/openim-msgtransfer.sh @@ -16,15 +16,13 @@ # ./scripts/install/openim-msgtransfer.sh openim::msgtransfer::start # Common utilities, variables and checks for all build scripts. -set -o errexit -set +o nounset -set -o pipefail + + + OPENIM_ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")"/../.. && pwd -P) [[ -z ${COMMON_SOURCED} ]] && source "${OPENIM_ROOT}"/scripts/install/common.sh -openim::util::set_max_fd 200000 - SERVER_NAME="openim-msgtransfer" function openim::msgtransfer::start() { @@ -33,9 +31,7 @@ function openim::msgtransfer::start() { openim::log::info "Start OpenIM Msggateway, binary root: ${SERVER_NAME}" openim::log::status "Start OpenIM Msggateway, path: ${OPENIM_MSGTRANSFER_BINARY}" - - openim::util::stop_services_with_name ${OPENIM_MSGTRANSFER_BINARY} - + # Message Transfer Prometheus port list MSG_TRANSFER_PROM_PORTS=(openim::util::list-to-string ${MSG_TRANSFER_PROM_PORT} ) @@ -46,11 +42,11 @@ function openim::msgtransfer::start() { openim::log::info "openim maggateway num: ${OPENIM_MSGGATEWAY_NUM}" if [ "${OPENIM_MSGGATEWAY_NUM}" -lt 1 ]; then - opeim::log::error_exit "OPENIM_MSGGATEWAY_NUM must be greater than 0" + opeim::log::error "OPENIM_MSGGATEWAY_NUM must be greater than 0" fi if [ ${OPENIM_MSGGATEWAY_NUM} -ne $((${#MSG_TRANSFER_PROM_PORTS[@]} - 1)) ]; then - openim::log::error_exit "OPENIM_MSGGATEWAY_NUM must be equal to the number of MSG_TRANSFER_PROM_PORTS" + openim::log::error "OPENIM_MSGGATEWAY_NUM must be equal to the number of MSG_TRANSFER_PROM_PORTS" fi for (( i=0; i<$OPENIM_MSGGATEWAY_NUM; i++ )) do @@ -63,17 +59,18 @@ function openim::msgtransfer::start() { fi nohup ${OPENIM_MSGTRANSFER_BINARY} ${PROMETHEUS_PORT_OPTION} -c ${OPENIM_MSGTRANSFER_CONFIG} -n ${i} >> ${LOG_FILE} 2> >(tee -a "${STDERR_LOG_FILE}" "$TMP_LOG_FILE" >&2) & done - - openim::util::check_process_names "${OPENIM_OUTPUT_HOSTBIN}/${SERVER_NAME}" + return 0 + } function openim::msgtransfer::check() { PIDS=$(pgrep -f "${OPENIM_OUTPUT_HOSTBIN}/openim-msgtransfer") - - NUM_PROCESSES=$(echo "$PIDS" | wc -l) - + if [ -z "$PIDS" ]; then + NUM_PROCESSES=0 + else + NUM_PROCESSES=$(echo "$PIDS" | wc -l) + fi if [ "$NUM_PROCESSES" -eq "$OPENIM_MSGGATEWAY_NUM" ]; then - openim::log::info "Found $OPENIM_MSGGATEWAY_NUM processes named $OPENIM_OUTPUT_HOSTBIN" for PID in $PIDS; do if [[ "$OSTYPE" == "linux-gnu"* ]]; then ps -p $PID -o pid,cmd @@ -84,10 +81,39 @@ function openim::msgtransfer::check() { fi done else - openim::log::error_exit "Expected $OPENIM_MSGGATEWAY_NUM openim msgtransfer processes, but found $NUM_PROCESSES msgtransfer processes." + openim::log::error "Expected $OPENIM_MSGGATEWAY_NUM openim msgtransfer processes, but found $NUM_PROCESSES msgtransfer processes." + return 1 fi + return 0 } +function openim::msgtransfer::check_for_stop() { + PIDS=$(pgrep -f "${OPENIM_OUTPUT_HOSTBIN}/openim-msgtransfer") || PIDS="0" + if [ "$PIDS" = "0" ]; then + return 0 + fi + + NUM_PROCESSES=$(echo "$PIDS" | wc -l | xargs) + + if [ "$NUM_PROCESSES" -gt 0 ]; then + openim::log::error "Found $NUM_PROCESSES processes for $OPENIM_OUTPUT_HOSTBIN/openim-msgtransfer" + for PID in $PIDS; do + if [[ "$OSTYPE" == "linux-gnu"* ]]; then + echo -e "\033[31m$(ps -p $PID -o pid,cmd)\033[0m" + elif [[ "$OSTYPE" == "darwin"* ]]; then + echo -e "\033[31m$(ps -p $PID -o pid,comm)\033[0m" + else + openim::log::error "Unsupported OS type: $OSTYPE" + fi + done + openim::log::error "Processes have not been stopped properly." + else + openim::log::success "All openim-msgtransfer processes have been stopped properly." + fi + return 0 +} + + ###################################### Linux Systemd ###################################### SYSTEM_FILE_PATH="/etc/systemd/system/${SERVER_NAME}.service" @@ -138,7 +164,7 @@ function openim::msgtransfer::uninstall() { openim::common::sudo "rm -f ${OPENIM_INSTALL_DIR}/${SERVER_NAME}" openim::common::sudo "rm -f ${OPENIM_CONFIG_DIR}/${SERVER_NAME}.yaml" openim::common::sudo "rm -f /etc/systemd/system/${SERVER_NAME}.service" - set -o errexit + openim::log::info "uninstall ${SERVER_NAME} successfully" } diff --git a/scripts/install/openim-push.sh b/scripts/install/openim-push.sh index 95da16c8a9..8684f185c1 100755 --- a/scripts/install/openim-push.sh +++ b/scripts/install/openim-push.sh @@ -40,9 +40,9 @@ # # Note: Ensure that the appropriate permissions and environmental variables are set prior to script execution. # -set -o errexit -set +o nounset -set -o pipefail + + + OPENIM_ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")"/../.. && pwd -P) [[ -z ${COMMON_SOURCED} ]] && source "${OPENIM_ROOT}"/scripts/install/common.sh @@ -61,22 +61,20 @@ function openim::push::start() { OPENIM_PUSH_PORTS_ARRAY=$(openim::util::list-to-string ${OPENIM_PUSH_PORT} ) PUSH_PROM_PORTS_ARRAY=$(openim::util::list-to-string ${PUSH_PROM_PORT} ) - - openim::util::stop_services_with_name ${SERVER_NAME} - + openim::log::status "push port list: ${OPENIM_PUSH_PORTS_ARRAY[@]}" openim::log::status "prometheus port list: ${PUSH_PROM_PORTS_ARRAY[@]}" if [ ${#OPENIM_PUSH_PORTS_ARRAY[@]} -ne ${#PUSH_PROM_PORTS_ARRAY[@]} ]; then - openim::log::error_exit "The length of the two port lists is different!" + openim::log::error "The length of the two port lists is different!" fi for (( i=0; i<${#OPENIM_PUSH_PORTS_ARRAY[@]}; i++ )); do openim::log::info "start push process, port: ${OPENIM_PUSH_PORTS_ARRAY[$i]}, prometheus port: ${PUSH_PROM_PORTS_ARRAY[$i]}" nohup ${OPENIM_PUSH_BINARY} --port ${OPENIM_PUSH_PORTS_ARRAY[$i]} -c ${OPENIM_PUSH_CONFIG} --prometheus_port ${PUSH_PROM_PORTS_ARRAY[$i]} >> ${LOG_FILE} 2> >(tee -a "${STDERR_LOG_FILE}" "$TMP_LOG_FILE" >&2) & done + return 0 - openim::util::check_process_names ${SERVER_NAME} } ###################################### Linux Systemd ###################################### @@ -125,7 +123,7 @@ function openim::push::uninstall() { openim::common::sudo "rm -f ${OPENIM_INSTALL_DIR}/${SERVER_NAME}" openim::common::sudo "rm -f ${OPENIM_CONFIG_DIR}/${SERVER_NAME}.yaml" openim::common::sudo "rm -f /etc/systemd/system/${SERVER_NAME}.service" - set -o errexit + openim::log::info "uninstall ${SERVER_NAME} successfully" } diff --git a/scripts/install/openim-rpc.sh b/scripts/install/openim-rpc.sh index f8feaaa572..023cb65947 100755 --- a/scripts/install/openim-rpc.sh +++ b/scripts/install/openim-rpc.sh @@ -38,9 +38,9 @@ # Note: Before executing this script, ensure that the necessary permissions are granted and relevant environmental variables are set. # -set -o errexit -set +o nounset -set -o pipefail + + + OPENIM_ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")"/../.. && pwd -P) [[ -z ${COMMON_SOURCED} ]] && source "${OPENIM_ROOT}"/scripts/install/common.sh @@ -64,6 +64,16 @@ IFS=" " read -ra OPENIM_RPC_SERVICE_TARGETS <<< "$(openim::rpc::service_name)" readonly OPENIM_RPC_SERVICE_TARGETS readonly OPENIM_RPC_SERVICE_LISTARIES=("${OPENIM_RPC_SERVICE_TARGETS[@]##*/}") + +OPENIM_ALL_RPC_FULL_PATH=() +for target in openim::rpc::service_name; do + OPENIM_ALL_RPC_FULL_PATH+=("${OPENIM_OUTPUT_HOSTBIN}/${target}") +done +readonly OPENIM_ALL_RPC_FULL_PATH + + + + # Make sure the environment is only called via common to avoid too much nesting openim::rpc::service_port() { local targets=( @@ -121,14 +131,11 @@ function openim::rpc::start() { printf "+------------------------+-------+-----------------+\n" done + # start all rpc services for ((i = 0; i < ${#OPENIM_RPC_SERVICE_LISTARIES[*]}; i++)); do - # openim::util::stop_services_with_name ${OPENIM_RPC_SERVICE_LISTARIES - openim::util::stop_services_on_ports ${OPENIM_RPC_PORT_LISTARIES[$i]} - openim::util::stop_services_on_ports ${OPENIM_RPC_PROM_PORT_LISTARIES[$i]} openim::log::info "OpenIM ${OPENIM_RPC_SERVICE_LISTARIES[$i]} config path: ${OPENIM_RPC_CONFIG}" - # Get the service and Prometheus ports. OPENIM_RPC_SERVICE_PORTS=( $(openim::util::list-to-string ${OPENIM_RPC_PORT_LISTARIES[$i]}) ) read -a OPENIM_RPC_SERVICE_PORTS_ARRAY <<< ${OPENIM_RPC_SERVICE_PORTS} @@ -138,15 +145,17 @@ function openim::rpc::start() { for ((j = 0; j < ${#OPENIM_RPC_SERVICE_PORTS_ARRAY[@]}; j++)); do openim::log::info "Starting ${OPENIM_RPC_SERVICE_LISTARIES[$i]} service, port: ${OPENIM_RPC_SERVICE_PORTS[j]}, prometheus port: ${OPENIM_RPC_PROM_PORTS[j]}, binary root: ${OPENIM_OUTPUT_HOSTBIN}/${OPENIM_RPC_SERVICE_LISTARIES[$i]}" - openim::rpc::start_service "${OPENIM_RPC_SERVICE_LISTARIES[$i]}" "${OPENIM_RPC_SERVICE_PORTS[j]}" "${OPENIM_RPC_PROM_PORTS[j]}" + result=$(openim::rpc::start_service "${OPENIM_RPC_SERVICE_LISTARIES[$i]}" "${OPENIM_RPC_SERVICE_PORTS[j]}" "${OPENIM_RPC_PROM_PORTS[j]}") + if [[ $? -ne 0 ]]; then + openim::log::error "start ${SERVER_NAME} failed" + else + openim::log::info "$result" + fi done done - sleep 5 - - openim::util::check_ports ${OPENIM_RPC_PORT_TARGETS[@]} - # openim::util::check_ports ${OPENIM_RPC_PROM_PORT_TARGETS[@]} + return 0 } function openim::rpc::start_service() { @@ -161,6 +170,7 @@ function openim::rpc::start_service() { cmd="${cmd} --prometheus_port ${prometheus_port}" fi nohup ${cmd} >> "${LOG_FILE}" 2> >(tee -a "${STDERR_LOG_FILE}" "$TMP_LOG_FILE" >&2) & + return 0 } ###################################### Linux Systemd ###################################### @@ -220,7 +230,7 @@ function openim::rpc::uninstall() { openim::common::sudo "rm -f ${OPENIM_CONFIG_DIR}/${service}.yaml" openim::common::sudo "rm -f ${SYSTEM_FILE_PATHS[$service]}" done - set -o errexit + openim::log::info "uninstall openim-rpc successfully" } diff --git a/scripts/install/openim-tools.sh b/scripts/install/openim-tools.sh index ac60a5f45e..72005ed8e4 100755 --- a/scripts/install/openim-tools.sh +++ b/scripts/install/openim-tools.sh @@ -38,9 +38,9 @@ # Example: ./openim-tools.sh openim::tools::install # -set -o errexit -set +o nounset -set -o pipefail + + + OPENIM_ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")"/../.. && pwd -P) [[ -z ${COMMON_SOURCED} ]] && source "${OPENIM_ROOT}"/scripts/install/common.sh @@ -122,7 +122,6 @@ function openim::tools::pre-start() { for tool in "${OPENIM_TOOLS_PRE_START_NAME_LISTARIES[@]}"; do openim::log::info "Starting ${tool}..." openim::tools::start_service ${tool} ${OPNEIM_CONFIG} - sleep 0.2 done } @@ -131,7 +130,6 @@ function openim::tools::post-start() { for tool in "${OPENIM_TOOLS_POST_START_NAME_LISTARIES[@]}"; do openim::log::info "Starting ${tool}..." openim::tools::start_service ${tool} - sleep 0.2 done } diff --git a/scripts/lib/golang.sh b/scripts/lib/golang.sh index af04771d5d..7b9d7e60c0 100755 --- a/scripts/lib/golang.sh +++ b/scripts/lib/golang.sh @@ -84,6 +84,57 @@ openim::golang::server_targets() { echo "${targets[@]}" } +openim::golang::server_targets_no_transfer() { + local targets=( + openim-api + openim-crontask + openim-msggateway + openim-push + openim-rpc-auth + openim-rpc-conversation + openim-rpc-friend + openim-rpc-group + openim-rpc-msg + openim-rpc-third + openim-rpc-user + ) + echo "${targets[@]}" +} + +openim::golang::server_targets_no_cmdutils() { + local targets=( + openim-api + openim-crontask + openim-msggateway + openim-msgtransfer + openim-push + openim-rpc-auth + openim-rpc-conversation + openim-rpc-friend + openim-rpc-group + openim-rpc-msg + openim-rpc-third + openim-rpc-user + ) + echo "${targets[@]}" +} + + +IFS=" " read -ra OPENIM_SERVER_TARGETS_NO_CMDUTILS <<< "$(openim::golang::server_targets_no_cmdutils)" +readonly OPENIM_SERVER_TARGETS_NO_CMDUTILS +readonly OPENIM_SERVER_BINARIES_NO_CMDUTILS=("${OPENIM_SERVER_TARGETS_NO_CMDUTILS[@]##*/}") + + + + + +IFS=" " read -ra OPENIM_SERVER_TARGETS_NO_TRANSFER <<< "$(openim::golang::server_targets_no_transfer)" +readonly OPENIM_SERVER_TARGETS_NO_TRANSFER +readonly OPENIM_SERVER_BINARIES_NO_TRANSFER=("${OPENIM_SERVER_TARGETS_NO_TRANSFER[@]##*/}") + + + + IFS=" " read -ra OPENIM_SERVER_TARGETS <<< "$(openim::golang::server_targets)" readonly OPENIM_SERVER_TARGETS readonly OPENIM_SERVER_BINARIES=("${OPENIM_SERVER_TARGETS[@]##*/}") diff --git a/scripts/lib/init.sh b/scripts/lib/init.sh index be8e9f8aa5..4cd6d9fb88 100755 --- a/scripts/lib/init.sh +++ b/scripts/lib/init.sh @@ -13,9 +13,9 @@ # See the License for the specific language governing permissions and # limitations under the License. -set -o errexit -set +o nounset -set -o pipefail + + + # Short-circuit if init.sh has already been sourced [[ $(type -t openim::init::loaded) == function ]] && return 0 diff --git a/scripts/lib/logging.sh b/scripts/lib/logging.sh index 8f2bb33cf7..7afb6bfced 100755 --- a/scripts/lib/logging.sh +++ b/scripts/lib/logging.sh @@ -75,12 +75,13 @@ openim::log::errexit() { openim::log::install_errexit() { # trap ERR to provide an error handler whenever a command exits nonzero this - # is a more verbose version of set -o errexit - trap 'openim::log::errexit' ERR + # is a more verbose version of + # trap 'openim::log::errexit' ERR # setting errtrace allows our ERR trap handler to be propagated to functions, # expansions and subshells - set -o errtrace + #set -o errtrace + return 0 } # Print out the stack trace @@ -205,22 +206,27 @@ openim::log::status() { fi timestamp=$(date +"[%Y-%m-%d %H:%M:%S %Z]") - echo_log "+++ ${timestamp} ${1}" + echo_log "${timestamp} ${1}" shift for message; do echo_log " ${message}" done } + openim::log::success() { local V="${V:-0}" if [[ ${OPENIM_VERBOSE} < ${V} ]]; then return fi - timestamp=$(date +"%m%d %H:%M:%S") - echo_log -e "${COLOR_GREEN}[success ${timestamp}] ${COLOR_SUFFIX}==> " "$@" + local timestamp=$(date +"%m%d %H:%M:%S") + local reset_color='\033[0m' + echo_log -e "${COLOR_GREEN}[success ${timestamp}]${COLOR_SUFFIX}==> ${COLOR_GREEN}$@${reset_color}" } + + + function openim::log::test_log() { echo_log "test log" openim::log::info "openim::log::info" diff --git a/scripts/lib/util.sh b/scripts/lib/util.sh index 1bdb7f6404..4322255bba 100755 --- a/scripts/lib/util.sh +++ b/scripts/lib/util.sh @@ -298,7 +298,7 @@ openim::util::check_ports() { # An array to collect information about processes that are running. local started=() - openim::log::info "Checking ports: $*" + echo "Checking ports: $*" # Iterate over each given port. for port in "$@"; do # Initialize variables @@ -344,7 +344,7 @@ openim::util::check_ports() { # Print information about ports whose processes are not running. if [[ ${#not_started[@]} -ne 0 ]]; then - openim::log::info "\n### Not started ports:" + echo "### Not started ports:" for port in "${not_started[@]}"; do openim::log::error "Port $port is not started." done @@ -352,20 +352,20 @@ openim::util::check_ports() { # Print information about ports whose processes are running. if [[ ${#started[@]} -ne 0 ]]; then - openim::log::info "\n### Started ports:" + echo "### Started ports:" for info in "${started[@]}"; do - openim::log::info "$info" + echo "$info" done fi # If any of the processes is not running, return a status of 1. if [[ ${#not_started[@]} -ne 0 ]]; then - openim::color::echo $COLOR_RED " OpenIM Stdout Log >> cat ${LOG_FILE}" - openim::color::echo $COLOR_RED " OpenIM Stderr Log >> cat ${STDERR_LOG_FILE}" + openim::color::echo $COLOR_RED "OpenIM Stdout Log >> cat ${LOG_FILE}" + openim::color::echo $COLOR_RED "OpenIM Stderr Log >> cat ${STDERR_LOG_FILE}" cat "$TMP_LOG_FILE" | awk '{print "\033[31m" $0 "\033[0m"}' return 1 else - openim::log::success "All specified processes are running." + #openim::log::success "All specified ports are running." return 0 fi } @@ -373,7 +373,7 @@ openim::util::check_ports() { # set +o errexit # Sample call for testing: # openim::util::check_ports 10002 1004 12345 13306 -# set -o errexit +# # The `openim::util::check_process_names` function analyzes the state of processes based on given names. # It accepts multiple process names as arguments and prints: @@ -402,7 +402,6 @@ openim::util::check_process_names() { local not_started=() local started=() - openim::log::info "Checking processes: $*" # Iterate over each given process name for process_name in "$@"; do # Use `pgrep` to find process IDs related to the given process name @@ -430,24 +429,24 @@ openim::util::check_process_names() { # Print information if [[ ${#not_started[@]} -ne 0 ]]; then - openim::log::info "Not started processes:" + echo "Not started processes:" for process_name in "${not_started[@]}"; do - openim::log::error "Process $process_name is not started." + echo "Process $process_name is not started." done fi if [[ ${#started[@]} -ne 0 ]]; then echo - openim::log::info "Started processes:" + echo "Started processes:" for info in "${started[@]}"; do - openim::log::info "$info" + echo "$info" done fi # Return status if [[ ${#not_started[@]} -ne 0 ]]; then - openim::color::echo $COLOR_RED " OpenIM Stdout Log >> cat ${LOG_FILE}" - openim::color::echo $COLOR_RED " OpenIM Stderr Log >> cat ${STDERR_LOG_FILE}" + openim::color::echo $COLOR_RED "OpenIM Stdout Log >> cat ${LOG_FILE}" + openim::color::echo $COLOR_RED "OpenIM Stderr Log >> cat ${STDERR_LOG_FILE}" cat "$TMP_LOG_FILE" | awk '{print "\033[31m" $0 "\033[0m"}' return 1 else @@ -457,6 +456,66 @@ openim::util::check_process_names() { fi } +openim::util::check_process_names_for_stop() { + # Function to get the port of a process + get_port() { + local pid=$1 + if [[ "$OSTYPE" == "linux-gnu"* ]]; then + # Linux + ss -ltnp 2>/dev/null | grep $pid | awk '{print $4}' | cut -d ':' -f2 + elif [[ "$OSTYPE" == "darwin"* ]]; then + # macOS + lsof -nP -iTCP -sTCP:LISTEN -a -p $pid | awk 'NR>1 {print $9}' | sed 's/.*://' + else + echo "Unsupported OS" + return 1 + fi + } + + # Arrays to collect details of processes + local not_started=() + local started=() + + + # Iterate over each given process name + for process_name in "$@"; do + # Use `pgrep` to find process IDs related to the given process name + local pids=($(pgrep -f $process_name)) + + # Check if any process IDs were found + if [[ ${#pids[@]} -eq 0 ]]; then + not_started+=($process_name) + else + # If there are PIDs, loop through each one + for pid in "${pids[@]}"; do + local command=$(ps -p $pid -o cmd=) + local start_time=$(ps -p $pid -o lstart=) + local port=$(get_port $pid) + + # Check if port information was found for the PID + if [[ -z $port ]]; then + port="N/A" + fi + + started+=("Process $process_name - Command: $command, PID: $pid, Port: $port, Start time: $start_time") + done + fi + done + + + if [[ ${#started[@]} -ne 0 ]]; then + echo + echo "The programs that have not exited are:" + for info in "${started[@]}"; do + echo "$info " + done + return 1 + fi + + return 0 + +} + # openim::util::check_process_names docker-pr # The `openim::util::stop_services_on_ports` function stops services running on specified ports. @@ -473,7 +532,7 @@ openim::util::stop_services_on_ports() { # An array to collect information about processes that were stopped. local stopped=() - openim::log::info "Stopping services on ports: $*" + echo "Stopping services on ports: $*" # Iterate over each given port. for port in "$@"; do # Use the `lsof` command to find process information related to the given port. @@ -497,7 +556,7 @@ openim::util::stop_services_on_ports() { # Print information about ports whose processes couldn't be stopped. if [[ ${#not_stopped[@]} -ne 0 ]]; then - openim::log::info "Ports that couldn't be stopped:" + echo "Ports that couldn't be stopped:" for port in "${not_stopped[@]}"; do openim::log::status "Failed to stop service on port $port." done @@ -506,7 +565,7 @@ openim::util::stop_services_on_ports() { # Print information about ports whose processes were successfully stopped. if [[ ${#stopped[@]} -ne 0 ]]; then for port in "${stopped[@]}"; do - openim::log::info "Successfully stopped service on port $port." + echo "Successfully stopped service on port $port." done fi @@ -539,7 +598,7 @@ openim::util::stop_services_with_name() { # An array to collect information about processes that were stopped. local stopped=() - openim::log::info "Stopping services with names: $*" + echo "Stopping services with names: $*" # Iterate over each given service name. for server_name in "$@"; do # Use the `pgrep` command to find process IDs related to the given service name. @@ -573,26 +632,8 @@ openim::util::stop_services_with_name() { not_stopped+=("$server_name") fi done + return 0 - # Print information about services whose processes couldn't be stopped. - if [[ ${#not_stopped[@]} -ne 0 ]]; then - openim::log::info "Services that couldn't be stopped:" - for name in "${not_stopped[@]}"; do - openim::log::status "Failed to stop the $name service." - done - fi - - # Print information about services whose processes were successfully stopped. - if [[ ${#stopped[@]} -ne 0 ]]; then - echo - openim::log::info "Stopped services:" - for name in "${stopped[@]}"; do - openim::log::info "Successfully stopped the $name service." - done - fi - - openim::log::success "All specified services were stopped." - echo "" } # sleep 333333& # sleep 444444& @@ -1531,7 +1572,7 @@ openim::util::check_ports() { # An array to collect information about processes that are running. local started=() - openim::log::info "Checking ports: $*" + echo "Checking ports: $*" # Iterate over each given port. for port in "$@"; do # Initialize variables @@ -1577,7 +1618,7 @@ openim::util::check_ports() { # Print information about ports whose processes are not running. if [[ ${#not_started[@]} -ne 0 ]]; then - openim::log::info "\n### Not started ports:" + printf "\n### Not started ports:" for port in "${not_started[@]}"; do openim::log::error "Port $port is not started." done @@ -1585,16 +1626,16 @@ openim::util::check_ports() { # Print information about ports whose processes are running. if [[ ${#started[@]} -ne 0 ]]; then - openim::log::info "\n### Started ports:" + printf "\n### Started ports:" for info in "${started[@]}"; do - openim::log::info "$info" + echo "$info" done fi # If any of the processes is not running, return a status of 1. if [[ ${#not_started[@]} -ne 0 ]]; then - openim::color::echo $COLOR_RED " OpenIM Stdout Log >> cat ${LOG_FILE}" - openim::color::echo $COLOR_RED " OpenIM Stderr Log >> cat ${STDERR_LOG_FILE}" + openim::color::echo $COLOR_RED "OpenIM Stdout Log >> cat ${LOG_FILE}" + openim::color::echo $COLOR_RED "OpenIM Stderr Log >> cat ${STDERR_LOG_FILE}" echo "" cat "$TMP_LOG_FILE" | awk '{print "\033[31m" $0 "\033[0m"}' return 1 @@ -1607,7 +1648,7 @@ openim::util::check_ports() { # set +o errexit # Sample call for testing: # openim::util::check_ports 10002 1004 12345 13306 -# set -o errexit +# # The `openim::util::check_process_names` function analyzes the state of processes based on given names. # It accepts multiple process names as arguments and prints: @@ -1636,7 +1677,7 @@ openim::util::check_process_names() { local not_started=() local started=() - openim::log::info "Checking processes: $*" + echo "Checking processes: $*" # Iterate over each given process name for process_name in "$@"; do # Use `pgrep` to find process IDs related to the given process name @@ -1664,7 +1705,7 @@ openim::util::check_process_names() { # Print information if [[ ${#not_started[@]} -ne 0 ]]; then - openim::log::info "Not started processes:" + echo "Not started processes:" for process_name in "${not_started[@]}"; do openim::log::error "Process $process_name is not started." done @@ -1672,9 +1713,9 @@ openim::util::check_process_names() { if [[ ${#started[@]} -ne 0 ]]; then echo - openim::log::info "Started processes:" + echo "Started processes:" for info in "${started[@]}"; do - openim::log::info "$info" + echo "$info" done fi @@ -1707,7 +1748,7 @@ openim::util::stop_services_on_ports() { # An array to collect information about processes that were stopped. local stopped=() - openim::log::info "Stopping services on ports: $*" + echo "Stopping services on ports: $*" # Iterate over each given port. for port in "$@"; do # Use the `lsof` command to find process information related to the given port. @@ -1731,7 +1772,7 @@ openim::util::stop_services_on_ports() { # Print information about ports whose processes couldn't be stopped. if [[ ${#not_stopped[@]} -ne 0 ]]; then - openim::log::info "Ports that couldn't be stopped:" + echo "Ports that couldn't be stopped:" for port in "${not_stopped[@]}"; do openim::log::status "Failed to stop service on port $port." done @@ -1740,7 +1781,7 @@ openim::util::stop_services_on_ports() { # Print information about ports whose processes were successfully stopped. if [[ ${#stopped[@]} -ne 0 ]]; then for port in "${stopped[@]}"; do - openim::log::info "Successfully stopped service on port $port." + echo "Successfully stopped service on port $port." done fi @@ -1773,7 +1814,7 @@ openim::util::stop_services_with_name() { # An array to collect information about processes that were stopped. local stopped=() - openim::log::info "Stopping services with names: $*" + echo "Stopping services with names: $*" # Iterate over each given service name. for server_name in "$@"; do # Use the `pgrep` command to find process IDs related to the given service name. @@ -1810,7 +1851,7 @@ openim::util::stop_services_with_name() { # Print information about services whose processes couldn't be stopped. if [[ ${#not_stopped[@]} -ne 0 ]]; then - openim::log::info "Services that couldn't be stopped:" + echo "Services that couldn't be stopped:" for name in "${not_stopped[@]}"; do openim::log::status "Failed to stop the $name service." done @@ -1819,9 +1860,9 @@ openim::util::stop_services_with_name() { # Print information about services whose processes were successfully stopped. if [[ ${#stopped[@]} -ne 0 ]]; then echo - openim::log::info "Stopped services:" + echo "Stopped services:" for name in "${stopped[@]}"; do - openim::log::info "Successfully stopped the $name service." + echo "Successfully stopped the $name service." done fi @@ -2822,6 +2863,46 @@ function openim::util::gen_os_arch() { fi } + + +function openim::util::check_process_names_for_stop() { + local all_stopped=true + for service in "${OPENIM_ALL_SERVICE_LIBRARIES[@]}"; do + + PIDS=$(pgrep -f "${service}") || PIDS="0" + if [ "$PIDS" = "0" ]; then + continue + fi + + + NUM_PROCESSES=$(echo "$PIDS" | wc -l | xargs) + if [ "$NUM_PROCESSES" -gt 0 ]; then + all_stopped=false + echo "Found $NUM_PROCESSES processes for ${service}" + for PID in $PIDS; do + if [[ "$OSTYPE" == "linux-gnu"* ]]; then + echo -e "\033[31m$(ps -p $PID -o pid,cmd)\033[0m" + elif [[ "$OSTYPE" == "darwin"* ]]; then + echo -e "\033[31m$(ps -p $PID -o pid,comm)\033[0m" + else + openim::log::error "Unsupported OS type: $OSTYPE" + fi + done + echo "Processes for ${service} have not been stopped properly. " "$NUM_PROCESSES" + fi + done + + if [ "$all_stopped" = true ]; then + openim::log::success "All processes have been stopped properly." + return 0 + fi + + return 1 +} + + + + if [[ "$*" =~ openim::util:: ]];then eval $* -fi \ No newline at end of file +fi diff --git a/scripts/list-feature-tests.sh b/scripts/list-feature-tests.sh index 438474baea..d6eaa48731 100755 --- a/scripts/list-feature-tests.sh +++ b/scripts/list-feature-tests.sh @@ -18,9 +18,9 @@ # # Usage: `scripts/list-feature-tests.sh`. -set -o errexit -set -o nounset -set -o pipefail + + + OPENIM_ROOT=$(dirname "${BASH_SOURCE[0]}")/.. grep "\[Feature:\w+\]" "${OPENIM_ROOT}"/test/e2e/**/*.go -Eoh | LC_ALL=C sort -u \ No newline at end of file diff --git a/scripts/release.sh b/scripts/release.sh index a34d5ee229..eb8b04359f 100755 --- a/scripts/release.sh +++ b/scripts/release.sh @@ -47,9 +47,9 @@ # images and other build artifacts. # Build a OpenIM release. This script supports various flags for flexible execution control. -set -o errexit -set -o nounset -set -o pipefail + + + OPENIM_ROOT=$(dirname "${BASH_SOURCE[0]}")/.. source "${OPENIM_ROOT}/scripts/common.sh" source "${OPENIM_ROOT}/scripts/lib/release.sh" diff --git a/scripts/run-in-gopath.sh b/scripts/run-in-gopath.sh index 9bb8ec8821..6af9869757 100755 --- a/scripts/run-in-gopath.sh +++ b/scripts/run-in-gopath.sh @@ -20,9 +20,9 @@ # the project. # Usage: `scripts/run-in-gopath.sh `. -set -o errexit -set -o nounset -set -o pipefail + + + OPENIM_ROOT=$(dirname "${BASH_SOURCE[0]}")/.. source "${OPENIM_ROOT}/scripts/lib/init.sh" diff --git a/scripts/start-all.sh b/scripts/start-all.sh index ca03f0c3ce..9a98bfca3a 100755 --- a/scripts/start-all.sh +++ b/scripts/start-all.sh @@ -16,70 +16,100 @@ #FIXME This script is the startup script for multiple servers. #FIXME The full names of the shell scripts that need to be started are placed in the `need_to_start_server_shell` array. -set -o nounset -set -o pipefail -OPENIM_ROOT=$(dirname "${BASH_SOURCE[0]}")/.. -source "${OPENIM_ROOT}/scripts/install/common.sh" -openim::log::info "\n# Begin to start all openim service scripts" -set +o errexit -openim::golang::check_openim_binaries -if [[ $? -ne 0 ]]; then - openim::log::error "OpenIM binaries are not found. Please run 'make build' to build binaries." - "${OPENIM_ROOT}"/scripts/build-all-service.sh -fi -set -o errexit - -"${OPENIM_ROOT}"/scripts/init-config.sh --skip +OPENIM_ROOT=$(dirname "${BASH_SOURCE[0]}")/.. +source "${OPENIM_ROOT}/scripts/install/common.sh" -echo "You need to start the following scripts in order: ${OPENIM_SERVER_SCRIPTARIES[@]}" -openim::log::install_errexit # Function to execute the scripts. -function execute_scripts() { +function execute_start_scripts() { for script_path in "${OPENIM_SERVER_SCRIPT_START_LIST[@]}"; do # Extract the script name without extension for argument generation. script_name_with_prefix=$(basename "$script_path" .sh) - + # Remove the "openim-" prefix. script_name=${script_name_with_prefix#openim-} - + # Construct the argument based on the script name. arg="openim::${script_name}::start" - + # Check if the script file exists and is executable. if [[ -x "$script_path" ]]; then - openim::log::status "Starting script: ${script_path##*/}" # Log the script name. - + openim::log::info "Starting script: ${script_path##*/}" # Log the script name. + # Execute the script with the constructed argument. - "$script_path" "$arg" - - # Check if the script executed successfully. - if [[ $? -eq 0 ]]; then - openim::log::info "${script_path##*/} executed successfully." - else - openim::log::errexit "Error executing ${script_path##*/}." + result=$("$script_path" "$arg") + if [[ $? -ne 0 ]]; then + openim::log::error "Start script: ${script_path##*/} failed" + openim::log::error "$result" + return 1 fi + else openim::log::errexit "Script ${script_path##*/} is missing or not executable." + return 1 fi done - sleep 0.5 } + + + + + +openim::golang::check_openim_binaries +if [[ $? -ne 0 ]]; then + openim::log::error "OpenIM binaries are not found. Please run 'make build' to build binaries." + "${OPENIM_ROOT}"/scripts/build-all-service.sh +fi + + +"${OPENIM_ROOT}"/scripts/init-config.sh --skip + +echo "You need to start the following scripts in order: ${OPENIM_SERVER_SCRIPTARIES[@]}" + + # TODO Prelaunch tools, simple for now, can abstract functions later TOOLS_START_SCRIPTS_PATH=${START_SCRIPTS_PATH}/openim-tools.sh -openim::log::info "\n## Pre Starting OpenIM services" +openim::log::status "\n## Pre Starting OpenIM services" ${TOOLS_START_SCRIPTS_PATH} openim::tools::pre-start -openim::log::info "\n## Starting OpenIM services" -execute_scripts -openim::log::info "\n## Post Starting OpenIM services" +result=$("${OPENIM_ROOT}"/scripts/stop-all.sh) +if [[ $? -ne 0 ]]; then + echo "+++ cat openim log file >>> ${LOG_FILE}" + openim::log::error "Some programs have not exited; the start process is aborted .\n $result" + exit 1 +fi + + + +openim::log::status "\n## Starting openim scripts: " +execute_start_scripts + +sleep 2 + +result=$(. $(dirname ${BASH_SOURCE})/install/openim-msgtransfer.sh openim::msgtransfer::check) +if [[ $? -ne 0 ]]; then + echo "+++ cat openim log file >>> ${LOG_FILE}" + openim::log::error "The program may fail to start.\n $result" + exit 1 +fi + + +result=$(openim::util::check_process_names ${OPENIM_ALL_SERVICE_LIBRARIES_NO_TRANSFER[@]}) +if [[ $? -ne 0 ]]; then + echo "+++ cat openim log file >>> ${LOG_FILE}" + openim::log::error "The program may fail to start.\n $result" + exit 1 +fi + + +openim::log::info "\n## Post Starting openim services" ${TOOLS_START_SCRIPTS_PATH} openim::tools::post-start -openim::color::echo $COLOR_BLUE "✨ All OpenIM services have been successfully started!" \ No newline at end of file +openim::log::success "All openim services have been successfully started!" \ No newline at end of file diff --git a/scripts/stop-all.sh b/scripts/stop-all.sh index 2acb9cdc52..b2572f7d5e 100755 --- a/scripts/stop-all.sh +++ b/scripts/stop-all.sh @@ -18,22 +18,43 @@ # Usage: `scripts/stop.sh`. # Encapsulated as: `make stop`. -set -o errexit -set -o nounset -set -o pipefail + + + OPENIM_ROOT=$(dirname "${BASH_SOURCE[0]}")/.. source "${OPENIM_ROOT}/scripts/install/common.sh" -openim::log::info "\n# Begin to stop all openim service" +openim::log::status "Begin to stop all openim service" -echo "++ Ready to stop port: ${OPENIM_SERVER_PORT_LISTARIES[@]}" +openim::log::status "Stop all processes in the path ${OPENIM_OUTPUT_HOSTBIN}" -openim::util::stop_services_on_ports ${OPENIM_SERVER_PORT_LISTARIES[@]} +openim::util::stop_services_with_name "${OPENIM_OUTPUT_HOSTBIN}" +# todo OPENIM_ALL_SERVICE_LIBRARIES -echo -e "\n++ Stop all processes in the path ${OPENIM_OUTPUT_HOSTBIN}" -openim::util::stop_services_with_name "${OPENIM_OUTPUT_HOSTBIN}" -openim::log::success "✨ All processes to be killed" \ No newline at end of file + +max_retries=15 +attempt=0 + +while [[ $attempt -lt $max_retries ]] +do + result=$(openim::util::check_process_names_for_stop) + + if [[ $? -ne 0 ]]; then + if [[ $attempt -ne 0 ]] ; then + echo "+++ cat openim log file >>> ${LOG_FILE} " $attempt + openim::log::error "stop process failed. continue waiting\n" "${result}" + fi + sleep 1 + ((attempt++)) + else + openim::log::success " All openim processes to be stopped" + exit 0 + fi +done + +openim::log::error "openim processes stopped failed" +exit 1 diff --git a/scripts/update-generated-docs.sh b/scripts/update-generated-docs.sh index c37c4a1f9e..d48a4067be 100755 --- a/scripts/update-generated-docs.sh +++ b/scripts/update-generated-docs.sh @@ -18,9 +18,9 @@ # immediately before exporting docs. We do not want to check these documents in # by default. -set -o errexit -set -o nounset -set -o pipefail + + + OPENIM_ROOT=$(dirname "${BASH_SOURCE[0]}")/.. source "${OPENIM_ROOT}/scripts/lib/init.sh" diff --git a/scripts/update-yamlfmt.sh b/scripts/update-yamlfmt.sh index 90ec8aa627..24ec60de91 100755 --- a/scripts/update-yamlfmt.sh +++ b/scripts/update-yamlfmt.sh @@ -14,9 +14,9 @@ # limitations under the License. -set -o errexit -set -o nounset -set -o pipefail + + + OPENIM_ROOT=$(dirname "${BASH_SOURCE[0]}")/.. source "${OPENIM_ROOT}/scripts/lib/init.sh" diff --git a/scripts/verify-pkg-names.sh b/scripts/verify-pkg-names.sh index 1459992e9d..7fce3d7adb 100755 --- a/scripts/verify-pkg-names.sh +++ b/scripts/verify-pkg-names.sh @@ -17,9 +17,9 @@ # This script verifies whether codes follow golang convention. # Usage: `scripts/verify-pkg-names.sh`. -set -o errexit -set -o nounset -set -o pipefail + + + OPENIM_ROOT=$(dirname "${BASH_SOURCE[0]}")/.. source "${OPENIM_ROOT}/scripts/lib/init.sh" diff --git a/scripts/verify-shellcheck.sh b/scripts/verify-shellcheck.sh index 8a5ad7321e..c7e713d093 100755 --- a/scripts/verify-shellcheck.sh +++ b/scripts/verify-shellcheck.sh @@ -17,9 +17,9 @@ # This script lints each shell script by `shellcheck`. # Usage: `scripts/verify-shellcheck.sh`. -set -o errexit -set -o nounset -set -o pipefail + + + OPENIM_ROOT=$(dirname "${BASH_SOURCE[0]}")/.. source "${OPENIM_ROOT}/scripts/lib/init.sh" diff --git a/scripts/verify-spelling.sh b/scripts/verify-spelling.sh index 2c02dccf7d..fa0852866d 100755 --- a/scripts/verify-spelling.sh +++ b/scripts/verify-spelling.sh @@ -17,9 +17,9 @@ # working directory by client9/misspell package. # Usage: `scripts/verify-spelling.sh`. -set -o errexit -set -o nounset -set -o pipefail + + + OPENIM_ROOT=$(dirname "${BASH_SOURCE[0]}")/.. export OPENIM_ROOT diff --git a/scripts/verify-typecheck.sh b/scripts/verify-typecheck.sh index 62fca40491..c9b2aaf309 100755 --- a/scripts/verify-typecheck.sh +++ b/scripts/verify-typecheck.sh @@ -16,9 +16,9 @@ # This script does a fast type check of script srnetes code for all platforms. # Usage: `scripts/verify-typecheck.sh`. -set -o errexit -set -o nounset -set -o pipefail + + + OPENIM_ROOT=$(dirname "${BASH_SOURCE[0]}")/.. source "${OPENIM_ROOT}/scripts/lib/init.sh" diff --git a/scripts/verify-yamlfmt.sh b/scripts/verify-yamlfmt.sh index 3d0a0180dd..3acbf457c9 100755 --- a/scripts/verify-yamlfmt.sh +++ b/scripts/verify-yamlfmt.sh @@ -19,9 +19,9 @@ # # Usage: `scripts/verify-yamlfmt.sh`. -set -o errexit -set -o nounset -set -o pipefail + + + OPENIM_ROOT=$(dirname "${BASH_SOURCE[0]}")/.. source "${OPENIM_ROOT}/scripts/lib/init.sh" From 2becd46bdd9e544101dcb45e9fe6fec62e8fbabf Mon Sep 17 00:00:00 2001 From: longyuqing112 <105913803+longyuqing112@users.noreply.github.com> Date: Tue, 27 Feb 2024 22:12:01 +0800 Subject: [PATCH 068/188] Fix lint errors in modified code in the /pkg directory (#1962) * /pkg-make lint Signed-off-by: longyuqing112 <105913803+longyuqing112@users.noreply.github.com> * /pkg_make_lint Signed-off-by: longyuqing112 <105913803+longyuqing112@users.noreply.github.com> --------- Signed-off-by: longyuqing112 <105913803+longyuqing112@users.noreply.github.com> --- go.mod | 1 + go.sum | 2 ++ pkg/common/db/s3/aws/aws.go | 2 +- pkg/common/db/unrelation/user.go | 2 +- pkg/common/kafka/producer.go | 8 +++++++- pkg/rpcclient/notification/friend.go | 10 ++++++++-- pkg/rpcclient/notification/group.go | 13 +++++++------ pkg/rpcclient/notification/user.go | 8 ++++---- 8 files changed, 31 insertions(+), 15 deletions(-) diff --git a/go.mod b/go.mod index 30bfcf146d..6194cd5443 100644 --- a/go.mod +++ b/go.mod @@ -121,6 +121,7 @@ require ( github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect github.com/rs/xid v1.5.0 // indirect github.com/sergi/go-diff v1.0.0 // indirect + github.com/smallstep/cli v0.25.2 // indirect github.com/src-d/gcfg v1.4.0 // indirect github.com/stretchr/objx v0.5.0 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect diff --git a/go.sum b/go.sum index 6277afac39..7e181fd5db 100644 --- a/go.sum +++ b/go.sum @@ -312,6 +312,8 @@ github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/smallstep/cli v0.25.2 h1:vkwnKLAAXj9vA3SJHqa0ytz2orHMUJn/glv79UuAthQ= +github.com/smallstep/cli v0.25.2/go.mod h1:g0jvoTvGKFhw2PeFXwA2E99k9rTX4J3Vc983i+jbVKM= github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= diff --git a/pkg/common/db/s3/aws/aws.go b/pkg/common/db/s3/aws/aws.go index 42d5cd14c1..d996485c73 100644 --- a/pkg/common/db/s3/aws/aws.go +++ b/pkg/common/db/s3/aws/aws.go @@ -259,7 +259,7 @@ func (a *Aws) StatObject(ctx context.Context, name string) (*s3.ObjectInfo, erro return res, nil } -// AccessURL todo +// AccessURL todo. func (a *Aws) AccessURL(ctx context.Context, name string, expire time.Duration, opt *s3.AccessURLOption) (string, error) { // todo return "", nil diff --git a/pkg/common/db/unrelation/user.go b/pkg/common/db/unrelation/user.go index f5595c4ebb..4c882fc645 100644 --- a/pkg/common/db/unrelation/user.go +++ b/pkg/common/db/unrelation/user.go @@ -64,7 +64,7 @@ func (u *UserMongoDriver) AddSubscriptionList(ctx context.Context, userID string } // iterate over aggregated results for cursor.Next(ctx) { - err := cursor.Decode(&cnt) + err = cursor.Decode(&cnt) if err != nil { return errs.Wrap(err) } diff --git a/pkg/common/kafka/producer.go b/pkg/common/kafka/producer.go index c2e0f33dc2..bdb8394048 100644 --- a/pkg/common/kafka/producer.go +++ b/pkg/common/kafka/producer.go @@ -29,6 +29,8 @@ import ( "github.com/OpenIMSDK/tools/mcontext" "google.golang.org/protobuf/proto" + "fmt" + "github.com/openimsdk/open-im-server/v3/pkg/common/config" ) @@ -118,7 +120,11 @@ func configureProducerAck(p *Producer, ackConfig string) { // configureCompression configures the message compression type for the producer. func configureCompression(p *Producer, compressType string) { var compress sarama.CompressionCodec = sarama.CompressionNone - compress.UnmarshalText(bytes.ToLower([]byte(compressType))) + err := compress.UnmarshalText(bytes.ToLower([]byte(compressType))) + if err != nil { + fmt.Printf("Failed to configure compression: %v\n", err) + return + } p.config.Producer.Compression = compress } diff --git a/pkg/rpcclient/notification/friend.go b/pkg/rpcclient/notification/friend.go index b98a1d38e6..a55bc0e5ef 100644 --- a/pkg/rpcclient/notification/friend.go +++ b/pkg/rpcclient/notification/friend.go @@ -109,6 +109,7 @@ func (f *FriendNotificationSender) getUsersInfoMap( return result, nil } +//nolint:unused func (f *FriendNotificationSender) getFromToUserNickname( ctx context.Context, fromUserID, toUserID string, @@ -214,7 +215,9 @@ func (f *FriendNotificationSender) BlackDeletedNotification(ctx context.Context, FromUserID: req.OwnerUserID, ToUserID: req.BlackUserID, }} - f.Notification(ctx, req.OwnerUserID, req.BlackUserID, constant.BlackDeletedNotification, &blackDeletedTips) + if err := f.Notification(ctx, req.OwnerUserID, req.BlackUserID, constant.BlackDeletedNotification, &blackDeletedTips); err != nil { + //err + } } func (f *FriendNotificationSender) FriendInfoUpdatedNotification( @@ -223,5 +226,8 @@ func (f *FriendNotificationSender) FriendInfoUpdatedNotification( needNotifiedUserID string, ) { tips := sdkws.UserInfoUpdatedTips{UserID: changedUserID} - f.Notification(ctx, mcontext.GetOpUserID(ctx), needNotifiedUserID, constant.FriendInfoUpdatedNotification, &tips) + if err := f.Notification(ctx, mcontext.GetOpUserID(ctx), needNotifiedUserID, + constant.FriendInfoUpdatedNotification, &tips); err != nil { + // err + } } diff --git a/pkg/rpcclient/notification/group.go b/pkg/rpcclient/notification/group.go index 7f40326b76..d336e4b129 100755 --- a/pkg/rpcclient/notification/group.go +++ b/pkg/rpcclient/notification/group.go @@ -192,6 +192,7 @@ func (g *GroupNotificationSender) getGroupOwnerAndAdminUserID(ctx context.Contex return utils.Slice(members, fn), nil } +//nolint:unused func (g *GroupNotificationSender) groupDB2PB(group *relation.GroupModel, ownerUserID string, memberCount uint32) *sdkws.GroupInfo { return &sdkws.GroupInfo{ GroupID: group.GroupID, @@ -231,7 +232,7 @@ func (g *GroupNotificationSender) groupMemberDB2PB(member *relation.GroupMemberM } } -func (g *GroupNotificationSender) getUsersInfoMap(ctx context.Context, userIDs []string) (map[string]*sdkws.UserInfo, error) { +/* func (g *GroupNotificationSender) getUsersInfoMap(ctx context.Context, userIDs []string) (map[string]*sdkws.UserInfo, error) { users, err := g.getUsersInfo(ctx, userIDs) if err != nil { return nil, err @@ -241,7 +242,7 @@ func (g *GroupNotificationSender) getUsersInfoMap(ctx context.Context, userIDs [ result[user.GetUserID()] = user.(*sdkws.UserInfo) } return result, nil -} +} */ func (g *GroupNotificationSender) fillOpUser(ctx context.Context, opUser **sdkws.GroupMemberFullInfo, groupID string) (err error) { defer log.ZDebug(ctx, "return") @@ -266,11 +267,11 @@ func (g *GroupNotificationSender) fillOpUser(ctx context.Context, opUser **sdkws AppMangerLevel: constant.AppAdmin, } } else { - member, err := g.db.TakeGroupMember(ctx, groupID, userID) - if err == nil { + member, err2 := g.db.TakeGroupMember(ctx, groupID, userID) + if err2 == nil { *opUser = g.groupMemberDB2PB(member, 0) - } else if !errs.ErrRecordNotFound.Is(err) { - return err + } else if !errs.ErrRecordNotFound.Is(err2) { + return err2 } } } diff --git a/pkg/rpcclient/notification/user.go b/pkg/rpcclient/notification/user.go index 4347faece7..13e5b6abb6 100644 --- a/pkg/rpcclient/notification/user.go +++ b/pkg/rpcclient/notification/user.go @@ -71,7 +71,7 @@ func NewUserNotificationSender( return f } -func (u *UserNotificationSender) getUsersInfoMap( +/* func (u *UserNotificationSender) getUsersInfoMap( ctx context.Context, userIDs []string, ) (map[string]*sdkws.UserInfo, error) { @@ -84,9 +84,9 @@ func (u *UserNotificationSender) getUsersInfoMap( result[user.GetUserID()] = user.(*sdkws.UserInfo) } return result, nil -} +} */ -func (u *UserNotificationSender) getFromToUserNickname( +/* func (u *UserNotificationSender) getFromToUserNickname( ctx context.Context, fromUserID, toUserID string, ) (string, string, error) { @@ -95,7 +95,7 @@ func (u *UserNotificationSender) getFromToUserNickname( return "", "", nil } return users[fromUserID].Nickname, users[toUserID].Nickname, nil -} +} */ func (u *UserNotificationSender) UserStatusChangeNotification( ctx context.Context, From 613bacb78912f391ee5697a769c8d37622a82645 Mon Sep 17 00:00:00 2001 From: OpenIM Bot <124379614+kubbot@users.noreply.github.com> Date: Wed, 28 Feb 2024 11:01:30 +0800 Subject: [PATCH 069/188] cicd: bump League Patch (#1963) --- go.mod | 1 - go.sum | 2 -- internal/msgtransfer/init.go | 1 + pkg/common/kafka/consumer_group.go | 1 + 4 files changed, 2 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 6194cd5443..30bfcf146d 100644 --- a/go.mod +++ b/go.mod @@ -121,7 +121,6 @@ require ( github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect github.com/rs/xid v1.5.0 // indirect github.com/sergi/go-diff v1.0.0 // indirect - github.com/smallstep/cli v0.25.2 // indirect github.com/src-d/gcfg v1.4.0 // indirect github.com/stretchr/objx v0.5.0 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect diff --git a/go.sum b/go.sum index 7e181fd5db..6277afac39 100644 --- a/go.sum +++ b/go.sum @@ -312,8 +312,6 @@ github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= -github.com/smallstep/cli v0.25.2 h1:vkwnKLAAXj9vA3SJHqa0ytz2orHMUJn/glv79UuAthQ= -github.com/smallstep/cli v0.25.2/go.mod h1:g0jvoTvGKFhw2PeFXwA2E99k9rTX4J3Vc983i+jbVKM= github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= diff --git a/internal/msgtransfer/init.go b/internal/msgtransfer/init.go index df06ec0f92..91a5474409 100644 --- a/internal/msgtransfer/init.go +++ b/internal/msgtransfer/init.go @@ -20,6 +20,7 @@ import ( "fmt" "github.com/OpenIMSDK/tools/errs" + util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" "net/http" diff --git a/pkg/common/kafka/consumer_group.go b/pkg/common/kafka/consumer_group.go index d63527620b..ed961b93e4 100644 --- a/pkg/common/kafka/consumer_group.go +++ b/pkg/common/kafka/consumer_group.go @@ -17,6 +17,7 @@ package kafka import ( "context" "errors" + "github.com/IBM/sarama" "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/log" From bcc6a95633e544f5493e70e0b54227b65100bc54 Mon Sep 17 00:00:00 2001 From: xuan <146319162+wxuanF@users.noreply.github.com> Date: Thu, 29 Feb 2024 11:52:41 +0800 Subject: [PATCH 070/188] Fix lint errors in modified code (#1966) * makelint /internal 0228 Signed-off-by: xuan <146319162+wxuanF@users.noreply.github.com> * Update server.go --------- Signed-off-by: xuan <146319162+wxuanF@users.noreply.github.com> --- internal/push/consumer_init.go | 5 +++-- internal/rpc/friend/black.go | 2 +- internal/rpc/friend/friend.go | 16 ++++++++-------- internal/rpc/group/group.go | 28 ++++++++++++++-------------- internal/rpc/msg/as_read.go | 2 +- internal/rpc/msg/revoke.go | 4 ++-- internal/rpc/msg/send.go | 8 ++++---- internal/rpc/msg/server.go | 24 ++++++++++++------------ internal/rpc/third/s3.go | 6 +++--- internal/rpc/third/third.go | 2 +- internal/rpc/user/user.go | 4 ++-- 11 files changed, 51 insertions(+), 50 deletions(-) diff --git a/internal/push/consumer_init.go b/internal/push/consumer_init.go index daaa37e8a3..92ce4714e6 100644 --- a/internal/push/consumer_init.go +++ b/internal/push/consumer_init.go @@ -19,8 +19,9 @@ import ( ) type Consumer struct { - pushCh ConsumerHandler - successCount uint64 + pushCh ConsumerHandler + // successCount is unused + // successCount uint64 } func NewConsumer(pusher *Pusher) (*Consumer, error) { diff --git a/internal/rpc/friend/black.go b/internal/rpc/friend/black.go index ed5791c380..6bf780d3ae 100644 --- a/internal/rpc/friend/black.go +++ b/internal/rpc/friend/black.go @@ -28,7 +28,7 @@ import ( ) func (s *friendServer) GetPaginationBlacks(ctx context.Context, req *pbfriend.GetPaginationBlacksReq) (resp *pbfriend.GetPaginationBlacksResp, err error) { - if err := s.userRpcClient.Access(ctx, req.UserID); err != nil { + if accessErr := s.userRpcClient.Access(ctx, req.UserID); accessErr != nil { return nil, err } total, blacks, err := s.blackDatabase.FindOwnerBlacks(ctx, req.UserID, req.Pagination) diff --git a/internal/rpc/friend/friend.go b/internal/rpc/friend/friend.go index 84702f5481..a85f758c5f 100644 --- a/internal/rpc/friend/friend.go +++ b/internal/rpc/friend/friend.go @@ -115,7 +115,7 @@ func Start(client registry.SvcDiscoveryRegistry, server *grpc.Server) error { func (s *friendServer) ApplyToAddFriend(ctx context.Context, req *pbfriend.ApplyToAddFriendReq) (resp *pbfriend.ApplyToAddFriendResp, err error) { defer log.ZInfo(ctx, utils.GetFuncName()+" Return") resp = &pbfriend.ApplyToAddFriendResp{} - if err := authverify.CheckAccessV3(ctx, req.FromUserID); err != nil { + if accessErr := authverify.CheckAccessV3(ctx, req.FromUserID); accessErr != nil { return nil, err } if req.ToUserID == req.FromUserID { @@ -124,7 +124,7 @@ func (s *friendServer) ApplyToAddFriend(ctx context.Context, req *pbfriend.Apply if err = CallbackBeforeAddFriend(ctx, req); err != nil && err != errs.ErrCallbackContinue { return nil, err } - if _, err := s.userRpcClient.GetUsersInfoMap(ctx, []string{req.ToUserID, req.FromUserID}); err != nil { + if _, getUserInfoErr := s.userRpcClient.GetUsersInfoMap(ctx, []string{req.ToUserID, req.FromUserID}); getUserInfoErr != nil { return nil, err } in1, in2, err := s.friendDatabase.CheckIn(ctx, req.FromUserID, req.ToUserID) @@ -219,7 +219,7 @@ func (s *friendServer) RespondFriendApply(ctx context.Context, req *pbfriend.Res func (s *friendServer) DeleteFriend(ctx context.Context, req *pbfriend.DeleteFriendReq) (resp *pbfriend.DeleteFriendResp, err error) { defer log.ZInfo(ctx, utils.GetFuncName()+" Return") resp = &pbfriend.DeleteFriendResp{} - if err := s.userRpcClient.Access(ctx, req.OwnerUserID); err != nil { + if accessErr := s.userRpcClient.Access(ctx, req.OwnerUserID); accessErr != nil { return nil, err } _, err = s.friendDatabase.FindFriendsWithError(ctx, req.OwnerUserID, []string{req.FriendUserID}) @@ -244,7 +244,7 @@ func (s *friendServer) SetFriendRemark(ctx context.Context, req *pbfriend.SetFri return nil, err } resp = &pbfriend.SetFriendRemarkResp{} - if err := s.userRpcClient.Access(ctx, req.OwnerUserID); err != nil { + if accessErr := s.userRpcClient.Access(ctx, req.OwnerUserID); accessErr != nil { return nil, err } _, err = s.friendDatabase.FindFriendsWithError(ctx, req.OwnerUserID, []string{req.FriendUserID}) @@ -295,7 +295,7 @@ func (s *friendServer) GetDesignatedFriendsApply(ctx context.Context, // ok 获取接收到的好友申请(即别人主动申请的). func (s *friendServer) GetPaginationFriendsApplyTo(ctx context.Context, req *pbfriend.GetPaginationFriendsApplyToReq) (resp *pbfriend.GetPaginationFriendsApplyToResp, err error) { defer log.ZInfo(ctx, utils.GetFuncName()+" Return") - if err := s.userRpcClient.Access(ctx, req.UserID); err != nil { + if accessErr := s.userRpcClient.Access(ctx, req.UserID); accessErr != nil { return nil, err } total, friendRequests, err := s.friendDatabase.PageFriendRequestToMe(ctx, req.UserID, req.Pagination) @@ -315,7 +315,7 @@ func (s *friendServer) GetPaginationFriendsApplyTo(ctx context.Context, req *pbf func (s *friendServer) GetPaginationFriendsApplyFrom(ctx context.Context, req *pbfriend.GetPaginationFriendsApplyFromReq) (resp *pbfriend.GetPaginationFriendsApplyFromResp, err error) { defer log.ZInfo(ctx, utils.GetFuncName()+" Return") resp = &pbfriend.GetPaginationFriendsApplyFromResp{} - if err := s.userRpcClient.Access(ctx, req.UserID); err != nil { + if accessErr := s.userRpcClient.Access(ctx, req.UserID); accessErr != nil { return nil, err } total, friendRequests, err := s.friendDatabase.PageFriendRequestFromMe(ctx, req.UserID, req.Pagination) @@ -343,7 +343,7 @@ func (s *friendServer) IsFriend(ctx context.Context, req *pbfriend.IsFriendReq) func (s *friendServer) GetPaginationFriends(ctx context.Context, req *pbfriend.GetPaginationFriendsReq) (resp *pbfriend.GetPaginationFriendsResp, err error) { defer log.ZInfo(ctx, utils.GetFuncName()+" Return") - if err := s.userRpcClient.Access(ctx, req.UserID); err != nil { + if accessErr := s.userRpcClient.Access(ctx, req.UserID); accessErr != nil { return nil, err } total, friends, err := s.friendDatabase.PageOwnerFriends(ctx, req.UserID, req.Pagination) @@ -361,7 +361,7 @@ func (s *friendServer) GetPaginationFriends(ctx context.Context, req *pbfriend.G func (s *friendServer) GetFriendIDs(ctx context.Context, req *pbfriend.GetFriendIDsReq) (resp *pbfriend.GetFriendIDsResp, err error) { defer log.ZInfo(ctx, utils.GetFuncName()+" Return") - if err := s.userRpcClient.Access(ctx, req.UserID); err != nil { + if accessErr := s.userRpcClient.Access(ctx, req.UserID); accessErr != nil { return nil, err } resp = &pbfriend.GetFriendIDsResp{} diff --git a/internal/rpc/group/group.go b/internal/rpc/group/group.go index 95f82266f9..8bce182b84 100644 --- a/internal/rpc/group/group.go +++ b/internal/rpc/group/group.go @@ -539,7 +539,7 @@ func (s *groupServer) KickGroupMember(ctx context.Context, req *pbgroup.KickGrou if err != nil { return nil, err } - if err := s.PopulateGroupMember(ctx, members...); err != nil { + if populateErr := s.PopulateGroupMember(ctx, members...); populateErr != nil { return nil, err } memberMap := make(map[string]*relationtb.GroupMemberModel) @@ -765,12 +765,12 @@ func (s *groupServer) GroupApplicationResponse(ctx context.Context, req *pbgroup return nil, errs.ErrGroupRequestHandled.Wrap("group request already processed") } var inGroup bool - if _, err := s.db.TakeGroupMember(ctx, req.GroupID, req.FromUserID); err == nil { + if _, takeErr := s.db.TakeGroupMember(ctx, req.GroupID, req.FromUserID); takeErr == nil { inGroup = true // 已经在群里了 } else if !s.IsNotFound(err) { return nil, err } - if _, err := s.User.GetPublicUserInfo(ctx, req.FromUserID); err != nil { + if _, getInfoErr := s.User.GetPublicUserInfo(ctx, req.FromUserID); getInfoErr != nil { return nil, err } var member *relationtb.GroupMemberModel @@ -857,14 +857,14 @@ func (s *groupServer) JoinGroup(ctx context.Context, req *pbgroup.JoinGroupReq) JoinTime: time.Now(), MuteEndTime: time.UnixMilli(0), } - if err := CallbackBeforeMemberJoinGroup(ctx, groupMember, group.Ex); err != nil { + if callbackErr := CallbackBeforeMemberJoinGroup(ctx, groupMember, group.Ex); callbackErr != nil { return nil, err } - if err := s.db.CreateGroup(ctx, nil, []*relationtb.GroupMemberModel{groupMember}); err != nil { + if createErr := s.db.CreateGroup(ctx, nil, []*relationtb.GroupMemberModel{groupMember}); createErr != nil { return nil, err } - if err := s.conversationRpcClient.GroupChatFirstCreateConversation(ctx, req.GroupID, []string{req.InviterUserID}); err != nil { + if createErr := s.conversationRpcClient.GroupChatFirstCreateConversation(ctx, req.GroupID, []string{req.InviterUserID}); createErr != nil { return nil, err } s.Notification.MemberEnterNotification(ctx, req.GroupID, req.InviterUserID) @@ -905,7 +905,7 @@ func (s *groupServer) QuitGroup(ctx context.Context, req *pbgroup.QuitGroupReq) if member.RoleLevel == constant.GroupOwner { return nil, errs.ErrNoPermission.Wrap("group owner can't quit") } - if err := s.PopulateGroupMember(ctx, member); err != nil { + if populateErr := s.PopulateGroupMember(ctx, member); populateErr != nil { return nil, err } err = s.db.DeleteGroupMember(ctx, req.GroupID, []string{req.UserID}) @@ -967,14 +967,14 @@ func (s *groupServer) SetGroupInfo(ctx context.Context, req *pbgroup.SetGroupInf if err != nil { return nil, err } - if err := s.PopulateGroupMember(ctx, owner); err != nil { + if populateErr := s.PopulateGroupMember(ctx, owner); populateErr != nil { return nil, err } update := UpdateGroupInfoMap(ctx, req.GroupInfoForSet) if len(update) == 0 { return resp, nil } - if err := s.db.UpdateGroup(ctx, group.GroupID, update); err != nil { + if updateErr := s.db.UpdateGroup(ctx, group.GroupID, update); updateErr != nil { return nil, err } group, err = s.db.TakeGroup(ctx, req.GroupInfoForSet.GroupID) @@ -1168,7 +1168,7 @@ func (s *groupServer) GetUserReqApplicationList(ctx context.Context, req *pbgrou if err != nil { return nil, err } - if err := s.PopulateGroupMember(ctx, owners...); err != nil { + if populateErr := s.PopulateGroupMember(ctx, owners...); populateErr != nil { return nil, err } ownerMap := utils.SliceToMap(owners, func(e *relationtb.GroupMemberModel) string { @@ -1200,17 +1200,17 @@ func (s *groupServer) DismissGroup(ctx context.Context, req *pbgroup.DismissGrou return nil, errs.ErrNoPermission.Wrap("not group owner") } } - if err := s.PopulateGroupMember(ctx, owner); err != nil { + if populateErr := s.PopulateGroupMember(ctx, owner); populateErr != nil { return nil, err } group, err := s.db.TakeGroup(ctx, req.GroupID) if err != nil { return nil, err } - if req.DeleteMember == false && group.Status == constant.GroupStatusDismissed { + if !req.DeleteMember && group.Status == constant.GroupStatusDismissed { return nil, errs.ErrDismissedAlready.Wrap("group status is dismissed") } - if err := s.db.DismissGroup(ctx, req.GroupID, req.DeleteMember); err != nil { + if dismissErr := s.db.DismissGroup(ctx, req.GroupID, req.DeleteMember); dismissErr != nil { return nil, err } if !req.DeleteMember { @@ -1566,7 +1566,7 @@ func (s *groupServer) GetGroupUsersReqApplicationList(ctx context.Context, req * if err != nil { return nil, err } - if err := s.PopulateGroupMember(ctx, owners...); err != nil { + if populateErr := s.PopulateGroupMember(ctx, owners...); populateErr != nil { return nil, err } ownerMap := utils.SliceToMap(owners, func(e *relationtb.GroupMemberModel) string { diff --git a/internal/rpc/msg/as_read.go b/internal/rpc/msg/as_read.go index cb292421e9..c1816ce183 100644 --- a/internal/rpc/msg/as_read.go +++ b/internal/rpc/msg/as_read.go @@ -82,7 +82,7 @@ func (m *msgServer) SetConversationHasReadSeq( if req.HasReadSeq > maxSeq { return nil, errs.ErrArgs.Wrap("hasReadSeq must not be bigger than maxSeq") } - if err := m.MsgDatabase.SetHasReadSeq(ctx, req.UserID, req.ConversationID, req.HasReadSeq); err != nil { + if setErr := m.MsgDatabase.SetHasReadSeq(ctx, req.UserID, req.ConversationID, req.HasReadSeq); setErr != nil { return nil, err } if err = m.sendMarkAsReadNotification(ctx, req.ConversationID, constant.SingleChatType, req.UserID, diff --git a/internal/rpc/msg/revoke.go b/internal/rpc/msg/revoke.go index 0a24753b2d..7808ce87ce 100644 --- a/internal/rpc/msg/revoke.go +++ b/internal/rpc/msg/revoke.go @@ -68,7 +68,7 @@ func (m *msgServer) RevokeMsg(ctx context.Context, req *msg.RevokeMsgReq) (*msg. if !authverify.IsAppManagerUid(ctx) { switch msgs[0].SessionType { case constant.SingleChatType: - if err := authverify.CheckAccessV3(ctx, msgs[0].SendID); err != nil { + if accessErr := authverify.CheckAccessV3(ctx, msgs[0].SendID); accessErr != nil { return nil, err } role = user.AppMangerLevel @@ -133,7 +133,7 @@ func (m *msgServer) RevokeMsg(ctx context.Context, req *msg.RevokeMsgReq) (*msg. } else { recvID = msgs[0].RecvID } - if err := m.notificationSender.NotificationWithSesstionType(ctx, req.UserID, recvID, constant.MsgRevokeNotification, msgs[0].SessionType, &tips); err != nil { + if notificationErr := m.notificationSender.NotificationWithSesstionType(ctx, req.UserID, recvID, constant.MsgRevokeNotification, msgs[0].SessionType, &tips); notificationErr != nil { return nil, err } if err = CallbackAfterRevokeMsg(ctx, req); err != nil { diff --git a/internal/rpc/msg/send.go b/internal/rpc/msg/send.go index 630b74a4a1..d3e9f0a020 100644 --- a/internal/rpc/msg/send.go +++ b/internal/rpc/msg/send.go @@ -66,7 +66,7 @@ func (m *msgServer) sendMsgSuperGroupChat( return nil, err } - if err := callbackMsgModify(ctx, req); err != nil { + if modifyErr := callbackMsgModify(ctx, req); modifyErr != nil { return nil, err } err = m.MsgDatabase.MsgToMQ(ctx, utils.GenConversationUniqueKeyForGroup(req.MsgData.GroupID), req.MsgData) @@ -144,7 +144,7 @@ func (m *msgServer) sendMsgNotification( } func (m *msgServer) sendMsgSingleChat(ctx context.Context, req *pbmsg.SendMsgReq) (resp *pbmsg.SendMsgResp, err error) { - if err := m.messageVerification(ctx, req); err != nil { + if verificationErr := m.messageVerification(ctx, req); verificationErr != nil { return nil, err } isSend := true @@ -169,10 +169,10 @@ func (m *msgServer) sendMsgSingleChat(ctx context.Context, req *pbmsg.SendMsgReq return nil, err } - if err := callbackMsgModify(ctx, req); err != nil { + if modifyErr := callbackMsgModify(ctx, req); modifyErr != nil { return nil, err } - if err := m.MsgDatabase.MsgToMQ(ctx, utils.GenConversationUniqueKeyForSingle(req.MsgData.SendID, req.MsgData.RecvID), req.MsgData); err != nil { + if mqErr := m.MsgDatabase.MsgToMQ(ctx, utils.GenConversationUniqueKeyForSingle(req.MsgData.SendID, req.MsgData.RecvID), req.MsgData); mqErr != nil { prommetrics.SingleChatMsgProcessFailedCounter.Inc() return nil, err } diff --git a/internal/rpc/msg/server.go b/internal/rpc/msg/server.go index fe1baa4531..615097a1a6 100644 --- a/internal/rpc/msg/server.go +++ b/internal/rpc/msg/server.go @@ -15,7 +15,6 @@ package msg import ( - "context" "google.golang.org/grpc" @@ -51,16 +50,17 @@ func (m *msgServer) addInterceptorHandler(interceptorFunc ...MessageInterceptorF m.Handlers = append(m.Handlers, interceptorFunc...) } -func (m *msgServer) execInterceptorHandler(ctx context.Context, req *msg.SendMsgReq) error { - for _, handler := range m.Handlers { - msgData, err := handler(ctx, req) - if err != nil { - return err - } - req.MsgData = msgData - } - return nil -} +// func `(*msgServer).execInterceptorHandler` is unused +// func (m *msgServer) execInterceptorHandler(ctx context.Context, req *msg.SendMsgReq) error { +// for _, handler := range m.Handlers { +// msgData, err := handler(ctx, req) +// if err != nil { +// return err +// } +// req.MsgData = msgData +// } +// return nil +// } func Start(client discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) error { rdb, err := cache.NewRedis() @@ -71,7 +71,7 @@ func Start(client discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) e if err != nil { return err } - if err := mongo.CreateMsgIndex(); err != nil { + if indexErr := mongo.CreateMsgIndex(); indexErr != nil { return err } cacheModel := cache.NewMsgCacheModel(rdb) diff --git a/internal/rpc/third/s3.go b/internal/rpc/third/s3.go index 3b501d4add..55ee08da7c 100644 --- a/internal/rpc/third/s3.go +++ b/internal/rpc/third/s3.go @@ -75,7 +75,7 @@ func (t *thirdServer) InitiateMultipartUpload(ctx context.Context, req *third.In Group: req.Cause, CreateTime: time.Now(), } - if err := t.s3dataBase.SetObject(ctx, obj); err != nil { + if setObjectErr := t.s3dataBase.SetObject(ctx, obj); setObjectErr != nil { return nil, err } return &third.InitiateMultipartUploadResp{ @@ -257,10 +257,10 @@ func (t *thirdServer) CompleteFormData(ctx context.Context, req *third.CompleteF return nil, errs.ErrArgs.Wrap("invalid id " + err.Error()) } var mate FormDataMate - if err := json.Unmarshal(data, &mate); err != nil { + if unmarshalErr := json.Unmarshal(data, &mate); unmarshalErr != nil { return nil, errs.ErrArgs.Wrap("invalid id " + err.Error()) } - if err := checkUploadName(ctx, mate.Name); err != nil { + if uploadErr := checkUploadName(ctx, mate.Name); uploadErr != nil { return nil, err } info, err := t.s3dataBase.StatObject(ctx, mate.Key) diff --git a/internal/rpc/third/third.go b/internal/rpc/third/third.go index 7a63d3526a..06a8622f39 100644 --- a/internal/rpc/third/third.go +++ b/internal/rpc/third/third.go @@ -56,7 +56,7 @@ func Start(client discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) e if apiURL == "" { return fmt.Errorf("api url is empty") } - if _, err := url.Parse(config.Config.Object.ApiURL); err != nil { + if _, parseErr := url.Parse(config.Config.Object.ApiURL); parseErr != nil { return err } if apiURL[len(apiURL)-1] != '/' { diff --git a/internal/rpc/user/user.go b/internal/rpc/user/user.go index 6f9e2949f3..0a98851213 100644 --- a/internal/rpc/user/user.go +++ b/internal/rpc/user/user.go @@ -123,11 +123,11 @@ func (s *userServer) UpdateUserInfo(ctx context.Context, req *pbuser.UpdateUserI if err != nil { return nil, err } - if err := CallbackBeforeUpdateUserInfo(ctx, req); err != nil { + if callbackErr := CallbackBeforeUpdateUserInfo(ctx, req); callbackErr != nil { return nil, err } data := convert.UserPb2DBMap(req.UserInfo) - if err := s.UpdateByMap(ctx, req.UserInfo.UserID, data); err != nil { + if updateErr := s.UpdateByMap(ctx, req.UserInfo.UserID, data); updateErr != nil { return nil, err } _ = s.friendNotificationSender.UserInfoUpdatedNotification(ctx, req.UserInfo.UserID) From 1e7a301d093cb969482e9f65e01a3e22a20bf7f8 Mon Sep 17 00:00:00 2001 From: OpenIM Bot <124379614+kubbot@users.noreply.github.com> Date: Sat, 2 Mar 2024 10:41:20 +0800 Subject: [PATCH 071/188] cicd: bump League Patch (#1969) --- internal/rpc/msg/server.go | 1 - 1 file changed, 1 deletion(-) diff --git a/internal/rpc/msg/server.go b/internal/rpc/msg/server.go index 615097a1a6..f38f6f66f0 100644 --- a/internal/rpc/msg/server.go +++ b/internal/rpc/msg/server.go @@ -15,7 +15,6 @@ package msg import ( - "google.golang.org/grpc" "github.com/OpenIMSDK/protocol/constant" From 18f14c9722aba3764d0c339bc10566033ee687cd Mon Sep 17 00:00:00 2001 From: Xinwei Xiong <3293172751NSS@gmail.com> Date: Sat, 2 Mar 2024 11:48:38 +0800 Subject: [PATCH 072/188] Update go-code.md (#1980) --- docs/contrib/go-code.md | 355 ++++++++++++++++++++++++++++++++++------ 1 file changed, 301 insertions(+), 54 deletions(-) diff --git a/docs/contrib/go-code.md b/docs/contrib/go-code.md index 1de448da71..b122917ca7 100644 --- a/docs/contrib/go-code.md +++ b/docs/contrib/go-code.md @@ -26,19 +26,19 @@ jwt "github.com/dgrijalva/jwt-go/v4" ```go import ( -// go standard package -"fmt" - -// third party package -"github.com/jinzhu/gorm" -"github.com/spf13/cobra" -"github.com/spf13/viper" - -// Anonymous packages are grouped separately, and anonymous package references are explained -// import mysql driver -_ "github.com/jinzhu/gorm/dialects/mysql" - -// inner package + // go standard package + "fmt" + + // third party package + "github.com/jinzhu/gorm" + "github.com/spf13/cobra" + "github.com/spf13/viper" + + // Anonymous packages are grouped separately, and anonymous package references are explained + // import mysql driver + _ "github.com/jinzhu/gorm/dialects/mysql" + + // inner package ) ``` @@ -48,33 +48,33 @@ When multiple variables need to be used in a function, the `var` declaration can ```go var ( -Width int -Height int + Width int + Height int ) ``` - When initializing a structure reference, please use `&T{}` instead of `new(T)` to make it consistent with structure initialization. ```go -// bad -sptr := new(T) -sptr.Name = "bar" - -// good -sptr := &T{Name: "bar"} + // bad + sptr := new(T) + sptr.Name = "bar" + + // good + sptr := &T{Name: "bar"} ``` - The struct declaration and initialization format takes multiple lines and is defined as follows. ```go -type User struct{ - Username string - Email string -} - -user := User{ -Username: "belm", -Email: "nosbelm@qq.com", + type User struct{ + Username string + Email string + } + + user := User{ + Username: "belm", + Email: "nosbelm@qq.com", } ``` @@ -217,20 +217,20 @@ if err != nil { // bad v, err := foo() if err != nil || v == nil { -// error handling -return err + // error handling + return err } //good v, err := foo() if err != nil { -// error handling -return err + // error handling + return err } if v == nil { -// error handling -return errors. New("invalid value v") + // error handling + return errors. New("invalid value v") } ``` @@ -239,13 +239,14 @@ return errors. New("invalid value v") ```go v, err := f() if err != nil { - // error handling - return // or continue. + // error handling + return // or continue. } ``` - Bug description suggestions - Error descriptions start with a lowercase letter and do not end with punctuation, for example: + ```go // bad errors.New("Redis connection failed") @@ -254,6 +255,7 @@ errors.New("redis connection failed.") // good errors.New("redis connection failed") ``` + - Tell users what they can do, not what they can't. - When declaring a requirement, use must instead of should. For example, `must be greater than 0, must match regex '[a-z]+'`. - When declaring that a format is incorrect, use must not. For example, `must not contain`. @@ -359,18 +361,18 @@ u := User{ For example: -``` +```go // Seeking to an offset before the start of the file is an error. // Seeking to any positive offset is legal, but the behavior of subsequent // I/O operations on the underlying object are implementation-dependent. type Seeker interface { -Seek(offset int64, whence int) (int64, error) + Seek(offset int64, whence int) (int64, error) } // ReadWriter is the interface that groups the basic Read and Write methods. type ReadWriter interface { -reader -Writer + reader + Writer } ``` @@ -386,7 +388,7 @@ Writer Some common nouns are listed below. -``` +```go // A GonicMapper that contains a list of common initialisms taken from golang/lint var LintGonicMapper = GonicMapper{ "API": true, @@ -523,6 +525,7 @@ package genericclioptions // ErrSigningMethod defines invalid signing method error. var ErrSigningMethod = errors. New("Invalid signing method") ``` + - When there is a large block of constant or variable definition, you can comment a general description in front, and then comment the definition of the constant in detail before or at the end of each line of constant, for example: ```go // Code must start with 1xxxxx. @@ -567,7 +570,7 @@ Each function or method that needs to be exported must have a comment, the forma // BeforeUpdate run before update database record. func (p *Policy) BeforeUpdate() (err error) { // normal code -return nil + return nil } ``` @@ -743,9 +746,9 @@ for i := 0; i < 10; i++ { ```go // bad for file := range files { -fd, err := os. Open(file) -if err != nil { -return err + fd, err := os. Open(file) + if err != nil { + return err } defer fd. Close() // normal code @@ -753,14 +756,14 @@ defer fd. Close() //good for file := range files { -func() { -fd, err := os. Open(file) -if err != nil { -return err -} -defer fd. Close() -// normal code -}() + func() { + fd, err := os. Open(file) + if err != nil { + return err + } + defer fd. Close() + // normal code + }() } ``` @@ -888,6 +891,7 @@ type LogHandler struct { } var_http.Handler = LogHandler{} ``` + - When the server processes a request, it should create a context, save the relevant information of the request (such as requestID), and pass it in the function call chain. ### 9.1 Performance @@ -900,3 +904,246 @@ var_http.Handler = LogHandler{} - If you want to directly modify the value of the map, the value can only be a pointer, otherwise the original value must be overwritten. - map needs to be locked during concurrency. - The conversion of interface{} cannot be checked during compilation, it can only be checked at runtime, be careful to cause panic. + +## 10 Golang CI Lint + +- Golang CI Lint is a fast Go linters runner. It runs linters in parallel, uses caching, and works well with all environments, including CI. + +**In local development, you can use the following command to install Golang CI Lint: ** + +```bash +make lint +``` + +**In CI/CD, Check the Github Actions status code below after you submit the code directly** + +[![OpenIM golangci-lint](https://github.com/openimsdk/open-im-server/actions/workflows/golangci-lint.yml/badge.svg)](https://github.com/openimsdk/open-im-server/actions/workflows/golangci-lint.yml) + +golangci lint can select the types of tools, refer to the official documentation: [https://golangci-lint.run/usage/linters/](https://golangci-lint.run/usage/linters/) + +The types of comments we currently use include: [https://github.com/openimsdk/open-im-server/blob/main/.golangci.yml](https://github.com/openimsdk/open-im-server/blob/main/.golangci.yml) the `linters.enable` field in the file. + +e.g: +```yaml +linters: + # please, do not use `enable-all`: it's deprecated and will be removed soon. + # inverted configuration with `enable-all` and `disable` is not scalable during updates of golangci-lint + # enable-all: true + disable-all: true + enable: + - typecheck # Basic type checking + - gofmt # Format check + - govet # Go's standard linting tool + - gosimple # Suggestions for simplifying code + - misspell # Spelling mistakes + - staticcheck # Static analysis + - unused # Checks for unused code + - goimports # Checks if imports are correctly sorted and formatted + - godot # Checks for comment punctuation + - bodyclose # Ensures HTTP response body is closed + - errcheck # Checks for missed error returns + fast: true +``` + +Add that Chinese comments are not allowed in go code, please write a complete golangci lint specification on the basis of the above. + + +### 10.1 Configuration Document + +This configuration document is designed to configure the operational parameters of OpenIM (a hypothetical or specific code analysis tool), customize output formats, and provide detailed settings for specific code checkers (linters). Below is a summary of the document drafted based on the provided configuration information. + +#### 10.1 Runtime Options + +- **Concurrency** (`concurrency`): Default to use the available CPU count, can be manually set to 4 for parallel analysis. +- **Timeout** (`timeout`): Timeout duration for analysis operations, default is 1 minute, set here to 5 minutes. +- **Issue Exit Code** (`issues-exit-code`): Exit code defaults to 1 if at least one issue is found. +- **Test Files** (`tests`): Whether to include test files, defaults to true. +- **Build Tags** (`build-tags`): Specify build tags used by all linters, defaults to an empty list. Example adds `mytag`. +- **Skip Directories** (`skip-dirs`): Configure which directories' issues are not reported, defaults to empty, but some default directories are independently skipped. +- **Skip Files** (`skip-files`): Specify files where issues should not be reported, supports regular expressions. + +#### 10.2 Output Configuration + +- **Format** (`format`): Set output format, default is "colored-line-number". +- **Print Issued Lines** (`print-issued-lines`): Whether to print the lines where issues occur, defaults to true. +- **Print Linter Name** (`print-linter-name`): Whether to print the linter name at the end of issue text, defaults to true. +- **Uniqueness Filter** (`uniq-by-line`): Whether to make issue outputs unique per line, defaults to true. +- **Path Prefix** (`path-prefix`): Prefix to add to output file references, defaults to no prefix. +- **Sort Results** (`sort-results`): Sort results by file path, line number, and column number. + +#### 10.3 Linters Settings + +In the configuration file, the `linters-settings` section allows detailed configuration of individual linters. Below are examples of specific linters settings and their purposes: + +- **bidichk**: Used to check bidirectional text characters, ensuring correct display direction of text, especially when dealing with mixed left-to-right (LTR) and right-to-left (RTL) text. + +- **dogsled**: Monitors excessive use of blank identifiers (`_`) in assignment operations, which may obscure data processing errors or unclear logic. + +- **dupl**: Identifies duplicate code blocks, helping developers avoid code redundancy. The `threshold` parameter in settings allows adjustment of code similarity threshold triggering warnings. + +- **errcheck**: Checks for unhandled errors. In Go, error handling is achieved by checking function return values. This linter helps ensure all errors are properly handled. + +- **exhaustive**: Checks if `switch` statements include all possible values of an enum type, ensuring exhaustiveness of code. This helps avoid forgetting to handle certain cases. + +#### 10.4 Example: `errcheck` + +**Incorrect Code Example**: +```go +package main + +import ( + "fmt" + "os" +) + +func main() { + f, _ := os.Open("filename.ext") + defer f.Close() +} +``` + +**Issue**: In the above code, the error return value of `os.Open` function is explicitly ignored. This is a common mistake as it may lead to unhandled errors and hard-to-trace bugs. + +**Correct Form**: +```go +package main + +import ( + "fmt" + "os" +) + +func main() { + f, err := os.Open("filename.ext") + if err != nil { + fmt.Printf("error opening file: %v\n", err) + return + } + defer f.Close() +} +``` + +In the correct form, by checking the error (`err`) returned by `os.Open`, we gracefully handle error cases rather than simply ignoring them. + +#### 10.5 Example: `gofmt` + +**Incorrect Code Example**: +```go +package main +import "fmt" +func main() { +fmt.Println("Hello, world!") +} +``` + +**Issue**: This code snippet doesn't follow Go's standard formatting rules, for example, incorrect indentation of `fmt.Println`. + +**Correct Form**: +```go +package main + +import "fmt" + +func main() { + fmt.Println("Hello, world!") +} +``` + +Using `gofmt` tool can automatically fix such formatting issues, ensuring the code adheres to the coding standards of the Go community. + +#### 10.6 Example: `unused` + +**Incorrect Code Example**: +```go +package main + +func helper() {} + +func main() {} +``` + +**Issue**: The `helper` function is defined but not called anywhere, indicating potential redundant code or missing functionality implementation. + +**Correct Form**: +```go +package main + +// If the helper function is indeed needed, ensure it's used properly. +func helper() { + // Implement the function's functionality or ensure it's called elsewhere +} + +func main() { + helper() +} +``` + +To improve the section on Linters settings in the document, we'll expand with more detailed explanations and reinforce understanding through examples. + +#### 10.7 Example: `dogsled` + +**Incorrect Code Example**: +```go +func getValues() (int, int, int) { + return 1, 2, 3 +} + +func main() { + _, _, val := getValues() + fmt.Println(val) // Only interested in the third return value +} +``` + +**Explanation**: In the above code, we use two blank identifiers to ignore the first two return values. Excessive use of blank identifiers can make code reading difficult. + +**Improved Code**: +Consider refactoring the function or the usage of return values to reduce the need for blank identifiers or explicitly comment why ignoring certain values is safe. + +#### 10.8: `exhaustive` + +**Incorrect Code Example**: +```go +type Fruit int + +const ( + Apple Fruit = iota + Banana + Orange +) + +func getFruitName(f Fruit) string { + switch f { + case Apple: + return "Apple" + case Banana: + return "Banana" + // Missing handling for Orange + } + return "Unknown" +} +``` + +**Explanation**: In this code, the `switch` statement doesn't cover all possible values of the `Fruit` type; the case for `Orange` is missing. + +**Improved Code**: +```go +func getFruitName(f Fruit) string { + switch f { + case Apple: + return "Apple" + case Banana: + return "Banana" + case Orange: + return "Orange" + } + return "Unknown" +} +``` + +By adding the missing `case`, we ensure the `switch` statement is exhaustive, handling every possible enum value. + +#### 10.9 Optimization of Configuration Files and Application of Code Analysis Tools + +Through these examples, we demonstrate how to improve code quality by identifying and fixing common coding issues. OpenIM's configuration files allow developers to customize linters' behavior according to project requirements, ensuring code compliance with predefined quality standards and style guidelines. + +By employing these tools and configuration strategies, teams can reduce the number of bugs, enhance code maintainability, and facilitate efficient collaboration during code review processes. From b511dc7ec461d855f72b75298f928601189d6b90 Mon Sep 17 00:00:00 2001 From: Xinwei Xiong <3293172751NSS@gmail.com> Date: Sat, 2 Mar 2024 14:31:01 +0800 Subject: [PATCH 073/188] Update test.sh (#1968) --- scripts/install/test.sh | 43 +++++++++++++++++++---------------------- 1 file changed, 20 insertions(+), 23 deletions(-) diff --git a/scripts/install/test.sh b/scripts/install/test.sh index 4a78e45040..4ea3f16caf 100755 --- a/scripts/install/test.sh +++ b/scripts/install/test.sh @@ -34,8 +34,8 @@ # # The root of the build/dist directory -IAM_ROOT=$(dirname "${BASH_SOURCE[0]}")/../.. -[[ -z ${COMMON_SOURCED} ]] && source ${IAM_ROOT}/scripts/install/common.sh +OPENIM_ROOT=$(dirname "${BASH_SOURCE[0]}")/../.. +[[ -z ${COMMON_SOURCED} ]] && source ${OPENIM_ROOT}/scripts/install/common.sh # API Server API Address:Port INSECURE_OPENIMAPI="http://${OPENIM_API_HOST}:${API_OPENIM_PORT}" @@ -72,7 +72,7 @@ function openim::test::auth() { # Define a function to get a token for a specific user openim::test::get_token() { - local user_id="${1:-openIM123456}" # Default user ID if not provided + local user_id="${1:-imAdmin}" # Default user ID if not provided token_response=$( ${CCURL} "${OperationID}" "${Header}" ${INSECURE_OPENIMAPI}/auth/user_token \ -d'{"secret": "'"$SECRET"'","platformID": 1,"userID": "'$user_id'"}' @@ -142,10 +142,7 @@ openim::test::check_user_account() { cat < Date: Sun, 3 Mar 2024 21:15:27 +0800 Subject: [PATCH 074/188] docs: update openim server readme github codespaces (#1984) --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index e83afe5aaa..1552f62e5e 100644 --- a/README.md +++ b/README.md @@ -125,6 +125,8 @@ We support many platforms. Here are the addresses for quick experience on the we ## :hammer_and_wrench: To Start Developing OpenIM +[![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/openimsdk/open-im-server) + [![Open in Dev Container](https://img.shields.io/static/v1?label=Dev%20Container&message=Open&color=blue&logo=visualstudiocode)](https://vscode.dev/github/openimsdk/open-im-server) OpenIM Our goal is to build a top-level open source community. We have a set of standards, in the [Community repository](https://github.com/OpenIMSDK/community). From 57331182c2d034c42383c282b31e4e5d61165325 Mon Sep 17 00:00:00 2001 From: Xinwei Xiong <3293172751NSS@gmail.com> Date: Mon, 4 Mar 2024 10:45:04 +0800 Subject: [PATCH 075/188] feat: update golangci.yml file add and delete some linters (#1989) --- .golangci.yml | 50 +++++++++++++++++++++++++++++++++----------------- 1 file changed, 33 insertions(+), 17 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index b129ffd685..0a0d40c215 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -40,10 +40,14 @@ run: # "/" will be replaced by current OS file path separator to properly work # on Windows. skip-dirs: + - components + - docs - util - .*~ - api/swagger/docs - server/docs + - components/mnt/config/certs + - logs # default is true. Enables skipping of directories: # vendor$, third_party$, testdata$, examples$, Godeps$, builtin$ @@ -58,6 +62,11 @@ run: skip-files: - ".*\\.my\\.go$" - _test.go + - ".*_test.go" + - "mocks/" + - ".github/" + - "logs/" + - "components/" # by default isn't set. If set we pass it to "go list -mod={option}". From "go help modules": # If invoked with -mod=readonly, the go command is disallowed from the implicit @@ -131,8 +140,8 @@ linters-settings: # path to a file containing a list of functions to exclude from checking # see https://github.com/kisielk/errcheck#excluding-functions for details - #exclude: errcheck.txt - + # exclude: errcheck.txt + errorlint: # Check whether fmt.Errorf uses the %w verb for formatting errors. See the readme for caveats errorf: true @@ -418,7 +427,7 @@ linters-settings: govet: # report about shadowed variables - check-shadowing: true + check-shadowing: false # settings per analyzer settings: @@ -489,9 +498,9 @@ linters-settings: - github.com\/user\/package\/v4\.Type lll: - # max line length, lines longer will be reported. Default is 120. + # max line length, lines longer will be reported. Default is 250. # '\t' is counted as 1 character by default, and can be changed with the tab-width option - line-length: 240 + line-length: 250 # tab width in spaces. Default to 1. tab-width: 4 maligned: @@ -715,17 +724,19 @@ linters: # enable-all: true disable-all: true enable: - - typecheck # 基本的类型检查 - - gofmt # 格式检查 - - govet # Go 语言的标准检查工具 - - gosimple # 简化代码的建议 - - misspell # 拼写错误 - - staticcheck # 静态检查 - - unused # 未使用的代码检查 - - goimports # 检查导入是否正确排序和格式化 - - godot # 注释句点检查 - - bodyclose # 确保 HTTP response body 被关闭 - - errcheck # 检查是否遗漏了错误返回值 + - typecheck # Basic type checking + - gofmt # Format check + - govet # Go's standard linting tool + - gosimple # Suggestions for simplifying code + - misspell # Spelling mistakes + - staticcheck # Static analysis + - unused # Checks for unused code + - goimports # Checks if imports are correctly sorted and formatted + - godot # Checks for comment punctuation + - bodyclose # Ensures HTTP response body is closed + - stylecheck # Style checker for Go code + - unused # Checks for unused code + - errcheck # Checks for missed error returns fast: true issues: @@ -792,6 +803,11 @@ issues: - lll source: "^//go:generate " + - text: ".*[\u4e00-\u9fa5]+.*" + linters: + - golint + source: "^//.*$" + # Independently from option `exclude` we use default exclude patterns, # it can be disabled by this option. To list all # excluded by default patterns execute `golangci-lint run --help`. @@ -852,4 +868,4 @@ severity: rules: - linters: - dupl - severity: info \ No newline at end of file + severity: info From 1ef26b29a744a8b45c0c8c48352004c7f9051c47 Mon Sep 17 00:00:00 2001 From: xuan <146319162+wxuanF@users.noreply.github.com> Date: Mon, 4 Mar 2024 11:18:38 +0800 Subject: [PATCH 076/188] back err_name (#1976) Signed-off-by: xuan <146319162+wxuanF@users.noreply.github.com> --- internal/msgtransfer/init.go | 2 +- internal/rpc/friend/black.go | 2 +- internal/rpc/friend/friend.go | 16 ++++++++-------- internal/rpc/group/group.go | 24 ++++++++++++------------ internal/rpc/msg/as_read.go | 2 +- internal/rpc/msg/revoke.go | 4 ++-- internal/rpc/msg/send.go | 8 ++++---- internal/rpc/msg/server.go | 2 +- internal/rpc/third/s3.go | 6 +++--- internal/rpc/third/third.go | 2 +- internal/rpc/user/user.go | 4 ++-- 11 files changed, 36 insertions(+), 36 deletions(-) diff --git a/internal/msgtransfer/init.go b/internal/msgtransfer/init.go index 91a5474409..9b1b853f28 100644 --- a/internal/msgtransfer/init.go +++ b/internal/msgtransfer/init.go @@ -70,7 +70,7 @@ func StartTransfer(prometheusPort int) error { return err } - if err2 := client.CreateRpcRootNodes(config.Config.GetServiceNames()); err2 != nil { + if err := client.CreateRpcRootNodes(config.Config.GetServiceNames()); err != nil { return err } client.AddOption(mw.GrpcClient(), grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithDefaultServiceConfig(fmt.Sprintf(`{"LoadBalancingPolicy": "%s"}`, "round_robin"))) diff --git a/internal/rpc/friend/black.go b/internal/rpc/friend/black.go index 6bf780d3ae..ed5791c380 100644 --- a/internal/rpc/friend/black.go +++ b/internal/rpc/friend/black.go @@ -28,7 +28,7 @@ import ( ) func (s *friendServer) GetPaginationBlacks(ctx context.Context, req *pbfriend.GetPaginationBlacksReq) (resp *pbfriend.GetPaginationBlacksResp, err error) { - if accessErr := s.userRpcClient.Access(ctx, req.UserID); accessErr != nil { + if err := s.userRpcClient.Access(ctx, req.UserID); err != nil { return nil, err } total, blacks, err := s.blackDatabase.FindOwnerBlacks(ctx, req.UserID, req.Pagination) diff --git a/internal/rpc/friend/friend.go b/internal/rpc/friend/friend.go index a85f758c5f..84702f5481 100644 --- a/internal/rpc/friend/friend.go +++ b/internal/rpc/friend/friend.go @@ -115,7 +115,7 @@ func Start(client registry.SvcDiscoveryRegistry, server *grpc.Server) error { func (s *friendServer) ApplyToAddFriend(ctx context.Context, req *pbfriend.ApplyToAddFriendReq) (resp *pbfriend.ApplyToAddFriendResp, err error) { defer log.ZInfo(ctx, utils.GetFuncName()+" Return") resp = &pbfriend.ApplyToAddFriendResp{} - if accessErr := authverify.CheckAccessV3(ctx, req.FromUserID); accessErr != nil { + if err := authverify.CheckAccessV3(ctx, req.FromUserID); err != nil { return nil, err } if req.ToUserID == req.FromUserID { @@ -124,7 +124,7 @@ func (s *friendServer) ApplyToAddFriend(ctx context.Context, req *pbfriend.Apply if err = CallbackBeforeAddFriend(ctx, req); err != nil && err != errs.ErrCallbackContinue { return nil, err } - if _, getUserInfoErr := s.userRpcClient.GetUsersInfoMap(ctx, []string{req.ToUserID, req.FromUserID}); getUserInfoErr != nil { + if _, err := s.userRpcClient.GetUsersInfoMap(ctx, []string{req.ToUserID, req.FromUserID}); err != nil { return nil, err } in1, in2, err := s.friendDatabase.CheckIn(ctx, req.FromUserID, req.ToUserID) @@ -219,7 +219,7 @@ func (s *friendServer) RespondFriendApply(ctx context.Context, req *pbfriend.Res func (s *friendServer) DeleteFriend(ctx context.Context, req *pbfriend.DeleteFriendReq) (resp *pbfriend.DeleteFriendResp, err error) { defer log.ZInfo(ctx, utils.GetFuncName()+" Return") resp = &pbfriend.DeleteFriendResp{} - if accessErr := s.userRpcClient.Access(ctx, req.OwnerUserID); accessErr != nil { + if err := s.userRpcClient.Access(ctx, req.OwnerUserID); err != nil { return nil, err } _, err = s.friendDatabase.FindFriendsWithError(ctx, req.OwnerUserID, []string{req.FriendUserID}) @@ -244,7 +244,7 @@ func (s *friendServer) SetFriendRemark(ctx context.Context, req *pbfriend.SetFri return nil, err } resp = &pbfriend.SetFriendRemarkResp{} - if accessErr := s.userRpcClient.Access(ctx, req.OwnerUserID); accessErr != nil { + if err := s.userRpcClient.Access(ctx, req.OwnerUserID); err != nil { return nil, err } _, err = s.friendDatabase.FindFriendsWithError(ctx, req.OwnerUserID, []string{req.FriendUserID}) @@ -295,7 +295,7 @@ func (s *friendServer) GetDesignatedFriendsApply(ctx context.Context, // ok 获取接收到的好友申请(即别人主动申请的). func (s *friendServer) GetPaginationFriendsApplyTo(ctx context.Context, req *pbfriend.GetPaginationFriendsApplyToReq) (resp *pbfriend.GetPaginationFriendsApplyToResp, err error) { defer log.ZInfo(ctx, utils.GetFuncName()+" Return") - if accessErr := s.userRpcClient.Access(ctx, req.UserID); accessErr != nil { + if err := s.userRpcClient.Access(ctx, req.UserID); err != nil { return nil, err } total, friendRequests, err := s.friendDatabase.PageFriendRequestToMe(ctx, req.UserID, req.Pagination) @@ -315,7 +315,7 @@ func (s *friendServer) GetPaginationFriendsApplyTo(ctx context.Context, req *pbf func (s *friendServer) GetPaginationFriendsApplyFrom(ctx context.Context, req *pbfriend.GetPaginationFriendsApplyFromReq) (resp *pbfriend.GetPaginationFriendsApplyFromResp, err error) { defer log.ZInfo(ctx, utils.GetFuncName()+" Return") resp = &pbfriend.GetPaginationFriendsApplyFromResp{} - if accessErr := s.userRpcClient.Access(ctx, req.UserID); accessErr != nil { + if err := s.userRpcClient.Access(ctx, req.UserID); err != nil { return nil, err } total, friendRequests, err := s.friendDatabase.PageFriendRequestFromMe(ctx, req.UserID, req.Pagination) @@ -343,7 +343,7 @@ func (s *friendServer) IsFriend(ctx context.Context, req *pbfriend.IsFriendReq) func (s *friendServer) GetPaginationFriends(ctx context.Context, req *pbfriend.GetPaginationFriendsReq) (resp *pbfriend.GetPaginationFriendsResp, err error) { defer log.ZInfo(ctx, utils.GetFuncName()+" Return") - if accessErr := s.userRpcClient.Access(ctx, req.UserID); accessErr != nil { + if err := s.userRpcClient.Access(ctx, req.UserID); err != nil { return nil, err } total, friends, err := s.friendDatabase.PageOwnerFriends(ctx, req.UserID, req.Pagination) @@ -361,7 +361,7 @@ func (s *friendServer) GetPaginationFriends(ctx context.Context, req *pbfriend.G func (s *friendServer) GetFriendIDs(ctx context.Context, req *pbfriend.GetFriendIDsReq) (resp *pbfriend.GetFriendIDsResp, err error) { defer log.ZInfo(ctx, utils.GetFuncName()+" Return") - if accessErr := s.userRpcClient.Access(ctx, req.UserID); accessErr != nil { + if err := s.userRpcClient.Access(ctx, req.UserID); err != nil { return nil, err } resp = &pbfriend.GetFriendIDsResp{} diff --git a/internal/rpc/group/group.go b/internal/rpc/group/group.go index 8bce182b84..9b1198d588 100644 --- a/internal/rpc/group/group.go +++ b/internal/rpc/group/group.go @@ -539,7 +539,7 @@ func (s *groupServer) KickGroupMember(ctx context.Context, req *pbgroup.KickGrou if err != nil { return nil, err } - if populateErr := s.PopulateGroupMember(ctx, members...); populateErr != nil { + if err := s.PopulateGroupMember(ctx, members...); err != nil { return nil, err } memberMap := make(map[string]*relationtb.GroupMemberModel) @@ -765,12 +765,12 @@ func (s *groupServer) GroupApplicationResponse(ctx context.Context, req *pbgroup return nil, errs.ErrGroupRequestHandled.Wrap("group request already processed") } var inGroup bool - if _, takeErr := s.db.TakeGroupMember(ctx, req.GroupID, req.FromUserID); takeErr == nil { + if _, err := s.db.TakeGroupMember(ctx, req.GroupID, req.FromUserID); err == nil { inGroup = true // 已经在群里了 } else if !s.IsNotFound(err) { return nil, err } - if _, getInfoErr := s.User.GetPublicUserInfo(ctx, req.FromUserID); getInfoErr != nil { + if _, err := s.User.GetPublicUserInfo(ctx, req.FromUserID); err != nil { return nil, err } var member *relationtb.GroupMemberModel @@ -857,14 +857,14 @@ func (s *groupServer) JoinGroup(ctx context.Context, req *pbgroup.JoinGroupReq) JoinTime: time.Now(), MuteEndTime: time.UnixMilli(0), } - if callbackErr := CallbackBeforeMemberJoinGroup(ctx, groupMember, group.Ex); callbackErr != nil { + if err := CallbackBeforeMemberJoinGroup(ctx, groupMember, group.Ex); err != nil { return nil, err } - if createErr := s.db.CreateGroup(ctx, nil, []*relationtb.GroupMemberModel{groupMember}); createErr != nil { + if err := s.db.CreateGroup(ctx, nil, []*relationtb.GroupMemberModel{groupMember}); err != nil { return nil, err } - if createErr := s.conversationRpcClient.GroupChatFirstCreateConversation(ctx, req.GroupID, []string{req.InviterUserID}); createErr != nil { + if err := s.conversationRpcClient.GroupChatFirstCreateConversation(ctx, req.GroupID, []string{req.InviterUserID}); err != nil { return nil, err } s.Notification.MemberEnterNotification(ctx, req.GroupID, req.InviterUserID) @@ -905,7 +905,7 @@ func (s *groupServer) QuitGroup(ctx context.Context, req *pbgroup.QuitGroupReq) if member.RoleLevel == constant.GroupOwner { return nil, errs.ErrNoPermission.Wrap("group owner can't quit") } - if populateErr := s.PopulateGroupMember(ctx, member); populateErr != nil { + if err := s.PopulateGroupMember(ctx, member); err != nil { return nil, err } err = s.db.DeleteGroupMember(ctx, req.GroupID, []string{req.UserID}) @@ -967,7 +967,7 @@ func (s *groupServer) SetGroupInfo(ctx context.Context, req *pbgroup.SetGroupInf if err != nil { return nil, err } - if populateErr := s.PopulateGroupMember(ctx, owner); populateErr != nil { + if err := s.PopulateGroupMember(ctx, owner); err != nil { return nil, err } update := UpdateGroupInfoMap(ctx, req.GroupInfoForSet) @@ -1168,7 +1168,7 @@ func (s *groupServer) GetUserReqApplicationList(ctx context.Context, req *pbgrou if err != nil { return nil, err } - if populateErr := s.PopulateGroupMember(ctx, owners...); populateErr != nil { + if err := s.PopulateGroupMember(ctx, owners...); err != nil { return nil, err } ownerMap := utils.SliceToMap(owners, func(e *relationtb.GroupMemberModel) string { @@ -1200,7 +1200,7 @@ func (s *groupServer) DismissGroup(ctx context.Context, req *pbgroup.DismissGrou return nil, errs.ErrNoPermission.Wrap("not group owner") } } - if populateErr := s.PopulateGroupMember(ctx, owner); populateErr != nil { + if err := s.PopulateGroupMember(ctx, owner); err != nil { return nil, err } group, err := s.db.TakeGroup(ctx, req.GroupID) @@ -1210,7 +1210,7 @@ func (s *groupServer) DismissGroup(ctx context.Context, req *pbgroup.DismissGrou if !req.DeleteMember && group.Status == constant.GroupStatusDismissed { return nil, errs.ErrDismissedAlready.Wrap("group status is dismissed") } - if dismissErr := s.db.DismissGroup(ctx, req.GroupID, req.DeleteMember); dismissErr != nil { + if err := s.db.DismissGroup(ctx, req.GroupID, req.DeleteMember); err != nil { return nil, err } if !req.DeleteMember { @@ -1566,7 +1566,7 @@ func (s *groupServer) GetGroupUsersReqApplicationList(ctx context.Context, req * if err != nil { return nil, err } - if populateErr := s.PopulateGroupMember(ctx, owners...); populateErr != nil { + if err := s.PopulateGroupMember(ctx, owners...); err != nil { return nil, err } ownerMap := utils.SliceToMap(owners, func(e *relationtb.GroupMemberModel) string { diff --git a/internal/rpc/msg/as_read.go b/internal/rpc/msg/as_read.go index c1816ce183..cb292421e9 100644 --- a/internal/rpc/msg/as_read.go +++ b/internal/rpc/msg/as_read.go @@ -82,7 +82,7 @@ func (m *msgServer) SetConversationHasReadSeq( if req.HasReadSeq > maxSeq { return nil, errs.ErrArgs.Wrap("hasReadSeq must not be bigger than maxSeq") } - if setErr := m.MsgDatabase.SetHasReadSeq(ctx, req.UserID, req.ConversationID, req.HasReadSeq); setErr != nil { + if err := m.MsgDatabase.SetHasReadSeq(ctx, req.UserID, req.ConversationID, req.HasReadSeq); err != nil { return nil, err } if err = m.sendMarkAsReadNotification(ctx, req.ConversationID, constant.SingleChatType, req.UserID, diff --git a/internal/rpc/msg/revoke.go b/internal/rpc/msg/revoke.go index 7808ce87ce..0a24753b2d 100644 --- a/internal/rpc/msg/revoke.go +++ b/internal/rpc/msg/revoke.go @@ -68,7 +68,7 @@ func (m *msgServer) RevokeMsg(ctx context.Context, req *msg.RevokeMsgReq) (*msg. if !authverify.IsAppManagerUid(ctx) { switch msgs[0].SessionType { case constant.SingleChatType: - if accessErr := authverify.CheckAccessV3(ctx, msgs[0].SendID); accessErr != nil { + if err := authverify.CheckAccessV3(ctx, msgs[0].SendID); err != nil { return nil, err } role = user.AppMangerLevel @@ -133,7 +133,7 @@ func (m *msgServer) RevokeMsg(ctx context.Context, req *msg.RevokeMsgReq) (*msg. } else { recvID = msgs[0].RecvID } - if notificationErr := m.notificationSender.NotificationWithSesstionType(ctx, req.UserID, recvID, constant.MsgRevokeNotification, msgs[0].SessionType, &tips); notificationErr != nil { + if err := m.notificationSender.NotificationWithSesstionType(ctx, req.UserID, recvID, constant.MsgRevokeNotification, msgs[0].SessionType, &tips); err != nil { return nil, err } if err = CallbackAfterRevokeMsg(ctx, req); err != nil { diff --git a/internal/rpc/msg/send.go b/internal/rpc/msg/send.go index d3e9f0a020..630b74a4a1 100644 --- a/internal/rpc/msg/send.go +++ b/internal/rpc/msg/send.go @@ -66,7 +66,7 @@ func (m *msgServer) sendMsgSuperGroupChat( return nil, err } - if modifyErr := callbackMsgModify(ctx, req); modifyErr != nil { + if err := callbackMsgModify(ctx, req); err != nil { return nil, err } err = m.MsgDatabase.MsgToMQ(ctx, utils.GenConversationUniqueKeyForGroup(req.MsgData.GroupID), req.MsgData) @@ -144,7 +144,7 @@ func (m *msgServer) sendMsgNotification( } func (m *msgServer) sendMsgSingleChat(ctx context.Context, req *pbmsg.SendMsgReq) (resp *pbmsg.SendMsgResp, err error) { - if verificationErr := m.messageVerification(ctx, req); verificationErr != nil { + if err := m.messageVerification(ctx, req); err != nil { return nil, err } isSend := true @@ -169,10 +169,10 @@ func (m *msgServer) sendMsgSingleChat(ctx context.Context, req *pbmsg.SendMsgReq return nil, err } - if modifyErr := callbackMsgModify(ctx, req); modifyErr != nil { + if err := callbackMsgModify(ctx, req); err != nil { return nil, err } - if mqErr := m.MsgDatabase.MsgToMQ(ctx, utils.GenConversationUniqueKeyForSingle(req.MsgData.SendID, req.MsgData.RecvID), req.MsgData); mqErr != nil { + if err := m.MsgDatabase.MsgToMQ(ctx, utils.GenConversationUniqueKeyForSingle(req.MsgData.SendID, req.MsgData.RecvID), req.MsgData); err != nil { prommetrics.SingleChatMsgProcessFailedCounter.Inc() return nil, err } diff --git a/internal/rpc/msg/server.go b/internal/rpc/msg/server.go index f38f6f66f0..c258792762 100644 --- a/internal/rpc/msg/server.go +++ b/internal/rpc/msg/server.go @@ -70,7 +70,7 @@ func Start(client discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) e if err != nil { return err } - if indexErr := mongo.CreateMsgIndex(); indexErr != nil { + if err := mongo.CreateMsgIndex(); err != nil { return err } cacheModel := cache.NewMsgCacheModel(rdb) diff --git a/internal/rpc/third/s3.go b/internal/rpc/third/s3.go index 55ee08da7c..3b501d4add 100644 --- a/internal/rpc/third/s3.go +++ b/internal/rpc/third/s3.go @@ -75,7 +75,7 @@ func (t *thirdServer) InitiateMultipartUpload(ctx context.Context, req *third.In Group: req.Cause, CreateTime: time.Now(), } - if setObjectErr := t.s3dataBase.SetObject(ctx, obj); setObjectErr != nil { + if err := t.s3dataBase.SetObject(ctx, obj); err != nil { return nil, err } return &third.InitiateMultipartUploadResp{ @@ -257,10 +257,10 @@ func (t *thirdServer) CompleteFormData(ctx context.Context, req *third.CompleteF return nil, errs.ErrArgs.Wrap("invalid id " + err.Error()) } var mate FormDataMate - if unmarshalErr := json.Unmarshal(data, &mate); unmarshalErr != nil { + if err := json.Unmarshal(data, &mate); err != nil { return nil, errs.ErrArgs.Wrap("invalid id " + err.Error()) } - if uploadErr := checkUploadName(ctx, mate.Name); uploadErr != nil { + if err := checkUploadName(ctx, mate.Name); err != nil { return nil, err } info, err := t.s3dataBase.StatObject(ctx, mate.Key) diff --git a/internal/rpc/third/third.go b/internal/rpc/third/third.go index 06a8622f39..7a63d3526a 100644 --- a/internal/rpc/third/third.go +++ b/internal/rpc/third/third.go @@ -56,7 +56,7 @@ func Start(client discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) e if apiURL == "" { return fmt.Errorf("api url is empty") } - if _, parseErr := url.Parse(config.Config.Object.ApiURL); parseErr != nil { + if _, err := url.Parse(config.Config.Object.ApiURL); err != nil { return err } if apiURL[len(apiURL)-1] != '/' { diff --git a/internal/rpc/user/user.go b/internal/rpc/user/user.go index 0a98851213..6f9e2949f3 100644 --- a/internal/rpc/user/user.go +++ b/internal/rpc/user/user.go @@ -123,11 +123,11 @@ func (s *userServer) UpdateUserInfo(ctx context.Context, req *pbuser.UpdateUserI if err != nil { return nil, err } - if callbackErr := CallbackBeforeUpdateUserInfo(ctx, req); callbackErr != nil { + if err := CallbackBeforeUpdateUserInfo(ctx, req); err != nil { return nil, err } data := convert.UserPb2DBMap(req.UserInfo) - if updateErr := s.UpdateByMap(ctx, req.UserInfo.UserID, data); updateErr != nil { + if err := s.UpdateByMap(ctx, req.UserInfo.UserID, data); err != nil { return nil, err } _ = s.friendNotificationSender.UserInfoUpdatedNotification(ctx, req.UserInfo.UserID) From 853ac47e4274fa04997665b3832e7e0c8ba67bde Mon Sep 17 00:00:00 2001 From: Xinwei Xiong <3293172751NSS@gmail.com> Date: Mon, 4 Mar 2024 12:12:14 +0800 Subject: [PATCH 077/188] feat: Integrate Comprehensive E2E Testing for GoChat (#1906) * feat: create e2e test readme Signed-off-by: Xinwei Xiong (cubxxw) <3293172751nss@gmail.com> * feat: fix markdown file * feat: add openim make lint * feat: add git chglog pull request * feat: add git chglog pull request * fix: fix openim api err code * fix: fix openim api err code * fix: fix openim api err code * feat: Improve CICD * feat: Combining GitHub and Google Workspace for Effective Project Management' * feat: fix openim tools error code * feat: fix openim tools error code * feat: add openim error handle * feat: add openim error handle * feat: optimize tim white prom code return err * feat: fix openim tools error code * style: format openim server code style * feat: add openim optimize commit code * feat: add openim optimize commit code * feat: add openim auto format code * feat: add openim auto format code * feat: add openim auto format code * feat: add openim auto format code * feat: add openim auto format code * feat: format openim code * feat: Some of the notes were translated * feat: Some of the notes were translated * feat: update openim server code * feat: optimize openim reset code * feat: optimize openim reset code --------- Signed-off-by: Xinwei Xiong (cubxxw) <3293172751nss@gmail.com> --- .github/workflows/e2e-test.yml | 2 + .github/workflows/pull-request.yml | 11 ++ CHANGELOG/CHANGELOG-3.5.md | 22 ++- Makefile | 2 +- cmd/openim-api/main.go | 10 +- cmd/openim-push/main.go | 2 +- cmd/openim-rpc/openim-rpc-auth/main.go | 2 +- .../openim-rpc-conversation/main.go | 2 +- cmd/openim-rpc/openim-rpc-friend/main.go | 2 +- cmd/openim-rpc/openim-rpc-group/main.go | 2 +- cmd/openim-rpc/openim-rpc-msg/main.go | 2 +- cmd/openim-rpc/openim-rpc-third/main.go | 2 +- cmd/openim-rpc/openim-rpc-user/main.go | 2 +- docs/contrib/code-conventions.md | 21 ++- internal/api/custom_validator.go | 11 +- internal/api/msg.go | 9 +- internal/api/route.go | 14 +- internal/api/user.go | 4 +- internal/msggateway/client.go | 37 ++--- internal/msggateway/compressor.go | 42 +++--- internal/msggateway/compressor_test.go | 13 ++ internal/msggateway/encoder.go | 4 +- internal/msggateway/init.go | 9 +- internal/msggateway/long_conn.go | 16 ++- internal/msggateway/message_handler.go | 32 +++-- internal/msggateway/n_ws_server.go | 7 +- internal/msggateway/options.go | 10 +- internal/msgtransfer/init.go | 13 +- .../msgtransfer/online_history_msg_handler.go | 14 +- internal/push/callback.go | 9 +- internal/push/offlinepush/fcm/push.go | 6 +- internal/push/push_to_client.go | 3 +- internal/rpc/conversation/conversaion.go | 6 +- internal/rpc/friend/friend.go | 4 +- internal/rpc/group/group.go | 4 +- internal/rpc/third/third.go | 2 +- internal/tools/conversation.go | 8 +- internal/tools/cron_task.go | 8 +- internal/tools/msg.go | 4 +- pkg/apistruct/msg.go | 1 + pkg/authverify/token.go | 3 +- pkg/common/cmd/api.go | 31 ++++- pkg/common/cmd/cron_task.go | 4 + pkg/common/cmd/msg_gateway.go | 55 ++++++-- pkg/common/cmd/msg_gateway_test.go | 2 +- pkg/common/cmd/msg_transfer.go | 18 ++- pkg/common/cmd/msg_utils.go | 3 +- pkg/common/cmd/root.go | 52 ++++--- pkg/common/cmd/rpc.go | 131 +++++++++--------- pkg/common/config/parse.go | 89 ++++++++---- pkg/common/config/parse_test.go | 4 +- pkg/common/convert/black.go | 6 +- pkg/common/convert/friend.go | 9 +- pkg/common/db/cache/black.go | 6 +- pkg/common/db/cache/init_redis.go | 16 ++- pkg/common/db/cache/meta_cache.go | 14 +- pkg/common/db/cache/msg.go | 7 +- pkg/common/db/cache/user.go | 12 +- pkg/common/db/controller/auth.go | 16 +-- pkg/common/db/controller/black.go | 24 ++-- pkg/common/db/controller/conversation.go | 44 +++--- pkg/common/db/controller/friend.go | 70 ++++++---- pkg/common/db/controller/group.go | 52 +++++-- pkg/common/db/controller/msg.go | 51 ++++--- pkg/common/db/controller/third.go | 8 +- pkg/common/db/s3/aws/aws.go | 4 +- pkg/common/db/s3/cont/consts.go | 26 +++- pkg/common/db/s3/cont/controller.go | 8 +- pkg/common/db/s3/cont/structs.go | 11 +- pkg/common/db/s3/minio/image.go | 90 +++++------- pkg/common/db/s3/oss/oss.go | 31 +++-- pkg/common/db/table/relation/group.go | 4 +- pkg/common/db/table/relation/user.go | 4 +- pkg/common/db/unrelation/msg.go | 124 +++++------------ .../discoveryregister/direct/directconn.go | 5 +- .../discoveryregister/discoveryregister.go | 3 +- .../discoveryregister_test.go | 2 +- pkg/common/http/http_client.go | 14 +- pkg/common/kafka/consumer.go | 36 ++--- pkg/common/kafka/producer.go | 5 +- pkg/common/kafka/util.go | 9 +- pkg/common/prommetrics/prommetrics.go | 1 - pkg/common/startrpc/start.go | 2 +- pkg/common/tls/tls.go | 36 +++-- pkg/msgprocessor/conversation.go | 3 +- pkg/rpcclient/auth.go | 3 +- pkg/rpcclient/conversation.go | 10 +- pkg/rpcclient/friend.go | 5 +- pkg/rpcclient/group.go | 3 +- pkg/rpcclient/msg.go | 22 ++- pkg/rpcclient/notification/conversation.go | 4 +- pkg/rpcclient/notification/friend.go | 2 +- pkg/rpcclient/push.go | 8 +- pkg/rpcclient/third.go | 39 ++++-- pkg/rpcclient/user.go | 3 +- pkg/util/genutil/genutil.go | 8 +- scripts/install/openim-tools.sh | 8 +- scripts/make-rules/golang.mk | 2 +- test/codescan/main.go | 1 + test/e2e/README.md | 2 + test/e2e/api/token/token.go | 15 -- test/e2e/framework/config/config_test.go | 2 +- test/e2e/framework/helpers/chat/chat.go | 37 ++--- test/e2e/page/chat_page.go | 1 + test/e2e/page/login_page.go | 1 + test/e2e/web/.keep | 1 - test/e2e/web/Readme.md | 2 + .../chat/cmd/conversion-chat/chat.go | 18 +-- tools/data-conversion/chat/v2/admin.go | 10 +- tools/data-conversion/chat/v2/chat.go | 16 +-- tools/data-conversion/chat/v3/admin/admin.go | 2 +- .../chat/v3/admin/client_config.go | 2 +- .../chat/v3/admin/forbidden_account.go | 2 +- .../chat/v3/admin/invitation_register.go | 2 +- .../chat/v3/admin/ip_forbidden.go | 2 +- .../chat/v3/admin/limit_user_login_ip.go | 2 +- .../chat/v3/admin/register_add_friend.go | 2 +- .../chat/v3/admin/register_add_group.go | 2 +- tools/data-conversion/chat/v3/chat/account.go | 2 +- .../data-conversion/chat/v3/chat/attribute.go | 2 +- .../data-conversion/chat/v3/chat/register.go | 2 +- .../chat/v3/chat/user_login_record.go | 2 +- .../cmd/conversion-msg/conversion-msg.go | 21 ++- .../cmd/conversion-mysql/conversion-mysql.go | 34 +++-- .../data-conversion/openim/mysql/v3/friend.go | 61 ++++---- .../openim/mysql/v3/friend_request.go | 40 +++--- .../data-conversion/openim/mysql/v3/group.go | 5 +- tools/data-conversion/openim/mysql/v3/user.go | 25 +++- tools/formitychecker/checker/checker.go | 3 +- tools/infra/infra.go | 4 +- tools/url2im/main.go | 43 ++++-- 131 files changed, 1127 insertions(+), 875 deletions(-) mode change 100755 => 100644 pkg/common/tls/tls.go create mode 100644 test/codescan/main.go create mode 100644 test/e2e/page/chat_page.go create mode 100644 test/e2e/page/login_page.go delete mode 100644 test/e2e/web/.keep create mode 100644 test/e2e/web/Readme.md diff --git a/.github/workflows/e2e-test.yml b/.github/workflows/e2e-test.yml index 6970e7d9c7..b5f901d250 100644 --- a/.github/workflows/e2e-test.yml +++ b/.github/workflows/e2e-test.yml @@ -92,6 +92,7 @@ jobs: - name: Exec OpenIM API test run: | + sudo make test-api mkdir -p ./tmp touch ./tmp/test.md echo "# OpenIM Test" >> ./tmp/test.md @@ -104,6 +105,7 @@ jobs: - name: Exec OpenIM E2E Test run: | + sudo make test-e2e echo "" >> ./tmp/test.md echo "## OpenIM E2E Test" >> ./tmp/test.md echo "
Command Output for OpenIM E2E Test" >> ./tmp/test.md diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index bc1b094bf8..c123566f1c 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -74,6 +74,17 @@ jobs: 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 diff --git a/CHANGELOG/CHANGELOG-3.5.md b/CHANGELOG/CHANGELOG-3.5.md index ed9ba77c65..0a7f5bfa35 100644 --- a/CHANGELOG/CHANGELOG-3.5.md +++ b/CHANGELOG/CHANGELOG-3.5.md @@ -8,6 +8,21 @@ ## [Unreleased] + +## [v3.5.1-alpha.2] - 2024-01-26 + + +## [v3.5.0+15.d356f7a] - 2024-01-26 + + +## [v3.5.1-rc.1] - 2024-01-23 + + +## [v3.5.0+2.e0bd54f-3-g52f9fc209] - 2024-01-12 + + +## [v3.5.0+2.e0bd54f-1-g4ce6a0fa6] - 2024-01-12 + ## [v3.5.1-alpha.1] - 2024-01-09 @@ -59,7 +74,12 @@ - Merge branch 'tuoyun' -[Unreleased]: https://github.com/openimsdk/open-im-server/compare/v3.5.1-alpha.1...HEAD +[Unreleased]: https://github.com/openimsdk/open-im-server/compare/v3.5.1-alpha.2...HEAD +[v3.5.1-alpha.2]: https://github.com/openimsdk/open-im-server/compare/v3.5.0+15.d356f7a...v3.5.1-alpha.2 +[v3.5.0+15.d356f7a]: https://github.com/openimsdk/open-im-server/compare/v3.5.1-rc.1...v3.5.0+15.d356f7a +[v3.5.1-rc.1]: https://github.com/openimsdk/open-im-server/compare/v3.5.0+2.e0bd54f-3-g52f9fc209...v3.5.1-rc.1 +[v3.5.0+2.e0bd54f-3-g52f9fc209]: https://github.com/openimsdk/open-im-server/compare/v3.5.0+2.e0bd54f-1-g4ce6a0fa6...v3.5.0+2.e0bd54f-3-g52f9fc209 +[v3.5.0+2.e0bd54f-1-g4ce6a0fa6]: https://github.com/openimsdk/open-im-server/compare/v3.5.1-alpha.1...v3.5.0+2.e0bd54f-1-g4ce6a0fa6 [v3.5.1-alpha.1]: https://github.com/openimsdk/open-im-server/compare/v3.5.0...v3.5.1-alpha.1 [v3.5.0]: https://github.com/openimsdk/open-im-server/compare/v3.5.1...v3.5.0 [v3.5.1]: https://github.com/openimsdk/open-im-server/compare/v3.5.1-bate.1...v3.5.1 diff --git a/Makefile b/Makefile index 4faf1c21d4..89b9e41522 100644 --- a/Makefile +++ b/Makefile @@ -184,7 +184,7 @@ test-e2e: imports: @$(MAKE) go.imports -## clean: Remove all files that are created by building. ✨ +## clean: Delete all files created by the build, as well as all log files. ✨ .PHONY: clean clean: @$(MAKE) go.clean diff --git a/cmd/openim-api/main.go b/cmd/openim-api/main.go index 34ada1d579..eeaa04d075 100644 --- a/cmd/openim-api/main.go +++ b/cmd/openim-api/main.go @@ -67,20 +67,22 @@ func run(port int, proPort int) error { // Determine whether zk is passed according to whether it is a clustered deployment client, err = kdisc.NewDiscoveryRegister(config.Config.Envs.Discovery) if err != nil { - return errs.Wrap(err, "register discovery err") + return err } if err = client.CreateRpcRootNodes(config.Config.GetServiceNames()); err != nil { - return errs.Wrap(err, "create rpc root nodes error") + return err } if err = client.RegisterConf2Registry(constant.OpenIMCommonConfigKey, config.Config.EncodeConfig()); err != nil { return err } + var ( netDone = make(chan struct{}, 1) netErr error ) + router := api.NewGinRouter(client, rdb) if config.Config.Prometheus.Enable { go func() { @@ -91,7 +93,6 @@ func run(port int, proPort int) error { netDone <- struct{}{} } }() - } var address string @@ -108,7 +109,6 @@ func run(port int, proPort int) error { if err != nil && err != http.ErrServerClosed { netErr = errs.Wrap(err, fmt.Sprintf("api start err: %s", server.Addr)) netDone <- struct{}{} - } }() @@ -122,7 +122,7 @@ func run(port int, proPort int) error { util.SIGTERMExit() err := server.Shutdown(ctx) if err != nil { - return errs.Wrap(err, "shutdown err") + return errs.Wrap(err, "api shutdown err") } case <-netDone: close(netDone) diff --git a/cmd/openim-push/main.go b/cmd/openim-push/main.go index e0539fa52c..bd31ffdef3 100644 --- a/cmd/openim-push/main.go +++ b/cmd/openim-push/main.go @@ -26,7 +26,7 @@ func main() { pushCmd.AddPortFlag() pushCmd.AddPrometheusPortFlag() if err := pushCmd.Exec(); err != nil { - panic(err.Error()) + util.ExitWithError(err) } if err := pushCmd.StartSvr(config.Config.RpcRegisterName.OpenImPushName, push.Start); err != nil { util.ExitWithError(err) diff --git a/cmd/openim-rpc/openim-rpc-auth/main.go b/cmd/openim-rpc/openim-rpc-auth/main.go index b526c3b86e..992a2b4328 100644 --- a/cmd/openim-rpc/openim-rpc-auth/main.go +++ b/cmd/openim-rpc/openim-rpc-auth/main.go @@ -26,7 +26,7 @@ func main() { authCmd.AddPortFlag() authCmd.AddPrometheusPortFlag() if err := authCmd.Exec(); err != nil { - panic(err.Error()) + util.ExitWithError(err) } if err := authCmd.StartSvr(config.Config.RpcRegisterName.OpenImAuthName, auth.Start); err != nil { util.ExitWithError(err) diff --git a/cmd/openim-rpc/openim-rpc-conversation/main.go b/cmd/openim-rpc/openim-rpc-conversation/main.go index bde191c518..10fe0b46c2 100644 --- a/cmd/openim-rpc/openim-rpc-conversation/main.go +++ b/cmd/openim-rpc/openim-rpc-conversation/main.go @@ -26,7 +26,7 @@ func main() { rpcCmd.AddPortFlag() rpcCmd.AddPrometheusPortFlag() if err := rpcCmd.Exec(); err != nil { - panic(err.Error()) + util.ExitWithError(err) } if err := rpcCmd.StartSvr(config.Config.RpcRegisterName.OpenImConversationName, conversation.Start); err != nil { util.ExitWithError(err) diff --git a/cmd/openim-rpc/openim-rpc-friend/main.go b/cmd/openim-rpc/openim-rpc-friend/main.go index 8eeb9c8e13..63de23293e 100644 --- a/cmd/openim-rpc/openim-rpc-friend/main.go +++ b/cmd/openim-rpc/openim-rpc-friend/main.go @@ -26,7 +26,7 @@ func main() { rpcCmd.AddPortFlag() rpcCmd.AddPrometheusPortFlag() if err := rpcCmd.Exec(); err != nil { - panic(err.Error()) + util.ExitWithError(err) } if err := rpcCmd.StartSvr(config.Config.RpcRegisterName.OpenImFriendName, friend.Start); err != nil { util.ExitWithError(err) diff --git a/cmd/openim-rpc/openim-rpc-group/main.go b/cmd/openim-rpc/openim-rpc-group/main.go index a5842ffd13..c0780acab4 100644 --- a/cmd/openim-rpc/openim-rpc-group/main.go +++ b/cmd/openim-rpc/openim-rpc-group/main.go @@ -26,7 +26,7 @@ func main() { rpcCmd.AddPortFlag() rpcCmd.AddPrometheusPortFlag() if err := rpcCmd.Exec(); err != nil { - panic(err.Error()) + util.ExitWithError(err) } if err := rpcCmd.StartSvr(config.Config.RpcRegisterName.OpenImGroupName, group.Start); err != nil { util.ExitWithError(err) diff --git a/cmd/openim-rpc/openim-rpc-msg/main.go b/cmd/openim-rpc/openim-rpc-msg/main.go index b3895a5027..62bdff0a5a 100644 --- a/cmd/openim-rpc/openim-rpc-msg/main.go +++ b/cmd/openim-rpc/openim-rpc-msg/main.go @@ -26,7 +26,7 @@ func main() { rpcCmd.AddPortFlag() rpcCmd.AddPrometheusPortFlag() if err := rpcCmd.Exec(); err != nil { - panic(err.Error()) + util.ExitWithError(err) } if err := rpcCmd.StartSvr(config.Config.RpcRegisterName.OpenImMsgName, msg.Start); err != nil { util.ExitWithError(err) diff --git a/cmd/openim-rpc/openim-rpc-third/main.go b/cmd/openim-rpc/openim-rpc-third/main.go index 8f390bb6a4..c2893a398d 100644 --- a/cmd/openim-rpc/openim-rpc-third/main.go +++ b/cmd/openim-rpc/openim-rpc-third/main.go @@ -26,7 +26,7 @@ func main() { rpcCmd.AddPortFlag() rpcCmd.AddPrometheusPortFlag() if err := rpcCmd.Exec(); err != nil { - panic(err.Error()) + util.ExitWithError(err) } if err := rpcCmd.StartSvr(config.Config.RpcRegisterName.OpenImThirdName, third.Start); err != nil { util.ExitWithError(err) diff --git a/cmd/openim-rpc/openim-rpc-user/main.go b/cmd/openim-rpc/openim-rpc-user/main.go index 6994ea2b15..f7948bda08 100644 --- a/cmd/openim-rpc/openim-rpc-user/main.go +++ b/cmd/openim-rpc/openim-rpc-user/main.go @@ -26,7 +26,7 @@ func main() { rpcCmd.AddPortFlag() rpcCmd.AddPrometheusPortFlag() if err := rpcCmd.Exec(); err != nil { - panic(err.Error()) + util.ExitWithError(err) } if err := rpcCmd.StartSvr(config.Config.RpcRegisterName.OpenImUserName, user.Start); err != nil { util.ExitWithError(err) diff --git a/docs/contrib/code-conventions.md b/docs/contrib/code-conventions.md index 049df63811..6b534779b2 100644 --- a/docs/contrib/code-conventions.md +++ b/docs/contrib/code-conventions.md @@ -3,7 +3,15 @@ - [Code conventions](#code-conventions) - [POSIX shell](#posix-shell) - [Go](#go) - - [Directory and file conventions](#directory-and-file-conventions) + - [OpenIM Naming Conventions Guide](#openim-naming-conventions-guide) + - [1. General File Naming](#1-general-file-naming) + - [2. Special File Types](#2-special-file-types) + - [a. Script and Markdown Files](#a-script-and-markdown-files) + - [b. Uppercase Markdown Documentation](#b-uppercase-markdown-documentation) + - [3. Directory Naming](#3-directory-naming) + - [4. Configuration Files](#4-configuration-files) + - [Best Practices](#best-practices) + - [Directory and File Conventions](#directory-and-file-conventions) - [Testing conventions](#testing-conventions) ## POSIX shell @@ -67,12 +75,13 @@ Files within the OpenIM project should adhere to the following rules: + Stick to lowercase naming where possible for consistency and to prevent issues with case-sensitive systems. + Include version numbers or dates in file names if the file is subject to updates, following the format: `project-plan-v1.2.md` or `backup-2023-03-15.sql`. -## Directory and file conventions +## Directory and File Conventions + +- Avoid generic utility packages. Instead of naming a package "util", choose a name that clearly describes its purpose. For instance, functions related to waiting operations are contained within the `wait` package, which includes methods like `Poll`, fully named as `wait.Poll`. +- All filenames, script files, configuration files, and directories should be in lowercase and use dashes (`-`) as separators. +- For Go language files, filenames should be in lowercase and use underscores (`_`). +- Package names should match their directory names to ensure consistency. For example, within the `openim-api` directory, the Go file should be named `openim-api.go`, following the convention of using dashes for directory names and aligning package names with directory names. -- Avoid general utility packages. Packages called "util" are suspect. Instead, derive a name that describes your desired function. For example, the utility functions dealing with waiting for operations are in the `wait` package and include functionality like `Poll`. The full name is `wait.Poll`. -- All filenames should be lowercase. -- All source files and directories should use underscores, not dashes. - - Package directories should generally avoid using separators as much as possible. When package names are multiple words, they usually should be in nested subdirectories. ## Testing conventions diff --git a/internal/api/custom_validator.go b/internal/api/custom_validator.go index 8c5890501b..1df4169e45 100644 --- a/internal/api/custom_validator.go +++ b/internal/api/custom_validator.go @@ -20,19 +20,16 @@ import ( "github.com/OpenIMSDK/protocol/constant" ) +// RequiredIf validates if the specified field is required based on the session type. func RequiredIf(fl validator.FieldLevel) bool { sessionType := fl.Parent().FieldByName("SessionType").Int() + switch sessionType { case constant.SingleChatType, constant.NotificationChatType: - if fl.FieldName() == "RecvID" { - return fl.Field().String() != "" - } + return fl.FieldName() != "RecvID" || fl.Field().String() != "" case constant.GroupChatType, constant.SuperGroupChatType: - if fl.FieldName() == "GroupID" { - return fl.Field().String() != "" - } + return fl.FieldName() != "GroupID" || fl.Field().String() != "" default: return true } - return true } diff --git a/internal/api/msg.go b/internal/api/msg.go index 9348596ace..1bbcf5428d 100644 --- a/internal/api/msg.go +++ b/internal/api/msg.go @@ -210,7 +210,6 @@ func (m *MessageApi) SendMessage(c *gin.Context) { sendMsgReq, err := m.getSendMsgReq(c, req.SendMsg) if err != nil { // Log and respond with an error if preparation fails. - log.ZError(c, "decodeData failed", err) apiresp.GinError(c, err) return } @@ -226,7 +225,6 @@ func (m *MessageApi) SendMessage(c *gin.Context) { if err != nil { // Set the status to failed and respond with an error if sending fails. status = constant.MsgSendFailed - log.ZError(c, "send message err", err) apiresp.GinError(c, err) return } @@ -240,7 +238,8 @@ func (m *MessageApi) SendMessage(c *gin.Context) { }) if err != nil { // Log the error if updating the status fails. - log.ZError(c, "SetSendMsgStatus failed", err) + apiresp.GinError(c, err) + return } // Respond with a success message and the response payload. @@ -299,7 +298,6 @@ func (m *MessageApi) BatchSendMsg(c *gin.Context) { resp apistruct.BatchSendMsgResp ) if err := c.BindJSON(&req); err != nil { - log.ZError(c, "BatchSendMsg BindJSON failed", err) apiresp.GinError(c, errs.ErrArgs.WithDetail(err.Error()).Wrap()) return } @@ -310,14 +308,12 @@ func (m *MessageApi) BatchSendMsg(c *gin.Context) { } var recvIDs []string - var err error if req.IsSendAll { pageNumber := 1 showNumber := 500 for { recvIDsPart, err := m.userRpcClient.GetAllUserIDs(c, int32(pageNumber), int32(showNumber)) if err != nil { - log.ZError(c, "GetAllUserIDs failed", err) apiresp.GinError(c, err) return } @@ -333,7 +329,6 @@ func (m *MessageApi) BatchSendMsg(c *gin.Context) { log.ZDebug(c, "BatchSendMsg nums", "nums ", len(recvIDs)) sendMsgReq, err := m.getSendMsgReq(c, req.SendMsg) if err != nil { - log.ZError(c, "decodeData failed", err) apiresp.GinError(c, err) return } diff --git a/internal/api/route.go b/internal/api/route.go index 24ed5f6bb4..a6d73b6835 100644 --- a/internal/api/route.go +++ b/internal/api/route.go @@ -44,7 +44,7 @@ import ( ) func NewGinRouter(discov discoveryregistry.SvcDiscoveryRegistry, rdb redis.UniversalClient) *gin.Engine { - discov.AddOption(mw.GrpcClient(), grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithDefaultServiceConfig(fmt.Sprintf(`{"LoadBalancingPolicy": "%s"}`, "round_robin"))) // 默认RPC中间件 + discov.AddOption(mw.GrpcClient(), grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithDefaultServiceConfig(fmt.Sprintf(`{"LoadBalancingPolicy": "%s"}`, "round_robin"))) // Default RPC middleware gin.SetMode(gin.ReleaseMode) r := gin.New() if v, ok := binding.Validator.Engine().(*validator.Validate); ok { @@ -225,6 +225,7 @@ func NewGinRouter(discov discoveryregistry.SvcDiscoveryRegistry, rdb redis.Unive return r } +// GinParseToken is a middleware that parses the token in the request header and verifies it. func GinParseToken(rdb redis.UniversalClient) gin.HandlerFunc { dataBase := controller.NewAuthDatabase( cache.NewMsgCacheModel(rdb), @@ -250,13 +251,11 @@ func GinParseToken(rdb redis.UniversalClient) gin.HandlerFunc { } m, err := dataBase.GetTokensWithoutError(c, claims.UserID, claims.PlatformID) if err != nil { - log.ZWarn(c, "cache get token error", errs.ErrTokenNotExist.Wrap()) apiresp.GinError(c, errs.ErrTokenNotExist.Wrap()) c.Abort() return } if len(m) == 0 { - log.ZWarn(c, "cache do not exist token error", errs.ErrTokenNotExist.Wrap()) apiresp.GinError(c, errs.ErrTokenNotExist.Wrap()) c.Abort() return @@ -265,12 +264,10 @@ func GinParseToken(rdb redis.UniversalClient) gin.HandlerFunc { switch v { case constant.NormalToken: case constant.KickedToken: - log.ZWarn(c, "cache kicked token error", errs.ErrTokenKicked.Wrap()) apiresp.GinError(c, errs.ErrTokenKicked.Wrap()) c.Abort() return default: - log.ZWarn(c, "cache unknown token error", errs.ErrTokenUnknown.Wrap()) apiresp.GinError(c, errs.ErrTokenUnknown.Wrap()) c.Abort() return @@ -286,3 +283,10 @@ func GinParseToken(rdb redis.UniversalClient) gin.HandlerFunc { } } } + +// // handleGinError logs and returns an error response through Gin context. +// func handleGinError(c *gin.Context, logMessage string, errType errs.CodeError, detail string) { +// wrappedErr := errType.Wrap(detail) +// apiresp.GinError(c, wrappedErr) +// c.Abort() +// } diff --git a/internal/api/user.go b/internal/api/user.go index e7bbd4bfbc..9019983193 100644 --- a/internal/api/user.go +++ b/internal/api/user.go @@ -68,7 +68,7 @@ func (u *UserApi) GetUsers(c *gin.Context) { func (u *UserApi) GetUsersOnlineStatus(c *gin.Context) { var req msggateway.GetUsersOnlineStatusReq if err := c.BindJSON(&req); err != nil { - apiresp.GinError(c, errs.ErrArgs.WithDetail(err.Error()).Wrap()) + apiresp.GinError(c, err) return } conns, err := u.Discov.GetConns(c, config.Config.RpcRegisterName.OpenImMessageGatewayName) @@ -86,7 +86,7 @@ func (u *UserApi) GetUsersOnlineStatus(c *gin.Context) { msgClient := msggateway.NewMsgGatewayClient(v) reply, err := msgClient.GetUsersOnlineStatus(c, &req) if err != nil { - log.ZWarn(c, "GetUsersOnlineStatus rpc err", err) + log.ZDebug(c, "GetUsersOnlineStatus rpc error", err) parseError := apiresp.ParseError(err) if parseError.ErrCode == errs.NoPermissionError { diff --git a/internal/msggateway/client.go b/internal/msggateway/client.go index 9a4005e6c0..06efea12f4 100644 --- a/internal/msggateway/client.go +++ b/internal/msggateway/client.go @@ -91,13 +91,7 @@ type Client struct { // } // ResetClient updates the client's state with new connection and context information. -func (c *Client) ResetClient( - ctx *UserConnContext, - conn LongConn, - isBackground, isCompress bool, - longConnServer LongConnServer, - token string, -) { +func (c *Client) ResetClient(ctx *UserConnContext, conn LongConn, isBackground, isCompress bool, longConnServer LongConnServer, token string) { c.w = new(sync.Mutex) c.conn = conn c.PlatformID = utils.StringToInt(ctx.GetPlatformID()) @@ -112,9 +106,11 @@ func (c *Client) ResetClient( c.token = token } -// pingHandler handles ping messages and sends pong responses. func (c *Client) pingHandler(_ string) error { - _ = c.conn.SetReadDeadline(pongWait) + if err := c.conn.SetReadDeadline(pongWait); err != nil { + return err + } + return c.writePongMsg() } @@ -141,7 +137,8 @@ func (c *Client) readMessage() { } log.ZDebug(c.ctx, "readMessage", "messageType", messageType) - if c.closed.Load() { // 连接刚置位已经关闭,但是协程还没退出的场景 + if c.closed.Load() { + // The scenario where the connection has just been closed, but the coroutine has not exited c.closedErr = ErrConnClosed return } @@ -185,11 +182,11 @@ func (c *Client) handleMessage(message []byte) error { err := c.longConnServer.Decode(message, binaryReq) if err != nil { - return errs.Wrap(err) + return err } if err := c.longConnServer.Validate(binaryReq); err != nil { - return errs.Wrap(err) + return err } if binaryReq.SendID != c.UserID { @@ -239,7 +236,7 @@ func (c *Client) setAppBackgroundStatus(ctx context.Context, req *Req) ([]byte, } c.IsBackground = isBackground - // todo callback + // TODO: callback return resp, nil } @@ -273,7 +270,7 @@ func (c *Client) replyMessage(ctx context.Context, binaryReq *Req, err error, re } if binaryReq.ReqIdentifier == WsLogoutMsg { - return errors.New("user logout") + return errs.Wrap(errors.New("user logout")) } return nil } @@ -316,17 +313,21 @@ func (c *Client) writeBinaryMsg(resp Resp) error { encodedBuf, err := c.longConnServer.Encode(resp) if err != nil { - return errs.Wrap(err) + return err } c.w.Lock() defer c.w.Unlock() - _ = c.conn.SetWriteDeadline(writeWait) + err = c.conn.SetWriteDeadline(writeWait) + if err != nil { + return err + } + if c.IsCompress { resultBuf, compressErr := c.longConnServer.CompressWithPool(encodedBuf) if compressErr != nil { - return errs.Wrap(compressErr) + return compressErr } return c.conn.WriteMessage(MessageBinary, resultBuf) } @@ -344,7 +345,7 @@ func (c *Client) writePongMsg() error { err := c.conn.SetWriteDeadline(writeWait) if err != nil { - return errs.Wrap(err) + return err } return c.conn.WriteMessage(PongMessage, nil) diff --git a/internal/msggateway/compressor.go b/internal/msggateway/compressor.go index d4789536e1..140aac4d86 100644 --- a/internal/msggateway/compressor.go +++ b/internal/msggateway/compressor.go @@ -17,7 +17,6 @@ package msggateway import ( "bytes" "compress/gzip" - "errors" "io" "sync" @@ -46,12 +45,15 @@ func NewGzipCompressor() *GzipCompressor { func (g *GzipCompressor) Compress(rawData []byte) ([]byte, error) { gzipBuffer := bytes.Buffer{} gz := gzip.NewWriter(&gzipBuffer) + if _, err := gz.Write(rawData); err != nil { - return nil, errs.Wrap(err) + return nil, errs.Wrap(err, "GzipCompressor.Compress: writing to gzip writer failed") } + if err := gz.Close(); err != nil { - return nil, errs.Wrap(err) + return nil, errs.Wrap(err, "GzipCompressor.Compress: closing gzip writer failed") } + return gzipBuffer.Bytes(), nil } @@ -63,10 +65,10 @@ func (g *GzipCompressor) CompressWithPool(rawData []byte) ([]byte, error) { gz.Reset(&gzipBuffer) if _, err := gz.Write(rawData); err != nil { - return nil, errs.Wrap(err) + return nil, errs.Wrap(err, "GzipCompressor.CompressWithPool: error writing data") } if err := gz.Close(); err != nil { - return nil, errs.Wrap(err) + return nil, errs.Wrap(err, "GzipCompressor.CompressWithPool: error closing gzip writer") } return gzipBuffer.Bytes(), nil } @@ -75,32 +77,36 @@ func (g *GzipCompressor) DeCompress(compressedData []byte) ([]byte, error) { buff := bytes.NewBuffer(compressedData) reader, err := gzip.NewReader(buff) if err != nil { - return nil, errs.Wrap(err, "NewReader failed") + return nil, errs.Wrap(err, "GzipCompressor.DeCompress: NewReader creation failed") } - compressedData, err = io.ReadAll(reader) + decompressedData, err := io.ReadAll(reader) if err != nil { - return nil, errs.Wrap(err, "ReadAll failed") + return nil, errs.Wrap(err, "GzipCompressor.DeCompress: reading from gzip reader failed") } - _ = reader.Close() - return compressedData, nil + if err = reader.Close(); err != nil { + // Even if closing the reader fails, we've successfully read the data, + // so we return the decompressed data and an error indicating the close failure. + return decompressedData, errs.Wrap(err, "GzipCompressor.DeCompress: closing gzip reader failed") + } + return decompressedData, nil } func (g *GzipCompressor) DecompressWithPool(compressedData []byte) ([]byte, error) { reader := gzipReaderPool.Get().(*gzip.Reader) - if reader == nil { - return nil, errs.Wrap(errors.New("NewReader failed")) - } defer gzipReaderPool.Put(reader) err := reader.Reset(bytes.NewReader(compressedData)) if err != nil { - return nil, errs.Wrap(err, "NewReader failed") + return nil, errs.Wrap(err, "GzipCompressor.DecompressWithPool: resetting gzip reader failed") } - compressedData, err = io.ReadAll(reader) + decompressedData, err := io.ReadAll(reader) if err != nil { - return nil, errs.Wrap(err, "ReadAll failed") + return nil, errs.Wrap(err, "GzipCompressor.DecompressWithPool: reading from pooled gzip reader failed") + } + if err = reader.Close(); err != nil { + // Similar to DeCompress, return the data and error for close failure. + return decompressedData, errs.Wrap(err, "GzipCompressor.DecompressWithPool: closing pooled gzip reader failed") } - _ = reader.Close() - return compressedData, nil + return decompressedData, nil } diff --git a/internal/msggateway/compressor_test.go b/internal/msggateway/compressor_test.go index b1544f063f..bb7106d9f5 100644 --- a/internal/msggateway/compressor_test.go +++ b/internal/msggateway/compressor_test.go @@ -37,10 +37,16 @@ func TestCompressDecompress(t *testing.T) { // compress dest, err := compressor.CompressWithPool(src) + if err != nil { + t.Log(err) + } assert.Equal(t, nil, err) // decompress res, err := compressor.DecompressWithPool(dest) + if err != nil { + t.Log(err) + } assert.Equal(t, nil, err) // check @@ -60,10 +66,16 @@ func TestCompressDecompressWithConcurrency(t *testing.T) { // compress dest, err := compressor.CompressWithPool(src) + if err != nil { + t.Log(err) + } assert.Equal(t, nil, err) // decompress res, err := compressor.DecompressWithPool(dest) + if err != nil { + t.Log(err) + } assert.Equal(t, nil, err) // check @@ -99,6 +111,7 @@ func BenchmarkDecompress(b *testing.B) { compressor := NewGzipCompressor() comdata, err := compressor.Compress(src) + assert.Equal(b, nil, err) for i := 0; i < b.N; i++ { diff --git a/internal/msggateway/encoder.go b/internal/msggateway/encoder.go index 69a899591a..cd2c50d964 100644 --- a/internal/msggateway/encoder.go +++ b/internal/msggateway/encoder.go @@ -37,7 +37,7 @@ func (g *GobEncoder) Encode(data any) ([]byte, error) { enc := gob.NewEncoder(&buff) err := enc.Encode(data) if err != nil { - return nil, err + return nil, errs.Wrap(err, "GobEncoder.Encode failed") } return buff.Bytes(), nil } @@ -47,7 +47,7 @@ func (g *GobEncoder) Decode(encodeData []byte, decodeData any) error { dec := gob.NewDecoder(buff) err := dec.Decode(decodeData) if err != nil { - return errs.Wrap(err) + return errs.Wrap(err, "GobEncoder.Decode failed") } return nil } diff --git a/internal/msggateway/init.go b/internal/msggateway/init.go index b18efcd50d..5d19ad16d0 100644 --- a/internal/msggateway/init.go +++ b/internal/msggateway/init.go @@ -23,14 +23,7 @@ import ( // RunWsAndServer run ws server. func RunWsAndServer(rpcPort, wsPort, prometheusPort int) error { - fmt.Println( - "start rpc/msg_gateway server, port: ", - rpcPort, - wsPort, - prometheusPort, - ", OpenIM version: ", - config.Version, - ) + fmt.Println("start rpc/msg_gateway server, port: ", rpcPort, wsPort, prometheusPort, ", OpenIM version: ", config.Version) longServer, err := NewWsServer( WithPort(wsPort), WithMaxConnNum(int64(config.Config.LongConnSvr.WebsocketMaxConnNum)), diff --git a/internal/msggateway/long_conn.go b/internal/msggateway/long_conn.go index a4251a50fe..7dc79c834f 100644 --- a/internal/msggateway/long_conn.go +++ b/internal/msggateway/long_conn.go @@ -15,9 +15,11 @@ package msggateway import ( + "errors" "net/http" "time" + "github.com/OpenIMSDK/tools/errs" "github.com/gorilla/websocket" ) @@ -72,7 +74,8 @@ func (d *GWebSocket) GenerateLongConn(w http.ResponseWriter, r *http.Request) er conn, err := upgrader.Upgrade(w, r, nil) if err != nil { - return err + // The upgrader.Upgrade method usually returns enough error messages to diagnose problems that may occur during the upgrade + return errs.Wrap(err, "GenerateLongConn: WebSocket upgrade failed") } d.conn = conn return nil @@ -96,7 +99,16 @@ func (d *GWebSocket) SetReadDeadline(timeout time.Duration) error { } func (d *GWebSocket) SetWriteDeadline(timeout time.Duration) error { - return d.conn.SetWriteDeadline(time.Now().Add(timeout)) + // TODO add error + if timeout <= 0 { + return errs.Wrap(errors.New("timeout must be greater than 0")) + } + + // TODO SetWriteDeadline Future add error handling + if err := d.conn.SetWriteDeadline(time.Now().Add(timeout)); err != nil { + return errs.Wrap(err, "GWebSocket.SetWriteDeadline failed") + } + return nil } func (d *GWebSocket) Dial(urlStr string, requestHeader http.Header) (*http.Response, error) { diff --git a/internal/msggateway/message_handler.go b/internal/msggateway/message_handler.go index dd5e00f18c..3c5bd6121a 100644 --- a/internal/msggateway/message_handler.go +++ b/internal/msggateway/message_handler.go @@ -20,6 +20,7 @@ import ( "github.com/OpenIMSDK/protocol/push" "github.com/OpenIMSDK/tools/discoveryregistry" + "github.com/OpenIMSDK/tools/errs" "github.com/go-playground/validator/v10" "google.golang.org/protobuf/proto" @@ -119,10 +120,10 @@ func NewGrpcHandler(validate *validator.Validate, client discoveryregistry.SvcDi func (g GrpcHandler) GetSeq(context context.Context, data *Req) ([]byte, error) { req := sdkws.GetMaxSeqReq{} if err := proto.Unmarshal(data.Data, &req); err != nil { - return nil, err + return nil, errs.Wrap(err, "GetSeq: error unmarshaling request") } if err := g.validate.Struct(&req); err != nil { - return nil, err + return nil, errs.Wrap(err, "GetSeq: validation failed") } resp, err := g.msgRpcClient.GetMaxSeq(context, &req) if err != nil { @@ -130,28 +131,37 @@ func (g GrpcHandler) GetSeq(context context.Context, data *Req) ([]byte, error) } c, err := proto.Marshal(resp) if err != nil { - return nil, err + return nil, errs.Wrap(err, "GetSeq: error marshaling response") } return c, nil } -func (g GrpcHandler) SendMessage(context context.Context, data *Req) ([]byte, error) { - msgData := sdkws.MsgData{} +// SendMessage handles the sending of messages through gRPC. It unmarshals the request data, +// validates the message, and then sends it using the message RPC client. +func (g GrpcHandler) SendMessage(ctx context.Context, data *Req) ([]byte, error) { + // Unmarshal the message data from the request. + var msgData sdkws.MsgData if err := proto.Unmarshal(data.Data, &msgData); err != nil { - return nil, err + return nil, errs.Wrap(err, "error unmarshalling message data") } + + // Validate the message data structure. if err := g.validate.Struct(&msgData); err != nil { - return nil, err + return nil, errs.Wrap(err, "message data validation failed") } + req := msg.SendMsgReq{MsgData: &msgData} - resp, err := g.msgRpcClient.SendMsg(context, &req) + + resp, err := g.msgRpcClient.SendMsg(ctx, &req) if err != nil { return nil, err } + c, err := proto.Marshal(resp) if err != nil { - return nil, err + return nil, errs.Wrap(err, "error marshaling response") } + return c, nil } @@ -162,7 +172,7 @@ func (g GrpcHandler) SendSignalMessage(context context.Context, data *Req) ([]by } c, err := proto.Marshal(resp) if err != nil { - return nil, err + return nil, errs.Wrap(err, "error marshaling response") } return c, nil } @@ -170,7 +180,7 @@ func (g GrpcHandler) SendSignalMessage(context context.Context, data *Req) ([]by func (g GrpcHandler) PullMessageBySeqList(context context.Context, data *Req) ([]byte, error) { req := sdkws.PullMessageBySeqsReq{} if err := proto.Unmarshal(data.Data, &req); err != nil { - return nil, err + return nil, errs.Wrap(err, "error unmarshaling request") } if err := g.validate.Struct(data); err != nil { return nil, err diff --git a/internal/msggateway/n_ws_server.go b/internal/msggateway/n_ws_server.go index b734dee6d5..f466a7dc44 100644 --- a/internal/msggateway/n_ws_server.go +++ b/internal/msggateway/n_ws_server.go @@ -88,6 +88,7 @@ type WsServer struct { Encoder MessageHandler } + type kickHandler struct { clientOK bool oldClients []*Client @@ -129,7 +130,9 @@ func (ws *WsServer) UnRegister(c *Client) { } func (ws *WsServer) Validate(s any) error { - //?question? + if s == nil { + return errs.Wrap(errors.New("input cannot be nil")) + } return nil } @@ -276,7 +279,7 @@ func (ws *WsServer) registerClient(client *Client) { log.ZDebug(client.ctx, "user exist", "userID", client.UserID, "platformID", client.PlatformID) if clientOK { ws.clients.Set(client.UserID, client) - // 已经有同平台的连接存在 + // There is already a connection to the platform log.ZInfo(client.ctx, "repeat login", "userID", client.UserID, "platformID", client.PlatformID, "old remote addr", getRemoteAdders(oldClients)) ws.onlineUserConnNum.Add(1) } else { diff --git a/internal/msggateway/options.go b/internal/msggateway/options.go index 6513ac5dc9..b65f8e36cb 100644 --- a/internal/msggateway/options.go +++ b/internal/msggateway/options.go @@ -19,15 +19,15 @@ import "time" type ( Option func(opt *configs) configs struct { - // 长连接监听端口 + // Long connection listening port port int - // 长连接允许最大链接数 + // Maximum number of connections allowed for long connection maxConnNum int64 - // 连接握手超时时间 + // Connection handshake timeout handshakeTimeout time.Duration - // 允许消息最大长度 + // Maximum length allowed for messages messageMaxMsgLength int - // websocket write buffer, default: 4096, 4kb. + // Websocket write buffer, default: 4096, 4kb. writeBufferSize int } ) diff --git a/internal/msgtransfer/init.go b/internal/msgtransfer/init.go index 9b1b853f28..b5f8516f88 100644 --- a/internal/msgtransfer/init.go +++ b/internal/msgtransfer/init.go @@ -45,8 +45,13 @@ import ( ) type MsgTransfer struct { - historyCH *OnlineHistoryRedisConsumerHandler // 这个消费者聚合消息, 订阅的topic:ws2ms_chat, 修改通知发往msg_to_modify topic, 消息存入redis后Incr Redis, 再发消息到ms2pschat topic推送, 发消息到msg_to_mongo topic持久化 - historyMongoCH *OnlineHistoryMongoConsumerHandler // mongoDB批量插入, 成功后删除redis中消息,以及处理删除通知消息删除的 订阅的topic: msg_to_mongo + // This consumer aggregated messages, subscribed to the topic:ws2ms_chat, + // the modification notification is sent to msg_to_modify topic, the message is stored in redis, Incr Redis, + // and then the message is sent to ms2pschat topic for push, and the message is sent to msg_to_mongo topic for persistence + historyCH *OnlineHistoryRedisConsumerHandler + // mongoDB batch insert, delete messages in redis after success, + // and handle the deletion notification message deleted subscriptions topic: msg_to_mongo + historyMongoCH *OnlineHistoryMongoConsumerHandler ctx context.Context cancel context.CancelFunc } @@ -65,6 +70,7 @@ func StartTransfer(prometheusPort int) error { if err = mongo.CreateMsgIndex(); err != nil { return err } + client, err := kdisc.NewDiscoveryRegister(config.Config.Envs.Discovery) if err != nil { return err @@ -73,6 +79,7 @@ func StartTransfer(prometheusPort int) error { if err := client.CreateRpcRootNodes(config.Config.GetServiceNames()); err != nil { return err } + client.AddOption(mw.GrpcClient(), grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithDefaultServiceConfig(fmt.Sprintf(`{"LoadBalancingPolicy": "%s"}`, "round_robin"))) msgModel := cache.NewMsgCacheModel(rdb) msgDocModel := unrelation.NewMsgMongoDriver(mongo.GetDatabase()) @@ -106,7 +113,7 @@ func NewMsgTransfer(msgDatabase controller.CommonMsgDatabase, conversationRpcCli } func (m *MsgTransfer) Start(prometheusPort int) error { - fmt.Println("start msg transfer", "prometheusPort:", prometheusPort) + fmt.Println("Start msg transfer", "prometheusPort:", prometheusPort) if prometheusPort <= 0 { return errs.Wrap(errors.New("prometheusPort not correct")) } diff --git a/internal/msgtransfer/online_history_msg_handler.go b/internal/msgtransfer/online_history_msg_handler.go index 393ec7a75f..5023ac0087 100644 --- a/internal/msgtransfer/online_history_msg_handler.go +++ b/internal/msgtransfer/online_history_msg_handler.go @@ -155,21 +155,13 @@ func (och *OnlineHistoryRedisConsumerHandler) Run(channelID int) { notStorageNotificationList, ) if err := och.msgDatabase.MsgToModifyMQ(ctx, msgChannelValue.uniqueKey, conversationIDNotification, modifyMsgList); err != nil { - log.ZError( - ctx, - "msg to modify mq error", - err, - "uniqueKey", - msgChannelValue.uniqueKey, - "modifyMsgList", - modifyMsgList, - ) + log.ZError(ctx, "msg to modify mq error", err, "uniqueKey", msgChannelValue.uniqueKey, "modifyMsgList", modifyMsgList) } } } } -// 获取消息/通知 存储的消息列表, 不存储并且推送的消息列表,. +// Get messages/notifications stored message list, not stored and pushed message list. func (och *OnlineHistoryRedisConsumerHandler) getPushStorageMsgList( totalMsgs []*ContextMsg, ) (storageMsgList, notStorageMsgList, storageNotificatoinList, notStorageNotificationList, modifyMsgList []*sdkws.MsgData) { @@ -190,7 +182,7 @@ func (och *OnlineHistoryRedisConsumerHandler) getPushStorageMsgList( // clone msg from notificationMsg if options.IsSendMsg() { msg := proto.Clone(v.message).(*sdkws.MsgData) - // 消息 + // message if v.message.Options != nil { msg.Options = msgprocessor.NewMsgOptions() } diff --git a/internal/push/callback.go b/internal/push/callback.go index a572fa572c..46b5545fb3 100644 --- a/internal/push/callback.go +++ b/internal/push/callback.go @@ -31,12 +31,7 @@ func url() string { return config.Config.Callback.CallbackUrl } -func callbackOfflinePush( - ctx context.Context, - userIDs []string, - msg *sdkws.MsgData, - offlinePushUserIDs *[]string, -) error { +func callbackOfflinePush(ctx context.Context, userIDs []string, msg *sdkws.MsgData, offlinePushUserIDs *[]string) error { if !config.Config.Callback.CallbackOfflinePush.Enable || msg.ContentType == constant.Typing { return nil } @@ -59,10 +54,12 @@ func callbackOfflinePush( AtUserIDs: msg.AtUserIDList, Content: GetContent(msg), } + resp := &callbackstruct.CallbackBeforePushResp{} if err := http.CallBackPostReturn(ctx, url(), req, resp, config.Config.Callback.CallbackOfflinePush); err != nil { return err } + if len(resp.UserIDs) != 0 { *offlinePushUserIDs = resp.UserIDs } diff --git a/internal/push/offlinepush/fcm/push.go b/internal/push/offlinepush/fcm/push.go index 8145d4c170..a60570860c 100644 --- a/internal/push/offlinepush/fcm/push.go +++ b/internal/push/offlinepush/fcm/push.go @@ -39,20 +39,22 @@ type Fcm struct { cache cache.MsgModel } +// NewClient initializes a new FCM client using the Firebase Admin SDK. +// It requires the FCM service account credentials file located within the project's configuration directory. func NewClient(cache cache.MsgModel) *Fcm { - projectRoot := config.GetProjectRoot() + projectRoot, _ := config.GetProjectRoot() credentialsFilePath := filepath.Join(projectRoot, "config", config.Config.Push.Fcm.ServiceAccount) opt := option.WithCredentialsFile(credentialsFilePath) fcmApp, err := firebase.NewApp(context.Background(), nil, opt) if err != nil { return nil } - ctx := context.Background() fcmMsgClient, err := fcmApp.Messaging(ctx) if err != nil { return nil } + return &Fcm{fcmMsgCli: fcmMsgClient, cache: cache} } diff --git a/internal/push/push_to_client.go b/internal/push/push_to_client.go index 5fce34e83b..1140e8ce40 100644 --- a/internal/push/push_to_client.go +++ b/internal/push/push_to_client.go @@ -229,7 +229,8 @@ func (p *Pusher) Push2SuperGroup(ctx context.Context, groupID string, msg *sdkws }(groupID, kickedUsers) pushToUserIDs = append(pushToUserIDs, kickedUsers...) case constant.GroupDismissedNotification: - if msgprocessor.IsNotification(msgprocessor.GetConversationIDByMsg(msg)) { // 消息先到,通知后到 + // Messages arrive first, notifications arrive later + if msgprocessor.IsNotification(msgprocessor.GetConversationIDByMsg(msg)) { var tips sdkws.GroupDismissedTips if p.UnmarshalNotificationElem(msg.Content, &tips) != nil { return err diff --git a/internal/rpc/conversation/conversaion.go b/internal/rpc/conversation/conversaion.go index 8558a23ea4..582f932462 100644 --- a/internal/rpc/conversation/conversaion.go +++ b/internal/rpc/conversation/conversaion.go @@ -310,7 +310,7 @@ func (c *conversationServer) SetConversations(ctx context.Context, unequal++ } } - if err := c.conversationDatabase.SetUsersConversationFiledTx(ctx, req.UserIDs, &conversation, m); err != nil { + if err := c.conversationDatabase.SetUsersConversationFieldTx(ctx, req.UserIDs, &conversation, m); err != nil { return nil, err } if unequal > 0 { @@ -321,7 +321,7 @@ func (c *conversationServer) SetConversations(ctx context.Context, return &pbconversation.SetConversationsResp{}, nil } -// 获取超级大群开启免打扰的用户ID. +// Get user IDs with "Do Not Disturb" enabled in super large groups. func (c *conversationServer) GetRecvMsgNotNotifyUserIDs(ctx context.Context, req *pbconversation.GetRecvMsgNotNotifyUserIDsReq) (*pbconversation.GetRecvMsgNotNotifyUserIDsResp, error) { //userIDs, err := c.conversationDatabase.FindRecvMsgNotNotifyUserIDs(ctx, req.GroupID) //if err != nil { @@ -378,7 +378,7 @@ func (c *conversationServer) CreateGroupChatConversations(ctx context.Context, r } func (c *conversationServer) SetConversationMaxSeq(ctx context.Context, req *pbconversation.SetConversationMaxSeqReq) (*pbconversation.SetConversationMaxSeqResp, error) { - if err := c.conversationDatabase.UpdateUsersConversationFiled(ctx, req.OwnerUserID, req.ConversationID, + if err := c.conversationDatabase.UpdateUsersConversationField(ctx, req.OwnerUserID, req.ConversationID, map[string]any{"max_seq": req.MaxSeq}); err != nil { return nil, err } diff --git a/internal/rpc/friend/friend.go b/internal/rpc/friend/friend.go index 84702f5481..9c49af220f 100644 --- a/internal/rpc/friend/friend.go +++ b/internal/rpc/friend/friend.go @@ -278,6 +278,7 @@ func (s *friendServer) GetDesignatedFriends(ctx context.Context, req *pbfriend.G return resp, nil } +// Get the list of friend requests sent out proactively. func (s *friendServer) GetDesignatedFriendsApply(ctx context.Context, req *pbfriend.GetDesignatedFriendsApplyReq) (resp *pbfriend.GetDesignatedFriendsApplyResp, err error) { friendRequests, err := s.friendDatabase.FindBothFriendRequests(ctx, req.FromUserID, req.ToUserID) @@ -292,7 +293,7 @@ func (s *friendServer) GetDesignatedFriendsApply(ctx context.Context, return resp, nil } -// ok 获取接收到的好友申请(即别人主动申请的). +// Get received friend requests (i.e., those initiated by others). func (s *friendServer) GetPaginationFriendsApplyTo(ctx context.Context, req *pbfriend.GetPaginationFriendsApplyToReq) (resp *pbfriend.GetPaginationFriendsApplyToResp, err error) { defer log.ZInfo(ctx, utils.GetFuncName()+" Return") if err := s.userRpcClient.Access(ctx, req.UserID); err != nil { @@ -311,7 +312,6 @@ func (s *friendServer) GetPaginationFriendsApplyTo(ctx context.Context, req *pbf return resp, nil } -// ok 获取主动发出去的好友申请列表. func (s *friendServer) GetPaginationFriendsApplyFrom(ctx context.Context, req *pbfriend.GetPaginationFriendsApplyFromReq) (resp *pbfriend.GetPaginationFriendsApplyFromResp, err error) { defer log.ZInfo(ctx, utils.GetFuncName()+" Return") resp = &pbfriend.GetPaginationFriendsApplyFromResp{} diff --git a/internal/rpc/group/group.go b/internal/rpc/group/group.go index 9b1198d588..60f6c3eb5c 100644 --- a/internal/rpc/group/group.go +++ b/internal/rpc/group/group.go @@ -765,8 +765,8 @@ func (s *groupServer) GroupApplicationResponse(ctx context.Context, req *pbgroup return nil, errs.ErrGroupRequestHandled.Wrap("group request already processed") } var inGroup bool - if _, err := s.db.TakeGroupMember(ctx, req.GroupID, req.FromUserID); err == nil { - inGroup = true // 已经在群里了 + if _, takeErr := s.db.TakeGroupMember(ctx, req.GroupID, req.FromUserID); takeErr == nil { + inGroup = true // Already in group } else if !s.IsNotFound(err) { return nil, err } diff --git a/internal/rpc/third/third.go b/internal/rpc/third/third.go index 7a63d3526a..0d474d2c44 100644 --- a/internal/rpc/third/third.go +++ b/internal/rpc/third/third.go @@ -67,7 +67,7 @@ func Start(client discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) e if err != nil { return err } - // 根据配置文件策略选择 oss 方式 + // Select based on the configuration file strategy enable := config.Config.Object.Enable var o s3.Interface switch config.Config.Object.Enable { diff --git a/internal/tools/conversation.go b/internal/tools/conversation.go index 0d02753393..6b918c0d12 100644 --- a/internal/tools/conversation.go +++ b/internal/tools/conversation.go @@ -58,9 +58,9 @@ import ( // continue // } // if len(seqs) > 0 { -// if err := c.conversationDatabase.UpdateUsersConversationFiled(ctx, []string{conversation.OwnerUserID}, conversation.ConversationID, map[string]interface{}{"latest_msg_destruct_time": now}); err +// if err := c.conversationDatabase.UpdateUsersConversationField(ctx, []string{conversation.OwnerUserID}, conversation.ConversationID, map[string]interface{}{"latest_msg_destruct_time": now}); err // != nil { -// log.ZError(ctx, "updateUsersConversationFiled failed", err, "conversationID", conversation.ConversationID, "ownerUserID", conversation.OwnerUserID) +// log.ZError(ctx, "updateUsersConversationField failed", err, "conversationID", conversation.ConversationID, "ownerUserID", conversation.OwnerUserID) // continue // } // if err := c.msgNotificationSender.UserDeleteMsgsNotification(ctx, conversation.OwnerUserID, conversation.ConversationID, seqs); err != nil { @@ -139,8 +139,8 @@ func (c *MsgTool) ConversationsDestructMsgs() { continue } if len(seqs) > 0 { - if err := c.conversationDatabase.UpdateUsersConversationFiled(ctx, []string{conversation.OwnerUserID}, conversation.ConversationID, map[string]any{"latest_msg_destruct_time": now}); err != nil { - log.ZError(ctx, "updateUsersConversationFiled failed", err, "conversationID", conversation.ConversationID, "ownerUserID", conversation.OwnerUserID) + if err := c.conversationDatabase.UpdateUsersConversationField(ctx, []string{conversation.OwnerUserID}, conversation.ConversationID, map[string]any{"latest_msg_destruct_time": now}); err != nil { + log.ZError(ctx, "updateUsersConversationField failed", err, "conversationID", conversation.ConversationID, "ownerUserID", conversation.OwnerUserID) continue } if err := c.msgNotificationSender.UserDeleteMsgsNotification(ctx, conversation.OwnerUserID, conversation.ConversationID, seqs); err != nil { diff --git a/internal/tools/cron_task.go b/internal/tools/cron_task.go index decc1aa826..0544f2f859 100644 --- a/internal/tools/cron_task.go +++ b/internal/tools/cron_task.go @@ -32,7 +32,7 @@ import ( ) func StartTask() error { - fmt.Println("cron task start, config", config.Config.ChatRecordsClearTime) + fmt.Println("Cron task start, config:", config.Config.ChatRecordsClearTime) msgTool, err := InitMsgTool() if err != nil { @@ -48,16 +48,16 @@ func StartTask() error { // register cron tasks var crontab = cron.New() - fmt.Println("start chatRecordsClearTime cron task", "cron config", config.Config.ChatRecordsClearTime) + fmt.Printf("Start chatRecordsClearTime cron task, cron config: %s\n", config.Config.ChatRecordsClearTime) _, err = crontab.AddFunc(config.Config.ChatRecordsClearTime, cronWrapFunc(rdb, "cron_clear_msg_and_fix_seq", msgTool.AllConversationClearMsgAndFixSeq)) if err != nil { return errs.Wrap(err) } - fmt.Println("start msgDestruct cron task", "cron config", config.Config.MsgDestructTime) + fmt.Printf("Start msgDestruct cron task, cron config: %s\n", config.Config.MsgDestructTime) _, err = crontab.AddFunc(config.Config.MsgDestructTime, cronWrapFunc(rdb, "cron_conversations_destruct_msgs", msgTool.ConversationsDestructMsgs)) if err != nil { - return errs.Wrap(err) + return errs.Wrap(err, "cron_conversations_destruct_msgs") } // start crontab diff --git a/internal/tools/msg.go b/internal/tools/msg.go index 1ec1e03a25..7548e3c04e 100644 --- a/internal/tools/msg.go +++ b/internal/tools/msg.go @@ -197,7 +197,8 @@ func (c *MsgTool) checkMaxSeqWithMongo(ctx context.Context, conversationID strin return err } if math.Abs(float64(maxSeqMongo-maxSeqCache)) > 10 { - log.ZError(ctx, "cache max seq and mongo max seq is diff > 10", nil, "maxSeqMongo", maxSeqMongo, "minSeqMongo", minSeqMongo, "maxSeqCache", maxSeqCache, "conversationID", conversationID) + err = fmt.Errorf("cache max seq and mongo max seq is diff > 10, maxSeqMongo:%d,minSeqMongo:%d,maxSeqCache:%d,conversationID:%s", maxSeqMongo, minSeqMongo, maxSeqCache, conversationID) + return errs.Wrap(err) } return nil } @@ -219,7 +220,6 @@ func (c *MsgTool) checkMaxSeq(ctx context.Context, conversationID string) error func (c *MsgTool) FixAllSeq(ctx context.Context) error { conversationIDs, err := c.conversationDatabase.GetAllConversationIDs(ctx) if err != nil { - log.ZError(ctx, "GetAllConversationIDs failed", err) return err } for _, conversationID := range conversationIDs { diff --git a/pkg/apistruct/msg.go b/pkg/apistruct/msg.go index d23db9bf57..d1ce427fc5 100644 --- a/pkg/apistruct/msg.go +++ b/pkg/apistruct/msg.go @@ -67,6 +67,7 @@ type LocationElem struct { Longitude float64 `mapstructure:"longitude" validate:"required"` Latitude float64 `mapstructure:"latitude" validate:"required"` } + type CustomElem struct { Data string `mapstructure:"data" validate:"required"` Description string `mapstructure:"description"` diff --git a/pkg/authverify/token.go b/pkg/authverify/token.go index 97bb033916..cfba2d8443 100644 --- a/pkg/authverify/token.go +++ b/pkg/authverify/token.go @@ -44,7 +44,7 @@ func CheckAccessV3(ctx context.Context, ownerUserID string) (err error) { if opUserID == ownerUserID { return nil } - return errs.ErrNoPermission.Wrap(utils.GetSelfFuncName()) + return errs.Wrap(errs.ErrNoPermission, "CheckAccessV3: no permission for user "+opUserID) } func IsAppManagerUid(ctx context.Context) bool { @@ -61,6 +61,7 @@ func CheckAdmin(ctx context.Context) error { } return errs.ErrNoPermission.Wrap(fmt.Sprintf("user %s is not admin userID", mcontext.GetOpUserID(ctx))) } + func CheckIMAdmin(ctx context.Context) error { if utils.IsContain(mcontext.GetOpUserID(ctx), config.Config.IMAdmin.UserID) { return nil diff --git a/pkg/common/cmd/api.go b/pkg/common/cmd/api.go index db1f488ad8..7156ce6c45 100644 --- a/pkg/common/cmd/api.go +++ b/pkg/common/cmd/api.go @@ -15,6 +15,9 @@ package cmd import ( + "errors" + "fmt" + "github.com/OpenIMSDK/protocol/constant" "github.com/spf13/cobra" @@ -32,17 +35,35 @@ func NewApiCmd() *ApiCmd { return ret } +// AddApi configures the API command to run with specified ports for the API and Prometheus monitoring. +// It ensures error handling for port retrieval and only proceeds if both port numbers are successfully obtained. func (a *ApiCmd) AddApi(f func(port int, promPort int) error) { a.Command.RunE = func(cmd *cobra.Command, args []string) error { - return f(a.getPortFlag(cmd), a.getPrometheusPortFlag(cmd)) + port, err := a.getPortFlag(cmd) + if err != nil { + return err + } + + promPort, err := a.getPrometheusPortFlag(cmd) + if err != nil { + return err + } + + return f(port, promPort) } } -func (a *ApiCmd) GetPortFromConfig(portType string) int { +func (a *ApiCmd) GetPortFromConfig(portType string) (int, error) { if portType == constant.FlagPort { - return config2.Config.Api.OpenImApiPort[0] + if len(config2.Config.Api.OpenImApiPort) > 0 { + return config2.Config.Api.OpenImApiPort[0], nil + } + return 0, errors.New("API port configuration is empty or missing") } else if portType == constant.FlagPrometheusPort { - return config2.Config.Prometheus.ApiPrometheusPort[0] + if len(config2.Config.Prometheus.ApiPrometheusPort) > 0 { + return config2.Config.Prometheus.ApiPrometheusPort[0], nil + } + return 0, errors.New("Prometheus port configuration is empty or missing") } - return 0 + return 0, fmt.Errorf("unknown port type: %s", portType) } diff --git a/pkg/common/cmd/cron_task.go b/pkg/common/cmd/cron_task.go index 1b0e796aca..fa7a46351d 100644 --- a/pkg/common/cmd/cron_task.go +++ b/pkg/common/cmd/cron_task.go @@ -36,3 +36,7 @@ func (c *CronTaskCmd) Exec(f func() error) error { c.addRunE(f) return c.Execute() } + +func (c *CronTaskCmd) GetPortFromConfig(portType string) (int, error) { + return 0, nil +} diff --git a/pkg/common/cmd/msg_gateway.go b/pkg/common/cmd/msg_gateway.go index 25fcc11774..317844770c 100644 --- a/pkg/common/cmd/msg_gateway.go +++ b/pkg/common/cmd/msg_gateway.go @@ -15,13 +15,15 @@ package cmd import ( - "log" + "errors" "github.com/spf13/cobra" + "github.com/openimsdk/open-im-server/v3/internal/msggateway" + "github.com/OpenIMSDK/protocol/constant" + "github.com/OpenIMSDK/tools/errs" - "github.com/openimsdk/open-im-server/v3/internal/msggateway" v3config "github.com/openimsdk/open-im-server/v3/pkg/common/config" ) @@ -39,20 +41,32 @@ func (m *MsgGatewayCmd) AddWsPortFlag() { m.Command.Flags().IntP(constant.FlagWsPort, "w", 0, "ws server listen port") } -func (m *MsgGatewayCmd) getWsPortFlag(cmd *cobra.Command) int { +func (m *MsgGatewayCmd) getWsPortFlag(cmd *cobra.Command) (int, error) { port, err := cmd.Flags().GetInt(constant.FlagWsPort) if err != nil { - log.Println("Error getting ws port flag:", err) + return 0, errs.Wrap(err, "error getting ws port flag") } if port == 0 { - port = m.PortFromConfig(constant.FlagWsPort) + port, _ = m.PortFromConfig(constant.FlagWsPort) } - return port + return port, nil } func (m *MsgGatewayCmd) addRunE() { m.Command.RunE = func(cmd *cobra.Command, args []string) error { - return msggateway.RunWsAndServer(m.getPortFlag(cmd), m.getWsPortFlag(cmd), m.getPrometheusPortFlag(cmd)) + wsPort, err := m.getWsPortFlag(cmd) + if err != nil { + return errs.Wrap(err, "failed to get WS port flag") + } + port, err := m.getPortFlag(cmd) + if err != nil { + return err + } + prometheusPort, err := m.getPrometheusPortFlag(cmd) + if err != nil { + return err + } + return msggateway.RunWsAndServer(port, wsPort, prometheusPort) } } @@ -61,18 +75,33 @@ func (m *MsgGatewayCmd) Exec() error { return m.Execute() } -func (m *MsgGatewayCmd) GetPortFromConfig(portType string) int { +func (m *MsgGatewayCmd) GetPortFromConfig(portType string) (int, error) { + var port int + var exists bool + switch portType { case constant.FlagWsPort: - return v3config.Config.LongConnSvr.OpenImWsPort[0] + if len(v3config.Config.LongConnSvr.OpenImWsPort) > 0 { + port = v3config.Config.LongConnSvr.OpenImWsPort[0] + exists = true + } case constant.FlagPort: - return v3config.Config.LongConnSvr.OpenImMessageGatewayPort[0] + if len(v3config.Config.LongConnSvr.OpenImMessageGatewayPort) > 0 { + port = v3config.Config.LongConnSvr.OpenImMessageGatewayPort[0] + exists = true + } case constant.FlagPrometheusPort: - return v3config.Config.Prometheus.MessageGatewayPrometheusPort[0] + if len(v3config.Config.Prometheus.MessageGatewayPrometheusPort) > 0 { + port = v3config.Config.Prometheus.MessageGatewayPrometheusPort[0] + exists = true + } + } - default: - return 0 + if !exists { + return 0, errs.Wrap(errors.New("port type '%s' not found in configuration"), portType) } + + return port, nil } diff --git a/pkg/common/cmd/msg_gateway_test.go b/pkg/common/cmd/msg_gateway_test.go index c0ea2b057c..106ad74ecd 100644 --- a/pkg/common/cmd/msg_gateway_test.go +++ b/pkg/common/cmd/msg_gateway_test.go @@ -44,7 +44,7 @@ func TestMsgGatewayCmd_GetPortFromConfig(t *testing.T) { } for _, tt := range tests { t.Run(tt.portType, func(t *testing.T) { - got := msgGatewayCmd.GetPortFromConfig(tt.portType) + got, _ := msgGatewayCmd.GetPortFromConfig(tt.portType) assert.Equal(t, tt.want, got) }) } diff --git a/pkg/common/cmd/msg_transfer.go b/pkg/common/cmd/msg_transfer.go index e57bab89d5..545c7543b6 100644 --- a/pkg/common/cmd/msg_transfer.go +++ b/pkg/common/cmd/msg_transfer.go @@ -37,7 +37,11 @@ func NewMsgTransferCmd() *MsgTransferCmd { func (m *MsgTransferCmd) addRunE() { m.Command.RunE = func(cmd *cobra.Command, args []string) error { - return msgtransfer.StartTransfer(m.getPrometheusPortFlag(cmd)) + prometheusPort, err := m.getPrometheusPortFlag(cmd) + if err != nil { + return err + } + return msgtransfer.StartTransfer(prometheusPort) } } @@ -46,14 +50,18 @@ func (m *MsgTransferCmd) Exec() error { return m.Execute() } -func (m *MsgTransferCmd) GetPortFromConfig(portType string) int { +func (m *MsgTransferCmd) GetPortFromConfig(portType string) (int, error) { if portType == constant.FlagPort { - return 0 + return 0, nil } else if portType == constant.FlagPrometheusPort { n := m.getTransferProgressFlagValue() - return config2.Config.Prometheus.MessageTransferPrometheusPort[n] + + if n < len(config2.Config.Prometheus.MessageTransferPrometheusPort) { + return config2.Config.Prometheus.MessageTransferPrometheusPort[n], nil + } + return 0, fmt.Errorf("index out of range for MessageTransferPrometheusPort with index %d", n) } - return 0 + return 0, fmt.Errorf("unknown port type: %s", portType) } func (m *MsgTransferCmd) AddTransferProgressFlag() { diff --git a/pkg/common/cmd/msg_utils.go b/pkg/common/cmd/msg_utils.go index dd6d645d71..3c670ad85a 100644 --- a/pkg/common/cmd/msg_utils.go +++ b/pkg/common/cmd/msg_utils.go @@ -18,6 +18,7 @@ import ( "github.com/spf13/cobra" "github.com/openimsdk/open-im-server/v3/internal/tools" + util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" ) type MsgUtilsCmd struct { @@ -137,7 +138,7 @@ func (s *SeqCmd) GetSeqCmd() *cobra.Command { s.Command.Run = func(cmdLines *cobra.Command, args []string) { _, err := tools.InitMsgTool() if err != nil { - panic(err) + util.ExitWithError(err) } userID := s.getUserIDFlag(cmdLines) superGroupID := s.getSuperGroupIDFlag(cmdLines) diff --git a/pkg/common/cmd/root.go b/pkg/common/cmd/root.go index eab4a32bc9..7256bd0edc 100644 --- a/pkg/common/cmd/root.go +++ b/pkg/common/cmd/root.go @@ -19,6 +19,8 @@ import ( config2 "github.com/openimsdk/open-im-server/v3/pkg/common/config" + "github.com/OpenIMSDK/tools/errs" + "github.com/spf13/cobra" "github.com/OpenIMSDK/protocol/constant" @@ -28,8 +30,9 @@ import ( ) type RootCmdPt interface { - GetPortFromConfig(portType string) int + GetPortFromConfig(portType string) (int, error) } + type RootCmd struct { Command cobra.Command Name string @@ -77,7 +80,7 @@ func (rc *RootCmd) persistentPreRun(cmd *cobra.Command, opts ...func(*CmdOpts)) cmdOpts := rc.applyOptions(opts...) if err := rc.initializeLogger(cmdOpts); err != nil { - return fmt.Errorf("failed to initialize from config: %w", err) + return errs.Wrap(err, "failed to initialize logger") } return nil @@ -130,31 +133,41 @@ func (r *RootCmd) AddPortFlag() { r.Command.Flags().IntP(constant.FlagPort, "p", 0, "server listen port") } -func (r *RootCmd) getPortFlag(cmd *cobra.Command) int { +func (r *RootCmd) getPortFlag(cmd *cobra.Command) (int, error) { port, err := cmd.Flags().GetInt(constant.FlagPort) if err != nil { - fmt.Println("Error getting ws port flag:", err) + // Wrapping the error with additional context + return 0, errs.Wrap(err, "error getting port flag") } if port == 0 { - port = r.PortFromConfig(constant.FlagPort) + port, _ = r.PortFromConfig(constant.FlagPort) + // port, err := r.PortFromConfig(constant.FlagPort) + // if err != nil { + // // Optionally wrap the error if it's an internal error needing context + // return 0, errs.Wrap(err, "error getting port from config") + // } } - return port + return port, nil } -func (r *RootCmd) GetPortFlag() int { - return r.port +// // GetPortFlag returns the port flag. +func (r *RootCmd) GetPortFlag() (int, error) { + return r.port, nil } func (r *RootCmd) AddPrometheusPortFlag() { r.Command.Flags().IntP(constant.FlagPrometheusPort, "", 0, "server prometheus listen port") } -func (r *RootCmd) getPrometheusPortFlag(cmd *cobra.Command) int { - port, _ := cmd.Flags().GetInt(constant.FlagPrometheusPort) - if port == 0 { - port = r.PortFromConfig(constant.FlagPrometheusPort) +func (r *RootCmd) getPrometheusPortFlag(cmd *cobra.Command) (int, error) { + port, err := cmd.Flags().GetInt(constant.FlagPrometheusPort) + if err != nil || port == 0 { + port, err = r.PortFromConfig(constant.FlagPrometheusPort) + if err != nil { + return 0, err + } } - return port + return port, nil } func (r *RootCmd) GetPrometheusPortFlag() int { @@ -175,10 +188,11 @@ func (r *RootCmd) AddCommand(cmds ...*cobra.Command) { r.Command.AddCommand(cmds...) } -func (r *RootCmd) GetPortFromConfig(portType string) int { - return 0 -} - -func (r *RootCmd) PortFromConfig(portType string) int { - return r.cmdItf.GetPortFromConfig(portType) +func (r *RootCmd) PortFromConfig(portType string) (int, error) { + // Retrieve the port and cache it + port, err := r.cmdItf.GetPortFromConfig(portType) + if err != nil { + return 0, err + } + return port, nil } diff --git a/pkg/common/cmd/rpc.go b/pkg/common/cmd/rpc.go index ea2a00b078..39bf9c0366 100644 --- a/pkg/common/cmd/rpc.go +++ b/pkg/common/cmd/rpc.go @@ -16,11 +16,14 @@ package cmd import ( "errors" + "fmt" "github.com/OpenIMSDK/protocol/constant" "github.com/spf13/cobra" "google.golang.org/grpc" + "github.com/OpenIMSDK/tools/errs" + config2 "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/OpenIMSDK/tools/discoveryregistry" @@ -39,78 +42,78 @@ func NewRpcCmd(name string) *RpcCmd { } func (a *RpcCmd) Exec() error { - a.Command.Run = func(cmd *cobra.Command, args []string) { - a.port = a.getPortFlag(cmd) - a.prometheusPort = a.getPrometheusPortFlag(cmd) + a.Command.RunE = func(cmd *cobra.Command, args []string) error { + portFlag, err := a.getPortFlag(cmd) + if err != nil { + return err + } + a.port = portFlag + + prometheusPort, err := a.getPrometheusPortFlag(cmd) + if err != nil { + return err + } + a.prometheusPort = prometheusPort + + return nil } return a.Execute() } func (a *RpcCmd) StartSvr(name string, rpcFn func(discov discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) error) error { - if a.GetPortFlag() == 0 { - return errors.New("port is required") + portFlag, err := a.GetPortFlag() + if err != nil { + return err + } else { + a.port = portFlag } - return startrpc.Start(a.GetPortFlag(), name, a.GetPrometheusPortFlag(), rpcFn) + + return startrpc.Start(portFlag, name, a.GetPrometheusPortFlag(), rpcFn) } -func (a *RpcCmd) GetPortFromConfig(portType string) int { - switch a.Name { - case RpcPushServer: - if portType == constant.FlagPort { - return config2.Config.RpcPort.OpenImPushPort[0] - } - if portType == constant.FlagPrometheusPort { - return config2.Config.Prometheus.PushPrometheusPort[0] - } - case RpcAuthServer: - if portType == constant.FlagPort { - return config2.Config.RpcPort.OpenImAuthPort[0] - } - if portType == constant.FlagPrometheusPort { - return config2.Config.Prometheus.AuthPrometheusPort[0] - } - case RpcConversationServer: - if portType == constant.FlagPort { - return config2.Config.RpcPort.OpenImConversationPort[0] - } - if portType == constant.FlagPrometheusPort { - return config2.Config.Prometheus.ConversationPrometheusPort[0] - } - case RpcFriendServer: - if portType == constant.FlagPort { - return config2.Config.RpcPort.OpenImFriendPort[0] - } - if portType == constant.FlagPrometheusPort { - return config2.Config.Prometheus.FriendPrometheusPort[0] - } - case RpcGroupServer: - if portType == constant.FlagPort { - return config2.Config.RpcPort.OpenImGroupPort[0] - } - if portType == constant.FlagPrometheusPort { - return config2.Config.Prometheus.GroupPrometheusPort[0] - } - case RpcMsgServer: - if portType == constant.FlagPort { - return config2.Config.RpcPort.OpenImMessagePort[0] - } - if portType == constant.FlagPrometheusPort { - return config2.Config.Prometheus.MessagePrometheusPort[0] - } - case RpcThirdServer: - if portType == constant.FlagPort { - return config2.Config.RpcPort.OpenImThirdPort[0] - } - if portType == constant.FlagPrometheusPort { - return config2.Config.Prometheus.ThirdPrometheusPort[0] - } - case RpcUserServer: - if portType == constant.FlagPort { - return config2.Config.RpcPort.OpenImUserPort[0] - } - if portType == constant.FlagPrometheusPort { - return config2.Config.Prometheus.UserPrometheusPort[0] +func (a *RpcCmd) GetPortFromConfig(portType string) (int, error) { + portConfigMap := map[string]map[string]int{ + RpcPushServer: { + constant.FlagPort: config2.Config.RpcPort.OpenImPushPort[0], + constant.FlagPrometheusPort: config2.Config.Prometheus.PushPrometheusPort[0], + }, + RpcAuthServer: { + constant.FlagPort: config2.Config.RpcPort.OpenImAuthPort[0], + constant.FlagPrometheusPort: config2.Config.Prometheus.AuthPrometheusPort[0], + }, + RpcConversationServer: { + constant.FlagPort: config2.Config.RpcPort.OpenImConversationPort[0], + constant.FlagPrometheusPort: config2.Config.Prometheus.ConversationPrometheusPort[0], + }, + RpcFriendServer: { + constant.FlagPort: config2.Config.RpcPort.OpenImFriendPort[0], + constant.FlagPrometheusPort: config2.Config.Prometheus.FriendPrometheusPort[0], + }, + RpcGroupServer: { + constant.FlagPort: config2.Config.RpcPort.OpenImGroupPort[0], + constant.FlagPrometheusPort: config2.Config.Prometheus.GroupPrometheusPort[0], + }, + RpcMsgServer: { + constant.FlagPort: config2.Config.RpcPort.OpenImMessagePort[0], + constant.FlagPrometheusPort: config2.Config.Prometheus.MessagePrometheusPort[0], + }, + RpcThirdServer: { + constant.FlagPort: config2.Config.RpcPort.OpenImThirdPort[0], + constant.FlagPrometheusPort: config2.Config.Prometheus.ThirdPrometheusPort[0], + }, + RpcUserServer: { + constant.FlagPort: config2.Config.RpcPort.OpenImUserPort[0], + constant.FlagPrometheusPort: config2.Config.Prometheus.UserPrometheusPort[0], + }, + } + + if portMap, ok := portConfigMap[a.Name]; ok { + if port, ok := portMap[portType]; ok { + return port, nil + } else { + return 0, errs.Wrap(errors.New("port type not found"), fmt.Sprintf("Failed to get port for %s", a.Name)) } } - return 0 + + return 0, errs.Wrap(fmt.Errorf("server name '%s' not found", a.Name), "Failed to get port configuration") } diff --git a/pkg/common/config/parse.go b/pkg/common/config/parse.go index 4037429e34..e216f6014f 100644 --- a/pkg/common/config/parse.go +++ b/pkg/common/config/parse.go @@ -21,6 +21,7 @@ import ( "path/filepath" "github.com/OpenIMSDK/protocol/constant" + "github.com/OpenIMSDK/tools/errs" "gopkg.in/yaml.v3" "github.com/openimsdk/open-im-server/v3/pkg/msgprocessor" @@ -36,32 +37,38 @@ const ( DefaultFolderPath = "../config/" ) -// return absolude path join ../config/, this is k8s container config path. -func GetDefaultConfigPath() string { +// GetDefaultConfigPath returns the absolute path to the default configuration directory +// relative to the executable's location. It is intended for use in Kubernetes container configurations. +// Errors are returned to the caller to allow for flexible error handling. +func GetDefaultConfigPath() (string, error) { executablePath, err := os.Executable() if err != nil { - fmt.Println("GetDefaultConfigPath error:", err.Error()) - return "" + return "", errs.Wrap(err, "failed to get executable path") } + // Calculate the config path as a directory relative to the executable's location configPath, err := genutil.OutDir(filepath.Join(filepath.Dir(executablePath), "../config/")) if err != nil { - fmt.Fprintf(os.Stderr, "failed to get output directory: %v\n", err) - os.Exit(1) + return "", errs.Wrap(err, "failed to get output directory") } - return configPath + return configPath, nil } -// getProjectRoot returns the absolute path of the project root directory. -func GetProjectRoot() string { - executablePath, _ := os.Executable() +// GetProjectRoot returns the absolute path of the project root directory by navigating up from the directory +// containing the executable. It provides a detailed error if the path cannot be determined. +func GetProjectRoot() (string, error) { + executablePath, err := os.Executable() + if err != nil { + return "", errs.Wrap(err, "failed to retrieve executable path") + } + // Attempt to compute the project root by navigating up from the executable's directory projectRoot, err := genutil.OutDir(filepath.Join(filepath.Dir(executablePath), "../../../../..")) if err != nil { - fmt.Fprintf(os.Stderr, "failed to get output directory: %v\n", err) - os.Exit(1) + return "", err } - return projectRoot + + return projectRoot, nil } func GetOptionsByNotification(cfg NotificationConf) msgprocessor.Options { @@ -83,42 +90,66 @@ func GetOptionsByNotification(cfg NotificationConf) msgprocessor.Options { return opts } +// initConfig loads configuration from a specified path into the provided config structure. +// If the specified config file does not exist, it attempts to load from the project's default "config" directory. +// It logs informative messages regarding the configuration path being used. func initConfig(config any, configName, configFolderPath string) error { - configFolderPath = filepath.Join(configFolderPath, configName) - _, err := os.Stat(configFolderPath) + configFilePath := filepath.Join(configFolderPath, configName) + _, err := os.Stat(configFilePath) if err != nil { if !os.IsNotExist(err) { - fmt.Println("stat config path error:", err.Error()) - return fmt.Errorf("stat config path error: %w", err) + return errs.Wrap(err, fmt.Sprintf("failed to check existence of config file at path: %s", configFilePath)) + } + var projectRoot string + projectRoot, err = GetProjectRoot() + if err != nil { + return err } - configFolderPath = filepath.Join(GetProjectRoot(), "config", configName) - fmt.Println("flag's path,enviment's path,default path all is not exist,using project path:", configFolderPath) + configFilePath = filepath.Join(projectRoot, "config", configName) + fmt.Printf("Configuration file not found at specified path. Falling back to project path: %s\n", configFilePath) } - data, err := os.ReadFile(configFolderPath) + + data, err := os.ReadFile(configFilePath) if err != nil { - return fmt.Errorf("read file error: %w", err) + // Wrap and return the error if reading the configuration file fails. + return errs.Wrap(err, fmt.Sprintf("failed to read configuration file at path: %s", configFilePath)) } + if err = yaml.Unmarshal(data, config); err != nil { - return fmt.Errorf("unmarshal yaml error: %w", err) + // Wrap and return the error if unmarshalling the YAML configuration fails. + return errs.Wrap(err, "failed to unmarshal YAML configuration") } - fmt.Println("The path of the configuration file to start the process:", configFolderPath) + fmt.Printf("Configuration file loaded successfully from path: %s\n", configFilePath) return nil } +// InitConfig initializes the application configuration by loading it from a specified folder path. +// If the folder path is not provided, it attempts to use the OPENIMCONFIG environment variable, +// and as a fallback, it uses the default configuration path. It loads both the main configuration +// and notification configuration, wrapping errors for better context. func InitConfig(configFolderPath string) error { + // Use the provided config folder path, or fallback to environment variable or default path if configFolderPath == "" { - envConfigPath := os.Getenv("OPENIMCONFIG") - if envConfigPath != "" { - configFolderPath = envConfigPath - } else { - configFolderPath = GetDefaultConfigPath() + configFolderPath = os.Getenv("OPENIMCONFIG") + if configFolderPath == "" { + var err error + configFolderPath, err = GetDefaultConfigPath() + if err != nil { + return err + } } } + // Initialize the main configuration if err := initConfig(&Config, FileName, configFolderPath); err != nil { return err } - return initConfig(&Config.Notification, NotificationFileName, configFolderPath) + // Initialize the notification configuration + if err := initConfig(&Config.Notification, NotificationFileName, configFolderPath); err != nil { + return err + } + + return nil } diff --git a/pkg/common/config/parse_test.go b/pkg/common/config/parse_test.go index 38171ec088..b980de7bd8 100644 --- a/pkg/common/config/parse_test.go +++ b/pkg/common/config/parse_test.go @@ -31,7 +31,7 @@ func TestGetDefaultConfigPath(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - if got := GetDefaultConfigPath(); got != tt.want { + if got, _ := GetDefaultConfigPath(); got != tt.want { t.Errorf("GetDefaultConfigPath() = %v, want %v", got, tt.want) } }) @@ -47,7 +47,7 @@ func TestGetProjectRoot(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - if got := GetProjectRoot(); got != tt.want { + if got, _ := GetProjectRoot(); got != tt.want { t.Errorf("GetProjectRoot() = %v, want %v", got, tt.want) } }) diff --git a/pkg/common/convert/black.go b/pkg/common/convert/black.go index 50c270dcb0..57140f4361 100644 --- a/pkg/common/convert/black.go +++ b/pkg/common/convert/black.go @@ -23,11 +23,7 @@ import ( "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" ) -func BlackDB2Pb( - ctx context.Context, - blackDBs []*relation.BlackModel, - f func(ctx context.Context, userIDs []string) (map[string]*sdkws.UserInfo, error), -) (blackPbs []*sdk.BlackInfo, err error) { +func BlackDB2Pb(ctx context.Context, blackDBs []*relation.BlackModel, f func(ctx context.Context, userIDs []string) (map[string]*sdkws.UserInfo, error)) (blackPbs []*sdk.BlackInfo, err error) { if len(blackDBs) == 0 { return nil, nil } diff --git a/pkg/common/convert/friend.go b/pkg/common/convert/friend.go index f3a19e459c..0e9a057663 100644 --- a/pkg/common/convert/friend.go +++ b/pkg/common/convert/friend.go @@ -53,11 +53,7 @@ func FriendDB2Pb(ctx context.Context, friendDB *relation.FriendModel, }, nil } -func FriendsDB2Pb( - ctx context.Context, - friendsDB []*relation.FriendModel, - getUsers func(ctx context.Context, userIDs []string) (map[string]*sdkws.UserInfo, error), -) (friendsPb []*sdkws.FriendInfo, err error) { +func FriendsDB2Pb(ctx context.Context, friendsDB []*relation.FriendModel, getUsers func(ctx context.Context, userIDs []string) (map[string]*sdkws.UserInfo, error)) (friendsPb []*sdkws.FriendInfo, err error) { if len(friendsDB) == 0 { return nil, nil } @@ -89,8 +85,7 @@ func FriendsDB2Pb( } -func FriendRequestDB2Pb( - ctx context.Context, +func FriendRequestDB2Pb(ctx context.Context, friendRequests []*relation.FriendRequestModel, getUsers func(ctx context.Context, userIDs []string) (map[string]*sdkws.UserInfo, error), ) ([]*sdkws.FriendRequest, error) { diff --git a/pkg/common/db/cache/black.go b/pkg/common/db/cache/black.go index d1abe945ca..48bc3c2853 100644 --- a/pkg/common/db/cache/black.go +++ b/pkg/common/db/cache/black.go @@ -46,11 +46,7 @@ type BlackCacheRedis struct { blackDB relationtb.BlackModelInterface } -func NewBlackCacheRedis( - rdb redis.UniversalClient, - blackDB relationtb.BlackModelInterface, - options rockscache.Options, -) BlackCache { +func NewBlackCacheRedis(rdb redis.UniversalClient, blackDB relationtb.BlackModelInterface, options rockscache.Options) BlackCache { rcClient := rockscache.NewClient(rdb, options) return &BlackCacheRedis{ diff --git a/pkg/common/db/cache/init_redis.go b/pkg/common/db/cache/init_redis.go index 3cec73be54..a41a4f4602 100644 --- a/pkg/common/db/cache/init_redis.go +++ b/pkg/common/db/cache/init_redis.go @@ -49,7 +49,7 @@ func NewRedis() (redis.UniversalClient, error) { overrideConfigFromEnv() if len(config.Config.Redis.Address) == 0 { - return nil, errs.Wrap(errors.New("redis address is empty")) + return nil, errs.Wrap(errors.New("redis address is empty"), "Redis configuration error") } specialerror.AddReplace(redis.Nil, errs.ErrRecordNotFound) var rdb redis.UniversalClient @@ -65,9 +65,9 @@ func NewRedis() (redis.UniversalClient, error) { rdb = redis.NewClient(&redis.Options{ Addr: config.Config.Redis.Address[0], Username: config.Config.Redis.Username, - Password: config.Config.Redis.Password, - DB: 0, // use default DB - PoolSize: 100, // connection pool size + Password: config.Config.Redis.Password, // no password set + DB: 0, // use default DB + PoolSize: 100, // connection pool size MaxRetries: maxRetry, }) } @@ -77,9 +77,9 @@ func NewRedis() (redis.UniversalClient, error) { defer cancel() err = rdb.Ping(ctx).Err() if err != nil { - uriFormat := "address:%s, username:%s, password:%s, clusterMode:%t, enablePipeline:%t" - errMsg := fmt.Sprintf(uriFormat, config.Config.Redis.Address, config.Config.Redis.Username, config.Config.Redis.Password, config.Config.Redis.ClusterMode, config.Config.Redis.EnablePipeline) - return nil, errs.Wrap(err, errMsg) + uriFormat := "address:%v, username:%s, clusterMode:%t, enablePipeline:%t" + errMsg := fmt.Sprintf(uriFormat, config.Config.Redis.Address, config.Config.Redis.Username, config.Config.Redis.ClusterMode, config.Config.Redis.EnablePipeline) + return nil, errs.Wrap(err, "Redis connection failed: %s", errMsg) } redisClient = rdb return rdb, err @@ -98,9 +98,11 @@ func overrideConfigFromEnv() { config.Config.Redis.Address = strings.Split(envAddr, ",") } } + if envUser := os.Getenv("REDIS_USERNAME"); envUser != "" { config.Config.Redis.Username = envUser } + if envPass := os.Getenv("REDIS_PASSWORD"); envPass != "" { config.Config.Redis.Password = envPass } diff --git a/pkg/common/db/cache/meta_cache.go b/pkg/common/db/cache/meta_cache.go index 7eb486c9ab..fee982dc50 100644 --- a/pkg/common/db/cache/meta_cache.go +++ b/pkg/common/db/cache/meta_cache.go @@ -134,7 +134,7 @@ func getCache[T any](ctx context.Context, rcClient *rockscache.Client, key strin } bs, err := json.Marshal(t) if err != nil { - return "", errs.Wrap(err) + return "", errs.Wrap(err, "marshal failed") } write = true @@ -152,8 +152,7 @@ func getCache[T any](ctx context.Context, rcClient *rockscache.Client, key strin err = json.Unmarshal([]byte(v), &t) if err != nil { log.ZError(ctx, "cache json.Unmarshal failed", err, "key", key, "value", v, "expire", expire) - - return t, errs.Wrap(err) + return t, errs.Wrap(err, "unmarshal failed") } return t, nil @@ -197,14 +196,7 @@ func getCache[T any](ctx context.Context, rcClient *rockscache.Client, key strin // return tArrays, nil //} -func batchGetCache2[T any, K comparable]( - ctx context.Context, - rcClient *rockscache.Client, - expire time.Duration, - keys []K, - keyFn func(key K) string, - fns func(ctx context.Context, key K) (T, error), -) ([]T, error) { +func batchGetCache2[T any, K comparable](ctx context.Context, rcClient *rockscache.Client, expire time.Duration, keys []K, keyFn func(key K) string, fns func(ctx context.Context, key K) (T, error)) ([]T, error) { if len(keys) == 0 { return nil, nil } diff --git a/pkg/common/db/cache/msg.go b/pkg/common/db/cache/msg.go index 8a54e1a8b2..5cef509ed6 100644 --- a/pkg/common/db/cache/msg.go +++ b/pkg/common/db/cache/msg.go @@ -24,12 +24,11 @@ import ( "github.com/openimsdk/open-im-server/v3/pkg/msgprocessor" - "github.com/OpenIMSDK/tools/errs" - "github.com/gogo/protobuf/jsonpb" "github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/protocol/sdkws" + "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/utils" @@ -433,7 +432,7 @@ func (c *msgCache) PipeSetMessageToCache(ctx context.Context, conversationID str for _, msg := range msgs { s, err := msgprocessor.Pb2String(msg) if err != nil { - return 0, errs.Wrap(err, "pb.marshal") + return 0, err } key := c.getMessageCacheKey(conversationID, msg.Seq) @@ -442,7 +441,7 @@ func (c *msgCache) PipeSetMessageToCache(ctx context.Context, conversationID str results, err := pipe.Exec(ctx) if err != nil { - return 0, errs.Wrap(err, "pipe.set") + return 0, errs.Wrap(err) } for _, res := range results { diff --git a/pkg/common/db/cache/user.go b/pkg/common/db/cache/user.go index 979bd06e4c..f444a2c465 100644 --- a/pkg/common/db/cache/user.go +++ b/pkg/common/db/cache/user.go @@ -66,11 +66,7 @@ type UserCacheRedis struct { rcClient *rockscache.Client } -func NewUserCacheRedis( - rdb redis.UniversalClient, - userDB relationtb.UserModelInterface, - options rockscache.Options, -) UserCache { +func NewUserCacheRedis(rdb redis.UniversalClient, userDB relationtb.UserModelInterface, options rockscache.Options) UserCache { rcClient := rockscache.NewClient(rdb, options) return &UserCacheRedis{ @@ -282,8 +278,8 @@ func (u *UserCacheRedis) refreshStatusOnline(ctx context.Context, userID string, var onlineStatus user.OnlineStatus if !isNil { err2 := json.Unmarshal([]byte(result), &onlineStatus) - if err != nil { - return errs.Wrap(err2) + if err2 != nil { + return errs.Wrap(err, "json.Unmarshal failed") } onlineStatus.PlatformIDs = RemoveRepeatedElementsInList(append(onlineStatus.PlatformIDs, platformID)) } else { @@ -293,7 +289,7 @@ func (u *UserCacheRedis) refreshStatusOnline(ctx context.Context, userID string, onlineStatus.UserID = userID newjsonData, err := json.Marshal(&onlineStatus) if err != nil { - return errs.Wrap(err) + return errs.Wrap(err, "json.Marshal failed") } _, err = u.rdb.HSet(ctx, key, userID, string(newjsonData)).Result() if err != nil { diff --git a/pkg/common/db/controller/auth.go b/pkg/common/db/controller/auth.go index 18c64ad8f4..13bc066cad 100644 --- a/pkg/common/db/controller/auth.go +++ b/pkg/common/db/controller/auth.go @@ -30,9 +30,9 @@ import ( ) type AuthDatabase interface { - // 结果为空 不返回错误 + // If the result is empty, no error is returned. GetTokensWithoutError(ctx context.Context, userID string, platformID int) (map[string]int, error) - // 创建token + // Create token CreateToken(ctx context.Context, userID string, platformID int) (string, error) } @@ -47,16 +47,12 @@ func NewAuthDatabase(cache cache.MsgModel, accessSecret string, accessExpire int return &authDatabase{cache: cache, accessSecret: accessSecret, accessExpire: accessExpire} } -// 结果为空 不返回错误. -func (a *authDatabase) GetTokensWithoutError( - ctx context.Context, - userID string, - platformID int, -) (map[string]int, error) { +// If the result is empty. +func (a *authDatabase) GetTokensWithoutError(ctx context.Context, userID string, platformID int) (map[string]int, error) { return a.cache.GetTokensWithoutError(ctx, userID, platformID) } -// 创建token. +// Create Token. func (a *authDatabase) CreateToken(ctx context.Context, userID string, platformID int) (string, error) { tokens, err := a.cache.GetTokensWithoutError(ctx, userID, platformID) if err != nil { @@ -80,7 +76,7 @@ func (a *authDatabase) CreateToken(ctx context.Context, userID string, platformI token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) tokenString, err := token.SignedString([]byte(a.accessSecret)) if err != nil { - return "", errs.Wrap(err) + return "", errs.Wrap(err, "token.SignedString") } return tokenString, a.cache.AddTokenFlag(ctx, userID, platformID, tokenString, constant.NormalToken) } diff --git a/pkg/common/db/controller/black.go b/pkg/common/db/controller/black.go index e68d06b01e..3c8a47a017 100644 --- a/pkg/common/db/controller/black.go +++ b/pkg/common/db/controller/black.go @@ -27,14 +27,14 @@ import ( ) type BlackDatabase interface { - // Create 增加黑名单 + // Create add BlackList Create(ctx context.Context, blacks []*relation.BlackModel) (err error) - // Delete 删除黑名单 + // Delete delete BlackList Delete(ctx context.Context, blacks []*relation.BlackModel) (err error) - // FindOwnerBlacks 获取黑名单列表 + // FindOwnerBlacks get BlackList list FindOwnerBlacks(ctx context.Context, ownerUserID string, pagination pagination.Pagination) (total int64, blacks []*relation.BlackModel, err error) FindBlackInfos(ctx context.Context, ownerUserID string, userIDs []string) (blacks []*relation.BlackModel, err error) - // CheckIn 检查user2是否在user1的黑名单列表中(inUser1Blacks==true) 检查user1是否在user2的黑名单列表中(inUser2Blacks==true) + // CheckIn Check whether user2 is in the black list of user1 (inUser1Blacks==true) Check whether user1 is in the black list of user2 (inUser2Blacks==true) CheckIn(ctx context.Context, userID1, userID2 string) (inUser1Blacks bool, inUser2Blacks bool, err error) } @@ -47,7 +47,7 @@ func NewBlackDatabase(black relation.BlackModelInterface, cache cache.BlackCache return &blackDatabase{black, cache} } -// Create 增加黑名单. +// Create Add Blacklist. func (b *blackDatabase) Create(ctx context.Context, blacks []*relation.BlackModel) (err error) { if err := b.black.Create(ctx, blacks); err != nil { return err @@ -55,7 +55,7 @@ func (b *blackDatabase) Create(ctx context.Context, blacks []*relation.BlackMode return b.deleteBlackIDsCache(ctx, blacks) } -// Delete 删除黑名单. +// Delete Delete Blacklist. func (b *blackDatabase) Delete(ctx context.Context, blacks []*relation.BlackModel) (err error) { if err := b.black.Delete(ctx, blacks); err != nil { return err @@ -63,6 +63,7 @@ func (b *blackDatabase) Delete(ctx context.Context, blacks []*relation.BlackMode return b.deleteBlackIDsCache(ctx, blacks) } +// FindOwnerBlacks Get Blacklist List. func (b *blackDatabase) deleteBlackIDsCache(ctx context.Context, blacks []*relation.BlackModel) (err error) { cache := b.cache.NewCache() for _, black := range blacks { @@ -71,16 +72,13 @@ func (b *blackDatabase) deleteBlackIDsCache(ctx context.Context, blacks []*relat return cache.ExecDel(ctx) } -// FindOwnerBlacks 获取黑名单列表. +// FindOwnerBlacks Get Blacklist List. func (b *blackDatabase) FindOwnerBlacks(ctx context.Context, ownerUserID string, pagination pagination.Pagination) (total int64, blacks []*relation.BlackModel, err error) { return b.black.FindOwnerBlacks(ctx, ownerUserID, pagination) } -// CheckIn 检查user2是否在user1的黑名单列表中(inUser1Blacks==true) 检查user1是否在user2的黑名单列表中(inUser2Blacks==true). -func (b *blackDatabase) CheckIn( - ctx context.Context, - userID1, userID2 string, -) (inUser1Blacks bool, inUser2Blacks bool, err error) { +// FindOwnerBlacks Get Blacklist List. +func (b *blackDatabase) CheckIn(ctx context.Context, userID1, userID2 string) (inUser1Blacks bool, inUser2Blacks bool, err error) { userID1BlackIDs, err := b.cache.GetBlackIDs(ctx, userID1) if err != nil { return @@ -93,10 +91,12 @@ func (b *blackDatabase) CheckIn( return utils.IsContain(userID2, userID1BlackIDs), utils.IsContain(userID1, userID2BlackIDs), nil } +// FindBlackIDs Get Blacklist List. func (b *blackDatabase) FindBlackIDs(ctx context.Context, ownerUserID string) (blackIDs []string, err error) { return b.cache.GetBlackIDs(ctx, ownerUserID) } +// FindBlackInfos Get Blacklist List. func (b *blackDatabase) FindBlackInfos(ctx context.Context, ownerUserID string, userIDs []string) (blacks []*relation.BlackModel, err error) { return b.black.FindOwnerBlackInfos(ctx, ownerUserID, userIDs) } diff --git a/pkg/common/db/controller/conversation.go b/pkg/common/db/controller/conversation.go index c53d4ab874..0c64169a70 100644 --- a/pkg/common/db/controller/conversation.go +++ b/pkg/common/db/controller/conversation.go @@ -32,32 +32,40 @@ import ( ) type ConversationDatabase interface { - // UpdateUserConversationFiled 更新用户该会话的属性信息 - UpdateUsersConversationFiled(ctx context.Context, userIDs []string, conversationID string, args map[string]any) error - // CreateConversation 创建一批新的会话 + // UpdateUsersConversationField updates the properties of a conversation for specified users. + UpdateUsersConversationField(ctx context.Context, userIDs []string, conversationID string, args map[string]any) error + // CreateConversation creates a batch of new conversations. CreateConversation(ctx context.Context, conversations []*relationtb.ConversationModel) error - // SyncPeerUserPrivateConversation 同步对端私聊会话内部保证事务操作 + // SyncPeerUserPrivateConversationTx ensures transactional operation while syncing private conversations between peers. SyncPeerUserPrivateConversationTx(ctx context.Context, conversation []*relationtb.ConversationModel) error - // FindConversations 根据会话ID获取某个用户的多个会话 + // FindConversations retrieves multiple conversations of a user by conversation IDs. FindConversations(ctx context.Context, ownerUserID string, conversationIDs []string) ([]*relationtb.ConversationModel, error) - // FindRecvMsgNotNotifyUserIDs 获取超级大群开启免打扰的用户ID - //FindRecvMsgNotNotifyUserIDs(ctx context.Context, groupID string) ([]string, error) - // GetUserAllConversation 获取一个用户在服务器上所有的会话 + // GetUserAllConversation fetches all conversations of a user on the server. GetUserAllConversation(ctx context.Context, ownerUserID string) ([]*relationtb.ConversationModel, error) - // SetUserConversations 设置用户多个会话属性,如果会话不存在则创建,否则更新,内部保证原子性 + // SetUserConversations sets multiple conversation properties for a user, creates new conversations if they do not exist, or updates them otherwise. This operation is atomic. SetUserConversations(ctx context.Context, ownerUserID string, conversations []*relationtb.ConversationModel) error - // SetUsersConversationFiledTx 设置多个用户会话关于某个字段的更新操作,如果会话不存在则创建,否则更新,内部保证事务操作 - SetUsersConversationFiledTx(ctx context.Context, userIDs []string, conversation *relationtb.ConversationModel, filedMap map[string]any) error + // SetUsersConversationFieldTx updates a specific field for multiple users' conversations, creating new conversations if they do not exist, or updates them otherwise. This operation is transactional. + SetUsersConversationFieldTx(ctx context.Context, userIDs []string, conversation *relationtb.ConversationModel, fieldMap map[string]any) error + // CreateGroupChatConversation creates a group chat conversation for the specified group ID and user IDs. CreateGroupChatConversation(ctx context.Context, groupID string, userIDs []string) error + // GetConversationIDs retrieves conversation IDs for a given user. GetConversationIDs(ctx context.Context, userID string) ([]string, error) + // GetUserConversationIDsHash gets the hash of conversation IDs for a given user. GetUserConversationIDsHash(ctx context.Context, ownerUserID string) (hash uint64, err error) + // GetAllConversationIDs fetches all conversation IDs. GetAllConversationIDs(ctx context.Context) ([]string, error) + // GetAllConversationIDsNumber returns the number of all conversation IDs. GetAllConversationIDsNumber(ctx context.Context) (int64, error) + // PageConversationIDs paginates through conversation IDs based on the specified pagination settings. PageConversationIDs(ctx context.Context, pagination pagination.Pagination) (conversationIDs []string, err error) - //GetUserAllHasReadSeqs(ctx context.Context, ownerUserID string) (map[string]int64, error) + // GetConversationsByConversationID retrieves conversations by their IDs. GetConversationsByConversationID(ctx context.Context, conversationIDs []string) ([]*relationtb.ConversationModel, error) + // GetConversationIDsNeedDestruct fetches conversations that need to be destructed based on specific criteria. GetConversationIDsNeedDestruct(ctx context.Context) ([]*relationtb.ConversationModel, error) + // GetConversationNotReceiveMessageUserIDs gets user IDs for users in a conversation who have not received messages. GetConversationNotReceiveMessageUserIDs(ctx context.Context, conversationID string) ([]string, error) + //GetUserAllHasReadSeqs(ctx context.Context, ownerUserID string) (map[string]int64, error) + //FindRecvMsgNotNotifyUserIDs(ctx context.Context, groupID string) ([]string, error) } func NewConversationDatabase(conversation relationtb.ConversationModelInterface, cache cache.ConversationCache, tx tx.CtxTx) ConversationDatabase { @@ -74,7 +82,7 @@ type conversationDatabase struct { tx tx.CtxTx } -func (c *conversationDatabase) SetUsersConversationFiledTx(ctx context.Context, userIDs []string, conversation *relationtb.ConversationModel, filedMap map[string]any) (err error) { +func (c *conversationDatabase) SetUsersConversationFieldTx(ctx context.Context, userIDs []string, conversation *relationtb.ConversationModel, fieldMap map[string]any) (err error) { return c.tx.Transaction(ctx, func(ctx context.Context) error { cache := c.cache.NewCache() if conversation.GroupID != "" { @@ -85,22 +93,22 @@ func (c *conversationDatabase) SetUsersConversationFiledTx(ctx context.Context, return err } if len(haveUserIDs) > 0 { - _, err = c.conversationDB.UpdateByMap(ctx, haveUserIDs, conversation.ConversationID, filedMap) + _, err = c.conversationDB.UpdateByMap(ctx, haveUserIDs, conversation.ConversationID, fieldMap) if err != nil { return err } cache = cache.DelUsersConversation(conversation.ConversationID, haveUserIDs...) - if _, ok := filedMap["has_read_seq"]; ok { + if _, ok := fieldMap["has_read_seq"]; ok { for _, userID := range haveUserIDs { cache = cache.DelUserAllHasReadSeqs(userID, conversation.ConversationID) } } - if _, ok := filedMap["recv_msg_opt"]; ok { + if _, ok := fieldMap["recv_msg_opt"]; ok { cache = cache.DelConversationNotReceiveMessageUserIDs(conversation.ConversationID) } } NotUserIDs := utils.DifferenceString(haveUserIDs, userIDs) - log.ZDebug(ctx, "SetUsersConversationFiledTx", "NotUserIDs", NotUserIDs, "haveUserIDs", haveUserIDs, "userIDs", userIDs) + log.ZDebug(ctx, "SetUsersConversationFieldTx", "NotUserIDs", NotUserIDs, "haveUserIDs", haveUserIDs, "userIDs", userIDs) var conversations []*relationtb.ConversationModel now := time.Now() for _, v := range NotUserIDs { @@ -123,7 +131,7 @@ func (c *conversationDatabase) SetUsersConversationFiledTx(ctx context.Context, }) } -func (c *conversationDatabase) UpdateUsersConversationFiled(ctx context.Context, userIDs []string, conversationID string, args map[string]any) error { +func (c *conversationDatabase) UpdateUsersConversationField(ctx context.Context, userIDs []string, conversationID string, args map[string]any) error { _, err := c.conversationDB.UpdateByMap(ctx, userIDs, conversationID, args) if err != nil { return err diff --git a/pkg/common/db/controller/friend.go b/pkg/common/db/controller/friend.go index 3b98f5d7b9..bb5ec3087c 100644 --- a/pkg/common/db/controller/friend.go +++ b/pkg/common/db/controller/friend.go @@ -16,6 +16,7 @@ package controller import ( "context" + "fmt" "time" "github.com/OpenIMSDK/tools/pagination" @@ -89,20 +90,30 @@ func NewFriendDatabase(friend relation.FriendModelInterface, friendRequest relat return &friendDatabase{friend: friend, friendRequest: friendRequest, cache: cache, tx: tx} } -// ok 检查user2是否在user1的好友列表中(inUser1Friends==true) 检查user1是否在user2的好友列表中(inUser2Friends==true). +// CheckIn verifies if user2 is in user1's friend list (inUser1Friends returns true) and +// if user1 is in user2's friend list (inUser2Friends returns true). func (f *friendDatabase) CheckIn(ctx context.Context, userID1, userID2 string) (inUser1Friends bool, inUser2Friends bool, err error) { + // Retrieve friend IDs of userID1 from the cache userID1FriendIDs, err := f.cache.GetFriendIDs(ctx, userID1) if err != nil { + err = fmt.Errorf("error retrieving friend IDs for user %s: %w", userID1, err) return } + + // Retrieve friend IDs of userID2 from the cache userID2FriendIDs, err := f.cache.GetFriendIDs(ctx, userID2) if err != nil { + err = fmt.Errorf("error retrieving friend IDs for user %s: %w", userID2, err) return } - return utils.IsContain(userID2, userID1FriendIDs), utils.IsContain(userID1, userID2FriendIDs), nil + + // Check if userID2 is in userID1's friend list and vice versa + inUser1Friends = utils.IsContain(userID2, userID1FriendIDs) + inUser2Friends = utils.IsContain(userID1, userID2FriendIDs) + return inUser1Friends, inUser2Friends, nil } -// 增加或者更新好友申请 如果之前有记录则更新,没有记录则新增. +// AddFriendRequest adds or updates a friend request. func (f *friendDatabase) AddFriendRequest(ctx context.Context, fromUserID, toUserID string, reqMsg string, ex string) (err error) { return f.tx.Transaction(ctx, func(ctx context.Context) error { _, err := f.friendRequest.Take(ctx, fromUserID, toUserID) @@ -126,11 +137,11 @@ func (f *friendDatabase) AddFriendRequest(ctx context.Context, fromUserID, toUse }) } -// (1)先判断是否在好友表 (在不在都不返回错误) (2)对于不在好友列表的 插入即可. +// (1) First determine whether it is in the friends list (in or out does not return an error) (2) for not in the friends list can be inserted. func (f *friendDatabase) BecomeFriends(ctx context.Context, ownerUserID string, friendUserIDs []string, addSource int32) (err error) { return f.tx.Transaction(ctx, func(ctx context.Context) error { cache := f.cache.NewCache() - // 先find 找出重复的 去掉重复的 + // User find friends fs1, err := f.friend.FindFriends(ctx, ownerUserID, friendUserIDs) if err != nil { return err @@ -170,26 +181,37 @@ func (f *friendDatabase) BecomeFriends(ctx context.Context, ownerUserID string, }) } -// 拒绝好友申请 (1)检查是否有申请记录且为未处理状态 (没有记录返回错误) (2)修改申请记录 已拒绝. -func (f *friendDatabase) RefuseFriendRequest(ctx context.Context, friendRequest *relation.FriendRequestModel) (err error) { +// RefuseFriendRequest rejects a friend request. It first checks for an existing, unprocessed request. +// If no such request exists, it returns an error. Otherwise, it marks the request as refused. +func (f *friendDatabase) RefuseFriendRequest(ctx context.Context, friendRequest *relation.FriendRequestModel) error { + // Attempt to retrieve the friend request from the database. fr, err := f.friendRequest.Take(ctx, friendRequest.FromUserID, friendRequest.ToUserID) if err != nil { - return err + return fmt.Errorf("failed to retrieve friend request from %s to %s: %w", friendRequest.FromUserID, friendRequest.ToUserID, err) } + + // Check if the friend request has already been handled. if fr.HandleResult != 0 { - return errs.ErrArgs.Wrap("the friend request has been processed") + return fmt.Errorf("friend request from %s to %s has already been processed", friendRequest.FromUserID, friendRequest.ToUserID) } - log.ZDebug(ctx, "refuse friend request", "friendRequest db", fr, "friendRequest arg", friendRequest) + + // Log the action of refusing the friend request for debugging and auditing purposes. + log.ZDebug(ctx, "Refusing friend request", map[string]interface{}{ + "DB_FriendRequest": fr, + "Arg_FriendRequest": friendRequest, + }) + + // Mark the friend request as refused and update the handle time. friendRequest.HandleResult = constant.FriendResponseRefuse friendRequest.HandleTime = time.Now() - err = f.friendRequest.Update(ctx, friendRequest) - if err != nil { - return err + if err := f.friendRequest.Update(ctx, friendRequest); err != nil { + return fmt.Errorf("failed to update friend request from %s to %s as refused: %w", friendRequest.FromUserID, friendRequest.ToUserID, err) } + return nil } -// AgreeFriendRequest 同意好友申请 (1)检查是否有申请记录且为未处理状态 (没有记录返回错误) (2)检查是否好友(不返回错误) (3) 建立双向好友关系(存在的忽略). +// AgreeFriendRequest accepts a friend request. It first checks for an existing, unprocessed request. func (f *friendDatabase) AgreeFriendRequest(ctx context.Context, friendRequest *relation.FriendRequestModel) (err error) { return f.tx.Transaction(ctx, func(ctx context.Context) error { defer log.ZDebug(ctx, "return line") @@ -227,10 +249,10 @@ func (f *friendDatabase) AgreeFriendRequest(ctx context.Context, friendRequest * return err } existsMap := utils.SliceSet(utils.Slice(exists, func(friend *relation.FriendModel) [2]string { - return [...]string{friend.OwnerUserID, friend.FriendUserID} // 自己 - 好友 + return [...]string{friend.OwnerUserID, friend.FriendUserID} // My - Friend })) var adds []*relation.FriendModel - if _, ok := existsMap[[...]string{friendRequest.ToUserID, friendRequest.FromUserID}]; !ok { // 自己 - 好友 + if _, ok := existsMap[[...]string{friendRequest.ToUserID, friendRequest.FromUserID}]; !ok { // My - Friend adds = append( adds, &relation.FriendModel{ @@ -241,7 +263,7 @@ func (f *friendDatabase) AgreeFriendRequest(ctx context.Context, friendRequest * }, ) } - if _, ok := existsMap[[...]string{friendRequest.FromUserID, friendRequest.ToUserID}]; !ok { // 好友 - 自己 + if _, ok := existsMap[[...]string{friendRequest.FromUserID, friendRequest.ToUserID}]; !ok { // My - Friend adds = append( adds, &relation.FriendModel{ @@ -261,7 +283,7 @@ func (f *friendDatabase) AgreeFriendRequest(ctx context.Context, friendRequest * }) } -// 删除好友 外部判断是否好友关系. +// Delete removes a friend relationship. It is assumed that the external caller has verified the friendship status. func (f *friendDatabase) Delete(ctx context.Context, ownerUserID string, friendUserIDs []string) (err error) { if err := f.friend.Delete(ctx, ownerUserID, friendUserIDs); err != nil { return err @@ -269,7 +291,7 @@ func (f *friendDatabase) Delete(ctx context.Context, ownerUserID string, friendU return f.cache.DelFriendIDs(append(friendUserIDs, ownerUserID)...).ExecDel(ctx) } -// 更新好友备注 零值也支持. +// UpdateRemark updates the remark for a friend. Zero value for remark is also supported. func (f *friendDatabase) UpdateRemark(ctx context.Context, ownerUserID, friendUserID, remark string) (err error) { if err := f.friend.UpdateRemark(ctx, ownerUserID, friendUserID, remark); err != nil { return err @@ -277,27 +299,27 @@ func (f *friendDatabase) UpdateRemark(ctx context.Context, ownerUserID, friendUs return f.cache.DelFriend(ownerUserID, friendUserID).ExecDel(ctx) } -// 获取ownerUserID的好友列表 无结果不返回错误. +// PageOwnerFriends retrieves the list of friends for the ownerUserID. It does not return an error if the result is empty. func (f *friendDatabase) PageOwnerFriends(ctx context.Context, ownerUserID string, pagination pagination.Pagination) (total int64, friends []*relation.FriendModel, err error) { return f.friend.FindOwnerFriends(ctx, ownerUserID, pagination) } -// friendUserID在哪些人的好友列表中. +// PageInWhoseFriends identifies in whose friend lists the friendUserID appears. func (f *friendDatabase) PageInWhoseFriends(ctx context.Context, friendUserID string, pagination pagination.Pagination) (total int64, friends []*relation.FriendModel, err error) { return f.friend.FindInWhoseFriends(ctx, friendUserID, pagination) } -// 获取我发出去的好友申请 无结果不返回错误. +// PageFriendRequestFromMe retrieves friend requests sent by me. It does not return an error if the result is empty. func (f *friendDatabase) PageFriendRequestFromMe(ctx context.Context, userID string, pagination pagination.Pagination) (total int64, friends []*relation.FriendRequestModel, err error) { return f.friendRequest.FindFromUserID(ctx, userID, pagination) } -// 获取我收到的的好友申请 无结果不返回错误. +// PageFriendRequestToMe retrieves friend requests received by me. It does not return an error if the result is empty. func (f *friendDatabase) PageFriendRequestToMe(ctx context.Context, userID string, pagination pagination.Pagination) (total int64, friends []*relation.FriendRequestModel, err error) { return f.friendRequest.FindToUserID(ctx, userID, pagination) } -// 获取某人指定好友的信息 如果有好友不存在,也返回错误. +// FindFriendsWithError retrieves specified friends' information for ownerUserID. Returns an error if any friend does not exist. func (f *friendDatabase) FindFriendsWithError(ctx context.Context, ownerUserID string, friendUserIDs []string) (friends []*relation.FriendModel, err error) { friends, err = f.friend.FindFriends(ctx, ownerUserID, friendUserIDs) if err != nil { diff --git a/pkg/common/db/controller/group.go b/pkg/common/db/controller/group.go index decd868d65..6f208cc24d 100644 --- a/pkg/common/db/controller/group.go +++ b/pkg/common/db/controller/group.go @@ -31,47 +31,79 @@ import ( ) type GroupDatabase interface { - // Group + // CreateGroup creates new groups along with their members. CreateGroup(ctx context.Context, groups []*relationtb.GroupModel, groupMembers []*relationtb.GroupMemberModel) error + // TakeGroup retrieves a single group by its ID. TakeGroup(ctx context.Context, groupID string) (group *relationtb.GroupModel, err error) + // FindGroup retrieves multiple groups by their IDs. FindGroup(ctx context.Context, groupIDs []string) (groups []*relationtb.GroupModel, err error) + // SearchGroup searches for groups based on a keyword and pagination settings, returns total count and groups. SearchGroup(ctx context.Context, keyword string, pagination pagination.Pagination) (int64, []*relationtb.GroupModel, error) + // UpdateGroup updates the properties of a group identified by its ID. UpdateGroup(ctx context.Context, groupID string, data map[string]any) error - DismissGroup(ctx context.Context, groupID string, deleteMember bool) error // 解散群,并删除群成员 + // DismissGroup disbands a group and optionally removes its members based on the deleteMember flag. + DismissGroup(ctx context.Context, groupID string, deleteMember bool) error + // TakeGroupMember retrieves a specific group member by group ID and user ID. TakeGroupMember(ctx context.Context, groupID string, userID string) (groupMember *relationtb.GroupMemberModel, err error) + // TakeGroupOwner retrieves the owner of a group by group ID. TakeGroupOwner(ctx context.Context, groupID string) (*relationtb.GroupMemberModel, error) - FindGroupMembers(ctx context.Context, groupID string, userIDs []string) (groupMembers []*relationtb.GroupMemberModel, err error) // * - FindGroupMemberUser(ctx context.Context, groupIDs []string, userID string) (groupMembers []*relationtb.GroupMemberModel, err error) // * - FindGroupMemberRoleLevels(ctx context.Context, groupID string, roleLevels []int32) (groupMembers []*relationtb.GroupMemberModel, err error) // * - FindGroupMemberAll(ctx context.Context, groupID string) (groupMembers []*relationtb.GroupMemberModel, err error) // * + // FindGroupMembers retrieves members of a group filtered by user IDs. + FindGroupMembers(ctx context.Context, groupID string, userIDs []string) (groupMembers []*relationtb.GroupMemberModel, err error) + // FindGroupMemberUser retrieves groups that a user is a member of, filtered by group IDs. + FindGroupMemberUser(ctx context.Context, groupIDs []string, userID string) (groupMembers []*relationtb.GroupMemberModel, err error) + // FindGroupMemberRoleLevels retrieves group members filtered by their role levels within a group. + FindGroupMemberRoleLevels(ctx context.Context, groupID string, roleLevels []int32) (groupMembers []*relationtb.GroupMemberModel, err error) + // FindGroupMemberAll retrieves all members of a group. + FindGroupMemberAll(ctx context.Context, groupID string) (groupMembers []*relationtb.GroupMemberModel, err error) + // FindGroupsOwner retrieves the owners for multiple groups. FindGroupsOwner(ctx context.Context, groupIDs []string) ([]*relationtb.GroupMemberModel, error) + // FindGroupMemberUserID retrieves the user IDs of all members in a group. FindGroupMemberUserID(ctx context.Context, groupID string) ([]string, error) + // FindGroupMemberNum retrieves the number of members in a group. FindGroupMemberNum(ctx context.Context, groupID string) (uint32, error) + // FindUserManagedGroupID retrieves group IDs managed by a user. FindUserManagedGroupID(ctx context.Context, userID string) (groupIDs []string, err error) + // PageGroupRequest paginates through group requests for specified groups. PageGroupRequest(ctx context.Context, groupIDs []string, pagination pagination.Pagination) (int64, []*relationtb.GroupRequestModel, error) + // GetGroupRoleLevelMemberIDs retrieves user IDs of group members with a specific role level. GetGroupRoleLevelMemberIDs(ctx context.Context, groupID string, roleLevel int32) ([]string, error) + // PageGetJoinGroup paginates through groups that a user has joined. PageGetJoinGroup(ctx context.Context, userID string, pagination pagination.Pagination) (total int64, totalGroupMembers []*relationtb.GroupMemberModel, err error) + // PageGetGroupMember paginates through members of a group. PageGetGroupMember(ctx context.Context, groupID string, pagination pagination.Pagination) (total int64, totalGroupMembers []*relationtb.GroupMemberModel, err error) + // SearchGroupMember searches for group members based on a keyword, group ID, and pagination settings. SearchGroupMember(ctx context.Context, keyword string, groupID string, pagination pagination.Pagination) (int64, []*relationtb.GroupMemberModel, error) + // HandlerGroupRequest processes a group join request with a specified result. HandlerGroupRequest(ctx context.Context, groupID string, userID string, handledMsg string, handleResult int32, member *relationtb.GroupMemberModel) error + // DeleteGroupMember removes specified users from a group. DeleteGroupMember(ctx context.Context, groupID string, userIDs []string) error + // MapGroupMemberUserID maps group IDs to their members' simplified user IDs. MapGroupMemberUserID(ctx context.Context, groupIDs []string) (map[string]*relationtb.GroupSimpleUserID, error) + // MapGroupMemberNum maps group IDs to their member count. MapGroupMemberNum(ctx context.Context, groupIDs []string) (map[string]uint32, error) - TransferGroupOwner(ctx context.Context, groupID string, oldOwnerUserID, newOwnerUserID string, roleLevel int32) error // 转让群 + // TransferGroupOwner transfers the ownership of a group to another user. + TransferGroupOwner(ctx context.Context, groupID string, oldOwnerUserID, newOwnerUserID string, roleLevel int32) error + // UpdateGroupMember updates properties of a group member. UpdateGroupMember(ctx context.Context, groupID string, userID string, data map[string]any) error + // UpdateGroupMembers batch updates properties of group members. UpdateGroupMembers(ctx context.Context, data []*relationtb.BatchUpdateGroupMember) error - // GroupRequest + + // CreateGroupRequest creates new group join requests. CreateGroupRequest(ctx context.Context, requests []*relationtb.GroupRequestModel) error + // TakeGroupRequest retrieves a specific group join request. TakeGroupRequest(ctx context.Context, groupID string, userID string) (*relationtb.GroupRequestModel, error) + // FindGroupRequests retrieves multiple group join requests. FindGroupRequests(ctx context.Context, groupID string, userIDs []string) ([]*relationtb.GroupRequestModel, error) + // PageGroupRequestUser paginates through group join requests made by a user. PageGroupRequestUser(ctx context.Context, userID string, pagination pagination.Pagination) (int64, []*relationtb.GroupRequestModel, error) - // 获取群总数 + // CountTotal counts the total number of groups as of a certain date. CountTotal(ctx context.Context, before *time.Time) (count int64, err error) - // 获取范围内群增量 + // CountRangeEverydayTotal counts the daily group creation total within a specified date range. CountRangeEverydayTotal(ctx context.Context, start time.Time, end time.Time) (map[string]int64, error) + // DeleteGroupMemberHash deletes the hash entries for group members in specified groups. DeleteGroupMemberHash(ctx context.Context, groupIDs []string) error } diff --git a/pkg/common/db/controller/msg.go b/pkg/common/db/controller/msg.go index 7eac624a74..add9b63ce7 100644 --- a/pkg/common/db/controller/msg.go +++ b/pkg/common/db/controller/msg.go @@ -48,33 +48,32 @@ const ( updateKeyRevoke ) +// CommonMsgDatabase defines the interface for message database operations. type CommonMsgDatabase interface { - // 批量插入消息 + // BatchInsertChat2DB inserts a batch of messages into the database for a specific conversation. BatchInsertChat2DB(ctx context.Context, conversationID string, msgs []*sdkws.MsgData, currentMaxSeq int64) error - // 撤回消息 + // RevokeMsg revokes a message in a conversation. RevokeMsg(ctx context.Context, conversationID string, seq int64, revoke *unrelationtb.RevokeModel) error - // mark as read + // MarkSingleChatMsgsAsRead marks messages as read for a single chat by sequence numbers. MarkSingleChatMsgsAsRead(ctx context.Context, userID string, conversationID string, seqs []int64) error - // 刪除redis中消息缓存 + // DeleteMessagesFromCache deletes message caches from Redis by sequence numbers. DeleteMessagesFromCache(ctx context.Context, conversationID string, seqs []int64) error + // DelUserDeleteMsgsList deletes user's message deletion list. DelUserDeleteMsgsList(ctx context.Context, conversationID string, seqs []int64) - // incrSeq然后批量插入缓存 + // BatchInsertChat2Cache increments the sequence number and then batch inserts messages into the cache. BatchInsertChat2Cache(ctx context.Context, conversationID string, msgs []*sdkws.MsgData) (seq int64, isNewConversation bool, err error) - - // 通过seqList获取mongo中写扩散消息 + // GetMsgBySeqsRange retrieves messages from MongoDB by a range of sequence numbers. GetMsgBySeqsRange(ctx context.Context, userID string, conversationID string, begin, end, num, userMaxSeq int64) (minSeq int64, maxSeq int64, seqMsg []*sdkws.MsgData, err error) - // 通过seqList获取大群在 mongo里面的消息 + // GetMsgBySeqs retrieves messages for large groups from MongoDB by sequence numbers. GetMsgBySeqs(ctx context.Context, userID string, conversationID string, seqs []int64) (minSeq int64, maxSeq int64, seqMsg []*sdkws.MsgData, err error) - // 删除会话消息重置最小seq, remainTime为消息保留的时间单位秒,超时消息删除, 传0删除所有消息(此方法不删除redis cache) + // DeleteConversationMsgsAndSetMinSeq deletes conversation messages and resets the minimum sequence number. If `remainTime` is 0, all messages are deleted (this method does not delete Redis cache). DeleteConversationMsgsAndSetMinSeq(ctx context.Context, conversationID string, remainTime int64) error - // 用户标记删除过期消息返回标记删除的seq列表 + // UserMsgsDestruct marks messages for deletion based on destruct time and returns a list of sequence numbers for marked messages. UserMsgsDestruct(ctx context.Context, userID string, conversationID string, destructTime int64, lastMsgDestructTime time.Time) (seqs []int64, err error) - - // 用户根据seq删除消息 + // DeleteUserMsgsBySeqs allows a user to delete messages based on sequence numbers. DeleteUserMsgsBySeqs(ctx context.Context, userID string, conversationID string, seqs []int64) error - // 物理删除消息置空 + // DeleteMsgsPhysicalBySeqs physically deletes messages by emptying them based on sequence numbers. DeleteMsgsPhysicalBySeqs(ctx context.Context, conversationID string, seqs []int64) error - SetMaxSeq(ctx context.Context, conversationID string, maxSeq int64) error GetMaxSeqs(ctx context.Context, conversationIDs []string) (map[string]int64, error) GetMaxSeq(ctx context.Context, conversationID string) (int64, error) @@ -200,7 +199,7 @@ func (db *commonMsgDatabase) BatchInsertBlock(ctx context.Context, conversationI } num := db.msg.GetSingleGocMsgNum() // num = 100 - for i, field := range fields { // 检查类型 + for i, field := range fields { // Check the type of the field var ok bool switch key { case updateKeyMsg: @@ -218,7 +217,7 @@ func (db *commonMsgDatabase) BatchInsertBlock(ctx context.Context, conversationI return errs.ErrInternalServer.Wrap("field type is invalid") } } - // 返回值为true表示数据库存在该文档,false表示数据库不存在该文档 + // Returns true if the document exists in the database, false if the document does not exist in the database updateMsgModel := func(seq int64, i int) (bool, error) { var ( res *mongo.UpdateResult @@ -240,21 +239,21 @@ func (db *commonMsgDatabase) BatchInsertBlock(ctx context.Context, conversationI } tryUpdate := true for i := 0; i < len(fields); i++ { - seq := firstSeq + int64(i) // 当前seq + seq := firstSeq + int64(i) // Current sequence number if tryUpdate { matched, err := updateMsgModel(seq, i) if err != nil { return err } if matched { - continue // 匹配到了,继续下一个(不一定修改) + continue // The current data has been updated, skip the current data } } doc := unrelationtb.MsgDocModel{ DocID: db.msg.GetDocID(conversationID, seq), Msg: make([]*unrelationtb.MsgInfoModel, num), } - var insert int // 插入的数量 + var insert int // Inserted data number for j := i; j < len(fields); j++ { seq = firstSeq + int64(j) if db.msg.GetDocID(conversationID, seq) != doc.DocID { @@ -283,14 +282,14 @@ func (db *commonMsgDatabase) BatchInsertBlock(ctx context.Context, conversationI } if err := db.msgDocDatabase.Create(ctx, &doc); err != nil { if mongo.IsDuplicateKeyError(err) { - i-- // 存在并发,重试当前数据 - tryUpdate = true // 以修改模式 + i-- // already inserted + tryUpdate = true // next block use update mode continue } return err } - tryUpdate = false // 当前以插入成功,下一块优先插入模式 - i += insert - 1 // 跳过已插入的数据 + tryUpdate = false // The current block is inserted successfully, and the next block is inserted preferentially + i += insert - 1 // Skip the inserted data } return nil } @@ -754,7 +753,7 @@ func (db *commonMsgDatabase) UserMsgsDestruct(ctx context.Context, userID string log.ZError(ctx, "deleteMsgRecursion GetUserMsgListByIndex failed", err, "conversationID", conversationID, "index", index) } } - // 获取报错,或者获取不到了,物理删除并且返回seq delMongoMsgsPhysical(delStruct.delDocIDList), 结束递归 + // If an error is reported, or the error cannot be obtained, it is physically deleted and seq delMongoMsgsPhysical(delStruct.delDocIDList) is returned to end the recursion break } index++ @@ -809,7 +808,7 @@ func (d *delMsgRecursionStruct) getSetMinSeq() int64 { // index 0....19(del) 20...69 // seq 70 // set minSeq 21 -// recursion 删除list并且返回设置的最小seq. +// recursion deletes the list and returns the set minimum seq. func (db *commonMsgDatabase) deleteMsgRecursion(ctx context.Context, conversationID string, index int64, delStruct *delMsgRecursionStruct, remainTime int64) (int64, error) { // find from oldest list msgDocModel, err := db.msgDocDatabase.GetMsgDocModelByIndex(ctx, conversationID, index, 1) @@ -821,7 +820,7 @@ func (db *commonMsgDatabase) deleteMsgRecursion(ctx context.Context, conversatio log.ZError(ctx, "deleteMsgRecursion GetUserMsgListByIndex failed", err, "conversationID", conversationID, "index", index) } } - // 获取报错,或者获取不到了,物理删除并且返回seq delMongoMsgsPhysical(delStruct.delDocIDList), 结束递归 + // If an error is reported, or the error cannot be obtained, it is physically deleted and seq delMongoMsgsPhysical(delStruct.delDocIDList) is returned to end the recursion err = db.msgDocDatabase.DeleteDocs(ctx, delStruct.delDocIDs) if err != nil { return 0, err diff --git a/pkg/common/db/controller/third.go b/pkg/common/db/controller/third.go index fb5b0ccbe7..55c047bd63 100644 --- a/pkg/common/db/controller/third.go +++ b/pkg/common/db/controller/third.go @@ -63,13 +63,7 @@ func NewThirdDatabase(cache cache.MsgModel, logdb relation.LogInterface) ThirdDa return &thirdDatabase{cache: cache, logdb: logdb} } -func (t *thirdDatabase) FcmUpdateToken( - ctx context.Context, - account string, - platformID int, - fcmToken string, - expireTime int64, -) error { +func (t *thirdDatabase) FcmUpdateToken(ctx context.Context, account string, platformID int, fcmToken string, expireTime int64) error { return t.cache.SetFcmToken(ctx, account, platformID, fcmToken, expireTime) } diff --git a/pkg/common/db/s3/aws/aws.go b/pkg/common/db/s3/aws/aws.go index d996485c73..7588eea91b 100644 --- a/pkg/common/db/s3/aws/aws.go +++ b/pkg/common/db/s3/aws/aws.go @@ -58,10 +58,10 @@ func NewAWS() (s3.Interface, error) { credential := credentials.NewStaticCredentials( conf.AccessKeyID, // accessKey conf.AccessKeySecret, // secretKey - "") // sts的临时凭证 + "") // stoken sess, err := session.NewSession(&aws.Config{ - Region: aws.String(conf.Region), // 桶所在的区域 + Region: aws.String(conf.Region), // The area where the bucket is located Credentials: credential, }) diff --git a/pkg/common/db/s3/cont/consts.go b/pkg/common/db/s3/cont/consts.go index a01a8312c0..b51878e496 100644 --- a/pkg/common/db/s3/cont/consts.go +++ b/pkg/common/db/s3/cont/consts.go @@ -15,10 +15,24 @@ package cont const ( - hashPath = "openim/data/hash/" - tempPath = "openim/temp/" - DirectPath = "openim/direct" - UploadTypeMultipart = 1 // 分片上传 - UploadTypePresigned = 2 // 预签名上传 - partSeparator = "," + // hashPath defines the storage path for hash data within the 'openim' directory. + hashPath = "openim/data/hash/" + + // tempPath specifies the directory for temporary files in the 'openim' structure. + tempPath = "openim/temp/" + + // DirectPath indicates the directory for direct uploads or access within the 'openim' structure. + DirectPath = "openim/direct" + + // UploadTypeMultipart represents the identifier for multipart uploads, + // allowing large files to be uploaded in chunks. + UploadTypeMultipart = 1 + + // UploadTypePresigned signifies the use of presigned URLs for uploads, + // facilitating secure, authorized file transfers without requiring direct access to the storage credentials. + UploadTypePresigned = 2 + + // partSeparator is used as a delimiter in multipart upload processes, + // separating individual file parts. + partSeparator = "," ) diff --git a/pkg/common/db/s3/cont/controller.go b/pkg/common/db/s3/cont/controller.go index 2a66aeaf6e..f60c2c650d 100644 --- a/pkg/common/db/s3/cont/controller.go +++ b/pkg/common/db/s3/cont/controller.go @@ -114,7 +114,7 @@ func (c *Controller) InitiateUpload(ctx context.Context, hash string, size int64 return nil, err } if size <= partSize { - // 预签名上传 + // Pre-signed upload key := path.Join(tempPath, c.NowPath(), fmt.Sprintf("%s_%d_%s.presigned", hash, size, c.UUID())) rawURL, err := c.impl.PresignedPutObject(ctx, key, expire) if err != nil { @@ -139,7 +139,7 @@ func (c *Controller) InitiateUpload(ctx context.Context, hash string, size int64 }, }, nil } else { - // 分片上传 + // Fragment upload upload, err := c.impl.InitiateMultipartUpload(ctx, c.HashPath(hash)) if err != nil { return nil, err @@ -206,7 +206,7 @@ func (c *Controller) CompleteUpload(ctx context.Context, uploadID string, partHa ETag: part, } } - // todo: 验证大小 + // todo: Validation size result, err := c.impl.CompleteMultipartUpload(ctx, upload.ID, upload.Key, parts) if err != nil { return nil, err @@ -225,7 +225,7 @@ func (c *Controller) CompleteUpload(ctx context.Context, uploadID string, partHa if md5val := hex.EncodeToString(md5Sum[:]); md5val != upload.Hash { return nil, errs.ErrArgs.Wrap(fmt.Sprintf("md5 mismatching %s != %s", md5val, upload.Hash)) } - // 防止在这个时候,并发操作,导致文件被覆盖 + // Prevents concurrent operations at this time that cause files to be overwritten copyInfo, err := c.impl.CopyObject(ctx, uploadInfo.Key, upload.Key+"."+c.UUID()) if err != nil { return nil, err diff --git a/pkg/common/db/s3/cont/structs.go b/pkg/common/db/s3/cont/structs.go index ff5ca79431..de484cc5f2 100644 --- a/pkg/common/db/s3/cont/structs.go +++ b/pkg/common/db/s3/cont/structs.go @@ -17,9 +17,14 @@ package cont import "github.com/openimsdk/open-im-server/v3/pkg/common/db/s3" type InitiateUploadResult struct { - UploadID string `json:"uploadID"` // 上传ID - PartSize int64 `json:"partSize"` // 分片大小 - Sign *s3.AuthSignResult `json:"sign"` // 分片信息 + // UploadID uniquely identifies the upload session for tracking and management purposes. + UploadID string `json:"uploadID"` + + // PartSize specifies the size of each part in a multipart upload. This is relevant for breaking down large uploads into manageable pieces. + PartSize int64 `json:"partSize"` + + // Sign contains the authentication and signature information necessary for securely uploading each part. This could include signed URLs or tokens. + Sign *s3.AuthSignResult `json:"sign"` } type UploadResult struct { diff --git a/pkg/common/db/s3/minio/image.go b/pkg/common/db/s3/minio/image.go index 71db1ea519..f363f94b1c 100644 --- a/pkg/common/db/s3/minio/image.go +++ b/pkg/common/db/s3/minio/image.go @@ -42,79 +42,51 @@ func ImageWidthHeight(img image.Image) (int, int) { return bounds.X, bounds.Y } +// resizeImage resizes an image to a specified maximum width and height, maintaining the aspect ratio. +// If both maxWidth and maxHeight are set to 0, the original image is returned. +// If both are non-zero, the image is scaled to fit within the constraints while maintaining aspect ratio. +// If only one of maxWidth or maxHeight is non-zero, the image is scaled accordingly. func resizeImage(img image.Image, maxWidth, maxHeight int) image.Image { bounds := img.Bounds() - imgWidth := bounds.Max.X - imgHeight := bounds.Max.Y + imgWidth, imgHeight := bounds.Dx(), bounds.Dy() - // 计算缩放比例 - scaleWidth := float64(maxWidth) / float64(imgWidth) - scaleHeight := float64(maxHeight) / float64(imgHeight) - - // 如果都为0,则不缩放,返回原始图片 + // Return original image if no resizing is needed. if maxWidth == 0 && maxHeight == 0 { return img } - // 如果宽度和高度都大于0,则选择较小的缩放比例,以保持宽高比 + var scale float64 = 1 if maxWidth > 0 && maxHeight > 0 { - scale := scaleWidth - if scaleHeight < scaleWidth { - scale = scaleHeight - } - - // 计算缩略图尺寸 - thumbnailWidth := int(float64(imgWidth) * scale) - thumbnailHeight := int(float64(imgHeight) * scale) - - // 使用"image"库的Resample方法生成缩略图 - thumbnail := image.NewRGBA(image.Rect(0, 0, thumbnailWidth, thumbnailHeight)) - for y := 0; y < thumbnailHeight; y++ { - for x := 0; x < thumbnailWidth; x++ { - srcX := int(float64(x) / scale) - srcY := int(float64(y) / scale) - thumbnail.Set(x, y, img.At(srcX, srcY)) - } - } - - return thumbnail + scaleWidth := float64(maxWidth) / float64(imgWidth) + scaleHeight := float64(maxHeight) / float64(imgHeight) + // Choose the smaller scale to fit both constraints. + scale = min(scaleWidth, scaleHeight) + } else if maxWidth > 0 { + scale = float64(maxWidth) / float64(imgWidth) + } else if maxHeight > 0 { + scale = float64(maxHeight) / float64(imgHeight) } - // 如果只指定了宽度或高度,则根据最大不超过的规则生成缩略图 - if maxWidth > 0 { - thumbnailWidth := maxWidth - thumbnailHeight := int(float64(imgHeight) * scaleWidth) + newWidth := int(float64(imgWidth) * scale) + newHeight := int(float64(imgHeight) * scale) - // 使用"image"库的Resample方法生成缩略图 - thumbnail := image.NewRGBA(image.Rect(0, 0, thumbnailWidth, thumbnailHeight)) - for y := 0; y < thumbnailHeight; y++ { - for x := 0; x < thumbnailWidth; x++ { - srcX := int(float64(x) / scaleWidth) - srcY := int(float64(y) / scaleWidth) - thumbnail.Set(x, y, img.At(srcX, srcY)) - } + // Resize the image by creating a new image and manually copying pixels. + thumbnail := image.NewRGBA(image.Rect(0, 0, newWidth, newHeight)) + for y := 0; y < newHeight; y++ { + for x := 0; x < newWidth; x++ { + srcX := int(float64(x) / scale) + srcY := int(float64(y) / scale) + thumbnail.Set(x, y, img.At(srcX, srcY)) } - - return thumbnail } - if maxHeight > 0 { - thumbnailWidth := int(float64(imgWidth) * scaleHeight) - thumbnailHeight := maxHeight - - // 使用"image"库的Resample方法生成缩略图 - thumbnail := image.NewRGBA(image.Rect(0, 0, thumbnailWidth, thumbnailHeight)) - for y := 0; y < thumbnailHeight; y++ { - for x := 0; x < thumbnailWidth; x++ { - srcX := int(float64(x) / scaleHeight) - srcY := int(float64(y) / scaleHeight) - thumbnail.Set(x, y, img.At(srcX, srcY)) - } - } + return thumbnail +} - return thumbnail +// min returns the smaller of x or y. +func min(x, y float64) float64 { + if x < y { + return x } - - // 默认情况下,返回原始图片 - return img + return y } diff --git a/pkg/common/db/s3/oss/oss.go b/pkg/common/db/s3/oss/oss.go index 98473b87f2..a6be41d394 100644 --- a/pkg/common/db/s3/oss/oss.go +++ b/pkg/common/db/s3/oss/oss.go @@ -30,6 +30,7 @@ import ( "strings" "time" + "github.com/OpenIMSDK/tools/errs" "github.com/aliyun/aliyun-oss-go-sdk/oss" "github.com/openimsdk/open-im-server/v3/pkg/common/config" @@ -60,7 +61,7 @@ const successCode = http.StatusOK func NewOSS() (s3.Interface, error) { conf := config.Config.Object.Oss if conf.BucketURL == "" { - return nil, errors.New("bucket url is empty") + return nil, errs.Wrap(errors.New("bucket url is empty")) } client, err := oss.New(conf.Endpoint, conf.AccessKeyID, conf.AccessKeySecret) if err != nil { @@ -68,7 +69,7 @@ func NewOSS() (s3.Interface, error) { } bucket, err := client.Bucket(conf.Bucket) if err != nil { - return nil, err + return nil, errs.Wrap(err, "ali-oss bucket error") } if conf.BucketURL[len(conf.BucketURL)-1] != '/' { conf.BucketURL += "/" @@ -138,10 +139,10 @@ func (o *OSS) CompleteMultipartUpload(ctx context.Context, uploadID string, name func (o *OSS) PartSize(ctx context.Context, size int64) (int64, error) { if size <= 0 { - return 0, errors.New("size must be greater than 0") + return 0, errs.Wrap(errors.New("size must be greater than 0")) } if size > maxPartSize*maxNumSize { - return 0, fmt.Errorf("OSS size must be less than the maximum allowed limit") + return 0, errs.Wrap(errors.New("size must be less than the maximum allowed limit")) } if size <= minPartSize*maxNumSize { return minPartSize, nil @@ -196,25 +197,25 @@ func (o *OSS) StatObject(ctx context.Context, name string) (*s3.ObjectInfo, erro } res := &s3.ObjectInfo{Key: name} if res.ETag = strings.ToLower(strings.ReplaceAll(header.Get("ETag"), `"`, ``)); res.ETag == "" { - return nil, errors.New("StatObject etag not found") + return nil, errs.Wrap(errors.New("StatObject etag not found")) } if contentLengthStr := header.Get("Content-Length"); contentLengthStr == "" { return nil, errors.New("StatObject content-length not found") } else { res.Size, err = strconv.ParseInt(contentLengthStr, 10, 64) if err != nil { - return nil, fmt.Errorf("StatObject content-length parse error: %w", err) + return nil, errs.Wrap(err, "StatObject content-length parse error") } if res.Size < 0 { - return nil, errors.New("StatObject content-length must be greater than 0") + return nil, errs.Wrap(errors.New("StatObject content-length must be greater than 0")) } } if lastModified := header.Get("Last-Modified"); lastModified == "" { - return nil, errors.New("StatObject last-modified not found") + return nil, errs.Wrap(errors.New("StatObject last-modified not found")) } else { res.LastModified, err = time.Parse(http.TimeFormat, lastModified) if err != nil { - return nil, fmt.Errorf("StatObject last-modified parse error: %w", err) + return nil, errs.Wrap(err, "StatObject last-modified parse error") } } return res, nil @@ -227,7 +228,7 @@ func (o *OSS) DeleteObject(ctx context.Context, name string) error { func (o *OSS) CopyObject(ctx context.Context, src string, dst string) (*s3.CopyObjectInfo, error) { result, err := o.bucket.CopyObject(src, dst) if err != nil { - return nil, err + return nil, errs.Wrap(err, "CopyObject error") } return &s3.CopyObjectInfo{ Key: dst, @@ -261,7 +262,7 @@ func (o *OSS) ListUploadedParts(ctx context.Context, uploadID string, name strin Bucket: o.bucket.BucketName, }, oss.MaxUploads(100), oss.MaxParts(maxParts), oss.PartNumberMarker(partNumberMarker)) if err != nil { - return nil, err + return nil, errs.Wrap(err, "ListUploadedParts error") } res := &s3.ListUploadedPartsResult{ Key: result.Key, @@ -286,7 +287,7 @@ func (o *OSS) AccessURL(ctx context.Context, name string, expire time.Duration, var opts []oss.Option if opt != nil { if opt.Image != nil { - // 文档地址: https://help.aliyun.com/zh/oss/user-guide/resize-images-4?spm=a2c4g.11186623.0.0.4b3b1e4fWW6yji + // Docs Address: https://help.aliyun.com/zh/oss/user-guide/resize-images-4?spm=a2c4g.11186623.0.0.4b3b1e4fWW6yji var format string switch opt.Image.Format { case @@ -329,7 +330,7 @@ func (o *OSS) AccessURL(ctx context.Context, name string, expire time.Duration, } rawParams, err := oss.GetRawParams(opts) if err != nil { - return "", err + return "", errs.Wrap(err, "AccessURL error") } params := getURLParams(*o.bucket.Client.Conn, rawParams) return getURL(o.um, o.bucket.BucketName, name, params).String(), nil @@ -351,12 +352,12 @@ func (o *OSS) FormData(ctx context.Context, name string, size int64, contentType } policyJson, err := json.Marshal(policy) if err != nil { - return nil, err + return nil, errs.Wrap(err, "Marshal json error") } policyStr := base64.StdEncoding.EncodeToString(policyJson) h := hmac.New(sha1.New, []byte(o.credentials.GetAccessKeySecret())) if _, err := io.WriteString(h, policyStr); err != nil { - return nil, err + return nil, errs.Wrap(err, "WriteString error") } fd := &s3.FormData{ URL: o.bucketURL, diff --git a/pkg/common/db/table/relation/group.go b/pkg/common/db/table/relation/group.go index 57d6b1d62e..1f969cd4fb 100644 --- a/pkg/common/db/table/relation/group.go +++ b/pkg/common/db/table/relation/group.go @@ -46,8 +46,8 @@ type GroupModelInterface interface { Find(ctx context.Context, groupIDs []string) (groups []*GroupModel, err error) Take(ctx context.Context, groupID string) (group *GroupModel, err error) Search(ctx context.Context, keyword string, pagination pagination.Pagination) (total int64, groups []*GroupModel, err error) - // 获取群总数 + // Get Group total quantity CountTotal(ctx context.Context, before *time.Time) (count int64, err error) - // 获取范围内群增量 + // Get Group total quantity every day CountRangeEverydayTotal(ctx context.Context, start time.Time, end time.Time) (map[string]int64, error) } diff --git a/pkg/common/db/table/relation/user.go b/pkg/common/db/table/relation/user.go index dbb2ff4647..265c3c93a2 100644 --- a/pkg/common/db/table/relation/user.go +++ b/pkg/common/db/table/relation/user.go @@ -62,9 +62,9 @@ type UserModelInterface interface { Exist(ctx context.Context, userID string) (exist bool, err error) GetAllUserID(ctx context.Context, pagination pagination.Pagination) (count int64, userIDs []string, err error) GetUserGlobalRecvMsgOpt(ctx context.Context, userID string) (opt int, err error) - // 获取用户总数 + // Get user total quantity CountTotal(ctx context.Context, before *time.Time) (count int64, err error) - // 获取范围内用户增量 + // Get user total quantity every day CountRangeEverydayTotal(ctx context.Context, start time.Time, end time.Time) (map[string]int64, error) //CRUD user command AddUserCommand(ctx context.Context, userID string, Type int32, UUID string, value string, ex string) error diff --git a/pkg/common/db/unrelation/msg.go b/pkg/common/db/unrelation/msg.go index bc9118a9a2..0a6f683a57 100644 --- a/pkg/common/db/unrelation/msg.go +++ b/pkg/common/db/unrelation/msg.go @@ -21,8 +21,6 @@ import ( "fmt" "time" - "github.com/OpenIMSDK/tools/log" - "github.com/OpenIMSDK/protocol/msg" "github.com/OpenIMSDK/protocol/constant" @@ -35,6 +33,7 @@ import ( "github.com/OpenIMSDK/protocol/sdkws" "github.com/OpenIMSDK/tools/errs" + "github.com/OpenIMSDK/tools/log" table "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/unrelation" ) @@ -122,13 +121,7 @@ func (m *MsgMongoDriver) UpdateMsgContent(ctx context.Context, docID string, ind return nil } -func (m *MsgMongoDriver) UpdateMsgStatusByIndexInOneDoc( - ctx context.Context, - docID string, - msg *sdkws.MsgData, - seqIndex int, - status int32, -) error { +func (m *MsgMongoDriver) UpdateMsgStatusByIndexInOneDoc(ctx context.Context, docID string, msg *sdkws.MsgData, seqIndex int, status int32) error { msg.Status = status bytes, err := proto.Marshal(msg) if err != nil { @@ -140,7 +133,7 @@ func (m *MsgMongoDriver) UpdateMsgStatusByIndexInOneDoc( bson.M{"$set": bson.M{fmt.Sprintf("msgs.%d.msg", seqIndex): bytes}}, ) if err != nil { - return errs.Wrap(err) + return errs.Wrap(err, fmt.Sprintf("docID is %s, seqIndex is %d", docID, seqIndex)) } return nil } @@ -166,7 +159,7 @@ func (m *MsgMongoDriver) GetMsgDocModelByIndex( findOpts, ) if err != nil { - return nil, errs.Wrap(err) + return nil, errs.Wrap(err, fmt.Sprintf("conversationID is %s", conversationID)) } var msgs []table.MsgDocModel err = cursor.All(ctx, &msgs) @@ -222,7 +215,7 @@ func (m *MsgMongoDriver) DeleteMsgsInOneDocByIndex(ctx context.Context, docID st } _, err := m.MsgCollection.UpdateMany(ctx, bson.M{"doc_id": docID}, updates) if err != nil { - return errs.Wrap(err) + return errs.Wrap(err, fmt.Sprintf("docID is %s, indexes is %v", docID, indexes)) } return nil } @@ -289,7 +282,7 @@ func (m *MsgMongoDriver) GetMsgBySeqIndexIn1Doc( defer cur.Close(ctx) var msgDocModel []table.MsgDocModel if err := cur.All(ctx, &msgDocModel); err != nil { - return nil, errs.Wrap(err) + return nil, errs.Wrap(err, fmt.Sprintf("docID is %s, seqs is %v", docID, seqs)) } if len(msgDocModel) == 0 { return nil, errs.Wrap(mongo.ErrNoDocuments) @@ -316,14 +309,14 @@ func (m *MsgMongoDriver) GetMsgBySeqIndexIn1Doc( } data, err := json.Marshal(&revokeContent) if err != nil { - return nil, err + return nil, errs.Wrap(err, fmt.Sprintf("docID is %s, seqs is %v", docID, seqs)) } elem := sdkws.NotificationElem{ Detail: string(data), } content, err := json.Marshal(&elem) if err != nil { - return nil, err + return nil, errs.Wrap(err, fmt.Sprintf("docID is %s, seqs is %v", docID, seqs)) } msg.Msg.ContentType = constant.MsgRevokeNotification msg.Msg.Content = string(content) @@ -336,17 +329,12 @@ func (m *MsgMongoDriver) GetMsgBySeqIndexIn1Doc( func (m *MsgMongoDriver) IsExistDocID(ctx context.Context, docID string) (bool, error) { count, err := m.MsgCollection.CountDocuments(ctx, bson.M{"doc_id": docID}) if err != nil { - return false, errs.Wrap(err) + return false, errs.Wrap(err, fmt.Sprintf("docID is %s", docID)) } return count > 0, nil } -func (m *MsgMongoDriver) MarkSingleChatMsgsAsRead( - ctx context.Context, - userID string, - docID string, - indexes []int64, -) error { +func (m *MsgMongoDriver) MarkSingleChatMsgsAsRead(ctx context.Context, userID string, docID string, indexes []int64) error { updates := []mongo.WriteModel{} for _, index := range indexes { filter := bson.M{ @@ -366,7 +354,7 @@ func (m *MsgMongoDriver) MarkSingleChatMsgsAsRead( updates = append(updates, updateModel) } _, err := m.MsgCollection.BulkWrite(ctx, updates) - return err + return errs.Wrap(err, fmt.Sprintf("docID is %s, indexes is %v", docID, indexes)) } // RangeUserSendCount @@ -662,7 +650,7 @@ func (m *MsgMongoDriver) RangeUserSendCount( "$dateToString": bson.M{ "format": "%Y-%m-%d", "date": bson.M{ - "$toDate": "$$item.msg.send_time", // 毫秒时间戳 + "$toDate": "$$item.msg.send_time", // Millisecond timestamp }, }, }, @@ -911,7 +899,7 @@ func (m *MsgMongoDriver) RangeGroupSendCount( "$dateToString": bson.M{ "format": "%Y-%m-%d", "date": bson.M{ - "$toDate": "$$item.msg.send_time", // 毫秒时间戳 + "$toDate": "$$item.msg.send_time", // Millisecond timestamp }, }, }, @@ -1076,6 +1064,7 @@ func (m *MsgMongoDriver) searchMessage(ctx context.Context, req *msg.SearchMessa var pipe mongo.Pipeline condition := bson.A{} if req.SendTime != "" { + // Changed to keyed fields for bson.M to avoid govet errors condition = append(condition, bson.M{"$eq": bson.A{bson.M{"$dateToString": bson.M{"format": "%Y-%m-%d", "date": bson.M{"$toDate": "$$item.msg.send_time"}}}, req.SendTime}}) } if req.MsgType != 0 { @@ -1092,62 +1081,26 @@ func (m *MsgMongoDriver) searchMessage(ctx context.Context, req *msg.SearchMessa } or := bson.A{ - bson.M{ - "doc_id": bson.M{ - "$regex": "^si_", - "$options": "i", - }, - }, + bson.M{"doc_id": bson.M{"$regex": "^si_", "$options": "i"}}, + bson.M{"doc_id": bson.M{"$regex": "^g_", "$options": "i"}}, + bson.M{"doc_id": bson.M{"$regex": "^sg_", "$options": "i"}}, } - or = append(or, - bson.M{ - "doc_id": bson.M{ - "$regex": "^g_", - "$options": "i", - }, - }, - bson.M{ - "doc_id": bson.M{ - "$regex": "^sg_", - "$options": "i", - }, - }, - ) + // Use bson.D with keyed fields to specify the order explicitly pipe = mongo.Pipeline{ - { - {"$match", bson.D{ - { - "$or", or, - }, - }}, - }, - { - {"$project", bson.D{ - { - "msgs", bson.D{ - { - "$filter", bson.D{ - {"input", "$msgs"}, - {"as", "item"}, - { - "cond", bson.D{ - {"$and", condition}, - }, - }, - }, - }, - }, - }, - {"doc_id", 1}, + {{"$match", bson.D{{Key: "$or", Value: or}}}}, + {{"$project", bson.D{ + {Key: "msgs", Value: bson.D{ + {Key: "$filter", Value: bson.D{ + {Key: "input", Value: "$msgs"}, + {Key: "as", Value: "item"}, + {Key: "cond", Value: bson.D{{Key: "$and", Value: condition}}}, + }}, }}, - }, - { - {"$unwind", bson.M{"path": "$msgs"}}, - }, - { - {"$sort", bson.M{"msgs.msg.send_time": -1}}, - }, + {Key: "doc_id", Value: 1}, + }}}, + {{"$unwind", bson.M{"path": "$msgs"}}}, + {{"$sort", bson.M{"msgs.msg.send_time": -1}}}, } cursor, err := m.MsgCollection.Aggregate(ctx, pipe) if err != nil { @@ -1160,12 +1113,12 @@ func (m *MsgMongoDriver) searchMessage(ctx context.Context, req *msg.SearchMessa var msgsDocs []docModel err = cursor.All(ctx, &msgsDocs) if err != nil { - return 0, nil, err + return 0, nil, errs.Wrap(err, "cursor.All msgsDocs") } log.ZDebug(ctx, "query mongoDB", "result", msgsDocs) msgs := make([]*table.MsgInfoModel, 0) - for index := range msgsDocs { - msgInfo := msgsDocs[index].Msg + for _, doc := range msgsDocs { + msgInfo := doc.Msg if msgInfo == nil || msgInfo.Msg == nil { continue } @@ -1185,14 +1138,12 @@ func (m *MsgMongoDriver) searchMessage(ctx context.Context, req *msg.SearchMessa } data, err := json.Marshal(&revokeContent) if err != nil { - return 0, nil, err - } - elem := sdkws.NotificationElem{ - Detail: string(data), + return 0, nil, errs.Wrap(err, "json.Marshal revokeContent") } + elem := sdkws.NotificationElem{Detail: string(data)} content, err := json.Marshal(&elem) if err != nil { - return 0, nil, err + return 0, nil, errs.Wrap(err, "json.Marshal elem") } msgInfo.Msg.ContentType = constant.MsgRevokeNotification msgInfo.Msg.Content = string(content) @@ -1203,7 +1154,8 @@ func (m *MsgMongoDriver) searchMessage(ctx context.Context, req *msg.SearchMessa n := int32(len(msgs)) if start >= n { return n, []*table.MsgInfoModel{}, nil - } else if start+req.Pagination.ShowNumber < n { + } + if start+req.Pagination.ShowNumber < n { msgs = msgs[start : start+req.Pagination.ShowNumber] } else { msgs = msgs[start:] diff --git a/pkg/common/discoveryregister/direct/directconn.go b/pkg/common/discoveryregister/direct/directconn.go index 84f173ea6d..cc59934a39 100644 --- a/pkg/common/discoveryregister/direct/directconn.go +++ b/pkg/common/discoveryregister/direct/directconn.go @@ -105,7 +105,7 @@ func (cd *ConnDirect) GetConns(ctx context.Context, } if len(connections) == 0 { - return nil, fmt.Errorf("no connections found for service: %s", serviceName) + return nil, errs.Wrap(errors.New("no connections found for service"), "serviceName", serviceName) } return connections, nil } @@ -155,10 +155,11 @@ func (cd *ConnDirect) dialService(ctx context.Context, address string, opts ...g conn, err := grpc.DialContext(ctx, cd.resolverDirect.Scheme()+":///"+address, options...) if err != nil { - return nil, err + return nil, errs.Wrap(err, "address", address) } return conn, nil } + func (cd *ConnDirect) dialServiceWithoutResolver(ctx context.Context, address string, opts ...grpc.DialOption) (*grpc.ClientConn, error) { options := append(opts, grpc.WithTransportCredentials(insecure.NewCredentials())) conn, err := grpc.DialContext(ctx, address, options...) diff --git a/pkg/common/discoveryregister/discoveryregister.go b/pkg/common/discoveryregister/discoveryregister.go index 23a9e32450..4ade0147ad 100644 --- a/pkg/common/discoveryregister/discoveryregister.go +++ b/pkg/common/discoveryregister/discoveryregister.go @@ -24,6 +24,7 @@ import ( "github.com/openimsdk/open-im-server/v3/pkg/common/discoveryregister/zookeeper" "github.com/OpenIMSDK/tools/discoveryregistry" + "github.com/OpenIMSDK/tools/errs" ) // NewDiscoveryRegister creates a new service discovery and registry client based on the provided environment type. @@ -41,6 +42,6 @@ func NewDiscoveryRegister(envType string) (discoveryregistry.SvcDiscoveryRegistr case "direct": return direct.NewConnDirect() default: - return nil, errors.New("envType not correct") + return nil, errs.Wrap(errors.New("envType not correct")) } } diff --git a/pkg/common/discoveryregister/discoveryregister_test.go b/pkg/common/discoveryregister/discoveryregister_test.go index 5317db5c69..e7a5fb276f 100644 --- a/pkg/common/discoveryregister/discoveryregister_test.go +++ b/pkg/common/discoveryregister/discoveryregister_test.go @@ -39,7 +39,7 @@ func TestNewDiscoveryRegister(t *testing.T) { expectedResult bool }{ {"zookeeper", false, true}, - {"k8s", false, true}, // 假设 k8s 配置也已正确设置 + {"k8s", false, true}, // Assume that the k8s configuration is also set up correctly {"direct", false, true}, {"invalid", true, false}, } diff --git a/pkg/common/http/http_client.go b/pkg/common/http/http_client.go index 7fc456a1d0..141284b645 100644 --- a/pkg/common/http/http_client.go +++ b/pkg/common/http/http_client.go @@ -66,12 +66,12 @@ func Post(ctx context.Context, url string, header map[string]string, data any, t jsonStr, err := json.Marshal(data) if err != nil { - return nil, err + return nil, errs.Wrap(err, "Post: JSON marshal failed") } req, err := http.NewRequestWithContext(ctx, http.MethodPost, url, bytes.NewBuffer(jsonStr)) if err != nil { - return nil, err + return nil, errs.Wrap(err, "Post: NewRequestWithContext failed") } if operationID, _ := ctx.Value(constant.OperationID).(string); operationID != "" { @@ -84,13 +84,13 @@ func Post(ctx context.Context, url string, header map[string]string, data any, t resp, err := client.Do(req) if err != nil { - return nil, err + return nil, errs.Wrap(err, "Post: client.Do failed") } defer resp.Body.Close() result, err := io.ReadAll(resp.Body) if err != nil { - return nil, err + return nil, errs.Wrap(err, "Post: ReadAll failed") } return result, nil @@ -102,7 +102,10 @@ func PostReturn(ctx context.Context, url string, header map[string]string, input return err } err = json.Unmarshal(b, output) - return err + if err != nil { + return errs.Wrap(err, "PostReturn: JSON unmarshal failed") + } + return nil } func callBackPostReturn(ctx context.Context, url, command string, input interface{}, output callbackstruct.CallbackResp, callbackConfig config.CallBackConfig) error { @@ -127,7 +130,6 @@ func callBackPostReturn(ctx context.Context, url, command string, input interfac } if err := output.Parse(); err != nil { log.ZWarn(ctx, "callback parse failed", err, "url", url, "input", input, "response", string(b)) - return err } log.ZInfo(ctx, "callback success", "url", url, "input", input, "response", string(b)) return nil diff --git a/pkg/common/kafka/consumer.go b/pkg/common/kafka/consumer.go index 98adfdcf19..d0e06d4823 100644 --- a/pkg/common/kafka/consumer.go +++ b/pkg/common/kafka/consumer.go @@ -17,9 +17,8 @@ package kafka import ( "sync" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" - "github.com/IBM/sarama" + "github.com/OpenIMSDK/tools/errs" ) type Consumer struct { @@ -30,28 +29,33 @@ type Consumer struct { Consumer sarama.Consumer } -func NewKafkaConsumer(addr []string, topic string) *Consumer { - p := Consumer{} - p.Topic = topic - p.addr = addr - consumerConfig := sarama.NewConfig() - if config.Config.Kafka.Username != "" && config.Config.Kafka.Password != "" { - consumerConfig.Net.SASL.Enable = true - consumerConfig.Net.SASL.User = config.Config.Kafka.Username - consumerConfig.Net.SASL.Password = config.Config.Kafka.Password +func NewKafkaConsumer(addr []string, topic string, kafkaConfig *sarama.Config) (*Consumer, error) { + p := Consumer{ + Topic: topic, + addr: addr, + } + + if kafkaConfig.Net.SASL.User != "" && kafkaConfig.Net.SASL.Password != "" { + kafkaConfig.Net.SASL.Enable = true + } + + err := SetupTLSConfig(kafkaConfig) + if err != nil { + return nil, err } - SetupTLSConfig(consumerConfig) - consumer, err := sarama.NewConsumer(p.addr, consumerConfig) + + consumer, err := sarama.NewConsumer(p.addr, kafkaConfig) if err != nil { - panic(err.Error()) + return nil, errs.Wrap(err, "NewKafkaConsumer: creating consumer failed") } p.Consumer = consumer partitionList, err := consumer.Partitions(p.Topic) if err != nil { - panic(err.Error()) + return nil, errs.Wrap(err, "NewKafkaConsumer: getting partitions failed") } p.PartitionList = partitionList - return &p + return &p, nil + } diff --git a/pkg/common/kafka/producer.go b/pkg/common/kafka/producer.go index bdb8394048..4b5ce6b525 100644 --- a/pkg/common/kafka/producer.go +++ b/pkg/common/kafka/producer.go @@ -90,11 +90,10 @@ func NewKafkaProducer(addr []string, topic string) (*Producer, error) { for i := 0; i <= maxRetry; i++ { p.producer, err = sarama.NewSyncProducer(p.addr, p.config) if err == nil { - return &p, nil + return &p, errs.Wrap(err) } time.Sleep(1 * time.Second) // Wait before retrying } - // Panic if unable to create producer after retries if err != nil { return nil, errs.Wrap(errors.New("failed to create Kafka producer: " + err.Error())) @@ -179,7 +178,7 @@ func (p *Producer) SendMessage(ctx context.Context, key string, msg proto.Messag // Attach context metadata as headers header, err := GetMQHeaderWithContext(ctx) if err != nil { - return 0, 0, errs.Wrap(err) + return 0, 0, err } kMsg.Headers = header diff --git a/pkg/common/kafka/util.go b/pkg/common/kafka/util.go index f318ecf732..578a308efc 100644 --- a/pkg/common/kafka/util.go +++ b/pkg/common/kafka/util.go @@ -26,16 +26,21 @@ import ( ) // SetupTLSConfig set up the TLS config from config file. -func SetupTLSConfig(cfg *sarama.Config) { +func SetupTLSConfig(cfg *sarama.Config) error { if config.Config.Kafka.TLS != nil { cfg.Net.TLS.Enable = true - cfg.Net.TLS.Config = tls.NewTLSConfig( + tlsConfig, err := tls.NewTLSConfig( config.Config.Kafka.TLS.ClientCrt, config.Config.Kafka.TLS.ClientKey, config.Config.Kafka.TLS.CACrt, []byte(config.Config.Kafka.TLS.ClientKeyPwd), ) + if err != nil { + return err + } + cfg.Net.TLS.Config = tlsConfig } + return nil } // getEnvOrConfig returns the value of the environment variable if it exists, diff --git a/pkg/common/prommetrics/prommetrics.go b/pkg/common/prommetrics/prommetrics.go index b7c5e07f47..1ed13a1ef3 100644 --- a/pkg/common/prommetrics/prommetrics.go +++ b/pkg/common/prommetrics/prommetrics.go @@ -24,7 +24,6 @@ import ( ) func NewGrpcPromObj(cusMetrics []prometheus.Collector) (*prometheus.Registry, *gp.ServerMetrics, error) { - //////////////////////////////////////////////////////// reg := prometheus.NewRegistry() grpcMetrics := gp.NewServerMetrics() grpcMetrics.EnableHandlingTimeHistogram() diff --git a/pkg/common/startrpc/start.go b/pkg/common/startrpc/start.go index be9fbd25bf..e19456d860 100644 --- a/pkg/common/startrpc/start.go +++ b/pkg/common/startrpc/start.go @@ -70,7 +70,7 @@ func Start( defer listener.Close() client, err := kdisc.NewDiscoveryRegister(config.Config.Envs.Discovery) if err != nil { - return errs.Wrap(err) + return err } defer client.Close() diff --git a/pkg/common/tls/tls.go b/pkg/common/tls/tls.go old mode 100755 new mode 100644 index dba49e605b..e897c13b67 --- a/pkg/common/tls/tls.go +++ b/pkg/common/tls/tls.go @@ -21,6 +21,8 @@ import ( "errors" "os" + "github.com/OpenIMSDK/tools/errs" + "github.com/openimsdk/open-im-server/v3/pkg/common/config" ) @@ -49,37 +51,41 @@ func readEncryptablePEMBlock(path string, pwd []byte) ([]byte, error) { } // NewTLSConfig setup the TLS config from general config file. -func NewTLSConfig(clientCertFile, clientKeyFile, caCertFile string, keyPwd []byte) *tls.Config { - tlsConfig := tls.Config{} +func NewTLSConfig(clientCertFile, clientKeyFile, caCertFile string, keyPwd []byte) (*tls.Config, error) { + var tlsConfig tls.Config if clientCertFile != "" && clientKeyFile != "" { certPEMBlock, err := os.ReadFile(clientCertFile) if err != nil { - panic(err) + return nil, errs.Wrap(err, "NewTLSConfig: failed to read client cert file") } + keyPEMBlock, err := readEncryptablePEMBlock(clientKeyFile, keyPwd) if err != nil { - panic(err) + return nil, err } + cert, err := tls.X509KeyPair(certPEMBlock, keyPEMBlock) if err != nil { - panic(err) + return nil, errs.Wrap(err, "NewTLSConfig: failed to create X509 key pair") } tlsConfig.Certificates = []tls.Certificate{cert} } - caCert, err := os.ReadFile(caCertFile) - if err != nil { - panic(err) - } - caCertPool := x509.NewCertPool() - ok := caCertPool.AppendCertsFromPEM(caCert) - if !ok { - panic(errors.New("not a valid CA cert")) + if caCertFile != "" { + caCert, err := os.ReadFile(caCertFile) + if err != nil { + return nil, errs.Wrap(err, "NewTLSConfig: failed to read CA cert file") + } + + caCertPool := x509.NewCertPool() + if ok := caCertPool.AppendCertsFromPEM(caCert); !ok { + return nil, errors.New("NewTLSConfig: not a valid CA cert") + } + tlsConfig.RootCAs = caCertPool } - tlsConfig.RootCAs = caCertPool tlsConfig.InsecureSkipVerify = config.Config.Kafka.TLS.InsecureSkipVerify - return &tlsConfig + return &tlsConfig, nil } diff --git a/pkg/msgprocessor/conversation.go b/pkg/msgprocessor/conversation.go index 7477bea7a6..e3ea89fadd 100644 --- a/pkg/msgprocessor/conversation.go +++ b/pkg/msgprocessor/conversation.go @@ -20,6 +20,7 @@ import ( "github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/protocol/sdkws" + "github.com/OpenIMSDK/tools/errs" "google.golang.org/protobuf/proto" ) @@ -188,7 +189,7 @@ func (s MsgBySeq) Swap(i, j int) { func Pb2String(pb proto.Message) (string, error) { s, err := proto.Marshal(pb) if err != nil { - return "", err + return "", errs.Wrap(err) } return string(s), nil } diff --git a/pkg/rpcclient/auth.go b/pkg/rpcclient/auth.go index 0ee021de1b..810b7ae935 100644 --- a/pkg/rpcclient/auth.go +++ b/pkg/rpcclient/auth.go @@ -23,12 +23,13 @@ import ( "github.com/OpenIMSDK/tools/discoveryregistry" "github.com/openimsdk/open-im-server/v3/pkg/common/config" + util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" ) func NewAuth(discov discoveryregistry.SvcDiscoveryRegistry) *Auth { conn, err := discov.GetConn(context.Background(), config.Config.RpcRegisterName.OpenImAuthName) if err != nil { - panic(err) + util.ExitWithError(err) } client := auth.NewAuthClient(conn) return &Auth{discov: discov, conn: conn, Client: client} diff --git a/pkg/rpcclient/conversation.go b/pkg/rpcclient/conversation.go index 3ba8dd8c0f..9afa45004a 100644 --- a/pkg/rpcclient/conversation.go +++ b/pkg/rpcclient/conversation.go @@ -24,6 +24,8 @@ import ( "github.com/OpenIMSDK/tools/discoveryregistry" "github.com/OpenIMSDK/tools/errs" + util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" + "github.com/openimsdk/open-im-server/v3/pkg/common/config" ) @@ -36,7 +38,7 @@ type Conversation struct { func NewConversation(discov discoveryregistry.SvcDiscoveryRegistry) *Conversation { conn, err := discov.GetConn(context.Background(), config.Config.RpcRegisterName.OpenImConversationName) if err != nil { - panic(err) + util.ExitWithError(err) } client := pbconversation.NewConversationClient(conn) return &Conversation{discov: discov, conn: conn, Client: client} @@ -114,11 +116,7 @@ func (c *ConversationRpcClient) GetConversationsByConversationID(ctx context.Con return resp.Conversations, nil } -func (c *ConversationRpcClient) GetConversations( - ctx context.Context, - ownerUserID string, - conversationIDs []string, -) ([]*pbconversation.Conversation, error) { +func (c *ConversationRpcClient) GetConversations(ctx context.Context, ownerUserID string, conversationIDs []string) ([]*pbconversation.Conversation, error) { if len(conversationIDs) == 0 { return nil, nil } diff --git a/pkg/rpcclient/friend.go b/pkg/rpcclient/friend.go index b84db40d4d..39026b10c1 100644 --- a/pkg/rpcclient/friend.go +++ b/pkg/rpcclient/friend.go @@ -24,6 +24,7 @@ import ( "github.com/OpenIMSDK/tools/discoveryregistry" "github.com/openimsdk/open-im-server/v3/pkg/common/config" + util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" ) type Friend struct { @@ -35,7 +36,7 @@ type Friend struct { func NewFriend(discov discoveryregistry.SvcDiscoveryRegistry) *Friend { conn, err := discov.GetConn(context.Background(), config.Config.RpcRegisterName.OpenImFriendName) if err != nil { - panic(err) + util.ExitWithError(err) } client := friend.NewFriendClient(conn) return &Friend{discov: discov, conn: conn, Client: client} @@ -62,7 +63,7 @@ func (f *FriendRpcClient) GetFriendsInfo( return } -// possibleFriendUserID是否在userID的好友中. +// possibleFriendUserID Is PossibleFriendUserId's friends. func (f *FriendRpcClient) IsFriend(ctx context.Context, possibleFriendUserID, userID string) (bool, error) { resp, err := f.Client.IsFriend(ctx, &friend.IsFriendReq{UserID1: userID, UserID2: possibleFriendUserID}) if err != nil { diff --git a/pkg/rpcclient/group.go b/pkg/rpcclient/group.go index bf0efe60ca..cb61579be1 100644 --- a/pkg/rpcclient/group.go +++ b/pkg/rpcclient/group.go @@ -28,6 +28,7 @@ import ( "github.com/OpenIMSDK/tools/utils" "github.com/openimsdk/open-im-server/v3/pkg/common/config" + util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" ) type Group struct { @@ -39,7 +40,7 @@ type Group struct { func NewGroup(discov discoveryregistry.SvcDiscoveryRegistry) *Group { conn, err := discov.GetConn(context.Background(), config.Config.RpcRegisterName.OpenImGroupName) if err != nil { - panic(err) + util.ExitWithError(err) } client := group.NewGroupClient(conn) return &Group{discov: discov, conn: conn, Client: client} diff --git a/pkg/rpcclient/msg.go b/pkg/rpcclient/msg.go index 56167d7f44..6804e78a2e 100644 --- a/pkg/rpcclient/msg.go +++ b/pkg/rpcclient/msg.go @@ -147,14 +147,24 @@ func NewMessageRpcClient(discov discoveryregistry.SvcDiscoveryRegistry) MessageR return MessageRpcClient(*NewMessage(discov)) } +// SendMsg sends a message through the gRPC client and returns the response. +// It wraps any encountered error for better error handling and context understanding. func (m *MessageRpcClient) SendMsg(ctx context.Context, req *msg.SendMsgReq) (*msg.SendMsgResp, error) { resp, err := m.Client.SendMsg(ctx, req) - return resp, err + if err != nil { + return nil, err + } + return resp, nil } +// GetMaxSeq retrieves the maximum sequence number from the gRPC client. +// Errors during the gRPC call are wrapped to provide additional context. func (m *MessageRpcClient) GetMaxSeq(ctx context.Context, req *sdkws.GetMaxSeqReq) (*sdkws.GetMaxSeqResp, error) { resp, err := m.Client.GetMaxSeq(ctx, req) - return resp, err + if err != nil { + return nil, err + } + return resp, nil } func (m *MessageRpcClient) GetMaxSeqs(ctx context.Context, conversationIDs []string) (map[string]int64, error) { @@ -181,9 +191,15 @@ func (m *MessageRpcClient) GetMsgByConversationIDs(ctx context.Context, docIDs [ return resp.MsgDatas, err } +// PullMessageBySeqList retrieves messages by their sequence numbers using the gRPC client. +// It directly forwards the request to the gRPC client and returns the response along with any error encountered. func (m *MessageRpcClient) PullMessageBySeqList(ctx context.Context, req *sdkws.PullMessageBySeqsReq) (*sdkws.PullMessageBySeqsResp, error) { resp, err := m.Client.PullMessageBySeqs(ctx, req) - return resp, err + if err != nil { + // Wrap the error to provide more context if the gRPC call fails. + return nil, err + } + return resp, nil } func (m *MessageRpcClient) GetConversationMaxSeq(ctx context.Context, conversationID string) (int64, error) { diff --git a/pkg/rpcclient/notification/conversation.go b/pkg/rpcclient/notification/conversation.go index 0fefb147e4..3bbad746e0 100644 --- a/pkg/rpcclient/notification/conversation.go +++ b/pkg/rpcclient/notification/conversation.go @@ -31,7 +31,7 @@ func NewConversationNotificationSender(msgRpcClient *rpcclient.MessageRpcClient) return &ConversationNotificationSender{rpcclient.NewNotificationSender(rpcclient.WithRpcClient(msgRpcClient))} } -// SetPrivate调用. +// SetPrivate invote. func (c *ConversationNotificationSender) ConversationSetPrivateNotification(ctx context.Context, sendID, recvID string, isPrivateChat bool, conversationID string, ) error { @@ -45,7 +45,6 @@ func (c *ConversationNotificationSender) ConversationSetPrivateNotification(ctx return c.Notification(ctx, sendID, recvID, constant.ConversationPrivateChatNotification, tips) } -// 会话改变. func (c *ConversationNotificationSender) ConversationChangeNotification(ctx context.Context, userID string, conversationIDs []string) error { tips := &sdkws.ConversationUpdateTips{ UserID: userID, @@ -55,7 +54,6 @@ func (c *ConversationNotificationSender) ConversationChangeNotification(ctx cont return c.Notification(ctx, userID, userID, constant.ConversationChangeNotification, tips) } -// 会话未读数同步. func (c *ConversationNotificationSender) ConversationUnreadChangeNotification( ctx context.Context, userID, conversationID string, diff --git a/pkg/rpcclient/notification/friend.go b/pkg/rpcclient/notification/friend.go index a55bc0e5ef..a6b6937249 100644 --- a/pkg/rpcclient/notification/friend.go +++ b/pkg/rpcclient/notification/friend.go @@ -31,7 +31,7 @@ import ( type FriendNotificationSender struct { *rpcclient.NotificationSender - // 找不到报错 + // Target not found err getUsersInfo func(ctx context.Context, userIDs []string) ([]CommonUser, error) // db controller db controller.FriendDatabase diff --git a/pkg/rpcclient/push.go b/pkg/rpcclient/push.go index 6d08769728..b5a5c49cfd 100644 --- a/pkg/rpcclient/push.go +++ b/pkg/rpcclient/push.go @@ -23,6 +23,7 @@ import ( "github.com/OpenIMSDK/tools/discoveryregistry" "github.com/openimsdk/open-im-server/v3/pkg/common/config" + util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" ) type Push struct { @@ -34,7 +35,7 @@ type Push struct { func NewPush(discov discoveryregistry.SvcDiscoveryRegistry) *Push { conn, err := discov.GetConn(context.Background(), config.Config.RpcRegisterName.OpenImPushName) if err != nil { - panic(err) + util.ExitWithError(err) } return &Push{ discov: discov, @@ -49,9 +50,6 @@ func NewPushRpcClient(discov discoveryregistry.SvcDiscoveryRegistry) PushRpcClie return PushRpcClient(*NewPush(discov)) } -func (p *PushRpcClient) DelUserPushToken( - ctx context.Context, - req *push.DelUserPushTokenReq, -) (*push.DelUserPushTokenResp, error) { +func (p *PushRpcClient) DelUserPushToken(ctx context.Context, req *push.DelUserPushTokenReq) (*push.DelUserPushTokenResp, error) { return p.Client.DelUserPushToken(ctx, req) } diff --git a/pkg/rpcclient/third.go b/pkg/rpcclient/third.go index b3557bf836..05b825060d 100755 --- a/pkg/rpcclient/third.go +++ b/pkg/rpcclient/third.go @@ -24,8 +24,10 @@ import ( "github.com/OpenIMSDK/protocol/third" "github.com/OpenIMSDK/tools/discoveryregistry" + "github.com/OpenIMSDK/tools/errs" "github.com/openimsdk/open-im-server/v3/pkg/common/config" + util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" ) type Third struct { @@ -38,35 +40,42 @@ type Third struct { func NewThird(discov discoveryregistry.SvcDiscoveryRegistry) *Third { conn, err := discov.GetConn(context.Background(), config.Config.RpcRegisterName.OpenImThirdName) if err != nil { - panic(err) + util.ExitWithError(err) } client := third.NewThirdClient(conn) minioClient, err := minioInit() if err != nil { - panic(err) + util.ExitWithError(err) } return &Third{discov: discov, Client: client, conn: conn, MinioClient: minioClient} } func minioInit() (*minio.Client, error) { - minioClient := &minio.Client{} - initUrl := config.Config.Object.Minio.Endpoint - minioUrl, err := url.Parse(initUrl) + // Retrieve MinIO configuration details + endpoint := config.Config.Object.Minio.Endpoint + accessKeyID := config.Config.Object.Minio.AccessKeyID + secretAccessKey := config.Config.Object.Minio.SecretAccessKey + + // Parse the MinIO URL to determine if the connection should be secure + minioURL, err := url.Parse(endpoint) if err != nil { - return nil, err + return nil, errs.Wrap(err, "minioInit: failed to parse MinIO endpoint URL") } + + // Determine the security of the connection based on the scheme + secure := minioURL.Scheme == "https" + + // Setup MinIO client options opts := &minio.Options{ - Creds: credentials.NewStaticV4(config.Config.Object.Minio.AccessKeyID, config.Config.Object.Minio.SecretAccessKey, ""), - // Region: config.Config.Credential.Minio.Location, + Creds: credentials.NewStaticV4(accessKeyID, secretAccessKey, ""), + Secure: secure, } - if minioUrl.Scheme == "http" { - opts.Secure = false - } else if minioUrl.Scheme == "https" { - opts.Secure = true - } - minioClient, err = minio.New(minioUrl.Host, opts) + + // Initialize MinIO client + minioClient, err := minio.New(minioURL.Host, opts) if err != nil { - return nil, err + return nil, errs.Wrap(err, "minioInit: failed to create MinIO client") } + return minioClient, nil } diff --git a/pkg/rpcclient/user.go b/pkg/rpcclient/user.go index 451914cd31..810a88ad0f 100644 --- a/pkg/rpcclient/user.go +++ b/pkg/rpcclient/user.go @@ -19,6 +19,7 @@ import ( "strings" "github.com/openimsdk/open-im-server/v3/pkg/authverify" + util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" "google.golang.org/grpc" @@ -42,7 +43,7 @@ type User struct { func NewUser(discov discoveryregistry.SvcDiscoveryRegistry) *User { conn, err := discov.GetConn(context.Background(), config.Config.RpcRegisterName.OpenImUserName) if err != nil { - panic(err) + util.ExitWithError(err) } client := user.NewUserClient(conn) return &User{Discov: discov, Client: client, conn: conn} diff --git a/pkg/util/genutil/genutil.go b/pkg/util/genutil/genutil.go index bd9376d583..95735485d5 100644 --- a/pkg/util/genutil/genutil.go +++ b/pkg/util/genutil/genutil.go @@ -18,6 +18,8 @@ import ( "fmt" "os" "path/filepath" + + "github.com/OpenIMSDK/tools/errs" ) // OutDir creates the absolute path name from path and checks path exists. @@ -25,16 +27,16 @@ import ( func OutDir(path string) (string, error) { outDir, err := filepath.Abs(path) if err != nil { - return "", err + return "", errs.Wrap(err, "output directory %s does not exist", path) } stat, err := os.Stat(outDir) if err != nil { - return "", err + return "", errs.Wrap(err, "output directory %s does not exist", outDir) } if !stat.IsDir() { - return "", fmt.Errorf("output directory %s is not a directory", outDir) + return "", errs.Wrap(err, "output directory %s is not a directory", outDir) } outDir += "/" return outDir, nil diff --git a/scripts/install/openim-tools.sh b/scripts/install/openim-tools.sh index 72005ed8e4..d8c27e9858 100755 --- a/scripts/install/openim-tools.sh +++ b/scripts/install/openim-tools.sh @@ -103,14 +103,14 @@ function openim::tools::start_service() { printf "Specifying prometheus port: %s\n" "${prometheus_port}" cmd="${cmd} --prometheus_port ${prometheus_port}" fi - openim::log::status "Starting ${binary_name}..." + openim::log::status "Starting binary ${binary_name}..." ${cmd} | tee -a "${LOG_FILE}" } function openim::tools::start() { openim::log::info "Starting OpenIM Tools..." for tool in "${OPENIM_TOOLS_NAME_LISTARIES[@]}"; do - openim::log::info "Starting ${tool}..." + openim::log::info "Starting tool ${tool}..." # openim::tools::start_service ${tool} sleep 0.2 done @@ -120,7 +120,7 @@ function openim::tools::start() { function openim::tools::pre-start() { openim::log::info "Preparing to start OpenIM Tools..." for tool in "${OPENIM_TOOLS_PRE_START_NAME_LISTARIES[@]}"; do - openim::log::info "Starting ${tool}..." + openim::log::info "Starting tool ${tool}..." openim::tools::start_service ${tool} ${OPNEIM_CONFIG} done } @@ -128,7 +128,7 @@ function openim::tools::pre-start() { function openim::tools::post-start() { openim::log::info "Post-start actions for OpenIM Tools..." for tool in "${OPENIM_TOOLS_POST_START_NAME_LISTARIES[@]}"; do - openim::log::info "Starting ${tool}..." + openim::log::info "Starting tool ${tool}..." openim::tools::start_service ${tool} done } diff --git a/scripts/make-rules/golang.mk b/scripts/make-rules/golang.mk index 915639b61c..5a5d1a7885 100644 --- a/scripts/make-rules/golang.mk +++ b/scripts/make-rules/golang.mk @@ -17,7 +17,7 @@ # GO := go -GO_SUPPORTED_VERSIONS ?= 1.19|1.20|1.21|1.22 +GO_SUPPORTED_VERSIONS ?= 1.19|1.20|1.21|1.22|1.23 GO_LDFLAGS += -X $(VERSION_PACKAGE).gitVersion=$(GIT_TAG) \ -X $(VERSION_PACKAGE).gitCommit=$(GIT_COMMIT) \ diff --git a/test/codescan/main.go b/test/codescan/main.go new file mode 100644 index 0000000000..06ab7d0f9a --- /dev/null +++ b/test/codescan/main.go @@ -0,0 +1 @@ +package main diff --git a/test/e2e/README.md b/test/e2e/README.md index 1e73dbaecf..49215e811b 100644 --- a/test/e2e/README.md +++ b/test/e2e/README.md @@ -128,6 +128,8 @@ Open issue: https://github.com/openimsdk/open-im-server/issues/new/choose, choos The E2E test suite is integrated with CI, which runs the tests automatically on each code commit. The results are reported back to the pull request or commit to provide immediate feedback on the impact of the changes. +[![OpenIM Linux System E2E Test](https://github.com/openimsdk/open-im-server/actions/workflows/e2e-test.yml/badge.svg)](https://github.com/openimsdk/open-im-server/actions/workflows/e2e-test.yml) + ## Contact diff --git a/test/e2e/api/token/token.go b/test/e2e/api/token/token.go index 88af72058b..b4dbda330c 100644 --- a/test/e2e/api/token/token.go +++ b/test/e2e/api/token/token.go @@ -19,7 +19,6 @@ import ( "encoding/json" "fmt" "io" - "log" "net/http" ) @@ -58,20 +57,6 @@ type UserRegisterRequest struct { Users []User `json:"users"` } -func main() { - // Example usage of functions - token, err := GetUserToken("openIM123456") - if err != nil { - log.Fatalf("Error getting user token: %v", err) - } - fmt.Println("Token:", token) - - err = RegisterUser(token, "testUserID", "TestNickname", "https://example.com/image.jpg") - if err != nil { - log.Fatalf("Error registering user: %v", err) - } -} - // GetUserToken requests a user token from the API. func GetUserToken(userID string) (string, error) { reqBody := UserTokenRequest{ diff --git a/test/e2e/framework/config/config_test.go b/test/e2e/framework/config/config_test.go index b7259bf37b..66f845db3b 100644 --- a/test/e2e/framework/config/config_test.go +++ b/test/e2e/framework/config/config_test.go @@ -76,7 +76,7 @@ func TestCopyFlags(t *testing.T) { }() CopyFlags(tt.args.source, tt.args.target) - // 验证复制的标记 + // Verify the replicated tag if !tt.wantErr { tt.args.source.VisitAll(func(f *flag.Flag) { if gotFlag := tt.args.target.Lookup(f.Name); gotFlag == nil || !reflect.DeepEqual(gotFlag, f) { diff --git a/test/e2e/framework/helpers/chat/chat.go b/test/e2e/framework/helpers/chat/chat.go index a4ead528bb..82dcc1aabf 100644 --- a/test/e2e/framework/helpers/chat/chat.go +++ b/test/e2e/framework/helpers/chat/chat.go @@ -38,6 +38,9 @@ func main() { // } latestVersion := defaultTemplateVersion + // getLatestVersion + // getLatestVersion + // Construct the download URL downloadURL := fmt.Sprintf("https://github.com/openimsdk/chat/releases/download/%s/chat_Linux_x86_64.tar.gz", latestVersion) @@ -98,23 +101,23 @@ func main() { select {} } -// getLatestVersion fetches the latest version number from a given URL. -func getLatestVersion(url string) (string, error) { - resp, err := http.Get(url) - if err != nil { - return "", err - } - defer resp.Body.Close() - - location := resp.Header.Get("Location") - if location == "" { - return defaultTemplateVersion, nil - } - - // Extract the version number from the URL - latestVersion := filepath.Base(location) - return latestVersion, nil -} +// // getLatestVersion fetches the latest version number from a given URL. +// func getLatestVersion(url string) (string, error) { +// resp, err := http.Get(url) +// if err != nil { +// return "", err +// } +// defer resp.Body.Close() + +// location := resp.Header.Get("Location") +// if location == "" { +// return defaultTemplateVersion, nil +// } + +// // Extract the version number from the URL +// latestVersion := filepath.Base(location) +// return latestVersion, nil +// } // downloadAndExtract downloads a file from a URL and extracts it to a destination directory. func downloadAndExtract(url, destDir string) error { diff --git a/test/e2e/page/chat_page.go b/test/e2e/page/chat_page.go new file mode 100644 index 0000000000..52aa8377d3 --- /dev/null +++ b/test/e2e/page/chat_page.go @@ -0,0 +1 @@ +package page diff --git a/test/e2e/page/login_page.go b/test/e2e/page/login_page.go new file mode 100644 index 0000000000..52aa8377d3 --- /dev/null +++ b/test/e2e/page/login_page.go @@ -0,0 +1 @@ +package page diff --git a/test/e2e/web/.keep b/test/e2e/web/.keep deleted file mode 100644 index 4f07f1caf6..0000000000 --- a/test/e2e/web/.keep +++ /dev/null @@ -1 +0,0 @@ -.keep \ No newline at end of file diff --git a/test/e2e/web/Readme.md b/test/e2e/web/Readme.md new file mode 100644 index 0000000000..741ca51d5e --- /dev/null +++ b/test/e2e/web/Readme.md @@ -0,0 +1,2 @@ +# OpenIM Web E2E + diff --git a/tools/data-conversion/chat/cmd/conversion-chat/chat.go b/tools/data-conversion/chat/cmd/conversion-chat/chat.go index 0fc49c7821..f68b71b16b 100644 --- a/tools/data-conversion/chat/cmd/conversion-chat/chat.go +++ b/tools/data-conversion/chat/cmd/conversion-chat/chat.go @@ -28,20 +28,20 @@ import ( func main() { var ( - usernameV2 = "root" // v2版本mysql用户名 - passwordV2 = "openIM" // v2版本mysql密码 - addrV2 = "127.0.0.1:13306" // v2版本mysql地址 - databaseV2 = "admin_chat" // v2版本mysql数据库名字 + usernameV2 = "root" // Username for MySQL v2 version + passwordV2 = "openIM" // Password for MySQL v2 version + addrV2 = "127.0.0.1:13306" // Address for MySQL v2 version + databaseV2 = "admin_chat" // Database name for MySQL v2 version ) var ( - usernameV3 = "root" // v3版本mysql用户名 - passwordV3 = "openIM123" // v3版本mysql密码 - addrV3 = "127.0.0.1:13306" // v3版本mysql地址 - databaseV3 = "openim_enterprise" // v3版本mysql数据库名字 + usernameV3 = "root" // Username for MySQL v3 version + passwordV3 = "openIM123" // Password for MySQL v3 version + addrV3 = "127.0.0.1:13306" // Address for MySQL v3 version + databaseV3 = "openim_enterprise" // Database name for MySQL v3 version ) - var concurrency = 1 // 并发数量 + var concurrency = 1 // Concurrency quantity log.SetFlags(log.LstdFlags | log.Llongfile) dsnV2 := fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=utf8mb4&parseTime=True&loc=Local", usernameV2, passwordV2, addrV2, databaseV2) diff --git a/tools/data-conversion/chat/v2/admin.go b/tools/data-conversion/chat/v2/admin.go index fec11ff5b1..20cf22a366 100644 --- a/tools/data-conversion/chat/v2/admin.go +++ b/tools/data-conversion/chat/v2/admin.go @@ -18,7 +18,7 @@ import ( "time" ) -// AppVersion pc端版本管理 +// AppVersion manages PC client versions type AppVersion struct { Version string `gorm:"column:version;size:64" json:"version"` Type int `gorm:"column:type;primary_key" json:"type"` @@ -29,7 +29,7 @@ type AppVersion struct { UpdateLog string `gorm:"column:update_log" json:"update_log"` } -// Admin 后台管理员 +// Admin manages backend administrators type Admin struct { Account string `gorm:"column:account;primary_key;type:char(64)" json:"account"` Password string `gorm:"column:Password;type:char(64)" json:"password"` @@ -40,19 +40,19 @@ type Admin struct { CreateTime time.Time `gorm:"column:create_time" json:"createTime"` } -// RegisterAddFriend 注册时默认好友 +// RegisterAddFriend specifies default friends when registering type RegisterAddFriend struct { UserID string `gorm:"column:user_id;primary_key;type:char(64)" json:"userID"` CreateTime time.Time `gorm:"column:create_time" json:"createTime"` } -// RegisterAddGroup 注册时默认群组 +// RegisterAddGroup specifies default groups when registering type RegisterAddGroup struct { GroupID string `gorm:"column:group_id;primary_key;type:char(64)" json:"userID"` CreateTime time.Time `gorm:"column:create_time" json:"createTime"` } -// ClientInitConfig 系统相关配置项 +// ClientInitConfig contains system-related configuration items type ClientInitConfig struct { DiscoverPageURL string `gorm:"column:discover_page_url;size:128" json:"discoverPageURL"` OrdinaryUserAddFriend int32 `gorm:"column:ordinary_user_add_friend; default:1" json:"ordinaryUserAddFriend"` diff --git a/tools/data-conversion/chat/v2/chat.go b/tools/data-conversion/chat/v2/chat.go index 15cc4797fe..4e0a0c04a1 100644 --- a/tools/data-conversion/chat/v2/chat.go +++ b/tools/data-conversion/chat/v2/chat.go @@ -18,7 +18,7 @@ import ( "time" ) -// Register 注册信息表 +// Register Registration information sheet type Register struct { UserID string `gorm:"column:user_id;primary_key;type:char(64)" json:"userID"` DeviceID string `gorm:"column:device_id;type:varchar(255)" json:"deviceID"` @@ -29,7 +29,7 @@ type Register struct { CreateTime time.Time `gorm:"column:create_time" json:"createTime"` } -// Account 账号密码表 +// Account username and password table type Account struct { UserID string `gorm:"column:user_id;primary_key;type:char(64)" json:"userID"` Password string `gorm:"column:password;type:varchar(255)" json:"password"` @@ -38,7 +38,7 @@ type Account struct { OperatorUserID string `gorm:"column:operator_user_id;type:varchar(64)" json:"operatorUserID"` } -// Attribute 用户属性表 +// Attribute user information table type Attribute struct { UserID string `gorm:"column:user_id;primary_key;type:char(64)" json:"userID"` Account string `gorm:"column:account;type:char(64)" json:"account"` @@ -58,7 +58,7 @@ type Attribute struct { AllowAddFriend int32 `gorm:"column:allow_add_friend;default:1" json:"allowAddFriend"` } -// 封号表 +// User friend relationship table type ForbiddenAccount struct { UserID string `gorm:"column:user_id;index:userID;primary_key;type:char(64)" json:"userID"` CreateTime time.Time `gorm:"column:create_time" json:"createTime"` @@ -66,7 +66,7 @@ type ForbiddenAccount struct { OperatorUserID string `gorm:"column:operator_user_id;type:varchar(255)" json:"operatorUserID"` } -// 用户登录信息表 +// user login record table type UserLoginRecord struct { UserID string `gorm:"column:user_id;size:64" json:"userID"` LoginTime time.Time `gorm:"column:login_time" json:"loginTime"` @@ -75,7 +75,7 @@ type UserLoginRecord struct { Platform string `gorm:"column:platform;type:varchar(32)" json:"platform"` } -// 禁止ip登录 注册 +// ip login registration is prohibited type IPForbidden struct { IP string `gorm:"column:ip;primary_key;type:char(32)" json:"ip"` LimitRegister int32 `gorm:"column:limit_register" json:"limitRegister"` @@ -83,14 +83,14 @@ type IPForbidden struct { CreateTime time.Time `gorm:"column:create_time" json:"createTime"` } -// 限制userID只能在某些ip登录 +// Restrict userids to certain ip addresses type LimitUserLoginIP struct { UserID string `gorm:"column:user_id;primary_key;type:char(64)" json:"userID"` IP string `gorm:"column:ip;primary_key;type:char(32)" json:"ip"` CreateTime time.Time `gorm:"column:create_time" json:"createTime"` } -// 邀请码被注册使用 +// The invitation code is registered for use type InvitationRegister struct { InvitationCode string `gorm:"column:invitation_code;primary_key;type:char(32)" json:"invitationCode"` CreateTime time.Time `gorm:"column:create_time" json:"createTime"` diff --git a/tools/data-conversion/chat/v3/admin/admin.go b/tools/data-conversion/chat/v3/admin/admin.go index 22a81a0684..90bd7f8f76 100644 --- a/tools/data-conversion/chat/v3/admin/admin.go +++ b/tools/data-conversion/chat/v3/admin/admin.go @@ -18,7 +18,7 @@ import ( "time" ) -// Admin 后台管理员. +// Admin Background administrator. type Admin struct { Account string `gorm:"column:account;primary_key;type:varchar(64)"` Password string `gorm:"column:password;type:varchar(64)"` diff --git a/tools/data-conversion/chat/v3/admin/client_config.go b/tools/data-conversion/chat/v3/admin/client_config.go index ceccd51055..48869fceb4 100644 --- a/tools/data-conversion/chat/v3/admin/client_config.go +++ b/tools/data-conversion/chat/v3/admin/client_config.go @@ -14,7 +14,7 @@ package admin -// ClientConfig 客户端相关配置项. +// ClientConfig Client related configuration items. type ClientConfig struct { Key string `gorm:"column:key;primary_key;type:varchar(255)"` Value string `gorm:"column:value;not null;type:text"` diff --git a/tools/data-conversion/chat/v3/admin/forbidden_account.go b/tools/data-conversion/chat/v3/admin/forbidden_account.go index 104e793b07..e081256994 100644 --- a/tools/data-conversion/chat/v3/admin/forbidden_account.go +++ b/tools/data-conversion/chat/v3/admin/forbidden_account.go @@ -18,7 +18,7 @@ import ( "time" ) -// ForbiddenAccount 封号表. +// ForbiddenAccount forbidden account. type ForbiddenAccount struct { UserID string `gorm:"column:user_id;index:userID;primary_key;type:char(64)"` Reason string `gorm:"column:reason;type:varchar(255)" ` diff --git a/tools/data-conversion/chat/v3/admin/invitation_register.go b/tools/data-conversion/chat/v3/admin/invitation_register.go index 60f9067e2c..4b71ccfe04 100644 --- a/tools/data-conversion/chat/v3/admin/invitation_register.go +++ b/tools/data-conversion/chat/v3/admin/invitation_register.go @@ -18,7 +18,7 @@ import ( "time" ) -// 邀请码被注册使用. +// The invitation code is registered for use. type InvitationRegister struct { InvitationCode string `gorm:"column:invitation_code;primary_key;type:char(32)"` UsedByUserID string `gorm:"column:user_id;index:userID;type:char(64)"` diff --git a/tools/data-conversion/chat/v3/admin/ip_forbidden.go b/tools/data-conversion/chat/v3/admin/ip_forbidden.go index 40c9257efd..886924abb2 100644 --- a/tools/data-conversion/chat/v3/admin/ip_forbidden.go +++ b/tools/data-conversion/chat/v3/admin/ip_forbidden.go @@ -18,7 +18,7 @@ import ( "time" ) -// 禁止ip登录 注册. +// ip login registration is prohibited. type IPForbidden struct { IP string `gorm:"column:ip;primary_key;type:char(32)"` LimitRegister bool `gorm:"column:limit_register"` diff --git a/tools/data-conversion/chat/v3/admin/limit_user_login_ip.go b/tools/data-conversion/chat/v3/admin/limit_user_login_ip.go index 8427eaf80e..0eaa5bc1e7 100644 --- a/tools/data-conversion/chat/v3/admin/limit_user_login_ip.go +++ b/tools/data-conversion/chat/v3/admin/limit_user_login_ip.go @@ -18,7 +18,7 @@ import ( "time" ) -// 限制userID只能在某些ip登录. +// Restrict userids to certain ip addresses. type LimitUserLoginIP struct { UserID string `gorm:"column:user_id;primary_key;type:char(64)"` IP string `gorm:"column:ip;primary_key;type:char(32)"` diff --git a/tools/data-conversion/chat/v3/admin/register_add_friend.go b/tools/data-conversion/chat/v3/admin/register_add_friend.go index e21896d901..8281f64853 100644 --- a/tools/data-conversion/chat/v3/admin/register_add_friend.go +++ b/tools/data-conversion/chat/v3/admin/register_add_friend.go @@ -18,7 +18,7 @@ import ( "time" ) -// RegisterAddFriend 注册时默认好友. +// RegisterAddFriend Indicates the default friend when registering. type RegisterAddFriend struct { UserID string `gorm:"column:user_id;primary_key;type:char(64)"` CreateTime time.Time `gorm:"column:create_time"` diff --git a/tools/data-conversion/chat/v3/admin/register_add_group.go b/tools/data-conversion/chat/v3/admin/register_add_group.go index e9c1317b98..1204ff97bf 100644 --- a/tools/data-conversion/chat/v3/admin/register_add_group.go +++ b/tools/data-conversion/chat/v3/admin/register_add_group.go @@ -18,7 +18,7 @@ import ( "time" ) -// RegisterAddGroup 注册时默认群组. +// RegisterAddGroup Indicates the default group for registration. type RegisterAddGroup struct { GroupID string `gorm:"column:group_id;primary_key;type:char(64)"` CreateTime time.Time `gorm:"column:create_time"` diff --git a/tools/data-conversion/chat/v3/chat/account.go b/tools/data-conversion/chat/v3/chat/account.go index d2117e7ca7..6d01c20e24 100644 --- a/tools/data-conversion/chat/v3/chat/account.go +++ b/tools/data-conversion/chat/v3/chat/account.go @@ -18,7 +18,7 @@ import ( "time" ) -// Account 账号密码表. +// Account Account password table. type Account struct { UserID string `gorm:"column:user_id;primary_key;type:char(64)"` Password string `gorm:"column:password;type:varchar(32)"` diff --git a/tools/data-conversion/chat/v3/chat/attribute.go b/tools/data-conversion/chat/v3/chat/attribute.go index 6a6f975d1c..23de217bd3 100644 --- a/tools/data-conversion/chat/v3/chat/attribute.go +++ b/tools/data-conversion/chat/v3/chat/attribute.go @@ -18,7 +18,7 @@ import ( "time" ) -// Attribute 用户属性表. +// Attribute Indicates the user attribute table. type Attribute struct { UserID string `gorm:"column:user_id;primary_key;type:char(64)"` Account string `gorm:"column:account;type:char(64)"` diff --git a/tools/data-conversion/chat/v3/chat/register.go b/tools/data-conversion/chat/v3/chat/register.go index 7401594364..29e5cb698e 100644 --- a/tools/data-conversion/chat/v3/chat/register.go +++ b/tools/data-conversion/chat/v3/chat/register.go @@ -18,7 +18,7 @@ import ( "time" ) -// Register 注册信息表. +// Register Indicates the registration information. type Register struct { UserID string `gorm:"column:user_id;primary_key;type:char(64)"` DeviceID string `gorm:"column:device_id;type:varchar(255)"` diff --git a/tools/data-conversion/chat/v3/chat/user_login_record.go b/tools/data-conversion/chat/v3/chat/user_login_record.go index 8db3699d68..31e57b6ce6 100644 --- a/tools/data-conversion/chat/v3/chat/user_login_record.go +++ b/tools/data-conversion/chat/v3/chat/user_login_record.go @@ -18,7 +18,7 @@ import ( "time" ) -// 用户登录信息表. +// User login information table. type UserLoginRecord struct { UserID string `gorm:"column:user_id;size:64"` LoginTime time.Time `gorm:"column:login_time"` diff --git a/tools/data-conversion/openim/cmd/conversion-msg/conversion-msg.go b/tools/data-conversion/openim/cmd/conversion-msg/conversion-msg.go index f2b9623a6f..416fdcb9f8 100644 --- a/tools/data-conversion/openim/cmd/conversion-msg/conversion-msg.go +++ b/tools/data-conversion/openim/cmd/conversion-msg/conversion-msg.go @@ -38,11 +38,20 @@ import ( func main() { var ( - topic = "ws2ms_chat" // v2版本配置文件kafka.topic.ws2ms_chat - kafkaAddr = "127.0.0.1:9092" // v2版本配置文件kafka.topic.addr - rpcAddr = "127.0.0.1:10130" // v3版本配置文件rpcPort.openImMessagePort - adminUserID = "openIM123456" // v3版本管理员userID - concurrency = 1 // 并发数量 + // The Kafka topic for ws2ms_chat in version 2 configuration + topic = "ws2ms_chat" + + // The Kafka address in version 2 configuration + kafkaAddr = "127.0.0.1:9092" + + // The RPC address in version 3 configuration + rpcAddr = "127.0.0.1:10130" + + // The administrator userID in version 3 + adminUserID = "openIM123456" + + // The number of concurrent processes + concurrency = 1 ) getRpcConn := func() (*grpc.ClientConn, error) { @@ -99,7 +108,7 @@ func main() { ch := pc.Messages() for { select { - case <-time.After(time.Second * 10): // 10s读取不到就关闭 + case <-time.After(time.Second * 10): // 10s Shuts down when the data cannot be read return case message, ok := <-ch: if !ok { diff --git a/tools/data-conversion/openim/cmd/conversion-mysql/conversion-mysql.go b/tools/data-conversion/openim/cmd/conversion-mysql/conversion-mysql.go index 8a951e16f9..08fa4ca553 100644 --- a/tools/data-conversion/openim/cmd/conversion-mysql/conversion-mysql.go +++ b/tools/data-conversion/openim/cmd/conversion-mysql/conversion-mysql.go @@ -27,21 +27,37 @@ import ( ) func main() { + var ( - usernameV2 = "root" // v2版本mysql用户名 - passwordV2 = "openIM" // v2版本mysql密码 - addrV2 = "127.0.0.1:13306" // v2版本mysql地址 - databaseV2 = "openIM_v2" // v2版本mysql数据库名字 + // MySQL username for version 2 + usernameV2 = "root" + + // MySQL password for version 2 + passwordV2 = "openIM" + + // MySQL address for version 2 + addrV2 = "127.0.0.1:13306" + + // MySQL database name for version 2 + databaseV2 = "openIM_v2" ) var ( - usernameV3 = "root" // v3版本mysql用户名 - passwordV3 = "openIM123" // v3版本mysql密码 - addrV3 = "127.0.0.1:13306" // v3版本mysql地址 - databaseV3 = "openim_v3" // v3版本mysql数据库名字 + // MySQL username for version 3 + usernameV3 = "root" + + // MySQL password for version 3 + passwordV3 = "openIM123" + + // MySQL address for version 3 + addrV3 = "127.0.0.1:13306" + + // MySQL database name for version 3 + databaseV3 = "openim_v3" ) - var concurrency = 1 // 并发数量 + // The number of concurrent processes + var concurrency = 1 log.SetFlags(log.LstdFlags | log.Llongfile) dsnV2 := fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=utf8mb4&parseTime=True&loc=Local", usernameV2, passwordV2, addrV2, databaseV2) diff --git a/tools/data-conversion/openim/mysql/v3/friend.go b/tools/data-conversion/openim/mysql/v3/friend.go index 58d8d1d344..4f3fb6bdfc 100644 --- a/tools/data-conversion/openim/mysql/v3/friend.go +++ b/tools/data-conversion/openim/mysql/v3/friend.go @@ -38,41 +38,30 @@ func (FriendModel) TableName() string { } type FriendModelInterface interface { - // 插入多条记录 - Create(ctx context.Context, friends []*FriendModel) (err error) - // 删除ownerUserID指定的好友 - Delete(ctx context.Context, ownerUserID string, friendUserIDs []string) (err error) - // 更新ownerUserID单个好友信息 更新零值 - UpdateByMap(ctx context.Context, ownerUserID string, friendUserID string, args map[string]interface{}) (err error) - // 更新好友信息的非零值 - Update(ctx context.Context, friends []*FriendModel) (err error) - // 更新好友备注(也支持零值 ) - UpdateRemark(ctx context.Context, ownerUserID, friendUserID, remark string) (err error) - // 获取单个好友信息,如没找到 返回错误 - Take(ctx context.Context, ownerUserID, friendUserID string) (friend *FriendModel, err error) - // 查找好友关系,如果是双向关系,则都返回 - FindUserState(ctx context.Context, userID1, userID2 string) (friends []*FriendModel, err error) - // 获取 owner指定的好友列表 如果有friendUserIDs不存在,也不返回错误 - FindFriends(ctx context.Context, ownerUserID string, friendUserIDs []string) (friends []*FriendModel, err error) - // 获取哪些人添加了friendUserID 如果有ownerUserIDs不存在,也不返回错误 - FindReversalFriends( - ctx context.Context, - friendUserID string, - ownerUserIDs []string, - ) (friends []*FriendModel, err error) - // 获取ownerUserID好友列表 支持翻页 - FindOwnerFriends( - ctx context.Context, - ownerUserID string, - pageNumber, showNumber int32, - ) (friends []*FriendModel, total int64, err error) - // 获取哪些人添加了friendUserID 支持翻页 - FindInWhoseFriends( - ctx context.Context, - friendUserID string, - pageNumber, showNumber int32, - ) (friends []*FriendModel, total int64, err error) - // 获取好友UserID列表 - FindFriendUserIDs(ctx context.Context, ownerUserID string) (friendUserIDs []string, err error) + // Create inserts multiple friend records. + Create(ctx context.Context, friends []*FriendModel) error + // Delete removes specified friends for an owner user. + Delete(ctx context.Context, ownerUserID string, friendUserIDs []string) error + // UpdateByMap updates a single friend's information for an owner user based on a map of arguments. Zero values are updated. + UpdateByMap(ctx context.Context, ownerUserID string, friendUserID string, args map[string]interface{}) error + // Update modifies the information of friends, excluding zero values. + Update(ctx context.Context, friends []*FriendModel) error + // UpdateRemark updates the remark for a friend, supporting zero values. + UpdateRemark(ctx context.Context, ownerUserID, friendUserID, remark string) error + // Take retrieves a single friend's information. Returns an error if not found. + Take(ctx context.Context, ownerUserID, friendUserID string) (*FriendModel, error) + // FindUserState finds the friendship status between two users, returning both if a mutual friendship exists. + FindUserState(ctx context.Context, userID1, userID2 string) ([]*FriendModel, error) + // FindFriends retrieves a list of friends for an owner, not returning an error for non-existent friendUserIDs. + FindFriends(ctx context.Context, ownerUserID string, friendUserIDs []string) ([]*FriendModel, error) + // FindReversalFriends finds who has added the specified user as a friend, not returning an error for non-existent ownerUserIDs. + FindReversalFriends(ctx context.Context, friendUserID string, ownerUserIDs []string) ([]*FriendModel, error) + // FindOwnerFriends paginates through the friends list of an owner user. + FindOwnerFriends(ctx context.Context, ownerUserID string, pageNumber, showNumber int32) ([]*FriendModel, int64, error) + // FindInWhoseFriends paginates through users who have added the specified user as a friend. + FindInWhoseFriends(ctx context.Context, friendUserID string, pageNumber, showNumber int32) ([]*FriendModel, int64, error) + // FindFriendUserIDs retrieves a list of friend user IDs for an owner user. + FindFriendUserIDs(ctx context.Context, ownerUserID string) ([]string, error) + // NewTx creates a new transactional instance of the FriendModelInterface. NewTx(tx any) FriendModelInterface } diff --git a/tools/data-conversion/openim/mysql/v3/friend_request.go b/tools/data-conversion/openim/mysql/v3/friend_request.go index 51ea0ef6e3..4fc5ba7c1d 100644 --- a/tools/data-conversion/openim/mysql/v3/friend_request.go +++ b/tools/data-conversion/openim/mysql/v3/friend_request.go @@ -38,29 +38,33 @@ func (FriendRequestModel) TableName() string { } type FriendRequestModelInterface interface { - // 插入多条记录 + // Insert multiple records Create(ctx context.Context, friendRequests []*FriendRequestModel) (err error) - // 删除记录 + + // Delete a record Delete(ctx context.Context, fromUserID, toUserID string) (err error) - // 更新零值 - UpdateByMap(ctx context.Context, formUserID string, toUserID string, args map[string]interface{}) (err error) - // 更新多条记录 (非零值) + + // Update records with zero values based on a map of changes + UpdateByMap(ctx context.Context, formUserID, toUserID string, args map[string]interface{}) (err error) + + // Update multiple records (non-zero values) Update(ctx context.Context, friendRequest *FriendRequestModel) (err error) - // 获取来指定用户的好友申请 未找到 不返回错误 + + // Find a friend request sent to a specific user; does not return an error if not found Find(ctx context.Context, fromUserID, toUserID string) (friendRequest *FriendRequestModel, err error) + + // Alias for Find (retrieves a friend request between two users) Take(ctx context.Context, fromUserID, toUserID string) (friendRequest *FriendRequestModel, err error) - // 获取toUserID收到的好友申请列表 - FindToUserID( - ctx context.Context, - toUserID string, - pageNumber, showNumber int32, - ) (friendRequests []*FriendRequestModel, total int64, err error) - // 获取fromUserID发出去的好友申请列表 - FindFromUserID( - ctx context.Context, - fromUserID string, - pageNumber, showNumber int32, - ) (friendRequests []*FriendRequestModel, total int64, err error) + + // Get a list of friend requests received by `toUserID` + FindToUserID(ctx context.Context, toUserID string, pageNumber, showNumber int32) (friendRequests []*FriendRequestModel, total int64, err error) + + // Get a list of friend requests sent by `fromUserID` + FindFromUserID(ctx context.Context, fromUserID string, pageNumber, showNumber int32) (friendRequests []*FriendRequestModel, total int64, err error) + + // Find all friend requests between two users (both directions) FindBothFriendRequests(ctx context.Context, fromUserID, toUserID string) (friends []*FriendRequestModel, err error) + + // Create a new transaction NewTx(tx any) FriendRequestModelInterface } diff --git a/tools/data-conversion/openim/mysql/v3/group.go b/tools/data-conversion/openim/mysql/v3/group.go index 6759e0d352..ccf61266ae 100644 --- a/tools/data-conversion/openim/mysql/v3/group.go +++ b/tools/data-conversion/openim/mysql/v3/group.go @@ -58,9 +58,10 @@ type GroupModelInterface interface { keyword string, pageNumber, showNumber int32, ) (total uint32, groups []*GroupModel, err error) + // GetGroupIDsByCreatorUserID retrieves a list of group IDs created by the specified user. GetGroupIDsByGroupType(ctx context.Context, groupType int) (groupIDs []string, err error) - // 获取群总数 + // CountTotal retrieves the total number of groups. CountTotal(ctx context.Context, before *time.Time) (count int64, err error) - // 获取范围内群增量 + // CountRangeEverydayTotal retrieves the total number of groups created every day within the specified time range. CountRangeEverydayTotal(ctx context.Context, start time.Time, end time.Time) (map[string]int64, error) } diff --git a/tools/data-conversion/openim/mysql/v3/user.go b/tools/data-conversion/openim/mysql/v3/user.go index 10a715bda8..4096899330 100644 --- a/tools/data-conversion/openim/mysql/v3/user.go +++ b/tools/data-conversion/openim/mysql/v3/user.go @@ -53,20 +53,35 @@ func (UserModel) TableName() string { return UserModelTableName } +// UserModelInterface defines the operations available for managing user models. type UserModelInterface interface { + // Create inserts a new user or multiple users into the database. Create(ctx context.Context, users []*UserModel) (err error) + + // UpdateByMap updates a user's information based on a map of changes. UpdateByMap(ctx context.Context, userID string, args map[string]interface{}) (err error) + + // Update modifies a user's information in the database. Update(ctx context.Context, user *UserModel) (err error) - // 获取指定用户信息 不存在,也不返回错误 + + // Find retrieves information for a list of users by their IDs. If a user does not exist, it is simply skipped without returning an error. Find(ctx context.Context, userIDs []string) (users []*UserModel, err error) - // 获取某个用户信息 不存在,则返回错误 + + // Take retrieves a specific user's information by their ID. Returns an error if the user does not exist. Take(ctx context.Context, userID string) (user *UserModel, err error) - // 获取用户信息 不存在,不返回错误 + + // Page retrieves a paginated list of users and the total count of users. If no users exist, returns an empty list without an error. Page(ctx context.Context, pageNumber, showNumber int32) (users []*UserModel, count int64, err error) + + // GetAllUserID retrieves all user IDs in a paginated manner. GetAllUserID(ctx context.Context, pageNumber, showNumber int32) (userIDs []string, err error) + + // GetUserGlobalRecvMsgOpt retrieves a user's global message receiving option. GetUserGlobalRecvMsgOpt(ctx context.Context, userID string) (opt int, err error) - // 获取用户总数 + + // CountTotal returns the total number of users before a specified time. CountTotal(ctx context.Context, before *time.Time) (count int64, err error) - // 获取范围内用户增量 + + // CountRangeEverydayTotal calculates the daily increment of users within a specified time range. CountRangeEverydayTotal(ctx context.Context, start time.Time, end time.Time) (map[string]int64, error) } diff --git a/tools/formitychecker/checker/checker.go b/tools/formitychecker/checker/checker.go index c9ad8239f5..9a64b70902 100644 --- a/tools/formitychecker/checker/checker.go +++ b/tools/formitychecker/checker/checker.go @@ -21,6 +21,7 @@ import ( "regexp" "strings" + "github.com/OpenIMSDK/tools/errs" "github.com/openimsdk/open-im-server/tools/formitychecker/config" ) @@ -39,7 +40,7 @@ func CheckDirectory(cfg *config.Config) error { for _, targetDir := range cfg.TargetDirs { err := filepath.Walk(targetDir, func(path string, info os.FileInfo, err error) error { if err != nil { - return err + return errs.Wrap(err, fmt.Sprintf("error walking directory '%s'", targetDir)) } // Skip if the directory is in the ignore list diff --git a/tools/infra/infra.go b/tools/infra/infra.go index c14b92fa30..bc01a00eb6 100644 --- a/tools/infra/infra.go +++ b/tools/infra/infra.go @@ -20,7 +20,7 @@ import ( "github.com/fatih/color" ) -// 定义一个函数以打印重要的链接信息 +// Define a function to print important link information func printLinks() { blue := color.New(color.FgBlue).SprintFunc() fmt.Printf("OpenIM Github: %s\n", blue("https://github.com/OpenIMSDK/Open-IM-Server")) @@ -47,5 +47,5 @@ Keep checking for updates! ` blue.Println(message) - printLinks() // 调用函数以打印链接信息 + printLinks() // Call the function to print the link information } diff --git a/tools/url2im/main.go b/tools/url2im/main.go index 8d6151b09f..28c1e1c439 100644 --- a/tools/url2im/main.go +++ b/tools/url2im/main.go @@ -31,17 +31,38 @@ import ( */ func main() { - var conf pkg.Config // 后面带*的为必填项 - flag.StringVar(&conf.TaskPath, "task", "take.txt", "task path") // 任务日志文件* - flag.StringVar(&conf.ProgressPath, "progress", "", "progress path") // 进度日志文件 - flag.IntVar(&conf.Concurrency, "concurrency", 1, "concurrency num") // 并发数 - flag.IntVar(&conf.Retry, "retry", 1, "retry num") // 重试次数 - flag.StringVar(&conf.TempDir, "temp", "", "temp dir") // 临时文件夹 - flag.Int64Var(&conf.CacheSize, "cache", 1024*1024*100, "cache size") // 缓存大小(超过时,下载到磁盘) - flag.Int64Var((*int64)(&conf.Timeout), "timeout", 5000, "timeout") // 请求超时时间(毫秒) - flag.StringVar(&conf.Api, "api", "http://127.0.0.1:10002", "api") // im地址* - flag.StringVar(&conf.UserID, "userID", "openIM123456", "userID") // im管理员 - flag.StringVar(&conf.Secret, "secret", "openIM123", "secret") // im config secret + var conf pkg.Config // Configuration object, '*' denotes required fields + + // *Required*: Path for the task log file + flag.StringVar(&conf.TaskPath, "task", "take.txt", "Path for the task log file") + + // Optional: Path for the progress log file + flag.StringVar(&conf.ProgressPath, "progress", "", "Path for the progress log file") + + // Number of concurrent operations + flag.IntVar(&conf.Concurrency, "concurrency", 1, "Number of concurrent operations") + + // Number of retry attempts + flag.IntVar(&conf.Retry, "retry", 1, "Number of retry attempts") + + // Optional: Path for the temporary directory + flag.StringVar(&conf.TempDir, "temp", "", "Path for the temporary directory") + + // Cache size in bytes (downloads move to disk when exceeded) + flag.Int64Var(&conf.CacheSize, "cache", 1024*1024*100, "Cache size in bytes") + + // Request timeout in milliseconds + flag.Int64Var((*int64)(&conf.Timeout), "timeout", 5000, "Request timeout in milliseconds") + + // *Required*: API endpoint for the IM service + flag.StringVar(&conf.Api, "api", "http://127.0.0.1:10002", "API endpoint for the IM service") + + // IM administrator's user ID + flag.StringVar(&conf.UserID, "userID", "openIM123456", "IM administrator's user ID") + + // Secret for the IM configuration + flag.StringVar(&conf.Secret, "secret", "openIM123", "Secret for the IM configuration") + flag.Parse() if !filepath.IsAbs(conf.TaskPath) { var err error From 02a3cfb021f4b0adad41bbbe384a31d616bc9dce Mon Sep 17 00:00:00 2001 From: Xinwei Xiong <3293172751NSS@gmail.com> Date: Mon, 4 Mar 2024 17:30:17 +0800 Subject: [PATCH 078/188] feat: Introduce Language-Specific Comment Detection Tool and Standardize Log Filename Convention (#1992) * feat: optimize openim reset code * feat: optimize openim reset code * feat: optimize openim reset code * feat: optimize openim reset code * feat: optimize openim reset code * feat: optimize openim reset code * feat: optimize openim reset code * feat: optimize openim reset code --- .golangci.yml | 1 + config/templates/prometheus-dashboard.yaml | 8 +- docs/contrib/environment.md | 2 +- go.work | 1 + internal/api/user.go | 2 +- internal/msggateway/message_handler.go | 12 +-- internal/msgtransfer/init.go | 2 +- internal/rpc/group/group.go | 2 +- pkg/common/cmd/root.go | 4 +- scripts/build-all-service.sh | 3 - scripts/common.sh | 3 - scripts/install/environment.sh | 2 +- scripts/install/openim-rpc.sh | 4 - scripts/install/openim-tools.sh | 3 - scripts/lib/init.sh | 3 - scripts/lib/logging.sh | 6 +- scripts/lib/release.sh | 1 + scripts/verify-annotation-language.sh | 46 +++++++++++ scripts/verify-pkg-names.sh | 3 - test/codescan/main.go | 1 - tools/codescan/checker/checker.go | 90 ++++++++++++++++++++++ tools/codescan/codescan.go | 20 +++++ tools/codescan/config.yaml | 7 ++ tools/codescan/config/config.go | 35 +++++++++ tools/codescan/go.mod | 3 + 25 files changed, 224 insertions(+), 40 deletions(-) create mode 100755 scripts/verify-annotation-language.sh delete mode 100644 test/codescan/main.go create mode 100644 tools/codescan/checker/checker.go create mode 100644 tools/codescan/codescan.go create mode 100644 tools/codescan/config.yaml create mode 100644 tools/codescan/config/config.go create mode 100644 tools/codescan/go.mod diff --git a/.golangci.yml b/.golangci.yml index 0a0d40c215..67419d05e7 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -66,6 +66,7 @@ run: - "mocks/" - ".github/" - "logs/" + - "_output/" - "components/" # by default isn't set. If set we pass it to "go list -mod={option}". From "go help modules": diff --git a/config/templates/prometheus-dashboard.yaml b/config/templates/prometheus-dashboard.yaml index 417f3d343b..2e1ae7760c 100644 --- a/config/templates/prometheus-dashboard.yaml +++ b/config/templates/prometheus-dashboard.yaml @@ -53,7 +53,7 @@ }, "id": 16, "panels": [], - "title": "openim自定义指标", + "title": "openim Custom Metrics", "type": "row" }, { @@ -144,7 +144,7 @@ "refId": "A" } ], - "title": "在线人数", + "title": "Online population", "type": "timeseries" }, { @@ -235,7 +235,7 @@ "refId": "A" } ], - "title": "登入/注册人数", + "title": "Login/registration numbers", "type": "timeseries" }, { @@ -1345,7 +1345,7 @@ "type": "timeseries" } ], - "title": "应用服务器流量指标", + "title": "Traffic indicators of the application server", "type": "row" } ], diff --git a/docs/contrib/environment.md b/docs/contrib/environment.md index dc11a3c7b8..d2db7cbf3d 100644 --- a/docs/contrib/environment.md +++ b/docs/contrib/environment.md @@ -449,7 +449,7 @@ This section involves configuring the log settings, including storage location, | Parameter | Example Value | Description | | ------------------------- | ------------------------ | --------------------------------- | -| LOG_STORAGE_LOCATION | "${OPENIM_ROOT}/logs/" | Location for storing logs | +| LOG_STORAGE_LOCATION | "${OPENIM_ROOT}/_output/logs/" | Location for storing logs | | LOG_ROTATION_TIME | "24" | Log rotation time (in hours) | | LOG_REMAIN_ROTATION_COUNT | "2" | Number of log rotations to retain | | LOG_REMAIN_LOG_LEVEL | "6" | Log level to retain | diff --git a/go.work b/go.work index 97d2816d64..be67ce842d 100644 --- a/go.work +++ b/go.work @@ -3,6 +3,7 @@ go 1.19 use ( . ./test/typecheck + ./tools/codescan ./tools/changelog ./tools/component ./tools/data-conversion diff --git a/internal/api/user.go b/internal/api/user.go index 9019983193..16efcd704d 100644 --- a/internal/api/user.go +++ b/internal/api/user.go @@ -145,7 +145,7 @@ func (u *UserApi) GetUsersOnlineTokenDetail(c *gin.Context) { msgClient := msggateway.NewMsgGatewayClient(v) reply, err := msgClient.GetUsersOnlineStatus(c, &req) if err != nil { - log.ZWarn(c, "GetUsersOnlineStatus rpc err", err) + log.ZWarn(c, "GetUsersOnlineStatus rpc err", err) continue } else { wsResult = append(wsResult, reply.SuccessResult...) diff --git a/internal/msggateway/message_handler.go b/internal/msggateway/message_handler.go index 3c5bd6121a..74bde1ff5a 100644 --- a/internal/msggateway/message_handler.go +++ b/internal/msggateway/message_handler.go @@ -183,7 +183,7 @@ func (g GrpcHandler) PullMessageBySeqList(context context.Context, data *Req) ([ return nil, errs.Wrap(err, "error unmarshaling request") } if err := g.validate.Struct(data); err != nil { - return nil, err + return nil, errs.Wrap(err, "validation failed") } resp, err := g.msgRpcClient.PullMessageBySeqList(context, &req) if err != nil { @@ -191,7 +191,7 @@ func (g GrpcHandler) PullMessageBySeqList(context context.Context, data *Req) ([ } c, err := proto.Marshal(resp) if err != nil { - return nil, err + return nil, errs.Wrap(err, "error marshaling response") } return c, nil } @@ -199,7 +199,7 @@ func (g GrpcHandler) PullMessageBySeqList(context context.Context, data *Req) ([ func (g GrpcHandler) UserLogout(context context.Context, data *Req) ([]byte, error) { req := push.DelUserPushTokenReq{} if err := proto.Unmarshal(data.Data, &req); err != nil { - return nil, err + return nil, errs.Wrap(err, "error unmarshaling request") } resp, err := g.pushClient.DelUserPushToken(context, &req) if err != nil { @@ -207,7 +207,7 @@ func (g GrpcHandler) UserLogout(context context.Context, data *Req) ([]byte, err } c, err := proto.Marshal(resp) if err != nil { - return nil, err + return nil, errs.Wrap(err, "error marshaling response") } return c, nil } @@ -215,10 +215,10 @@ func (g GrpcHandler) UserLogout(context context.Context, data *Req) ([]byte, err func (g GrpcHandler) SetUserDeviceBackground(_ context.Context, data *Req) ([]byte, bool, error) { req := sdkws.SetAppBackgroundStatusReq{} if err := proto.Unmarshal(data.Data, &req); err != nil { - return nil, false, err + return nil, false, errs.Wrap(err, "error unmarshaling request") } if err := g.validate.Struct(data); err != nil { - return nil, false, err + return nil, false, errs.Wrap(err, "validation failed") } return nil, req.IsBackground, nil } diff --git a/internal/msgtransfer/init.go b/internal/msgtransfer/init.go index b5f8516f88..ca9ab5ac47 100644 --- a/internal/msgtransfer/init.go +++ b/internal/msgtransfer/init.go @@ -121,7 +121,7 @@ func (m *MsgTransfer) Start(prometheusPort int) error { var ( netDone = make(chan struct{}, 1) - netErr error + netErr error ) go m.historyCH.historyConsumerGroup.RegisterHandleAndConsumer(m.ctx, m.historyCH) diff --git a/internal/rpc/group/group.go b/internal/rpc/group/group.go index 60f6c3eb5c..db5108f316 100644 --- a/internal/rpc/group/group.go +++ b/internal/rpc/group/group.go @@ -974,7 +974,7 @@ func (s *groupServer) SetGroupInfo(ctx context.Context, req *pbgroup.SetGroupInf if len(update) == 0 { return resp, nil } - if updateErr := s.db.UpdateGroup(ctx, group.GroupID, update); updateErr != nil { + if err := s.db.UpdateGroup(ctx, group.GroupID, update); err != nil { return nil, err } group, err = s.db.TakeGroup(ctx, req.GroupInfoForSet.GroupID) diff --git a/pkg/common/cmd/root.go b/pkg/common/cmd/root.go index 7256bd0edc..4f4c5e69b6 100644 --- a/pkg/common/cmd/root.go +++ b/pkg/common/cmd/root.go @@ -47,7 +47,7 @@ type CmdOpts struct { func WithCronTaskLogName() func(*CmdOpts) { return func(opts *CmdOpts) { - opts.loggerPrefixName = "openim.crontask.log.all" + opts.loggerPrefixName = "openim-crontask" } } @@ -117,7 +117,7 @@ func (rc *RootCmd) initializeLogger(cmdOpts *CmdOpts) error { func defaultCmdOpts() *CmdOpts { return &CmdOpts{ - loggerPrefixName: "OpenIM.log.all", + loggerPrefixName: "openim-all", } } diff --git a/scripts/build-all-service.sh b/scripts/build-all-service.sh index 6335b0e08d..eea380b4fd 100755 --- a/scripts/build-all-service.sh +++ b/scripts/build-all-service.sh @@ -23,9 +23,6 @@ # Example: `scripts/build-go.sh WHAT=cmd/kubelet`. - - - OPENIM_ROOT=$(dirname "${BASH_SOURCE[0]}")/.. source "${OPENIM_ROOT}/scripts/lib/init.sh" diff --git a/scripts/common.sh b/scripts/common.sh index 702f555885..f7155fca2a 100755 --- a/scripts/common.sh +++ b/scripts/common.sh @@ -19,9 +19,6 @@ # Common utilities, variables and checks for all build scripts. - - - # Unset CDPATH, having it set messes up with script import paths unset CDPATH diff --git a/scripts/install/environment.sh b/scripts/install/environment.sh index 8962887753..64e76853d6 100755 --- a/scripts/install/environment.sh +++ b/scripts/install/environment.sh @@ -332,7 +332,7 @@ def "OPENIM_CONVERSATION_NAME" "Conversation" # OpenIM对话服务名称 def "OPENIM_THIRD_NAME" "Third" # OpenIM第三方服务名称 ###################### Log Configuration Variables ###################### -def "LOG_STORAGE_LOCATION" "${OPENIM_ROOT}/logs/" # 日志存储位置 +def "LOG_STORAGE_LOCATION" "${OPENIM_ROOT}/_output/logs/" # 日志存储位置 def "LOG_ROTATION_TIME" "24" # 日志轮替时间 def "LOG_REMAIN_ROTATION_COUNT" "2" # 保留的日志轮替数量 def "LOG_REMAIN_LOG_LEVEL" "6" # 保留的日志级别 diff --git a/scripts/install/openim-rpc.sh b/scripts/install/openim-rpc.sh index 023cb65947..e7ee430d24 100755 --- a/scripts/install/openim-rpc.sh +++ b/scripts/install/openim-rpc.sh @@ -38,10 +38,6 @@ # Note: Before executing this script, ensure that the necessary permissions are granted and relevant environmental variables are set. # - - - - OPENIM_ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")"/../.. && pwd -P) [[ -z ${COMMON_SOURCED} ]] && source "${OPENIM_ROOT}"/scripts/install/common.sh diff --git a/scripts/install/openim-tools.sh b/scripts/install/openim-tools.sh index d8c27e9858..4eb722c6e3 100755 --- a/scripts/install/openim-tools.sh +++ b/scripts/install/openim-tools.sh @@ -39,9 +39,6 @@ # - - - OPENIM_ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")"/../.. && pwd -P) [[ -z ${COMMON_SOURCED} ]] && source "${OPENIM_ROOT}"/scripts/install/common.sh diff --git a/scripts/lib/init.sh b/scripts/lib/init.sh index 4cd6d9fb88..6f12db36e7 100755 --- a/scripts/lib/init.sh +++ b/scripts/lib/init.sh @@ -14,9 +14,6 @@ # limitations under the License. - - - # Short-circuit if init.sh has already been sourced [[ $(type -t openim::init::loaded) == function ]] && return 0 diff --git a/scripts/lib/logging.sh b/scripts/lib/logging.sh index 7afb6bfced..bef3b5961a 100755 --- a/scripts/lib/logging.sh +++ b/scripts/lib/logging.sh @@ -25,9 +25,9 @@ if [ -z "${OPENIM_OUTPUT+x}" ]; then fi # Set the log file path -LOG_FILE="${OPENIM_OUTPUT}/logs/openim_$(date '+%Y%m%d').log" -STDERR_LOG_FILE="${OPENIM_OUTPUT}/logs/openim_error_$(date '+%Y%m%d').log" -TMP_LOG_FILE="${OPENIM_OUTPUT}/logs/openim_tmp_$(date '+%Y%m%d').log" +LOG_FILE="${OPENIM_OUTPUT}/logs/openim-$(date '+%Y%m%d').log" +STDERR_LOG_FILE="${OPENIM_OUTPUT}/logs/openim-error-$(date '+%Y%m%d').log" +TMP_LOG_FILE="${OPENIM_OUTPUT}/logs/openim-tmp-$(date '+%Y%m%d').log" if [[ ! -d "${OPENIM_OUTPUT}/logs" ]]; then mkdir -p "${OPENIM_OUTPUT}/logs" diff --git a/scripts/lib/release.sh b/scripts/lib/release.sh index 521e5cedc1..c1fbd00a1b 100755 --- a/scripts/lib/release.sh +++ b/scripts/lib/release.sh @@ -152,6 +152,7 @@ function openim::release::package_src_tarball() { -path "${OPENIM_ROOT}"/.github\* -o \ -path "${OPENIM_ROOT}"/components\* -o \ -path "${OPENIM_ROOT}"/logs\* -o \ + -path "${OPENIM_ROOT}"/_output\* -o \ -path "${OPENIM_ROOT}"/.gitignore\* -o \ -path "${OPENIM_ROOT}"/.gsemver.yml\* -o \ -path "${OPENIM_ROOT}"/.config\* -o \ diff --git a/scripts/verify-annotation-language.sh b/scripts/verify-annotation-language.sh new file mode 100755 index 0000000000..6b863776c9 --- /dev/null +++ b/scripts/verify-annotation-language.sh @@ -0,0 +1,46 @@ +#!/usr/bin/env bash +# 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. + + +# This script verifies whether codes follow golang convention. +# Usage: `scripts/verify-pkg-names.sh`. + +set -o errexit + +OPENIM_ROOT=$(dirname "${BASH_SOURCE[0]}")/.. +source "${OPENIM_ROOT}/scripts/lib/init.sh" + +openim::golang::verify_go_version + +openim::golang::verify_go_version + +OPENIM_OUTPUT_HOSTBIN_TOOLS="${OPENIM_ROOT}/_output/bin/tools/linux/amd64" +CODESCAN_BINARY="${OPENIM_OUTPUT_HOSTBIN_TOOLS}/codescan" + +if [[ ! -f "${CODESCAN_BINARY}" ]]; then + echo "codescan binary not found, building..." + pushd "${OPENIM_ROOT}" >/dev/null + make build BINS="codescan" + popd >/dev/null +fi + +if [[ ! -f "${CODESCAN_BINARY}" ]]; then + echo "Failed to build codescan binary." + exit 1 +fi + +CONFIG_PATH="${OPENIM_ROOT}/tools/codescan/config.yaml" + +"${CODESCAN_BINARY}" -config "${CONFIG_PATH}" \ No newline at end of file diff --git a/scripts/verify-pkg-names.sh b/scripts/verify-pkg-names.sh index 7fce3d7adb..be1acd015d 100755 --- a/scripts/verify-pkg-names.sh +++ b/scripts/verify-pkg-names.sh @@ -18,9 +18,6 @@ # Usage: `scripts/verify-pkg-names.sh`. - - - OPENIM_ROOT=$(dirname "${BASH_SOURCE[0]}")/.. source "${OPENIM_ROOT}/scripts/lib/init.sh" diff --git a/test/codescan/main.go b/test/codescan/main.go deleted file mode 100644 index 06ab7d0f9a..0000000000 --- a/test/codescan/main.go +++ /dev/null @@ -1 +0,0 @@ -package main diff --git a/tools/codescan/checker/checker.go b/tools/codescan/checker/checker.go new file mode 100644 index 0000000000..953236d0fa --- /dev/null +++ b/tools/codescan/checker/checker.go @@ -0,0 +1,90 @@ +package checker + +import ( + "bufio" + "fmt" + "os" + "path/filepath" + "regexp" + "strings" + + "github.com/openimsdk/open-im-server/tools/codescan/config" +) + +type CheckResult struct { + FilePath string + Lines []int +} + +func checkFileForChineseComments(filePath string) ([]CheckResult, error) { + file, err := os.Open(filePath) + if err != nil { + return nil, err + } + defer file.Close() + + var results []CheckResult + scanner := bufio.NewScanner(file) + reg := regexp.MustCompile(`[\p{Han}]+`) + lineNumber := 0 + + var linesWithChinese []int + for scanner.Scan() { + lineNumber++ + if reg.FindString(scanner.Text()) != "" { + linesWithChinese = append(linesWithChinese, lineNumber) + } + } + + if len(linesWithChinese) > 0 { + results = append(results, CheckResult{ + FilePath: filePath, + Lines: linesWithChinese, + }) + } + + if err := scanner.Err(); err != nil { + return nil, err + } + + return results, nil +} + +func WalkDirAndCheckComments(cfg config.Config) error { + var allResults []CheckResult + err := filepath.Walk(cfg.Directory, func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + if info.IsDir() { + return nil + } + for _, fileType := range cfg.FileTypes { + if filepath.Ext(path) == fileType { + results, err := checkFileForChineseComments(path) + if err != nil { + return err + } + if len(results) > 0 { + allResults = append(allResults, results...) + } + } + } + return nil + }) + + if err != nil { + return err + } + + if len(allResults) > 0 { + var errMsg strings.Builder + errMsg.WriteString("Files containing Chinese comments:\n") + for _, result := range allResults { + errMsg.WriteString(fmt.Sprintf("%s: Lines %v\n", result.FilePath, result.Lines)) + } + return fmt.Errorf(errMsg.String()) + } + + return nil +} diff --git a/tools/codescan/codescan.go b/tools/codescan/codescan.go new file mode 100644 index 0000000000..c46f7a7044 --- /dev/null +++ b/tools/codescan/codescan.go @@ -0,0 +1,20 @@ +package main + +import ( + "log" + + "github.com/openimsdk/open-im-server/tools/codescan/checker" + "github.com/openimsdk/open-im-server/tools/codescan/config" +) + +func main() { + cfg, err := config.ParseConfig() + if err != nil { + log.Fatalf("Error parsing config: %v", err) + } + + err = checker.WalkDirAndCheckComments(cfg) + if err != nil { + panic(err) + } +} diff --git a/tools/codescan/config.yaml b/tools/codescan/config.yaml new file mode 100644 index 0000000000..9a81236b8a --- /dev/null +++ b/tools/codescan/config.yaml @@ -0,0 +1,7 @@ +directory: ./ +file_types: + - .go + - .yaml + - .yml +languages: + - Chinese \ No newline at end of file diff --git a/tools/codescan/config/config.go b/tools/codescan/config/config.go new file mode 100644 index 0000000000..8f051e3dad --- /dev/null +++ b/tools/codescan/config/config.go @@ -0,0 +1,35 @@ +package config + +import ( + "flag" + "log" + "os" + + "gopkg.in/yaml.v2" +) + +type Config struct { + Directory string `yaml:"directory"` + FileTypes []string `yaml:"file_types"` + Languages []string `yaml:"languages"` +} + +func ParseConfig() (Config, error) { + var configPath string + flag.StringVar(&configPath, "config", "./", "Path to config file") + flag.Parse() + + var config Config + if configPath != "" { + configFile, err := os.ReadFile(configPath) + if err != nil { + return Config{}, err + } + if err := yaml.Unmarshal(configFile, &config); err != nil { + return Config{}, err + } + } else { + log.Fatal("Config file must be provided") + } + return config, nil +} diff --git a/tools/codescan/go.mod b/tools/codescan/go.mod new file mode 100644 index 0000000000..2ad1321018 --- /dev/null +++ b/tools/codescan/go.mod @@ -0,0 +1,3 @@ +module github.com/openimsdk/open-im-server/tools/codescan + +go 1.19 From 88bcabee1ccde76ef376cfa2f732363330e89dd4 Mon Sep 17 00:00:00 2001 From: longyuqing112 <105913803+longyuqing112@users.noreply.github.com> Date: Mon, 4 Mar 2024 18:20:25 +0800 Subject: [PATCH 079/188] feat: optimize openim make lint style format (#1995) * feat: add openim make lint * feat: add openim make lint * feat: add openim make lint * feat: add openim make lint * feat: add openim make lint --- .../msgtransfer/online_history_msg_handler.go | 3 ++- internal/push/offlinepush/fcm/push.go | 1 - .../kubernetes/kubernetes.go | 2 +- pkg/common/kafka/producer.go | 2 +- test/e2e/api/token/token.go | 14 ++++++++++++ test/e2e/framework/helpers/chat/chat.go | 22 +++++++++---------- 6 files changed, 29 insertions(+), 15 deletions(-) diff --git a/internal/msgtransfer/online_history_msg_handler.go b/internal/msgtransfer/online_history_msg_handler.go index 5023ac0087..635fe2eac1 100644 --- a/internal/msgtransfer/online_history_msg_handler.go +++ b/internal/msgtransfer/online_history_msg_handler.go @@ -257,7 +257,8 @@ func (och *OnlineHistoryRedisConsumerHandler) toPushTopic( msgs []*sdkws.MsgData, ) { for _, v := range msgs { - och.msgDatabase.MsgToPushMQ(ctx, key, conversationID, v) + och.msgDatabase.MsgToPushMQ(ctx, key, conversationID, v) // nolint: errcheck + } } diff --git a/internal/push/offlinepush/fcm/push.go b/internal/push/offlinepush/fcm/push.go index a60570860c..b1f16b4b27 100644 --- a/internal/push/offlinepush/fcm/push.go +++ b/internal/push/offlinepush/fcm/push.go @@ -127,7 +127,6 @@ func (f *Fcm) Push(ctx context.Context, userIDs []string, title, content string, response, err := f.fcmMsgCli.SendAll(ctx, messages) if err != nil { Fail = Fail + messageCount - // log.Info(operationID, "some token push err", err.Error(), messageCount) } else { Success = Success + response.SuccessCount Fail = Fail + response.FailureCount diff --git a/pkg/common/discoveryregister/kubernetes/kubernetes.go b/pkg/common/discoveryregister/kubernetes/kubernetes.go index 7c40399a3a..ab8864c6f1 100644 --- a/pkg/common/discoveryregister/kubernetes/kubernetes.go +++ b/pkg/common/discoveryregister/kubernetes/kubernetes.go @@ -194,5 +194,5 @@ func (cli *K8sDR) GetClientLocalConns() map[string][]*grpc.ClientConn { return nil } func (cli *K8sDR) Close() { - return + } diff --git a/pkg/common/kafka/producer.go b/pkg/common/kafka/producer.go index 4b5ce6b525..81064ab5fa 100644 --- a/pkg/common/kafka/producer.go +++ b/pkg/common/kafka/producer.go @@ -118,7 +118,7 @@ func configureProducerAck(p *Producer, ackConfig string) { // configureCompression configures the message compression type for the producer. func configureCompression(p *Producer, compressType string) { - var compress sarama.CompressionCodec = sarama.CompressionNone + var compress = sarama.CompressionNone err := compress.UnmarshalText(bytes.ToLower([]byte(compressType))) if err != nil { fmt.Printf("Failed to configure compression: %v\n", err) diff --git a/test/e2e/api/token/token.go b/test/e2e/api/token/token.go index b4dbda330c..908f9b8a0f 100644 --- a/test/e2e/api/token/token.go +++ b/test/e2e/api/token/token.go @@ -57,6 +57,20 @@ type UserRegisterRequest struct { Users []User `json:"users"` } +/* func main() { + // Example usage of functions + token, err := GetUserToken("openIM123456") + if err != nil { + log.Fatalf("Error getting user token: %v", err) + } + fmt.Println("Token:", token) + + err = RegisterUser(token, "testUserID", "TestNickname", "https://example.com/image.jpg") + if err != nil { + log.Fatalf("Error registering user: %v", err) + } +} */ + // GetUserToken requests a user token from the API. func GetUserToken(userID string) (string, error) { reqBody := UserTokenRequest{ diff --git a/test/e2e/framework/helpers/chat/chat.go b/test/e2e/framework/helpers/chat/chat.go index 82dcc1aabf..aa37c34b55 100644 --- a/test/e2e/framework/helpers/chat/chat.go +++ b/test/e2e/framework/helpers/chat/chat.go @@ -101,23 +101,23 @@ func main() { select {} } -// // getLatestVersion fetches the latest version number from a given URL. -// func getLatestVersion(url string) (string, error) { -// resp, err := http.Get(url) -// if err != nil { -// return "", err -// } -// defer resp.Body.Close() +// getLatestVersion fetches the latest version number from a given URL. +/* func getLatestVersion(url string) (string, error) { + resp, err := http.Get(url) + if err != nil { + return "", err + } + defer resp.Body.Close() // location := resp.Header.Get("Location") // if location == "" { // return defaultTemplateVersion, nil // } -// // Extract the version number from the URL -// latestVersion := filepath.Base(location) -// return latestVersion, nil -// } + // Extract the version number from the URL + latestVersion := filepath.Base(location) + return latestVersion, nil +} */ // downloadAndExtract downloads a file from a URL and extracts it to a destination directory. func downloadAndExtract(url, destDir string) error { From 33a61f29f20ee7326e755ea5d84500d96c77b5c3 Mon Sep 17 00:00:00 2001 From: Xinwei Xiong <3293172751NSS@gmail.com> Date: Mon, 4 Mar 2024 21:32:07 +0800 Subject: [PATCH 080/188] feat: format openim make lint code (#1997) --- .golangci.yml | 16 ++++++++- cmd/openim-api/main.go | 6 ++-- internal/api/auth.go | 3 +- internal/api/conversation.go | 3 +- internal/api/custom_validator.go | 3 +- internal/api/friend.go | 3 +- internal/api/group.go | 3 +- internal/api/msg.go | 3 +- internal/api/route.go | 15 ++++---- internal/api/statistics.go | 3 +- internal/api/third.go | 6 ++-- internal/msggateway/client.go | 10 +++--- internal/msggateway/hub_server.go | 3 +- internal/msggateway/message_handler.go | 8 ++--- internal/msggateway/n_ws_server.go | 10 +++--- internal/msgtransfer/init.go | 9 ++--- .../msgtransfer/online_history_msg_handler.go | 11 +++--- .../online_msg_to_mongo_handler.go | 3 +- internal/push/offlinepush/fcm/push.go | 3 +- internal/push/offlinepush/getui/push.go | 3 +- internal/push/push_handler.go | 3 +- internal/push/push_rpc_server.go | 6 ++-- internal/push/push_to_client.go | 6 ++-- internal/rpc/auth/auth.go | 6 ++-- internal/rpc/conversation/conversaion.go | 14 +++----- internal/rpc/friend/black.go | 3 +- internal/rpc/friend/friend.go | 20 ++++------- internal/rpc/group/callback.go | 6 ++-- internal/rpc/group/db_map.go | 3 +- internal/rpc/group/group.go | 34 +++++++------------ internal/rpc/msg/as_read.go | 10 +++--- internal/rpc/msg/callback.go | 6 ++-- internal/rpc/msg/delete.go | 4 +-- internal/rpc/msg/revoke.go | 3 +- internal/rpc/msg/send.go | 6 ++-- internal/rpc/msg/server.go | 3 +- internal/rpc/msg/sync_msg.go | 7 ++-- internal/rpc/third/s3.go | 9 ++--- internal/rpc/third/third.go | 17 ++++------ internal/rpc/third/tool.go | 4 +-- internal/rpc/user/user.go | 25 +++++--------- internal/tools/conversation.go | 1 - internal/tools/cron_task.go | 1 - internal/tools/msg.go | 19 ++++------- pkg/common/cmd/msg_gateway.go | 6 ++-- pkg/common/cmd/msg_transfer.go | 3 +- pkg/common/cmd/root.go | 9 ++--- pkg/common/cmd/rpc.go | 7 ++-- pkg/common/db/cache/conversation.go | 3 +- pkg/common/db/cache/friend.go | 3 +- pkg/common/db/cache/group.go | 5 +-- pkg/common/db/cache/init_redis.go | 3 +- pkg/common/db/cache/meta_cache.go | 6 ++-- pkg/common/db/cache/msg.go | 12 +++---- pkg/common/db/cache/user.go | 9 ++--- pkg/common/db/controller/auth.go | 9 ++--- pkg/common/db/controller/black.go | 3 +- pkg/common/db/controller/conversation.go | 6 ++-- pkg/common/db/controller/friend.go | 3 +- pkg/common/db/controller/group.go | 5 ++- pkg/common/db/controller/msg.go | 15 +++----- pkg/common/db/controller/user.go | 12 +++---- pkg/common/db/mgo/conversation.go | 3 +- pkg/common/db/mgo/friend.go | 3 +- pkg/common/db/mgo/friend_request.go | 3 +- pkg/common/db/mgo/group.go | 1 - pkg/common/db/mgo/group_member.go | 3 +- pkg/common/db/mgo/group_request.go | 1 - pkg/common/db/mgo/user.go | 3 +- pkg/common/db/s3/cont/controller.go | 6 ++-- pkg/common/db/s3/minio/minio.go | 3 +- pkg/common/db/table/relation/user.go | 1 - pkg/common/db/table/unrelation/msg.go | 4 +-- pkg/common/db/unrelation/mongo.go | 5 ++- pkg/common/db/unrelation/msg.go | 11 +++--- .../discoveryregister/discoveryregister.go | 7 ++-- .../kubernetes/kubernetes.go | 6 ++-- .../discoveryregister/zookeeper/zookeeper.go | 3 +- pkg/common/kafka/consumer_group.go | 3 +- pkg/common/kafka/producer.go | 6 ++-- pkg/common/startrpc/start.go | 19 ++++------- pkg/rpcclient/auth.go | 3 +- pkg/rpcclient/conversation.go | 6 ++-- pkg/rpcclient/friend.go | 3 +- pkg/rpcclient/group.go | 3 +- pkg/rpcclient/msg.go | 6 ++-- pkg/rpcclient/notification/friend.go | 3 +- pkg/rpcclient/notification/group.go | 3 +- pkg/rpcclient/push.go | 3 +- pkg/rpcclient/third.go | 7 ++-- pkg/rpcclient/user.go | 8 ++--- 91 files changed, 220 insertions(+), 375 deletions(-) mode change 100755 => 100644 pkg/rpcclient/notification/group.go mode change 100755 => 100644 pkg/rpcclient/third.go diff --git a/.golangci.yml b/.golangci.yml index 67419d05e7..5bf9eeba9a 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -118,7 +118,6 @@ linters-settings: right-to-left-isolate: true first-strong-isolate: true pop-directional-isolate: true - dogsled: # checks assignments with too many blank identifiers; default is 2 max-blank-identifiers: 2 dupl: @@ -729,6 +728,21 @@ linters: - gofmt # Format check - govet # Go's standard linting tool - gosimple # Suggestions for simplifying code + - errcheck + - decorder + - sloglint + - ineffassign + - revive + - reassign + - tparallel + - unconvert + - dupl + - dupword + - errname + - gci + - goheader + - goprintffuncname + - gosec - misspell # Spelling mistakes - staticcheck # Static analysis - unused # Checks for unused code diff --git a/cmd/openim-api/main.go b/cmd/openim-api/main.go index eeaa04d075..ad4e3b5c45 100644 --- a/cmd/openim-api/main.go +++ b/cmd/openim-api/main.go @@ -26,12 +26,9 @@ import ( "syscall" "time" - util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" - - "github.com/OpenIMSDK/tools/errs" - "github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/tools/discoveryregistry" + "github.com/OpenIMSDK/tools/errs" "github.com/openimsdk/open-im-server/v3/internal/api" "github.com/openimsdk/open-im-server/v3/pkg/common/cmd" @@ -40,6 +37,7 @@ import ( kdisc "github.com/openimsdk/open-im-server/v3/pkg/common/discoveryregister" ginprom "github.com/openimsdk/open-im-server/v3/pkg/common/ginprometheus" "github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics" + util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" ) func main() { diff --git a/internal/api/auth.go b/internal/api/auth.go index 88539f63a7..4aeadd7908 100644 --- a/internal/api/auth.go +++ b/internal/api/auth.go @@ -15,10 +15,9 @@ package api import ( - "github.com/gin-gonic/gin" - "github.com/OpenIMSDK/protocol/auth" "github.com/OpenIMSDK/tools/a2r" + "github.com/gin-gonic/gin" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" ) diff --git a/internal/api/conversation.go b/internal/api/conversation.go index eb735e5503..c9101fb26c 100644 --- a/internal/api/conversation.go +++ b/internal/api/conversation.go @@ -15,10 +15,9 @@ package api import ( - "github.com/gin-gonic/gin" - "github.com/OpenIMSDK/protocol/conversation" "github.com/OpenIMSDK/tools/a2r" + "github.com/gin-gonic/gin" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" ) diff --git a/internal/api/custom_validator.go b/internal/api/custom_validator.go index 1df4169e45..d135b0dc47 100644 --- a/internal/api/custom_validator.go +++ b/internal/api/custom_validator.go @@ -15,9 +15,8 @@ package api import ( - "github.com/go-playground/validator/v10" - "github.com/OpenIMSDK/protocol/constant" + "github.com/go-playground/validator/v10" ) // RequiredIf validates if the specified field is required based on the session type. diff --git a/internal/api/friend.go b/internal/api/friend.go index 7dc898a02d..98e86a0376 100644 --- a/internal/api/friend.go +++ b/internal/api/friend.go @@ -17,10 +17,9 @@ package api import ( "github.com/OpenIMSDK/protocol/friend" "github.com/OpenIMSDK/tools/a2r" + "github.com/gin-gonic/gin" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" - - "github.com/gin-gonic/gin" ) type FriendApi rpcclient.Friend diff --git a/internal/api/group.go b/internal/api/group.go index e525cd4959..af90c2db48 100644 --- a/internal/api/group.go +++ b/internal/api/group.go @@ -17,10 +17,9 @@ package api import ( "github.com/OpenIMSDK/protocol/group" "github.com/OpenIMSDK/tools/a2r" + "github.com/gin-gonic/gin" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" - - "github.com/gin-gonic/gin" ) type GroupApi rpcclient.Group diff --git a/internal/api/msg.go b/internal/api/msg.go index 1bbcf5428d..4b253f56b8 100644 --- a/internal/api/msg.go +++ b/internal/api/msg.go @@ -28,10 +28,9 @@ import ( "github.com/go-playground/validator/v10" "github.com/mitchellh/mapstructure" + "github.com/openimsdk/open-im-server/v3/pkg/apistruct" "github.com/openimsdk/open-im-server/v3/pkg/authverify" "github.com/openimsdk/open-im-server/v3/pkg/common/config" - - "github.com/openimsdk/open-im-server/v3/pkg/apistruct" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" ) diff --git a/internal/api/route.go b/internal/api/route.go index a6d73b6835..c6e0f53aa2 100644 --- a/internal/api/route.go +++ b/internal/api/route.go @@ -21,13 +21,11 @@ import ( "github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/tools/apiresp" + "github.com/OpenIMSDK/tools/discoveryregistry" "github.com/OpenIMSDK/tools/errs" + "github.com/OpenIMSDK/tools/log" + "github.com/OpenIMSDK/tools/mw" "github.com/OpenIMSDK/tools/tokenverify" - - "github.com/openimsdk/open-im-server/v3/pkg/authverify" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" - "github.com/gin-gonic/gin" "github.com/gin-gonic/gin/binding" "github.com/go-playground/validator/v10" @@ -35,11 +33,10 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" - "github.com/OpenIMSDK/tools/discoveryregistry" - "github.com/OpenIMSDK/tools/log" - "github.com/OpenIMSDK/tools/mw" - + "github.com/openimsdk/open-im-server/v3/pkg/authverify" "github.com/openimsdk/open-im-server/v3/pkg/common/config" + "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" + "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" ) diff --git a/internal/api/statistics.go b/internal/api/statistics.go index 5750a73153..397523e881 100644 --- a/internal/api/statistics.go +++ b/internal/api/statistics.go @@ -15,10 +15,9 @@ package api import ( - "github.com/gin-gonic/gin" - "github.com/OpenIMSDK/protocol/user" "github.com/OpenIMSDK/tools/a2r" + "github.com/gin-gonic/gin" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" ) diff --git a/internal/api/third.go b/internal/api/third.go index 0a1ef0fbee..2acf1ce89a 100644 --- a/internal/api/third.go +++ b/internal/api/third.go @@ -19,15 +19,13 @@ import ( "net/http" "strconv" - config2 "github.com/openimsdk/open-im-server/v3/pkg/common/config" - - "github.com/gin-gonic/gin" - "github.com/OpenIMSDK/protocol/third" "github.com/OpenIMSDK/tools/a2r" "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/mcontext" + "github.com/gin-gonic/gin" + config2 "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" ) diff --git a/internal/msggateway/client.go b/internal/msggateway/client.go index 06efea12f4..7017cf7d4c 100644 --- a/internal/msggateway/client.go +++ b/internal/msggateway/client.go @@ -22,18 +22,16 @@ import ( "sync" "sync/atomic" - "github.com/OpenIMSDK/tools/errs" - - "github.com/openimsdk/open-im-server/v3/pkg/msgprocessor" - - "google.golang.org/protobuf/proto" - "github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/protocol/sdkws" "github.com/OpenIMSDK/tools/apiresp" + "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/mcontext" "github.com/OpenIMSDK/tools/utils" + "google.golang.org/protobuf/proto" + + "github.com/openimsdk/open-im-server/v3/pkg/msgprocessor" ) var ( diff --git a/internal/msggateway/hub_server.go b/internal/msggateway/hub_server.go index 807c4af3bc..f6228717d1 100644 --- a/internal/msggateway/hub_server.go +++ b/internal/msggateway/hub_server.go @@ -17,8 +17,6 @@ package msggateway import ( "context" - "google.golang.org/grpc" - "github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/protocol/msggateway" "github.com/OpenIMSDK/tools/discoveryregistry" @@ -26,6 +24,7 @@ import ( "github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/mcontext" "github.com/OpenIMSDK/tools/utils" + "google.golang.org/grpc" "github.com/openimsdk/open-im-server/v3/pkg/authverify" "github.com/openimsdk/open-im-server/v3/pkg/common/config" diff --git a/internal/msggateway/message_handler.go b/internal/msggateway/message_handler.go index 74bde1ff5a..1cf91f67d4 100644 --- a/internal/msggateway/message_handler.go +++ b/internal/msggateway/message_handler.go @@ -18,17 +18,15 @@ import ( "context" "sync" + "github.com/OpenIMSDK/protocol/msg" "github.com/OpenIMSDK/protocol/push" + "github.com/OpenIMSDK/protocol/sdkws" "github.com/OpenIMSDK/tools/discoveryregistry" "github.com/OpenIMSDK/tools/errs" - + "github.com/OpenIMSDK/tools/utils" "github.com/go-playground/validator/v10" "google.golang.org/protobuf/proto" - "github.com/OpenIMSDK/protocol/msg" - "github.com/OpenIMSDK/protocol/sdkws" - "github.com/OpenIMSDK/tools/utils" - "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" ) diff --git a/internal/msggateway/n_ws_server.go b/internal/msggateway/n_ws_server.go index f466a7dc44..bf8a0da399 100644 --- a/internal/msggateway/n_ws_server.go +++ b/internal/msggateway/n_ws_server.go @@ -25,18 +25,16 @@ import ( "sync/atomic" "time" - "github.com/OpenIMSDK/tools/apiresp" - - "github.com/go-playground/validator/v10" - "github.com/redis/go-redis/v9" - "golang.org/x/sync/errgroup" - "github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/protocol/msggateway" + "github.com/OpenIMSDK/tools/apiresp" "github.com/OpenIMSDK/tools/discoveryregistry" "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/utils" + "github.com/go-playground/validator/v10" + "github.com/redis/go-redis/v9" + "golang.org/x/sync/errgroup" "github.com/openimsdk/open-im-server/v3/pkg/authverify" "github.com/openimsdk/open-im-server/v3/pkg/common/config" diff --git a/internal/msgtransfer/init.go b/internal/msgtransfer/init.go index ca9ab5ac47..077282f836 100644 --- a/internal/msgtransfer/init.go +++ b/internal/msgtransfer/init.go @@ -18,16 +18,12 @@ import ( "context" "errors" "fmt" - - "github.com/OpenIMSDK/tools/errs" - - util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" - "net/http" "os" "os/signal" "syscall" + "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/mw" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/collectors" @@ -42,6 +38,7 @@ import ( kdisc "github.com/openimsdk/open-im-server/v3/pkg/common/discoveryregister" "github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" + util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" ) type MsgTransfer struct { @@ -121,7 +118,7 @@ func (m *MsgTransfer) Start(prometheusPort int) error { var ( netDone = make(chan struct{}, 1) - netErr error + netErr error ) go m.historyCH.historyConsumerGroup.RegisterHandleAndConsumer(m.ctx, m.historyCH) diff --git a/internal/msgtransfer/online_history_msg_handler.go b/internal/msgtransfer/online_history_msg_handler.go index 635fe2eac1..e06ab5f07f 100644 --- a/internal/msgtransfer/online_history_msg_handler.go +++ b/internal/msgtransfer/online_history_msg_handler.go @@ -22,23 +22,20 @@ import ( "sync/atomic" "time" - "github.com/openimsdk/open-im-server/v3/pkg/msgprocessor" - - "github.com/OpenIMSDK/tools/errs" - "github.com/IBM/sarama" - "github.com/go-redis/redis" - "google.golang.org/protobuf/proto" - "github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/protocol/sdkws" + "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/mcontext" "github.com/OpenIMSDK/tools/utils" + "github.com/go-redis/redis" + "google.golang.org/protobuf/proto" "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" "github.com/openimsdk/open-im-server/v3/pkg/common/kafka" + "github.com/openimsdk/open-im-server/v3/pkg/msgprocessor" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" ) diff --git a/internal/msgtransfer/online_msg_to_mongo_handler.go b/internal/msgtransfer/online_msg_to_mongo_handler.go index 6e6c4c8195..35c0a4a4cc 100644 --- a/internal/msgtransfer/online_msg_to_mongo_handler.go +++ b/internal/msgtransfer/online_msg_to_mongo_handler.go @@ -18,10 +18,9 @@ import ( "context" "github.com/IBM/sarama" - "google.golang.org/protobuf/proto" - pbmsg "github.com/OpenIMSDK/protocol/msg" "github.com/OpenIMSDK/tools/log" + "google.golang.org/protobuf/proto" "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" diff --git a/internal/push/offlinepush/fcm/push.go b/internal/push/offlinepush/fcm/push.go index b1f16b4b27..a3453ba5a9 100644 --- a/internal/push/offlinepush/fcm/push.go +++ b/internal/push/offlinepush/fcm/push.go @@ -20,11 +20,10 @@ import ( firebase "firebase.google.com/go" "firebase.google.com/go/messaging" + "github.com/OpenIMSDK/protocol/constant" "github.com/redis/go-redis/v9" "google.golang.org/api/option" - "github.com/OpenIMSDK/protocol/constant" - "github.com/openimsdk/open-im-server/v3/internal/push/offlinepush" "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" diff --git a/internal/push/offlinepush/getui/push.go b/internal/push/offlinepush/getui/push.go index 8115e4efb9..81dbfaee31 100644 --- a/internal/push/offlinepush/getui/push.go +++ b/internal/push/offlinepush/getui/push.go @@ -23,12 +23,11 @@ import ( "sync" "time" - "github.com/redis/go-redis/v9" - "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/mcontext" "github.com/OpenIMSDK/tools/utils/splitter" + "github.com/redis/go-redis/v9" "github.com/openimsdk/open-im-server/v3/internal/push/offlinepush" "github.com/openimsdk/open-im-server/v3/pkg/common/config" diff --git a/internal/push/push_handler.go b/internal/push/push_handler.go index 19d42ebb9e..18b987267c 100644 --- a/internal/push/push_handler.go +++ b/internal/push/push_handler.go @@ -18,13 +18,12 @@ import ( "context" "github.com/IBM/sarama" - "google.golang.org/protobuf/proto" - "github.com/OpenIMSDK/protocol/constant" pbchat "github.com/OpenIMSDK/protocol/msg" pbpush "github.com/OpenIMSDK/protocol/push" "github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/utils" + "google.golang.org/protobuf/proto" "github.com/openimsdk/open-im-server/v3/pkg/common/config" kfk "github.com/openimsdk/open-im-server/v3/pkg/common/kafka" diff --git a/internal/push/push_rpc_server.go b/internal/push/push_rpc_server.go index f558aeec3d..30896849a3 100644 --- a/internal/push/push_rpc_server.go +++ b/internal/push/push_rpc_server.go @@ -17,14 +17,12 @@ package push import ( "context" - "github.com/OpenIMSDK/tools/utils" - - "google.golang.org/grpc" - "github.com/OpenIMSDK/protocol/constant" pbpush "github.com/OpenIMSDK/protocol/push" "github.com/OpenIMSDK/tools/discoveryregistry" "github.com/OpenIMSDK/tools/log" + "github.com/OpenIMSDK/tools/utils" + "google.golang.org/grpc" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" diff --git a/internal/push/push_to_client.go b/internal/push/push_to_client.go index 1140e8ce40..6e767a6be7 100644 --- a/internal/push/push_to_client.go +++ b/internal/push/push_to_client.go @@ -20,10 +20,6 @@ import ( "errors" "sync" - "google.golang.org/grpc" - - "golang.org/x/sync/errgroup" - "github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/protocol/conversation" "github.com/OpenIMSDK/protocol/msggateway" @@ -32,6 +28,8 @@ import ( "github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/mcontext" "github.com/OpenIMSDK/tools/utils" + "golang.org/x/sync/errgroup" + "google.golang.org/grpc" "github.com/openimsdk/open-im-server/v3/internal/push/offlinepush" "github.com/openimsdk/open-im-server/v3/internal/push/offlinepush/dummy" diff --git a/internal/rpc/auth/auth.go b/internal/rpc/auth/auth.go index cde1e6ac5e..774717cf9b 100644 --- a/internal/rpc/auth/auth.go +++ b/internal/rpc/auth/auth.go @@ -17,10 +17,6 @@ package auth import ( "context" - "github.com/openimsdk/open-im-server/v3/pkg/authverify" - - "google.golang.org/grpc" - pbauth "github.com/OpenIMSDK/protocol/auth" "github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/protocol/msggateway" @@ -29,7 +25,9 @@ import ( "github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/mcontext" "github.com/OpenIMSDK/tools/tokenverify" + "google.golang.org/grpc" + "github.com/openimsdk/open-im-server/v3/pkg/authverify" "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" diff --git a/internal/rpc/conversation/conversaion.go b/internal/rpc/conversation/conversaion.go index 582f932462..f513d1a2c8 100644 --- a/internal/rpc/conversation/conversaion.go +++ b/internal/rpc/conversation/conversaion.go @@ -19,26 +19,22 @@ import ( "errors" "sort" - "github.com/OpenIMSDK/protocol/sdkws" - - "github.com/OpenIMSDK/tools/tx" - - "github.com/openimsdk/open-im-server/v3/pkg/common/db/mgo" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/unrelation" - - "google.golang.org/grpc" - "github.com/OpenIMSDK/protocol/constant" pbconversation "github.com/OpenIMSDK/protocol/conversation" + "github.com/OpenIMSDK/protocol/sdkws" "github.com/OpenIMSDK/tools/discoveryregistry" "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/log" + "github.com/OpenIMSDK/tools/tx" "github.com/OpenIMSDK/tools/utils" + "google.golang.org/grpc" "github.com/openimsdk/open-im-server/v3/pkg/common/convert" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" + "github.com/openimsdk/open-im-server/v3/pkg/common/db/mgo" tablerelation "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" + "github.com/openimsdk/open-im-server/v3/pkg/common/db/unrelation" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient/notification" ) diff --git a/internal/rpc/friend/black.go b/internal/rpc/friend/black.go index ed5791c380..979cfdc954 100644 --- a/internal/rpc/friend/black.go +++ b/internal/rpc/friend/black.go @@ -18,11 +18,10 @@ import ( "context" "time" - "github.com/openimsdk/open-im-server/v3/pkg/authverify" - pbfriend "github.com/OpenIMSDK/protocol/friend" "github.com/OpenIMSDK/tools/mcontext" + "github.com/openimsdk/open-im-server/v3/pkg/authverify" "github.com/openimsdk/open-im-server/v3/pkg/common/convert" "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" ) diff --git a/internal/rpc/friend/friend.go b/internal/rpc/friend/friend.go index 9c49af220f..f3aea14f58 100644 --- a/internal/rpc/friend/friend.go +++ b/internal/rpc/friend/friend.go @@ -17,30 +17,24 @@ package friend import ( "context" - "github.com/OpenIMSDK/tools/tx" - - "github.com/OpenIMSDK/protocol/sdkws" - - "github.com/openimsdk/open-im-server/v3/pkg/authverify" - - "github.com/OpenIMSDK/tools/log" - - "github.com/openimsdk/open-im-server/v3/pkg/common/convert" - "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" - - "google.golang.org/grpc" - "github.com/OpenIMSDK/protocol/constant" pbfriend "github.com/OpenIMSDK/protocol/friend" + "github.com/OpenIMSDK/protocol/sdkws" registry "github.com/OpenIMSDK/tools/discoveryregistry" "github.com/OpenIMSDK/tools/errs" + "github.com/OpenIMSDK/tools/log" + "github.com/OpenIMSDK/tools/tx" "github.com/OpenIMSDK/tools/utils" + "google.golang.org/grpc" + "github.com/openimsdk/open-im-server/v3/pkg/authverify" + "github.com/openimsdk/open-im-server/v3/pkg/common/convert" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" "github.com/openimsdk/open-im-server/v3/pkg/common/db/mgo" tablerelation "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" "github.com/openimsdk/open-im-server/v3/pkg/common/db/unrelation" + "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient/notification" ) diff --git a/internal/rpc/group/callback.go b/internal/rpc/group/callback.go index d891f4d1ee..2a0ce65848 100644 --- a/internal/rpc/group/callback.go +++ b/internal/rpc/group/callback.go @@ -18,16 +18,14 @@ import ( "context" "time" - "github.com/OpenIMSDK/tools/log" - "github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/protocol/group" + pbgroup "github.com/OpenIMSDK/protocol/group" "github.com/OpenIMSDK/protocol/wrapperspb" + "github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/mcontext" "github.com/OpenIMSDK/tools/utils" - pbgroup "github.com/OpenIMSDK/protocol/group" - "github.com/openimsdk/open-im-server/v3/pkg/apistruct" "github.com/openimsdk/open-im-server/v3/pkg/callbackstruct" "github.com/openimsdk/open-im-server/v3/pkg/common/config" diff --git a/internal/rpc/group/db_map.go b/internal/rpc/group/db_map.go index 07084873c5..e4c18bb17b 100644 --- a/internal/rpc/group/db_map.go +++ b/internal/rpc/group/db_map.go @@ -18,10 +18,9 @@ import ( "context" "time" - "github.com/OpenIMSDK/tools/mcontext" - pbgroup "github.com/OpenIMSDK/protocol/group" "github.com/OpenIMSDK/protocol/sdkws" + "github.com/OpenIMSDK/tools/mcontext" ) func UpdateGroupInfoMap(ctx context.Context, group *sdkws.GroupInfoForSet) map[string]any { diff --git a/internal/rpc/group/group.go b/internal/rpc/group/group.go index db5108f316..d8a1e1d564 100644 --- a/internal/rpc/group/group.go +++ b/internal/rpc/group/group.go @@ -23,40 +23,32 @@ import ( "strings" "time" - "github.com/openimsdk/open-im-server/v3/pkg/callbackstruct" - - pbconversation "github.com/OpenIMSDK/protocol/conversation" - "github.com/OpenIMSDK/protocol/wrapperspb" - "github.com/OpenIMSDK/tools/tx" - - "github.com/openimsdk/open-im-server/v3/pkg/common/db/mgo" - "github.com/openimsdk/open-im-server/v3/pkg/rpcclient/grouphash" - - "github.com/openimsdk/open-im-server/v3/pkg/authverify" - "github.com/openimsdk/open-im-server/v3/pkg/msgprocessor" - - "github.com/openimsdk/open-im-server/v3/pkg/rpcclient/notification" - - "github.com/OpenIMSDK/tools/mw/specialerror" - - "github.com/openimsdk/open-im-server/v3/pkg/common/convert" - "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" - - "google.golang.org/grpc" - "github.com/OpenIMSDK/protocol/constant" + pbconversation "github.com/OpenIMSDK/protocol/conversation" pbgroup "github.com/OpenIMSDK/protocol/group" "github.com/OpenIMSDK/protocol/sdkws" + "github.com/OpenIMSDK/protocol/wrapperspb" "github.com/OpenIMSDK/tools/discoveryregistry" "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/mcontext" + "github.com/OpenIMSDK/tools/mw/specialerror" + "github.com/OpenIMSDK/tools/tx" "github.com/OpenIMSDK/tools/utils" + "google.golang.org/grpc" + "github.com/openimsdk/open-im-server/v3/pkg/authverify" + "github.com/openimsdk/open-im-server/v3/pkg/callbackstruct" + "github.com/openimsdk/open-im-server/v3/pkg/common/convert" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" + "github.com/openimsdk/open-im-server/v3/pkg/common/db/mgo" relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" "github.com/openimsdk/open-im-server/v3/pkg/common/db/unrelation" + "github.com/openimsdk/open-im-server/v3/pkg/msgprocessor" + "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" + "github.com/openimsdk/open-im-server/v3/pkg/rpcclient/grouphash" + "github.com/openimsdk/open-im-server/v3/pkg/rpcclient/notification" ) func Start(client discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) error { diff --git a/internal/rpc/msg/as_read.go b/internal/rpc/msg/as_read.go index cb292421e9..f9a44577ba 100644 --- a/internal/rpc/msg/as_read.go +++ b/internal/rpc/msg/as_read.go @@ -17,17 +17,15 @@ package msg import ( "context" - utils2 "github.com/OpenIMSDK/tools/utils" - - cbapi "github.com/openimsdk/open-im-server/v3/pkg/callbackstruct" - - "github.com/redis/go-redis/v9" - "github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/protocol/msg" "github.com/OpenIMSDK/protocol/sdkws" "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/log" + utils2 "github.com/OpenIMSDK/tools/utils" + "github.com/redis/go-redis/v9" + + cbapi "github.com/openimsdk/open-im-server/v3/pkg/callbackstruct" ) func (m *msgServer) GetConversationsHasReadAndMaxSeq(ctx context.Context, req *msg.GetConversationsHasReadAndMaxSeqReq) (resp *msg.GetConversationsHasReadAndMaxSeqResp, err error) { diff --git a/internal/rpc/msg/callback.go b/internal/rpc/msg/callback.go index f98318bba1..e281e48289 100644 --- a/internal/rpc/msg/callback.go +++ b/internal/rpc/msg/callback.go @@ -17,17 +17,15 @@ package msg import ( "context" - "github.com/OpenIMSDK/protocol/sdkws" - "google.golang.org/protobuf/proto" - "github.com/OpenIMSDK/protocol/constant" pbchat "github.com/OpenIMSDK/protocol/msg" + "github.com/OpenIMSDK/protocol/sdkws" "github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/mcontext" "github.com/OpenIMSDK/tools/utils" + "google.golang.org/protobuf/proto" cbapi "github.com/openimsdk/open-im-server/v3/pkg/callbackstruct" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/http" ) diff --git a/internal/rpc/msg/delete.go b/internal/rpc/msg/delete.go index b5c23bed6e..e2d81c92a5 100644 --- a/internal/rpc/msg/delete.go +++ b/internal/rpc/msg/delete.go @@ -17,14 +17,14 @@ package msg import ( "context" - "github.com/openimsdk/open-im-server/v3/pkg/authverify" - "github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/protocol/conversation" "github.com/OpenIMSDK/protocol/msg" "github.com/OpenIMSDK/protocol/sdkws" "github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/utils" + + "github.com/openimsdk/open-im-server/v3/pkg/authverify" ) func (m *msgServer) getMinSeqs(maxSeqs map[string]int64) map[string]int64 { diff --git a/internal/rpc/msg/revoke.go b/internal/rpc/msg/revoke.go index 0a24753b2d..2272911bc2 100644 --- a/internal/rpc/msg/revoke.go +++ b/internal/rpc/msg/revoke.go @@ -19,8 +19,6 @@ import ( "encoding/json" "time" - "github.com/openimsdk/open-im-server/v3/pkg/authverify" - "github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/protocol/msg" "github.com/OpenIMSDK/protocol/sdkws" @@ -29,6 +27,7 @@ import ( "github.com/OpenIMSDK/tools/mcontext" "github.com/OpenIMSDK/tools/utils" + "github.com/openimsdk/open-im-server/v3/pkg/authverify" "github.com/openimsdk/open-im-server/v3/pkg/common/config" unrelationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/unrelation" ) diff --git a/internal/rpc/msg/send.go b/internal/rpc/msg/send.go index 630b74a4a1..6f590578c8 100644 --- a/internal/rpc/msg/send.go +++ b/internal/rpc/msg/send.go @@ -17,9 +17,6 @@ package msg import ( "context" - "github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics" - "github.com/openimsdk/open-im-server/v3/pkg/msgprocessor" - "github.com/OpenIMSDK/protocol/constant" pbconversation "github.com/OpenIMSDK/protocol/conversation" pbmsg "github.com/OpenIMSDK/protocol/msg" @@ -29,6 +26,9 @@ import ( "github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/mcontext" "github.com/OpenIMSDK/tools/utils" + + "github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics" + "github.com/openimsdk/open-im-server/v3/pkg/msgprocessor" ) func (m *msgServer) SendMsg(ctx context.Context, req *pbmsg.SendMsgReq) (resp *pbmsg.SendMsgResp, error error) { diff --git a/internal/rpc/msg/server.go b/internal/rpc/msg/server.go index c258792762..0643abe26e 100644 --- a/internal/rpc/msg/server.go +++ b/internal/rpc/msg/server.go @@ -15,12 +15,11 @@ package msg import ( - "google.golang.org/grpc" - "github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/protocol/conversation" "github.com/OpenIMSDK/protocol/msg" "github.com/OpenIMSDK/tools/discoveryregistry" + "google.golang.org/grpc" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" diff --git a/internal/rpc/msg/sync_msg.go b/internal/rpc/msg/sync_msg.go index dbd8da4d80..3b76db1e44 100644 --- a/internal/rpc/msg/sync_msg.go +++ b/internal/rpc/msg/sync_msg.go @@ -17,15 +17,14 @@ package msg import ( "context" - "github.com/openimsdk/open-im-server/v3/pkg/authverify" - "github.com/openimsdk/open-im-server/v3/pkg/msgprocessor" - "github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/protocol/msg" - "github.com/OpenIMSDK/protocol/sdkws" "github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/utils" + + "github.com/openimsdk/open-im-server/v3/pkg/authverify" + "github.com/openimsdk/open-im-server/v3/pkg/msgprocessor" ) func (m *msgServer) PullMessageBySeqs( diff --git a/internal/rpc/third/s3.go b/internal/rpc/third/s3.go index 3b501d4add..488deb19e4 100644 --- a/internal/rpc/third/s3.go +++ b/internal/rpc/third/s3.go @@ -23,18 +23,15 @@ import ( "strconv" "time" - "github.com/google/uuid" - - "github.com/openimsdk/open-im-server/v3/pkg/authverify" - - "github.com/openimsdk/open-im-server/v3/pkg/common/db/s3" - "github.com/OpenIMSDK/protocol/third" "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/mcontext" "github.com/OpenIMSDK/tools/utils" + "github.com/google/uuid" + "github.com/openimsdk/open-im-server/v3/pkg/authverify" + "github.com/openimsdk/open-im-server/v3/pkg/common/db/s3" "github.com/openimsdk/open-im-server/v3/pkg/common/db/s3/cont" "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" ) diff --git a/internal/rpc/third/third.go b/internal/rpc/third/third.go index 0d474d2c44..dfa77f9d3d 100644 --- a/internal/rpc/third/third.go +++ b/internal/rpc/third/third.go @@ -20,22 +20,19 @@ import ( "net/url" "time" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/mgo" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/unrelation" - - "github.com/openimsdk/open-im-server/v3/pkg/common/db/s3" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/s3/cos" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/s3/minio" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/s3/oss" - - "google.golang.org/grpc" - "github.com/OpenIMSDK/protocol/third" "github.com/OpenIMSDK/tools/discoveryregistry" + "google.golang.org/grpc" "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" + "github.com/openimsdk/open-im-server/v3/pkg/common/db/mgo" + "github.com/openimsdk/open-im-server/v3/pkg/common/db/s3" + "github.com/openimsdk/open-im-server/v3/pkg/common/db/s3/cos" + "github.com/openimsdk/open-im-server/v3/pkg/common/db/s3/minio" + "github.com/openimsdk/open-im-server/v3/pkg/common/db/s3/oss" + "github.com/openimsdk/open-im-server/v3/pkg/common/db/unrelation" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" ) diff --git a/internal/rpc/third/tool.go b/internal/rpc/third/tool.go index a6c16ff9d1..efa047a437 100644 --- a/internal/rpc/third/tool.go +++ b/internal/rpc/third/tool.go @@ -21,11 +21,11 @@ import ( "strings" "unicode/utf8" - "github.com/openimsdk/open-im-server/v3/pkg/authverify" - "github.com/OpenIMSDK/protocol/third" "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/mcontext" + + "github.com/openimsdk/open-im-server/v3/pkg/authverify" ) func toPbMapArray(m map[string][]string) []*third.KeyValues { diff --git a/internal/rpc/user/user.go b/internal/rpc/user/user.go index 6f9e2949f3..b4140420b8 100644 --- a/internal/rpc/user/user.go +++ b/internal/rpc/user/user.go @@ -21,35 +21,28 @@ import ( "strings" "time" - "github.com/OpenIMSDK/tools/pagination" - - "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" - - "github.com/OpenIMSDK/tools/tx" - - "github.com/openimsdk/open-im-server/v3/pkg/common/db/mgo" - "github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/protocol/sdkws" + pbuser "github.com/OpenIMSDK/protocol/user" + registry "github.com/OpenIMSDK/tools/discoveryregistry" "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/log" + "github.com/OpenIMSDK/tools/pagination" + "github.com/OpenIMSDK/tools/tx" + "github.com/OpenIMSDK/tools/utils" + "google.golang.org/grpc" "github.com/openimsdk/open-im-server/v3/pkg/authverify" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/unrelation" - - registry "github.com/OpenIMSDK/tools/discoveryregistry" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/convert" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" + "github.com/openimsdk/open-im-server/v3/pkg/common/db/mgo" + "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" tablerelation "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" + "github.com/openimsdk/open-im-server/v3/pkg/common/db/unrelation" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient/notification" - - pbuser "github.com/OpenIMSDK/protocol/user" - "github.com/OpenIMSDK/tools/utils" - "google.golang.org/grpc" ) type userServer struct { diff --git a/internal/tools/conversation.go b/internal/tools/conversation.go index 6b918c0d12..5550bbad20 100644 --- a/internal/tools/conversation.go +++ b/internal/tools/conversation.go @@ -20,7 +20,6 @@ import ( "time" "github.com/OpenIMSDK/protocol/sdkws" - "github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/mcontext" "github.com/OpenIMSDK/tools/utils" diff --git a/internal/tools/cron_task.go b/internal/tools/cron_task.go index 0544f2f859..8d198ff28d 100644 --- a/internal/tools/cron_task.go +++ b/internal/tools/cron_task.go @@ -23,7 +23,6 @@ import ( "time" "github.com/OpenIMSDK/tools/errs" - "github.com/redis/go-redis/v9" "github.com/robfig/cron/v3" diff --git a/internal/tools/msg.go b/internal/tools/msg.go index 7548e3c04e..6d5a50b1e5 100644 --- a/internal/tools/msg.go +++ b/internal/tools/msg.go @@ -18,30 +18,25 @@ import ( "context" "fmt" "math" - - "github.com/OpenIMSDK/protocol/sdkws" - "github.com/OpenIMSDK/tools/tx" - - "github.com/openimsdk/open-im-server/v3/pkg/common/db/mgo" - - "github.com/redis/go-redis/v9" - "google.golang.org/grpc" - "google.golang.org/grpc/credentials/insecure" - - kdisc "github.com/openimsdk/open-im-server/v3/pkg/common/discoveryregister" - "math/rand" + "github.com/OpenIMSDK/protocol/sdkws" "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/mcontext" "github.com/OpenIMSDK/tools/mw" + "github.com/OpenIMSDK/tools/tx" "github.com/OpenIMSDK/tools/utils" + "github.com/redis/go-redis/v9" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" + "github.com/openimsdk/open-im-server/v3/pkg/common/db/mgo" "github.com/openimsdk/open-im-server/v3/pkg/common/db/unrelation" + kdisc "github.com/openimsdk/open-im-server/v3/pkg/common/discoveryregister" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient/notification" ) diff --git a/pkg/common/cmd/msg_gateway.go b/pkg/common/cmd/msg_gateway.go index 317844770c..1543afe15f 100644 --- a/pkg/common/cmd/msg_gateway.go +++ b/pkg/common/cmd/msg_gateway.go @@ -17,13 +17,11 @@ package cmd import ( "errors" - "github.com/spf13/cobra" - - "github.com/openimsdk/open-im-server/v3/internal/msggateway" - "github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/tools/errs" + "github.com/spf13/cobra" + "github.com/openimsdk/open-im-server/v3/internal/msggateway" v3config "github.com/openimsdk/open-im-server/v3/pkg/common/config" ) diff --git a/pkg/common/cmd/msg_transfer.go b/pkg/common/cmd/msg_transfer.go index 545c7543b6..6ea2b86fa3 100644 --- a/pkg/common/cmd/msg_transfer.go +++ b/pkg/common/cmd/msg_transfer.go @@ -20,9 +20,8 @@ import ( "github.com/OpenIMSDK/protocol/constant" "github.com/spf13/cobra" - config2 "github.com/openimsdk/open-im-server/v3/pkg/common/config" - "github.com/openimsdk/open-im-server/v3/internal/msgtransfer" + config2 "github.com/openimsdk/open-im-server/v3/pkg/common/config" ) type MsgTransferCmd struct { diff --git a/pkg/common/cmd/root.go b/pkg/common/cmd/root.go index 4f4c5e69b6..69a2af950f 100644 --- a/pkg/common/cmd/root.go +++ b/pkg/common/cmd/root.go @@ -17,16 +17,13 @@ package cmd import ( "fmt" - config2 "github.com/openimsdk/open-im-server/v3/pkg/common/config" - - "github.com/OpenIMSDK/tools/errs" - - "github.com/spf13/cobra" - "github.com/OpenIMSDK/protocol/constant" + "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/log" + "github.com/spf13/cobra" "github.com/openimsdk/open-im-server/v3/pkg/common/config" + config2 "github.com/openimsdk/open-im-server/v3/pkg/common/config" ) type RootCmdPt interface { diff --git a/pkg/common/cmd/rpc.go b/pkg/common/cmd/rpc.go index 39bf9c0366..d78233cbcc 100644 --- a/pkg/common/cmd/rpc.go +++ b/pkg/common/cmd/rpc.go @@ -19,15 +19,12 @@ import ( "fmt" "github.com/OpenIMSDK/protocol/constant" + "github.com/OpenIMSDK/tools/discoveryregistry" + "github.com/OpenIMSDK/tools/errs" "github.com/spf13/cobra" "google.golang.org/grpc" - "github.com/OpenIMSDK/tools/errs" - config2 "github.com/openimsdk/open-im-server/v3/pkg/common/config" - - "github.com/OpenIMSDK/tools/discoveryregistry" - "github.com/openimsdk/open-im-server/v3/pkg/common/startrpc" ) diff --git a/pkg/common/db/cache/conversation.go b/pkg/common/db/cache/conversation.go index 0471889472..c8cc11923b 100644 --- a/pkg/common/db/cache/conversation.go +++ b/pkg/common/db/cache/conversation.go @@ -20,11 +20,10 @@ import ( "strings" "time" + "github.com/OpenIMSDK/tools/utils" "github.com/dtm-labs/rockscache" "github.com/redis/go-redis/v9" - "github.com/OpenIMSDK/tools/utils" - relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" ) diff --git a/pkg/common/db/cache/friend.go b/pkg/common/db/cache/friend.go index a2b60d48fb..91faddaf95 100644 --- a/pkg/common/db/cache/friend.go +++ b/pkg/common/db/cache/friend.go @@ -18,11 +18,10 @@ import ( "context" "time" + "github.com/OpenIMSDK/tools/utils" "github.com/dtm-labs/rockscache" "github.com/redis/go-redis/v9" - "github.com/OpenIMSDK/tools/utils" - relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" ) diff --git a/pkg/common/db/cache/group.go b/pkg/common/db/cache/group.go index 57fcf1a9b4..0acf95ed4f 100644 --- a/pkg/common/db/cache/group.go +++ b/pkg/common/db/cache/group.go @@ -22,14 +22,11 @@ import ( "github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/tools/errs" - "github.com/OpenIMSDK/tools/log" - + "github.com/OpenIMSDK/tools/utils" "github.com/dtm-labs/rockscache" "github.com/redis/go-redis/v9" - "github.com/OpenIMSDK/tools/utils" - relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" ) diff --git a/pkg/common/db/cache/init_redis.go b/pkg/common/db/cache/init_redis.go index a41a4f4602..24de092b05 100644 --- a/pkg/common/db/cache/init_redis.go +++ b/pkg/common/db/cache/init_redis.go @@ -22,10 +22,9 @@ import ( "strings" "time" - "github.com/redis/go-redis/v9" - "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/mw/specialerror" + "github.com/redis/go-redis/v9" "github.com/openimsdk/open-im-server/v3/pkg/common/config" ) diff --git a/pkg/common/db/cache/meta_cache.go b/pkg/common/db/cache/meta_cache.go index fee982dc50..5f05ff1660 100644 --- a/pkg/common/db/cache/meta_cache.go +++ b/pkg/common/db/cache/meta_cache.go @@ -20,13 +20,11 @@ import ( "errors" "time" - "github.com/OpenIMSDK/tools/mw/specialerror" - - "github.com/dtm-labs/rockscache" - "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/log" + "github.com/OpenIMSDK/tools/mw/specialerror" "github.com/OpenIMSDK/tools/utils" + "github.com/dtm-labs/rockscache" ) const ( diff --git a/pkg/common/db/cache/msg.go b/pkg/common/db/cache/msg.go index 5cef509ed6..09c456ab3f 100644 --- a/pkg/common/db/cache/msg.go +++ b/pkg/common/db/cache/msg.go @@ -20,21 +20,17 @@ import ( "strconv" "time" - "golang.org/x/sync/errgroup" - - "github.com/openimsdk/open-im-server/v3/pkg/msgprocessor" - - "github.com/gogo/protobuf/jsonpb" - "github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/protocol/sdkws" "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/utils" + "github.com/gogo/protobuf/jsonpb" + "github.com/redis/go-redis/v9" + "golang.org/x/sync/errgroup" "github.com/openimsdk/open-im-server/v3/pkg/common/config" - - "github.com/redis/go-redis/v9" + "github.com/openimsdk/open-im-server/v3/pkg/msgprocessor" ) const ( diff --git a/pkg/common/db/cache/user.go b/pkg/common/db/cache/user.go index f444a2c465..11c46b5aca 100644 --- a/pkg/common/db/cache/user.go +++ b/pkg/common/db/cache/user.go @@ -22,17 +22,14 @@ import ( "strconv" "time" - relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" - - "github.com/OpenIMSDK/tools/log" - "github.com/OpenIMSDK/protocol/constant" - "github.com/OpenIMSDK/protocol/user" "github.com/OpenIMSDK/tools/errs" - + "github.com/OpenIMSDK/tools/log" "github.com/dtm-labs/rockscache" "github.com/redis/go-redis/v9" + + relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" ) const ( diff --git a/pkg/common/db/controller/auth.go b/pkg/common/db/controller/auth.go index 13bc066cad..04c5d2617c 100644 --- a/pkg/common/db/controller/auth.go +++ b/pkg/common/db/controller/auth.go @@ -17,15 +17,12 @@ package controller import ( "context" - "github.com/OpenIMSDK/tools/errs" - - "github.com/openimsdk/open-im-server/v3/pkg/authverify" - - "github.com/golang-jwt/jwt/v4" - "github.com/OpenIMSDK/protocol/constant" + "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/tokenverify" + "github.com/golang-jwt/jwt/v4" + "github.com/openimsdk/open-im-server/v3/pkg/authverify" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" ) diff --git a/pkg/common/db/controller/black.go b/pkg/common/db/controller/black.go index 3c8a47a017..427194ecd6 100644 --- a/pkg/common/db/controller/black.go +++ b/pkg/common/db/controller/black.go @@ -17,9 +17,8 @@ package controller import ( "context" - "github.com/OpenIMSDK/tools/pagination" - "github.com/OpenIMSDK/tools/log" + "github.com/OpenIMSDK/tools/pagination" "github.com/OpenIMSDK/tools/utils" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" diff --git a/pkg/common/db/controller/conversation.go b/pkg/common/db/controller/conversation.go index 0c64169a70..bf4349cf46 100644 --- a/pkg/common/db/controller/conversation.go +++ b/pkg/common/db/controller/conversation.go @@ -18,17 +18,15 @@ import ( "context" "time" - "github.com/OpenIMSDK/tools/pagination" - - "github.com/openimsdk/open-im-server/v3/pkg/msgprocessor" - "github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/tools/log" + "github.com/OpenIMSDK/tools/pagination" "github.com/OpenIMSDK/tools/tx" "github.com/OpenIMSDK/tools/utils" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" + "github.com/openimsdk/open-im-server/v3/pkg/msgprocessor" ) type ConversationDatabase interface { diff --git a/pkg/common/db/controller/friend.go b/pkg/common/db/controller/friend.go index bb5ec3087c..24504c2272 100644 --- a/pkg/common/db/controller/friend.go +++ b/pkg/common/db/controller/friend.go @@ -19,12 +19,11 @@ import ( "fmt" "time" - "github.com/OpenIMSDK/tools/pagination" - "github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/mcontext" + "github.com/OpenIMSDK/tools/pagination" "github.com/OpenIMSDK/tools/tx" "github.com/OpenIMSDK/tools/utils" diff --git a/pkg/common/db/controller/group.go b/pkg/common/db/controller/group.go index 6f208cc24d..2f2a972e4e 100644 --- a/pkg/common/db/controller/group.go +++ b/pkg/common/db/controller/group.go @@ -18,12 +18,11 @@ import ( "context" "time" - "github.com/OpenIMSDK/tools/pagination" - "github.com/dtm-labs/rockscache" - "github.com/OpenIMSDK/protocol/constant" + "github.com/OpenIMSDK/tools/pagination" "github.com/OpenIMSDK/tools/tx" "github.com/OpenIMSDK/tools/utils" + "github.com/dtm-labs/rockscache" "github.com/redis/go-redis/v9" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" diff --git a/pkg/common/db/controller/msg.go b/pkg/common/db/controller/msg.go index add9b63ce7..07b540ec08 100644 --- a/pkg/common/db/controller/msg.go +++ b/pkg/common/db/controller/msg.go @@ -21,14 +21,12 @@ import ( "time" "github.com/OpenIMSDK/protocol/constant" - - "github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics" - - "github.com/redis/go-redis/v9" - + pbmsg "github.com/OpenIMSDK/protocol/msg" + "github.com/OpenIMSDK/protocol/sdkws" "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/log" - + "github.com/OpenIMSDK/tools/utils" + "github.com/redis/go-redis/v9" "go.mongodb.org/mongo-driver/mongo" "github.com/openimsdk/open-im-server/v3/pkg/common/config" @@ -37,10 +35,7 @@ import ( unrelationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/unrelation" "github.com/openimsdk/open-im-server/v3/pkg/common/db/unrelation" "github.com/openimsdk/open-im-server/v3/pkg/common/kafka" - - pbmsg "github.com/OpenIMSDK/protocol/msg" - "github.com/OpenIMSDK/protocol/sdkws" - "github.com/OpenIMSDK/tools/utils" + "github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics" ) const ( diff --git a/pkg/common/db/controller/user.go b/pkg/common/db/controller/user.go index 8ba1c01d31..c18fef3168 100644 --- a/pkg/common/db/controller/user.go +++ b/pkg/common/db/controller/user.go @@ -18,19 +18,15 @@ import ( "context" "time" - "github.com/OpenIMSDK/tools/pagination" - "github.com/OpenIMSDK/tools/tx" - - "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" - "github.com/OpenIMSDK/protocol/user" - - unrelationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/unrelation" - "github.com/OpenIMSDK/tools/errs" + "github.com/OpenIMSDK/tools/pagination" + "github.com/OpenIMSDK/tools/tx" "github.com/OpenIMSDK/tools/utils" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" + "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" + unrelationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/unrelation" ) type UserDatabase interface { diff --git a/pkg/common/db/mgo/conversation.go b/pkg/common/db/mgo/conversation.go index d0a46ae47c..93ca4eceb6 100644 --- a/pkg/common/db/mgo/conversation.go +++ b/pkg/common/db/mgo/conversation.go @@ -18,9 +18,8 @@ import ( "context" "time" - "github.com/OpenIMSDK/tools/errs" - "github.com/OpenIMSDK/protocol/constant" + "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/mgoutil" "github.com/OpenIMSDK/tools/pagination" "go.mongodb.org/mongo-driver/bson" diff --git a/pkg/common/db/mgo/friend.go b/pkg/common/db/mgo/friend.go index 851db61572..01719822d3 100644 --- a/pkg/common/db/mgo/friend.go +++ b/pkg/common/db/mgo/friend.go @@ -19,10 +19,9 @@ import ( "github.com/OpenIMSDK/tools/mgoutil" "github.com/OpenIMSDK/tools/pagination" - "go.mongodb.org/mongo-driver/mongo/options" - "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" ) diff --git a/pkg/common/db/mgo/friend_request.go b/pkg/common/db/mgo/friend_request.go index bfc1019171..a05ca10184 100644 --- a/pkg/common/db/mgo/friend_request.go +++ b/pkg/common/db/mgo/friend_request.go @@ -19,10 +19,9 @@ import ( "github.com/OpenIMSDK/tools/mgoutil" "github.com/OpenIMSDK/tools/pagination" - "go.mongodb.org/mongo-driver/mongo/options" - "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" ) diff --git a/pkg/common/db/mgo/group.go b/pkg/common/db/mgo/group.go index 922bfd4240..cfb104a21d 100644 --- a/pkg/common/db/mgo/group.go +++ b/pkg/common/db/mgo/group.go @@ -19,7 +19,6 @@ import ( "time" "github.com/OpenIMSDK/tools/errs" - "github.com/OpenIMSDK/tools/mgoutil" "github.com/OpenIMSDK/tools/pagination" "go.mongodb.org/mongo-driver/bson" diff --git a/pkg/common/db/mgo/group_member.go b/pkg/common/db/mgo/group_member.go index e28432b118..5d3331baa4 100644 --- a/pkg/common/db/mgo/group_member.go +++ b/pkg/common/db/mgo/group_member.go @@ -17,9 +17,8 @@ package mgo import ( "context" - "github.com/OpenIMSDK/tools/errs" - "github.com/OpenIMSDK/protocol/constant" + "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/mgoutil" "github.com/OpenIMSDK/tools/pagination" "go.mongodb.org/mongo-driver/bson" diff --git a/pkg/common/db/mgo/group_request.go b/pkg/common/db/mgo/group_request.go index d206822399..87fba16369 100644 --- a/pkg/common/db/mgo/group_request.go +++ b/pkg/common/db/mgo/group_request.go @@ -18,7 +18,6 @@ import ( "context" "github.com/OpenIMSDK/tools/errs" - "github.com/OpenIMSDK/tools/mgoutil" "github.com/OpenIMSDK/tools/pagination" "go.mongodb.org/mongo-driver/bson" diff --git a/pkg/common/db/mgo/user.go b/pkg/common/db/mgo/user.go index 2797bc53ff..df26776ac6 100644 --- a/pkg/common/db/mgo/user.go +++ b/pkg/common/db/mgo/user.go @@ -20,11 +20,10 @@ import ( "github.com/OpenIMSDK/protocol/user" "github.com/OpenIMSDK/tools/errs" - "go.mongodb.org/mongo-driver/bson/primitive" - "github.com/OpenIMSDK/tools/mgoutil" "github.com/OpenIMSDK/tools/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" diff --git a/pkg/common/db/s3/cont/controller.go b/pkg/common/db/s3/cont/controller.go index f60c2c650d..0a40d8f361 100644 --- a/pkg/common/db/s3/cont/controller.go +++ b/pkg/common/db/s3/cont/controller.go @@ -24,13 +24,11 @@ import ( "strings" "time" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" - - "github.com/google/uuid" - "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/log" + "github.com/google/uuid" + "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" "github.com/openimsdk/open-im-server/v3/pkg/common/db/s3" ) diff --git a/pkg/common/db/s3/minio/minio.go b/pkg/common/db/s3/minio/minio.go index 81545ff1b7..a5e34e1aa7 100644 --- a/pkg/common/db/s3/minio/minio.go +++ b/pkg/common/db/s3/minio/minio.go @@ -29,14 +29,13 @@ import ( "time" "unsafe" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" - "github.com/OpenIMSDK/tools/log" "github.com/minio/minio-go/v7" "github.com/minio/minio-go/v7/pkg/credentials" "github.com/minio/minio-go/v7/pkg/signer" "github.com/openimsdk/open-im-server/v3/pkg/common/config" + "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" "github.com/openimsdk/open-im-server/v3/pkg/common/db/s3" ) diff --git a/pkg/common/db/table/relation/user.go b/pkg/common/db/table/relation/user.go index 265c3c93a2..375930ddf2 100644 --- a/pkg/common/db/table/relation/user.go +++ b/pkg/common/db/table/relation/user.go @@ -19,7 +19,6 @@ import ( "time" "github.com/OpenIMSDK/protocol/user" - "github.com/OpenIMSDK/tools/pagination" ) diff --git a/pkg/common/db/table/unrelation/msg.go b/pkg/common/db/table/unrelation/msg.go index c95b211a8e..60dd7c260c 100644 --- a/pkg/common/db/table/unrelation/msg.go +++ b/pkg/common/db/table/unrelation/msg.go @@ -20,10 +20,8 @@ import ( "time" "github.com/OpenIMSDK/protocol/msg" - - "go.mongodb.org/mongo-driver/mongo" - "github.com/OpenIMSDK/protocol/sdkws" + "go.mongodb.org/mongo-driver/mongo" ) const ( diff --git a/pkg/common/db/unrelation/mongo.go b/pkg/common/db/unrelation/mongo.go index 4c093b3c36..25bf4d10c4 100644 --- a/pkg/common/db/unrelation/mongo.go +++ b/pkg/common/db/unrelation/mongo.go @@ -21,13 +21,12 @@ import ( "strings" "time" + "github.com/OpenIMSDK/tools/errs" + "github.com/OpenIMSDK/tools/mw/specialerror" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo/options" - "github.com/OpenIMSDK/tools/errs" - "github.com/OpenIMSDK/tools/mw/specialerror" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/unrelation" ) diff --git a/pkg/common/db/unrelation/msg.go b/pkg/common/db/unrelation/msg.go index 0a6f683a57..0e33970c34 100644 --- a/pkg/common/db/unrelation/msg.go +++ b/pkg/common/db/unrelation/msg.go @@ -21,20 +21,17 @@ import ( "fmt" "time" - "github.com/OpenIMSDK/protocol/msg" - "github.com/OpenIMSDK/protocol/constant" - + "github.com/OpenIMSDK/protocol/msg" + "github.com/OpenIMSDK/protocol/sdkws" + "github.com/OpenIMSDK/tools/errs" + "github.com/OpenIMSDK/tools/log" "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" "google.golang.org/protobuf/proto" - "github.com/OpenIMSDK/protocol/sdkws" - "github.com/OpenIMSDK/tools/errs" - "github.com/OpenIMSDK/tools/log" - table "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/unrelation" ) diff --git a/pkg/common/discoveryregister/discoveryregister.go b/pkg/common/discoveryregister/discoveryregister.go index 4ade0147ad..18684c3499 100644 --- a/pkg/common/discoveryregister/discoveryregister.go +++ b/pkg/common/discoveryregister/discoveryregister.go @@ -18,13 +18,12 @@ import ( "errors" "os" - "github.com/openimsdk/open-im-server/v3/pkg/common/discoveryregister/direct" + "github.com/OpenIMSDK/tools/discoveryregistry" + "github.com/OpenIMSDK/tools/errs" + "github.com/openimsdk/open-im-server/v3/pkg/common/discoveryregister/direct" "github.com/openimsdk/open-im-server/v3/pkg/common/discoveryregister/kubernetes" "github.com/openimsdk/open-im-server/v3/pkg/common/discoveryregister/zookeeper" - - "github.com/OpenIMSDK/tools/discoveryregistry" - "github.com/OpenIMSDK/tools/errs" ) // NewDiscoveryRegister creates a new service discovery and registry client based on the provided environment type. diff --git a/pkg/common/discoveryregister/kubernetes/kubernetes.go b/pkg/common/discoveryregister/kubernetes/kubernetes.go index ab8864c6f1..59a78a336b 100644 --- a/pkg/common/discoveryregister/kubernetes/kubernetes.go +++ b/pkg/common/discoveryregister/kubernetes/kubernetes.go @@ -22,12 +22,10 @@ import ( "strconv" "strings" - "github.com/stathat/consistent" - - "google.golang.org/grpc" - "github.com/OpenIMSDK/tools/discoveryregistry" "github.com/OpenIMSDK/tools/log" + "github.com/stathat/consistent" + "google.golang.org/grpc" "github.com/openimsdk/open-im-server/v3/pkg/common/config" ) diff --git a/pkg/common/discoveryregister/zookeeper/zookeeper.go b/pkg/common/discoveryregister/zookeeper/zookeeper.go index 6e55b6b8b4..099badf420 100644 --- a/pkg/common/discoveryregister/zookeeper/zookeeper.go +++ b/pkg/common/discoveryregister/zookeeper/zookeeper.go @@ -20,10 +20,9 @@ import ( "strings" "time" - "github.com/OpenIMSDK/tools/errs" - "github.com/OpenIMSDK/tools/discoveryregistry" openkeeper "github.com/OpenIMSDK/tools/discoveryregistry/zookeeper" + "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/log" "github.com/openimsdk/open-im-server/v3/pkg/common/config" diff --git a/pkg/common/kafka/consumer_group.go b/pkg/common/kafka/consumer_group.go index ed961b93e4..f8b3ee2496 100644 --- a/pkg/common/kafka/consumer_group.go +++ b/pkg/common/kafka/consumer_group.go @@ -17,13 +17,12 @@ package kafka import ( "context" "errors" + "strings" "github.com/IBM/sarama" "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/log" - "strings" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" ) diff --git a/pkg/common/kafka/producer.go b/pkg/common/kafka/producer.go index 81064ab5fa..19ff198289 100644 --- a/pkg/common/kafka/producer.go +++ b/pkg/common/kafka/producer.go @@ -18,19 +18,17 @@ import ( "bytes" "context" "errors" + "fmt" "strings" "time" - "github.com/OpenIMSDK/tools/errs" - "github.com/IBM/sarama" "github.com/OpenIMSDK/protocol/constant" + "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/mcontext" "google.golang.org/protobuf/proto" - "fmt" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" ) diff --git a/pkg/common/startrpc/start.go b/pkg/common/startrpc/start.go index e19456d860..07b50070f8 100644 --- a/pkg/common/startrpc/start.go +++ b/pkg/common/startrpc/start.go @@ -27,25 +27,20 @@ import ( "syscall" "time" + "github.com/OpenIMSDK/tools/discoveryregistry" "github.com/OpenIMSDK/tools/errs" - - util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" - + "github.com/OpenIMSDK/tools/mw" + "github.com/OpenIMSDK/tools/network" + grpcprometheus "github.com/grpc-ecosystem/go-grpc-prometheus" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promhttp" - - "github.com/openimsdk/open-im-server/v3/pkg/common/config" - "github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics" - - grpcprometheus "github.com/grpc-ecosystem/go-grpc-prometheus" "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" + "github.com/openimsdk/open-im-server/v3/pkg/common/config" kdisc "github.com/openimsdk/open-im-server/v3/pkg/common/discoveryregister" - - "github.com/OpenIMSDK/tools/discoveryregistry" - "github.com/OpenIMSDK/tools/mw" - "github.com/OpenIMSDK/tools/network" + "github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics" + util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" ) // Start rpc server. diff --git a/pkg/rpcclient/auth.go b/pkg/rpcclient/auth.go index 810b7ae935..387acf320a 100644 --- a/pkg/rpcclient/auth.go +++ b/pkg/rpcclient/auth.go @@ -17,10 +17,9 @@ package rpcclient import ( "context" - "google.golang.org/grpc" - "github.com/OpenIMSDK/protocol/auth" "github.com/OpenIMSDK/tools/discoveryregistry" + "google.golang.org/grpc" "github.com/openimsdk/open-im-server/v3/pkg/common/config" util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" diff --git a/pkg/rpcclient/conversation.go b/pkg/rpcclient/conversation.go index 9afa45004a..926c571a47 100644 --- a/pkg/rpcclient/conversation.go +++ b/pkg/rpcclient/conversation.go @@ -18,15 +18,13 @@ import ( "context" "fmt" - "google.golang.org/grpc" - pbconversation "github.com/OpenIMSDK/protocol/conversation" "github.com/OpenIMSDK/tools/discoveryregistry" "github.com/OpenIMSDK/tools/errs" - - util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" + "google.golang.org/grpc" "github.com/openimsdk/open-im-server/v3/pkg/common/config" + util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" ) type Conversation struct { diff --git a/pkg/rpcclient/friend.go b/pkg/rpcclient/friend.go index 39026b10c1..a0e0226ec7 100644 --- a/pkg/rpcclient/friend.go +++ b/pkg/rpcclient/friend.go @@ -17,11 +17,10 @@ package rpcclient import ( "context" - "google.golang.org/grpc" - "github.com/OpenIMSDK/protocol/friend" sdkws "github.com/OpenIMSDK/protocol/sdkws" "github.com/OpenIMSDK/tools/discoveryregistry" + "google.golang.org/grpc" "github.com/openimsdk/open-im-server/v3/pkg/common/config" util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" diff --git a/pkg/rpcclient/group.go b/pkg/rpcclient/group.go index cb61579be1..7a15c11160 100644 --- a/pkg/rpcclient/group.go +++ b/pkg/rpcclient/group.go @@ -18,14 +18,13 @@ import ( "context" "strings" - "google.golang.org/grpc" - "github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/protocol/group" "github.com/OpenIMSDK/protocol/sdkws" "github.com/OpenIMSDK/tools/discoveryregistry" "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/utils" + "google.golang.org/grpc" "github.com/openimsdk/open-im-server/v3/pkg/common/config" util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" diff --git a/pkg/rpcclient/msg.go b/pkg/rpcclient/msg.go index 6804e78a2e..f468a65692 100644 --- a/pkg/rpcclient/msg.go +++ b/pkg/rpcclient/msg.go @@ -18,18 +18,16 @@ import ( "context" "encoding/json" - "google.golang.org/grpc" - "google.golang.org/protobuf/proto" - "github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/protocol/msg" "github.com/OpenIMSDK/protocol/sdkws" "github.com/OpenIMSDK/tools/discoveryregistry" "github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/utils" + "google.golang.org/grpc" + "google.golang.org/protobuf/proto" "github.com/openimsdk/open-im-server/v3/pkg/common/config" - // "google.golang.org/protobuf/proto". ) func newContentTypeConf() map[int32]config.NotificationConf { diff --git a/pkg/rpcclient/notification/friend.go b/pkg/rpcclient/notification/friend.go index a6b6937249..ba7a77c55f 100644 --- a/pkg/rpcclient/notification/friend.go +++ b/pkg/rpcclient/notification/friend.go @@ -17,11 +17,10 @@ package notification import ( "context" - "github.com/OpenIMSDK/tools/mcontext" - "github.com/OpenIMSDK/protocol/constant" pbfriend "github.com/OpenIMSDK/protocol/friend" "github.com/OpenIMSDK/protocol/sdkws" + "github.com/OpenIMSDK/tools/mcontext" "github.com/openimsdk/open-im-server/v3/pkg/common/convert" "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" diff --git a/pkg/rpcclient/notification/group.go b/pkg/rpcclient/notification/group.go old mode 100755 new mode 100644 index d336e4b129..8b355b663c --- a/pkg/rpcclient/notification/group.go +++ b/pkg/rpcclient/notification/group.go @@ -18,8 +18,6 @@ import ( "context" "fmt" - "github.com/openimsdk/open-im-server/v3/pkg/authverify" - "github.com/OpenIMSDK/protocol/constant" pbgroup "github.com/OpenIMSDK/protocol/group" "github.com/OpenIMSDK/protocol/sdkws" @@ -28,6 +26,7 @@ import ( "github.com/OpenIMSDK/tools/mcontext" "github.com/OpenIMSDK/tools/utils" + "github.com/openimsdk/open-im-server/v3/pkg/authverify" "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" diff --git a/pkg/rpcclient/push.go b/pkg/rpcclient/push.go index b5a5c49cfd..20296e6cdb 100644 --- a/pkg/rpcclient/push.go +++ b/pkg/rpcclient/push.go @@ -17,10 +17,9 @@ package rpcclient import ( "context" - "google.golang.org/grpc" - "github.com/OpenIMSDK/protocol/push" "github.com/OpenIMSDK/tools/discoveryregistry" + "google.golang.org/grpc" "github.com/openimsdk/open-im-server/v3/pkg/common/config" util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" diff --git a/pkg/rpcclient/third.go b/pkg/rpcclient/third.go old mode 100755 new mode 100644 index 05b825060d..f6ca458fd9 --- a/pkg/rpcclient/third.go +++ b/pkg/rpcclient/third.go @@ -18,13 +18,12 @@ import ( "context" "net/url" - "github.com/minio/minio-go/v7" - "github.com/minio/minio-go/v7/pkg/credentials" - "google.golang.org/grpc" - "github.com/OpenIMSDK/protocol/third" "github.com/OpenIMSDK/tools/discoveryregistry" "github.com/OpenIMSDK/tools/errs" + "github.com/minio/minio-go/v7" + "github.com/minio/minio-go/v7/pkg/credentials" + "google.golang.org/grpc" "github.com/openimsdk/open-im-server/v3/pkg/common/config" util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" diff --git a/pkg/rpcclient/user.go b/pkg/rpcclient/user.go index 810a88ad0f..8d0f7fc8b0 100644 --- a/pkg/rpcclient/user.go +++ b/pkg/rpcclient/user.go @@ -18,18 +18,16 @@ import ( "context" "strings" - "github.com/openimsdk/open-im-server/v3/pkg/authverify" - util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" - - "google.golang.org/grpc" - "github.com/OpenIMSDK/protocol/sdkws" "github.com/OpenIMSDK/protocol/user" "github.com/OpenIMSDK/tools/discoveryregistry" "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/utils" + "google.golang.org/grpc" + "github.com/openimsdk/open-im-server/v3/pkg/authverify" "github.com/openimsdk/open-im-server/v3/pkg/common/config" + util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" ) // User represents a structure holding connection details for the User RPC client. From e8377d9c2c248dd94a30bc317c4ebdb4dd75bc19 Mon Sep 17 00:00:00 2001 From: OpenIM Bot <124379614+kubbot@users.noreply.github.com> Date: Tue, 5 Mar 2024 10:51:55 +0800 Subject: [PATCH 081/188] cicd: bump League Patch (#1998) --- CHANGELOG/CHANGELOG-3.5.md | 16 +---- cmd/openim-api/main.go | 1 - internal/api/auth.go | 1 - internal/api/conversation.go | 1 - internal/api/friend.go | 1 - internal/api/group.go | 1 - internal/api/msg.go | 1 - internal/api/route.go | 13 +++-- internal/api/statistics.go | 1 - internal/api/third.go | 1 - internal/api/user.go | 1 - internal/msggateway/callback.go | 1 - internal/msggateway/client.go | 3 +- internal/msggateway/compressor_test.go | 2 +- internal/msggateway/hub_server.go | 3 +- internal/msggateway/message_handler.go | 3 +- internal/msggateway/n_ws_server.go | 5 +- internal/msgtransfer/init.go | 11 ++-- .../msgtransfer/online_history_msg_handler.go | 3 +- .../online_msg_to_mongo_handler.go | 3 +- internal/push/callback.go | 1 - internal/push/offlinepush/fcm/push.go | 5 +- internal/push/offlinepush/getui/push.go | 3 +- internal/push/push_handler.go | 3 +- internal/push/push_rpc_server.go | 3 +- internal/push/push_to_client.go | 5 +- internal/rpc/auth/auth.go | 3 +- internal/rpc/conversation/conversaion.go | 3 +- internal/rpc/friend/black.go | 1 - internal/rpc/friend/callback.go | 1 - internal/rpc/friend/friend.go | 3 +- internal/rpc/group/cache.go | 1 - internal/rpc/group/callback.go | 1 - internal/rpc/group/convert.go | 1 - internal/rpc/group/group.go | 3 +- internal/rpc/msg/as_read.go | 3 +- internal/rpc/msg/callback.go | 3 +- internal/rpc/msg/delete.go | 1 - internal/rpc/msg/message_interceptor.go | 1 - internal/rpc/msg/revoke.go | 1 - internal/rpc/msg/send.go | 1 - internal/rpc/msg/server.go | 3 +- internal/rpc/msg/statistics.go | 1 - internal/rpc/msg/sync_msg.go | 1 - internal/rpc/msg/utils.go | 3 +- internal/rpc/msg/verify.go | 1 - internal/rpc/third/log.go | 1 - internal/rpc/third/s3.go | 1 - internal/rpc/third/third.go | 3 +- internal/rpc/third/tool.go | 1 - internal/rpc/user/callback.go | 1 - internal/rpc/user/user.go | 3 +- internal/tools/conversation.go | 1 - internal/tools/cron_task.go | 5 +- internal/tools/msg.go | 7 +-- internal/tools/msg_doc_convert.go | 1 - pkg/authverify/token.go | 1 - pkg/callbackstruct/group.go | 1 - pkg/common/cmd/api.go | 3 +- pkg/common/cmd/msg_gateway.go | 3 +- pkg/common/cmd/msg_transfer.go | 3 +- pkg/common/cmd/msg_utils.go | 3 +- pkg/common/cmd/root.go | 3 +- pkg/common/cmd/rpc.go | 5 +- pkg/common/config/parse.go | 3 +- pkg/common/convert/black.go | 1 - pkg/common/convert/conversation.go | 1 - pkg/common/convert/friend.go | 7 ++- pkg/common/convert/group.go | 1 - pkg/common/convert/msg.go | 1 - pkg/common/convert/user.go | 1 - pkg/common/db/cache/black.go | 3 +- pkg/common/db/cache/conversation.go | 3 +- pkg/common/db/cache/friend.go | 3 +- pkg/common/db/cache/group.go | 3 +- pkg/common/db/cache/init_redis.go | 3 +- pkg/common/db/cache/meta_cache.go | 9 ++- pkg/common/db/cache/msg.go | 5 +- pkg/common/db/cache/s3.go | 3 +- pkg/common/db/cache/user.go | 3 +- pkg/common/db/controller/auth.go | 1 - pkg/common/db/controller/black.go | 1 - pkg/common/db/controller/conversation.go | 4 +- pkg/common/db/controller/friend.go | 1 - pkg/common/db/controller/group.go | 3 +- pkg/common/db/controller/msg.go | 8 +-- pkg/common/db/controller/s3.go | 3 +- pkg/common/db/controller/third.go | 1 - pkg/common/db/controller/user.go | 1 - pkg/common/db/localcache/conversation.go | 1 - pkg/common/db/localcache/group.go | 1 - pkg/common/db/mgo/black.go | 3 +- pkg/common/db/mgo/conversation.go | 3 +- pkg/common/db/mgo/friend.go | 3 +- pkg/common/db/mgo/friend_request.go | 3 +- pkg/common/db/mgo/group.go | 3 +- pkg/common/db/mgo/group_member.go | 3 +- pkg/common/db/mgo/group_request.go | 3 +- pkg/common/db/mgo/log.go | 3 +- pkg/common/db/mgo/object.go | 3 +- pkg/common/db/mgo/user.go | 3 +- pkg/common/db/s3/aws/aws.go | 1 - pkg/common/db/s3/cont/controller.go | 1 - pkg/common/db/s3/cos/cos.go | 3 +- pkg/common/db/s3/minio/minio.go | 1 - pkg/common/db/s3/minio/thumbnail.go | 1 - pkg/common/db/s3/oss/oss.go | 1 - pkg/common/db/unrelation/mongo.go | 5 +- pkg/common/db/unrelation/msg.go | 3 +- pkg/common/db/unrelation/msg_convert.go | 3 +- pkg/common/db/unrelation/user.go | 3 +- .../discoveryregister/direct/directconn.go | 3 +- .../discoveryregister/discoveryregister.go | 1 - .../kubernetes/kubernetes.go | 3 +- .../discoveryregister/zookeeper/zookeeper.go | 1 - pkg/common/http/http_client.go | 1 - pkg/common/kafka/consumer_group.go | 1 - pkg/common/kafka/producer.go | 3 +- pkg/common/kafka/util.go | 1 - pkg/common/prommetrics/prommetrics.go | 5 +- pkg/common/startrpc/start.go | 9 ++- pkg/common/tls/tls.go | 1 - pkg/rpcclient/auth.go | 3 +- pkg/rpcclient/conversation.go | 3 +- pkg/rpcclient/friend.go | 3 +- pkg/rpcclient/group.go | 3 +- pkg/rpcclient/msg.go | 3 +- pkg/rpcclient/notification/conversation.go | 1 - pkg/rpcclient/notification/friend.go | 1 - pkg/rpcclient/notification/group.go | 1 - pkg/rpcclient/notification/msg.go | 1 - pkg/rpcclient/notification/user.go | 1 - pkg/rpcclient/push.go | 3 +- pkg/rpcclient/third.go | 3 +- pkg/rpcclient/user.go | 3 +- test/e2e/page/chat_page.go | 14 +++++ test/e2e/page/login_page.go | 14 +++++ tools/codescan/checker/checker.go | 14 +++++ tools/codescan/codescan.go | 14 +++++ tools/codescan/config.yaml | 14 +++++ tools/codescan/config/config.go | 14 +++++ tools/formitychecker/checker/checker.go | 1 + tools/url2im/main.go | 58 +++++++++---------- 143 files changed, 230 insertions(+), 272 deletions(-) diff --git a/CHANGELOG/CHANGELOG-3.5.md b/CHANGELOG/CHANGELOG-3.5.md index 0a7f5bfa35..b929922f16 100644 --- a/CHANGELOG/CHANGELOG-3.5.md +++ b/CHANGELOG/CHANGELOG-3.5.md @@ -11,18 +11,9 @@ ## [v3.5.1-alpha.2] - 2024-01-26 - -## [v3.5.0+15.d356f7a] - 2024-01-26 - ## [v3.5.1-rc.1] - 2024-01-23 - -## [v3.5.0+2.e0bd54f-3-g52f9fc209] - 2024-01-12 - - -## [v3.5.0+2.e0bd54f-1-g4ce6a0fa6] - 2024-01-12 - ## [v3.5.1-alpha.1] - 2024-01-09 @@ -75,11 +66,8 @@ [Unreleased]: https://github.com/openimsdk/open-im-server/compare/v3.5.1-alpha.2...HEAD -[v3.5.1-alpha.2]: https://github.com/openimsdk/open-im-server/compare/v3.5.0+15.d356f7a...v3.5.1-alpha.2 -[v3.5.0+15.d356f7a]: https://github.com/openimsdk/open-im-server/compare/v3.5.1-rc.1...v3.5.0+15.d356f7a -[v3.5.1-rc.1]: https://github.com/openimsdk/open-im-server/compare/v3.5.0+2.e0bd54f-3-g52f9fc209...v3.5.1-rc.1 -[v3.5.0+2.e0bd54f-3-g52f9fc209]: https://github.com/openimsdk/open-im-server/compare/v3.5.0+2.e0bd54f-1-g4ce6a0fa6...v3.5.0+2.e0bd54f-3-g52f9fc209 -[v3.5.0+2.e0bd54f-1-g4ce6a0fa6]: https://github.com/openimsdk/open-im-server/compare/v3.5.1-alpha.1...v3.5.0+2.e0bd54f-1-g4ce6a0fa6 +[v3.5.1-alpha.2]: https://github.com/openimsdk/open-im-server/compare/v3.5.1-rc.1...v3.5.1-alpha.2 +[v3.5.1-rc.1]: https://github.com/openimsdk/open-im-server/compare/v3.5.1-alpha.1...v3.5.1-rc.1 [v3.5.1-alpha.1]: https://github.com/openimsdk/open-im-server/compare/v3.5.0...v3.5.1-alpha.1 [v3.5.0]: https://github.com/openimsdk/open-im-server/compare/v3.5.1...v3.5.0 [v3.5.1]: https://github.com/openimsdk/open-im-server/compare/v3.5.1-bate.1...v3.5.1 diff --git a/cmd/openim-api/main.go b/cmd/openim-api/main.go index ad4e3b5c45..0fb609aa3f 100644 --- a/cmd/openim-api/main.go +++ b/cmd/openim-api/main.go @@ -29,7 +29,6 @@ import ( "github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/tools/discoveryregistry" "github.com/OpenIMSDK/tools/errs" - "github.com/openimsdk/open-im-server/v3/internal/api" "github.com/openimsdk/open-im-server/v3/pkg/common/cmd" "github.com/openimsdk/open-im-server/v3/pkg/common/config" diff --git a/internal/api/auth.go b/internal/api/auth.go index 4aeadd7908..0f7a3933b3 100644 --- a/internal/api/auth.go +++ b/internal/api/auth.go @@ -18,7 +18,6 @@ import ( "github.com/OpenIMSDK/protocol/auth" "github.com/OpenIMSDK/tools/a2r" "github.com/gin-gonic/gin" - "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" ) diff --git a/internal/api/conversation.go b/internal/api/conversation.go index c9101fb26c..fe6c67001e 100644 --- a/internal/api/conversation.go +++ b/internal/api/conversation.go @@ -18,7 +18,6 @@ import ( "github.com/OpenIMSDK/protocol/conversation" "github.com/OpenIMSDK/tools/a2r" "github.com/gin-gonic/gin" - "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" ) diff --git a/internal/api/friend.go b/internal/api/friend.go index 98e86a0376..24bcbf8990 100644 --- a/internal/api/friend.go +++ b/internal/api/friend.go @@ -18,7 +18,6 @@ import ( "github.com/OpenIMSDK/protocol/friend" "github.com/OpenIMSDK/tools/a2r" "github.com/gin-gonic/gin" - "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" ) diff --git a/internal/api/group.go b/internal/api/group.go index af90c2db48..c18ded64b1 100644 --- a/internal/api/group.go +++ b/internal/api/group.go @@ -18,7 +18,6 @@ import ( "github.com/OpenIMSDK/protocol/group" "github.com/OpenIMSDK/tools/a2r" "github.com/gin-gonic/gin" - "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" ) diff --git a/internal/api/msg.go b/internal/api/msg.go index 4b253f56b8..61cd1ae6c5 100644 --- a/internal/api/msg.go +++ b/internal/api/msg.go @@ -27,7 +27,6 @@ import ( "github.com/gin-gonic/gin" "github.com/go-playground/validator/v10" "github.com/mitchellh/mapstructure" - "github.com/openimsdk/open-im-server/v3/pkg/apistruct" "github.com/openimsdk/open-im-server/v3/pkg/authverify" "github.com/openimsdk/open-im-server/v3/pkg/common/config" diff --git a/internal/api/route.go b/internal/api/route.go index c6e0f53aa2..5c920ca05a 100644 --- a/internal/api/route.go +++ b/internal/api/route.go @@ -29,19 +29,22 @@ import ( "github.com/gin-gonic/gin" "github.com/gin-gonic/gin/binding" "github.com/go-playground/validator/v10" - "github.com/redis/go-redis/v9" - "google.golang.org/grpc" - "google.golang.org/grpc/credentials/insecure" - "github.com/openimsdk/open-im-server/v3/pkg/authverify" "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" + "github.com/redis/go-redis/v9" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" ) func NewGinRouter(discov discoveryregistry.SvcDiscoveryRegistry, rdb redis.UniversalClient) *gin.Engine { - discov.AddOption(mw.GrpcClient(), grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithDefaultServiceConfig(fmt.Sprintf(`{"LoadBalancingPolicy": "%s"}`, "round_robin"))) // Default RPC middleware + discov.AddOption( + mw.GrpcClient(), + grpc.WithTransportCredentials(insecure.NewCredentials()), + grpc.WithDefaultServiceConfig(fmt.Sprintf(`{"LoadBalancingPolicy": "%s"}`, "round_robin")), + ) // Default RPC middleware gin.SetMode(gin.ReleaseMode) r := gin.New() if v, ok := binding.Validator.Engine().(*validator.Validate); ok { diff --git a/internal/api/statistics.go b/internal/api/statistics.go index 397523e881..2b80a15857 100644 --- a/internal/api/statistics.go +++ b/internal/api/statistics.go @@ -18,7 +18,6 @@ import ( "github.com/OpenIMSDK/protocol/user" "github.com/OpenIMSDK/tools/a2r" "github.com/gin-gonic/gin" - "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" ) diff --git a/internal/api/third.go b/internal/api/third.go index 2acf1ce89a..f00c0d8d37 100644 --- a/internal/api/third.go +++ b/internal/api/third.go @@ -24,7 +24,6 @@ import ( "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/mcontext" "github.com/gin-gonic/gin" - config2 "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" ) diff --git a/internal/api/user.go b/internal/api/user.go index 16efcd704d..3cc5470a71 100644 --- a/internal/api/user.go +++ b/internal/api/user.go @@ -23,7 +23,6 @@ import ( "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/log" "github.com/gin-gonic/gin" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" ) diff --git a/internal/msggateway/callback.go b/internal/msggateway/callback.go index 7d53817547..ede48f74a2 100644 --- a/internal/msggateway/callback.go +++ b/internal/msggateway/callback.go @@ -20,7 +20,6 @@ import ( "github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/tools/mcontext" - cbapi "github.com/openimsdk/open-im-server/v3/pkg/callbackstruct" "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/http" diff --git a/internal/msggateway/client.go b/internal/msggateway/client.go index 7017cf7d4c..4e843821e2 100644 --- a/internal/msggateway/client.go +++ b/internal/msggateway/client.go @@ -29,9 +29,8 @@ import ( "github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/mcontext" "github.com/OpenIMSDK/tools/utils" - "google.golang.org/protobuf/proto" - "github.com/openimsdk/open-im-server/v3/pkg/msgprocessor" + "google.golang.org/protobuf/proto" ) var ( diff --git a/internal/msggateway/compressor_test.go b/internal/msggateway/compressor_test.go index bb7106d9f5..173c9bb204 100644 --- a/internal/msggateway/compressor_test.go +++ b/internal/msggateway/compressor_test.go @@ -111,7 +111,7 @@ func BenchmarkDecompress(b *testing.B) { compressor := NewGzipCompressor() comdata, err := compressor.Compress(src) - + assert.Equal(b, nil, err) for i := 0; i < b.N; i++ { diff --git a/internal/msggateway/hub_server.go b/internal/msggateway/hub_server.go index f6228717d1..826c2488bc 100644 --- a/internal/msggateway/hub_server.go +++ b/internal/msggateway/hub_server.go @@ -24,12 +24,11 @@ import ( "github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/mcontext" "github.com/OpenIMSDK/tools/utils" - "google.golang.org/grpc" - "github.com/openimsdk/open-im-server/v3/pkg/authverify" "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" "github.com/openimsdk/open-im-server/v3/pkg/common/startrpc" + "google.golang.org/grpc" ) func (s *Server) InitServer(disCov discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) error { diff --git a/internal/msggateway/message_handler.go b/internal/msggateway/message_handler.go index 1cf91f67d4..105a77336e 100644 --- a/internal/msggateway/message_handler.go +++ b/internal/msggateway/message_handler.go @@ -25,9 +25,8 @@ import ( "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/utils" "github.com/go-playground/validator/v10" - "google.golang.org/protobuf/proto" - "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" + "google.golang.org/protobuf/proto" ) type Req struct { diff --git a/internal/msggateway/n_ws_server.go b/internal/msggateway/n_ws_server.go index bf8a0da399..e8ba9939ae 100644 --- a/internal/msggateway/n_ws_server.go +++ b/internal/msggateway/n_ws_server.go @@ -33,14 +33,13 @@ import ( "github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/utils" "github.com/go-playground/validator/v10" - "github.com/redis/go-redis/v9" - "golang.org/x/sync/errgroup" - "github.com/openimsdk/open-im-server/v3/pkg/authverify" "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" "github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" + "github.com/redis/go-redis/v9" + "golang.org/x/sync/errgroup" ) type LongConnServer interface { diff --git a/internal/msgtransfer/init.go b/internal/msgtransfer/init.go index 077282f836..dfb7c5307b 100644 --- a/internal/msgtransfer/init.go +++ b/internal/msgtransfer/init.go @@ -25,12 +25,6 @@ import ( "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/mw" - "github.com/prometheus/client_golang/prometheus" - "github.com/prometheus/client_golang/prometheus/collectors" - "github.com/prometheus/client_golang/prometheus/promhttp" - "google.golang.org/grpc" - "google.golang.org/grpc/credentials/insecure" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" @@ -39,6 +33,11 @@ import ( "github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/collectors" + "github.com/prometheus/client_golang/prometheus/promhttp" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" ) type MsgTransfer struct { diff --git a/internal/msgtransfer/online_history_msg_handler.go b/internal/msgtransfer/online_history_msg_handler.go index e06ab5f07f..4995d10e85 100644 --- a/internal/msgtransfer/online_history_msg_handler.go +++ b/internal/msgtransfer/online_history_msg_handler.go @@ -30,13 +30,12 @@ import ( "github.com/OpenIMSDK/tools/mcontext" "github.com/OpenIMSDK/tools/utils" "github.com/go-redis/redis" - "google.golang.org/protobuf/proto" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" "github.com/openimsdk/open-im-server/v3/pkg/common/kafka" "github.com/openimsdk/open-im-server/v3/pkg/msgprocessor" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" + "google.golang.org/protobuf/proto" ) const ( diff --git a/internal/msgtransfer/online_msg_to_mongo_handler.go b/internal/msgtransfer/online_msg_to_mongo_handler.go index 35c0a4a4cc..efffc191f9 100644 --- a/internal/msgtransfer/online_msg_to_mongo_handler.go +++ b/internal/msgtransfer/online_msg_to_mongo_handler.go @@ -20,12 +20,11 @@ import ( "github.com/IBM/sarama" pbmsg "github.com/OpenIMSDK/protocol/msg" "github.com/OpenIMSDK/tools/log" - "google.golang.org/protobuf/proto" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" kfk "github.com/openimsdk/open-im-server/v3/pkg/common/kafka" "github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics" + "google.golang.org/protobuf/proto" ) type OnlineHistoryMongoConsumerHandler struct { diff --git a/internal/push/callback.go b/internal/push/callback.go index 46b5545fb3..70862e4d23 100644 --- a/internal/push/callback.go +++ b/internal/push/callback.go @@ -21,7 +21,6 @@ import ( "github.com/OpenIMSDK/protocol/sdkws" "github.com/OpenIMSDK/tools/mcontext" "github.com/OpenIMSDK/tools/utils" - "github.com/openimsdk/open-im-server/v3/pkg/callbackstruct" "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/http" diff --git a/internal/push/offlinepush/fcm/push.go b/internal/push/offlinepush/fcm/push.go index a3453ba5a9..aa6ec186f2 100644 --- a/internal/push/offlinepush/fcm/push.go +++ b/internal/push/offlinepush/fcm/push.go @@ -21,12 +21,11 @@ import ( firebase "firebase.google.com/go" "firebase.google.com/go/messaging" "github.com/OpenIMSDK/protocol/constant" - "github.com/redis/go-redis/v9" - "google.golang.org/api/option" - "github.com/openimsdk/open-im-server/v3/internal/push/offlinepush" "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" + "github.com/redis/go-redis/v9" + "google.golang.org/api/option" ) const SinglePushCountLimit = 400 diff --git a/internal/push/offlinepush/getui/push.go b/internal/push/offlinepush/getui/push.go index 81dbfaee31..e950585a1f 100644 --- a/internal/push/offlinepush/getui/push.go +++ b/internal/push/offlinepush/getui/push.go @@ -27,12 +27,11 @@ import ( "github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/mcontext" "github.com/OpenIMSDK/tools/utils/splitter" - "github.com/redis/go-redis/v9" - "github.com/openimsdk/open-im-server/v3/internal/push/offlinepush" "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" http2 "github.com/openimsdk/open-im-server/v3/pkg/common/http" + "github.com/redis/go-redis/v9" ) var ( diff --git a/internal/push/push_handler.go b/internal/push/push_handler.go index 18b987267c..7b7a1150a3 100644 --- a/internal/push/push_handler.go +++ b/internal/push/push_handler.go @@ -23,10 +23,9 @@ import ( pbpush "github.com/OpenIMSDK/protocol/push" "github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/utils" - "google.golang.org/protobuf/proto" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" kfk "github.com/openimsdk/open-im-server/v3/pkg/common/kafka" + "google.golang.org/protobuf/proto" ) type ConsumerHandler struct { diff --git a/internal/push/push_rpc_server.go b/internal/push/push_rpc_server.go index 30896849a3..c5516e7cf2 100644 --- a/internal/push/push_rpc_server.go +++ b/internal/push/push_rpc_server.go @@ -22,12 +22,11 @@ import ( "github.com/OpenIMSDK/tools/discoveryregistry" "github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/utils" - "google.golang.org/grpc" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" "github.com/openimsdk/open-im-server/v3/pkg/common/db/localcache" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" + "google.golang.org/grpc" ) type pushServer struct { diff --git a/internal/push/push_to_client.go b/internal/push/push_to_client.go index 6e767a6be7..84efdba0cd 100644 --- a/internal/push/push_to_client.go +++ b/internal/push/push_to_client.go @@ -28,9 +28,6 @@ import ( "github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/mcontext" "github.com/OpenIMSDK/tools/utils" - "golang.org/x/sync/errgroup" - "google.golang.org/grpc" - "github.com/openimsdk/open-im-server/v3/internal/push/offlinepush" "github.com/openimsdk/open-im-server/v3/internal/push/offlinepush/dummy" "github.com/openimsdk/open-im-server/v3/internal/push/offlinepush/fcm" @@ -43,6 +40,8 @@ import ( "github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics" "github.com/openimsdk/open-im-server/v3/pkg/msgprocessor" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" + "golang.org/x/sync/errgroup" + "google.golang.org/grpc" ) type Pusher struct { diff --git a/internal/rpc/auth/auth.go b/internal/rpc/auth/auth.go index 774717cf9b..5f53911a4a 100644 --- a/internal/rpc/auth/auth.go +++ b/internal/rpc/auth/auth.go @@ -25,14 +25,13 @@ import ( "github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/mcontext" "github.com/OpenIMSDK/tools/tokenverify" - "google.golang.org/grpc" - "github.com/openimsdk/open-im-server/v3/pkg/authverify" "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" "github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" + "google.golang.org/grpc" ) type authServer struct { diff --git a/internal/rpc/conversation/conversaion.go b/internal/rpc/conversation/conversaion.go index f513d1a2c8..f3dc7ef17b 100644 --- a/internal/rpc/conversation/conversaion.go +++ b/internal/rpc/conversation/conversaion.go @@ -27,8 +27,6 @@ import ( "github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/tx" "github.com/OpenIMSDK/tools/utils" - "google.golang.org/grpc" - "github.com/openimsdk/open-im-server/v3/pkg/common/convert" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" @@ -37,6 +35,7 @@ import ( "github.com/openimsdk/open-im-server/v3/pkg/common/db/unrelation" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient/notification" + "google.golang.org/grpc" ) type conversationServer struct { diff --git a/internal/rpc/friend/black.go b/internal/rpc/friend/black.go index 979cfdc954..57edd26ba9 100644 --- a/internal/rpc/friend/black.go +++ b/internal/rpc/friend/black.go @@ -20,7 +20,6 @@ import ( pbfriend "github.com/OpenIMSDK/protocol/friend" "github.com/OpenIMSDK/tools/mcontext" - "github.com/openimsdk/open-im-server/v3/pkg/authverify" "github.com/openimsdk/open-im-server/v3/pkg/common/convert" "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" diff --git a/internal/rpc/friend/callback.go b/internal/rpc/friend/callback.go index e5054d9a9d..2b6e31899f 100644 --- a/internal/rpc/friend/callback.go +++ b/internal/rpc/friend/callback.go @@ -19,7 +19,6 @@ import ( pbfriend "github.com/OpenIMSDK/protocol/friend" "github.com/OpenIMSDK/tools/utils" - cbapi "github.com/openimsdk/open-im-server/v3/pkg/callbackstruct" "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/http" diff --git a/internal/rpc/friend/friend.go b/internal/rpc/friend/friend.go index f3aea14f58..4168731f7b 100644 --- a/internal/rpc/friend/friend.go +++ b/internal/rpc/friend/friend.go @@ -25,8 +25,6 @@ import ( "github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/tx" "github.com/OpenIMSDK/tools/utils" - "google.golang.org/grpc" - "github.com/openimsdk/open-im-server/v3/pkg/authverify" "github.com/openimsdk/open-im-server/v3/pkg/common/convert" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" @@ -36,6 +34,7 @@ import ( "github.com/openimsdk/open-im-server/v3/pkg/common/db/unrelation" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient/notification" + "google.golang.org/grpc" ) type friendServer struct { diff --git a/internal/rpc/group/cache.go b/internal/rpc/group/cache.go index fc387736dc..54b60c5543 100644 --- a/internal/rpc/group/cache.go +++ b/internal/rpc/group/cache.go @@ -18,7 +18,6 @@ import ( "context" pbgroup "github.com/OpenIMSDK/protocol/group" - "github.com/openimsdk/open-im-server/v3/pkg/common/convert" ) diff --git a/internal/rpc/group/callback.go b/internal/rpc/group/callback.go index 2a0ce65848..f09c23ec68 100644 --- a/internal/rpc/group/callback.go +++ b/internal/rpc/group/callback.go @@ -25,7 +25,6 @@ import ( "github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/mcontext" "github.com/OpenIMSDK/tools/utils" - "github.com/openimsdk/open-im-server/v3/pkg/apistruct" "github.com/openimsdk/open-im-server/v3/pkg/callbackstruct" "github.com/openimsdk/open-im-server/v3/pkg/common/config" diff --git a/internal/rpc/group/convert.go b/internal/rpc/group/convert.go index 2ee7f50561..ab4d3a2a1b 100644 --- a/internal/rpc/group/convert.go +++ b/internal/rpc/group/convert.go @@ -16,7 +16,6 @@ package group import ( "github.com/OpenIMSDK/protocol/sdkws" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" ) diff --git a/internal/rpc/group/group.go b/internal/rpc/group/group.go index d8a1e1d564..fa060efdac 100644 --- a/internal/rpc/group/group.go +++ b/internal/rpc/group/group.go @@ -35,8 +35,6 @@ import ( "github.com/OpenIMSDK/tools/mw/specialerror" "github.com/OpenIMSDK/tools/tx" "github.com/OpenIMSDK/tools/utils" - "google.golang.org/grpc" - "github.com/openimsdk/open-im-server/v3/pkg/authverify" "github.com/openimsdk/open-im-server/v3/pkg/callbackstruct" "github.com/openimsdk/open-im-server/v3/pkg/common/convert" @@ -49,6 +47,7 @@ import ( "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient/grouphash" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient/notification" + "google.golang.org/grpc" ) func Start(client discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) error { diff --git a/internal/rpc/msg/as_read.go b/internal/rpc/msg/as_read.go index f9a44577ba..cac9102fa4 100644 --- a/internal/rpc/msg/as_read.go +++ b/internal/rpc/msg/as_read.go @@ -23,9 +23,8 @@ import ( "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/log" utils2 "github.com/OpenIMSDK/tools/utils" - "github.com/redis/go-redis/v9" - cbapi "github.com/openimsdk/open-im-server/v3/pkg/callbackstruct" + "github.com/redis/go-redis/v9" ) func (m *msgServer) GetConversationsHasReadAndMaxSeq(ctx context.Context, req *msg.GetConversationsHasReadAndMaxSeqReq) (resp *msg.GetConversationsHasReadAndMaxSeqResp, err error) { diff --git a/internal/rpc/msg/callback.go b/internal/rpc/msg/callback.go index e281e48289..1a7cad70c1 100644 --- a/internal/rpc/msg/callback.go +++ b/internal/rpc/msg/callback.go @@ -23,11 +23,10 @@ import ( "github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/mcontext" "github.com/OpenIMSDK/tools/utils" - "google.golang.org/protobuf/proto" - cbapi "github.com/openimsdk/open-im-server/v3/pkg/callbackstruct" "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/http" + "google.golang.org/protobuf/proto" ) func cbURL() string { diff --git a/internal/rpc/msg/delete.go b/internal/rpc/msg/delete.go index e2d81c92a5..091f11f4cf 100644 --- a/internal/rpc/msg/delete.go +++ b/internal/rpc/msg/delete.go @@ -23,7 +23,6 @@ import ( "github.com/OpenIMSDK/protocol/sdkws" "github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/utils" - "github.com/openimsdk/open-im-server/v3/pkg/authverify" ) diff --git a/internal/rpc/msg/message_interceptor.go b/internal/rpc/msg/message_interceptor.go index a98c312199..3a2731fea4 100644 --- a/internal/rpc/msg/message_interceptor.go +++ b/internal/rpc/msg/message_interceptor.go @@ -21,7 +21,6 @@ import ( "github.com/OpenIMSDK/protocol/msg" "github.com/OpenIMSDK/protocol/sdkws" "github.com/OpenIMSDK/tools/errs" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" ) diff --git a/internal/rpc/msg/revoke.go b/internal/rpc/msg/revoke.go index 2272911bc2..eebfdf7797 100644 --- a/internal/rpc/msg/revoke.go +++ b/internal/rpc/msg/revoke.go @@ -26,7 +26,6 @@ import ( "github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/mcontext" "github.com/OpenIMSDK/tools/utils" - "github.com/openimsdk/open-im-server/v3/pkg/authverify" "github.com/openimsdk/open-im-server/v3/pkg/common/config" unrelationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/unrelation" diff --git a/internal/rpc/msg/send.go b/internal/rpc/msg/send.go index 6f590578c8..e04cebb3ba 100644 --- a/internal/rpc/msg/send.go +++ b/internal/rpc/msg/send.go @@ -26,7 +26,6 @@ import ( "github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/mcontext" "github.com/OpenIMSDK/tools/utils" - "github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics" "github.com/openimsdk/open-im-server/v3/pkg/msgprocessor" ) diff --git a/internal/rpc/msg/server.go b/internal/rpc/msg/server.go index 0643abe26e..79ae483a2e 100644 --- a/internal/rpc/msg/server.go +++ b/internal/rpc/msg/server.go @@ -19,13 +19,12 @@ import ( "github.com/OpenIMSDK/protocol/conversation" "github.com/OpenIMSDK/protocol/msg" "github.com/OpenIMSDK/tools/discoveryregistry" - "google.golang.org/grpc" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" "github.com/openimsdk/open-im-server/v3/pkg/common/db/localcache" "github.com/openimsdk/open-im-server/v3/pkg/common/db/unrelation" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" + "google.golang.org/grpc" ) type ( diff --git a/internal/rpc/msg/statistics.go b/internal/rpc/msg/statistics.go index ac09e3f69c..d7d33459b0 100644 --- a/internal/rpc/msg/statistics.go +++ b/internal/rpc/msg/statistics.go @@ -21,7 +21,6 @@ import ( "github.com/OpenIMSDK/protocol/msg" "github.com/OpenIMSDK/protocol/sdkws" "github.com/OpenIMSDK/tools/utils" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/unrelation" ) diff --git a/internal/rpc/msg/sync_msg.go b/internal/rpc/msg/sync_msg.go index 3b76db1e44..fa894e0344 100644 --- a/internal/rpc/msg/sync_msg.go +++ b/internal/rpc/msg/sync_msg.go @@ -22,7 +22,6 @@ import ( "github.com/OpenIMSDK/protocol/sdkws" "github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/utils" - "github.com/openimsdk/open-im-server/v3/pkg/authverify" "github.com/openimsdk/open-im-server/v3/pkg/msgprocessor" ) diff --git a/internal/rpc/msg/utils.go b/internal/rpc/msg/utils.go index e45d7b3959..d8a45e8750 100644 --- a/internal/rpc/msg/utils.go +++ b/internal/rpc/msg/utils.go @@ -18,10 +18,9 @@ import ( "github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/protocol/sdkws" "github.com/OpenIMSDK/tools/utils" + "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/redis/go-redis/v9" "go.mongodb.org/mongo-driver/mongo" - - "github.com/openimsdk/open-im-server/v3/pkg/common/config" ) func isMessageHasReadEnabled(msgData *sdkws.MsgData) bool { diff --git a/internal/rpc/msg/verify.go b/internal/rpc/msg/verify.go index 0080b6fdb8..11055fac11 100644 --- a/internal/rpc/msg/verify.go +++ b/internal/rpc/msg/verify.go @@ -25,7 +25,6 @@ import ( "github.com/OpenIMSDK/protocol/sdkws" "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/utils" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" ) diff --git a/internal/rpc/third/log.go b/internal/rpc/third/log.go index 11c7467b80..420f399ba4 100644 --- a/internal/rpc/third/log.go +++ b/internal/rpc/third/log.go @@ -25,7 +25,6 @@ import ( "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/utils" utils2 "github.com/OpenIMSDK/tools/utils" - "github.com/openimsdk/open-im-server/v3/pkg/authverify" relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" ) diff --git a/internal/rpc/third/s3.go b/internal/rpc/third/s3.go index 488deb19e4..7f68f4da89 100644 --- a/internal/rpc/third/s3.go +++ b/internal/rpc/third/s3.go @@ -29,7 +29,6 @@ import ( "github.com/OpenIMSDK/tools/mcontext" "github.com/OpenIMSDK/tools/utils" "github.com/google/uuid" - "github.com/openimsdk/open-im-server/v3/pkg/authverify" "github.com/openimsdk/open-im-server/v3/pkg/common/db/s3" "github.com/openimsdk/open-im-server/v3/pkg/common/db/s3/cont" diff --git a/internal/rpc/third/third.go b/internal/rpc/third/third.go index dfa77f9d3d..9dd3ffd65a 100644 --- a/internal/rpc/third/third.go +++ b/internal/rpc/third/third.go @@ -22,8 +22,6 @@ import ( "github.com/OpenIMSDK/protocol/third" "github.com/OpenIMSDK/tools/discoveryregistry" - "google.golang.org/grpc" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" @@ -34,6 +32,7 @@ import ( "github.com/openimsdk/open-im-server/v3/pkg/common/db/s3/oss" "github.com/openimsdk/open-im-server/v3/pkg/common/db/unrelation" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" + "google.golang.org/grpc" ) func Start(client discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) error { diff --git a/internal/rpc/third/tool.go b/internal/rpc/third/tool.go index efa047a437..cf25f98209 100644 --- a/internal/rpc/third/tool.go +++ b/internal/rpc/third/tool.go @@ -24,7 +24,6 @@ import ( "github.com/OpenIMSDK/protocol/third" "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/mcontext" - "github.com/openimsdk/open-im-server/v3/pkg/authverify" ) diff --git a/internal/rpc/user/callback.go b/internal/rpc/user/callback.go index 5276946a48..1437257f78 100644 --- a/internal/rpc/user/callback.go +++ b/internal/rpc/user/callback.go @@ -19,7 +19,6 @@ import ( pbuser "github.com/OpenIMSDK/protocol/user" "github.com/OpenIMSDK/tools/utils" - cbapi "github.com/openimsdk/open-im-server/v3/pkg/callbackstruct" "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/http" diff --git a/internal/rpc/user/user.go b/internal/rpc/user/user.go index b4140420b8..7ed3ff7d6d 100644 --- a/internal/rpc/user/user.go +++ b/internal/rpc/user/user.go @@ -30,8 +30,6 @@ import ( "github.com/OpenIMSDK/tools/pagination" "github.com/OpenIMSDK/tools/tx" "github.com/OpenIMSDK/tools/utils" - "google.golang.org/grpc" - "github.com/openimsdk/open-im-server/v3/pkg/authverify" "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/convert" @@ -43,6 +41,7 @@ import ( "github.com/openimsdk/open-im-server/v3/pkg/common/db/unrelation" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient/notification" + "google.golang.org/grpc" ) type userServer struct { diff --git a/internal/tools/conversation.go b/internal/tools/conversation.go index 5550bbad20..b555a33614 100644 --- a/internal/tools/conversation.go +++ b/internal/tools/conversation.go @@ -23,7 +23,6 @@ import ( "github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/mcontext" "github.com/OpenIMSDK/tools/utils" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" ) diff --git a/internal/tools/cron_task.go b/internal/tools/cron_task.go index 8d198ff28d..9b74a5767b 100644 --- a/internal/tools/cron_task.go +++ b/internal/tools/cron_task.go @@ -23,11 +23,10 @@ import ( "time" "github.com/OpenIMSDK/tools/errs" - "github.com/redis/go-redis/v9" - "github.com/robfig/cron/v3" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" + "github.com/redis/go-redis/v9" + "github.com/robfig/cron/v3" ) func StartTask() error { diff --git a/internal/tools/msg.go b/internal/tools/msg.go index 6d5a50b1e5..f2df0d3371 100644 --- a/internal/tools/msg.go +++ b/internal/tools/msg.go @@ -27,10 +27,6 @@ import ( "github.com/OpenIMSDK/tools/mw" "github.com/OpenIMSDK/tools/tx" "github.com/OpenIMSDK/tools/utils" - "github.com/redis/go-redis/v9" - "google.golang.org/grpc" - "google.golang.org/grpc/credentials/insecure" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" @@ -39,6 +35,9 @@ import ( kdisc "github.com/openimsdk/open-im-server/v3/pkg/common/discoveryregister" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient/notification" + "github.com/redis/go-redis/v9" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" ) type MsgTool struct { diff --git a/internal/tools/msg_doc_convert.go b/internal/tools/msg_doc_convert.go index b9150c3623..eea1b69e8a 100644 --- a/internal/tools/msg_doc_convert.go +++ b/internal/tools/msg_doc_convert.go @@ -18,7 +18,6 @@ import ( "github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/mcontext" - "github.com/openimsdk/open-im-server/v3/pkg/msgprocessor" ) diff --git a/pkg/authverify/token.go b/pkg/authverify/token.go index cfba2d8443..0a46af3ecf 100644 --- a/pkg/authverify/token.go +++ b/pkg/authverify/token.go @@ -23,7 +23,6 @@ import ( "github.com/OpenIMSDK/tools/tokenverify" "github.com/OpenIMSDK/tools/utils" "github.com/golang-jwt/jwt/v4" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" ) diff --git a/pkg/callbackstruct/group.go b/pkg/callbackstruct/group.go index 5968f1e557..467061a4aa 100644 --- a/pkg/callbackstruct/group.go +++ b/pkg/callbackstruct/group.go @@ -16,7 +16,6 @@ package callbackstruct import ( common "github.com/OpenIMSDK/protocol/sdkws" - "github.com/openimsdk/open-im-server/v3/pkg/apistruct" ) diff --git a/pkg/common/cmd/api.go b/pkg/common/cmd/api.go index 7156ce6c45..47e4116e39 100644 --- a/pkg/common/cmd/api.go +++ b/pkg/common/cmd/api.go @@ -19,9 +19,8 @@ import ( "fmt" "github.com/OpenIMSDK/protocol/constant" - "github.com/spf13/cobra" - config2 "github.com/openimsdk/open-im-server/v3/pkg/common/config" + "github.com/spf13/cobra" ) type ApiCmd struct { diff --git a/pkg/common/cmd/msg_gateway.go b/pkg/common/cmd/msg_gateway.go index 1543afe15f..403d0ec84d 100644 --- a/pkg/common/cmd/msg_gateway.go +++ b/pkg/common/cmd/msg_gateway.go @@ -19,10 +19,9 @@ import ( "github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/tools/errs" - "github.com/spf13/cobra" - "github.com/openimsdk/open-im-server/v3/internal/msggateway" v3config "github.com/openimsdk/open-im-server/v3/pkg/common/config" + "github.com/spf13/cobra" ) type MsgGatewayCmd struct { diff --git a/pkg/common/cmd/msg_transfer.go b/pkg/common/cmd/msg_transfer.go index 6ea2b86fa3..4db24fac54 100644 --- a/pkg/common/cmd/msg_transfer.go +++ b/pkg/common/cmd/msg_transfer.go @@ -18,10 +18,9 @@ import ( "fmt" "github.com/OpenIMSDK/protocol/constant" - "github.com/spf13/cobra" - "github.com/openimsdk/open-im-server/v3/internal/msgtransfer" config2 "github.com/openimsdk/open-im-server/v3/pkg/common/config" + "github.com/spf13/cobra" ) type MsgTransferCmd struct { diff --git a/pkg/common/cmd/msg_utils.go b/pkg/common/cmd/msg_utils.go index 3c670ad85a..03c1cab670 100644 --- a/pkg/common/cmd/msg_utils.go +++ b/pkg/common/cmd/msg_utils.go @@ -15,10 +15,9 @@ package cmd import ( - "github.com/spf13/cobra" - "github.com/openimsdk/open-im-server/v3/internal/tools" util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" + "github.com/spf13/cobra" ) type MsgUtilsCmd struct { diff --git a/pkg/common/cmd/root.go b/pkg/common/cmd/root.go index 69a2af950f..591bfc8049 100644 --- a/pkg/common/cmd/root.go +++ b/pkg/common/cmd/root.go @@ -20,10 +20,9 @@ import ( "github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/log" - "github.com/spf13/cobra" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" config2 "github.com/openimsdk/open-im-server/v3/pkg/common/config" + "github.com/spf13/cobra" ) type RootCmdPt interface { diff --git a/pkg/common/cmd/rpc.go b/pkg/common/cmd/rpc.go index d78233cbcc..e30de93a99 100644 --- a/pkg/common/cmd/rpc.go +++ b/pkg/common/cmd/rpc.go @@ -21,11 +21,10 @@ import ( "github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/tools/discoveryregistry" "github.com/OpenIMSDK/tools/errs" - "github.com/spf13/cobra" - "google.golang.org/grpc" - config2 "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/startrpc" + "github.com/spf13/cobra" + "google.golang.org/grpc" ) type RpcCmd struct { diff --git a/pkg/common/config/parse.go b/pkg/common/config/parse.go index e216f6014f..a73665386a 100644 --- a/pkg/common/config/parse.go +++ b/pkg/common/config/parse.go @@ -22,10 +22,9 @@ import ( "github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/tools/errs" - "gopkg.in/yaml.v3" - "github.com/openimsdk/open-im-server/v3/pkg/msgprocessor" "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" + "gopkg.in/yaml.v3" ) //go:embed version diff --git a/pkg/common/convert/black.go b/pkg/common/convert/black.go index 57140f4361..683517fbca 100644 --- a/pkg/common/convert/black.go +++ b/pkg/common/convert/black.go @@ -19,7 +19,6 @@ import ( "github.com/OpenIMSDK/protocol/sdkws" sdk "github.com/OpenIMSDK/protocol/sdkws" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" ) diff --git a/pkg/common/convert/conversation.go b/pkg/common/convert/conversation.go index 165262b7f9..b3f4913ebb 100644 --- a/pkg/common/convert/conversation.go +++ b/pkg/common/convert/conversation.go @@ -17,7 +17,6 @@ package convert import ( "github.com/OpenIMSDK/protocol/conversation" "github.com/OpenIMSDK/tools/utils" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" ) diff --git a/pkg/common/convert/friend.go b/pkg/common/convert/friend.go index 0e9a057663..4231eb49d1 100644 --- a/pkg/common/convert/friend.go +++ b/pkg/common/convert/friend.go @@ -20,7 +20,6 @@ import ( "github.com/OpenIMSDK/protocol/sdkws" "github.com/OpenIMSDK/tools/utils" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" ) @@ -53,7 +52,11 @@ func FriendDB2Pb(ctx context.Context, friendDB *relation.FriendModel, }, nil } -func FriendsDB2Pb(ctx context.Context, friendsDB []*relation.FriendModel, getUsers func(ctx context.Context, userIDs []string) (map[string]*sdkws.UserInfo, error)) (friendsPb []*sdkws.FriendInfo, err error) { +func FriendsDB2Pb( + ctx context.Context, + friendsDB []*relation.FriendModel, + getUsers func(ctx context.Context, userIDs []string) (map[string]*sdkws.UserInfo, error), +) (friendsPb []*sdkws.FriendInfo, err error) { if len(friendsDB) == 0 { return nil, nil } diff --git a/pkg/common/convert/group.go b/pkg/common/convert/group.go index 18940f5189..63372f21dc 100644 --- a/pkg/common/convert/group.go +++ b/pkg/common/convert/group.go @@ -19,7 +19,6 @@ import ( pbgroup "github.com/OpenIMSDK/protocol/group" sdkws "github.com/OpenIMSDK/protocol/sdkws" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" ) diff --git a/pkg/common/convert/msg.go b/pkg/common/convert/msg.go index 56f71f0183..34638049b2 100644 --- a/pkg/common/convert/msg.go +++ b/pkg/common/convert/msg.go @@ -17,7 +17,6 @@ package convert import ( "github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/protocol/sdkws" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/unrelation" ) diff --git a/pkg/common/convert/user.go b/pkg/common/convert/user.go index 62f80e458d..38afd8c199 100644 --- a/pkg/common/convert/user.go +++ b/pkg/common/convert/user.go @@ -18,7 +18,6 @@ import ( "time" "github.com/OpenIMSDK/protocol/sdkws" - relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" ) diff --git a/pkg/common/db/cache/black.go b/pkg/common/db/cache/black.go index 48bc3c2853..c8cf2ddd38 100644 --- a/pkg/common/db/cache/black.go +++ b/pkg/common/db/cache/black.go @@ -19,9 +19,8 @@ import ( "time" "github.com/dtm-labs/rockscache" - "github.com/redis/go-redis/v9" - relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" + "github.com/redis/go-redis/v9" ) const ( diff --git a/pkg/common/db/cache/conversation.go b/pkg/common/db/cache/conversation.go index c8cc11923b..90e4003638 100644 --- a/pkg/common/db/cache/conversation.go +++ b/pkg/common/db/cache/conversation.go @@ -22,9 +22,8 @@ import ( "github.com/OpenIMSDK/tools/utils" "github.com/dtm-labs/rockscache" - "github.com/redis/go-redis/v9" - relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" + "github.com/redis/go-redis/v9" ) const ( diff --git a/pkg/common/db/cache/friend.go b/pkg/common/db/cache/friend.go index 91faddaf95..a160837ba2 100644 --- a/pkg/common/db/cache/friend.go +++ b/pkg/common/db/cache/friend.go @@ -20,9 +20,8 @@ import ( "github.com/OpenIMSDK/tools/utils" "github.com/dtm-labs/rockscache" - "github.com/redis/go-redis/v9" - relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" + "github.com/redis/go-redis/v9" ) const ( diff --git a/pkg/common/db/cache/group.go b/pkg/common/db/cache/group.go index 0acf95ed4f..4a5266db5d 100644 --- a/pkg/common/db/cache/group.go +++ b/pkg/common/db/cache/group.go @@ -25,9 +25,8 @@ import ( "github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/utils" "github.com/dtm-labs/rockscache" - "github.com/redis/go-redis/v9" - relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" + "github.com/redis/go-redis/v9" ) const ( diff --git a/pkg/common/db/cache/init_redis.go b/pkg/common/db/cache/init_redis.go index 24de092b05..b81edf9e58 100644 --- a/pkg/common/db/cache/init_redis.go +++ b/pkg/common/db/cache/init_redis.go @@ -24,9 +24,8 @@ import ( "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/mw/specialerror" - "github.com/redis/go-redis/v9" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" + "github.com/redis/go-redis/v9" ) var ( diff --git a/pkg/common/db/cache/meta_cache.go b/pkg/common/db/cache/meta_cache.go index 5f05ff1660..4c25754d6b 100644 --- a/pkg/common/db/cache/meta_cache.go +++ b/pkg/common/db/cache/meta_cache.go @@ -194,7 +194,14 @@ func getCache[T any](ctx context.Context, rcClient *rockscache.Client, key strin // return tArrays, nil //} -func batchGetCache2[T any, K comparable](ctx context.Context, rcClient *rockscache.Client, expire time.Duration, keys []K, keyFn func(key K) string, fns func(ctx context.Context, key K) (T, error)) ([]T, error) { +func batchGetCache2[T any, K comparable]( + ctx context.Context, + rcClient *rockscache.Client, + expire time.Duration, + keys []K, + keyFn func(key K) string, + fns func(ctx context.Context, key K) (T, error), +) ([]T, error) { if len(keys) == 0 { return nil, nil } diff --git a/pkg/common/db/cache/msg.go b/pkg/common/db/cache/msg.go index 09c456ab3f..889f36baa9 100644 --- a/pkg/common/db/cache/msg.go +++ b/pkg/common/db/cache/msg.go @@ -26,11 +26,10 @@ import ( "github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/utils" "github.com/gogo/protobuf/jsonpb" - "github.com/redis/go-redis/v9" - "golang.org/x/sync/errgroup" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/msgprocessor" + "github.com/redis/go-redis/v9" + "golang.org/x/sync/errgroup" ) const ( diff --git a/pkg/common/db/cache/s3.go b/pkg/common/db/cache/s3.go index 1e68cedf8c..28e993be09 100644 --- a/pkg/common/db/cache/s3.go +++ b/pkg/common/db/cache/s3.go @@ -20,10 +20,9 @@ import ( "time" "github.com/dtm-labs/rockscache" - "github.com/redis/go-redis/v9" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/s3" relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" + "github.com/redis/go-redis/v9" ) type ObjectCache interface { diff --git a/pkg/common/db/cache/user.go b/pkg/common/db/cache/user.go index 11c46b5aca..c6c6966f3e 100644 --- a/pkg/common/db/cache/user.go +++ b/pkg/common/db/cache/user.go @@ -27,9 +27,8 @@ import ( "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/log" "github.com/dtm-labs/rockscache" - "github.com/redis/go-redis/v9" - relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" + "github.com/redis/go-redis/v9" ) const ( diff --git a/pkg/common/db/controller/auth.go b/pkg/common/db/controller/auth.go index 04c5d2617c..dfd7b3e78f 100644 --- a/pkg/common/db/controller/auth.go +++ b/pkg/common/db/controller/auth.go @@ -21,7 +21,6 @@ import ( "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/tokenverify" "github.com/golang-jwt/jwt/v4" - "github.com/openimsdk/open-im-server/v3/pkg/authverify" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" ) diff --git a/pkg/common/db/controller/black.go b/pkg/common/db/controller/black.go index 427194ecd6..c4b253c2f7 100644 --- a/pkg/common/db/controller/black.go +++ b/pkg/common/db/controller/black.go @@ -20,7 +20,6 @@ import ( "github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/pagination" "github.com/OpenIMSDK/tools/utils" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" ) diff --git a/pkg/common/db/controller/conversation.go b/pkg/common/db/controller/conversation.go index bf4349cf46..3d46e4fbc4 100644 --- a/pkg/common/db/controller/conversation.go +++ b/pkg/common/db/controller/conversation.go @@ -23,7 +23,6 @@ import ( "github.com/OpenIMSDK/tools/pagination" "github.com/OpenIMSDK/tools/tx" "github.com/OpenIMSDK/tools/utils" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" "github.com/openimsdk/open-im-server/v3/pkg/msgprocessor" @@ -42,7 +41,8 @@ type ConversationDatabase interface { GetUserAllConversation(ctx context.Context, ownerUserID string) ([]*relationtb.ConversationModel, error) // SetUserConversations sets multiple conversation properties for a user, creates new conversations if they do not exist, or updates them otherwise. This operation is atomic. SetUserConversations(ctx context.Context, ownerUserID string, conversations []*relationtb.ConversationModel) error - // SetUsersConversationFieldTx updates a specific field for multiple users' conversations, creating new conversations if they do not exist, or updates them otherwise. This operation is transactional. + // SetUsersConversationFieldTx updates a specific field for multiple users' conversations, creating new conversations if they do not exist, or updates them otherwise. This operation is + // transactional. SetUsersConversationFieldTx(ctx context.Context, userIDs []string, conversation *relationtb.ConversationModel, fieldMap map[string]any) error // CreateGroupChatConversation creates a group chat conversation for the specified group ID and user IDs. CreateGroupChatConversation(ctx context.Context, groupID string, userIDs []string) error diff --git a/pkg/common/db/controller/friend.go b/pkg/common/db/controller/friend.go index 24504c2272..3c81d922ce 100644 --- a/pkg/common/db/controller/friend.go +++ b/pkg/common/db/controller/friend.go @@ -26,7 +26,6 @@ import ( "github.com/OpenIMSDK/tools/pagination" "github.com/OpenIMSDK/tools/tx" "github.com/OpenIMSDK/tools/utils" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" ) diff --git a/pkg/common/db/controller/group.go b/pkg/common/db/controller/group.go index 2f2a972e4e..45bf87b6f1 100644 --- a/pkg/common/db/controller/group.go +++ b/pkg/common/db/controller/group.go @@ -23,10 +23,9 @@ import ( "github.com/OpenIMSDK/tools/tx" "github.com/OpenIMSDK/tools/utils" "github.com/dtm-labs/rockscache" - "github.com/redis/go-redis/v9" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" + "github.com/redis/go-redis/v9" ) type GroupDatabase interface { diff --git a/pkg/common/db/controller/msg.go b/pkg/common/db/controller/msg.go index 07b540ec08..56cb527035 100644 --- a/pkg/common/db/controller/msg.go +++ b/pkg/common/db/controller/msg.go @@ -26,9 +26,6 @@ import ( "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/utils" - "github.com/redis/go-redis/v9" - "go.mongodb.org/mongo-driver/mongo" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/convert" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" @@ -36,6 +33,8 @@ import ( "github.com/openimsdk/open-im-server/v3/pkg/common/db/unrelation" "github.com/openimsdk/open-im-server/v3/pkg/common/kafka" "github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics" + "github.com/redis/go-redis/v9" + "go.mongodb.org/mongo-driver/mongo" ) const ( @@ -61,7 +60,8 @@ type CommonMsgDatabase interface { GetMsgBySeqsRange(ctx context.Context, userID string, conversationID string, begin, end, num, userMaxSeq int64) (minSeq int64, maxSeq int64, seqMsg []*sdkws.MsgData, err error) // GetMsgBySeqs retrieves messages for large groups from MongoDB by sequence numbers. GetMsgBySeqs(ctx context.Context, userID string, conversationID string, seqs []int64) (minSeq int64, maxSeq int64, seqMsg []*sdkws.MsgData, err error) - // DeleteConversationMsgsAndSetMinSeq deletes conversation messages and resets the minimum sequence number. If `remainTime` is 0, all messages are deleted (this method does not delete Redis cache). + // DeleteConversationMsgsAndSetMinSeq deletes conversation messages and resets the minimum sequence number. If `remainTime` is 0, all messages are deleted (this method does not delete Redis + // cache). DeleteConversationMsgsAndSetMinSeq(ctx context.Context, conversationID string, remainTime int64) error // UserMsgsDestruct marks messages for deletion based on destruct time and returns a list of sequence numbers for marked messages. UserMsgsDestruct(ctx context.Context, userID string, conversationID string, destructTime int64, lastMsgDestructTime time.Time) (seqs []int64, err error) diff --git a/pkg/common/db/controller/s3.go b/pkg/common/db/controller/s3.go index 95505de417..e847c9c8ff 100644 --- a/pkg/common/db/controller/s3.go +++ b/pkg/common/db/controller/s3.go @@ -19,12 +19,11 @@ import ( "path/filepath" "time" - "github.com/redis/go-redis/v9" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" "github.com/openimsdk/open-im-server/v3/pkg/common/db/s3" "github.com/openimsdk/open-im-server/v3/pkg/common/db/s3/cont" "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" + "github.com/redis/go-redis/v9" ) type S3Database interface { diff --git a/pkg/common/db/controller/third.go b/pkg/common/db/controller/third.go index 55c047bd63..996d82c452 100644 --- a/pkg/common/db/controller/third.go +++ b/pkg/common/db/controller/third.go @@ -19,7 +19,6 @@ import ( "time" "github.com/OpenIMSDK/tools/pagination" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" ) diff --git a/pkg/common/db/controller/user.go b/pkg/common/db/controller/user.go index c18fef3168..0e1bdd3147 100644 --- a/pkg/common/db/controller/user.go +++ b/pkg/common/db/controller/user.go @@ -23,7 +23,6 @@ import ( "github.com/OpenIMSDK/tools/pagination" "github.com/OpenIMSDK/tools/tx" "github.com/OpenIMSDK/tools/utils" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" unrelationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/unrelation" diff --git a/pkg/common/db/localcache/conversation.go b/pkg/common/db/localcache/conversation.go index c40bcdbce6..9147fd3ce0 100644 --- a/pkg/common/db/localcache/conversation.go +++ b/pkg/common/db/localcache/conversation.go @@ -19,7 +19,6 @@ import ( "sync" "github.com/OpenIMSDK/protocol/conversation" - "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" ) diff --git a/pkg/common/db/localcache/group.go b/pkg/common/db/localcache/group.go index 4958d91eee..0fdea86424 100644 --- a/pkg/common/db/localcache/group.go +++ b/pkg/common/db/localcache/group.go @@ -20,7 +20,6 @@ import ( "github.com/OpenIMSDK/protocol/group" "github.com/OpenIMSDK/tools/errs" - "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" ) diff --git a/pkg/common/db/mgo/black.go b/pkg/common/db/mgo/black.go index 1047e5c30e..c555e0b776 100644 --- a/pkg/common/db/mgo/black.go +++ b/pkg/common/db/mgo/black.go @@ -19,11 +19,10 @@ import ( "github.com/OpenIMSDK/tools/mgoutil" "github.com/OpenIMSDK/tools/pagination" + "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo/options" - - "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" ) func NewBlackMongo(db *mongo.Database) (relation.BlackModelInterface, error) { diff --git a/pkg/common/db/mgo/conversation.go b/pkg/common/db/mgo/conversation.go index 93ca4eceb6..35e8a28e6a 100644 --- a/pkg/common/db/mgo/conversation.go +++ b/pkg/common/db/mgo/conversation.go @@ -22,11 +22,10 @@ import ( "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/mgoutil" "github.com/OpenIMSDK/tools/pagination" + "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo/options" - - "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" ) func NewConversationMongo(db *mongo.Database) (*ConversationMgo, error) { diff --git a/pkg/common/db/mgo/friend.go b/pkg/common/db/mgo/friend.go index 01719822d3..aa7775ce04 100644 --- a/pkg/common/db/mgo/friend.go +++ b/pkg/common/db/mgo/friend.go @@ -19,11 +19,10 @@ import ( "github.com/OpenIMSDK/tools/mgoutil" "github.com/OpenIMSDK/tools/pagination" + "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo/options" - - "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" ) // FriendMgo implements FriendModelInterface using MongoDB as the storage backend. diff --git a/pkg/common/db/mgo/friend_request.go b/pkg/common/db/mgo/friend_request.go index a05ca10184..3e0588a0b6 100644 --- a/pkg/common/db/mgo/friend_request.go +++ b/pkg/common/db/mgo/friend_request.go @@ -19,11 +19,10 @@ import ( "github.com/OpenIMSDK/tools/mgoutil" "github.com/OpenIMSDK/tools/pagination" + "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo/options" - - "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" ) func NewFriendRequestMongo(db *mongo.Database) (relation.FriendRequestModelInterface, error) { diff --git a/pkg/common/db/mgo/group.go b/pkg/common/db/mgo/group.go index cfb104a21d..1bef90ebeb 100644 --- a/pkg/common/db/mgo/group.go +++ b/pkg/common/db/mgo/group.go @@ -21,11 +21,10 @@ import ( "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/mgoutil" "github.com/OpenIMSDK/tools/pagination" + "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo/options" - - "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" ) func NewGroupMongo(db *mongo.Database) (relation.GroupModelInterface, error) { diff --git a/pkg/common/db/mgo/group_member.go b/pkg/common/db/mgo/group_member.go index 5d3331baa4..e1af34f7c1 100644 --- a/pkg/common/db/mgo/group_member.go +++ b/pkg/common/db/mgo/group_member.go @@ -21,11 +21,10 @@ import ( "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/mgoutil" "github.com/OpenIMSDK/tools/pagination" + "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo/options" - - "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" ) func NewGroupMember(db *mongo.Database) (relation.GroupMemberModelInterface, error) { diff --git a/pkg/common/db/mgo/group_request.go b/pkg/common/db/mgo/group_request.go index 87fba16369..9aee0e9605 100644 --- a/pkg/common/db/mgo/group_request.go +++ b/pkg/common/db/mgo/group_request.go @@ -20,11 +20,10 @@ import ( "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/mgoutil" "github.com/OpenIMSDK/tools/pagination" + "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo/options" - - "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" ) func NewGroupRequestMgo(db *mongo.Database) (relation.GroupRequestModelInterface, error) { diff --git a/pkg/common/db/mgo/log.go b/pkg/common/db/mgo/log.go index 09f002ee3f..ca28d5964b 100644 --- a/pkg/common/db/mgo/log.go +++ b/pkg/common/db/mgo/log.go @@ -20,11 +20,10 @@ import ( "github.com/OpenIMSDK/tools/mgoutil" "github.com/OpenIMSDK/tools/pagination" + "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo/options" - - "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" ) func NewLogMongo(db *mongo.Database) (relation.LogInterface, error) { diff --git a/pkg/common/db/mgo/object.go b/pkg/common/db/mgo/object.go index 88bfde2132..4c333afd61 100644 --- a/pkg/common/db/mgo/object.go +++ b/pkg/common/db/mgo/object.go @@ -18,11 +18,10 @@ import ( "context" "github.com/OpenIMSDK/tools/mgoutil" + "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo/options" - - "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" ) func NewS3Mongo(db *mongo.Database) (relation.ObjectInfoModelInterface, error) { diff --git a/pkg/common/db/mgo/user.go b/pkg/common/db/mgo/user.go index df26776ac6..dcdc14d4a0 100644 --- a/pkg/common/db/mgo/user.go +++ b/pkg/common/db/mgo/user.go @@ -22,12 +22,11 @@ import ( "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/mgoutil" "github.com/OpenIMSDK/tools/pagination" + "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" "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" - - "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" ) func NewUserMongo(db *mongo.Database) (relation.UserModelInterface, error) { diff --git a/pkg/common/db/s3/aws/aws.go b/pkg/common/db/s3/aws/aws.go index 7588eea91b..dd54ed1559 100644 --- a/pkg/common/db/s3/aws/aws.go +++ b/pkg/common/db/s3/aws/aws.go @@ -27,7 +27,6 @@ import ( "github.com/aws/aws-sdk-go/aws/credentials" "github.com/aws/aws-sdk-go/aws/session" sdk "github.com/aws/aws-sdk-go/service/s3" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/db/s3" ) diff --git a/pkg/common/db/s3/cont/controller.go b/pkg/common/db/s3/cont/controller.go index 0a40d8f361..915109aa51 100644 --- a/pkg/common/db/s3/cont/controller.go +++ b/pkg/common/db/s3/cont/controller.go @@ -27,7 +27,6 @@ import ( "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/log" "github.com/google/uuid" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" "github.com/openimsdk/open-im-server/v3/pkg/common/db/s3" ) diff --git a/pkg/common/db/s3/cos/cos.go b/pkg/common/db/s3/cos/cos.go index b302f1de6b..619f142abe 100644 --- a/pkg/common/db/s3/cos/cos.go +++ b/pkg/common/db/s3/cos/cos.go @@ -29,10 +29,9 @@ import ( "strings" "time" - "github.com/tencentyun/cos-go-sdk-v5" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/db/s3" + "github.com/tencentyun/cos-go-sdk-v5" ) const ( diff --git a/pkg/common/db/s3/minio/minio.go b/pkg/common/db/s3/minio/minio.go index a5e34e1aa7..1eb3257e11 100644 --- a/pkg/common/db/s3/minio/minio.go +++ b/pkg/common/db/s3/minio/minio.go @@ -33,7 +33,6 @@ import ( "github.com/minio/minio-go/v7" "github.com/minio/minio-go/v7/pkg/credentials" "github.com/minio/minio-go/v7/pkg/signer" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" "github.com/openimsdk/open-im-server/v3/pkg/common/db/s3" diff --git a/pkg/common/db/s3/minio/thumbnail.go b/pkg/common/db/s3/minio/thumbnail.go index 5dfdaee094..1bf96c27c9 100644 --- a/pkg/common/db/s3/minio/thumbnail.go +++ b/pkg/common/db/s3/minio/thumbnail.go @@ -31,7 +31,6 @@ import ( "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/log" "github.com/minio/minio-go/v7" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" "github.com/openimsdk/open-im-server/v3/pkg/common/db/s3" ) diff --git a/pkg/common/db/s3/oss/oss.go b/pkg/common/db/s3/oss/oss.go index a6be41d394..442f4e52fa 100644 --- a/pkg/common/db/s3/oss/oss.go +++ b/pkg/common/db/s3/oss/oss.go @@ -32,7 +32,6 @@ import ( "github.com/OpenIMSDK/tools/errs" "github.com/aliyun/aliyun-oss-go-sdk/oss" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/db/s3" ) diff --git a/pkg/common/db/unrelation/mongo.go b/pkg/common/db/unrelation/mongo.go index 25bf4d10c4..09880fb374 100644 --- a/pkg/common/db/unrelation/mongo.go +++ b/pkg/common/db/unrelation/mongo.go @@ -23,12 +23,11 @@ import ( "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/mw/specialerror" + "github.com/openimsdk/open-im-server/v3/pkg/common/config" + "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/unrelation" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo/options" - - "github.com/openimsdk/open-im-server/v3/pkg/common/config" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/unrelation" ) const ( diff --git a/pkg/common/db/unrelation/msg.go b/pkg/common/db/unrelation/msg.go index 0e33970c34..4deca56f80 100644 --- a/pkg/common/db/unrelation/msg.go +++ b/pkg/common/db/unrelation/msg.go @@ -26,13 +26,12 @@ import ( "github.com/OpenIMSDK/protocol/sdkws" "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/log" + table "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/unrelation" "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" "google.golang.org/protobuf/proto" - - table "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/unrelation" ) var ErrMsgListNotExist = errors.New("user not have msg in mongoDB") diff --git a/pkg/common/db/unrelation/msg_convert.go b/pkg/common/db/unrelation/msg_convert.go index 373bc843e6..30c74e927b 100644 --- a/pkg/common/db/unrelation/msg_convert.go +++ b/pkg/common/db/unrelation/msg_convert.go @@ -19,10 +19,9 @@ import ( "fmt" "github.com/OpenIMSDK/tools/log" + table "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/unrelation" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" - - table "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/unrelation" ) func (m *MsgMongoDriver) ConvertMsgsDocLen(ctx context.Context, conversationIDs []string) { diff --git a/pkg/common/db/unrelation/user.go b/pkg/common/db/unrelation/user.go index 4c882fc645..cbf395bf84 100644 --- a/pkg/common/db/unrelation/user.go +++ b/pkg/common/db/unrelation/user.go @@ -18,11 +18,10 @@ import ( "context" "github.com/OpenIMSDK/tools/errs" + "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/unrelation" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo/options" - - "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/unrelation" ) // prefixes and suffixes. diff --git a/pkg/common/discoveryregister/direct/directconn.go b/pkg/common/discoveryregister/direct/directconn.go index cc59934a39..2ae0de170b 100644 --- a/pkg/common/discoveryregister/direct/directconn.go +++ b/pkg/common/discoveryregister/direct/directconn.go @@ -20,10 +20,9 @@ import ( "fmt" "github.com/OpenIMSDK/tools/errs" + config2 "github.com/openimsdk/open-im-server/v3/pkg/common/config" "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" - - config2 "github.com/openimsdk/open-im-server/v3/pkg/common/config" ) type ServiceAddresses map[string][]int diff --git a/pkg/common/discoveryregister/discoveryregister.go b/pkg/common/discoveryregister/discoveryregister.go index 18684c3499..a21d8d62ac 100644 --- a/pkg/common/discoveryregister/discoveryregister.go +++ b/pkg/common/discoveryregister/discoveryregister.go @@ -20,7 +20,6 @@ import ( "github.com/OpenIMSDK/tools/discoveryregistry" "github.com/OpenIMSDK/tools/errs" - "github.com/openimsdk/open-im-server/v3/pkg/common/discoveryregister/direct" "github.com/openimsdk/open-im-server/v3/pkg/common/discoveryregister/kubernetes" "github.com/openimsdk/open-im-server/v3/pkg/common/discoveryregister/zookeeper" diff --git a/pkg/common/discoveryregister/kubernetes/kubernetes.go b/pkg/common/discoveryregister/kubernetes/kubernetes.go index 59a78a336b..1292c64a87 100644 --- a/pkg/common/discoveryregister/kubernetes/kubernetes.go +++ b/pkg/common/discoveryregister/kubernetes/kubernetes.go @@ -24,10 +24,9 @@ import ( "github.com/OpenIMSDK/tools/discoveryregistry" "github.com/OpenIMSDK/tools/log" + "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/stathat/consistent" "google.golang.org/grpc" - - "github.com/openimsdk/open-im-server/v3/pkg/common/config" ) // K8sDR represents the Kubernetes service discovery and registration client. diff --git a/pkg/common/discoveryregister/zookeeper/zookeeper.go b/pkg/common/discoveryregister/zookeeper/zookeeper.go index 099badf420..5f9a3b6bda 100644 --- a/pkg/common/discoveryregister/zookeeper/zookeeper.go +++ b/pkg/common/discoveryregister/zookeeper/zookeeper.go @@ -24,7 +24,6 @@ import ( openkeeper "github.com/OpenIMSDK/tools/discoveryregistry/zookeeper" "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/log" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" ) diff --git a/pkg/common/http/http_client.go b/pkg/common/http/http_client.go index 141284b645..83908b8d33 100644 --- a/pkg/common/http/http_client.go +++ b/pkg/common/http/http_client.go @@ -25,7 +25,6 @@ import ( "github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/log" - "github.com/openimsdk/open-im-server/v3/pkg/callbackstruct" "github.com/openimsdk/open-im-server/v3/pkg/common/config" ) diff --git a/pkg/common/kafka/consumer_group.go b/pkg/common/kafka/consumer_group.go index f8b3ee2496..824c5be2e0 100644 --- a/pkg/common/kafka/consumer_group.go +++ b/pkg/common/kafka/consumer_group.go @@ -22,7 +22,6 @@ import ( "github.com/IBM/sarama" "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/log" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" ) diff --git a/pkg/common/kafka/producer.go b/pkg/common/kafka/producer.go index 19ff198289..4c2378c59e 100644 --- a/pkg/common/kafka/producer.go +++ b/pkg/common/kafka/producer.go @@ -27,9 +27,8 @@ import ( "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/mcontext" - "google.golang.org/protobuf/proto" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" + "google.golang.org/protobuf/proto" ) const maxRetry = 10 // number of retries diff --git a/pkg/common/kafka/util.go b/pkg/common/kafka/util.go index 578a308efc..a94397819b 100644 --- a/pkg/common/kafka/util.go +++ b/pkg/common/kafka/util.go @@ -20,7 +20,6 @@ import ( "strings" "github.com/IBM/sarama" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/tls" ) diff --git a/pkg/common/prommetrics/prommetrics.go b/pkg/common/prommetrics/prommetrics.go index 1ed13a1ef3..52694168f9 100644 --- a/pkg/common/prommetrics/prommetrics.go +++ b/pkg/common/prommetrics/prommetrics.go @@ -16,11 +16,10 @@ package prommetrics import ( gp "github.com/grpc-ecosystem/go-grpc-prometheus" - "github.com/prometheus/client_golang/prometheus" - "github.com/prometheus/client_golang/prometheus/collectors" - config2 "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/ginprometheus" + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/collectors" ) func NewGrpcPromObj(cusMetrics []prometheus.Collector) (*prometheus.Registry, *gp.ServerMetrics, error) { diff --git a/pkg/common/startrpc/start.go b/pkg/common/startrpc/start.go index 07b50070f8..1576762e8c 100644 --- a/pkg/common/startrpc/start.go +++ b/pkg/common/startrpc/start.go @@ -32,15 +32,14 @@ import ( "github.com/OpenIMSDK/tools/mw" "github.com/OpenIMSDK/tools/network" grpcprometheus "github.com/grpc-ecosystem/go-grpc-prometheus" - "github.com/prometheus/client_golang/prometheus" - "github.com/prometheus/client_golang/prometheus/promhttp" - "google.golang.org/grpc" - "google.golang.org/grpc/credentials/insecure" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" kdisc "github.com/openimsdk/open-im-server/v3/pkg/common/discoveryregister" "github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics" util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/promhttp" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" ) // Start rpc server. diff --git a/pkg/common/tls/tls.go b/pkg/common/tls/tls.go index e897c13b67..a52f46df72 100644 --- a/pkg/common/tls/tls.go +++ b/pkg/common/tls/tls.go @@ -22,7 +22,6 @@ import ( "os" "github.com/OpenIMSDK/tools/errs" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" ) diff --git a/pkg/rpcclient/auth.go b/pkg/rpcclient/auth.go index 387acf320a..bfd4b1119f 100644 --- a/pkg/rpcclient/auth.go +++ b/pkg/rpcclient/auth.go @@ -19,10 +19,9 @@ import ( "github.com/OpenIMSDK/protocol/auth" "github.com/OpenIMSDK/tools/discoveryregistry" - "google.golang.org/grpc" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" + "google.golang.org/grpc" ) func NewAuth(discov discoveryregistry.SvcDiscoveryRegistry) *Auth { diff --git a/pkg/rpcclient/conversation.go b/pkg/rpcclient/conversation.go index 926c571a47..ee9818f8fc 100644 --- a/pkg/rpcclient/conversation.go +++ b/pkg/rpcclient/conversation.go @@ -21,10 +21,9 @@ import ( pbconversation "github.com/OpenIMSDK/protocol/conversation" "github.com/OpenIMSDK/tools/discoveryregistry" "github.com/OpenIMSDK/tools/errs" - "google.golang.org/grpc" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" + "google.golang.org/grpc" ) type Conversation struct { diff --git a/pkg/rpcclient/friend.go b/pkg/rpcclient/friend.go index a0e0226ec7..5206165645 100644 --- a/pkg/rpcclient/friend.go +++ b/pkg/rpcclient/friend.go @@ -20,10 +20,9 @@ import ( "github.com/OpenIMSDK/protocol/friend" sdkws "github.com/OpenIMSDK/protocol/sdkws" "github.com/OpenIMSDK/tools/discoveryregistry" - "google.golang.org/grpc" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" + "google.golang.org/grpc" ) type Friend struct { diff --git a/pkg/rpcclient/group.go b/pkg/rpcclient/group.go index 7a15c11160..bc9a3c75c3 100644 --- a/pkg/rpcclient/group.go +++ b/pkg/rpcclient/group.go @@ -24,10 +24,9 @@ import ( "github.com/OpenIMSDK/tools/discoveryregistry" "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/utils" - "google.golang.org/grpc" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" + "google.golang.org/grpc" ) type Group struct { diff --git a/pkg/rpcclient/msg.go b/pkg/rpcclient/msg.go index f468a65692..e4008ed200 100644 --- a/pkg/rpcclient/msg.go +++ b/pkg/rpcclient/msg.go @@ -24,10 +24,9 @@ import ( "github.com/OpenIMSDK/tools/discoveryregistry" "github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/utils" + "github.com/openimsdk/open-im-server/v3/pkg/common/config" "google.golang.org/grpc" "google.golang.org/protobuf/proto" - - "github.com/openimsdk/open-im-server/v3/pkg/common/config" ) func newContentTypeConf() map[int32]config.NotificationConf { diff --git a/pkg/rpcclient/notification/conversation.go b/pkg/rpcclient/notification/conversation.go index 3bbad746e0..b43e5494a9 100644 --- a/pkg/rpcclient/notification/conversation.go +++ b/pkg/rpcclient/notification/conversation.go @@ -19,7 +19,6 @@ import ( "github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/protocol/sdkws" - "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" ) diff --git a/pkg/rpcclient/notification/friend.go b/pkg/rpcclient/notification/friend.go index ba7a77c55f..9237111be8 100644 --- a/pkg/rpcclient/notification/friend.go +++ b/pkg/rpcclient/notification/friend.go @@ -21,7 +21,6 @@ import ( pbfriend "github.com/OpenIMSDK/protocol/friend" "github.com/OpenIMSDK/protocol/sdkws" "github.com/OpenIMSDK/tools/mcontext" - "github.com/openimsdk/open-im-server/v3/pkg/common/convert" "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" diff --git a/pkg/rpcclient/notification/group.go b/pkg/rpcclient/notification/group.go index 8b355b663c..1778a498d3 100644 --- a/pkg/rpcclient/notification/group.go +++ b/pkg/rpcclient/notification/group.go @@ -25,7 +25,6 @@ import ( "github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/mcontext" "github.com/OpenIMSDK/tools/utils" - "github.com/openimsdk/open-im-server/v3/pkg/authverify" "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" diff --git a/pkg/rpcclient/notification/msg.go b/pkg/rpcclient/notification/msg.go index 60fa64f404..83280f80a6 100644 --- a/pkg/rpcclient/notification/msg.go +++ b/pkg/rpcclient/notification/msg.go @@ -19,7 +19,6 @@ import ( "github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/protocol/sdkws" - "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" ) diff --git a/pkg/rpcclient/notification/user.go b/pkg/rpcclient/notification/user.go index 13e5b6abb6..f94e59a33b 100644 --- a/pkg/rpcclient/notification/user.go +++ b/pkg/rpcclient/notification/user.go @@ -19,7 +19,6 @@ import ( "github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/protocol/sdkws" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" diff --git a/pkg/rpcclient/push.go b/pkg/rpcclient/push.go index 20296e6cdb..2f540da81d 100644 --- a/pkg/rpcclient/push.go +++ b/pkg/rpcclient/push.go @@ -19,10 +19,9 @@ import ( "github.com/OpenIMSDK/protocol/push" "github.com/OpenIMSDK/tools/discoveryregistry" - "google.golang.org/grpc" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" + "google.golang.org/grpc" ) type Push struct { diff --git a/pkg/rpcclient/third.go b/pkg/rpcclient/third.go index f6ca458fd9..be40335d5c 100644 --- a/pkg/rpcclient/third.go +++ b/pkg/rpcclient/third.go @@ -23,10 +23,9 @@ import ( "github.com/OpenIMSDK/tools/errs" "github.com/minio/minio-go/v7" "github.com/minio/minio-go/v7/pkg/credentials" - "google.golang.org/grpc" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" + "google.golang.org/grpc" ) type Third struct { diff --git a/pkg/rpcclient/user.go b/pkg/rpcclient/user.go index 8d0f7fc8b0..a6c2021297 100644 --- a/pkg/rpcclient/user.go +++ b/pkg/rpcclient/user.go @@ -23,11 +23,10 @@ import ( "github.com/OpenIMSDK/tools/discoveryregistry" "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/utils" - "google.golang.org/grpc" - "github.com/openimsdk/open-im-server/v3/pkg/authverify" "github.com/openimsdk/open-im-server/v3/pkg/common/config" util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" + "google.golang.org/grpc" ) // User represents a structure holding connection details for the User RPC client. diff --git a/test/e2e/page/chat_page.go b/test/e2e/page/chat_page.go index 52aa8377d3..d92c7ec6e7 100644 --- a/test/e2e/page/chat_page.go +++ b/test/e2e/page/chat_page.go @@ -1 +1,15 @@ +// 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 page diff --git a/test/e2e/page/login_page.go b/test/e2e/page/login_page.go index 52aa8377d3..d92c7ec6e7 100644 --- a/test/e2e/page/login_page.go +++ b/test/e2e/page/login_page.go @@ -1 +1,15 @@ +// 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 page diff --git a/tools/codescan/checker/checker.go b/tools/codescan/checker/checker.go index 953236d0fa..ad724dd5bb 100644 --- a/tools/codescan/checker/checker.go +++ b/tools/codescan/checker/checker.go @@ -1,3 +1,17 @@ +// 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 checker import ( diff --git a/tools/codescan/codescan.go b/tools/codescan/codescan.go index c46f7a7044..a83e895fcb 100644 --- a/tools/codescan/codescan.go +++ b/tools/codescan/codescan.go @@ -1,3 +1,17 @@ +// 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 main import ( diff --git a/tools/codescan/config.yaml b/tools/codescan/config.yaml index 9a81236b8a..32a8c1f54b 100644 --- a/tools/codescan/config.yaml +++ b/tools/codescan/config.yaml @@ -1,3 +1,17 @@ +# 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. + directory: ./ file_types: - .go diff --git a/tools/codescan/config/config.go b/tools/codescan/config/config.go index 8f051e3dad..aebf0d4f75 100644 --- a/tools/codescan/config/config.go +++ b/tools/codescan/config/config.go @@ -1,3 +1,17 @@ +// 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 config import ( diff --git a/tools/formitychecker/checker/checker.go b/tools/formitychecker/checker/checker.go index 9a64b70902..b17cc5427c 100644 --- a/tools/formitychecker/checker/checker.go +++ b/tools/formitychecker/checker/checker.go @@ -22,6 +22,7 @@ import ( "strings" "github.com/OpenIMSDK/tools/errs" + "github.com/openimsdk/open-im-server/tools/formitychecker/config" ) diff --git a/tools/url2im/main.go b/tools/url2im/main.go index 28c1e1c439..9e319932f9 100644 --- a/tools/url2im/main.go +++ b/tools/url2im/main.go @@ -33,35 +33,35 @@ import ( func main() { var conf pkg.Config // Configuration object, '*' denotes required fields - // *Required*: Path for the task log file - flag.StringVar(&conf.TaskPath, "task", "take.txt", "Path for the task log file") - - // Optional: Path for the progress log file - flag.StringVar(&conf.ProgressPath, "progress", "", "Path for the progress log file") - - // Number of concurrent operations - flag.IntVar(&conf.Concurrency, "concurrency", 1, "Number of concurrent operations") - - // Number of retry attempts - flag.IntVar(&conf.Retry, "retry", 1, "Number of retry attempts") - - // Optional: Path for the temporary directory - flag.StringVar(&conf.TempDir, "temp", "", "Path for the temporary directory") - - // Cache size in bytes (downloads move to disk when exceeded) - flag.Int64Var(&conf.CacheSize, "cache", 1024*1024*100, "Cache size in bytes") - - // Request timeout in milliseconds - flag.Int64Var((*int64)(&conf.Timeout), "timeout", 5000, "Request timeout in milliseconds") - - // *Required*: API endpoint for the IM service - flag.StringVar(&conf.Api, "api", "http://127.0.0.1:10002", "API endpoint for the IM service") - - // IM administrator's user ID - flag.StringVar(&conf.UserID, "userID", "openIM123456", "IM administrator's user ID") - - // Secret for the IM configuration - flag.StringVar(&conf.Secret, "secret", "openIM123", "Secret for the IM configuration") + // *Required*: Path for the task log file + flag.StringVar(&conf.TaskPath, "task", "take.txt", "Path for the task log file") + + // Optional: Path for the progress log file + flag.StringVar(&conf.ProgressPath, "progress", "", "Path for the progress log file") + + // Number of concurrent operations + flag.IntVar(&conf.Concurrency, "concurrency", 1, "Number of concurrent operations") + + // Number of retry attempts + flag.IntVar(&conf.Retry, "retry", 1, "Number of retry attempts") + + // Optional: Path for the temporary directory + flag.StringVar(&conf.TempDir, "temp", "", "Path for the temporary directory") + + // Cache size in bytes (downloads move to disk when exceeded) + flag.Int64Var(&conf.CacheSize, "cache", 1024*1024*100, "Cache size in bytes") + + // Request timeout in milliseconds + flag.Int64Var((*int64)(&conf.Timeout), "timeout", 5000, "Request timeout in milliseconds") + + // *Required*: API endpoint for the IM service + flag.StringVar(&conf.Api, "api", "http://127.0.0.1:10002", "API endpoint for the IM service") + + // IM administrator's user ID + flag.StringVar(&conf.UserID, "userID", "openIM123456", "IM administrator's user ID") + + // Secret for the IM configuration + flag.StringVar(&conf.Secret, "secret", "openIM123", "Secret for the IM configuration") flag.Parse() if !filepath.IsAbs(conf.TaskPath) { From efb831053123772182f8275891a4937261fc7cee Mon Sep 17 00:00:00 2001 From: OpenIM Bot <124379614+kubbot@users.noreply.github.com> Date: Tue, 5 Mar 2024 15:27:26 +0800 Subject: [PATCH 082/188] Update readme and golangci lint (#1999) * Update README.md * Update .golangci.yml --------- Co-authored-by: Xinwei Xiong <3293172751NSS@gmail.com> --- .golangci.yml | 1 - README.md | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index 5bf9eeba9a..9c79606426 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -730,7 +730,6 @@ linters: - gosimple # Suggestions for simplifying code - errcheck - decorder - - sloglint - ineffassign - revive - reassign diff --git a/README.md b/README.md index 1552f62e5e..175db3326b 100644 --- a/README.md +++ b/README.md @@ -125,10 +125,10 @@ We support many platforms. Here are the addresses for quick experience on the we ## :hammer_and_wrench: To Start Developing OpenIM -[![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/openimsdk/open-im-server) - [![Open in Dev Container](https://img.shields.io/static/v1?label=Dev%20Container&message=Open&color=blue&logo=visualstudiocode)](https://vscode.dev/github/openimsdk/open-im-server) +[![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/openimsdk/open-im-server) + OpenIM Our goal is to build a top-level open source community. We have a set of standards, in the [Community repository](https://github.com/OpenIMSDK/community). If you'd like to contribute to this Open-IM-Server repository, please read our [contributor documentation](https://github.com/openimsdk/open-im-server/blob/main/CONTRIBUTING.md). From 383758782e114e22f4873a9573830bac41998933 Mon Sep 17 00:00:00 2001 From: OpenIM-Gordon <46924906+FGadvancer@users.noreply.github.com> Date: Tue, 5 Mar 2024 17:53:22 +0800 Subject: [PATCH 083/188] =?UTF-8?q?optimization:=20change=20the=20configur?= =?UTF-8?q?ation=20file=20from=20being=20read=20globally=20=E2=80=A6=20(#1?= =?UTF-8?q?935)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * optimization: change the configuration file from being read globally to being read independently. * optimization: change the configuration file from being read globally to being read independently. * optimization: change the configuration file from being read globally to being read independently. * optimization: config file changed to dependency injection. * fix: replace global config with dependency injection * fix: replace global config with dependency injection * fix: import the enough param * fix: import the enough param * fix: import the enough param * fix: fix the component check of path * fix: fix the kafka of tls is nil problem * fix: fix the TLS.CACrt is nil error * fix: fix the valiable shadows problem * fix: fix the comflect * optimization: message remove options. * fix: fix the param pass error * fix: find error * fix: find error * fix: find eror * fix: find error * fix: find error * fix: del the undifined func * fix: find error * fix: fix the error * fix: pass config * fix: find error * fix: find error * fix: find error * fix: find error * fix: find error * fix: fix the config * fix: fix the error * fix: fix the config pass error * fix: fix the eror * fix: fix the error * fix: fix the error * fix: fix the error * fix: find error * fix: fix the error * fix: fix the config * fix: add return err * fix: fix the err2 * fix: err * fix: fix the func * fix: del the chinese comment * fix: fix the func * fix: fix the gateway_test logic * fix: s3 * test * test * fix: not found --------- Co-authored-by: luhaoling <2198702716@qq.com> Co-authored-by: withchao <993506633@qq.com> --- cmd/openim-api/main.go | 100 +------ cmd/openim-crontask/main.go | 3 +- cmd/openim-msggateway/main.go | 1 - cmd/openim-push/main.go | 6 +- cmd/openim-rpc/openim-rpc-auth/main.go | 7 +- .../openim-rpc-conversation/main.go | 6 +- cmd/openim-rpc/openim-rpc-friend/main.go | 6 +- cmd/openim-rpc/openim-rpc-group/main.go | 6 +- cmd/openim-rpc/openim-rpc-msg/main.go | 6 +- cmd/openim-rpc/openim-rpc-third/main.go | 6 +- cmd/openim-rpc/openim-rpc-user/main.go | 6 +- internal/api/msg.go | 6 +- internal/api/route.go | 149 ++++++++-- internal/api/third.go | 8 +- internal/api/user.go | 6 +- internal/msggateway/callback.go | 22 +- internal/msggateway/hub_server.go | 19 +- internal/msggateway/init.go | 15 +- internal/msggateway/message_handler.go | 7 +- internal/msggateway/n_ws_server.go | 24 +- internal/msgtransfer/init.go | 49 ++-- .../msgtransfer/online_history_msg_handler.go | 25 +- .../online_msg_to_mongo_handler.go | 24 +- internal/push/callback.go | 27 +- internal/push/consumer_init.go | 6 +- internal/push/offlinepush/fcm/push.go | 12 +- internal/push/offlinepush/getui/body.go | 6 +- internal/push/offlinepush/getui/push.go | 23 +- .../offlinepush/jpush/body/notification.go | 5 +- internal/push/offlinepush/jpush/push.go | 16 +- internal/push/push_handler.go | 22 +- internal/push/push_rpc_server.go | 20 +- internal/push/push_to_client.go | 44 +-- internal/rpc/auth/auth.go | 31 +- internal/rpc/conversation/conversaion.go | 19 +- internal/rpc/friend/black.go | 2 +- internal/rpc/friend/callback.go | 60 ++-- internal/rpc/friend/friend.go | 68 +++-- internal/rpc/group/callback.go | 89 +++--- internal/rpc/group/group.go | 89 +++--- internal/rpc/msg/as_read.go | 4 +- internal/rpc/msg/callback.go | 52 ++-- internal/rpc/msg/delete.go | 8 +- internal/rpc/msg/message_interceptor.go | 8 +- internal/rpc/msg/revoke.go | 21 +- internal/rpc/msg/send.go | 21 +- internal/rpc/msg/server.go | 51 ++-- internal/rpc/msg/sync_msg.go | 2 +- internal/rpc/msg/utils.go | 6 +- internal/rpc/msg/verify.go | 14 +- internal/rpc/third/log.go | 4 +- internal/rpc/third/s3.go | 11 +- internal/rpc/third/third.go | 50 ++-- internal/rpc/third/tool.go | 11 +- internal/rpc/user/callback.go | 36 +-- internal/rpc/user/user.go | 98 ++++--- internal/tools/cron_task.go | 25 +- internal/tools/cron_task_test.go | 35 ++- internal/tools/msg.go | 37 +-- pkg/authverify/token.go | 43 ++- pkg/common/cmd/api.go | 50 ++-- pkg/common/cmd/cron_task.go | 22 +- pkg/common/cmd/msg_gateway.go | 59 +--- pkg/common/cmd/msg_gateway_test.go | 2 +- pkg/common/cmd/msg_transfer.go | 31 +- pkg/common/cmd/msg_utils.go | 3 +- pkg/common/cmd/root.go | 47 ++- pkg/common/cmd/rpc.go | 180 +++++++----- pkg/common/config/config.go | 16 +- pkg/common/config/parse.go | 93 +++--- pkg/common/config/parse_test.go | 3 +- pkg/common/db/cache/init_redis.go | 42 +-- pkg/common/db/cache/meta_cache.go | 19 +- pkg/common/db/cache/msg.go | 23 +- pkg/common/db/cache/user.go | 32 +- pkg/common/db/controller/auth.go | 11 +- pkg/common/db/controller/msg.go | 35 ++- pkg/common/db/controller/msg_test.go | 56 ++-- pkg/common/db/s3/aws/aws.go | 275 ------------------ pkg/common/db/s3/cos/cos.go | 22 +- pkg/common/db/s3/minio/image.go | 90 ++++-- pkg/common/db/s3/minio/minio.go | 62 ++-- pkg/common/db/s3/oss/oss.go | 26 +- pkg/common/db/unrelation/mongo.go | 31 +- .../discoveryregister/direct/directconn.go | 36 +-- .../discoveryregister/discoveryregister.go | 13 +- .../discoveryregister_test.go | 16 +- .../kubernetes/kubernetes.go | 32 +- .../discoveryregister/zookeeper/zookeeper.go | 18 +- pkg/common/kafka/consumer.go | 37 ++- pkg/common/kafka/consumer_group.go | 19 +- pkg/common/kafka/producer.go | 23 +- pkg/common/kafka/util.go | 22 +- pkg/common/prommetrics/prommetrics.go | 10 +- pkg/common/prommetrics/prommetrics_test.go | 7 +- pkg/common/startrpc/start.go | 42 +-- pkg/common/startrpc/start_test.go | 6 +- pkg/common/tls/tls.go | 8 +- pkg/rpcclient/auth.go | 7 +- pkg/rpcclient/conversation.go | 11 +- pkg/rpcclient/friend.go | 11 +- pkg/rpcclient/group.go | 11 +- pkg/rpcclient/msg.go | 103 +++---- pkg/rpcclient/notification/conversation.go | 5 +- pkg/rpcclient/notification/friend.go | 4 +- pkg/rpcclient/notification/group.go | 36 +-- pkg/rpcclient/notification/msg.go | 5 +- pkg/rpcclient/notification/user.go | 4 +- pkg/rpcclient/push.go | 8 +- pkg/rpcclient/third.go | 48 ++- pkg/rpcclient/user.go | 13 +- tools/component/component.go | 98 ++++--- tools/component/component_test.go | 29 +- tools/up35/pkg/pkg.go | 34 ++- 114 files changed, 1735 insertions(+), 1794 deletions(-) delete mode 100644 pkg/common/db/s3/aws/aws.go mode change 100644 => 100755 pkg/common/tls/tls.go mode change 100644 => 100755 pkg/rpcclient/third.go diff --git a/cmd/openim-api/main.go b/cmd/openim-api/main.go index 0fb609aa3f..9a307686d8 100644 --- a/cmd/openim-api/main.go +++ b/cmd/openim-api/main.go @@ -15,115 +15,17 @@ package main import ( - "context" - "fmt" - "net" - "net/http" + util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" _ "net/http/pprof" - "os" - "os/signal" - "strconv" - "syscall" - "time" - "github.com/OpenIMSDK/protocol/constant" - "github.com/OpenIMSDK/tools/discoveryregistry" - "github.com/OpenIMSDK/tools/errs" - "github.com/openimsdk/open-im-server/v3/internal/api" "github.com/openimsdk/open-im-server/v3/pkg/common/cmd" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" - kdisc "github.com/openimsdk/open-im-server/v3/pkg/common/discoveryregister" - ginprom "github.com/openimsdk/open-im-server/v3/pkg/common/ginprometheus" - "github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics" - util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" ) func main() { apiCmd := cmd.NewApiCmd() apiCmd.AddPortFlag() apiCmd.AddPrometheusPortFlag() - apiCmd.AddApi(run) if err := apiCmd.Execute(); err != nil { util.ExitWithError(err) } } - -func run(port int, proPort int) error { - if port == 0 || proPort == 0 { - err := "port or proPort is empty:" + strconv.Itoa(port) + "," + strconv.Itoa(proPort) - return errs.Wrap(fmt.Errorf(err)) - } - rdb, err := cache.NewRedis() - if err != nil { - return err - } - - var client discoveryregistry.SvcDiscoveryRegistry - - // Determine whether zk is passed according to whether it is a clustered deployment - client, err = kdisc.NewDiscoveryRegister(config.Config.Envs.Discovery) - if err != nil { - return err - } - - if err = client.CreateRpcRootNodes(config.Config.GetServiceNames()); err != nil { - return err - } - - if err = client.RegisterConf2Registry(constant.OpenIMCommonConfigKey, config.Config.EncodeConfig()); err != nil { - return err - } - - var ( - netDone = make(chan struct{}, 1) - netErr error - ) - - router := api.NewGinRouter(client, rdb) - if config.Config.Prometheus.Enable { - go func() { - p := ginprom.NewPrometheus("app", prommetrics.GetGinCusMetrics("Api")) - p.SetListenAddress(fmt.Sprintf(":%d", proPort)) - if err = p.Use(router); err != nil && err != http.ErrServerClosed { - netErr = errs.Wrap(err, fmt.Sprintf("prometheus start err: %d", proPort)) - netDone <- struct{}{} - } - }() - } - - var address string - if config.Config.Api.ListenIP != "" { - address = net.JoinHostPort(config.Config.Api.ListenIP, strconv.Itoa(port)) - } else { - address = net.JoinHostPort("0.0.0.0", strconv.Itoa(port)) - } - - server := http.Server{Addr: address, Handler: router} - - go func() { - err = server.ListenAndServe() - if err != nil && err != http.ErrServerClosed { - netErr = errs.Wrap(err, fmt.Sprintf("api start err: %s", server.Addr)) - netDone <- struct{}{} - } - }() - - sigs := make(chan os.Signal, 1) - signal.Notify(sigs, syscall.SIGTERM) - - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) - defer cancel() - select { - case <-sigs: - util.SIGTERMExit() - err := server.Shutdown(ctx) - if err != nil { - return errs.Wrap(err, "api shutdown err") - } - case <-netDone: - close(netDone) - return netErr - } - return nil -} diff --git a/cmd/openim-crontask/main.go b/cmd/openim-crontask/main.go index b284fd7739..b52029c64b 100644 --- a/cmd/openim-crontask/main.go +++ b/cmd/openim-crontask/main.go @@ -15,14 +15,13 @@ package main import ( - "github.com/openimsdk/open-im-server/v3/internal/tools" "github.com/openimsdk/open-im-server/v3/pkg/common/cmd" util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" ) func main() { cronTaskCmd := cmd.NewCronTaskCmd() - if err := cronTaskCmd.Exec(tools.StartTask); err != nil { + if err := cronTaskCmd.Exec(); err != nil { util.ExitWithError(err) } } diff --git a/cmd/openim-msggateway/main.go b/cmd/openim-msggateway/main.go index ed67b8f5d1..01b13560d3 100644 --- a/cmd/openim-msggateway/main.go +++ b/cmd/openim-msggateway/main.go @@ -24,7 +24,6 @@ func main() { msgGatewayCmd.AddWsPortFlag() msgGatewayCmd.AddPortFlag() msgGatewayCmd.AddPrometheusPortFlag() - if err := msgGatewayCmd.Exec(); err != nil { util.ExitWithError(err) } diff --git a/cmd/openim-push/main.go b/cmd/openim-push/main.go index bd31ffdef3..c7d29fc970 100644 --- a/cmd/openim-push/main.go +++ b/cmd/openim-push/main.go @@ -17,18 +17,14 @@ package main import ( "github.com/openimsdk/open-im-server/v3/internal/push" "github.com/openimsdk/open-im-server/v3/pkg/common/cmd" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" ) func main() { - pushCmd := cmd.NewRpcCmd(cmd.RpcPushServer) + pushCmd := cmd.NewRpcCmd(cmd.RpcPushServer, push.Start) pushCmd.AddPortFlag() pushCmd.AddPrometheusPortFlag() if err := pushCmd.Exec(); err != nil { util.ExitWithError(err) } - if err := pushCmd.StartSvr(config.Config.RpcRegisterName.OpenImPushName, push.Start); err != nil { - util.ExitWithError(err) - } } diff --git a/cmd/openim-rpc/openim-rpc-auth/main.go b/cmd/openim-rpc/openim-rpc-auth/main.go index 992a2b4328..da281b70ec 100644 --- a/cmd/openim-rpc/openim-rpc-auth/main.go +++ b/cmd/openim-rpc/openim-rpc-auth/main.go @@ -17,19 +17,14 @@ package main import ( "github.com/openimsdk/open-im-server/v3/internal/rpc/auth" "github.com/openimsdk/open-im-server/v3/pkg/common/cmd" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" ) func main() { - authCmd := cmd.NewRpcCmd(cmd.RpcAuthServer) + authCmd := cmd.NewRpcCmd(cmd.RpcAuthServer, auth.Start) authCmd.AddPortFlag() authCmd.AddPrometheusPortFlag() if err := authCmd.Exec(); err != nil { util.ExitWithError(err) } - if err := authCmd.StartSvr(config.Config.RpcRegisterName.OpenImAuthName, auth.Start); err != nil { - util.ExitWithError(err) - } - } diff --git a/cmd/openim-rpc/openim-rpc-conversation/main.go b/cmd/openim-rpc/openim-rpc-conversation/main.go index 10fe0b46c2..6e74b32517 100644 --- a/cmd/openim-rpc/openim-rpc-conversation/main.go +++ b/cmd/openim-rpc/openim-rpc-conversation/main.go @@ -17,18 +17,14 @@ package main import ( "github.com/openimsdk/open-im-server/v3/internal/rpc/conversation" "github.com/openimsdk/open-im-server/v3/pkg/common/cmd" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" ) func main() { - rpcCmd := cmd.NewRpcCmd(cmd.RpcConversationServer) + rpcCmd := cmd.NewRpcCmd(cmd.RpcConversationServer, conversation.Start) rpcCmd.AddPortFlag() rpcCmd.AddPrometheusPortFlag() if err := rpcCmd.Exec(); err != nil { util.ExitWithError(err) } - if err := rpcCmd.StartSvr(config.Config.RpcRegisterName.OpenImConversationName, conversation.Start); err != nil { - util.ExitWithError(err) - } } diff --git a/cmd/openim-rpc/openim-rpc-friend/main.go b/cmd/openim-rpc/openim-rpc-friend/main.go index 63de23293e..a307c01a14 100644 --- a/cmd/openim-rpc/openim-rpc-friend/main.go +++ b/cmd/openim-rpc/openim-rpc-friend/main.go @@ -17,18 +17,14 @@ package main import ( "github.com/openimsdk/open-im-server/v3/internal/rpc/friend" "github.com/openimsdk/open-im-server/v3/pkg/common/cmd" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" ) func main() { - rpcCmd := cmd.NewRpcCmd(cmd.RpcFriendServer) + rpcCmd := cmd.NewRpcCmd(cmd.RpcFriendServer, friend.Start) rpcCmd.AddPortFlag() rpcCmd.AddPrometheusPortFlag() if err := rpcCmd.Exec(); err != nil { util.ExitWithError(err) } - if err := rpcCmd.StartSvr(config.Config.RpcRegisterName.OpenImFriendName, friend.Start); err != nil { - util.ExitWithError(err) - } } diff --git a/cmd/openim-rpc/openim-rpc-group/main.go b/cmd/openim-rpc/openim-rpc-group/main.go index c0780acab4..2afb7963cc 100644 --- a/cmd/openim-rpc/openim-rpc-group/main.go +++ b/cmd/openim-rpc/openim-rpc-group/main.go @@ -17,18 +17,14 @@ package main import ( "github.com/openimsdk/open-im-server/v3/internal/rpc/group" "github.com/openimsdk/open-im-server/v3/pkg/common/cmd" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" ) func main() { - rpcCmd := cmd.NewRpcCmd(cmd.RpcGroupServer) + rpcCmd := cmd.NewRpcCmd(cmd.RpcGroupServer, group.Start) rpcCmd.AddPortFlag() rpcCmd.AddPrometheusPortFlag() if err := rpcCmd.Exec(); err != nil { util.ExitWithError(err) } - if err := rpcCmd.StartSvr(config.Config.RpcRegisterName.OpenImGroupName, group.Start); err != nil { - util.ExitWithError(err) - } } diff --git a/cmd/openim-rpc/openim-rpc-msg/main.go b/cmd/openim-rpc/openim-rpc-msg/main.go index 62bdff0a5a..bbffbcae7c 100644 --- a/cmd/openim-rpc/openim-rpc-msg/main.go +++ b/cmd/openim-rpc/openim-rpc-msg/main.go @@ -17,18 +17,14 @@ package main import ( "github.com/openimsdk/open-im-server/v3/internal/rpc/msg" "github.com/openimsdk/open-im-server/v3/pkg/common/cmd" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" ) func main() { - rpcCmd := cmd.NewRpcCmd(cmd.RpcMsgServer) + rpcCmd := cmd.NewRpcCmd(cmd.RpcMsgServer, msg.Start) rpcCmd.AddPortFlag() rpcCmd.AddPrometheusPortFlag() if err := rpcCmd.Exec(); err != nil { util.ExitWithError(err) } - if err := rpcCmd.StartSvr(config.Config.RpcRegisterName.OpenImMsgName, msg.Start); err != nil { - util.ExitWithError(err) - } } diff --git a/cmd/openim-rpc/openim-rpc-third/main.go b/cmd/openim-rpc/openim-rpc-third/main.go index c2893a398d..09a8409e6f 100644 --- a/cmd/openim-rpc/openim-rpc-third/main.go +++ b/cmd/openim-rpc/openim-rpc-third/main.go @@ -17,18 +17,14 @@ package main import ( "github.com/openimsdk/open-im-server/v3/internal/rpc/third" "github.com/openimsdk/open-im-server/v3/pkg/common/cmd" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" ) func main() { - rpcCmd := cmd.NewRpcCmd(cmd.RpcThirdServer) + rpcCmd := cmd.NewRpcCmd(cmd.RpcThirdServer, third.Start) rpcCmd.AddPortFlag() rpcCmd.AddPrometheusPortFlag() if err := rpcCmd.Exec(); err != nil { util.ExitWithError(err) } - if err := rpcCmd.StartSvr(config.Config.RpcRegisterName.OpenImThirdName, third.Start); err != nil { - util.ExitWithError(err) - } } diff --git a/cmd/openim-rpc/openim-rpc-user/main.go b/cmd/openim-rpc/openim-rpc-user/main.go index f7948bda08..18adbfae57 100644 --- a/cmd/openim-rpc/openim-rpc-user/main.go +++ b/cmd/openim-rpc/openim-rpc-user/main.go @@ -17,18 +17,14 @@ package main import ( "github.com/openimsdk/open-im-server/v3/internal/rpc/user" "github.com/openimsdk/open-im-server/v3/pkg/common/cmd" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" ) func main() { - rpcCmd := cmd.NewRpcCmd(cmd.RpcUserServer) + rpcCmd := cmd.NewRpcCmd(cmd.RpcUserServer, user.Start) rpcCmd.AddPortFlag() rpcCmd.AddPrometheusPortFlag() if err := rpcCmd.Exec(); err != nil { util.ExitWithError(err) } - if err := rpcCmd.StartSvr(config.Config.RpcRegisterName.OpenImUserName, user.Start); err != nil { - util.ExitWithError(err) - } } diff --git a/internal/api/msg.go b/internal/api/msg.go index 61cd1ae6c5..d38c14d4e5 100644 --- a/internal/api/msg.go +++ b/internal/api/msg.go @@ -198,7 +198,7 @@ func (m *MessageApi) SendMessage(c *gin.Context) { } // Check if the user has the app manager role. - if !authverify.IsAppManagerUid(c) { + if !authverify.IsAppManagerUid(c, m.Config) { // Respond with a permission error if the user is not an app manager. apiresp.GinError(c, errs.ErrNoPermission.Wrap("only app manager can send message")) return @@ -256,7 +256,7 @@ func (m *MessageApi) SendBusinessNotification(c *gin.Context) { return } - if !authverify.IsAppManagerUid(c) { + if !authverify.IsAppManagerUid(c, m.Config) { apiresp.GinError(c, errs.ErrNoPermission.Wrap("only app manager can send message")) return } @@ -300,7 +300,7 @@ func (m *MessageApi) BatchSendMsg(c *gin.Context) { return } log.ZInfo(c, "BatchSendMsg", "req", req) - if err := authverify.CheckAdmin(c); err != nil { + if err := authverify.CheckAdmin(c, m.Config); err != nil { apiresp.GinError(c, errs.ErrNoPermission.Wrap("only app manager can send message")) return } diff --git a/internal/api/route.go b/internal/api/route.go index 5c920ca05a..ce8e3a62b3 100644 --- a/internal/api/route.go +++ b/internal/api/route.go @@ -17,53 +17,142 @@ package api import ( "context" "fmt" + kdisc "github.com/openimsdk/open-im-server/v3/pkg/common/discoveryregister" + ginprom "github.com/openimsdk/open-im-server/v3/pkg/common/ginprometheus" + "github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics" + util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" + "net" "net/http" + "os" + "os/signal" + "strconv" + "syscall" + "time" "github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/tools/apiresp" - "github.com/OpenIMSDK/tools/discoveryregistry" "github.com/OpenIMSDK/tools/errs" - "github.com/OpenIMSDK/tools/log" - "github.com/OpenIMSDK/tools/mw" "github.com/OpenIMSDK/tools/tokenverify" - "github.com/gin-gonic/gin" - "github.com/gin-gonic/gin/binding" - "github.com/go-playground/validator/v10" + "github.com/openimsdk/open-im-server/v3/pkg/authverify" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" - "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" + + "github.com/gin-gonic/gin" + "github.com/gin-gonic/gin/binding" + "github.com/go-playground/validator/v10" "github.com/redis/go-redis/v9" "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" + + "github.com/OpenIMSDK/tools/discoveryregistry" + "github.com/OpenIMSDK/tools/log" + "github.com/OpenIMSDK/tools/mw" + + "github.com/openimsdk/open-im-server/v3/pkg/common/config" + "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" ) -func NewGinRouter(discov discoveryregistry.SvcDiscoveryRegistry, rdb redis.UniversalClient) *gin.Engine { - discov.AddOption( - mw.GrpcClient(), - grpc.WithTransportCredentials(insecure.NewCredentials()), - grpc.WithDefaultServiceConfig(fmt.Sprintf(`{"LoadBalancingPolicy": "%s"}`, "round_robin")), - ) // Default RPC middleware +func Start(config *config.GlobalConfig, port int, proPort int) error { + log.ZDebug(context.Background(), "configAPI1111111111111111111", config, "port", port, "javafdasfs") + if port == 0 || proPort == 0 { + err := "port or proPort is empty:" + strconv.Itoa(port) + "," + strconv.Itoa(proPort) + return errs.Wrap(fmt.Errorf(err)) + } + rdb, err := cache.NewRedis(config) + if err != nil { + return err + } + + var client discoveryregistry.SvcDiscoveryRegistry + + // Determine whether zk is passed according to whether it is a clustered deployment + client, err = kdisc.NewDiscoveryRegister(config) + if err != nil { + return errs.Wrap(err, "register discovery err") + } + + if err = client.CreateRpcRootNodes(config.GetServiceNames()); err != nil { + return errs.Wrap(err, "create rpc root nodes error") + } + + if err = client.RegisterConf2Registry(constant.OpenIMCommonConfigKey, config.EncodeConfig()); err != nil { + return errs.Wrap(err) + } + var ( + netDone = make(chan struct{}, 1) + netErr error + ) + router := newGinRouter(client, rdb, config) + if config.Prometheus.Enable { + go func() { + p := ginprom.NewPrometheus("app", prommetrics.GetGinCusMetrics("Api")) + p.SetListenAddress(fmt.Sprintf(":%d", proPort)) + if err = p.Use(router); err != nil && err != http.ErrServerClosed { + netErr = errs.Wrap(err, fmt.Sprintf("prometheus start err: %d", proPort)) + netDone <- struct{}{} + } + }() + + } + + var address string + if config.Api.ListenIP != "" { + address = net.JoinHostPort(config.Api.ListenIP, strconv.Itoa(port)) + } else { + address = net.JoinHostPort("0.0.0.0", strconv.Itoa(port)) + } + + server := http.Server{Addr: address, Handler: router} + + go func() { + err = server.ListenAndServe() + if err != nil && err != http.ErrServerClosed { + netErr = errs.Wrap(err, fmt.Sprintf("api start err: %s", server.Addr)) + netDone <- struct{}{} + + } + }() + + sigs := make(chan os.Signal, 1) + signal.Notify(sigs, syscall.SIGTERM) + + ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) + defer cancel() + select { + case <-sigs: + util.SIGTERMExit() + err := server.Shutdown(ctx) + if err != nil { + return errs.Wrap(err, "shutdown err") + } + case <-netDone: + close(netDone) + return netErr + } + return nil +} + +func newGinRouter(disCov discoveryregistry.SvcDiscoveryRegistry, rdb redis.UniversalClient, config *config.GlobalConfig) *gin.Engine { + disCov.AddOption(mw.GrpcClient(), grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithDefaultServiceConfig(fmt.Sprintf(`{"LoadBalancingPolicy": "%s"}`, "round_robin"))) gin.SetMode(gin.ReleaseMode) r := gin.New() if v, ok := binding.Validator.Engine().(*validator.Validate); ok { _ = v.RegisterValidation("required_if", RequiredIf) } - log.ZInfo(context.Background(), "load config", "config", config.Config) r.Use(gin.Recovery(), mw.CorsHandler(), mw.GinParseOperationID()) // init rpc client here - userRpc := rpcclient.NewUser(discov) - groupRpc := rpcclient.NewGroup(discov) - friendRpc := rpcclient.NewFriend(discov) - messageRpc := rpcclient.NewMessage(discov) - conversationRpc := rpcclient.NewConversation(discov) - authRpc := rpcclient.NewAuth(discov) - thirdRpc := rpcclient.NewThird(discov) + userRpc := rpcclient.NewUser(disCov, config) + groupRpc := rpcclient.NewGroup(disCov, config) + friendRpc := rpcclient.NewFriend(disCov, config) + messageRpc := rpcclient.NewMessage(disCov, config) + conversationRpc := rpcclient.NewConversation(disCov, config) + authRpc := rpcclient.NewAuth(disCov, config) + thirdRpc := rpcclient.NewThird(disCov, config) u := NewUserApi(*userRpc) m := NewMessageApi(messageRpc, userRpc) - ParseToken := GinParseToken(rdb) + ParseToken := GinParseToken(rdb, config) userRouterGroup := r.Group("/user") { userRouterGroup.POST("/user_register", u.UserRegister) @@ -157,8 +246,8 @@ func NewGinRouter(discov discoveryregistry.SvcDiscoveryRegistry, rdb redis.Unive // Third service thirdGroup := r.Group("/third", ParseToken) { - thirdGroup.GET("/prometheus", GetPrometheus) t := NewThirdApi(*thirdRpc) + thirdGroup.GET("/prometheus", t.GetPrometheus) thirdGroup.POST("/fcm_update_token", t.FcmUpdateToken) thirdGroup.POST("/set_app_badge", t.SetAppBadge) @@ -225,12 +314,12 @@ func NewGinRouter(discov discoveryregistry.SvcDiscoveryRegistry, rdb redis.Unive return r } -// GinParseToken is a middleware that parses the token in the request header and verifies it. -func GinParseToken(rdb redis.UniversalClient) gin.HandlerFunc { +func GinParseToken(rdb redis.UniversalClient, config *config.GlobalConfig) gin.HandlerFunc { dataBase := controller.NewAuthDatabase( - cache.NewMsgCacheModel(rdb), - config.Config.Secret, - config.Config.TokenPolicy.Expire, + cache.NewMsgCacheModel(rdb, config), + config.Secret, + config.TokenPolicy.Expire, + config, ) return func(c *gin.Context) { switch c.Request.Method { @@ -242,7 +331,7 @@ func GinParseToken(rdb redis.UniversalClient) gin.HandlerFunc { c.Abort() return } - claims, err := tokenverify.GetClaimFromToken(token, authverify.Secret()) + claims, err := tokenverify.GetClaimFromToken(token, authverify.Secret(config.Secret)) if err != nil { log.ZWarn(c, "jwt get token error", errs.ErrTokenUnknown.Wrap()) apiresp.GinError(c, errs.ErrTokenUnknown.Wrap()) diff --git a/internal/api/third.go b/internal/api/third.go index f00c0d8d37..190e0d5403 100644 --- a/internal/api/third.go +++ b/internal/api/third.go @@ -19,12 +19,12 @@ import ( "net/http" "strconv" + "github.com/gin-gonic/gin" + "github.com/OpenIMSDK/protocol/third" "github.com/OpenIMSDK/tools/a2r" "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/mcontext" - "github.com/gin-gonic/gin" - config2 "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" ) @@ -126,6 +126,6 @@ func (o *ThirdApi) SearchLogs(c *gin.Context) { a2r.Call(third.ThirdClient.SearchLogs, o.Client, c) } -func GetPrometheus(c *gin.Context) { - c.Redirect(http.StatusFound, config2.Config.Prometheus.GrafanaUrl) +func (o *ThirdApi) GetPrometheus(c *gin.Context) { + c.Redirect(http.StatusFound, o.Config.Prometheus.GrafanaUrl) } diff --git a/internal/api/user.go b/internal/api/user.go index 3cc5470a71..468432ee08 100644 --- a/internal/api/user.go +++ b/internal/api/user.go @@ -23,7 +23,7 @@ import ( "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/log" "github.com/gin-gonic/gin" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" + "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" ) @@ -70,7 +70,7 @@ func (u *UserApi) GetUsersOnlineStatus(c *gin.Context) { apiresp.GinError(c, err) return } - conns, err := u.Discov.GetConns(c, config.Config.RpcRegisterName.OpenImMessageGatewayName) + conns, err := u.Discov.GetConns(c, u.Config.RpcRegisterName.OpenImMessageGatewayName) if err != nil { apiresp.GinError(c, err) return @@ -134,7 +134,7 @@ func (u *UserApi) GetUsersOnlineTokenDetail(c *gin.Context) { apiresp.GinError(c, errs.ErrArgs.WithDetail(err.Error()).Wrap()) return } - conns, err := u.Discov.GetConns(c, config.Config.RpcRegisterName.OpenImMessageGatewayName) + conns, err := u.Discov.GetConns(c, u.Config.RpcRegisterName.OpenImMessageGatewayName) if err != nil { apiresp.GinError(c, err) return diff --git a/internal/msggateway/callback.go b/internal/msggateway/callback.go index ede48f74a2..ab8c1f51fd 100644 --- a/internal/msggateway/callback.go +++ b/internal/msggateway/callback.go @@ -25,12 +25,8 @@ import ( "github.com/openimsdk/open-im-server/v3/pkg/common/http" ) -func callBackURL() string { - return config.Config.Callback.CallbackUrl -} - -func CallbackUserOnline(ctx context.Context, userID string, platformID int, isAppBackground bool, connID string) error { - if !config.Config.Callback.CallbackUserOnline.Enable { +func CallbackUserOnline(ctx context.Context, globalConfig *config.GlobalConfig, userID string, platformID int, isAppBackground bool, connID string) error { + if !globalConfig.Callback.CallbackUserOnline.Enable { return nil } req := cbapi.CallbackUserOnlineReq{ @@ -48,14 +44,14 @@ func CallbackUserOnline(ctx context.Context, userID string, platformID int, isAp ConnID: connID, } resp := cbapi.CommonCallbackResp{} - if err := http.CallBackPostReturn(ctx, callBackURL(), &req, &resp, config.Config.Callback.CallbackUserOnline); err != nil { + if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, &req, &resp, globalConfig.Callback.CallbackUserOnline); err != nil { return err } return nil } -func CallbackUserOffline(ctx context.Context, userID string, platformID int, connID string) error { - if !config.Config.Callback.CallbackUserOffline.Enable { +func CallbackUserOffline(ctx context.Context, globalConfig *config.GlobalConfig, userID string, platformID int, connID string) error { + if !globalConfig.Callback.CallbackUserOffline.Enable { return nil } req := &cbapi.CallbackUserOfflineReq{ @@ -72,14 +68,14 @@ func CallbackUserOffline(ctx context.Context, userID string, platformID int, con ConnID: connID, } resp := &cbapi.CallbackUserOfflineResp{} - if err := http.CallBackPostReturn(ctx, callBackURL(), req, resp, config.Config.Callback.CallbackUserOffline); err != nil { + if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, req, resp, globalConfig.Callback.CallbackUserOffline); err != nil { return err } return nil } -func CallbackUserKickOff(ctx context.Context, userID string, platformID int) error { - if !config.Config.Callback.CallbackUserKickOff.Enable { +func CallbackUserKickOff(ctx context.Context, globalConfig *config.GlobalConfig, userID string, platformID int) error { + if !globalConfig.Callback.CallbackUserKickOff.Enable { return nil } req := &cbapi.CallbackUserKickOffReq{ @@ -95,7 +91,7 @@ func CallbackUserKickOff(ctx context.Context, userID string, platformID int) err Seq: time.Now().UnixMilli(), } resp := &cbapi.CommonCallbackResp{} - if err := http.CallBackPostReturn(ctx, callBackURL(), req, resp, config.Config.Callback.CallbackUserOffline); err != nil { + if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, req, resp, globalConfig.Callback.CallbackUserOffline); err != nil { return err } return nil diff --git a/internal/msggateway/hub_server.go b/internal/msggateway/hub_server.go index 826c2488bc..739c4232ff 100644 --- a/internal/msggateway/hub_server.go +++ b/internal/msggateway/hub_server.go @@ -31,24 +31,25 @@ import ( "google.golang.org/grpc" ) -func (s *Server) InitServer(disCov discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) error { - rdb, err := cache.NewRedis() +func (s *Server) InitServer(config *config.GlobalConfig, disCov discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) error { + rdb, err := cache.NewRedis(config) if err != nil { return err } - msgModel := cache.NewMsgCacheModel(rdb) - s.LongConnServer.SetDiscoveryRegistry(disCov) + msgModel := cache.NewMsgCacheModel(rdb, config) + s.LongConnServer.SetDiscoveryRegistry(disCov, config) s.LongConnServer.SetCacheHandler(msgModel) msggateway.RegisterMsgGatewayServer(server, s) return nil } -func (s *Server) Start() error { +func (s *Server) Start(conf *config.GlobalConfig) error { return startrpc.Start( s.rpcPort, - config.Config.RpcRegisterName.OpenImMessageGatewayName, + conf.RpcRegisterName.OpenImMessageGatewayName, s.prometheusPort, + conf, s.InitServer, ) } @@ -58,18 +59,20 @@ type Server struct { prometheusPort int LongConnServer LongConnServer pushTerminal []int + config *config.GlobalConfig } func (s *Server) SetLongConnServer(LongConnServer LongConnServer) { s.LongConnServer = LongConnServer } -func NewServer(rpcPort int, proPort int, longConnServer LongConnServer) *Server { +func NewServer(rpcPort int, proPort int, longConnServer LongConnServer, config *config.GlobalConfig) *Server { return &Server{ rpcPort: rpcPort, prometheusPort: proPort, LongConnServer: longConnServer, pushTerminal: []int{constant.IOSPlatformID, constant.AndroidPlatformID}, + config: config, } } @@ -84,7 +87,7 @@ func (s *Server) GetUsersOnlineStatus( ctx context.Context, req *msggateway.GetUsersOnlineStatusReq, ) (*msggateway.GetUsersOnlineStatusResp, error) { - if !authverify.IsAppManagerUid(ctx) { + if !authverify.IsAppManagerUid(ctx, s.config) { return nil, errs.ErrNoPermission.Wrap("only app manager") } var resp msggateway.GetUsersOnlineStatusResp diff --git a/internal/msggateway/init.go b/internal/msggateway/init.go index 5d19ad16d0..4efbb7cdf5 100644 --- a/internal/msggateway/init.go +++ b/internal/msggateway/init.go @@ -22,23 +22,24 @@ import ( ) // RunWsAndServer run ws server. -func RunWsAndServer(rpcPort, wsPort, prometheusPort int) error { +func RunWsAndServer(conf *config.GlobalConfig, rpcPort, wsPort, prometheusPort int) error { fmt.Println("start rpc/msg_gateway server, port: ", rpcPort, wsPort, prometheusPort, ", OpenIM version: ", config.Version) longServer, err := NewWsServer( + conf, WithPort(wsPort), - WithMaxConnNum(int64(config.Config.LongConnSvr.WebsocketMaxConnNum)), - WithHandshakeTimeout(time.Duration(config.Config.LongConnSvr.WebsocketTimeout)*time.Second), - WithMessageMaxMsgLength(config.Config.LongConnSvr.WebsocketMaxMsgLen), - WithWriteBufferSize(config.Config.LongConnSvr.WebsocketWriteBufferSize), + WithMaxConnNum(int64(conf.LongConnSvr.WebsocketMaxConnNum)), + WithHandshakeTimeout(time.Duration(conf.LongConnSvr.WebsocketTimeout)*time.Second), + WithMessageMaxMsgLength(conf.LongConnSvr.WebsocketMaxMsgLen), + WithWriteBufferSize(conf.LongConnSvr.WebsocketWriteBufferSize), ) if err != nil { return err } - hubServer := NewServer(rpcPort, prometheusPort, longServer) + hubServer := NewServer(rpcPort, prometheusPort, longServer, conf) netDone := make(chan error) go func() { - err = hubServer.Start() + err = hubServer.Start(conf) netDone <- err }() return hubServer.LongConnServer.Run(netDone) diff --git a/internal/msggateway/message_handler.go b/internal/msggateway/message_handler.go index 105a77336e..208cd6bf7f 100644 --- a/internal/msggateway/message_handler.go +++ b/internal/msggateway/message_handler.go @@ -16,6 +16,7 @@ package msggateway import ( "context" + "github.com/openimsdk/open-im-server/v3/pkg/common/config" "sync" "github.com/OpenIMSDK/protocol/msg" @@ -105,9 +106,9 @@ type GrpcHandler struct { validate *validator.Validate } -func NewGrpcHandler(validate *validator.Validate, client discoveryregistry.SvcDiscoveryRegistry) *GrpcHandler { - msgRpcClient := rpcclient.NewMessageRpcClient(client) - pushRpcClient := rpcclient.NewPushRpcClient(client) +func NewGrpcHandler(validate *validator.Validate, client discoveryregistry.SvcDiscoveryRegistry, config *config.GlobalConfig) *GrpcHandler { + msgRpcClient := rpcclient.NewMessageRpcClient(client, config) + pushRpcClient := rpcclient.NewPushRpcClient(client, config) return &GrpcHandler{ msgRpcClient: &msgRpcClient, pushClient: &pushRpcClient, validate: validate, diff --git a/internal/msggateway/n_ws_server.go b/internal/msggateway/n_ws_server.go index e8ba9939ae..f5838c7036 100644 --- a/internal/msggateway/n_ws_server.go +++ b/internal/msggateway/n_ws_server.go @@ -49,7 +49,7 @@ type LongConnServer interface { GetUserPlatformCons(userID string, platform int) ([]*Client, bool, bool) Validate(s any) error SetCacheHandler(cache cache.MsgModel) - SetDiscoveryRegistry(client discoveryregistry.SvcDiscoveryRegistry) + SetDiscoveryRegistry(client discoveryregistry.SvcDiscoveryRegistry, config *config.GlobalConfig) KickUserConn(client *Client) error UnRegister(c *Client) SetKickHandlerInfo(i *kickHandler) @@ -66,6 +66,7 @@ type LongConnServer interface { // } type WsServer struct { + globalConfig *config.GlobalConfig port int wsMaxConnNum int64 registerChan chan *Client @@ -92,9 +93,9 @@ type kickHandler struct { newClient *Client } -func (ws *WsServer) SetDiscoveryRegistry(disCov discoveryregistry.SvcDiscoveryRegistry) { - ws.MessageHandler = NewGrpcHandler(ws.validate, disCov) - u := rpcclient.NewUserRpcClient(disCov) +func (ws *WsServer) SetDiscoveryRegistry(disCov discoveryregistry.SvcDiscoveryRegistry, config *config.GlobalConfig) { + ws.MessageHandler = NewGrpcHandler(ws.validate, disCov, config) + u := rpcclient.NewUserRpcClient(disCov, config) ws.userClient = &u ws.disCov = disCov } @@ -106,12 +107,12 @@ func (ws *WsServer) SetUserOnlineStatus(ctx context.Context, client *Client, sta } switch status { case constant.Online: - err := CallbackUserOnline(ctx, client.UserID, client.PlatformID, client.IsBackground, client.ctx.GetConnID()) + err := CallbackUserOnline(ctx, ws.globalConfig, client.UserID, client.PlatformID, client.IsBackground, client.ctx.GetConnID()) if err != nil { log.ZWarn(ctx, "CallbackUserOnline err", err) } case constant.Offline: - err := CallbackUserOffline(ctx, client.UserID, client.PlatformID, client.ctx.GetConnID()) + err := CallbackUserOffline(ctx, ws.globalConfig, client.UserID, client.PlatformID, client.ctx.GetConnID()) if err != nil { log.ZWarn(ctx, "CallbackUserOffline err", err) } @@ -141,13 +142,14 @@ func (ws *WsServer) GetUserPlatformCons(userID string, platform int) ([]*Client, return ws.clients.Get(userID, platform) } -func NewWsServer(opts ...Option) (*WsServer, error) { +func NewWsServer(globalConfig *config.GlobalConfig, opts ...Option) (*WsServer, error) { var config configs for _, o := range opts { o(&config) } v := validator.New() return &WsServer{ + globalConfig: globalConfig, port: config.port, wsMaxConnNum: config.maxConnNum, writeBufferSize: config.writeBufferSize, @@ -221,7 +223,7 @@ func (ws *WsServer) Run(done chan error) error { var concurrentRequest = 3 func (ws *WsServer) sendUserOnlineInfoToOtherNode(ctx context.Context, client *Client) error { - conns, err := ws.disCov.GetConns(ctx, config.Config.RpcRegisterName.OpenImMessageGatewayName) + conns, err := ws.disCov.GetConns(ctx, ws.globalConfig.RpcRegisterName.OpenImMessageGatewayName) if err != nil { return err } @@ -286,7 +288,7 @@ func (ws *WsServer) registerClient(client *Client) { } wg := sync.WaitGroup{} - if config.Config.Envs.Discovery == "zookeeper" { + if ws.globalConfig.Envs.Discovery == "zookeeper" { wg.Add(1) go func() { defer wg.Done() @@ -329,7 +331,7 @@ func (ws *WsServer) KickUserConn(client *Client) error { } func (ws *WsServer) multiTerminalLoginChecker(clientOK bool, oldClients []*Client, newClient *Client) { - switch config.Config.MultiLoginPolicy { + switch ws.globalConfig.MultiLoginPolicy { case constant.DefalutNotKick: case constant.PCAndOther: if constant.PlatformIDToClass(newClient.PlatformID) == constant.TerminalPC { @@ -441,7 +443,7 @@ func (ws *WsServer) ParseWSArgs(r *http.Request) (args *WSArgs, err error) { return nil, errs.ErrConnArgsErr.Wrap("platformID is not int") } v.PlatformID = platformID - if err = authverify.WsVerifyToken(v.Token, v.UserID, platformID); err != nil { + if err = authverify.WsVerifyToken(v.Token, v.UserID, ws.globalConfig.Secret, platformID); err != nil { return nil, err } if query.Get(Compression) == GzipCompressionProtocol { diff --git a/internal/msgtransfer/init.go b/internal/msgtransfer/init.go index dfb7c5307b..5e9e80663f 100644 --- a/internal/msgtransfer/init.go +++ b/internal/msgtransfer/init.go @@ -44,21 +44,22 @@ type MsgTransfer struct { // This consumer aggregated messages, subscribed to the topic:ws2ms_chat, // the modification notification is sent to msg_to_modify topic, the message is stored in redis, Incr Redis, // and then the message is sent to ms2pschat topic for push, and the message is sent to msg_to_mongo topic for persistence - historyCH *OnlineHistoryRedisConsumerHandler + historyCH *OnlineHistoryRedisConsumerHandler + historyMongoCH *OnlineHistoryMongoConsumerHandler // mongoDB batch insert, delete messages in redis after success, // and handle the deletion notification message deleted subscriptions topic: msg_to_mongo - historyMongoCH *OnlineHistoryMongoConsumerHandler - ctx context.Context - cancel context.CancelFunc + ctx context.Context + cancel context.CancelFunc + config *config.GlobalConfig } -func StartTransfer(prometheusPort int) error { - rdb, err := cache.NewRedis() +func StartTransfer(config *config.GlobalConfig, prometheusPort int) error { + rdb, err := cache.NewRedis(config) if err != nil { return err } - mongo, err := unrelation.NewMongo() + mongo, err := unrelation.NewMongo(config) if err != nil { return err } @@ -66,38 +67,37 @@ func StartTransfer(prometheusPort int) error { if err = mongo.CreateMsgIndex(); err != nil { return err } - - client, err := kdisc.NewDiscoveryRegister(config.Config.Envs.Discovery) + client, err := kdisc.NewDiscoveryRegister(config) if err != nil { return err } - if err := client.CreateRpcRootNodes(config.Config.GetServiceNames()); err != nil { + if err := client.CreateRpcRootNodes(config.GetServiceNames()); err != nil { return err } client.AddOption(mw.GrpcClient(), grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithDefaultServiceConfig(fmt.Sprintf(`{"LoadBalancingPolicy": "%s"}`, "round_robin"))) - msgModel := cache.NewMsgCacheModel(rdb) - msgDocModel := unrelation.NewMsgMongoDriver(mongo.GetDatabase()) - msgDatabase, err := controller.NewCommonMsgDatabase(msgDocModel, msgModel) + msgModel := cache.NewMsgCacheModel(rdb, config) + msgDocModel := unrelation.NewMsgMongoDriver(mongo.GetDatabase(config.Mongo.Database)) + msgDatabase, err := controller.NewCommonMsgDatabase(msgDocModel, msgModel, config) if err != nil { return err } - conversationRpcClient := rpcclient.NewConversationRpcClient(client) - groupRpcClient := rpcclient.NewGroupRpcClient(client) - msgTransfer, err := NewMsgTransfer(msgDatabase, &conversationRpcClient, &groupRpcClient) + conversationRpcClient := rpcclient.NewConversationRpcClient(client, config) + groupRpcClient := rpcclient.NewGroupRpcClient(client, config) + msgTransfer, err := NewMsgTransfer(config, msgDatabase, &conversationRpcClient, &groupRpcClient) if err != nil { return err } - return msgTransfer.Start(prometheusPort) + return msgTransfer.Start(prometheusPort, config) } -func NewMsgTransfer(msgDatabase controller.CommonMsgDatabase, conversationRpcClient *rpcclient.ConversationRpcClient, groupRpcClient *rpcclient.GroupRpcClient) (*MsgTransfer, error) { - historyCH, err := NewOnlineHistoryRedisConsumerHandler(msgDatabase, conversationRpcClient, groupRpcClient) +func NewMsgTransfer(config *config.GlobalConfig, msgDatabase controller.CommonMsgDatabase, conversationRpcClient *rpcclient.ConversationRpcClient, groupRpcClient *rpcclient.GroupRpcClient) (*MsgTransfer, error) { + historyCH, err := NewOnlineHistoryRedisConsumerHandler(config, msgDatabase, conversationRpcClient, groupRpcClient) if err != nil { return nil, err } - historyMongoCH, err := NewOnlineHistoryMongoConsumerHandler(msgDatabase) + historyMongoCH, err := NewOnlineHistoryMongoConsumerHandler(config, msgDatabase) if err != nil { return nil, err } @@ -105,11 +105,12 @@ func NewMsgTransfer(msgDatabase controller.CommonMsgDatabase, conversationRpcCli return &MsgTransfer{ historyCH: historyCH, historyMongoCH: historyMongoCH, + config: config, }, nil } -func (m *MsgTransfer) Start(prometheusPort int) error { - fmt.Println("Start msg transfer", "prometheusPort:", prometheusPort) +func (m *MsgTransfer) Start(prometheusPort int, config *config.GlobalConfig) error { + fmt.Println("start msg transfer", "prometheusPort:", prometheusPort) if prometheusPort <= 0 { return errs.Wrap(errors.New("prometheusPort not correct")) } @@ -123,13 +124,13 @@ func (m *MsgTransfer) Start(prometheusPort int) error { go m.historyCH.historyConsumerGroup.RegisterHandleAndConsumer(m.ctx, m.historyCH) go m.historyMongoCH.historyConsumerGroup.RegisterHandleAndConsumer(m.ctx, m.historyMongoCH) - if config.Config.Prometheus.Enable { + if config.Prometheus.Enable { go func() { proreg := prometheus.NewRegistry() proreg.MustRegister( collectors.NewGoCollector(), ) - proreg.MustRegister(prommetrics.GetGrpcCusMetrics("Transfer")...) + proreg.MustRegister(prommetrics.GetGrpcCusMetrics("Transfer", config)...) http.Handle("/metrics", promhttp.HandlerFor(proreg, promhttp.HandlerOpts{Registry: proreg})) err := http.ListenAndServe(fmt.Sprintf(":%d", prometheusPort), nil) if err != nil && err != http.ErrServerClosed { diff --git a/internal/msgtransfer/online_history_msg_handler.go b/internal/msgtransfer/online_history_msg_handler.go index 4995d10e85..b81bd12b8c 100644 --- a/internal/msgtransfer/online_history_msg_handler.go +++ b/internal/msgtransfer/online_history_msg_handler.go @@ -81,6 +81,7 @@ type OnlineHistoryRedisConsumerHandler struct { } func NewOnlineHistoryRedisConsumerHandler( + config *config.GlobalConfig, database controller.CommonMsgDatabase, conversationRpcClient *rpcclient.ConversationRpcClient, groupRpcClient *rpcclient.GroupRpcClient, @@ -96,11 +97,29 @@ func NewOnlineHistoryRedisConsumerHandler( och.conversationRpcClient = conversationRpcClient och.groupRpcClient = groupRpcClient var err error + + var tlsConfig *kafka.TLSConfig + if config.Kafka.TLS != nil { + tlsConfig = &kafka.TLSConfig{ + CACrt: config.Kafka.TLS.CACrt, + ClientCrt: config.Kafka.TLS.ClientCrt, + ClientKey: config.Kafka.TLS.ClientKey, + ClientKeyPwd: config.Kafka.TLS.ClientKeyPwd, + InsecureSkipVerify: false, + } + } + och.historyConsumerGroup, err = kafka.NewMConsumerGroup(&kafka.MConsumerGroupConfig{ KafkaVersion: sarama.V2_0_0_0, - OffsetsInitial: sarama.OffsetNewest, IsReturnErr: false, - }, []string{config.Config.Kafka.LatestMsgToRedis.Topic}, - config.Config.Kafka.Addr, config.Config.Kafka.ConsumerGroupID.MsgToRedis) + OffsetsInitial: sarama.OffsetNewest, + IsReturnErr: false, + UserName: config.Kafka.Username, + Password: config.Kafka.Password, + }, []string{config.Kafka.LatestMsgToRedis.Topic}, + config.Kafka.Addr, + config.Kafka.ConsumerGroupID.MsgToRedis, + tlsConfig, + ) // statistics.NewStatistics(&och.singleMsgSuccessCount, config.Config.ModuleName.MsgTransferName, fmt.Sprintf("%d // second singleMsgCount insert to mongo", constant.StatisticsTimeInterval), constant.StatisticsTimeInterval) return &och, err diff --git a/internal/msgtransfer/online_msg_to_mongo_handler.go b/internal/msgtransfer/online_msg_to_mongo_handler.go index efffc191f9..045f822206 100644 --- a/internal/msgtransfer/online_msg_to_mongo_handler.go +++ b/internal/msgtransfer/online_msg_to_mongo_handler.go @@ -32,12 +32,28 @@ type OnlineHistoryMongoConsumerHandler struct { msgDatabase controller.CommonMsgDatabase } -func NewOnlineHistoryMongoConsumerHandler(database controller.CommonMsgDatabase) (*OnlineHistoryMongoConsumerHandler, error) { +func NewOnlineHistoryMongoConsumerHandler(config *config.GlobalConfig, database controller.CommonMsgDatabase) (*OnlineHistoryMongoConsumerHandler, error) { + var tlsConfig *kfk.TLSConfig + if config.Kafka.TLS != nil { + tlsConfig = &kfk.TLSConfig{ + CACrt: config.Kafka.TLS.CACrt, + ClientCrt: config.Kafka.TLS.ClientCrt, + ClientKey: config.Kafka.TLS.ClientKey, + ClientKeyPwd: config.Kafka.TLS.ClientKeyPwd, + InsecureSkipVerify: false, + } + } historyConsumerGroup, err := kfk.NewMConsumerGroup(&kfk.MConsumerGroupConfig{ KafkaVersion: sarama.V2_0_0_0, - OffsetsInitial: sarama.OffsetNewest, IsReturnErr: false, - }, []string{config.Config.Kafka.MsgToMongo.Topic}, - config.Config.Kafka.Addr, config.Config.Kafka.ConsumerGroupID.MsgToMongo) + OffsetsInitial: sarama.OffsetNewest, + IsReturnErr: false, + UserName: config.Kafka.Username, + Password: config.Kafka.Password, + }, []string{config.Kafka.MsgToMongo.Topic}, + config.Kafka.Addr, + config.Kafka.ConsumerGroupID.MsgToMongo, + tlsConfig, + ) if err != nil { return nil, err } diff --git a/internal/push/callback.go b/internal/push/callback.go index 70862e4d23..6415d63d6b 100644 --- a/internal/push/callback.go +++ b/internal/push/callback.go @@ -26,12 +26,14 @@ import ( "github.com/openimsdk/open-im-server/v3/pkg/common/http" ) -func url() string { - return config.Config.Callback.CallbackUrl -} - -func callbackOfflinePush(ctx context.Context, userIDs []string, msg *sdkws.MsgData, offlinePushUserIDs *[]string) error { - if !config.Config.Callback.CallbackOfflinePush.Enable || msg.ContentType == constant.Typing { +func callbackOfflinePush( + ctx context.Context, + config *config.GlobalConfig, + userIDs []string, + msg *sdkws.MsgData, + offlinePushUserIDs *[]string, +) error { + if !config.Callback.CallbackOfflinePush.Enable || msg.ContentType == constant.Typing { return nil } req := &callbackstruct.CallbackBeforePushReq{ @@ -55,7 +57,7 @@ func callbackOfflinePush(ctx context.Context, userIDs []string, msg *sdkws.MsgDa } resp := &callbackstruct.CallbackBeforePushResp{} - if err := http.CallBackPostReturn(ctx, url(), req, resp, config.Config.Callback.CallbackOfflinePush); err != nil { + if err := http.CallBackPostReturn(ctx, config.Callback.CallbackUrl, req, resp, config.Callback.CallbackOfflinePush); err != nil { return err } @@ -68,8 +70,8 @@ func callbackOfflinePush(ctx context.Context, userIDs []string, msg *sdkws.MsgDa return nil } -func callbackOnlinePush(ctx context.Context, userIDs []string, msg *sdkws.MsgData) error { - if !config.Config.Callback.CallbackOnlinePush.Enable || utils.Contain(msg.SendID, userIDs...) || msg.ContentType == constant.Typing { +func callbackOnlinePush(ctx context.Context, config *config.GlobalConfig, userIDs []string, msg *sdkws.MsgData) error { + if !config.Callback.CallbackOnlinePush.Enable || utils.Contain(msg.SendID, userIDs...) || msg.ContentType == constant.Typing { return nil } req := callbackstruct.CallbackBeforePushReq{ @@ -91,7 +93,7 @@ func callbackOnlinePush(ctx context.Context, userIDs []string, msg *sdkws.MsgDat Content: GetContent(msg), } resp := &callbackstruct.CallbackBeforePushResp{} - if err := http.CallBackPostReturn(ctx, url(), req, resp, config.Config.Callback.CallbackOnlinePush); err != nil { + if err := http.CallBackPostReturn(ctx, config.Callback.CallbackUrl, req, resp, config.Callback.CallbackOnlinePush); err != nil { return err } return nil @@ -99,11 +101,12 @@ func callbackOnlinePush(ctx context.Context, userIDs []string, msg *sdkws.MsgDat func callbackBeforeSuperGroupOnlinePush( ctx context.Context, + config *config.GlobalConfig, groupID string, msg *sdkws.MsgData, pushToUserIDs *[]string, ) error { - if !config.Config.Callback.CallbackBeforeSuperGroupOnlinePush.Enable || msg.ContentType == constant.Typing { + if !config.Callback.CallbackBeforeSuperGroupOnlinePush.Enable || msg.ContentType == constant.Typing { return nil } req := callbackstruct.CallbackBeforeSuperGroupOnlinePushReq{ @@ -123,7 +126,7 @@ func callbackBeforeSuperGroupOnlinePush( Seq: msg.Seq, } resp := &callbackstruct.CallbackBeforeSuperGroupOnlinePushResp{} - if err := http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, req, resp, config.Config.Callback.CallbackBeforeSuperGroupOnlinePush); err != nil { + if err := http.CallBackPostReturn(ctx, config.Callback.CallbackUrl, req, resp, config.Callback.CallbackBeforeSuperGroupOnlinePush); err != nil { return err } diff --git a/internal/push/consumer_init.go b/internal/push/consumer_init.go index 92ce4714e6..4ad77de2c1 100644 --- a/internal/push/consumer_init.go +++ b/internal/push/consumer_init.go @@ -16,6 +16,7 @@ package push import ( "context" + "github.com/openimsdk/open-im-server/v3/pkg/common/config" ) type Consumer struct { @@ -24,8 +25,8 @@ type Consumer struct { // successCount uint64 } -func NewConsumer(pusher *Pusher) (*Consumer, error) { - c, err := NewConsumerHandler(pusher) +func NewConsumer(config *config.GlobalConfig, pusher *Pusher) (*Consumer, error) { + c, err := NewConsumerHandler(config, pusher) if err != nil { return nil, err } @@ -36,5 +37,4 @@ func NewConsumer(pusher *Pusher) (*Consumer, error) { func (c *Consumer) Start() { go c.pushCh.pushConsumerGroup.RegisterHandleAndConsumer(context.Background(), &c.pushCh) - } diff --git a/internal/push/offlinepush/fcm/push.go b/internal/push/offlinepush/fcm/push.go index aa6ec186f2..977254462c 100644 --- a/internal/push/offlinepush/fcm/push.go +++ b/internal/push/offlinepush/fcm/push.go @@ -20,12 +20,14 @@ import ( firebase "firebase.google.com/go" "firebase.google.com/go/messaging" + "github.com/redis/go-redis/v9" + "google.golang.org/api/option" + "github.com/OpenIMSDK/protocol/constant" + "github.com/openimsdk/open-im-server/v3/internal/push/offlinepush" "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" - "github.com/redis/go-redis/v9" - "google.golang.org/api/option" ) const SinglePushCountLimit = 400 @@ -39,9 +41,9 @@ type Fcm struct { // NewClient initializes a new FCM client using the Firebase Admin SDK. // It requires the FCM service account credentials file located within the project's configuration directory. -func NewClient(cache cache.MsgModel) *Fcm { - projectRoot, _ := config.GetProjectRoot() - credentialsFilePath := filepath.Join(projectRoot, "config", config.Config.Push.Fcm.ServiceAccount) +func NewClient(globalConfig *config.GlobalConfig, cache cache.MsgModel) *Fcm { + projectRoot := config.GetProjectRoot() + credentialsFilePath := filepath.Join(projectRoot, "config", globalConfig.Push.Fcm.ServiceAccount) opt := option.WithCredentialsFile(credentialsFilePath) fcmApp, err := firebase.NewApp(context.Background(), nil, opt) if err != nil { diff --git a/internal/push/offlinepush/getui/body.go b/internal/push/offlinepush/getui/body.go index 01eb22e733..46479163ff 100644 --- a/internal/push/offlinepush/getui/body.go +++ b/internal/push/offlinepush/getui/body.go @@ -133,13 +133,13 @@ type Payload struct { IsSignal bool `json:"isSignal"` } -func newPushReq(title, content string) PushReq { +func newPushReq(config *config.GlobalConfig, title, content string) PushReq { pushReq := PushReq{PushMessage: &PushMessage{Notification: &Notification{ Title: title, Body: content, ClickType: "startapp", - ChannelID: config.Config.Push.GeTui.ChannelID, - ChannelName: config.Config.Push.GeTui.ChannelName, + ChannelID: config.Push.GeTui.ChannelID, + ChannelName: config.Push.GeTui.ChannelName, }}} return pushReq } diff --git a/internal/push/offlinepush/getui/push.go b/internal/push/offlinepush/getui/push.go index e950585a1f..67f6292db3 100644 --- a/internal/push/offlinepush/getui/push.go +++ b/internal/push/offlinepush/getui/push.go @@ -55,10 +55,15 @@ type Client struct { cache cache.MsgModel tokenExpireTime int64 taskIDTTL int64 + config *config.GlobalConfig } -func NewClient(cache cache.MsgModel) *Client { - return &Client{cache: cache, tokenExpireTime: tokenExpireTime, taskIDTTL: taskIDTTL} +func NewClient(config *config.GlobalConfig, cache cache.MsgModel) *Client { + return &Client{cache: cache, + tokenExpireTime: tokenExpireTime, + taskIDTTL: taskIDTTL, + config: config, + } } func (g *Client) Push(ctx context.Context, userIDs []string, title, content string, opts *offlinepush.Opts) error { @@ -74,7 +79,7 @@ func (g *Client) Push(ctx context.Context, userIDs []string, title, content stri return err } } - pushReq := newPushReq(title, content) + pushReq := newPushReq(g.config, title, content) pushReq.setPushChannel(title, content) if len(userIDs) > 1 { maxNum := 999 @@ -85,9 +90,9 @@ func (g *Client) Push(ctx context.Context, userIDs []string, title, content stri for i, v := range s.GetSplitResult() { go func(index int, userIDs []string) { defer wg.Done() - if err2 := g.batchPush(ctx, token, userIDs, pushReq); err2 != nil { - log.ZError(ctx, "batchPush failed", err2, "index", index, "token", token, "req", pushReq) - err = err2 + if err := g.batchPush(ctx, token, userIDs, pushReq); err != nil { + log.ZError(ctx, "batchPush failed", err, "index", index, "token", token, "req", pushReq) + err = err } }(i, v.Item) } @@ -110,13 +115,13 @@ func (g *Client) Push(ctx context.Context, userIDs []string, title, content stri func (g *Client) Auth(ctx context.Context, timeStamp int64) (token string, expireTime int64, err error) { h := sha256.New() h.Write( - []byte(config.Config.Push.GeTui.AppKey + strconv.Itoa(int(timeStamp)) + config.Config.Push.GeTui.MasterSecret), + []byte(g.config.Push.GeTui.AppKey + strconv.Itoa(int(timeStamp)) + g.config.Push.GeTui.MasterSecret), ) sign := hex.EncodeToString(h.Sum(nil)) reqAuth := AuthReq{ Sign: sign, Timestamp: strconv.Itoa(int(timeStamp)), - AppKey: config.Config.Push.GeTui.AppKey, + AppKey: g.config.Push.GeTui.AppKey, } respAuth := AuthResp{} err = g.request(ctx, authURL, reqAuth, "", &respAuth) @@ -159,7 +164,7 @@ func (g *Client) request(ctx context.Context, url string, input any, token strin header := map[string]string{"token": token} resp := &Resp{} resp.Data = output - return g.postReturn(ctx, config.Config.Push.GeTui.PushUrl+url, header, input, resp, 3) + return g.postReturn(ctx, g.config.Push.GeTui.PushUrl+url, header, input, resp, 3) } func (g *Client) postReturn( diff --git a/internal/push/offlinepush/jpush/body/notification.go b/internal/push/offlinepush/jpush/body/notification.go index ddf3802afe..b25882ea58 100644 --- a/internal/push/offlinepush/jpush/body/notification.go +++ b/internal/push/offlinepush/jpush/body/notification.go @@ -46,7 +46,6 @@ type Extras struct { func (n *Notification) SetAlert(alert string) { n.Alert = alert n.Android.Alert = alert - n.SetAndroidIntent() n.IOS.Alert = alert n.IOS.Sound = "default" n.IOS.Badge = "+1" @@ -57,8 +56,8 @@ func (n *Notification) SetExtras(extras Extras) { n.Android.Extras = extras } -func (n *Notification) SetAndroidIntent() { - n.Android.Intent.URL = config.Config.Push.Jpns.PushIntent +func (n *Notification) SetAndroidIntent(config *config.GlobalConfig) { + n.Android.Intent.URL = config.Push.Jpns.PushIntent } func (n *Notification) IOSEnableMutableContent() { diff --git a/internal/push/offlinepush/jpush/push.go b/internal/push/offlinepush/jpush/push.go index 567269f3c6..2ced4bfd3d 100644 --- a/internal/push/offlinepush/jpush/push.go +++ b/internal/push/offlinepush/jpush/push.go @@ -25,10 +25,12 @@ import ( http2 "github.com/openimsdk/open-im-server/v3/pkg/common/http" ) -type JPush struct{} +type JPush struct { + config *config.GlobalConfig +} -func NewClient() *JPush { - return &JPush{} +func NewClient(config *config.GlobalConfig) *JPush { + return &JPush{config: config} } func (j *JPush) Auth(apiKey, secretKey string, timeStamp int64) (token string, err error) { @@ -59,10 +61,12 @@ func (j *JPush) Push(ctx context.Context, userIDs []string, title, content strin no.IOSEnableMutableContent() no.SetExtras(extras) no.SetAlert(title) + no.SetAndroidIntent(j.config) + var msg body.Message msg.SetMsgContent(content) var opt body.Options - opt.SetApnsProduction(config.Config.IOSPush.Production) + opt.SetApnsProduction(j.config.IOSPush.Production) var pushObj body.PushObj pushObj.SetPlatform(&pf) pushObj.SetAudience(&au) @@ -76,9 +80,9 @@ func (j *JPush) Push(ctx context.Context, userIDs []string, title, content strin func (j *JPush) request(ctx context.Context, po body.PushObj, resp any, timeout int) error { return http2.PostReturn( ctx, - config.Config.Push.Jpns.PushUrl, + j.config.Push.Jpns.PushUrl, map[string]string{ - "Authorization": j.getAuthorization(config.Config.Push.Jpns.AppKey, config.Config.Push.Jpns.MasterSecret), + "Authorization": j.getAuthorization(j.config.Push.Jpns.AppKey, j.config.Push.Jpns.MasterSecret), }, po, resp, diff --git a/internal/push/push_handler.go b/internal/push/push_handler.go index 7b7a1150a3..0e68e76b3d 100644 --- a/internal/push/push_handler.go +++ b/internal/push/push_handler.go @@ -33,15 +33,29 @@ type ConsumerHandler struct { pusher *Pusher } -func NewConsumerHandler(pusher *Pusher) (*ConsumerHandler, error) { +func NewConsumerHandler(config *config.GlobalConfig, pusher *Pusher) (*ConsumerHandler, error) { var consumerHandler ConsumerHandler consumerHandler.pusher = pusher var err error + var tlsConfig *kfk.TLSConfig + if config.Kafka.TLS != nil { + tlsConfig = &kfk.TLSConfig{ + CACrt: config.Kafka.TLS.CACrt, + ClientCrt: config.Kafka.TLS.ClientCrt, + ClientKey: config.Kafka.TLS.ClientKey, + ClientKeyPwd: config.Kafka.TLS.ClientKeyPwd, + InsecureSkipVerify: false, + } + } consumerHandler.pushConsumerGroup, err = kfk.NewMConsumerGroup(&kfk.MConsumerGroupConfig{ KafkaVersion: sarama.V2_0_0_0, - OffsetsInitial: sarama.OffsetNewest, IsReturnErr: false, - }, []string{config.Config.Kafka.MsgToPush.Topic}, config.Config.Kafka.Addr, - config.Config.Kafka.ConsumerGroupID.MsgToPush) + OffsetsInitial: sarama.OffsetNewest, + IsReturnErr: false, + UserName: config.Kafka.Username, + Password: config.Kafka.Password, + }, []string{config.Kafka.MsgToPush.Topic}, config.Kafka.Addr, + config.Kafka.ConsumerGroupID.MsgToPush, + tlsConfig) if err != nil { return nil, err } diff --git a/internal/push/push_rpc_server.go b/internal/push/push_rpc_server.go index c5516e7cf2..ed2a0b1ef6 100644 --- a/internal/push/push_rpc_server.go +++ b/internal/push/push_rpc_server.go @@ -16,6 +16,7 @@ package push import ( "context" + "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/OpenIMSDK/protocol/constant" pbpush "github.com/OpenIMSDK/protocol/push" @@ -31,20 +32,22 @@ import ( type pushServer struct { pusher *Pusher + config *config.GlobalConfig } -func Start(client discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) error { - rdb, err := cache.NewRedis() +func Start(config *config.GlobalConfig, client discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) error { + rdb, err := cache.NewRedis(config) if err != nil { return err } - cacheModel := cache.NewMsgCacheModel(rdb) - offlinePusher := NewOfflinePusher(cacheModel) + cacheModel := cache.NewMsgCacheModel(rdb, config) + offlinePusher := NewOfflinePusher(config, cacheModel) database := controller.NewPushDatabase(cacheModel) - groupRpcClient := rpcclient.NewGroupRpcClient(client) - conversationRpcClient := rpcclient.NewConversationRpcClient(client) - msgRpcClient := rpcclient.NewMessageRpcClient(client) + groupRpcClient := rpcclient.NewGroupRpcClient(client, config) + conversationRpcClient := rpcclient.NewConversationRpcClient(client, config) + msgRpcClient := rpcclient.NewMessageRpcClient(client, config) pusher := NewPusher( + config, client, offlinePusher, database, @@ -57,9 +60,10 @@ func Start(client discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) e pbpush.RegisterPushMsgServiceServer(server, &pushServer{ pusher: pusher, + config: config, }) - consumer, err := NewConsumer(pusher) + consumer, err := NewConsumer(config, pusher) if err != nil { return err } diff --git a/internal/push/push_to_client.go b/internal/push/push_to_client.go index 84efdba0cd..49bce70ab0 100644 --- a/internal/push/push_to_client.go +++ b/internal/push/push_to_client.go @@ -45,6 +45,7 @@ import ( ) type Pusher struct { + config *config.GlobalConfig database controller.PushDatabase discov discoveryregistry.SvcDiscoveryRegistry offlinePusher offlinepush.OfflinePusher @@ -57,11 +58,12 @@ type Pusher struct { var errNoOfflinePusher = errors.New("no offlinePusher is configured") -func NewPusher(discov discoveryregistry.SvcDiscoveryRegistry, offlinePusher offlinepush.OfflinePusher, database controller.PushDatabase, +func NewPusher(config *config.GlobalConfig, discov discoveryregistry.SvcDiscoveryRegistry, offlinePusher offlinepush.OfflinePusher, database controller.PushDatabase, groupLocalCache *localcache.GroupLocalCache, conversationLocalCache *localcache.ConversationLocalCache, conversationRpcClient *rpcclient.ConversationRpcClient, groupRpcClient *rpcclient.GroupRpcClient, msgRpcClient *rpcclient.MessageRpcClient, ) *Pusher { return &Pusher{ + config: config, discov: discov, database: database, offlinePusher: offlinePusher, @@ -73,15 +75,15 @@ func NewPusher(discov discoveryregistry.SvcDiscoveryRegistry, offlinePusher offl } } -func NewOfflinePusher(cache cache.MsgModel) offlinepush.OfflinePusher { +func NewOfflinePusher(config *config.GlobalConfig, cache cache.MsgModel) offlinepush.OfflinePusher { var offlinePusher offlinepush.OfflinePusher - switch config.Config.Push.Enable { + switch config.Push.Enable { case "getui": - offlinePusher = getui.NewClient(cache) + offlinePusher = getui.NewClient(config, cache) case "fcm": - offlinePusher = fcm.NewClient(cache) + offlinePusher = fcm.NewClient(config, cache) case "jpush": - offlinePusher = jpush.NewClient() + offlinePusher = jpush.NewClient(config) default: offlinePusher = dummy.NewClient() } @@ -99,7 +101,7 @@ func (p *Pusher) DeleteMemberAndSetConversationSeq(ctx context.Context, groupID func (p *Pusher) Push2User(ctx context.Context, userIDs []string, msg *sdkws.MsgData) error { log.ZDebug(ctx, "Get msg from msg_transfer And push msg", "userIDs", userIDs, "msg", msg.String()) - if err := callbackOnlinePush(ctx, userIDs, msg); err != nil { + if err := callbackOnlinePush(ctx, p.config, userIDs, msg); err != nil { return err } // push @@ -127,7 +129,7 @@ func (p *Pusher) Push2User(ctx context.Context, userIDs []string, msg *sdkws.Msg }) if len(offlinePushUserIDList) > 0 { - if err = callbackOfflinePush(ctx, offlinePushUserIDList, msg, &[]string{}); err != nil { + if err = callbackOfflinePush(ctx, p.config, offlinePushUserIDList, msg, &[]string{}); err != nil { return err } err = p.offlinePushMsg(ctx, msg.SendID, msg, offlinePushUserIDList) @@ -160,7 +162,7 @@ func (p *Pusher) k8sOfflinePush2SuperGroup(ctx context.Context, groupID string, } if len(needOfflinePushUserIDs) > 0 { var offlinePushUserIDs []string - err := callbackOfflinePush(ctx, needOfflinePushUserIDs, msg, &offlinePushUserIDs) + err := callbackOfflinePush(ctx, p.config, needOfflinePushUserIDs, msg, &offlinePushUserIDs) if err != nil { return err } @@ -191,7 +193,7 @@ func (p *Pusher) k8sOfflinePush2SuperGroup(ctx context.Context, groupID string, func (p *Pusher) Push2SuperGroup(ctx context.Context, groupID string, msg *sdkws.MsgData) (err error) { log.ZDebug(ctx, "Get super group msg from msg_transfer and push msg", "msg", msg.String(), "groupID", groupID) var pushToUserIDs []string - if err = callbackBeforeSuperGroupOnlinePush(ctx, groupID, msg, &pushToUserIDs); err != nil { + if err = callbackBeforeSuperGroupOnlinePush(ctx, p.config, groupID, msg, &pushToUserIDs); err != nil { return err } @@ -233,11 +235,11 @@ func (p *Pusher) Push2SuperGroup(ctx context.Context, groupID string, msg *sdkws return err } log.ZInfo(ctx, "GroupDismissedNotificationInfo****", "groupID", groupID, "num", len(pushToUserIDs), "list", pushToUserIDs) - if len(config.Config.Manager.UserID) > 0 { - ctx = mcontext.WithOpUserIDContext(ctx, config.Config.Manager.UserID[0]) + if len(p.config.Manager.UserID) > 0 { + ctx = mcontext.WithOpUserIDContext(ctx, p.config.Manager.UserID[0]) } - if len(config.Config.Manager.UserID) == 0 && len(config.Config.IMAdmin.UserID) > 0 { - ctx = mcontext.WithOpUserIDContext(ctx, config.Config.IMAdmin.UserID[0]) + if len(p.config.Manager.UserID) == 0 && len(p.config.IMAdmin.UserID) > 0 { + ctx = mcontext.WithOpUserIDContext(ctx, p.config.IMAdmin.UserID[0]) } defer func(groupID string) { if err = p.groupRpcClient.DismissGroup(ctx, groupID); err != nil { @@ -255,10 +257,10 @@ func (p *Pusher) Push2SuperGroup(ctx context.Context, groupID string, msg *sdkws log.ZDebug(ctx, "get conn and online push success", "result", wsResults, "msg", msg) isOfflinePush := utils.GetSwitchFromOptions(msg.Options, constant.IsOfflinePush) - if isOfflinePush && config.Config.Envs.Discovery == "k8s" { + if isOfflinePush && p.config.Envs.Discovery == "k8s" { return p.k8sOfflinePush2SuperGroup(ctx, groupID, msg, wsResults) } - if isOfflinePush && config.Config.Envs.Discovery == "zookeeper" { + if isOfflinePush && p.config.Envs.Discovery == "zookeeper" { var ( onlineSuccessUserIDs = []string{msg.SendID} webAndPcBackgroundUserIDs []string @@ -296,7 +298,7 @@ func (p *Pusher) Push2SuperGroup(ctx context.Context, groupID string, msg *sdkws // Use offline push messaging if len(needOfflinePushUserIDs) > 0 { var offlinePushUserIDs []string - err = callbackOfflinePush(ctx, needOfflinePushUserIDs, msg, &offlinePushUserIDs) + err = callbackOfflinePush(ctx, p.config, needOfflinePushUserIDs, msg, &offlinePushUserIDs) if err != nil { return err } @@ -355,7 +357,7 @@ func (p *Pusher) k8sOnlinePush(ctx context.Context, msg *sdkws.MsgData, pushToUs var ( mu sync.Mutex wg = errgroup.Group{} - maxWorkers = config.Config.Push.MaxConcurrentWorkers + maxWorkers = p.config.Push.MaxConcurrentWorkers ) if maxWorkers < 3 { maxWorkers = 3 @@ -384,10 +386,10 @@ func (p *Pusher) k8sOnlinePush(ctx context.Context, msg *sdkws.MsgData, pushToUs return wsResults, nil } func (p *Pusher) GetConnsAndOnlinePush(ctx context.Context, msg *sdkws.MsgData, pushToUserIDs []string) (wsResults []*msggateway.SingleMsgToUserResults, err error) { - if config.Config.Envs.Discovery == "k8s" { + if p.config.Envs.Discovery == "k8s" { return p.k8sOnlinePush(ctx, msg, pushToUserIDs) } - conns, err := p.discov.GetConns(ctx, config.Config.RpcRegisterName.OpenImMessageGatewayName) + conns, err := p.discov.GetConns(ctx, p.config.RpcRegisterName.OpenImMessageGatewayName) log.ZDebug(ctx, "get gateway conn", "conn length", len(conns)) if err != nil { return nil, err @@ -397,7 +399,7 @@ func (p *Pusher) GetConnsAndOnlinePush(ctx context.Context, msg *sdkws.MsgData, mu sync.Mutex wg = errgroup.Group{} input = &msggateway.OnlineBatchPushOneMsgReq{MsgData: msg, PushToUserIDs: pushToUserIDs} - maxWorkers = config.Config.Push.MaxConcurrentWorkers + maxWorkers = p.config.Push.MaxConcurrentWorkers ) if maxWorkers < 3 { diff --git a/internal/rpc/auth/auth.go b/internal/rpc/auth/auth.go index 5f53911a4a..eb1e2f68a0 100644 --- a/internal/rpc/auth/auth.go +++ b/internal/rpc/auth/auth.go @@ -38,29 +38,32 @@ type authServer struct { authDatabase controller.AuthDatabase userRpcClient *rpcclient.UserRpcClient RegisterCenter discoveryregistry.SvcDiscoveryRegistry + config *config.GlobalConfig } -func Start(client discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) error { - rdb, err := cache.NewRedis() +func Start(config *config.GlobalConfig, client discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) error { + rdb, err := cache.NewRedis(config) if err != nil { return err } - userRpcClient := rpcclient.NewUserRpcClient(client) + userRpcClient := rpcclient.NewUserRpcClient(client, config) pbauth.RegisterAuthServer(server, &authServer{ userRpcClient: &userRpcClient, RegisterCenter: client, authDatabase: controller.NewAuthDatabase( - cache.NewMsgCacheModel(rdb), - config.Config.Secret, - config.Config.TokenPolicy.Expire, + cache.NewMsgCacheModel(rdb, config), + config.Secret, + config.TokenPolicy.Expire, + config, ), + config: config, }) return nil } func (s *authServer) UserToken(ctx context.Context, req *pbauth.UserTokenReq) (*pbauth.UserTokenResp, error) { resp := pbauth.UserTokenResp{} - if req.Secret != config.Config.Secret { + if req.Secret != s.config.Secret { return nil, errs.ErrNoPermission.Wrap("secret invalid") } if _, err := s.userRpcClient.GetUserInfo(ctx, req.UserID); err != nil { @@ -72,17 +75,17 @@ func (s *authServer) UserToken(ctx context.Context, req *pbauth.UserTokenReq) (* } prommetrics.UserLoginCounter.Inc() resp.Token = token - resp.ExpireTimeSeconds = config.Config.TokenPolicy.Expire * 24 * 60 * 60 + resp.ExpireTimeSeconds = s.config.TokenPolicy.Expire * 24 * 60 * 60 return &resp, nil } func (s *authServer) GetUserToken(ctx context.Context, req *pbauth.GetUserTokenReq) (*pbauth.GetUserTokenResp, error) { - if err := authverify.CheckAdmin(ctx); err != nil { + if err := authverify.CheckAdmin(ctx, s.config); err != nil { return nil, err } resp := pbauth.GetUserTokenResp{} - if authverify.IsManagerUserID(req.UserID) { + if authverify.IsManagerUserID(req.UserID, s.config) { return nil, errs.ErrNoPermission.Wrap("don't get Admin token") } @@ -94,12 +97,12 @@ func (s *authServer) GetUserToken(ctx context.Context, req *pbauth.GetUserTokenR return nil, err } resp.Token = token - resp.ExpireTimeSeconds = config.Config.TokenPolicy.Expire * 24 * 60 * 60 + resp.ExpireTimeSeconds = s.config.TokenPolicy.Expire * 24 * 60 * 60 return &resp, nil } func (s *authServer) parseToken(ctx context.Context, tokensString string) (claims *tokenverify.Claims, err error) { - claims, err = tokenverify.GetClaimFromToken(tokensString, authverify.Secret()) + claims, err = tokenverify.GetClaimFromToken(tokensString, authverify.Secret(s.config.Secret)) if err != nil { return nil, errs.Wrap(err) } @@ -139,7 +142,7 @@ func (s *authServer) ParseToken( } func (s *authServer) ForceLogout(ctx context.Context, req *pbauth.ForceLogoutReq) (*pbauth.ForceLogoutResp, error) { - if err := authverify.CheckAdmin(ctx); err != nil { + if err := authverify.CheckAdmin(ctx, s.config); err != nil { return nil, err } if err := s.forceKickOff(ctx, req.UserID, req.PlatformID, mcontext.GetOperationID(ctx)); err != nil { @@ -149,7 +152,7 @@ func (s *authServer) ForceLogout(ctx context.Context, req *pbauth.ForceLogoutReq } func (s *authServer) forceKickOff(ctx context.Context, userID string, platformID int32, operationID string) error { - conns, err := s.RegisterCenter.GetConns(ctx, config.Config.RpcRegisterName.OpenImMessageGatewayName) + conns, err := s.RegisterCenter.GetConns(ctx, s.config.RpcRegisterName.OpenImMessageGatewayName) if err != nil { return err } diff --git a/internal/rpc/conversation/conversaion.go b/internal/rpc/conversation/conversaion.go index f3dc7ef17b..cc08de2984 100644 --- a/internal/rpc/conversation/conversaion.go +++ b/internal/rpc/conversation/conversaion.go @@ -17,6 +17,7 @@ package conversation import ( "context" "errors" + "github.com/openimsdk/open-im-server/v3/pkg/common/config" "sort" "github.com/OpenIMSDK/protocol/constant" @@ -44,6 +45,7 @@ type conversationServer struct { groupRpcClient *rpcclient.GroupRpcClient conversationDatabase controller.ConversationDatabase conversationNotificationSender *notification.ConversationNotificationSender + config *config.GlobalConfig } func (c *conversationServer) GetConversationNotReceiveMessageUserIDs( @@ -54,28 +56,29 @@ func (c *conversationServer) GetConversationNotReceiveMessageUserIDs( panic("implement me") } -func Start(client discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) error { - rdb, err := cache.NewRedis() +func Start(config *config.GlobalConfig, client discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) error { + rdb, err := cache.NewRedis(config) if err != nil { return err } - mongo, err := unrelation.NewMongo() + mongo, err := unrelation.NewMongo(config) if err != nil { return err } - conversationDB, err := mgo.NewConversationMongo(mongo.GetDatabase()) + conversationDB, err := mgo.NewConversationMongo(mongo.GetDatabase(config.Mongo.Database)) if err != nil { return err } - groupRpcClient := rpcclient.NewGroupRpcClient(client) - msgRpcClient := rpcclient.NewMessageRpcClient(client) - userRpcClient := rpcclient.NewUserRpcClient(client) + groupRpcClient := rpcclient.NewGroupRpcClient(client, config) + msgRpcClient := rpcclient.NewMessageRpcClient(client, config) + userRpcClient := rpcclient.NewUserRpcClient(client, config) pbconversation.RegisterConversationServer(server, &conversationServer{ msgRpcClient: &msgRpcClient, user: &userRpcClient, - conversationNotificationSender: notification.NewConversationNotificationSender(&msgRpcClient), + conversationNotificationSender: notification.NewConversationNotificationSender(config, &msgRpcClient), groupRpcClient: &groupRpcClient, conversationDatabase: controller.NewConversationDatabase(conversationDB, cache.NewConversationRedis(rdb, cache.GetDefaultOpt(), conversationDB), tx.NewMongo(mongo.GetClient())), + config: config, }) return nil } diff --git a/internal/rpc/friend/black.go b/internal/rpc/friend/black.go index 57edd26ba9..64c63eb734 100644 --- a/internal/rpc/friend/black.go +++ b/internal/rpc/friend/black.go @@ -65,7 +65,7 @@ func (s *friendServer) RemoveBlack(ctx context.Context, req *pbfriend.RemoveBlac } func (s *friendServer) AddBlack(ctx context.Context, req *pbfriend.AddBlackReq) (*pbfriend.AddBlackResp, error) { - if err := authverify.CheckAccessV3(ctx, req.OwnerUserID); err != nil { + if err := authverify.CheckAccessV3(ctx, req.OwnerUserID, s.config); err != nil { return nil, err } _, err := s.userRpcClient.GetUsersInfo(ctx, []string{req.OwnerUserID, req.BlackUserID}) diff --git a/internal/rpc/friend/callback.go b/internal/rpc/friend/callback.go index 2b6e31899f..78d4fc926f 100644 --- a/internal/rpc/friend/callback.go +++ b/internal/rpc/friend/callback.go @@ -24,8 +24,8 @@ import ( "github.com/openimsdk/open-im-server/v3/pkg/common/http" ) -func CallbackBeforeAddFriend(ctx context.Context, req *pbfriend.ApplyToAddFriendReq) error { - if !config.Config.Callback.CallbackBeforeAddFriend.Enable { +func CallbackBeforeAddFriend(ctx context.Context, globalConfig *config.GlobalConfig, req *pbfriend.ApplyToAddFriendReq) error { + if !globalConfig.Callback.CallbackBeforeAddFriend.Enable { return nil } cbReq := &cbapi.CallbackBeforeAddFriendReq{ @@ -36,14 +36,14 @@ func CallbackBeforeAddFriend(ctx context.Context, req *pbfriend.ApplyToAddFriend Ex: req.Ex, } resp := &cbapi.CallbackBeforeAddFriendResp{} - if err := http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, cbReq, resp, config.Config.Callback.CallbackBeforeAddFriend); err != nil { + if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, cbReq, resp, globalConfig.Callback.CallbackBeforeAddFriend); err != nil { return err } return nil } -func CallbackBeforeSetFriendRemark(ctx context.Context, req *pbfriend.SetFriendRemarkReq) error { - if !config.Config.Callback.CallbackBeforeSetFriendRemark.Enable { +func CallbackBeforeSetFriendRemark(ctx context.Context, globalConfig *config.GlobalConfig, req *pbfriend.SetFriendRemarkReq) error { + if !globalConfig.Callback.CallbackBeforeSetFriendRemark.Enable { return nil } cbReq := &cbapi.CallbackBeforeSetFriendRemarkReq{ @@ -53,15 +53,15 @@ func CallbackBeforeSetFriendRemark(ctx context.Context, req *pbfriend.SetFriendR Remark: req.Remark, } resp := &cbapi.CallbackBeforeSetFriendRemarkResp{} - if err := http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, cbReq, resp, config.Config.Callback.CallbackBeforeAddFriend); err != nil { + if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, cbReq, resp, globalConfig.Callback.CallbackBeforeAddFriend); err != nil { return err } utils.NotNilReplace(&req.Remark, &resp.Remark) return nil } -func CallbackAfterSetFriendRemark(ctx context.Context, req *pbfriend.SetFriendRemarkReq) error { - if !config.Config.Callback.CallbackAfterSetFriendRemark.Enable { +func CallbackAfterSetFriendRemark(ctx context.Context, globalConfig *config.GlobalConfig, req *pbfriend.SetFriendRemarkReq) error { + if !globalConfig.Callback.CallbackAfterSetFriendRemark.Enable { return nil } cbReq := &cbapi.CallbackAfterSetFriendRemarkReq{ @@ -71,13 +71,13 @@ func CallbackAfterSetFriendRemark(ctx context.Context, req *pbfriend.SetFriendRe Remark: req.Remark, } resp := &cbapi.CallbackAfterSetFriendRemarkResp{} - if err := http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, cbReq, resp, config.Config.Callback.CallbackBeforeAddFriend); err != nil { + if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, cbReq, resp, globalConfig.Callback.CallbackBeforeAddFriend); err != nil { return err } return nil } -func CallbackBeforeAddBlack(ctx context.Context, req *pbfriend.AddBlackReq) error { - if !config.Config.Callback.CallbackBeforeAddBlack.Enable { +func CallbackBeforeAddBlack(ctx context.Context, globalConfig *config.GlobalConfig, req *pbfriend.AddBlackReq) error { + if !globalConfig.Callback.CallbackBeforeAddBlack.Enable { return nil } cbReq := &cbapi.CallbackBeforeAddBlackReq{ @@ -86,13 +86,13 @@ func CallbackBeforeAddBlack(ctx context.Context, req *pbfriend.AddBlackReq) erro BlackUserID: req.BlackUserID, } resp := &cbapi.CallbackBeforeAddBlackResp{} - if err := http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, cbReq, resp, config.Config.Callback.CallbackBeforeAddBlack); err != nil { + if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, cbReq, resp, globalConfig.Callback.CallbackBeforeAddBlack); err != nil { return err } return nil } -func CallbackAfterAddFriend(ctx context.Context, req *pbfriend.ApplyToAddFriendReq) error { - if !config.Config.Callback.CallbackAfterAddFriend.Enable { +func CallbackAfterAddFriend(ctx context.Context, globalConfig *config.GlobalConfig, req *pbfriend.ApplyToAddFriendReq) error { + if !globalConfig.Callback.CallbackAfterAddFriend.Enable { return nil } cbReq := &cbapi.CallbackAfterAddFriendReq{ @@ -102,14 +102,14 @@ func CallbackAfterAddFriend(ctx context.Context, req *pbfriend.ApplyToAddFriendR ReqMsg: req.ReqMsg, } resp := &cbapi.CallbackAfterAddFriendResp{} - if err := http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, cbReq, resp, config.Config.Callback.CallbackAfterAddFriend); err != nil { + if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, cbReq, resp, globalConfig.Callback.CallbackAfterAddFriend); err != nil { return err } return nil } -func CallbackBeforeAddFriendAgree(ctx context.Context, req *pbfriend.RespondFriendApplyReq) error { - if !config.Config.Callback.CallbackBeforeAddFriendAgree.Enable { +func CallbackBeforeAddFriendAgree(ctx context.Context, globalConfig *config.GlobalConfig, req *pbfriend.RespondFriendApplyReq) error { + if !globalConfig.Callback.CallbackBeforeAddFriendAgree.Enable { return nil } cbReq := &cbapi.CallbackBeforeAddFriendAgreeReq{ @@ -120,13 +120,13 @@ func CallbackBeforeAddFriendAgree(ctx context.Context, req *pbfriend.RespondFrie HandleResult: req.HandleResult, } resp := &cbapi.CallbackBeforeAddFriendAgreeResp{} - if err := http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, cbReq, resp, config.Config.Callback.CallbackBeforeAddFriendAgree); err != nil { + if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, cbReq, resp, globalConfig.Callback.CallbackBeforeAddFriendAgree); err != nil { return err } return nil } -func CallbackAfterDeleteFriend(ctx context.Context, req *pbfriend.DeleteFriendReq) error { - if !config.Config.Callback.CallbackAfterDeleteFriend.Enable { +func CallbackAfterDeleteFriend(ctx context.Context, globalConfig *config.GlobalConfig, req *pbfriend.DeleteFriendReq) error { + if !globalConfig.Callback.CallbackAfterDeleteFriend.Enable { return nil } cbReq := &cbapi.CallbackAfterDeleteFriendReq{ @@ -135,13 +135,13 @@ func CallbackAfterDeleteFriend(ctx context.Context, req *pbfriend.DeleteFriendRe FriendUserID: req.FriendUserID, } resp := &cbapi.CallbackAfterDeleteFriendResp{} - if err := http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, cbReq, resp, config.Config.Callback.CallbackAfterDeleteFriend); err != nil { + if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, cbReq, resp, globalConfig.Callback.CallbackAfterDeleteFriend); err != nil { return err } return nil } -func CallbackBeforeImportFriends(ctx context.Context, req *pbfriend.ImportFriendReq) error { - if !config.Config.Callback.CallbackBeforeImportFriends.Enable { +func CallbackBeforeImportFriends(ctx context.Context, globalConfig *config.GlobalConfig, req *pbfriend.ImportFriendReq) error { + if !globalConfig.Callback.CallbackBeforeImportFriends.Enable { return nil } cbReq := &cbapi.CallbackBeforeImportFriendsReq{ @@ -150,7 +150,7 @@ func CallbackBeforeImportFriends(ctx context.Context, req *pbfriend.ImportFriend FriendUserIDs: req.FriendUserIDs, } resp := &cbapi.CallbackBeforeImportFriendsResp{} - if err := http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, cbReq, resp, config.Config.Callback.CallbackBeforeImportFriends); err != nil { + if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, cbReq, resp, globalConfig.Callback.CallbackBeforeImportFriends); err != nil { return err } if len(resp.FriendUserIDs) != 0 { @@ -158,8 +158,8 @@ func CallbackBeforeImportFriends(ctx context.Context, req *pbfriend.ImportFriend } return nil } -func CallbackAfterImportFriends(ctx context.Context, req *pbfriend.ImportFriendReq) error { - if !config.Config.Callback.CallbackAfterImportFriends.Enable { +func CallbackAfterImportFriends(ctx context.Context, globalConfig *config.GlobalConfig, req *pbfriend.ImportFriendReq) error { + if !globalConfig.Callback.CallbackAfterImportFriends.Enable { return nil } cbReq := &cbapi.CallbackAfterImportFriendsReq{ @@ -168,14 +168,14 @@ func CallbackAfterImportFriends(ctx context.Context, req *pbfriend.ImportFriendR FriendUserIDs: req.FriendUserIDs, } resp := &cbapi.CallbackAfterImportFriendsResp{} - if err := http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, cbReq, resp, config.Config.Callback.CallbackAfterImportFriends); err != nil { + if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, cbReq, resp, globalConfig.Callback.CallbackAfterImportFriends); err != nil { return err } return nil } -func CallbackAfterRemoveBlack(ctx context.Context, req *pbfriend.RemoveBlackReq) error { - if !config.Config.Callback.CallbackAfterRemoveBlack.Enable { +func CallbackAfterRemoveBlack(ctx context.Context, globalConfig *config.GlobalConfig, req *pbfriend.RemoveBlackReq) error { + if !globalConfig.Callback.CallbackAfterRemoveBlack.Enable { return nil } cbReq := &cbapi.CallbackAfterRemoveBlackReq{ @@ -184,7 +184,7 @@ func CallbackAfterRemoveBlack(ctx context.Context, req *pbfriend.RemoveBlackReq) BlackUserID: req.BlackUserID, } resp := &cbapi.CallbackAfterRemoveBlackResp{} - if err := http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, cbReq, resp, config.Config.Callback.CallbackAfterRemoveBlack); err != nil { + if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, cbReq, resp, globalConfig.Callback.CallbackAfterRemoveBlack); err != nil { return err } return nil diff --git a/internal/rpc/friend/friend.go b/internal/rpc/friend/friend.go index 4168731f7b..ffdeee98f0 100644 --- a/internal/rpc/friend/friend.go +++ b/internal/rpc/friend/friend.go @@ -16,25 +16,33 @@ package friend import ( "context" + "github.com/openimsdk/open-im-server/v3/pkg/common/config" + + "github.com/OpenIMSDK/tools/tx" + + "github.com/OpenIMSDK/protocol/sdkws" + + "github.com/openimsdk/open-im-server/v3/pkg/authverify" + + "github.com/OpenIMSDK/tools/log" + + "github.com/openimsdk/open-im-server/v3/pkg/common/convert" + "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" + + "google.golang.org/grpc" "github.com/OpenIMSDK/protocol/constant" pbfriend "github.com/OpenIMSDK/protocol/friend" - "github.com/OpenIMSDK/protocol/sdkws" registry "github.com/OpenIMSDK/tools/discoveryregistry" "github.com/OpenIMSDK/tools/errs" - "github.com/OpenIMSDK/tools/log" - "github.com/OpenIMSDK/tools/tx" "github.com/OpenIMSDK/tools/utils" - "github.com/openimsdk/open-im-server/v3/pkg/authverify" - "github.com/openimsdk/open-im-server/v3/pkg/common/convert" + "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" "github.com/openimsdk/open-im-server/v3/pkg/common/db/mgo" tablerelation "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" "github.com/openimsdk/open-im-server/v3/pkg/common/db/unrelation" - "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient/notification" - "google.golang.org/grpc" ) type friendServer struct { @@ -44,42 +52,44 @@ type friendServer struct { notificationSender *notification.FriendNotificationSender conversationRpcClient rpcclient.ConversationRpcClient RegisterCenter registry.SvcDiscoveryRegistry + config *config.GlobalConfig } -func Start(client registry.SvcDiscoveryRegistry, server *grpc.Server) error { +func Start(config *config.GlobalConfig, client registry.SvcDiscoveryRegistry, server *grpc.Server) error { // Initialize MongoDB - mongo, err := unrelation.NewMongo() + mongo, err := unrelation.NewMongo(config) if err != nil { return err } // Initialize Redis - rdb, err := cache.NewRedis() + rdb, err := cache.NewRedis(config) if err != nil { return err } - friendMongoDB, err := mgo.NewFriendMongo(mongo.GetDatabase()) + friendMongoDB, err := mgo.NewFriendMongo(mongo.GetDatabase(config.Mongo.Database)) if err != nil { return err } - friendRequestMongoDB, err := mgo.NewFriendRequestMongo(mongo.GetDatabase()) + friendRequestMongoDB, err := mgo.NewFriendRequestMongo(mongo.GetDatabase(config.Mongo.Database)) if err != nil { return err } - blackMongoDB, err := mgo.NewBlackMongo(mongo.GetDatabase()) + blackMongoDB, err := mgo.NewBlackMongo(mongo.GetDatabase(config.Mongo.Database)) if err != nil { return err } // Initialize RPC clients - userRpcClient := rpcclient.NewUserRpcClient(client) - msgRpcClient := rpcclient.NewMessageRpcClient(client) + userRpcClient := rpcclient.NewUserRpcClient(client, config) + msgRpcClient := rpcclient.NewMessageRpcClient(client, config) // Initialize notification sender notificationSender := notification.NewFriendNotificationSender( + config, &msgRpcClient, notification.WithRpcFunc(userRpcClient.GetUsersInfo), ) @@ -98,7 +108,8 @@ func Start(client registry.SvcDiscoveryRegistry, server *grpc.Server) error { userRpcClient: &userRpcClient, notificationSender: notificationSender, RegisterCenter: client, - conversationRpcClient: rpcclient.NewConversationRpcClient(client), + conversationRpcClient: rpcclient.NewConversationRpcClient(client, config), + config: config, }) return nil @@ -106,15 +117,14 @@ func Start(client registry.SvcDiscoveryRegistry, server *grpc.Server) error { // ok. func (s *friendServer) ApplyToAddFriend(ctx context.Context, req *pbfriend.ApplyToAddFriendReq) (resp *pbfriend.ApplyToAddFriendResp, err error) { - defer log.ZInfo(ctx, utils.GetFuncName()+" Return") resp = &pbfriend.ApplyToAddFriendResp{} - if err := authverify.CheckAccessV3(ctx, req.FromUserID); err != nil { + if err := authverify.CheckAccessV3(ctx, req.FromUserID,s.config); err != nil { return nil, err } if req.ToUserID == req.FromUserID { - return nil, errs.ErrCanNotAddYourself.Wrap() + return nil, errs.ErrCanNotAddYourself.Wrap("req.ToUserID", req.ToUserID) } - if err = CallbackBeforeAddFriend(ctx, req); err != nil && err != errs.ErrCallbackContinue { + if err = CallbackBeforeAddFriend(ctx, s.config, req); err != nil && err != errs.ErrCallbackContinue { return nil, err } if _, err := s.userRpcClient.GetUsersInfoMap(ctx, []string{req.ToUserID, req.FromUserID}); err != nil { @@ -131,7 +141,7 @@ func (s *friendServer) ApplyToAddFriend(ctx context.Context, req *pbfriend.Apply return nil, err } s.notificationSender.FriendApplicationAddNotification(ctx, req) - if err = CallbackAfterAddFriend(ctx, req); err != nil && err != errs.ErrCallbackContinue { + if err = CallbackAfterAddFriend(ctx,s.config ,req); err != nil && err != errs.ErrCallbackContinue { return nil, err } return resp, nil @@ -140,7 +150,7 @@ func (s *friendServer) ApplyToAddFriend(ctx context.Context, req *pbfriend.Apply // ok. func (s *friendServer) ImportFriends(ctx context.Context, req *pbfriend.ImportFriendReq) (resp *pbfriend.ImportFriendResp, err error) { defer log.ZInfo(ctx, utils.GetFuncName()+" Return") - if err := authverify.CheckAdmin(ctx); err != nil { + if err := authverify.CheckAdmin(ctx, s.config); err != nil { return nil, err } if _, err := s.userRpcClient.GetUsersInfo(ctx, append([]string{req.OwnerUserID}, req.FriendUserIDs...)); err != nil { @@ -152,7 +162,7 @@ func (s *friendServer) ImportFriends(ctx context.Context, req *pbfriend.ImportFr if utils.Duplicate(req.FriendUserIDs) { return nil, errs.ErrArgs.Wrap("friend userID repeated") } - if err := CallbackBeforeImportFriends(ctx, req); err != nil { + if err := CallbackBeforeImportFriends(ctx, s.config, req); err != nil { return nil, err } @@ -166,7 +176,7 @@ func (s *friendServer) ImportFriends(ctx context.Context, req *pbfriend.ImportFr HandleResult: constant.FriendResponseAgree, }) } - if err := CallbackAfterImportFriends(ctx, req); err != nil { + if err := CallbackAfterImportFriends(ctx, s.config, req); err != nil { return nil, err } return &pbfriend.ImportFriendResp{}, nil @@ -176,7 +186,7 @@ func (s *friendServer) ImportFriends(ctx context.Context, req *pbfriend.ImportFr func (s *friendServer) RespondFriendApply(ctx context.Context, req *pbfriend.RespondFriendApplyReq) (resp *pbfriend.RespondFriendApplyResp, err error) { defer log.ZInfo(ctx, utils.GetFuncName()+" Return") resp = &pbfriend.RespondFriendApplyResp{} - if err := authverify.CheckAccessV3(ctx, req.ToUserID); err != nil { + if err := authverify.CheckAccessV3(ctx, req.ToUserID, s.config); err != nil { return nil, err } @@ -187,7 +197,7 @@ func (s *friendServer) RespondFriendApply(ctx context.Context, req *pbfriend.Res HandleResult: req.HandleResult, } if req.HandleResult == constant.FriendResponseAgree { - if err := CallbackBeforeAddFriendAgree(ctx, req); err != nil && err != errs.ErrCallbackContinue { + if err := CallbackBeforeAddFriendAgree(ctx, s.config, req); err != nil && err != errs.ErrCallbackContinue { return nil, err } err := s.friendDatabase.AgreeFriendRequest(ctx, &friendRequest) @@ -223,7 +233,7 @@ func (s *friendServer) DeleteFriend(ctx context.Context, req *pbfriend.DeleteFri return nil, err } s.notificationSender.FriendDeletedNotification(ctx, req) - if err := CallbackAfterDeleteFriend(ctx, req); err != nil { + if err := CallbackAfterDeleteFriend(ctx, s.config, req); err != nil { return nil, err } return resp, nil @@ -233,7 +243,7 @@ func (s *friendServer) DeleteFriend(ctx context.Context, req *pbfriend.DeleteFri func (s *friendServer) SetFriendRemark(ctx context.Context, req *pbfriend.SetFriendRemarkReq) (resp *pbfriend.SetFriendRemarkResp, err error) { defer log.ZInfo(ctx, utils.GetFuncName()+" Return") - if err = CallbackBeforeSetFriendRemark(ctx, req); err != nil && err != errs.ErrCallbackContinue { + if err = CallbackBeforeSetFriendRemark(ctx, s.config, req); err != nil && err != errs.ErrCallbackContinue { return nil, err } resp = &pbfriend.SetFriendRemarkResp{} @@ -247,7 +257,7 @@ func (s *friendServer) SetFriendRemark(ctx context.Context, req *pbfriend.SetFri if err := s.friendDatabase.UpdateRemark(ctx, req.OwnerUserID, req.FriendUserID, req.Remark); err != nil { return nil, err } - if err := CallbackAfterSetFriendRemark(ctx, req); err != nil && err != errs.ErrCallbackContinue { + if err := CallbackAfterSetFriendRemark(ctx, s.config, req); err != nil && err != errs.ErrCallbackContinue { return nil, err } s.notificationSender.FriendRemarkSetNotification(ctx, req.OwnerUserID, req.FriendUserID) diff --git a/internal/rpc/group/callback.go b/internal/rpc/group/callback.go index f09c23ec68..e82177dde0 100644 --- a/internal/rpc/group/callback.go +++ b/internal/rpc/group/callback.go @@ -32,8 +32,8 @@ import ( "github.com/openimsdk/open-im-server/v3/pkg/common/http" ) -func CallbackBeforeCreateGroup(ctx context.Context, req *group.CreateGroupReq) (err error) { - if !config.Config.Callback.CallbackBeforeCreateGroup.Enable { +func CallbackBeforeCreateGroup(ctx context.Context, globalConfig *config.GlobalConfig, req *group.CreateGroupReq) (err error) { + if !globalConfig.Callback.CallbackBeforeCreateGroup.Enable { return nil } cbReq := &callbackstruct.CallbackBeforeCreateGroupReq{ @@ -58,7 +58,7 @@ func CallbackBeforeCreateGroup(ctx context.Context, req *group.CreateGroupReq) ( }) } resp := &callbackstruct.CallbackBeforeCreateGroupResp{} - if err = http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, cbReq, resp, config.Config.Callback.CallbackBeforeCreateGroup); err != nil { + if err = http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, cbReq, resp, globalConfig.Callback.CallbackBeforeCreateGroup); err != nil { return err } utils.NotNilReplace(&req.GroupInfo.GroupID, resp.GroupID) @@ -76,8 +76,8 @@ func CallbackBeforeCreateGroup(ctx context.Context, req *group.CreateGroupReq) ( return nil } -func CallbackAfterCreateGroup(ctx context.Context, req *group.CreateGroupReq) (err error) { - if !config.Config.Callback.CallbackAfterCreateGroup.Enable { +func CallbackAfterCreateGroup(ctx context.Context, globalConfig *config.GlobalConfig, req *group.CreateGroupReq) (err error) { + if !globalConfig.Callback.CallbackAfterCreateGroup.Enable { return nil } cbReq := &callbackstruct.CallbackAfterCreateGroupReq{ @@ -101,7 +101,7 @@ func CallbackAfterCreateGroup(ctx context.Context, req *group.CreateGroupReq) (e }) } resp := &callbackstruct.CallbackAfterCreateGroupResp{} - if err = http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, cbReq, resp, config.Config.Callback.CallbackAfterCreateGroup); err != nil { + if err = http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, cbReq, resp, globalConfig.Callback.CallbackAfterCreateGroup); err != nil { return err } return nil @@ -109,10 +109,11 @@ func CallbackAfterCreateGroup(ctx context.Context, req *group.CreateGroupReq) (e func CallbackBeforeMemberJoinGroup( ctx context.Context, + globalConfig *config.GlobalConfig, groupMember *relation.GroupMemberModel, groupEx string, ) (err error) { - if !config.Config.Callback.CallbackBeforeMemberJoinGroup.Enable { + if !globalConfig.Callback.CallbackBeforeMemberJoinGroup.Enable { return nil } callbackReq := &callbackstruct.CallbackBeforeMemberJoinGroupReq{ @@ -125,10 +126,10 @@ func CallbackBeforeMemberJoinGroup( resp := &callbackstruct.CallbackBeforeMemberJoinGroupResp{} err = http.CallBackPostReturn( ctx, - config.Config.Callback.CallbackUrl, + globalConfig.Callback.CallbackUrl, callbackReq, resp, - config.Config.Callback.CallbackBeforeMemberJoinGroup, + globalConfig.Callback.CallbackBeforeMemberJoinGroup, ) if err != nil { return err @@ -143,8 +144,8 @@ func CallbackBeforeMemberJoinGroup( return nil } -func CallbackBeforeSetGroupMemberInfo(ctx context.Context, req *group.SetGroupMemberInfo) (err error) { - if !config.Config.Callback.CallbackBeforeSetGroupMemberInfo.Enable { +func CallbackBeforeSetGroupMemberInfo(ctx context.Context, globalConfig *config.GlobalConfig, req *group.SetGroupMemberInfo) (err error) { + if !globalConfig.Callback.CallbackBeforeSetGroupMemberInfo.Enable { return nil } callbackReq := callbackstruct.CallbackBeforeSetGroupMemberInfoReq{ @@ -167,10 +168,10 @@ func CallbackBeforeSetGroupMemberInfo(ctx context.Context, req *group.SetGroupMe resp := &callbackstruct.CallbackBeforeSetGroupMemberInfoResp{} err = http.CallBackPostReturn( ctx, - config.Config.Callback.CallbackUrl, + globalConfig.Callback.CallbackUrl, callbackReq, resp, - config.Config.Callback.CallbackBeforeSetGroupMemberInfo, + globalConfig.Callback.CallbackBeforeSetGroupMemberInfo, ) if err != nil { return err @@ -189,8 +190,8 @@ func CallbackBeforeSetGroupMemberInfo(ctx context.Context, req *group.SetGroupMe } return nil } -func CallbackAfterSetGroupMemberInfo(ctx context.Context, req *group.SetGroupMemberInfo) (err error) { - if !config.Config.Callback.CallbackBeforeSetGroupMemberInfo.Enable { +func CallbackAfterSetGroupMemberInfo(ctx context.Context, globalConfig *config.GlobalConfig, req *group.SetGroupMemberInfo) (err error) { + if !globalConfig.Callback.CallbackBeforeSetGroupMemberInfo.Enable { return nil } callbackReq := callbackstruct.CallbackAfterSetGroupMemberInfoReq{ @@ -211,14 +212,14 @@ func CallbackAfterSetGroupMemberInfo(ctx context.Context, req *group.SetGroupMem callbackReq.Ex = &req.Ex.Value } resp := &callbackstruct.CallbackAfterSetGroupMemberInfoResp{} - if err = http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, callbackReq, resp, config.Config.Callback.CallbackAfterSetGroupMemberInfo); err != nil { + if err = http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, callbackReq, resp, globalConfig.Callback.CallbackAfterSetGroupMemberInfo); err != nil { return err } return nil } -func CallbackQuitGroup(ctx context.Context, req *group.QuitGroupReq) (err error) { - if !config.Config.Callback.CallbackQuitGroup.Enable { +func CallbackQuitGroup(ctx context.Context, globalConfig *config.GlobalConfig, req *group.QuitGroupReq) (err error) { + if !globalConfig.Callback.CallbackQuitGroup.Enable { return nil } cbReq := &callbackstruct.CallbackQuitGroupReq{ @@ -227,14 +228,14 @@ func CallbackQuitGroup(ctx context.Context, req *group.QuitGroupReq) (err error) UserID: req.UserID, } resp := &callbackstruct.CallbackQuitGroupResp{} - if err = http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, cbReq, resp, config.Config.Callback.CallbackQuitGroup); err != nil { + if err = http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, cbReq, resp, globalConfig.Callback.CallbackQuitGroup); err != nil { return err } return nil } -func CallbackKillGroupMember(ctx context.Context, req *pbgroup.KickGroupMemberReq) (err error) { - if !config.Config.Callback.CallbackKillGroupMember.Enable { +func CallbackKillGroupMember(ctx context.Context, globalConfig *config.GlobalConfig, req *pbgroup.KickGroupMemberReq) (err error) { + if !globalConfig.Callback.CallbackKillGroupMember.Enable { return nil } cbReq := &callbackstruct.CallbackKillGroupMemberReq{ @@ -243,41 +244,41 @@ func CallbackKillGroupMember(ctx context.Context, req *pbgroup.KickGroupMemberRe KickedUserIDs: req.KickedUserIDs, } resp := &callbackstruct.CallbackKillGroupMemberResp{} - if err = http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, cbReq, resp, config.Config.Callback.CallbackQuitGroup); err != nil { + if err = http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, cbReq, resp, globalConfig.Callback.CallbackQuitGroup); err != nil { return err } return nil } -func CallbackDismissGroup(ctx context.Context, req *callbackstruct.CallbackDisMissGroupReq) (err error) { - if !config.Config.Callback.CallbackDismissGroup.Enable { +func CallbackDismissGroup(ctx context.Context, globalConfig *config.GlobalConfig, req *callbackstruct.CallbackDisMissGroupReq) (err error) { + if !globalConfig.Callback.CallbackDismissGroup.Enable { return nil } req.CallbackCommand = callbackstruct.CallbackDisMissGroupCommand resp := &callbackstruct.CallbackDisMissGroupResp{} - if err = http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, req, resp, config.Config.Callback.CallbackQuitGroup); err != nil { + if err = http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, req, resp, globalConfig.Callback.CallbackQuitGroup); err != nil { return err } return nil } -func CallbackApplyJoinGroupBefore(ctx context.Context, req *callbackstruct.CallbackJoinGroupReq) (err error) { - if !config.Config.Callback.CallbackBeforeJoinGroup.Enable { +func CallbackApplyJoinGroupBefore(ctx context.Context, globalConfig *config.GlobalConfig, req *callbackstruct.CallbackJoinGroupReq) (err error) { + if !globalConfig.Callback.CallbackBeforeJoinGroup.Enable { return nil } req.CallbackCommand = callbackstruct.CallbackBeforeJoinGroupCommand resp := &callbackstruct.CallbackJoinGroupResp{} - if err = http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, req, resp, config.Config.Callback.CallbackBeforeJoinGroup); err != nil { + if err = http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, req, resp, globalConfig.Callback.CallbackBeforeJoinGroup); err != nil { return err } return nil } -func CallbackAfterTransferGroupOwner(ctx context.Context, req *pbgroup.TransferGroupOwnerReq) (err error) { - if !config.Config.Callback.CallbackAfterTransferGroupOwner.Enable { +func CallbackAfterTransferGroupOwner(ctx context.Context, globalConfig *config.GlobalConfig, req *pbgroup.TransferGroupOwnerReq) (err error) { + if !globalConfig.Callback.CallbackAfterTransferGroupOwner.Enable { return nil } @@ -289,13 +290,13 @@ func CallbackAfterTransferGroupOwner(ctx context.Context, req *pbgroup.TransferG } resp := &callbackstruct.CallbackTransferGroupOwnerResp{} - if err = http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, cbReq, resp, config.Config.Callback.CallbackAfterTransferGroupOwner); err != nil { + if err = http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, cbReq, resp, globalConfig.Callback.CallbackAfterTransferGroupOwner); err != nil { return err } return nil } -func CallbackBeforeInviteUserToGroup(ctx context.Context, req *group.InviteUserToGroupReq) (err error) { - if !config.Config.Callback.CallbackBeforeInviteUserToGroup.Enable { +func CallbackBeforeInviteUserToGroup(ctx context.Context, globalConfig *config.GlobalConfig, req *group.InviteUserToGroupReq) (err error) { + if !globalConfig.Callback.CallbackBeforeInviteUserToGroup.Enable { return nil } @@ -310,10 +311,10 @@ func CallbackBeforeInviteUserToGroup(ctx context.Context, req *group.InviteUserT resp := &callbackstruct.CallbackBeforeInviteUserToGroupResp{} err = http.CallBackPostReturn( ctx, - config.Config.Callback.CallbackUrl, + globalConfig.Callback.CallbackUrl, callbackReq, resp, - config.Config.Callback.CallbackBeforeInviteUserToGroup, + globalConfig.Callback.CallbackBeforeInviteUserToGroup, ) if err != nil { @@ -327,8 +328,8 @@ func CallbackBeforeInviteUserToGroup(ctx context.Context, req *group.InviteUserT return nil } -func CallbackAfterJoinGroup(ctx context.Context, req *group.JoinGroupReq) error { - if !config.Config.Callback.CallbackAfterJoinGroup.Enable { +func CallbackAfterJoinGroup(ctx context.Context, globalConfig *config.GlobalConfig, req *group.JoinGroupReq) error { + if !globalConfig.Callback.CallbackAfterJoinGroup.Enable { return nil } callbackReq := &callbackstruct.CallbackAfterJoinGroupReq{ @@ -340,14 +341,14 @@ func CallbackAfterJoinGroup(ctx context.Context, req *group.JoinGroupReq) error InviterUserID: req.InviterUserID, } resp := &callbackstruct.CallbackAfterJoinGroupResp{} - if err := http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, callbackReq, resp, config.Config.Callback.CallbackAfterJoinGroup); err != nil { + if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, callbackReq, resp, globalConfig.Callback.CallbackAfterJoinGroup); err != nil { return err } return nil } -func CallbackBeforeSetGroupInfo(ctx context.Context, req *group.SetGroupInfoReq) error { - if !config.Config.Callback.CallbackBeforeSetGroupInfo.Enable { +func CallbackBeforeSetGroupInfo(ctx context.Context, globalConfig *config.GlobalConfig, req *group.SetGroupInfoReq) error { + if !globalConfig.Callback.CallbackBeforeSetGroupInfo.Enable { return nil } callbackReq := &callbackstruct.CallbackBeforeSetGroupInfoReq{ @@ -374,7 +375,7 @@ func CallbackBeforeSetGroupInfo(ctx context.Context, req *group.SetGroupInfoReq) } resp := &callbackstruct.CallbackBeforeSetGroupInfoResp{} - if err := http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, callbackReq, resp, config.Config.Callback.CallbackBeforeSetGroupInfo); err != nil { + if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, callbackReq, resp, globalConfig.Callback.CallbackBeforeSetGroupInfo); err != nil { return err } @@ -396,8 +397,8 @@ func CallbackBeforeSetGroupInfo(ctx context.Context, req *group.SetGroupInfoReq) utils.NotNilReplace(&req.GroupInfoForSet.Introduction, &resp.Introduction) return nil } -func CallbackAfterSetGroupInfo(ctx context.Context, req *group.SetGroupInfoReq) error { - if !config.Config.Callback.CallbackAfterSetGroupInfo.Enable { +func CallbackAfterSetGroupInfo(ctx context.Context, globalConfig *config.GlobalConfig, req *group.SetGroupInfoReq) error { + if !globalConfig.Callback.CallbackAfterSetGroupInfo.Enable { return nil } callbackReq := &callbackstruct.CallbackAfterSetGroupInfoReq{ @@ -421,7 +422,7 @@ func CallbackAfterSetGroupInfo(ctx context.Context, req *group.SetGroupInfoReq) callbackReq.ApplyMemberFriend = &req.GroupInfoForSet.ApplyMemberFriend.Value } resp := &callbackstruct.CallbackAfterSetGroupInfoResp{} - if err := http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, callbackReq, resp, config.Config.Callback.CallbackAfterSetGroupInfo); err != nil { + if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, callbackReq, resp, globalConfig.Callback.CallbackAfterSetGroupInfo); err != nil { return err } return nil diff --git a/internal/rpc/group/group.go b/internal/rpc/group/group.go index fa060efdac..325c1edce1 100644 --- a/internal/rpc/group/group.go +++ b/internal/rpc/group/group.go @@ -17,6 +17,7 @@ package group import ( "context" "fmt" + "github.com/openimsdk/open-im-server/v3/pkg/common/config" "math/big" "math/rand" "strconv" @@ -50,35 +51,35 @@ import ( "google.golang.org/grpc" ) -func Start(client discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) error { - mongo, err := unrelation.NewMongo() +func Start(config *config.GlobalConfig, client discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) error { + mongo, err := unrelation.NewMongo(config) if err != nil { return err } - rdb, err := cache.NewRedis() + rdb, err := cache.NewRedis(config) if err != nil { return err } - groupDB, err := mgo.NewGroupMongo(mongo.GetDatabase()) + groupDB, err := mgo.NewGroupMongo(mongo.GetDatabase(config.Mongo.Database)) if err != nil { return err } - groupMemberDB, err := mgo.NewGroupMember(mongo.GetDatabase()) + groupMemberDB, err := mgo.NewGroupMember(mongo.GetDatabase(config.Mongo.Database)) if err != nil { return err } - groupRequestDB, err := mgo.NewGroupRequestMgo(mongo.GetDatabase()) + groupRequestDB, err := mgo.NewGroupRequestMgo(mongo.GetDatabase(config.Mongo.Database)) if err != nil { return err } - userRpcClient := rpcclient.NewUserRpcClient(client) - msgRpcClient := rpcclient.NewMessageRpcClient(client) - conversationRpcClient := rpcclient.NewConversationRpcClient(client) + userRpcClient := rpcclient.NewUserRpcClient(client, config) + msgRpcClient := rpcclient.NewMessageRpcClient(client, config) + conversationRpcClient := rpcclient.NewConversationRpcClient(client, config) var gs groupServer database := controller.NewGroupDatabase(rdb, groupDB, groupMemberDB, groupRequestDB, tx.NewMongo(mongo.GetClient()), grouphash.NewGroupHashFromGroupServer(&gs)) gs.db = database gs.User = userRpcClient - gs.Notification = notification.NewGroupNotificationSender(database, &msgRpcClient, &userRpcClient, func(ctx context.Context, userIDs []string) ([]notification.CommonUser, error) { + gs.Notification = notification.NewGroupNotificationSender(database, &msgRpcClient, &userRpcClient, config, func(ctx context.Context, userIDs []string) ([]notification.CommonUser, error) { users, err := userRpcClient.GetUsersInfo(ctx, userIDs) if err != nil { return nil, err @@ -87,6 +88,7 @@ func Start(client discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) e }) gs.conversationRpcClient = conversationRpcClient gs.msgRpcClient = msgRpcClient + gs.config = config pbgroup.RegisterGroupServer(server, &gs) return nil } @@ -97,6 +99,7 @@ type groupServer struct { Notification *notification.GroupNotificationSender conversationRpcClient rpcclient.ConversationRpcClient msgRpcClient rpcclient.MessageRpcClient + config *config.GlobalConfig } func (s *groupServer) GetJoinedGroupIDs(ctx context.Context, req *pbgroup.GetJoinedGroupIDsReq) (*pbgroup.GetJoinedGroupIDsResp, error) { @@ -105,7 +108,6 @@ func (s *groupServer) GetJoinedGroupIDs(ctx context.Context, req *pbgroup.GetJoi } func (s *groupServer) NotificationUserInfoUpdate(ctx context.Context, req *pbgroup.NotificationUserInfoUpdateReq) (*pbgroup.NotificationUserInfoUpdateResp, error) { - defer log.ZDebug(ctx, "NotificationUserInfoUpdate return") members, err := s.db.FindGroupMemberUser(ctx, nil, req.UserID) if err != nil { return nil, err @@ -117,7 +119,6 @@ func (s *groupServer) NotificationUserInfoUpdate(ctx context.Context, req *pbgro } groupIDs = append(groupIDs, member.GroupID) } - log.ZInfo(ctx, "NotificationUserInfoUpdate", "joinGroupNum", len(members), "updateNum", len(groupIDs), "updateGroupIDs", groupIDs) for _, groupID := range groupIDs { if err := s.Notification.GroupMemberInfoSetNotification(ctx, groupID, req.UserID); err != nil { log.ZError(ctx, "NotificationUserInfoUpdate setGroupMemberInfo notification failed", err, "groupID", groupID) @@ -131,7 +132,7 @@ func (s *groupServer) NotificationUserInfoUpdate(ctx context.Context, req *pbgro } func (s *groupServer) CheckGroupAdmin(ctx context.Context, groupID string) error { - if !authverify.IsAppManagerUid(ctx) { + if !authverify.IsAppManagerUid(ctx, s.config) { groupMember, err := s.db.TakeGroupMember(ctx, groupID, mcontext.GetOpUserID(ctx)) if err != nil { return err @@ -196,7 +197,7 @@ func (s *groupServer) CreateGroup(ctx context.Context, req *pbgroup.CreateGroupR if req.OwnerUserID == "" { return nil, errs.ErrArgs.Wrap("no group owner") } - if err := authverify.CheckAccessV3(ctx, req.OwnerUserID); err != nil { + if err := authverify.CheckAccessV3(ctx, req.OwnerUserID, s.config); err != nil { return nil, err } userIDs := append(append(req.MemberUserIDs, req.AdminUserIDs...), req.OwnerUserID) @@ -215,7 +216,7 @@ func (s *groupServer) CreateGroup(ctx context.Context, req *pbgroup.CreateGroupR return nil, errs.ErrUserIDNotFound.Wrap("user not found") } // Callback Before create Group - if err := CallbackBeforeCreateGroup(ctx, req); err != nil { + if err := CallbackBeforeCreateGroup(ctx, s.config, req); err != nil { return nil, err } var groupMembers []*relationtb.GroupMemberModel @@ -234,7 +235,7 @@ func (s *groupServer) CreateGroup(ctx context.Context, req *pbgroup.CreateGroupR JoinTime: time.Now(), MuteEndTime: time.UnixMilli(0), } - if err := CallbackBeforeMemberJoinGroup(ctx, groupMember, group.Ex); err != nil { + if err := CallbackBeforeMemberJoinGroup(ctx, s.config, groupMember, group.Ex); err != nil { return err } groupMembers = append(groupMembers, groupMember) @@ -302,7 +303,7 @@ func (s *groupServer) CreateGroup(ctx context.Context, req *pbgroup.CreateGroupR AdminUserIDs: req.AdminUserIDs, } - if err := CallbackAfterCreateGroup(ctx, reqCallBackAfter); err != nil { + if err := CallbackAfterCreateGroup(ctx, s.config, reqCallBackAfter); err != nil { return nil, err } @@ -311,7 +312,7 @@ func (s *groupServer) CreateGroup(ctx context.Context, req *pbgroup.CreateGroupR func (s *groupServer) GetJoinedGroupList(ctx context.Context, req *pbgroup.GetJoinedGroupListReq) (*pbgroup.GetJoinedGroupListResp, error) { resp := &pbgroup.GetJoinedGroupListResp{} - if err := authverify.CheckAccessV3(ctx, req.FromUserID); err != nil { + if err := authverify.CheckAccessV3(ctx, req.FromUserID, s.config); err != nil { return nil, err } total, members, err := s.db.PageGetJoinGroup(ctx, req.FromUserID, req.Pagination) @@ -381,7 +382,7 @@ func (s *groupServer) InviteUserToGroup(ctx context.Context, req *pbgroup.Invite } var groupMember *relationtb.GroupMemberModel var opUserID string - if !authverify.IsAppManagerUid(ctx) { + if !authverify.IsAppManagerUid(ctx, s.config) { opUserID = mcontext.GetOpUserID(ctx) var err error groupMember, err = s.db.TakeGroupMember(ctx, req.GroupID, opUserID) @@ -393,11 +394,11 @@ func (s *groupServer) InviteUserToGroup(ctx context.Context, req *pbgroup.Invite } } - if err := CallbackBeforeInviteUserToGroup(ctx, req); err != nil { + if err := CallbackBeforeInviteUserToGroup(ctx, s.config, req); err != nil { return nil, err } if group.NeedVerification == constant.AllNeedVerification { - if !authverify.IsAppManagerUid(ctx) { + if !authverify.IsAppManagerUid(ctx, s.config) { if !(groupMember.RoleLevel == constant.GroupOwner || groupMember.RoleLevel == constant.GroupAdmin) { var requests []*relationtb.GroupRequestModel for _, userID := range req.InvitedUserIDs { @@ -437,7 +438,7 @@ func (s *groupServer) InviteUserToGroup(ctx context.Context, req *pbgroup.Invite JoinTime: time.Now(), MuteEndTime: time.UnixMilli(0), } - if err := CallbackBeforeMemberJoinGroup(ctx, member, group.Ex); err != nil { + if err := CallbackBeforeMemberJoinGroup(ctx, s.config, member, group.Ex); err != nil { return nil, err } groupMembers = append(groupMembers, member) @@ -537,7 +538,7 @@ func (s *groupServer) KickGroupMember(ctx context.Context, req *pbgroup.KickGrou for i, member := range members { memberMap[member.UserID] = members[i] } - isAppManagerUid := authverify.IsAppManagerUid(ctx) + isAppManagerUid := authverify.IsAppManagerUid(ctx, s.config) opMember := memberMap[opUserID] for _, userID := range req.KickedUserIDs { member, ok := memberMap[userID] @@ -609,7 +610,7 @@ func (s *groupServer) KickGroupMember(ctx context.Context, req *pbgroup.KickGrou return nil, err } - if err := CallbackKillGroupMember(ctx, req); err != nil { + if err := CallbackKillGroupMember(ctx, s.config, req); err != nil { return nil, err } return resp, nil @@ -735,7 +736,7 @@ func (s *groupServer) GroupApplicationResponse(ctx context.Context, req *pbgroup if !utils.Contain(req.HandleResult, constant.GroupResponseAgree, constant.GroupResponseRefuse) { return nil, errs.ErrArgs.Wrap("HandleResult unknown") } - if !authverify.IsAppManagerUid(ctx) { + if !authverify.IsAppManagerUid(ctx, s.config) { groupMember, err := s.db.TakeGroupMember(ctx, req.GroupID, mcontext.GetOpUserID(ctx)) if err != nil { return nil, err @@ -779,7 +780,7 @@ func (s *groupServer) GroupApplicationResponse(ctx context.Context, req *pbgroup OperatorUserID: mcontext.GetOpUserID(ctx), Ex: groupRequest.Ex, } - if err = CallbackBeforeMemberJoinGroup(ctx, member, group.Ex); err != nil { + if err = CallbackBeforeMemberJoinGroup(ctx, s.config, member, group.Ex); err != nil { return nil, err } } @@ -827,7 +828,7 @@ func (s *groupServer) JoinGroup(ctx context.Context, req *pbgroup.JoinGroupReq) Ex: req.Ex, } - if err = CallbackApplyJoinGroupBefore(ctx, reqCall); err != nil { + if err = CallbackApplyJoinGroupBefore(ctx, s.config, reqCall); err != nil { return nil, err } _, err = s.db.TakeGroupMember(ctx, req.GroupID, req.InviterUserID) @@ -848,7 +849,7 @@ func (s *groupServer) JoinGroup(ctx context.Context, req *pbgroup.JoinGroupReq) JoinTime: time.Now(), MuteEndTime: time.UnixMilli(0), } - if err := CallbackBeforeMemberJoinGroup(ctx, groupMember, group.Ex); err != nil { + if err := CallbackBeforeMemberJoinGroup(ctx, s.config, groupMember, group.Ex); err != nil { return nil, err } if err := s.db.CreateGroup(ctx, nil, []*relationtb.GroupMemberModel{groupMember}); err != nil { @@ -859,7 +860,7 @@ func (s *groupServer) JoinGroup(ctx context.Context, req *pbgroup.JoinGroupReq) return nil, err } s.Notification.MemberEnterNotification(ctx, req.GroupID, req.InviterUserID) - if err = CallbackAfterJoinGroup(ctx, req); err != nil { + if err = CallbackAfterJoinGroup(ctx, s.config, req); err != nil { return nil, err } return resp, nil @@ -873,7 +874,7 @@ func (s *groupServer) JoinGroup(ctx context.Context, req *pbgroup.JoinGroupReq) HandledTime: time.Unix(0, 0), Ex: req.Ex, } - if err := s.db.CreateGroupRequest(ctx, []*relationtb.GroupRequestModel{&groupRequest}); err != nil { + if err = s.db.CreateGroupRequest(ctx, []*relationtb.GroupRequestModel{&groupRequest}); err != nil { return nil, err } s.Notification.JoinGroupApplicationNotification(ctx, req) @@ -885,7 +886,7 @@ func (s *groupServer) QuitGroup(ctx context.Context, req *pbgroup.QuitGroupReq) if req.UserID == "" { req.UserID = mcontext.GetOpUserID(ctx) } else { - if err := authverify.CheckAccessV3(ctx, req.UserID); err != nil { + if err := authverify.CheckAccessV3(ctx, req.UserID, s.config); err != nil { return nil, err } } @@ -909,7 +910,7 @@ func (s *groupServer) QuitGroup(ctx context.Context, req *pbgroup.QuitGroupReq) } // callback - if err := CallbackQuitGroup(ctx, req); err != nil { + if err := CallbackQuitGroup(ctx, s.config, req); err != nil { return nil, err } return resp, nil @@ -926,7 +927,7 @@ func (s *groupServer) deleteMemberAndSetConversationSeq(ctx context.Context, gro func (s *groupServer) SetGroupInfo(ctx context.Context, req *pbgroup.SetGroupInfoReq) (*pbgroup.SetGroupInfoResp, error) { var opMember *relationtb.GroupMemberModel - if !authverify.IsAppManagerUid(ctx) { + if !authverify.IsAppManagerUid(ctx, s.config) { var err error opMember, err = s.db.TakeGroupMember(ctx, req.GroupInfoForSet.GroupID, mcontext.GetOpUserID(ctx)) if err != nil { @@ -939,7 +940,7 @@ func (s *groupServer) SetGroupInfo(ctx context.Context, req *pbgroup.SetGroupInf return nil, err } } - if err := CallbackBeforeSetGroupInfo(ctx, req); err != nil { + if err := CallbackBeforeSetGroupInfo(ctx, s.config, req); err != nil { return nil, err } group, err := s.db.TakeGroup(ctx, req.GroupInfoForSet.GroupID) @@ -1008,7 +1009,7 @@ func (s *groupServer) SetGroupInfo(ctx context.Context, req *pbgroup.SetGroupInf if num > 0 { _ = s.Notification.GroupInfoSetNotification(ctx, tips) } - if err := CallbackAfterSetGroupInfo(ctx, req); err != nil { + if err := CallbackAfterSetGroupInfo(ctx, s.config, req); err != nil { return nil, err } return resp, nil @@ -1045,7 +1046,7 @@ func (s *groupServer) TransferGroupOwner(ctx context.Context, req *pbgroup.Trans if newOwner == nil { return nil, errs.ErrArgs.Wrap("NewOwnerUser not in group " + req.NewOwnerUserID) } - if !authverify.IsAppManagerUid(ctx) { + if !authverify.IsAppManagerUid(ctx, s.config) { if !(mcontext.GetOpUserID(ctx) == oldOwner.UserID && oldOwner.RoleLevel == constant.GroupOwner) { return nil, errs.ErrNoPermission.Wrap("no permission transfer group owner") } @@ -1054,7 +1055,7 @@ func (s *groupServer) TransferGroupOwner(ctx context.Context, req *pbgroup.Trans return nil, err } - if err := CallbackAfterTransferGroupOwner(ctx, req); err != nil { + if err := CallbackAfterTransferGroupOwner(ctx, s.config, req); err != nil { return nil, err } s.Notification.GroupOwnerTransferredNotification(ctx, req) @@ -1186,7 +1187,7 @@ func (s *groupServer) DismissGroup(ctx context.Context, req *pbgroup.DismissGrou if err != nil { return nil, err } - if !authverify.IsAppManagerUid(ctx) { + if !authverify.IsAppManagerUid(ctx, s.config) { if owner.UserID != mcontext.GetOpUserID(ctx) { return nil, errs.ErrNoPermission.Wrap("not group owner") } @@ -1228,7 +1229,7 @@ func (s *groupServer) DismissGroup(ctx context.Context, req *pbgroup.DismissGrou MembersID: membersID, GroupType: string(group.GroupType), } - if err := CallbackDismissGroup(ctx, reqCall); err != nil { + if err := CallbackDismissGroup(ctx, s.config, reqCall); err != nil { return nil, err } @@ -1244,7 +1245,7 @@ func (s *groupServer) MuteGroupMember(ctx context.Context, req *pbgroup.MuteGrou if err := s.PopulateGroupMember(ctx, member); err != nil { return nil, err } - if !authverify.IsAppManagerUid(ctx) { + if !authverify.IsAppManagerUid(ctx, s.config) { opMember, err := s.db.TakeGroupMember(ctx, req.GroupID, mcontext.GetOpUserID(ctx)) if err != nil { return nil, err @@ -1278,7 +1279,7 @@ func (s *groupServer) CancelMuteGroupMember(ctx context.Context, req *pbgroup.Ca if err := s.PopulateGroupMember(ctx, member); err != nil { return nil, err } - if !authverify.IsAppManagerUid(ctx) { + if !authverify.IsAppManagerUid(ctx, s.config) { opMember, err := s.db.TakeGroupMember(ctx, req.GroupID, mcontext.GetOpUserID(ctx)) if err != nil { return nil, err @@ -1337,7 +1338,7 @@ func (s *groupServer) SetGroupMemberInfo(ctx context.Context, req *pbgroup.SetGr if opUserID == "" { return nil, errs.ErrNoPermission.Wrap("no op user id") } - isAppManagerUid := authverify.IsAppManagerUid(ctx) + isAppManagerUid := authverify.IsAppManagerUid(ctx, s.config) for i := range req.Members { req.Members[i].FaceURL = nil } @@ -1420,7 +1421,7 @@ func (s *groupServer) SetGroupMemberInfo(ctx context.Context, req *pbgroup.SetGr } } for i := 0; i < len(req.Members); i++ { - if err := CallbackBeforeSetGroupMemberInfo(ctx, req.Members[i]); err != nil { + if err := CallbackBeforeSetGroupMemberInfo(ctx, s.config, req.Members[i]); err != nil { return nil, err } } @@ -1447,7 +1448,7 @@ func (s *groupServer) SetGroupMemberInfo(ctx context.Context, req *pbgroup.SetGr } } for i := 0; i < len(req.Members); i++ { - if err := CallbackAfterSetGroupMemberInfo(ctx, req.Members[i]); err != nil { + if err := CallbackAfterSetGroupMemberInfo(ctx, s.config, req.Members[i]); err != nil { return nil, err } } diff --git a/internal/rpc/msg/as_read.go b/internal/rpc/msg/as_read.go index cac9102fa4..f16fdc62f7 100644 --- a/internal/rpc/msg/as_read.go +++ b/internal/rpc/msg/as_read.go @@ -129,7 +129,7 @@ func (m *msgServer) MarkMsgsAsRead( Seqs: req.Seqs, ContentType: conversation.ConversationType, } - if err = CallbackSingleMsgRead(ctx, req_callback); err != nil { + if err = CallbackSingleMsgRead(ctx, m.config, req_callback); err != nil { return nil, err } @@ -206,7 +206,7 @@ func (m *msgServer) MarkConversationAsRead( UnreadMsgNum: req.HasReadSeq, ContentType: int64(conversation.ConversationType), } - if err := CallbackGroupMsgRead(ctx, reqCall); err != nil { + if err := CallbackGroupMsgRead(ctx, m.config, reqCall); err != nil { return nil, err } diff --git a/internal/rpc/msg/callback.go b/internal/rpc/msg/callback.go index 1a7cad70c1..536402bf99 100644 --- a/internal/rpc/msg/callback.go +++ b/internal/rpc/msg/callback.go @@ -29,10 +29,6 @@ import ( "google.golang.org/protobuf/proto" ) -func cbURL() string { - return config.Config.Callback.CallbackUrl -} - func toCommonCallback(ctx context.Context, msg *pbchat.SendMsgReq, command string) cbapi.CommonCallbackReq { return cbapi.CommonCallbackReq{ SendID: msg.MsgData.SendID, @@ -66,8 +62,8 @@ func GetContent(msg *sdkws.MsgData) string { } } -func callbackBeforeSendSingleMsg(ctx context.Context, msg *pbchat.SendMsgReq) error { - if !config.Config.Callback.CallbackBeforeSendSingleMsg.Enable || msg.MsgData.ContentType == constant.Typing { +func callbackBeforeSendSingleMsg(ctx context.Context, globalConfig *config.GlobalConfig, msg *pbchat.SendMsgReq) error { + if !globalConfig.Callback.CallbackBeforeSendSingleMsg.Enable || msg.MsgData.ContentType == constant.Typing { return nil } req := &cbapi.CallbackBeforeSendSingleMsgReq{ @@ -75,14 +71,14 @@ func callbackBeforeSendSingleMsg(ctx context.Context, msg *pbchat.SendMsgReq) er RecvID: msg.MsgData.RecvID, } resp := &cbapi.CallbackBeforeSendSingleMsgResp{} - if err := http.CallBackPostReturn(ctx, cbURL(), req, resp, config.Config.Callback.CallbackBeforeSendSingleMsg); err != nil { + if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, req, resp, globalConfig.Callback.CallbackBeforeSendSingleMsg); err != nil { return err } return nil } -func callbackAfterSendSingleMsg(ctx context.Context, msg *pbchat.SendMsgReq) error { - if !config.Config.Callback.CallbackAfterSendSingleMsg.Enable || msg.MsgData.ContentType == constant.Typing { +func callbackAfterSendSingleMsg(ctx context.Context, globalConfig *config.GlobalConfig, msg *pbchat.SendMsgReq) error { + if !globalConfig.Callback.CallbackAfterSendSingleMsg.Enable || msg.MsgData.ContentType == constant.Typing { return nil } req := &cbapi.CallbackAfterSendSingleMsgReq{ @@ -90,14 +86,14 @@ func callbackAfterSendSingleMsg(ctx context.Context, msg *pbchat.SendMsgReq) err RecvID: msg.MsgData.RecvID, } resp := &cbapi.CallbackAfterSendSingleMsgResp{} - if err := http.CallBackPostReturn(ctx, cbURL(), req, resp, config.Config.Callback.CallbackAfterSendSingleMsg); err != nil { + if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, req, resp, globalConfig.Callback.CallbackAfterSendSingleMsg); err != nil { return err } return nil } -func callbackBeforeSendGroupMsg(ctx context.Context, msg *pbchat.SendMsgReq) error { - if !config.Config.Callback.CallbackBeforeSendGroupMsg.Enable || msg.MsgData.ContentType == constant.Typing { +func callbackBeforeSendGroupMsg(ctx context.Context, globalConfig *config.GlobalConfig, msg *pbchat.SendMsgReq) error { + if !globalConfig.Callback.CallbackBeforeSendGroupMsg.Enable || msg.MsgData.ContentType == constant.Typing { return nil } req := &cbapi.CallbackBeforeSendGroupMsgReq{ @@ -105,14 +101,14 @@ func callbackBeforeSendGroupMsg(ctx context.Context, msg *pbchat.SendMsgReq) err GroupID: msg.MsgData.GroupID, } resp := &cbapi.CallbackBeforeSendGroupMsgResp{} - if err := http.CallBackPostReturn(ctx, cbURL(), req, resp, config.Config.Callback.CallbackBeforeSendGroupMsg); err != nil { + if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, req, resp, globalConfig.Callback.CallbackBeforeSendGroupMsg); err != nil { return err } return nil } -func callbackAfterSendGroupMsg(ctx context.Context, msg *pbchat.SendMsgReq) error { - if !config.Config.Callback.CallbackAfterSendGroupMsg.Enable || msg.MsgData.ContentType == constant.Typing { +func callbackAfterSendGroupMsg(ctx context.Context, globalConfig *config.GlobalConfig, msg *pbchat.SendMsgReq) error { + if !globalConfig.Callback.CallbackAfterSendGroupMsg.Enable || msg.MsgData.ContentType == constant.Typing { return nil } req := &cbapi.CallbackAfterSendGroupMsgReq{ @@ -120,21 +116,21 @@ func callbackAfterSendGroupMsg(ctx context.Context, msg *pbchat.SendMsgReq) erro GroupID: msg.MsgData.GroupID, } resp := &cbapi.CallbackAfterSendGroupMsgResp{} - if err := http.CallBackPostReturn(ctx, cbURL(), req, resp, config.Config.Callback.CallbackAfterSendGroupMsg); err != nil { + if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, req, resp, globalConfig.Callback.CallbackAfterSendGroupMsg); err != nil { return err } return nil } -func callbackMsgModify(ctx context.Context, msg *pbchat.SendMsgReq) error { - if !config.Config.Callback.CallbackMsgModify.Enable || msg.MsgData.ContentType != constant.Text { +func callbackMsgModify(ctx context.Context, globalConfig *config.GlobalConfig, msg *pbchat.SendMsgReq) error { + if !globalConfig.Callback.CallbackMsgModify.Enable || msg.MsgData.ContentType != constant.Text { return nil } req := &cbapi.CallbackMsgModifyCommandReq{ CommonCallbackReq: toCommonCallback(ctx, msg, cbapi.CallbackMsgModifyCommand), } resp := &cbapi.CallbackMsgModifyCommandResp{} - if err := http.CallBackPostReturn(ctx, cbURL(), req, resp, config.Config.Callback.CallbackMsgModify); err != nil { + if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, req, resp, globalConfig.Callback.CallbackMsgModify); err != nil { return err } if resp.Content != nil { @@ -159,34 +155,34 @@ func callbackMsgModify(ctx context.Context, msg *pbchat.SendMsgReq) error { log.ZDebug(ctx, "callbackMsgModify", "msg", msg.MsgData) return nil } -func CallbackGroupMsgRead(ctx context.Context, req *cbapi.CallbackGroupMsgReadReq) error { - if !config.Config.Callback.CallbackGroupMsgRead.Enable || req.ContentType != constant.Text { +func CallbackGroupMsgRead(ctx context.Context, globalConfig *config.GlobalConfig, req *cbapi.CallbackGroupMsgReadReq) error { + if !globalConfig.Callback.CallbackGroupMsgRead.Enable || req.ContentType != constant.Text { return nil } req.CallbackCommand = cbapi.CallbackGroupMsgReadCommand resp := &cbapi.CallbackGroupMsgReadResp{} - if err := http.CallBackPostReturn(ctx, cbURL(), req, resp, config.Config.Callback.CallbackMsgModify); err != nil { + if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, req, resp, globalConfig.Callback.CallbackMsgModify); err != nil { return err } return nil } -func CallbackSingleMsgRead(ctx context.Context, req *cbapi.CallbackSingleMsgReadReq) error { - if !config.Config.Callback.CallbackSingleMsgRead.Enable || req.ContentType != constant.Text { +func CallbackSingleMsgRead(ctx context.Context, globalConfig *config.GlobalConfig, req *cbapi.CallbackSingleMsgReadReq) error { + if !globalConfig.Callback.CallbackSingleMsgRead.Enable || req.ContentType != constant.Text { return nil } req.CallbackCommand = cbapi.CallbackSingleMsgRead resp := &cbapi.CallbackSingleMsgReadResp{} - if err := http.CallBackPostReturn(ctx, cbURL(), req, resp, config.Config.Callback.CallbackMsgModify); err != nil { + if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, req, resp, globalConfig.Callback.CallbackMsgModify); err != nil { return err } return nil } -func CallbackAfterRevokeMsg(ctx context.Context, req *pbchat.RevokeMsgReq) error { - if !config.Config.Callback.CallbackAfterRevokeMsg.Enable { +func CallbackAfterRevokeMsg(ctx context.Context, globalConfig *config.GlobalConfig, req *pbchat.RevokeMsgReq) error { + if !globalConfig.Callback.CallbackAfterRevokeMsg.Enable { return nil } callbackReq := &cbapi.CallbackAfterRevokeMsgReq{ @@ -196,7 +192,7 @@ func CallbackAfterRevokeMsg(ctx context.Context, req *pbchat.RevokeMsgReq) error UserID: req.UserID, } resp := &cbapi.CallbackAfterRevokeMsgResp{} - if err := http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, callbackReq, resp, config.Config.Callback.CallbackAfterRevokeMsg); err != nil { + if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, callbackReq, resp, globalConfig.Callback.CallbackAfterRevokeMsg); err != nil { return err } return nil diff --git a/internal/rpc/msg/delete.go b/internal/rpc/msg/delete.go index 091f11f4cf..14e24d23e1 100644 --- a/internal/rpc/msg/delete.go +++ b/internal/rpc/msg/delete.go @@ -45,7 +45,7 @@ func (m *msgServer) ClearConversationsMsg( ctx context.Context, req *msg.ClearConversationsMsgReq, ) (*msg.ClearConversationsMsgResp, error) { - if err := authverify.CheckAccessV3(ctx, req.UserID); err != nil { + if err := authverify.CheckAccessV3(ctx, req.UserID, m.config); err != nil { return nil, err } if err := m.clearConversation(ctx, req.ConversationIDs, req.UserID, req.DeleteSyncOpt); err != nil { @@ -58,7 +58,7 @@ func (m *msgServer) UserClearAllMsg( ctx context.Context, req *msg.UserClearAllMsgReq, ) (*msg.UserClearAllMsgResp, error) { - if err := authverify.CheckAccessV3(ctx, req.UserID); err != nil { + if err := authverify.CheckAccessV3(ctx, req.UserID, m.config); err != nil { return nil, err } conversationIDs, err := m.ConversationLocalCache.GetConversationIDs(ctx, req.UserID) @@ -73,7 +73,7 @@ func (m *msgServer) UserClearAllMsg( } func (m *msgServer) DeleteMsgs(ctx context.Context, req *msg.DeleteMsgsReq) (*msg.DeleteMsgsResp, error) { - if err := authverify.CheckAccessV3(ctx, req.UserID); err != nil { + if err := authverify.CheckAccessV3(ctx, req.UserID, m.config); err != nil { return nil, err } isSyncSelf, isSyncOther := m.validateDeleteSyncOpt(req.DeleteSyncOpt) @@ -121,7 +121,7 @@ func (m *msgServer) DeleteMsgPhysical( ctx context.Context, req *msg.DeleteMsgPhysicalReq, ) (*msg.DeleteMsgPhysicalResp, error) { - if err := authverify.CheckAdmin(ctx); err != nil { + if err := authverify.CheckAdmin(ctx, m.config); err != nil { return nil, err } remainTime := utils.GetCurrentTimestampBySecond() - req.Timestamp diff --git a/internal/rpc/msg/message_interceptor.go b/internal/rpc/msg/message_interceptor.go index 3a2731fea4..97eac613d9 100644 --- a/internal/rpc/msg/message_interceptor.go +++ b/internal/rpc/msg/message_interceptor.go @@ -24,17 +24,17 @@ import ( "github.com/openimsdk/open-im-server/v3/pkg/common/config" ) -type MessageInterceptorFunc func(ctx context.Context, req *msg.SendMsgReq) (*sdkws.MsgData, error) +type MessageInterceptorFunc func(ctx context.Context, globalConfig *config.GlobalConfig, req *msg.SendMsgReq) (*sdkws.MsgData, error) -func MessageHasReadEnabled(_ context.Context, req *msg.SendMsgReq) (*sdkws.MsgData, error) { +func MessageHasReadEnabled(_ context.Context, globalConfig *config.GlobalConfig, req *msg.SendMsgReq) (*sdkws.MsgData, error) { switch { case req.MsgData.ContentType == constant.HasReadReceipt && req.MsgData.SessionType == constant.SingleChatType: - if !config.Config.SingleMessageHasReadReceiptEnable { + if !globalConfig.SingleMessageHasReadReceiptEnable { return nil, errs.ErrMessageHasReadDisable.Wrap() } return req.MsgData, nil case req.MsgData.ContentType == constant.HasReadReceipt && req.MsgData.SessionType == constant.SuperGroupChatType: - if !config.Config.GroupMessageHasReadReceiptEnable { + if !globalConfig.GroupMessageHasReadReceiptEnable { return nil, errs.ErrMessageHasReadDisable.Wrap() } return req.MsgData, nil diff --git a/internal/rpc/msg/revoke.go b/internal/rpc/msg/revoke.go index eebfdf7797..4f844369f7 100644 --- a/internal/rpc/msg/revoke.go +++ b/internal/rpc/msg/revoke.go @@ -19,6 +19,8 @@ import ( "encoding/json" "time" + "github.com/openimsdk/open-im-server/v3/pkg/authverify" + "github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/protocol/msg" "github.com/OpenIMSDK/protocol/sdkws" @@ -26,8 +28,7 @@ import ( "github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/mcontext" "github.com/OpenIMSDK/tools/utils" - "github.com/openimsdk/open-im-server/v3/pkg/authverify" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" + unrelationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/unrelation" ) @@ -42,7 +43,7 @@ func (m *msgServer) RevokeMsg(ctx context.Context, req *msg.RevokeMsgReq) (*msg. if req.Seq < 0 { return nil, errs.ErrArgs.Wrap("seq is invalid") } - if err := authverify.CheckAccessV3(ctx, req.UserID); err != nil { + if err := authverify.CheckAccessV3(ctx, req.UserID, m.config); err != nil { return nil, err } user, err := m.User.GetUserInfo(ctx, req.UserID) @@ -63,10 +64,10 @@ func (m *msgServer) RevokeMsg(ctx context.Context, req *msg.RevokeMsgReq) (*msg. data, _ := json.Marshal(msgs[0]) log.ZInfo(ctx, "GetMsgBySeqs", "conversationID", req.ConversationID, "seq", req.Seq, "msg", string(data)) var role int32 - if !authverify.IsAppManagerUid(ctx) { + if !authverify.IsAppManagerUid(ctx, m.config) { switch msgs[0].SessionType { case constant.SingleChatType: - if err := authverify.CheckAccessV3(ctx, msgs[0].SendID); err != nil { + if err := authverify.CheckAccessV3(ctx, msgs[0].SendID, m.config); err != nil { return nil, err } role = user.AppMangerLevel @@ -110,11 +111,11 @@ func (m *msgServer) RevokeMsg(ctx context.Context, req *msg.RevokeMsgReq) (*msg. } revokerUserID := mcontext.GetOpUserID(ctx) var flag bool - if len(config.Config.Manager.UserID) > 0 { - flag = utils.Contain(revokerUserID, config.Config.Manager.UserID...) + if len(m.config.Manager.UserID) > 0 { + flag = utils.Contain(revokerUserID, m.config.Manager.UserID...) } - if len(config.Config.Manager.UserID) == 0 && len(config.Config.IMAdmin.UserID) > 0 { - flag = utils.Contain(revokerUserID, config.Config.IMAdmin.UserID...) + if len(m.config.Manager.UserID) == 0 && len(m.config.IMAdmin.UserID) > 0 { + flag = utils.Contain(revokerUserID, m.config.IMAdmin.UserID...) } tips := sdkws.RevokeMsgTips{ RevokerUserID: revokerUserID, @@ -134,7 +135,7 @@ func (m *msgServer) RevokeMsg(ctx context.Context, req *msg.RevokeMsgReq) (*msg. if err := m.notificationSender.NotificationWithSesstionType(ctx, req.UserID, recvID, constant.MsgRevokeNotification, msgs[0].SessionType, &tips); err != nil { return nil, err } - if err = CallbackAfterRevokeMsg(ctx, req); err != nil { + if err = CallbackAfterRevokeMsg(ctx, m.config, req); err != nil { return nil, err } return &msg.RevokeMsgResp{}, nil diff --git a/internal/rpc/msg/send.go b/internal/rpc/msg/send.go index e04cebb3ba..4bac4d1e0a 100644 --- a/internal/rpc/msg/send.go +++ b/internal/rpc/msg/send.go @@ -17,6 +17,9 @@ package msg import ( "context" + "github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics" + "github.com/openimsdk/open-im-server/v3/pkg/msgprocessor" + "github.com/OpenIMSDK/protocol/constant" pbconversation "github.com/OpenIMSDK/protocol/conversation" pbmsg "github.com/OpenIMSDK/protocol/msg" @@ -26,14 +29,12 @@ import ( "github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/mcontext" "github.com/OpenIMSDK/tools/utils" - "github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics" - "github.com/openimsdk/open-im-server/v3/pkg/msgprocessor" ) func (m *msgServer) SendMsg(ctx context.Context, req *pbmsg.SendMsgReq) (resp *pbmsg.SendMsgResp, error error) { resp = &pbmsg.SendMsgResp{} if req.MsgData != nil { - flag := isMessageHasReadEnabled(req.MsgData) + flag := isMessageHasReadEnabled(req.MsgData, m.config) if !flag { return nil, errs.ErrMessageHasReadDisable.Wrap() } @@ -61,11 +62,11 @@ func (m *msgServer) sendMsgSuperGroupChat( prommetrics.GroupChatMsgProcessFailedCounter.Inc() return nil, err } - if err = callbackBeforeSendGroupMsg(ctx, req); err != nil { + if err = callbackBeforeSendGroupMsg(ctx, m.config, req); err != nil { return nil, err } - if err := callbackMsgModify(ctx, req); err != nil { + if err := callbackMsgModify(ctx, m.config, req); err != nil { return nil, err } err = m.MsgDatabase.MsgToMQ(ctx, utils.GenConversationUniqueKeyForGroup(req.MsgData.GroupID), req.MsgData) @@ -75,7 +76,7 @@ func (m *msgServer) sendMsgSuperGroupChat( if req.MsgData.ContentType == constant.AtText { go m.setConversationAtInfo(ctx, req.MsgData) } - if err = callbackAfterSendGroupMsg(ctx, req); err != nil { + if err = callbackAfterSendGroupMsg(ctx, m.config, req); err != nil { log.ZWarn(ctx, "CallbackAfterSendGroupMsg", err) } prommetrics.GroupChatMsgProcessSuccessCounter.Inc() @@ -107,7 +108,7 @@ func (m *msgServer) setConversationAtInfo(nctx context.Context, msg *sdkws.MsgDa conversation.GroupAtType = &wrapperspb.Int32Value{Value: constant.AtAll} } else { //@Everyone and @other people conversation.GroupAtType = &wrapperspb.Int32Value{Value: constant.AtAllAtMe} - err := m.Conversation.SetConversations(ctx, atUserID, conversation) + err = m.Conversation.SetConversations(ctx, atUserID, conversation) if err != nil { log.ZWarn(ctx, "SetConversations", err, "userID", atUserID, "conversation", conversation) } @@ -164,18 +165,18 @@ func (m *msgServer) sendMsgSingleChat(ctx context.Context, req *pbmsg.SendMsgReq prommetrics.SingleChatMsgProcessFailedCounter.Inc() return nil, nil } else { - if err = callbackBeforeSendSingleMsg(ctx, req); err != nil { + if err = callbackBeforeSendSingleMsg(ctx, m.config, req); err != nil { return nil, err } - if err := callbackMsgModify(ctx, req); err != nil { + if err := callbackMsgModify(ctx, m.config, req); err != nil { return nil, err } if err := m.MsgDatabase.MsgToMQ(ctx, utils.GenConversationUniqueKeyForSingle(req.MsgData.SendID, req.MsgData.RecvID), req.MsgData); err != nil { prommetrics.SingleChatMsgProcessFailedCounter.Inc() return nil, err } - err = callbackAfterSendSingleMsg(ctx, req) + err = callbackAfterSendSingleMsg(ctx, m.config, req) if err != nil { log.ZWarn(ctx, "CallbackAfterSendSingleMsg", err, "req", req) } diff --git a/internal/rpc/msg/server.go b/internal/rpc/msg/server.go index 79ae483a2e..5b7cd2f662 100644 --- a/internal/rpc/msg/server.go +++ b/internal/rpc/msg/server.go @@ -15,16 +15,20 @@ package msg import ( + "github.com/openimsdk/open-im-server/v3/pkg/common/config" + + "google.golang.org/grpc" + "github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/protocol/conversation" "github.com/OpenIMSDK/protocol/msg" "github.com/OpenIMSDK/tools/discoveryregistry" + "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" "github.com/openimsdk/open-im-server/v3/pkg/common/db/localcache" "github.com/openimsdk/open-im-server/v3/pkg/common/db/unrelation" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" - "google.golang.org/grpc" ) type ( @@ -40,6 +44,7 @@ type ( ConversationLocalCache *localcache.ConversationLocalCache Handlers MessageInterceptorChain notificationSender *rpcclient.NotificationSender + config *config.GlobalConfig } ) @@ -47,37 +52,36 @@ func (m *msgServer) addInterceptorHandler(interceptorFunc ...MessageInterceptorF m.Handlers = append(m.Handlers, interceptorFunc...) } -// func `(*msgServer).execInterceptorHandler` is unused -// func (m *msgServer) execInterceptorHandler(ctx context.Context, req *msg.SendMsgReq) error { -// for _, handler := range m.Handlers { -// msgData, err := handler(ctx, req) -// if err != nil { -// return err -// } -// req.MsgData = msgData -// } -// return nil -// } +//func (m *msgServer) execInterceptorHandler(ctx context.Context, config *config.GlobalConfig, req *msg.SendMsgReq) error { +// for _, handler := range m.Handlers { +// msgData, err := handler(ctx, config, req) +// if err != nil { +// return err +// } +// req.MsgData = msgData +// } +// return nil +//} -func Start(client discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) error { - rdb, err := cache.NewRedis() +func Start(config *config.GlobalConfig, client discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) error { + rdb, err := cache.NewRedis(config) if err != nil { return err } - mongo, err := unrelation.NewMongo() + mongo, err := unrelation.NewMongo(config) if err != nil { return err } if err := mongo.CreateMsgIndex(); err != nil { return err } - cacheModel := cache.NewMsgCacheModel(rdb) - msgDocModel := unrelation.NewMsgMongoDriver(mongo.GetDatabase()) - conversationClient := rpcclient.NewConversationRpcClient(client) - userRpcClient := rpcclient.NewUserRpcClient(client) - groupRpcClient := rpcclient.NewGroupRpcClient(client) - friendRpcClient := rpcclient.NewFriendRpcClient(client) - msgDatabase, err := controller.NewCommonMsgDatabase(msgDocModel, cacheModel) + cacheModel := cache.NewMsgCacheModel(rdb, config) + msgDocModel := unrelation.NewMsgMongoDriver(mongo.GetDatabase(config.Mongo.Database)) + conversationClient := rpcclient.NewConversationRpcClient(client, config) + userRpcClient := rpcclient.NewUserRpcClient(client, config) + groupRpcClient := rpcclient.NewGroupRpcClient(client, config) + friendRpcClient := rpcclient.NewFriendRpcClient(client, config) + msgDatabase, err := controller.NewCommonMsgDatabase(msgDocModel, cacheModel, config) if err != nil { return err } @@ -90,8 +94,9 @@ func Start(client discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) e GroupLocalCache: localcache.NewGroupLocalCache(&groupRpcClient), ConversationLocalCache: localcache.NewConversationLocalCache(&conversationClient), friend: &friendRpcClient, + config: config, } - s.notificationSender = rpcclient.NewNotificationSender(rpcclient.WithLocalSendMsg(s.SendMsg)) + s.notificationSender = rpcclient.NewNotificationSender(config, rpcclient.WithLocalSendMsg(s.SendMsg)) s.addInterceptorHandler(MessageHasReadEnabled) msg.RegisterMsgServer(server, s) return nil diff --git a/internal/rpc/msg/sync_msg.go b/internal/rpc/msg/sync_msg.go index fa894e0344..b714da375f 100644 --- a/internal/rpc/msg/sync_msg.go +++ b/internal/rpc/msg/sync_msg.go @@ -88,7 +88,7 @@ func (m *msgServer) PullMessageBySeqs( } func (m *msgServer) GetMaxSeq(ctx context.Context, req *sdkws.GetMaxSeqReq) (*sdkws.GetMaxSeqResp, error) { - if err := authverify.CheckAccessV3(ctx, req.UserID); err != nil { + if err := authverify.CheckAccessV3(ctx, req.UserID, m.config); err != nil { return nil, err } conversationIDs, err := m.ConversationLocalCache.GetConversationIDs(ctx, req.UserID) diff --git a/internal/rpc/msg/utils.go b/internal/rpc/msg/utils.go index d8a45e8750..48665562ad 100644 --- a/internal/rpc/msg/utils.go +++ b/internal/rpc/msg/utils.go @@ -23,16 +23,16 @@ import ( "go.mongodb.org/mongo-driver/mongo" ) -func isMessageHasReadEnabled(msgData *sdkws.MsgData) bool { +func isMessageHasReadEnabled(msgData *sdkws.MsgData, config *config.GlobalConfig) bool { switch { case msgData.ContentType == constant.HasReadReceipt && msgData.SessionType == constant.SingleChatType: - if config.Config.SingleMessageHasReadReceiptEnable { + if config.SingleMessageHasReadReceiptEnable { return true } else { return false } case msgData.ContentType == constant.HasReadReceipt && msgData.SessionType == constant.SuperGroupChatType: - if config.Config.GroupMessageHasReadReceiptEnable { + if config.GroupMessageHasReadReceiptEnable { return true } else { return false diff --git a/internal/rpc/msg/verify.go b/internal/rpc/msg/verify.go index 11055fac11..d72e4923ee 100644 --- a/internal/rpc/msg/verify.go +++ b/internal/rpc/msg/verify.go @@ -25,7 +25,6 @@ import ( "github.com/OpenIMSDK/protocol/sdkws" "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/utils" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" ) var ExcludeContentType = []int{constant.HasReadReceipt} @@ -50,10 +49,10 @@ type MessageRevoked struct { func (m *msgServer) messageVerification(ctx context.Context, data *msg.SendMsgReq) error { switch data.MsgData.SessionType { case constant.SingleChatType: - if len(config.Config.Manager.UserID) > 0 && utils.IsContain(data.MsgData.SendID, config.Config.Manager.UserID) { + if len(m.config.Manager.UserID) > 0 && utils.IsContain(data.MsgData.SendID, m.config.Manager.UserID) { return nil } - if utils.IsContain(data.MsgData.SendID, config.Config.IMAdmin.UserID) { + if utils.IsContain(data.MsgData.SendID, m.config.IMAdmin.UserID) { return nil } if data.MsgData.ContentType <= constant.NotificationEnd && @@ -67,7 +66,7 @@ func (m *msgServer) messageVerification(ctx context.Context, data *msg.SendMsgRe if black { return errs.ErrBlockedByPeer.Wrap() } - if *config.Config.MessageVerify.FriendVerify { + if *m.config.MessageVerify.FriendVerify { friend, err := m.friend.IsFriend(ctx, data.MsgData.SendID, data.MsgData.RecvID) if err != nil { return err @@ -90,10 +89,10 @@ func (m *msgServer) messageVerification(ctx context.Context, data *msg.SendMsgRe if groupInfo.GroupType == constant.SuperGroup { return nil } - if len(config.Config.Manager.UserID) > 0 && utils.IsContain(data.MsgData.SendID, config.Config.Manager.UserID) { + if len(m.config.Manager.UserID) > 0 && utils.IsContain(data.MsgData.SendID, m.config.Manager.UserID) { return nil } - if utils.IsContain(data.MsgData.SendID, config.Config.IMAdmin.UserID) { + if utils.IsContain(data.MsgData.SendID, m.config.IMAdmin.UserID) { return nil } if data.MsgData.ContentType <= constant.NotificationEnd && @@ -158,9 +157,6 @@ func (m *msgServer) encapsulateMsgData(msg *sdkws.MsgData) { case constant.Custom: fallthrough case constant.Quote: - utils.SetSwitchFromOptions(msg.Options, constant.IsConversationUpdate, true) - utils.SetSwitchFromOptions(msg.Options, constant.IsUnreadCount, true) - utils.SetSwitchFromOptions(msg.Options, constant.IsSenderSync, true) case constant.Revoke: utils.SetSwitchFromOptions(msg.Options, constant.IsUnreadCount, false) utils.SetSwitchFromOptions(msg.Options, constant.IsOfflinePush, false) diff --git a/internal/rpc/third/log.go b/internal/rpc/third/log.go index 420f399ba4..b425dd819e 100644 --- a/internal/rpc/third/log.go +++ b/internal/rpc/third/log.go @@ -82,7 +82,7 @@ func (t *thirdServer) UploadLogs(ctx context.Context, req *third.UploadLogsReq) } func (t *thirdServer) DeleteLogs(ctx context.Context, req *third.DeleteLogsReq) (*third.DeleteLogsResp, error) { - if err := authverify.CheckAdmin(ctx); err != nil { + if err := authverify.CheckAdmin(ctx, t.config); err != nil { return nil, err } userID := "" @@ -123,7 +123,7 @@ func dbToPbLogInfos(logs []*relationtb.LogModel) []*third.LogInfo { } func (t *thirdServer) SearchLogs(ctx context.Context, req *third.SearchLogsReq) (*third.SearchLogsResp, error) { - if err := authverify.CheckAdmin(ctx); err != nil { + if err := authverify.CheckAdmin(ctx, t.config); err != nil { return nil, err } var ( diff --git a/internal/rpc/third/s3.go b/internal/rpc/third/s3.go index 7f68f4da89..1975163e5e 100644 --- a/internal/rpc/third/s3.go +++ b/internal/rpc/third/s3.go @@ -29,7 +29,6 @@ import ( "github.com/OpenIMSDK/tools/mcontext" "github.com/OpenIMSDK/tools/utils" "github.com/google/uuid" - "github.com/openimsdk/open-im-server/v3/pkg/authverify" "github.com/openimsdk/open-im-server/v3/pkg/common/db/s3" "github.com/openimsdk/open-im-server/v3/pkg/common/db/s3/cont" "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" @@ -54,7 +53,7 @@ func (t *thirdServer) PartSize(ctx context.Context, req *third.PartSizeReq) (*th func (t *thirdServer) InitiateMultipartUpload(ctx context.Context, req *third.InitiateMultipartUploadReq) (*third.InitiateMultipartUploadResp, error) { defer log.ZDebug(ctx, "return") - if err := checkUploadName(ctx, req.Name); err != nil { + if err := t.checkUploadName(ctx, req.Name); err != nil { return nil, err } expireTime := time.Now().Add(t.defaultExpire) @@ -133,7 +132,7 @@ func (t *thirdServer) AuthSign(ctx context.Context, req *third.AuthSignReq) (*th func (t *thirdServer) CompleteMultipartUpload(ctx context.Context, req *third.CompleteMultipartUploadReq) (*third.CompleteMultipartUploadResp, error) { defer log.ZDebug(ctx, "return") - if err := checkUploadName(ctx, req.Name); err != nil { + if err := t.checkUploadName(ctx, req.Name); err != nil { return nil, err } result, err := t.s3dataBase.CompleteMultipartUpload(ctx, req.UploadID, req.Parts) @@ -190,13 +189,13 @@ func (t *thirdServer) InitiateFormData(ctx context.Context, req *third.InitiateF if req.Size <= 0 { return nil, errs.ErrArgs.Wrap("size must be greater than 0") } - if err := checkUploadName(ctx, req.Name); err != nil { + if err := t.checkUploadName(ctx, req.Name); err != nil { return nil, err } var duration time.Duration opUserID := mcontext.GetOpUserID(ctx) var key string - if authverify.IsManagerUserID(opUserID) { + if t.IsManagerUserID(opUserID) { if req.Millisecond <= 0 { duration = time.Minute * 10 } else { @@ -256,7 +255,7 @@ func (t *thirdServer) CompleteFormData(ctx context.Context, req *third.CompleteF if err := json.Unmarshal(data, &mate); err != nil { return nil, errs.ErrArgs.Wrap("invalid id " + err.Error()) } - if err := checkUploadName(ctx, mate.Name); err != nil { + if err := t.checkUploadName(ctx, mate.Name); err != nil { return nil, err } info, err := t.s3dataBase.StatObject(ctx, mate.Key) diff --git a/internal/rpc/third/third.go b/internal/rpc/third/third.go index 9dd3ffd65a..2bccb5c78f 100644 --- a/internal/rpc/third/third.go +++ b/internal/rpc/third/third.go @@ -20,59 +20,63 @@ import ( "net/url" "time" - "github.com/OpenIMSDK/protocol/third" - "github.com/OpenIMSDK/tools/discoveryregistry" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" "github.com/openimsdk/open-im-server/v3/pkg/common/db/mgo" + "github.com/openimsdk/open-im-server/v3/pkg/common/db/unrelation" + "github.com/openimsdk/open-im-server/v3/pkg/common/db/s3" "github.com/openimsdk/open-im-server/v3/pkg/common/db/s3/cos" "github.com/openimsdk/open-im-server/v3/pkg/common/db/s3/minio" "github.com/openimsdk/open-im-server/v3/pkg/common/db/s3/oss" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/unrelation" - "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" + "google.golang.org/grpc" + + "github.com/OpenIMSDK/protocol/third" + "github.com/OpenIMSDK/tools/discoveryregistry" + + "github.com/openimsdk/open-im-server/v3/pkg/common/config" + "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" + "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" + "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" ) -func Start(client discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) error { - mongo, err := unrelation.NewMongo() +func Start(config *config.GlobalConfig, client discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) error { + mongo, err := unrelation.NewMongo(config) if err != nil { return err } - logdb, err := mgo.NewLogMongo(mongo.GetDatabase()) + logdb, err := mgo.NewLogMongo(mongo.GetDatabase(config.Mongo.Database)) if err != nil { return err } - s3db, err := mgo.NewS3Mongo(mongo.GetDatabase()) + s3db, err := mgo.NewS3Mongo(mongo.GetDatabase(config.Mongo.Database)) if err != nil { return err } - apiURL := config.Config.Object.ApiURL + apiURL := config.Object.ApiURL if apiURL == "" { return fmt.Errorf("api url is empty") } - if _, err := url.Parse(config.Config.Object.ApiURL); err != nil { + if _, parseErr := url.Parse(config.Object.ApiURL); parseErr != nil { return err } if apiURL[len(apiURL)-1] != '/' { apiURL += "/" } apiURL += "object/" - rdb, err := cache.NewRedis() + rdb, err := cache.NewRedis(config) if err != nil { return err } - // Select based on the configuration file strategy - enable := config.Config.Object.Enable + // 根据配置文件策略选择 oss 方式 + enable := config.Object.Enable var o s3.Interface - switch config.Config.Object.Enable { + switch enable { case "minio": - o, err = minio.NewMinio(cache.NewMinioCache(rdb)) + o, err = minio.NewMinio(cache.NewMinioCache(rdb), minio.Config(config.Object.Minio)) case "cos": - o, err = cos.NewCos() + o, err = cos.NewCos(cos.Config(config.Object.Cos)) case "oss": - o, err = oss.NewOSS() + o, err = oss.NewOSS(oss.Config(config.Object.Oss)) default: err = fmt.Errorf("invalid object enable: %s", enable) } @@ -81,10 +85,11 @@ func Start(client discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) e } third.RegisterThirdServer(server, &thirdServer{ apiURL: apiURL, - thirdDatabase: controller.NewThirdDatabase(cache.NewMsgCacheModel(rdb), logdb), - userRpcClient: rpcclient.NewUserRpcClient(client), + thirdDatabase: controller.NewThirdDatabase(cache.NewMsgCacheModel(rdb, config), logdb), + userRpcClient: rpcclient.NewUserRpcClient(client, config), s3dataBase: controller.NewS3Database(rdb, o, s3db), defaultExpire: time.Hour * 24 * 7, + config: config, }) return nil } @@ -95,6 +100,7 @@ type thirdServer struct { s3dataBase controller.S3Database userRpcClient rpcclient.UserRpcClient defaultExpire time.Duration + config *config.GlobalConfig } func (t *thirdServer) FcmUpdateToken(ctx context.Context, req *third.FcmUpdateTokenReq) (resp *third.FcmUpdateTokenResp, err error) { diff --git a/internal/rpc/third/tool.go b/internal/rpc/third/tool.go index cf25f98209..6591134d62 100644 --- a/internal/rpc/third/tool.go +++ b/internal/rpc/third/tool.go @@ -21,10 +21,11 @@ import ( "strings" "unicode/utf8" + "github.com/openimsdk/open-im-server/v3/pkg/authverify" + "github.com/OpenIMSDK/protocol/third" "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/mcontext" - "github.com/openimsdk/open-im-server/v3/pkg/authverify" ) func toPbMapArray(m map[string][]string) []*third.KeyValues { @@ -41,7 +42,7 @@ func toPbMapArray(m map[string][]string) []*third.KeyValues { return res } -func checkUploadName(ctx context.Context, name string) error { +func (t *thirdServer) checkUploadName(ctx context.Context, name string) error { if name == "" { return errs.ErrArgs.Wrap("name is empty") } @@ -55,7 +56,7 @@ func checkUploadName(ctx context.Context, name string) error { if opUserID == "" { return errs.ErrNoPermission.Wrap("opUserID is empty") } - if !authverify.IsManagerUserID(opUserID) { + if !authverify.IsManagerUserID(opUserID, t.config) { if !strings.HasPrefix(name, opUserID+"/") { return errs.ErrNoPermission.Wrap(fmt.Sprintf("name must start with `%s/`", opUserID)) } @@ -79,3 +80,7 @@ func checkValidObjectName(objectName string) error { } return checkValidObjectNamePrefix(objectName) } + +func (t *thirdServer) IsManagerUserID(opUserID string) bool { + return authverify.IsManagerUserID(opUserID, t.config) +} diff --git a/internal/rpc/user/callback.go b/internal/rpc/user/callback.go index 1437257f78..34f211973d 100644 --- a/internal/rpc/user/callback.go +++ b/internal/rpc/user/callback.go @@ -24,8 +24,8 @@ import ( "github.com/openimsdk/open-im-server/v3/pkg/common/http" ) -func CallbackBeforeUpdateUserInfo(ctx context.Context, req *pbuser.UpdateUserInfoReq) error { - if !config.Config.Callback.CallbackBeforeUpdateUserInfo.Enable { +func CallbackBeforeUpdateUserInfo(ctx context.Context, globalConfig *config.GlobalConfig, req *pbuser.UpdateUserInfoReq) error { + if !globalConfig.Callback.CallbackBeforeUpdateUserInfo.Enable { return nil } cbReq := &cbapi.CallbackBeforeUpdateUserInfoReq{ @@ -35,7 +35,7 @@ func CallbackBeforeUpdateUserInfo(ctx context.Context, req *pbuser.UpdateUserInf Nickname: &req.UserInfo.Nickname, } resp := &cbapi.CallbackBeforeUpdateUserInfoResp{} - if err := http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, cbReq, resp, config.Config.Callback.CallbackBeforeUpdateUserInfo); err != nil { + if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, cbReq, resp, globalConfig.Callback.CallbackBeforeUpdateUserInfo); err != nil { return err } utils.NotNilReplace(&req.UserInfo.FaceURL, resp.FaceURL) @@ -43,8 +43,8 @@ func CallbackBeforeUpdateUserInfo(ctx context.Context, req *pbuser.UpdateUserInf utils.NotNilReplace(&req.UserInfo.Nickname, resp.Nickname) return nil } -func CallbackAfterUpdateUserInfo(ctx context.Context, req *pbuser.UpdateUserInfoReq) error { - if !config.Config.Callback.CallbackAfterUpdateUserInfo.Enable { +func CallbackAfterUpdateUserInfo(ctx context.Context, globalConfig *config.GlobalConfig, req *pbuser.UpdateUserInfoReq) error { + if !globalConfig.Callback.CallbackAfterUpdateUserInfo.Enable { return nil } cbReq := &cbapi.CallbackAfterUpdateUserInfoReq{ @@ -54,13 +54,13 @@ func CallbackAfterUpdateUserInfo(ctx context.Context, req *pbuser.UpdateUserInfo Nickname: req.UserInfo.Nickname, } resp := &cbapi.CallbackAfterUpdateUserInfoResp{} - if err := http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, cbReq, resp, config.Config.Callback.CallbackBeforeUpdateUserInfo); err != nil { + if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, cbReq, resp, globalConfig.Callback.CallbackBeforeUpdateUserInfo); err != nil { return err } return nil } -func CallbackBeforeUpdateUserInfoEx(ctx context.Context, req *pbuser.UpdateUserInfoExReq) error { - if !config.Config.Callback.CallbackBeforeUpdateUserInfoEx.Enable { +func CallbackBeforeUpdateUserInfoEx(ctx context.Context, globalConfig *config.GlobalConfig, req *pbuser.UpdateUserInfoExReq) error { + if !globalConfig.Callback.CallbackBeforeUpdateUserInfoEx.Enable { return nil } cbReq := &cbapi.CallbackBeforeUpdateUserInfoExReq{ @@ -70,7 +70,7 @@ func CallbackBeforeUpdateUserInfoEx(ctx context.Context, req *pbuser.UpdateUserI Nickname: req.UserInfo.Nickname, } resp := &cbapi.CallbackBeforeUpdateUserInfoExResp{} - if err := http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, cbReq, resp, config.Config.Callback.CallbackBeforeUpdateUserInfoEx); err != nil { + if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, cbReq, resp, globalConfig.Callback.CallbackBeforeUpdateUserInfoEx); err != nil { return err } utils.NotNilReplace(req.UserInfo.FaceURL, resp.FaceURL) @@ -78,8 +78,8 @@ func CallbackBeforeUpdateUserInfoEx(ctx context.Context, req *pbuser.UpdateUserI utils.NotNilReplace(req.UserInfo.Nickname, resp.Nickname) return nil } -func CallbackAfterUpdateUserInfoEx(ctx context.Context, req *pbuser.UpdateUserInfoExReq) error { - if !config.Config.Callback.CallbackAfterUpdateUserInfoEx.Enable { +func CallbackAfterUpdateUserInfoEx(ctx context.Context, globalConfig *config.GlobalConfig, req *pbuser.UpdateUserInfoExReq) error { + if !globalConfig.Callback.CallbackAfterUpdateUserInfoEx.Enable { return nil } cbReq := &cbapi.CallbackAfterUpdateUserInfoExReq{ @@ -89,14 +89,14 @@ func CallbackAfterUpdateUserInfoEx(ctx context.Context, req *pbuser.UpdateUserIn Nickname: req.UserInfo.Nickname, } resp := &cbapi.CallbackAfterUpdateUserInfoExResp{} - if err := http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, cbReq, resp, config.Config.Callback.CallbackBeforeUpdateUserInfoEx); err != nil { + if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, cbReq, resp, globalConfig.Callback.CallbackBeforeUpdateUserInfoEx); err != nil { return err } return nil } -func CallbackBeforeUserRegister(ctx context.Context, req *pbuser.UserRegisterReq) error { - if !config.Config.Callback.CallbackBeforeUserRegister.Enable { +func CallbackBeforeUserRegister(ctx context.Context, globalConfig *config.GlobalConfig, req *pbuser.UserRegisterReq) error { + if !globalConfig.Callback.CallbackBeforeUserRegister.Enable { return nil } cbReq := &cbapi.CallbackBeforeUserRegisterReq{ @@ -106,7 +106,7 @@ func CallbackBeforeUserRegister(ctx context.Context, req *pbuser.UserRegisterReq } resp := &cbapi.CallbackBeforeUserRegisterResp{} - if err := http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, cbReq, resp, config.Config.Callback.CallbackBeforeUpdateUserInfo); err != nil { + if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, cbReq, resp, globalConfig.Callback.CallbackBeforeUpdateUserInfo); err != nil { return err } if len(resp.Users) != 0 { @@ -115,8 +115,8 @@ func CallbackBeforeUserRegister(ctx context.Context, req *pbuser.UserRegisterReq return nil } -func CallbackAfterUserRegister(ctx context.Context, req *pbuser.UserRegisterReq) error { - if !config.Config.Callback.CallbackAfterUserRegister.Enable { +func CallbackAfterUserRegister(ctx context.Context, globalConfig *config.GlobalConfig, req *pbuser.UserRegisterReq) error { + if !globalConfig.Callback.CallbackAfterUserRegister.Enable { return nil } cbReq := &cbapi.CallbackAfterUserRegisterReq{ @@ -126,7 +126,7 @@ func CallbackAfterUserRegister(ctx context.Context, req *pbuser.UserRegisterReq) } resp := &cbapi.CallbackAfterUserRegisterResp{} - if err := http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, cbReq, resp, config.Config.Callback.CallbackAfterUpdateUserInfo); err != nil { + if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, cbReq, resp, globalConfig.Callback.CallbackAfterUpdateUserInfo); err != nil { return err } return nil diff --git a/internal/rpc/user/user.go b/internal/rpc/user/user.go index 7ed3ff7d6d..02e641d202 100644 --- a/internal/rpc/user/user.go +++ b/internal/rpc/user/user.go @@ -21,26 +21,34 @@ import ( "strings" "time" + "github.com/OpenIMSDK/tools/pagination" + + "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" + + "github.com/OpenIMSDK/tools/tx" + + "github.com/openimsdk/open-im-server/v3/pkg/common/db/mgo" + "github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/protocol/sdkws" - pbuser "github.com/OpenIMSDK/protocol/user" - registry "github.com/OpenIMSDK/tools/discoveryregistry" "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/log" - "github.com/OpenIMSDK/tools/pagination" - "github.com/OpenIMSDK/tools/tx" - "github.com/OpenIMSDK/tools/utils" + "github.com/openimsdk/open-im-server/v3/pkg/authverify" + "github.com/openimsdk/open-im-server/v3/pkg/common/db/unrelation" + + registry "github.com/OpenIMSDK/tools/discoveryregistry" + "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/convert" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/mgo" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" tablerelation "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/unrelation" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient/notification" + + pbuser "github.com/OpenIMSDK/protocol/user" + "github.com/OpenIMSDK/tools/utils" "google.golang.org/grpc" ) @@ -51,6 +59,7 @@ type userServer struct { friendRpcClient *rpcclient.FriendRpcClient groupRpcClient *rpcclient.GroupRpcClient RegisterCenter registry.SvcDiscoveryRegistry + config *config.GlobalConfig } func (s *userServer) GetGroupOnlineUser(ctx context.Context, req *pbuser.GetGroupOnlineUserReq) (*pbuser.GetGroupOnlineUserResp, error) { @@ -58,39 +67,40 @@ func (s *userServer) GetGroupOnlineUser(ctx context.Context, req *pbuser.GetGrou panic("implement me") } -func Start(client registry.SvcDiscoveryRegistry, server *grpc.Server) error { - rdb, err := cache.NewRedis() +func Start(config *config.GlobalConfig, client registry.SvcDiscoveryRegistry, server *grpc.Server) error { + rdb, err := cache.NewRedis(config) if err != nil { return err } - mongo, err := unrelation.NewMongo() + mongo, err := unrelation.NewMongo(config) if err != nil { return err } users := make([]*tablerelation.UserModel, 0) - if len(config.Config.IMAdmin.UserID) != len(config.Config.IMAdmin.Nickname) { - return errors.New("len(config.Config.AppNotificationAdmin.AppManagerUid) != len(config.Config.AppNotificationAdmin.Nickname)") + if len(config.IMAdmin.UserID) != len(config.IMAdmin.Nickname) { + return errors.New("len(s.config.AppNotificationAdmin.AppManagerUid) != len(s.config.AppNotificationAdmin.Nickname)") } - for k, v := range config.Config.IMAdmin.UserID { - users = append(users, &tablerelation.UserModel{UserID: v, Nickname: config.Config.IMAdmin.Nickname[k], AppMangerLevel: constant.AppNotificationAdmin}) + for k, v := range config.IMAdmin.UserID { + users = append(users, &tablerelation.UserModel{UserID: v, Nickname: config.IMAdmin.Nickname[k], AppMangerLevel: constant.AppNotificationAdmin}) } - userDB, err := mgo.NewUserMongo(mongo.GetDatabase()) + userDB, err := mgo.NewUserMongo(mongo.GetDatabase(config.Mongo.Database)) if err != nil { return err } cache := cache.NewUserCacheRedis(rdb, userDB, cache.GetDefaultOpt()) - userMongoDB := unrelation.NewUserMongoDriver(mongo.GetDatabase()) + userMongoDB := unrelation.NewUserMongoDriver(mongo.GetDatabase(config.Mongo.Database)) database := controller.NewUserDatabase(userDB, cache, tx.NewMongo(mongo.GetClient()), userMongoDB) - friendRpcClient := rpcclient.NewFriendRpcClient(client) - groupRpcClient := rpcclient.NewGroupRpcClient(client) - msgRpcClient := rpcclient.NewMessageRpcClient(client) + friendRpcClient := rpcclient.NewFriendRpcClient(client, config) + groupRpcClient := rpcclient.NewGroupRpcClient(client, config) + msgRpcClient := rpcclient.NewMessageRpcClient(client, config) u := &userServer{ UserDatabase: database, RegisterCenter: client, friendRpcClient: &friendRpcClient, groupRpcClient: &groupRpcClient, - friendNotificationSender: notification.NewFriendNotificationSender(&msgRpcClient, notification.WithDBFunc(database.FindWithError)), - userNotificationSender: notification.NewUserNotificationSender(&msgRpcClient, notification.WithUserFunc(database.FindWithError)), + friendNotificationSender: notification.NewFriendNotificationSender(config, &msgRpcClient, notification.WithDBFunc(database.FindWithError)), + userNotificationSender: notification.NewUserNotificationSender(config, &msgRpcClient, notification.WithUserFunc(database.FindWithError)), + config: config, } pbuser.RegisterUserServer(server, u) return u.UserDatabase.InitOnce(context.Background(), users) @@ -111,11 +121,11 @@ func (s *userServer) GetDesignateUsers(ctx context.Context, req *pbuser.GetDesig func (s *userServer) UpdateUserInfo(ctx context.Context, req *pbuser.UpdateUserInfoReq) (resp *pbuser.UpdateUserInfoResp, err error) { resp = &pbuser.UpdateUserInfoResp{} - err = authverify.CheckAccessV3(ctx, req.UserInfo.UserID) + err = authverify.CheckAccessV3(ctx, req.UserInfo.UserID, s.config) if err != nil { return nil, err } - if err := CallbackBeforeUpdateUserInfo(ctx, req); err != nil { + if err := CallbackBeforeUpdateUserInfo(ctx, s.config, req); err != nil { return nil, err } data := convert.UserPb2DBMap(req.UserInfo) @@ -128,29 +138,29 @@ func (s *userServer) UpdateUserInfo(ctx context.Context, req *pbuser.UpdateUserI return nil, err } if req.UserInfo.Nickname != "" || req.UserInfo.FaceURL != "" { - if err := s.groupRpcClient.NotificationUserInfoUpdate(ctx, req.UserInfo.UserID); err != nil { + if err = s.groupRpcClient.NotificationUserInfoUpdate(ctx, req.UserInfo.UserID); err != nil { log.ZError(ctx, "NotificationUserInfoUpdate", err) } } for _, friendID := range friends { s.friendNotificationSender.FriendInfoUpdatedNotification(ctx, req.UserInfo.UserID, friendID) } - if err := CallbackAfterUpdateUserInfo(ctx, req); err != nil { + if err = CallbackAfterUpdateUserInfo(ctx, s.config, req); err != nil { return nil, err } - if err := s.groupRpcClient.NotificationUserInfoUpdate(ctx, req.UserInfo.UserID); err != nil { + if err = s.groupRpcClient.NotificationUserInfoUpdate(ctx, req.UserInfo.UserID); err != nil { log.ZError(ctx, "NotificationUserInfoUpdate", err, "userID", req.UserInfo.UserID) } return resp, nil } func (s *userServer) UpdateUserInfoEx(ctx context.Context, req *pbuser.UpdateUserInfoExReq) (resp *pbuser.UpdateUserInfoExResp, err error) { resp = &pbuser.UpdateUserInfoExResp{} - err = authverify.CheckAccessV3(ctx, req.UserInfo.UserID) + err = authverify.CheckAccessV3(ctx, req.UserInfo.UserID, s.config) if err != nil { return nil, err } - if err = CallbackBeforeUpdateUserInfoEx(ctx, req); err != nil { + if err = CallbackBeforeUpdateUserInfoEx(ctx, s.config, req); err != nil { return nil, err } data := convert.UserPb2DBMapEx(req.UserInfo) @@ -170,7 +180,7 @@ func (s *userServer) UpdateUserInfoEx(ctx context.Context, req *pbuser.UpdateUse for _, friendID := range friends { s.friendNotificationSender.FriendInfoUpdatedNotification(ctx, req.UserInfo.UserID, friendID) } - if err := CallbackAfterUpdateUserInfoEx(ctx, req); err != nil { + if err := CallbackAfterUpdateUserInfoEx(ctx, s.config, req); err != nil { return nil, err } if err := s.groupRpcClient.NotificationUserInfoUpdate(ctx, req.UserInfo.UserID); err != nil { @@ -197,7 +207,7 @@ func (s *userServer) AccountCheck(ctx context.Context, req *pbuser.AccountCheckR if utils.Duplicate(req.CheckUserIDs) { return nil, errs.ErrArgs.Wrap("userID repeated") } - err = authverify.CheckAdmin(ctx) + err = authverify.CheckAdmin(ctx, s.config) if err != nil { return nil, err } @@ -244,8 +254,8 @@ func (s *userServer) UserRegister(ctx context.Context, req *pbuser.UserRegisterR if len(req.Users) == 0 { return nil, errs.ErrArgs.Wrap("users is empty") } - if req.Secret != config.Config.Secret { - log.ZDebug(ctx, "UserRegister", config.Config.Secret, req.Secret) + if req.Secret != s.config.Secret { + log.ZDebug(ctx, "UserRegister", s.config.Secret, req.Secret) return nil, errs.ErrNoPermission.Wrap("secret invalid") } if utils.DuplicateAny(req.Users, func(e *sdkws.UserInfo) string { return e.UserID }) { @@ -268,7 +278,7 @@ func (s *userServer) UserRegister(ctx context.Context, req *pbuser.UserRegisterR if exist { return nil, errs.ErrRegisteredAlready.Wrap("userID registered already") } - if err := CallbackBeforeUserRegister(ctx, req); err != nil { + if err := CallbackBeforeUserRegister(ctx, s.config, req); err != nil { return nil, err } now := time.Now() @@ -288,7 +298,7 @@ func (s *userServer) UserRegister(ctx context.Context, req *pbuser.UserRegisterR return nil, err } - if err := CallbackAfterUserRegister(ctx, req); err != nil { + if err := CallbackAfterUserRegister(ctx, s.config, req); err != nil { return nil, err } return resp, nil @@ -383,7 +393,7 @@ func (s *userServer) GetSubscribeUsersStatus(ctx context.Context, // ProcessUserCommandAdd user general function add. func (s *userServer) ProcessUserCommandAdd(ctx context.Context, req *pbuser.ProcessUserCommandAddReq) (*pbuser.ProcessUserCommandAddResp, error) { - err := authverify.CheckAccessV3(ctx, req.UserID) + err := authverify.CheckAccessV3(ctx, req.UserID, s.config) if err != nil { return nil, err } @@ -414,7 +424,7 @@ func (s *userServer) ProcessUserCommandAdd(ctx context.Context, req *pbuser.Proc // ProcessUserCommandDelete user general function delete. func (s *userServer) ProcessUserCommandDelete(ctx context.Context, req *pbuser.ProcessUserCommandDeleteReq) (*pbuser.ProcessUserCommandDeleteResp, error) { - err := authverify.CheckAccessV3(ctx, req.UserID) + err := authverify.CheckAccessV3(ctx, req.UserID, s.config) if err != nil { return nil, err } @@ -437,7 +447,7 @@ func (s *userServer) ProcessUserCommandDelete(ctx context.Context, req *pbuser.P // ProcessUserCommandUpdate user general function update. func (s *userServer) ProcessUserCommandUpdate(ctx context.Context, req *pbuser.ProcessUserCommandUpdateReq) (*pbuser.ProcessUserCommandUpdateResp, error) { - err := authverify.CheckAccessV3(ctx, req.UserID) + err := authverify.CheckAccessV3(ctx, req.UserID, s.config) if err != nil { return nil, err } @@ -469,7 +479,7 @@ func (s *userServer) ProcessUserCommandUpdate(ctx context.Context, req *pbuser.P func (s *userServer) ProcessUserCommandGet(ctx context.Context, req *pbuser.ProcessUserCommandGetReq) (*pbuser.ProcessUserCommandGetResp, error) { - err := authverify.CheckAccessV3(ctx, req.UserID) + err := authverify.CheckAccessV3(ctx, req.UserID, s.config) if err != nil { return nil, err } @@ -498,7 +508,7 @@ func (s *userServer) ProcessUserCommandGet(ctx context.Context, req *pbuser.Proc } func (s *userServer) ProcessUserCommandGetAll(ctx context.Context, req *pbuser.ProcessUserCommandGetAllReq) (*pbuser.ProcessUserCommandGetAllResp, error) { - err := authverify.CheckAccessV3(ctx, req.UserID) + err := authverify.CheckAccessV3(ctx, req.UserID, s.config) if err != nil { return nil, err } @@ -527,7 +537,7 @@ func (s *userServer) ProcessUserCommandGetAll(ctx context.Context, req *pbuser.P } func (s *userServer) AddNotificationAccount(ctx context.Context, req *pbuser.AddNotificationAccountReq) (*pbuser.AddNotificationAccountResp, error) { - if err := authverify.CheckIMAdmin(ctx); err != nil { + if err := authverify.CheckIMAdmin(ctx, s.config); err != nil { return nil, err } @@ -570,7 +580,7 @@ func (s *userServer) AddNotificationAccount(ctx context.Context, req *pbuser.Add } func (s *userServer) UpdateNotificationAccountInfo(ctx context.Context, req *pbuser.UpdateNotificationAccountInfoReq) (*pbuser.UpdateNotificationAccountInfoResp, error) { - if err := authverify.CheckIMAdmin(ctx); err != nil { + if err := authverify.CheckIMAdmin(ctx, s.config); err != nil { return nil, err } @@ -597,7 +607,7 @@ func (s *userServer) UpdateNotificationAccountInfo(ctx context.Context, req *pbu func (s *userServer) SearchNotificationAccount(ctx context.Context, req *pbuser.SearchNotificationAccountReq) (*pbuser.SearchNotificationAccountResp, error) { // Check if user is an admin - if err := authverify.CheckIMAdmin(ctx); err != nil { + if err := authverify.CheckIMAdmin(ctx, s.config); err != nil { return nil, err } @@ -671,7 +681,7 @@ func (s *userServer) userModelToResp(users []*relation.UserModel, pagination pag accounts := make([]*pbuser.NotificationAccountInfo, 0) var total int64 for _, v := range users { - if v.AppMangerLevel == constant.AppNotificationAdmin && !utils.IsContain(v.UserID, config.Config.IMAdmin.UserID) { + if v.AppMangerLevel == constant.AppNotificationAdmin && !utils.IsContain(v.UserID, s.config.IMAdmin.UserID) { temp := &pbuser.NotificationAccountInfo{ UserID: v.UserID, FaceURL: v.FaceURL, diff --git a/internal/tools/cron_task.go b/internal/tools/cron_task.go index 9b74a5767b..ce87e9b900 100644 --- a/internal/tools/cron_task.go +++ b/internal/tools/cron_task.go @@ -23,37 +23,38 @@ import ( "time" "github.com/OpenIMSDK/tools/errs" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" "github.com/redis/go-redis/v9" "github.com/robfig/cron/v3" + + "github.com/openimsdk/open-im-server/v3/pkg/common/config" + "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" ) -func StartTask() error { - fmt.Println("Cron task start, config:", config.Config.ChatRecordsClearTime) +func StartTask(config *config.GlobalConfig) error { + fmt.Println("cron task start, config", config.ChatRecordsClearTime) - msgTool, err := InitMsgTool() + msgTool, err := InitMsgTool(config) if err != nil { return err } msgTool.convertTools() - rdb, err := cache.NewRedis() + rdb, err := cache.NewRedis(config) if err != nil { return err } // register cron tasks var crontab = cron.New() - fmt.Printf("Start chatRecordsClearTime cron task, cron config: %s\n", config.Config.ChatRecordsClearTime) - _, err = crontab.AddFunc(config.Config.ChatRecordsClearTime, cronWrapFunc(rdb, "cron_clear_msg_and_fix_seq", msgTool.AllConversationClearMsgAndFixSeq)) + fmt.Printf("Start chatRecordsClearTime cron task, cron config: %s\n", config.ChatRecordsClearTime) + _, err = crontab.AddFunc(config.ChatRecordsClearTime, cronWrapFunc(config,rdb, "cron_clear_msg_and_fix_seq", msgTool.AllConversationClearMsgAndFixSeq)) if err != nil { return errs.Wrap(err) } - fmt.Printf("Start msgDestruct cron task, cron config: %s\n", config.Config.MsgDestructTime) - _, err = crontab.AddFunc(config.Config.MsgDestructTime, cronWrapFunc(rdb, "cron_conversations_destruct_msgs", msgTool.ConversationsDestructMsgs)) + fmt.Printf("Start msgDestruct cron task, cron config: %s\n", config.MsgDestructTime) + _, err = crontab.AddFunc(config.MsgDestructTime, cronWrapFunc(config,rdb, "cron_conversations_destruct_msgs", msgTool.ConversationsDestructMsgs)) if err != nil { return errs.Wrap(err, "cron_conversations_destruct_msgs") } @@ -91,8 +92,8 @@ func netlock(rdb redis.UniversalClient, key string, ttl time.Duration) bool { return ok } -func cronWrapFunc(rdb redis.UniversalClient, key string, fn func()) func() { - enableCronLocker := config.Config.EnableCronLocker +func cronWrapFunc(config *config.GlobalConfig, rdb redis.UniversalClient, key string, fn func()) func() { + enableCronLocker := config.EnableCronLocker return func() { // if don't enable cron-locker, call fn directly. if !enableCronLocker { diff --git a/internal/tools/cron_task_test.go b/internal/tools/cron_task_test.go index 28bc2c945b..fcae5a5f68 100644 --- a/internal/tools/cron_task_test.go +++ b/internal/tools/cron_task_test.go @@ -15,8 +15,12 @@ package tools import ( + "flag" "fmt" + "github.com/OpenIMSDK/tools/errs" + "gopkg.in/yaml.v3" "math/rand" + "os" "sync" "testing" "time" @@ -61,7 +65,7 @@ func TestCronWrapFunc(t *testing.T) { start := time.Now() key := fmt.Sprintf("cron-%v", rand.Int31()) crontab := cron.New(cron.WithSeconds()) - crontab.AddFunc("*/1 * * * * *", cronWrapFunc(rdb, key, cb)) + crontab.AddFunc("*/1 * * * * *", cronWrapFunc(config.NewGlobalConfig(), rdb, key, cb)) crontab.Start() <-done @@ -71,7 +75,11 @@ func TestCronWrapFunc(t *testing.T) { } func TestCronWrapFuncWithNetlock(t *testing.T) { - config.Config.EnableCronLocker = true + conf, err := initCfg() + if err != nil { + panic(err) + } + conf.EnableCronLocker = true rdb := redis.NewClient(&redis.Options{}) defer rdb.Close() @@ -80,10 +88,10 @@ func TestCronWrapFuncWithNetlock(t *testing.T) { crontab := cron.New(cron.WithSeconds()) key := fmt.Sprintf("cron-%v", rand.Int31()) - crontab.AddFunc("*/1 * * * * *", cronWrapFunc(rdb, key, func() { + crontab.AddFunc("*/1 * * * * *", cronWrapFunc(conf, rdb, key, func() { done <- "host1" })) - crontab.AddFunc("*/1 * * * * *", cronWrapFunc(rdb, key, func() { + crontab.AddFunc("*/1 * * * * *", cronWrapFunc(conf, rdb, key, func() { done <- "host2" })) crontab.Start() @@ -94,3 +102,22 @@ func TestCronWrapFuncWithNetlock(t *testing.T) { crontab.Stop() } + +func initCfg() (*config.GlobalConfig, error) { + const ( + defaultCfgPath = "../../../../../config/config.yaml" + ) + + cfgPath := flag.String("c", defaultCfgPath, "Path to the configuration file") + data, err := os.ReadFile(*cfgPath) + if err != nil { + return nil, errs.Wrap(err, "ReadFile unmarshal failed") + } + + conf := config.NewGlobalConfig() + err = yaml.Unmarshal(data, &conf) + if err != nil { + return nil, errs.Wrap(err, "InitConfig unmarshal failed") + } + return conf, nil +} diff --git a/internal/tools/msg.go b/internal/tools/msg.go index f2df0d3371..67c3895cb2 100644 --- a/internal/tools/msg.go +++ b/internal/tools/msg.go @@ -46,10 +46,12 @@ type MsgTool struct { userDatabase controller.UserDatabase groupDatabase controller.GroupDatabase msgNotificationSender *notification.MsgNotificationSender + Config *config.GlobalConfig } func NewMsgTool(msgDatabase controller.CommonMsgDatabase, userDatabase controller.UserDatabase, - groupDatabase controller.GroupDatabase, conversationDatabase controller.ConversationDatabase, msgNotificationSender *notification.MsgNotificationSender, + groupDatabase controller.GroupDatabase, conversationDatabase controller.ConversationDatabase, + msgNotificationSender *notification.MsgNotificationSender, config *config.GlobalConfig, ) *MsgTool { return &MsgTool{ msgDatabase: msgDatabase, @@ -57,32 +59,33 @@ func NewMsgTool(msgDatabase controller.CommonMsgDatabase, userDatabase controlle groupDatabase: groupDatabase, conversationDatabase: conversationDatabase, msgNotificationSender: msgNotificationSender, + Config: config, } } -func InitMsgTool() (*MsgTool, error) { - rdb, err := cache.NewRedis() +func InitMsgTool(config *config.GlobalConfig) (*MsgTool, error) { + rdb, err := cache.NewRedis(config) if err != nil { return nil, err } - mongo, err := unrelation.NewMongo() + mongo, err := unrelation.NewMongo(config) if err != nil { return nil, err } - discov, err := kdisc.NewDiscoveryRegister(config.Config.Envs.Discovery) + discov, err := kdisc.NewDiscoveryRegister(config) if err != nil { return nil, err } discov.AddOption(mw.GrpcClient(), grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithDefaultServiceConfig(fmt.Sprintf(`{"LoadBalancingPolicy": "%s"}`, "round_robin"))) - userDB, err := mgo.NewUserMongo(mongo.GetDatabase()) + userDB, err := mgo.NewUserMongo(mongo.GetDatabase(config.Mongo.Database)) if err != nil { return nil, err } - msgDatabase, err := controller.InitCommonMsgDatabase(rdb, mongo.GetDatabase()) + msgDatabase, err := controller.InitCommonMsgDatabase(rdb, mongo.GetDatabase(config.Mongo.Database), config) if err != nil { return nil, err } - userMongoDB := unrelation.NewUserMongoDriver(mongo.GetDatabase()) + userMongoDB := unrelation.NewUserMongoDriver(mongo.GetDatabase(config.Mongo.Database)) ctxTx := tx.NewMongo(mongo.GetClient()) userDatabase := controller.NewUserDatabase( userDB, @@ -90,19 +93,19 @@ func InitMsgTool() (*MsgTool, error) { ctxTx, userMongoDB, ) - groupDB, err := mgo.NewGroupMongo(mongo.GetDatabase()) + groupDB, err := mgo.NewGroupMongo(mongo.GetDatabase(config.Mongo.Database)) if err != nil { return nil, err } - groupMemberDB, err := mgo.NewGroupMember(mongo.GetDatabase()) + groupMemberDB, err := mgo.NewGroupMember(mongo.GetDatabase(config.Mongo.Database)) if err != nil { return nil, err } - groupRequestDB, err := mgo.NewGroupRequestMgo(mongo.GetDatabase()) + groupRequestDB, err := mgo.NewGroupRequestMgo(mongo.GetDatabase(config.Mongo.Database)) if err != nil { return nil, err } - conversationDB, err := mgo.NewConversationMongo(mongo.GetDatabase()) + conversationDB, err := mgo.NewConversationMongo(mongo.GetDatabase(config.Mongo.Database)) if err != nil { return nil, err } @@ -112,9 +115,9 @@ func InitMsgTool() (*MsgTool, error) { cache.NewConversationRedis(rdb, cache.GetDefaultOpt(), conversationDB), ctxTx, ) - msgRpcClient := rpcclient.NewMessageRpcClient(discov) - msgNotificationSender := notification.NewMsgNotificationSender(rpcclient.WithRpcClient(&msgRpcClient)) - msgTool := NewMsgTool(msgDatabase, userDatabase, groupDatabase, conversationDatabase, msgNotificationSender) + msgRpcClient := rpcclient.NewMessageRpcClient(discov, config) + msgNotificationSender := notification.NewMsgNotificationSender(config, rpcclient.WithRpcClient(&msgRpcClient)) + msgTool := NewMsgTool(msgDatabase, userDatabase, groupDatabase, conversationDatabase, msgNotificationSender, config) return msgTool, nil } @@ -176,8 +179,8 @@ func (c *MsgTool) AllConversationClearMsgAndFixSeq() { func (c *MsgTool) ClearConversationsMsg(ctx context.Context, conversationIDs []string) { for _, conversationID := range conversationIDs { - if err := c.msgDatabase.DeleteConversationMsgsAndSetMinSeq(ctx, conversationID, int64(config.Config.RetainChatRecords*24*60*60)); err != nil { - log.ZError(ctx, "DeleteUserSuperGroupMsgsAndSetMinSeq failed", err, "conversationID", conversationID, "DBRetainChatRecords", config.Config.RetainChatRecords) + if err := c.msgDatabase.DeleteConversationMsgsAndSetMinSeq(ctx, conversationID, int64(c.Config.RetainChatRecords*24*60*60)); err != nil { + log.ZError(ctx, "DeleteUserSuperGroupMsgsAndSetMinSeq failed", err, "conversationID", conversationID, "DBRetainChatRecords", c.Config.RetainChatRecords) } if err := c.checkMaxSeq(ctx, conversationID); err != nil { log.ZError(ctx, "fixSeq failed", err, "conversationID", conversationID) diff --git a/pkg/authverify/token.go b/pkg/authverify/token.go index 0a46af3ecf..26c43532d1 100644 --- a/pkg/authverify/token.go +++ b/pkg/authverify/token.go @@ -26,61 +26,60 @@ import ( "github.com/openimsdk/open-im-server/v3/pkg/common/config" ) -func Secret() jwt.Keyfunc { +func Secret(secret string) jwt.Keyfunc { return func(token *jwt.Token) (any, error) { - return []byte(config.Config.Secret), nil + return []byte(secret), nil } } -func CheckAccessV3(ctx context.Context, ownerUserID string) (err error) { +func CheckAccessV3(ctx context.Context, ownerUserID string, config *config.GlobalConfig) (err error) { opUserID := mcontext.GetOpUserID(ctx) - if len(config.Config.Manager.UserID) > 0 && utils.IsContain(opUserID, config.Config.Manager.UserID) { + if len(config.Manager.UserID) > 0 && utils.IsContain(opUserID, config.Manager.UserID) { return nil } - if utils.IsContain(opUserID, config.Config.IMAdmin.UserID) { + if utils.IsContain(opUserID, config.IMAdmin.UserID) { return nil } if opUserID == ownerUserID { return nil } - return errs.Wrap(errs.ErrNoPermission, "CheckAccessV3: no permission for user "+opUserID) + return errs.ErrNoPermission.Wrap("ownerUserID", ownerUserID) } -func IsAppManagerUid(ctx context.Context) bool { - return (len(config.Config.Manager.UserID) > 0 && utils.IsContain(mcontext.GetOpUserID(ctx), config.Config.Manager.UserID)) || - utils.IsContain(mcontext.GetOpUserID(ctx), config.Config.IMAdmin.UserID) +func IsAppManagerUid(ctx context.Context, config *config.GlobalConfig) bool { + return (len(config.Manager.UserID) > 0 && utils.IsContain(mcontext.GetOpUserID(ctx), config.Manager.UserID)) || + utils.IsContain(mcontext.GetOpUserID(ctx), config.IMAdmin.UserID) } -func CheckAdmin(ctx context.Context) error { - if len(config.Config.Manager.UserID) > 0 && utils.IsContain(mcontext.GetOpUserID(ctx), config.Config.Manager.UserID) { +func CheckAdmin(ctx context.Context, config *config.GlobalConfig) error { + if len(config.Manager.UserID) > 0 && utils.IsContain(mcontext.GetOpUserID(ctx), config.Manager.UserID) { return nil } - if utils.IsContain(mcontext.GetOpUserID(ctx), config.Config.IMAdmin.UserID) { + if utils.IsContain(mcontext.GetOpUserID(ctx), config.IMAdmin.UserID) { return nil } return errs.ErrNoPermission.Wrap(fmt.Sprintf("user %s is not admin userID", mcontext.GetOpUserID(ctx))) } - -func CheckIMAdmin(ctx context.Context) error { - if utils.IsContain(mcontext.GetOpUserID(ctx), config.Config.IMAdmin.UserID) { +func CheckIMAdmin(ctx context.Context, config *config.GlobalConfig) error { + if utils.IsContain(mcontext.GetOpUserID(ctx), config.IMAdmin.UserID) { return nil } - if len(config.Config.Manager.UserID) > 0 && utils.IsContain(mcontext.GetOpUserID(ctx), config.Config.Manager.UserID) { + if len(config.Manager.UserID) > 0 && utils.IsContain(mcontext.GetOpUserID(ctx), config.Manager.UserID) { return nil } return errs.ErrNoPermission.Wrap(fmt.Sprintf("user %s is not CheckIMAdmin userID", mcontext.GetOpUserID(ctx))) } -func ParseRedisInterfaceToken(redisToken any) (*tokenverify.Claims, error) { - return tokenverify.GetClaimFromToken(string(redisToken.([]uint8)), Secret()) +func ParseRedisInterfaceToken(redisToken any, secret string) (*tokenverify.Claims, error) { + return tokenverify.GetClaimFromToken(string(redisToken.([]uint8)), Secret(secret)) } -func IsManagerUserID(opUserID string) bool { - return (len(config.Config.Manager.UserID) > 0 && utils.IsContain(opUserID, config.Config.Manager.UserID)) || utils.IsContain(opUserID, config.Config.IMAdmin.UserID) +func IsManagerUserID(opUserID string, config *config.GlobalConfig) bool { + return (len(config.Manager.UserID) > 0 && utils.IsContain(opUserID, config.Manager.UserID)) || utils.IsContain(opUserID, config.IMAdmin.UserID) } -func WsVerifyToken(token, userID string, platformID int) error { - claim, err := tokenverify.GetClaimFromToken(token, Secret()) +func WsVerifyToken(token, userID, secret string, platformID int) error { + claim, err := tokenverify.GetClaimFromToken(token, Secret(secret)) if err != nil { return err } diff --git a/pkg/common/cmd/api.go b/pkg/common/cmd/api.go index 47e4116e39..859508ce3e 100644 --- a/pkg/common/cmd/api.go +++ b/pkg/common/cmd/api.go @@ -15,54 +15,44 @@ package cmd import ( - "errors" - "fmt" - "github.com/OpenIMSDK/protocol/constant" - config2 "github.com/openimsdk/open-im-server/v3/pkg/common/config" + "github.com/openimsdk/open-im-server/v3/internal/api" "github.com/spf13/cobra" + + "github.com/openimsdk/open-im-server/v3/pkg/common/config" ) type ApiCmd struct { *RootCmd + initFunc func(config *config.GlobalConfig, port int, promPort int) error } func NewApiCmd() *ApiCmd { - ret := &ApiCmd{NewRootCmd("api")} + ret := &ApiCmd{RootCmd: NewRootCmd("api"), initFunc: api.Start} ret.SetRootCmdPt(ret) - + ret.addPreRun() + ret.addRunE() return ret } -// AddApi configures the API command to run with specified ports for the API and Prometheus monitoring. -// It ensures error handling for port retrieval and only proceeds if both port numbers are successfully obtained. -func (a *ApiCmd) AddApi(f func(port int, promPort int) error) { - a.Command.RunE = func(cmd *cobra.Command, args []string) error { - port, err := a.getPortFlag(cmd) - if err != nil { - return err - } - - promPort, err := a.getPrometheusPortFlag(cmd) - if err != nil { - return err - } +func (a *ApiCmd) addPreRun() { + a.Command.PreRun = func(cmd *cobra.Command, args []string) { + a.port = a.getPortFlag(cmd) + a.prometheusPort = a.getPrometheusPortFlag(cmd) + } +} - return f(port, promPort) +func (a *ApiCmd) addRunE() { + a.Command.RunE = func(cmd *cobra.Command, args []string) error { + return a.initFunc(a.config, a.port, a.prometheusPort) } } -func (a *ApiCmd) GetPortFromConfig(portType string) (int, error) { +func (a *ApiCmd) GetPortFromConfig(portType string) int { if portType == constant.FlagPort { - if len(config2.Config.Api.OpenImApiPort) > 0 { - return config2.Config.Api.OpenImApiPort[0], nil - } - return 0, errors.New("API port configuration is empty or missing") + return a.config.Api.OpenImApiPort[0] } else if portType == constant.FlagPrometheusPort { - if len(config2.Config.Prometheus.ApiPrometheusPort) > 0 { - return config2.Config.Prometheus.ApiPrometheusPort[0], nil - } - return 0, errors.New("Prometheus port configuration is empty or missing") + return a.config.Prometheus.ApiPrometheusPort[0] } - return 0, fmt.Errorf("unknown port type: %s", portType) + return 0 } diff --git a/pkg/common/cmd/cron_task.go b/pkg/common/cmd/cron_task.go index fa7a46351d..d8c9dd2a8b 100644 --- a/pkg/common/cmd/cron_task.go +++ b/pkg/common/cmd/cron_task.go @@ -14,29 +14,35 @@ package cmd -import "github.com/spf13/cobra" +import ( + "github.com/openimsdk/open-im-server/v3/internal/tools" + "github.com/openimsdk/open-im-server/v3/pkg/common/config" + "github.com/spf13/cobra" +) type CronTaskCmd struct { *RootCmd + initFunc func(config *config.GlobalConfig) error } func NewCronTaskCmd() *CronTaskCmd { - ret := &CronTaskCmd{NewRootCmd("cronTask", WithCronTaskLogName())} + ret := &CronTaskCmd{RootCmd: NewRootCmd("cronTask", WithCronTaskLogName()), + initFunc: tools.StartTask} + ret.addRunE() ret.SetRootCmdPt(ret) return ret } -func (c *CronTaskCmd) addRunE(f func() error) { +func (c *CronTaskCmd) addRunE() { c.Command.RunE = func(cmd *cobra.Command, args []string) error { - return f() + return c.initFunc(c.config) } } -func (c *CronTaskCmd) Exec(f func() error) error { - c.addRunE(f) +func (c *CronTaskCmd) Exec() error { return c.Execute() } -func (c *CronTaskCmd) GetPortFromConfig(portType string) (int, error) { - return 0, nil +func (c *CronTaskCmd) GetPortFromConfig(portType string) int { + return 0 } diff --git a/pkg/common/cmd/msg_gateway.go b/pkg/common/cmd/msg_gateway.go index 403d0ec84d..3a939fa972 100644 --- a/pkg/common/cmd/msg_gateway.go +++ b/pkg/common/cmd/msg_gateway.go @@ -15,13 +15,13 @@ package cmd import ( - "errors" + "log" + + "github.com/spf13/cobra" "github.com/OpenIMSDK/protocol/constant" - "github.com/OpenIMSDK/tools/errs" + "github.com/openimsdk/open-im-server/v3/internal/msggateway" - v3config "github.com/openimsdk/open-im-server/v3/pkg/common/config" - "github.com/spf13/cobra" ) type MsgGatewayCmd struct { @@ -30,6 +30,7 @@ type MsgGatewayCmd struct { func NewMsgGatewayCmd() *MsgGatewayCmd { ret := &MsgGatewayCmd{NewRootCmd("msgGateway")} + ret.addRunE() ret.SetRootCmdPt(ret) return ret } @@ -38,67 +39,39 @@ func (m *MsgGatewayCmd) AddWsPortFlag() { m.Command.Flags().IntP(constant.FlagWsPort, "w", 0, "ws server listen port") } -func (m *MsgGatewayCmd) getWsPortFlag(cmd *cobra.Command) (int, error) { +func (m *MsgGatewayCmd) getWsPortFlag(cmd *cobra.Command) int { port, err := cmd.Flags().GetInt(constant.FlagWsPort) if err != nil { - return 0, errs.Wrap(err, "error getting ws port flag") + log.Println("Error getting ws port flag:", err) } if port == 0 { - port, _ = m.PortFromConfig(constant.FlagWsPort) + port = m.PortFromConfig(constant.FlagWsPort) } - return port, nil + return port } func (m *MsgGatewayCmd) addRunE() { m.Command.RunE = func(cmd *cobra.Command, args []string) error { - wsPort, err := m.getWsPortFlag(cmd) - if err != nil { - return errs.Wrap(err, "failed to get WS port flag") - } - port, err := m.getPortFlag(cmd) - if err != nil { - return err - } - prometheusPort, err := m.getPrometheusPortFlag(cmd) - if err != nil { - return err - } - return msggateway.RunWsAndServer(port, wsPort, prometheusPort) + return msggateway.RunWsAndServer(m.config, m.getPortFlag(cmd), m.getWsPortFlag(cmd), m.getPrometheusPortFlag(cmd)) } } func (m *MsgGatewayCmd) Exec() error { - m.addRunE() return m.Execute() } -func (m *MsgGatewayCmd) GetPortFromConfig(portType string) (int, error) { - var port int - var exists bool - +func (m *MsgGatewayCmd) GetPortFromConfig(portType string) int { switch portType { case constant.FlagWsPort: - if len(v3config.Config.LongConnSvr.OpenImWsPort) > 0 { - port = v3config.Config.LongConnSvr.OpenImWsPort[0] - exists = true - } + return m.config.LongConnSvr.OpenImWsPort[0] case constant.FlagPort: - if len(v3config.Config.LongConnSvr.OpenImMessageGatewayPort) > 0 { - port = v3config.Config.LongConnSvr.OpenImMessageGatewayPort[0] - exists = true - } + return m.config.LongConnSvr.OpenImMessageGatewayPort[0] case constant.FlagPrometheusPort: - if len(v3config.Config.Prometheus.MessageGatewayPrometheusPort) > 0 { - port = v3config.Config.Prometheus.MessageGatewayPrometheusPort[0] - exists = true - } - } + return m.config.Prometheus.MessageGatewayPrometheusPort[0] - if !exists { - return 0, errs.Wrap(errors.New("port type '%s' not found in configuration"), portType) + default: + return 0 } - - return port, nil } diff --git a/pkg/common/cmd/msg_gateway_test.go b/pkg/common/cmd/msg_gateway_test.go index 106ad74ecd..c0ea2b057c 100644 --- a/pkg/common/cmd/msg_gateway_test.go +++ b/pkg/common/cmd/msg_gateway_test.go @@ -44,7 +44,7 @@ func TestMsgGatewayCmd_GetPortFromConfig(t *testing.T) { } for _, tt := range tests { t.Run(tt.portType, func(t *testing.T) { - got, _ := msgGatewayCmd.GetPortFromConfig(tt.portType) + got := msgGatewayCmd.GetPortFromConfig(tt.portType) assert.Equal(t, tt.want, got) }) } diff --git a/pkg/common/cmd/msg_transfer.go b/pkg/common/cmd/msg_transfer.go index 4db24fac54..e46b66b52d 100644 --- a/pkg/common/cmd/msg_transfer.go +++ b/pkg/common/cmd/msg_transfer.go @@ -16,11 +16,10 @@ package cmd import ( "fmt" - "github.com/OpenIMSDK/protocol/constant" - "github.com/openimsdk/open-im-server/v3/internal/msgtransfer" - config2 "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/spf13/cobra" + + "github.com/openimsdk/open-im-server/v3/internal/msgtransfer" ) type MsgTransferCmd struct { @@ -29,37 +28,29 @@ type MsgTransferCmd struct { func NewMsgTransferCmd() *MsgTransferCmd { ret := &MsgTransferCmd{NewRootCmd("msgTransfer")} + ret.addRunE() ret.SetRootCmdPt(ret) return ret } func (m *MsgTransferCmd) addRunE() { m.Command.RunE = func(cmd *cobra.Command, args []string) error { - prometheusPort, err := m.getPrometheusPortFlag(cmd) - if err != nil { - return err - } - return msgtransfer.StartTransfer(prometheusPort) + return msgtransfer.StartTransfer(m.config, m.getPrometheusPortFlag(cmd)) } } func (m *MsgTransferCmd) Exec() error { - m.addRunE() return m.Execute() } -func (m *MsgTransferCmd) GetPortFromConfig(portType string) (int, error) { +func (m *MsgTransferCmd) GetPortFromConfig(portType string) int { if portType == constant.FlagPort { - return 0, nil + return 0 } else if portType == constant.FlagPrometheusPort { n := m.getTransferProgressFlagValue() - - if n < len(config2.Config.Prometheus.MessageTransferPrometheusPort) { - return config2.Config.Prometheus.MessageTransferPrometheusPort[n], nil - } - return 0, fmt.Errorf("index out of range for MessageTransferPrometheusPort with index %d", n) + return m.config.Prometheus.MessageTransferPrometheusPort[n] } - return 0, fmt.Errorf("unknown port type: %s", portType) + return 0 } func (m *MsgTransferCmd) AddTransferProgressFlag() { @@ -67,10 +58,10 @@ func (m *MsgTransferCmd) AddTransferProgressFlag() { } func (m *MsgTransferCmd) getTransferProgressFlagValue() int { - nindex, err := m.Command.Flags().GetInt(constant.FlagTransferProgressIndex) + nIndex, err := m.Command.Flags().GetInt(constant.FlagTransferProgressIndex) if err != nil { - fmt.Println("get transfercmd error,make sure it is k8s env or not") + fmt.Println("get transfer cmd error,make sure it is k8s env or not") return 0 } - return nindex + return nIndex } diff --git a/pkg/common/cmd/msg_utils.go b/pkg/common/cmd/msg_utils.go index 03c1cab670..df15acd87f 100644 --- a/pkg/common/cmd/msg_utils.go +++ b/pkg/common/cmd/msg_utils.go @@ -22,6 +22,7 @@ import ( type MsgUtilsCmd struct { cobra.Command + MsgTool *tools.MsgTool } func (m *MsgUtilsCmd) AddUserIDFlag() { @@ -135,7 +136,7 @@ func NewSeqCmd() *SeqCmd { func (s *SeqCmd) GetSeqCmd() *cobra.Command { s.Command.Run = func(cmdLines *cobra.Command, args []string) { - _, err := tools.InitMsgTool() + _, err := tools.InitMsgTool(s.MsgTool.Config) if err != nil { util.ExitWithError(err) } diff --git a/pkg/common/cmd/root.go b/pkg/common/cmd/root.go index 591bfc8049..478942a5bb 100644 --- a/pkg/common/cmd/root.go +++ b/pkg/common/cmd/root.go @@ -26,7 +26,7 @@ import ( ) type RootCmdPt interface { - GetPortFromConfig(portType string) (int, error) + GetPortFromConfig(portType string) int } type RootCmd struct { @@ -35,6 +35,11 @@ type RootCmd struct { port int prometheusPort int cmdItf RootCmdPt + config *config.GlobalConfig +} + +func (rc *RootCmd) Port() int { + return rc.port } type CmdOpts struct { @@ -54,7 +59,7 @@ func WithLogName(logName string) func(*CmdOpts) { } func NewRootCmd(name string, opts ...func(*CmdOpts)) *RootCmd { - rootCmd := &RootCmd{Name: name} + rootCmd := &RootCmd{Name: name, config: config.NewGlobalConfig()} cmd := cobra.Command{ Use: "Start openIM application", Short: fmt.Sprintf(`Start %s `, name), @@ -96,7 +101,7 @@ func (rc *RootCmd) applyOptions(opts ...func(*CmdOpts)) *CmdOpts { } func (rc *RootCmd) initializeLogger(cmdOpts *CmdOpts) error { - logConfig := config.Config.Log + logConfig := rc.config.Log return log.InitFromConfig( @@ -129,41 +134,36 @@ func (r *RootCmd) AddPortFlag() { r.Command.Flags().IntP(constant.FlagPort, "p", 0, "server listen port") } -func (r *RootCmd) getPortFlag(cmd *cobra.Command) (int, error) { +func (r *RootCmd) getPortFlag(cmd *cobra.Command) int { port, err := cmd.Flags().GetInt(constant.FlagPort) if err != nil { // Wrapping the error with additional context - return 0, errs.Wrap(err, "error getting port flag") + return 0 } if port == 0 { - port, _ = r.PortFromConfig(constant.FlagPort) - // port, err := r.PortFromConfig(constant.FlagPort) - // if err != nil { - // // Optionally wrap the error if it's an internal error needing context - // return 0, errs.Wrap(err, "error getting port from config") - // } + port = r.PortFromConfig(constant.FlagPort) } - return port, nil + return port } // // GetPortFlag returns the port flag. -func (r *RootCmd) GetPortFlag() (int, error) { - return r.port, nil +func (r *RootCmd) GetPortFlag() int { + return r.port } func (r *RootCmd) AddPrometheusPortFlag() { r.Command.Flags().IntP(constant.FlagPrometheusPort, "", 0, "server prometheus listen port") } -func (r *RootCmd) getPrometheusPortFlag(cmd *cobra.Command) (int, error) { +func (r *RootCmd) getPrometheusPortFlag(cmd *cobra.Command) int { port, err := cmd.Flags().GetInt(constant.FlagPrometheusPort) if err != nil || port == 0 { - port, err = r.PortFromConfig(constant.FlagPrometheusPort) + port = r.PortFromConfig(constant.FlagPrometheusPort) if err != nil { - return 0, err + return 0 } } - return port, nil + return port } func (r *RootCmd) GetPrometheusPortFlag() int { @@ -173,7 +173,7 @@ func (r *RootCmd) GetPrometheusPortFlag() int { func (r *RootCmd) getConfFromCmdAndInit(cmdLines *cobra.Command) error { configFolderPath, _ := cmdLines.Flags().GetString(constant.FlagConf) fmt.Println("The directory of the configuration file to start the process:", configFolderPath) - return config2.InitConfig(configFolderPath) + return config2.InitConfig(r.config, configFolderPath) } func (r *RootCmd) Execute() error { @@ -184,11 +184,8 @@ func (r *RootCmd) AddCommand(cmds ...*cobra.Command) { r.Command.AddCommand(cmds...) } -func (r *RootCmd) PortFromConfig(portType string) (int, error) { +func (r *RootCmd) PortFromConfig(portType string) int { // Retrieve the port and cache it - port, err := r.cmdItf.GetPortFromConfig(portType) - if err != nil { - return 0, err - } - return port, nil + port := r.cmdItf.GetPortFromConfig(portType) + return port } diff --git a/pkg/common/cmd/rpc.go b/pkg/common/cmd/rpc.go index e30de93a99..5199524e7b 100644 --- a/pkg/common/cmd/rpc.go +++ b/pkg/common/cmd/rpc.go @@ -16,100 +16,144 @@ package cmd import ( "errors" - "fmt" + "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/protocol/constant" - "github.com/OpenIMSDK/tools/discoveryregistry" - "github.com/OpenIMSDK/tools/errs" - config2 "github.com/openimsdk/open-im-server/v3/pkg/common/config" - "github.com/openimsdk/open-im-server/v3/pkg/common/startrpc" "github.com/spf13/cobra" "google.golang.org/grpc" + + config2 "github.com/openimsdk/open-im-server/v3/pkg/common/config" + + "github.com/OpenIMSDK/tools/discoveryregistry" + + "github.com/openimsdk/open-im-server/v3/pkg/common/startrpc" ) +type rpcInitFuc func(config *config2.GlobalConfig, disCov discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) error + type RpcCmd struct { *RootCmd + RpcRegisterName string + initFunc rpcInitFuc } -func NewRpcCmd(name string) *RpcCmd { - ret := &RpcCmd{NewRootCmd(name)} +func NewRpcCmd(name string, initFunc rpcInitFuc) *RpcCmd { + ret := &RpcCmd{RootCmd: NewRootCmd(name), initFunc: initFunc} + ret.addPreRun() + ret.addRunE() ret.SetRootCmdPt(ret) return ret } -func (a *RpcCmd) Exec() error { - a.Command.RunE = func(cmd *cobra.Command, args []string) error { - portFlag, err := a.getPortFlag(cmd) - if err != nil { - return err - } - a.port = portFlag +func (a *RpcCmd) addPreRun() { + a.Command.PreRun = func(cmd *cobra.Command, args []string) { + a.port = a.getPortFlag(cmd) + a.prometheusPort = a.getPrometheusPortFlag(cmd) + } +} - prometheusPort, err := a.getPrometheusPortFlag(cmd) +func (a *RpcCmd) addRunE() { + a.Command.RunE = func(cmd *cobra.Command, args []string) error { + rpcRegisterName, err := a.GetRpcRegisterNameFromConfig() if err != nil { return err + } else { + return a.StartSvr(rpcRegisterName, a.initFunc) } - a.prometheusPort = prometheusPort - - return nil } - return a.Execute() } -func (a *RpcCmd) StartSvr(name string, rpcFn func(discov discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) error) error { - portFlag, err := a.GetPortFlag() - if err != nil { - return err - } else { - a.port = portFlag - } - - return startrpc.Start(portFlag, name, a.GetPrometheusPortFlag(), rpcFn) +func (a *RpcCmd) Exec() error { + return a.Execute() } -func (a *RpcCmd) GetPortFromConfig(portType string) (int, error) { - portConfigMap := map[string]map[string]int{ - RpcPushServer: { - constant.FlagPort: config2.Config.RpcPort.OpenImPushPort[0], - constant.FlagPrometheusPort: config2.Config.Prometheus.PushPrometheusPort[0], - }, - RpcAuthServer: { - constant.FlagPort: config2.Config.RpcPort.OpenImAuthPort[0], - constant.FlagPrometheusPort: config2.Config.Prometheus.AuthPrometheusPort[0], - }, - RpcConversationServer: { - constant.FlagPort: config2.Config.RpcPort.OpenImConversationPort[0], - constant.FlagPrometheusPort: config2.Config.Prometheus.ConversationPrometheusPort[0], - }, - RpcFriendServer: { - constant.FlagPort: config2.Config.RpcPort.OpenImFriendPort[0], - constant.FlagPrometheusPort: config2.Config.Prometheus.FriendPrometheusPort[0], - }, - RpcGroupServer: { - constant.FlagPort: config2.Config.RpcPort.OpenImGroupPort[0], - constant.FlagPrometheusPort: config2.Config.Prometheus.GroupPrometheusPort[0], - }, - RpcMsgServer: { - constant.FlagPort: config2.Config.RpcPort.OpenImMessagePort[0], - constant.FlagPrometheusPort: config2.Config.Prometheus.MessagePrometheusPort[0], - }, - RpcThirdServer: { - constant.FlagPort: config2.Config.RpcPort.OpenImThirdPort[0], - constant.FlagPrometheusPort: config2.Config.Prometheus.ThirdPrometheusPort[0], - }, - RpcUserServer: { - constant.FlagPort: config2.Config.RpcPort.OpenImUserPort[0], - constant.FlagPrometheusPort: config2.Config.Prometheus.UserPrometheusPort[0], - }, +func (a *RpcCmd) StartSvr(name string, rpcFn func(config *config2.GlobalConfig, disCov discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) error) error { + if a.GetPortFlag() == 0 { + return errs.Wrap(errors.New("port is required")) } + return startrpc.Start(a.GetPortFlag(), name, a.GetPrometheusPortFlag(), a.config, rpcFn) +} - if portMap, ok := portConfigMap[a.Name]; ok { - if port, ok := portMap[portType]; ok { - return port, nil - } else { - return 0, errs.Wrap(errors.New("port type not found"), fmt.Sprintf("Failed to get port for %s", a.Name)) +func (a *RpcCmd) GetPortFromConfig(portType string) int { + switch a.Name { + case RpcPushServer: + if portType == constant.FlagPort { + return a.config.RpcPort.OpenImPushPort[0] + } + if portType == constant.FlagPrometheusPort { + return a.config.Prometheus.PushPrometheusPort[0] + } + case RpcAuthServer: + if portType == constant.FlagPort { + return a.config.RpcPort.OpenImAuthPort[0] + } + if portType == constant.FlagPrometheusPort { + return a.config.Prometheus.AuthPrometheusPort[0] + } + case RpcConversationServer: + if portType == constant.FlagPort { + return a.config.RpcPort.OpenImConversationPort[0] + } + if portType == constant.FlagPrometheusPort { + return a.config.Prometheus.ConversationPrometheusPort[0] + } + case RpcFriendServer: + if portType == constant.FlagPort { + return a.config.RpcPort.OpenImFriendPort[0] + } + if portType == constant.FlagPrometheusPort { + return a.config.Prometheus.FriendPrometheusPort[0] + } + case RpcGroupServer: + if portType == constant.FlagPort { + return a.config.RpcPort.OpenImGroupPort[0] + } + if portType == constant.FlagPrometheusPort { + return a.config.Prometheus.GroupPrometheusPort[0] + } + case RpcMsgServer: + if portType == constant.FlagPort { + return a.config.RpcPort.OpenImMessagePort[0] + } + if portType == constant.FlagPrometheusPort { + return a.config.Prometheus.MessagePrometheusPort[0] + } + case RpcThirdServer: + if portType == constant.FlagPort { + return a.config.RpcPort.OpenImThirdPort[0] + } + if portType == constant.FlagPrometheusPort { + return a.config.Prometheus.ThirdPrometheusPort[0] + } + case RpcUserServer: + if portType == constant.FlagPort { + return a.config.RpcPort.OpenImUserPort[0] + } + if portType == constant.FlagPrometheusPort { + return a.config.Prometheus.UserPrometheusPort[0] } } + return 0 +} - return 0, errs.Wrap(fmt.Errorf("server name '%s' not found", a.Name), "Failed to get port configuration") +func (a *RpcCmd) GetRpcRegisterNameFromConfig() (string, error) { + switch a.Name { + case RpcPushServer: + return a.config.RpcRegisterName.OpenImPushName, nil + case RpcAuthServer: + return a.config.RpcRegisterName.OpenImAuthName, nil + case RpcConversationServer: + return a.config.RpcRegisterName.OpenImConversationName, nil + case RpcFriendServer: + return a.config.RpcRegisterName.OpenImFriendName, nil + case RpcGroupServer: + return a.config.RpcRegisterName.OpenImGroupName, nil + case RpcMsgServer: + return a.config.RpcRegisterName.OpenImMsgName, nil + case RpcThirdServer: + return a.config.RpcRegisterName.OpenImThirdName, nil + case RpcUserServer: + return a.config.RpcRegisterName.OpenImUserName, nil + } + return "", errs.Wrap(errors.New("can not get rpc register name"), a.Name) } diff --git a/pkg/common/config/config.go b/pkg/common/config/config.go index 7ee55d876b..ac42395bf1 100644 --- a/pkg/common/config/config.go +++ b/pkg/common/config/config.go @@ -21,7 +21,7 @@ import ( "gopkg.in/yaml.v3" ) -var Config configStruct +var Config GlobalConfig const ConfKey = "conf" @@ -57,7 +57,7 @@ type MYSQL struct { SlowThreshold int `yaml:"slowThreshold"` } -type configStruct struct { +type GlobalConfig struct { Envs struct { Discovery string `yaml:"discovery"` } @@ -339,6 +339,10 @@ type configStruct struct { Notification notification `yaml:"notification"` } +func NewGlobalConfig() *GlobalConfig { + return &GlobalConfig{} +} + type notification struct { GroupCreated NotificationConf `yaml:"groupCreated"` GroupInfoSet NotificationConf `yaml:"groupInfoSet"` @@ -378,7 +382,7 @@ type notification struct { ConversationSetPrivate NotificationConf `yaml:"conversationSetPrivate"` } -func (c *configStruct) GetServiceNames() []string { +func (c *GlobalConfig) GetServiceNames() []string { return []string{ c.RpcRegisterName.OpenImUserName, c.RpcRegisterName.OpenImFriendName, @@ -392,7 +396,7 @@ func (c *configStruct) GetServiceNames() []string { } } -func (c *configStruct) RegisterConf2Registry(registry discoveryregistry.SvcDiscoveryRegistry) error { +func (c *GlobalConfig) RegisterConf2Registry(registry discoveryregistry.SvcDiscoveryRegistry) error { data, err := yaml.Marshal(c) if err != nil { return err @@ -400,11 +404,11 @@ func (c *configStruct) RegisterConf2Registry(registry discoveryregistry.SvcDisco return registry.RegisterConf2Registry(ConfKey, data) } -func (c *configStruct) GetConfFromRegistry(registry discoveryregistry.SvcDiscoveryRegistry) ([]byte, error) { +func (c *GlobalConfig) GetConfFromRegistry(registry discoveryregistry.SvcDiscoveryRegistry) ([]byte, error) { return registry.GetConfFromRegistry(ConfKey) } -func (c *configStruct) EncodeConfig() []byte { +func (c *GlobalConfig) EncodeConfig() []byte { buf := bytes.NewBuffer(nil) if err := yaml.NewEncoder(buf).Encode(c); err != nil { panic(err) diff --git a/pkg/common/config/parse.go b/pkg/common/config/parse.go index a73665386a..bfbf6daf7b 100644 --- a/pkg/common/config/parse.go +++ b/pkg/common/config/parse.go @@ -21,10 +21,10 @@ import ( "path/filepath" "github.com/OpenIMSDK/protocol/constant" - "github.com/OpenIMSDK/tools/errs" + "gopkg.in/yaml.v3" + "github.com/openimsdk/open-im-server/v3/pkg/msgprocessor" "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" - "gopkg.in/yaml.v3" ) //go:embed version @@ -36,38 +36,32 @@ const ( DefaultFolderPath = "../config/" ) -// GetDefaultConfigPath returns the absolute path to the default configuration directory -// relative to the executable's location. It is intended for use in Kubernetes container configurations. -// Errors are returned to the caller to allow for flexible error handling. -func GetDefaultConfigPath() (string, error) { +// return absolude path join ../config/, this is k8s container config path. +func GetDefaultConfigPath() string { executablePath, err := os.Executable() if err != nil { - return "", errs.Wrap(err, "failed to get executable path") + fmt.Println("GetDefaultConfigPath error:", err.Error()) + return "" } - // Calculate the config path as a directory relative to the executable's location configPath, err := genutil.OutDir(filepath.Join(filepath.Dir(executablePath), "../config/")) if err != nil { - return "", errs.Wrap(err, "failed to get output directory") + fmt.Fprintf(os.Stderr, "failed to get output directory: %v\n", err) + os.Exit(1) } - return configPath, nil + return configPath } -// GetProjectRoot returns the absolute path of the project root directory by navigating up from the directory -// containing the executable. It provides a detailed error if the path cannot be determined. -func GetProjectRoot() (string, error) { - executablePath, err := os.Executable() - if err != nil { - return "", errs.Wrap(err, "failed to retrieve executable path") - } +// getProjectRoot returns the absolute path of the project root directory. +func GetProjectRoot() string { + executablePath, _ := os.Executable() - // Attempt to compute the project root by navigating up from the executable's directory projectRoot, err := genutil.OutDir(filepath.Join(filepath.Dir(executablePath), "../../../../..")) if err != nil { - return "", err + fmt.Fprintf(os.Stderr, "failed to get output directory: %v\n", err) + os.Exit(1) } - - return projectRoot, nil + return projectRoot } func GetOptionsByNotification(cfg NotificationConf) msgprocessor.Options { @@ -93,62 +87,41 @@ func GetOptionsByNotification(cfg NotificationConf) msgprocessor.Options { // If the specified config file does not exist, it attempts to load from the project's default "config" directory. // It logs informative messages regarding the configuration path being used. func initConfig(config any, configName, configFolderPath string) error { - configFilePath := filepath.Join(configFolderPath, configName) - _, err := os.Stat(configFilePath) + configFolderPath = filepath.Join(configFolderPath, configName) + _, err := os.Stat(configFolderPath) if err != nil { if !os.IsNotExist(err) { - return errs.Wrap(err, fmt.Sprintf("failed to check existence of config file at path: %s", configFilePath)) + fmt.Println("stat config path error:", err.Error()) + return fmt.Errorf("stat config path error: %w", err) } - var projectRoot string - projectRoot, err = GetProjectRoot() - if err != nil { - return err - } - configFilePath = filepath.Join(projectRoot, "config", configName) - fmt.Printf("Configuration file not found at specified path. Falling back to project path: %s\n", configFilePath) + configFolderPath = filepath.Join(GetProjectRoot(), "config", configName) + fmt.Println("flag's path,enviment's path,default path all is not exist,using project path:", configFolderPath) } - - data, err := os.ReadFile(configFilePath) + data, err := os.ReadFile(configFolderPath) if err != nil { - // Wrap and return the error if reading the configuration file fails. - return errs.Wrap(err, fmt.Sprintf("failed to read configuration file at path: %s", configFilePath)) + return fmt.Errorf("read file error: %w", err) } - if err = yaml.Unmarshal(data, config); err != nil { - // Wrap and return the error if unmarshalling the YAML configuration fails. - return errs.Wrap(err, "failed to unmarshal YAML configuration") + return fmt.Errorf("unmarshal yaml error: %w", err) } + fmt.Println("The path of the configuration file to start the process:", configFolderPath) - fmt.Printf("Configuration file loaded successfully from path: %s\n", configFilePath) return nil } -// InitConfig initializes the application configuration by loading it from a specified folder path. -// If the folder path is not provided, it attempts to use the OPENIMCONFIG environment variable, -// and as a fallback, it uses the default configuration path. It loads both the main configuration -// and notification configuration, wrapping errors for better context. -func InitConfig(configFolderPath string) error { - // Use the provided config folder path, or fallback to environment variable or default path +func InitConfig(config *GlobalConfig, configFolderPath string) error { if configFolderPath == "" { - configFolderPath = os.Getenv("OPENIMCONFIG") - if configFolderPath == "" { - var err error - configFolderPath, err = GetDefaultConfigPath() - if err != nil { - return err - } + envConfigPath := os.Getenv("OPENIMCONFIG") + if envConfigPath != "" { + configFolderPath = envConfigPath + } else { + configFolderPath = GetDefaultConfigPath() } } - // Initialize the main configuration - if err := initConfig(&Config, FileName, configFolderPath); err != nil { + if err := initConfig(config, FileName, configFolderPath); err != nil { return err } - // Initialize the notification configuration - if err := initConfig(&Config.Notification, NotificationFileName, configFolderPath); err != nil { - return err - } - - return nil + return initConfig(&config.Notification, NotificationFileName, configFolderPath) } diff --git a/pkg/common/config/parse_test.go b/pkg/common/config/parse_test.go index b980de7bd8..84dee1165a 100644 --- a/pkg/common/config/parse_test.go +++ b/pkg/common/config/parse_test.go @@ -103,13 +103,14 @@ func TestInitConfig(t *testing.T) { tests := []struct { name string args args + config *GlobalConfig wantErr bool }{ // TODO: Add test cases. } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - if err := InitConfig(tt.args.configFolderPath); (err != nil) != tt.wantErr { + if err := InitConfig(tt.config, tt.args.configFolderPath); (err != nil) != tt.wantErr { t.Errorf("InitConfig() error = %v, wantErr %v", err, tt.wantErr) } }) diff --git a/pkg/common/db/cache/init_redis.go b/pkg/common/db/cache/init_redis.go index b81edf9e58..8f4e2c592c 100644 --- a/pkg/common/db/cache/init_redis.go +++ b/pkg/common/db/cache/init_redis.go @@ -38,34 +38,34 @@ const ( ) // NewRedis Initialize redis connection. -func NewRedis() (redis.UniversalClient, error) { +func NewRedis(config *config.GlobalConfig) (redis.UniversalClient, error) { if redisClient != nil { return redisClient, nil } // Read configuration from environment variables - overrideConfigFromEnv() + overrideConfigFromEnv(config) - if len(config.Config.Redis.Address) == 0 { - return nil, errs.Wrap(errors.New("redis address is empty"), "Redis configuration error") + if len(config.Redis.Address) == 0 { + return nil, errs.Wrap(errors.New("redis address is empty")) } specialerror.AddReplace(redis.Nil, errs.ErrRecordNotFound) var rdb redis.UniversalClient - if len(config.Config.Redis.Address) > 1 || config.Config.Redis.ClusterMode { + if len(config.Redis.Address) > 1 || config.Redis.ClusterMode { rdb = redis.NewClusterClient(&redis.ClusterOptions{ - Addrs: config.Config.Redis.Address, - Username: config.Config.Redis.Username, - Password: config.Config.Redis.Password, // no password set + Addrs: config.Redis.Address, + Username: config.Redis.Username, + Password: config.Redis.Password, // no password set PoolSize: 50, MaxRetries: maxRetry, }) } else { rdb = redis.NewClient(&redis.Options{ - Addr: config.Config.Redis.Address[0], - Username: config.Config.Redis.Username, - Password: config.Config.Redis.Password, // no password set - DB: 0, // use default DB - PoolSize: 100, // connection pool size + Addr: config.Redis.Address[0], + Username: config.Redis.Username, + Password: config.Redis.Password, + DB: 0, // use default DB + PoolSize: 100, // connection pool size MaxRetries: maxRetry, }) } @@ -75,33 +75,33 @@ func NewRedis() (redis.UniversalClient, error) { defer cancel() err = rdb.Ping(ctx).Err() if err != nil { - uriFormat := "address:%v, username:%s, clusterMode:%t, enablePipeline:%t" - errMsg := fmt.Sprintf(uriFormat, config.Config.Redis.Address, config.Config.Redis.Username, config.Config.Redis.ClusterMode, config.Config.Redis.EnablePipeline) - return nil, errs.Wrap(err, "Redis connection failed: %s", errMsg) + errMsg := fmt.Sprintf("address:%s, username:%s, password:%s, clusterMode:%t, enablePipeline:%t", config.Redis.Address, config.Redis.Username, + config.Redis.Password, config.Redis.ClusterMode, config.Redis.EnablePipeline) + return nil, errs.Wrap(err, errMsg) } redisClient = rdb return rdb, err } // overrideConfigFromEnv overrides configuration fields with environment variables if present. -func overrideConfigFromEnv() { +func overrideConfigFromEnv(config *config.GlobalConfig) { if envAddr := os.Getenv("REDIS_ADDRESS"); envAddr != "" { if envPort := os.Getenv("REDIS_PORT"); envPort != "" { addresses := strings.Split(envAddr, ",") for i, addr := range addresses { addresses[i] = addr + ":" + envPort } - config.Config.Redis.Address = addresses + config.Redis.Address = addresses } else { - config.Config.Redis.Address = strings.Split(envAddr, ",") + config.Redis.Address = strings.Split(envAddr, ",") } } if envUser := os.Getenv("REDIS_USERNAME"); envUser != "" { - config.Config.Redis.Username = envUser + config.Redis.Username = envUser } if envPass := os.Getenv("REDIS_PASSWORD"); envPass != "" { - config.Config.Redis.Password = envPass + config.Redis.Password = envPass } } diff --git a/pkg/common/db/cache/meta_cache.go b/pkg/common/db/cache/meta_cache.go index 4c25754d6b..1fbb6c3b66 100644 --- a/pkg/common/db/cache/meta_cache.go +++ b/pkg/common/db/cache/meta_cache.go @@ -18,13 +18,16 @@ import ( "context" "encoding/json" "errors" + "fmt" "time" + "github.com/OpenIMSDK/tools/mw/specialerror" + + "github.com/dtm-labs/rockscache" + "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/log" - "github.com/OpenIMSDK/tools/mw/specialerror" "github.com/OpenIMSDK/tools/utils" - "github.com/dtm-labs/rockscache" ) const ( @@ -128,7 +131,7 @@ func getCache[T any](ctx context.Context, rcClient *rockscache.Client, key strin v, err := rcClient.Fetch2(ctx, key, expire, func() (s string, err error) { t, err = fn(ctx) if err != nil { - return "", err + return "", errs.Wrap(err) } bs, err := json.Marshal(t) if err != nil { @@ -139,7 +142,7 @@ func getCache[T any](ctx context.Context, rcClient *rockscache.Client, key strin return string(bs), nil }) if err != nil { - return t, err + return t, errs.Wrap(err) } if write { return t, nil @@ -149,8 +152,8 @@ func getCache[T any](ctx context.Context, rcClient *rockscache.Client, key strin } err = json.Unmarshal([]byte(v), &t) if err != nil { - log.ZError(ctx, "cache json.Unmarshal failed", err, "key", key, "value", v, "expire", expire) - return t, errs.Wrap(err, "unmarshal failed") + errInfo := fmt.Sprintf("cache json.Unmarshal failed, key:%s, value:%s, expire:%s", key, v, expire) + return t, errs.Wrap(err, errInfo) } return t, nil @@ -203,7 +206,7 @@ func batchGetCache2[T any, K comparable]( fns func(ctx context.Context, key K) (T, error), ) ([]T, error) { if len(keys) == 0 { - return nil, nil + return nil, errs.ErrArgs.Wrap("groupID is empty") } res := make([]T, 0, len(keys)) for _, key := range keys { @@ -214,7 +217,7 @@ func batchGetCache2[T any, K comparable]( if errs.ErrRecordNotFound.Is(specialerror.ErrCode(errs.Unwrap(err))) { continue } - return nil, err + return nil, errs.Wrap(err) } res = append(res, val) } diff --git a/pkg/common/db/cache/msg.go b/pkg/common/db/cache/msg.go index 889f36baa9..1266875f1a 100644 --- a/pkg/common/db/cache/msg.go +++ b/pkg/common/db/cache/msg.go @@ -121,13 +121,14 @@ type MsgModel interface { UnLockMessageTypeKey(ctx context.Context, clientMsgID string, TypeKey string) error } -func NewMsgCacheModel(client redis.UniversalClient) MsgModel { - return &msgCache{rdb: client} +func NewMsgCacheModel(client redis.UniversalClient, config *config.GlobalConfig) MsgModel { + return &msgCache{rdb: client, config: config} } type msgCache struct { metaCache - rdb redis.UniversalClient + rdb redis.UniversalClient + config *config.GlobalConfig } func (c *msgCache) getMaxSeqKey(conversationID string) string { @@ -315,7 +316,7 @@ func (c *msgCache) allMessageCacheKey(conversationID string) string { } func (c *msgCache) GetMessagesBySeq(ctx context.Context, conversationID string, seqs []int64) (seqMsgs []*sdkws.MsgData, failedSeqs []int64, err error) { - if config.Config.Redis.EnablePipeline { + if c.config.Redis.EnablePipeline { return c.PipeGetMessagesBySeq(ctx, conversationID, seqs) } @@ -416,7 +417,7 @@ func (c *msgCache) ParallelGetMessagesBySeq(ctx context.Context, conversationID } func (c *msgCache) SetMessageToCache(ctx context.Context, conversationID string, msgs []*sdkws.MsgData) (int, error) { - if config.Config.Redis.EnablePipeline { + if c.config.Redis.EnablePipeline { return c.PipeSetMessageToCache(ctx, conversationID, msgs) } return c.ParallelSetMessageToCache(ctx, conversationID, msgs) @@ -431,7 +432,7 @@ func (c *msgCache) PipeSetMessageToCache(ctx context.Context, conversationID str } key := c.getMessageCacheKey(conversationID, msg.Seq) - _ = pipe.Set(ctx, key, s, time.Duration(config.Config.MsgCacheTimeout)*time.Second) + _ = pipe.Set(ctx, key, s, time.Duration(c.config.MsgCacheTimeout)*time.Second) } results, err := pipe.Exec(ctx) @@ -461,7 +462,7 @@ func (c *msgCache) ParallelSetMessageToCache(ctx context.Context, conversationID } key := c.getMessageCacheKey(conversationID, msg.Seq) - if err := c.rdb.Set(ctx, key, s, time.Duration(config.Config.MsgCacheTimeout)*time.Second).Err(); err != nil { + if err := c.rdb.Set(ctx, key, s, time.Duration(c.config.MsgCacheTimeout)*time.Second).Err(); err != nil { return errs.Wrap(err) } return nil @@ -496,10 +497,10 @@ func (c *msgCache) UserDeleteMsgs(ctx context.Context, conversationID string, se if err != nil { return errs.Wrap(err) } - if err := c.rdb.Expire(ctx, delUserListKey, time.Duration(config.Config.MsgCacheTimeout)*time.Second).Err(); err != nil { + if err := c.rdb.Expire(ctx, delUserListKey, time.Duration(c.config.MsgCacheTimeout)*time.Second).Err(); err != nil { return errs.Wrap(err) } - if err := c.rdb.Expire(ctx, userDelListKey, time.Duration(config.Config.MsgCacheTimeout)*time.Second).Err(); err != nil { + if err := c.rdb.Expire(ctx, userDelListKey, time.Duration(c.config.MsgCacheTimeout)*time.Second).Err(); err != nil { return errs.Wrap(err) } } @@ -604,7 +605,7 @@ func (c *msgCache) DelUserDeleteMsgsList(ctx context.Context, conversationID str } func (c *msgCache) DeleteMessages(ctx context.Context, conversationID string, seqs []int64) error { - if config.Config.Redis.EnablePipeline { + if c.config.Redis.EnablePipeline { return c.PipeDeleteMessages(ctx, conversationID, seqs) } @@ -686,7 +687,7 @@ func (c *msgCache) DelMsgFromCache(ctx context.Context, userID string, seqs []in if err != nil { return errs.Wrap(err) } - if err := c.rdb.Set(ctx, key, s, time.Duration(config.Config.MsgCacheTimeout)*time.Second).Err(); err != nil { + if err := c.rdb.Set(ctx, key, s, time.Duration(c.config.MsgCacheTimeout)*time.Second).Err(); err != nil { return errs.Wrap(err) } } diff --git a/pkg/common/db/cache/user.go b/pkg/common/db/cache/user.go index c6c6966f3e..34c220624a 100644 --- a/pkg/common/db/cache/user.go +++ b/pkg/common/db/cache/user.go @@ -22,12 +22,16 @@ import ( "strconv" "time" + relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" + + "github.com/OpenIMSDK/tools/log" + "github.com/OpenIMSDK/protocol/constant" + "github.com/OpenIMSDK/protocol/user" "github.com/OpenIMSDK/tools/errs" - "github.com/OpenIMSDK/tools/log" + "github.com/dtm-labs/rockscache" - relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" "github.com/redis/go-redis/v9" ) @@ -62,7 +66,11 @@ type UserCacheRedis struct { rcClient *rockscache.Client } -func NewUserCacheRedis(rdb redis.UniversalClient, userDB relationtb.UserModelInterface, options rockscache.Options) UserCache { +func NewUserCacheRedis( + rdb redis.UniversalClient, + userDB relationtb.UserModelInterface, + options rockscache.Options, +) UserCache { rcClient := rockscache.NewClient(rdb, options) return &UserCacheRedis{ @@ -193,13 +201,13 @@ func (u *UserCacheRedis) SetUserStatus(ctx context.Context, userID string, statu Status: constant.Online, PlatformIDs: []int32{platformID}, } - jsonData, err2 := json.Marshal(&onlineStatus) - if err2 != nil { - return errs.Wrap(err2) + jsonData, err := json.Marshal(&onlineStatus) + if err != nil { + return errs.Wrap(err) } - _, err2 = u.rdb.HSet(ctx, key, userID, string(jsonData)).Result() - if err2 != nil { - return errs.Wrap(err2) + _, err = u.rdb.HSet(ctx, key, userID, string(jsonData)).Result() + if err != nil { + return errs.Wrap(err) } u.rdb.Expire(ctx, key, userOlineStatusExpireTime) @@ -273,9 +281,9 @@ func (u *UserCacheRedis) refreshStatusOffline(ctx context.Context, userID string func (u *UserCacheRedis) refreshStatusOnline(ctx context.Context, userID string, platformID int32, isNil bool, err error, result, key string) error { var onlineStatus user.OnlineStatus if !isNil { - err2 := json.Unmarshal([]byte(result), &onlineStatus) - if err2 != nil { - return errs.Wrap(err, "json.Unmarshal failed") + err := json.Unmarshal([]byte(result), &onlineStatus) + if err != nil { + return errs.Wrap(err) } onlineStatus.PlatformIDs = RemoveRepeatedElementsInList(append(onlineStatus.PlatformIDs, platformID)) } else { diff --git a/pkg/common/db/controller/auth.go b/pkg/common/db/controller/auth.go index dfd7b3e78f..19bea59818 100644 --- a/pkg/common/db/controller/auth.go +++ b/pkg/common/db/controller/auth.go @@ -16,6 +16,7 @@ package controller import ( "context" + "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/tools/errs" @@ -33,14 +34,14 @@ type AuthDatabase interface { } type authDatabase struct { - cache cache.MsgModel - + cache cache.MsgModel accessSecret string accessExpire int64 + config *config.GlobalConfig } -func NewAuthDatabase(cache cache.MsgModel, accessSecret string, accessExpire int64) AuthDatabase { - return &authDatabase{cache: cache, accessSecret: accessSecret, accessExpire: accessExpire} +func NewAuthDatabase(cache cache.MsgModel, accessSecret string, accessExpire int64, config *config.GlobalConfig) AuthDatabase { + return &authDatabase{cache: cache, accessSecret: accessSecret, accessExpire: accessExpire, config: config} } // If the result is empty. @@ -56,7 +57,7 @@ func (a *authDatabase) CreateToken(ctx context.Context, userID string, platformI } var deleteTokenKey []string for k, v := range tokens { - _, err = tokenverify.GetClaimFromToken(k, authverify.Secret()) + _, err = tokenverify.GetClaimFromToken(k, authverify.Secret(a.config.Secret)) if err != nil || v != constant.NormalToken { deleteTokenKey = append(deleteTokenKey, k) } diff --git a/pkg/common/db/controller/msg.go b/pkg/common/db/controller/msg.go index 56cb527035..ccf209b7a1 100644 --- a/pkg/common/db/controller/msg.go +++ b/pkg/common/db/controller/msg.go @@ -120,16 +120,33 @@ type CommonMsgDatabase interface { ConvertMsgsDocLen(ctx context.Context, conversationIDs []string) } -func NewCommonMsgDatabase(msgDocModel unrelationtb.MsgDocModelInterface, cacheModel cache.MsgModel) (CommonMsgDatabase, error) { - producerToRedis, err := kafka.NewKafkaProducer(config.Config.Kafka.Addr, config.Config.Kafka.LatestMsgToRedis.Topic) +func NewCommonMsgDatabase(msgDocModel unrelationtb.MsgDocModelInterface, cacheModel cache.MsgModel, config *config.GlobalConfig) (CommonMsgDatabase, error) { + producerConfig := &kafka.ProducerConfig{ + ProducerAck: config.Kafka.ProducerAck, + CompressType: config.Kafka.CompressType, + Username: config.Kafka.Username, + Password: config.Kafka.Password, + } + + var tlsConfig *kafka.TLSConfig + if config.Kafka.TLS != nil { + tlsConfig = &kafka.TLSConfig{ + CACrt: config.Kafka.TLS.CACrt, + ClientCrt: config.Kafka.TLS.ClientCrt, + ClientKey: config.Kafka.TLS.ClientKey, + ClientKeyPwd: config.Kafka.TLS.ClientKeyPwd, + InsecureSkipVerify: false, + } + } + producerToRedis, err := kafka.NewKafkaProducer(config.Kafka.Addr, config.Kafka.LatestMsgToRedis.Topic, producerConfig, tlsConfig) if err != nil { return nil, err } - producerToMongo, err := kafka.NewKafkaProducer(config.Config.Kafka.Addr, config.Config.Kafka.MsgToMongo.Topic) + producerToMongo, err := kafka.NewKafkaProducer(config.Kafka.Addr, config.Kafka.MsgToMongo.Topic, producerConfig, tlsConfig) if err != nil { return nil, err } - producerToPush, err := kafka.NewKafkaProducer(config.Config.Kafka.Addr, config.Config.Kafka.MsgToPush.Topic) + producerToPush, err := kafka.NewKafkaProducer(config.Kafka.Addr, config.Kafka.MsgToPush.Topic, producerConfig, tlsConfig) if err != nil { return nil, err } @@ -142,10 +159,10 @@ func NewCommonMsgDatabase(msgDocModel unrelationtb.MsgDocModelInterface, cacheMo }, nil } -func InitCommonMsgDatabase(rdb redis.UniversalClient, database *mongo.Database) (CommonMsgDatabase, error) { - cacheModel := cache.NewMsgCacheModel(rdb) +func InitCommonMsgDatabase(rdb redis.UniversalClient, database *mongo.Database, config *config.GlobalConfig) (CommonMsgDatabase, error) { + cacheModel := cache.NewMsgCacheModel(rdb, config) msgDocModel := unrelation.NewMsgMongoDriver(database) - return NewCommonMsgDatabase(msgDocModel, cacheModel) + return NewCommonMsgDatabase(msgDocModel, cacheModel, config) } type commonMsgDatabase struct { @@ -397,9 +414,9 @@ func (db *commonMsgDatabase) BatchInsertChat2Cache(ctx context.Context, conversa log.ZError(ctx, "db.cache.SetMaxSeq error", err, "conversationID", conversationID) prommetrics.SeqSetFailedCounter.Inc() } - err2 := db.cache.SetHasReadSeqs(ctx, conversationID, userSeqMap) + err = db.cache.SetHasReadSeqs(ctx, conversationID, userSeqMap) if err != nil { - log.ZError(ctx, "SetHasReadSeqs error", err2, "userSeqMap", userSeqMap, "conversationID", conversationID) + log.ZError(ctx, "SetHasReadSeqs error", err, "userSeqMap", userSeqMap, "conversationID", conversationID) prommetrics.SeqSetFailedCounter.Inc() } return lastMaxSeq, isNew, errs.Wrap(err) diff --git a/pkg/common/db/controller/msg_test.go b/pkg/common/db/controller/msg_test.go index 70c055bf31..4c2ab20da3 100644 --- a/pkg/common/db/controller/msg_test.go +++ b/pkg/common/db/controller/msg_test.go @@ -33,27 +33,28 @@ import ( ) func Test_BatchInsertChat2DB(t *testing.T) { - config.Config.Mongo.Address = []string{"192.168.44.128:37017"} - // config.Config.Mongo.Timeout = 60 - config.Config.Mongo.Database = "openIM" - // config.Config.Mongo.Source = "admin" - config.Config.Mongo.Username = "root" - config.Config.Mongo.Password = "openIM123" - config.Config.Mongo.MaxPoolSize = 100 - config.Config.RetainChatRecords = 3650 - config.Config.ChatRecordsClearTime = "0 2 * * 3" - - mongo, err := unrelation.NewMongo() + conf := config.NewGlobalConfig() + conf.Mongo.Address = []string{"192.168.44.128:37017"} + // conf.Mongo.Timeout = 60 + conf.Mongo.Database = "openIM" + // conf.Mongo.Source = "admin" + conf.Mongo.Username = "root" + conf.Mongo.Password = "openIM123" + conf.Mongo.MaxPoolSize = 100 + conf.RetainChatRecords = 3650 + conf.ChatRecordsClearTime = "0 2 * * 3" + + mongo, err := unrelation.NewMongo(conf) if err != nil { t.Fatal(err) } - err = mongo.GetDatabase().Client().Ping(context.Background(), nil) + err = mongo.GetDatabase(conf.Mongo.Database).Client().Ping(context.Background(), nil) if err != nil { panic(err) } db := &commonMsgDatabase{ - msgDocDatabase: unrelation.NewMsgMongoDriver(mongo.GetDatabase()), + msgDocDatabase: unrelation.NewMsgMongoDriver(mongo.GetDatabase(conf.Mongo.Database)), } //ctx := context.Background() @@ -70,7 +71,7 @@ func Test_BatchInsertChat2DB(t *testing.T) { //} _ = db.BatchInsertChat2DB - c := mongo.GetDatabase().Collection("msg") + c := mongo.GetDatabase(conf.Mongo.Database).Collection("msg") ch := make(chan int) rand.Seed(time.Now().UnixNano()) @@ -144,26 +145,27 @@ func Test_BatchInsertChat2DB(t *testing.T) { } func GetDB() *commonMsgDatabase { - config.Config.Mongo.Address = []string{"203.56.175.233:37017"} - // config.Config.Mongo.Timeout = 60 - config.Config.Mongo.Database = "openim_v3" - // config.Config.Mongo.Source = "admin" - config.Config.Mongo.Username = "root" - config.Config.Mongo.Password = "openIM123" - config.Config.Mongo.MaxPoolSize = 100 - config.Config.RetainChatRecords = 3650 - config.Config.ChatRecordsClearTime = "0 2 * * 3" - - mongo, err := unrelation.NewMongo() + conf := config.NewGlobalConfig() + conf.Mongo.Address = []string{"203.56.175.233:37017"} + // conf.Mongo.Timeout = 60 + conf.Mongo.Database = "openim_v3" + // conf.Mongo.Source = "admin" + conf.Mongo.Username = "root" + conf.Mongo.Password = "openIM123" + conf.Mongo.MaxPoolSize = 100 + conf.RetainChatRecords = 3650 + conf.ChatRecordsClearTime = "0 2 * * 3" + + mongo, err := unrelation.NewMongo(conf) if err != nil { panic(err) } - err = mongo.GetDatabase().Client().Ping(context.Background(), nil) + err = mongo.GetDatabase(conf.Mongo.Database).Client().Ping(context.Background(), nil) if err != nil { panic(err) } return &commonMsgDatabase{ - msgDocDatabase: unrelation.NewMsgMongoDriver(mongo.GetDatabase()), + msgDocDatabase: unrelation.NewMsgMongoDriver(mongo.GetDatabase(conf.Mongo.Database)), } } diff --git a/pkg/common/db/s3/aws/aws.go b/pkg/common/db/s3/aws/aws.go deleted file mode 100644 index dd54ed1559..0000000000 --- a/pkg/common/db/s3/aws/aws.go +++ /dev/null @@ -1,275 +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. - -// docURL: https://docs.aws.amazon.com/AmazonS3/latest/API/Welcome.html - -package aws - -import ( - "context" - "errors" - "fmt" - "time" - - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aws/aws-sdk-go/aws/credentials" - "github.com/aws/aws-sdk-go/aws/session" - sdk "github.com/aws/aws-sdk-go/service/s3" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/s3" -) - -const ( - minPartSize int64 = 1024 * 1024 * 1 // 1MB - maxPartSize int64 = 1024 * 1024 * 1024 * 5 // 5GB - maxNumSize int64 = 10000 -) - -// const ( -// imagePng = "png" -// imageJpg = "jpg" -// imageJpeg = "jpeg" -// imageGif = "gif" -// imageWebp = "webp" -// ) - -// const successCode = http.StatusOK - -// const ( -// videoSnapshotImagePng = "png" -// videoSnapshotImageJpg = "jpg" -// ) - -func NewAWS() (s3.Interface, error) { - conf := config.Config.Object.Aws - credential := credentials.NewStaticCredentials( - conf.AccessKeyID, // accessKey - conf.AccessKeySecret, // secretKey - "") // stoken - - sess, err := session.NewSession(&aws.Config{ - Region: aws.String(conf.Region), // The area where the bucket is located - Credentials: credential, - }) - - if err != nil { - return nil, err - } - return &Aws{ - bucket: conf.Bucket, - client: sdk.New(sess), - credential: credential, - }, nil -} - -type Aws struct { - bucket string - client *sdk.S3 - credential *credentials.Credentials -} - -func (a *Aws) Engine() string { - return "aws" -} - -func (a *Aws) InitiateMultipartUpload(ctx context.Context, name string) (*s3.InitiateMultipartUploadResult, error) { - input := &sdk.CreateMultipartUploadInput{ - Bucket: aws.String(a.bucket), // TODO: To be verified whether it is required - Key: aws.String(name), - } - result, err := a.client.CreateMultipartUploadWithContext(ctx, input) - if err != nil { - return nil, err - } - return &s3.InitiateMultipartUploadResult{ - Bucket: *result.Bucket, - Key: *result.Key, - UploadID: *result.UploadId, - }, nil -} - -func (a *Aws) CompleteMultipartUpload(ctx context.Context, uploadID string, name string, parts []s3.Part) (*s3.CompleteMultipartUploadResult, error) { - sdkParts := make([]*sdk.CompletedPart, len(parts)) - for i, part := range parts { - sdkParts[i] = &sdk.CompletedPart{ - ETag: aws.String(part.ETag), - PartNumber: aws.Int64(int64(part.PartNumber)), - } - } - input := &sdk.CompleteMultipartUploadInput{ - Bucket: aws.String(a.bucket), // TODO: To be verified whether it is required - Key: aws.String(name), - UploadId: aws.String(uploadID), - MultipartUpload: &sdk.CompletedMultipartUpload{ - Parts: sdkParts, - }, - } - result, err := a.client.CompleteMultipartUploadWithContext(ctx, input) - if err != nil { - return nil, err - } - return &s3.CompleteMultipartUploadResult{ - Location: *result.Location, - Bucket: *result.Bucket, - Key: *result.Key, - ETag: *result.ETag, - }, nil -} - -func (a *Aws) PartSize(ctx context.Context, size int64) (int64, error) { - if size <= 0 { - return 0, errors.New("size must be greater than 0") - } - if size > maxPartSize*maxNumSize { - return 0, fmt.Errorf("AWS size must be less than the maximum allowed limit") - } - if size <= minPartSize*maxNumSize { - return minPartSize, nil - } - partSize := size / maxNumSize - if size%maxNumSize != 0 { - partSize++ - } - return partSize, nil -} - -func (a *Aws) DeleteObject(ctx context.Context, name string) error { - _, err := a.client.DeleteObjectWithContext(ctx, &sdk.DeleteObjectInput{ - Bucket: aws.String(a.bucket), - Key: aws.String(name), - }) - return err -} - -func (a *Aws) CopyObject(ctx context.Context, src string, dst string) (*s3.CopyObjectInfo, error) { - result, err := a.client.CopyObjectWithContext(ctx, &sdk.CopyObjectInput{ - Bucket: aws.String(a.bucket), - Key: aws.String(dst), - CopySource: aws.String(src), - }) - if err != nil { - return nil, err - } - return &s3.CopyObjectInfo{ - ETag: *result.CopyObjectResult.ETag, - Key: dst, - }, nil -} - -func (a *Aws) IsNotFound(err error) bool { - if err == nil { - return false - } - if aerr, ok := err.(awserr.Error); ok { - switch aerr.Code() { - case sdk.ErrCodeNoSuchKey: - return true - default: - return false - } - } - return false -} - -func (a *Aws) AbortMultipartUpload(ctx context.Context, uploadID string, name string) error { - _, err := a.client.AbortMultipartUploadWithContext(ctx, &sdk.AbortMultipartUploadInput{ - Bucket: aws.String(a.bucket), - Key: aws.String(name), - UploadId: aws.String(uploadID), - }) - return err -} - -func (a *Aws) ListUploadedParts(ctx context.Context, uploadID string, name string, partNumberMarker int, maxParts int) (*s3.ListUploadedPartsResult, error) { - result, err := a.client.ListPartsWithContext(ctx, &sdk.ListPartsInput{ - Bucket: aws.String(a.bucket), - Key: aws.String(name), - UploadId: aws.String(uploadID), - MaxParts: aws.Int64(int64(maxParts)), - PartNumberMarker: aws.Int64(int64(partNumberMarker)), - }) - if err != nil { - return nil, err - } - parts := make([]s3.UploadedPart, len(result.Parts)) - for i, part := range result.Parts { - parts[i] = s3.UploadedPart{ - PartNumber: int(*part.PartNumber), - LastModified: *part.LastModified, - Size: *part.Size, - ETag: *part.ETag, - } - } - return &s3.ListUploadedPartsResult{ - Key: *result.Key, - UploadID: *result.UploadId, - NextPartNumberMarker: int(*result.NextPartNumberMarker), - MaxParts: int(*result.MaxParts), - UploadedParts: parts, - }, nil -} - -func (a *Aws) PartLimit() *s3.PartLimit { - return &s3.PartLimit{ - MinPartSize: minPartSize, - MaxPartSize: maxPartSize, - MaxNumSize: maxNumSize, - } -} - -func (a *Aws) PresignedPutObject(ctx context.Context, name string, expire time.Duration) (string, error) { - req, _ := a.client.PutObjectRequest(&sdk.PutObjectInput{ - Bucket: aws.String(a.bucket), - Key: aws.String(name), - }) - url, err := req.Presign(expire) - if err != nil { - return "", err - } - return url, nil -} - -func (a *Aws) StatObject(ctx context.Context, name string) (*s3.ObjectInfo, error) { - result, err := a.client.GetObjectWithContext(ctx, &sdk.GetObjectInput{ - Bucket: aws.String(a.bucket), - Key: aws.String(name), - }) - if err != nil { - return nil, err - } - res := &s3.ObjectInfo{ - Key: name, - ETag: *result.ETag, - Size: *result.ContentLength, - LastModified: *result.LastModified, - } - return res, nil -} - -// AccessURL todo. -func (a *Aws) AccessURL(ctx context.Context, name string, expire time.Duration, opt *s3.AccessURLOption) (string, error) { - // todo - return "", nil -} - -func (a *Aws) FormData(ctx context.Context, name string, size int64, contentType string, duration time.Duration) (*s3.FormData, error) { - // todo - return nil, nil -} - -func (a *Aws) AuthSign(ctx context.Context, uploadID string, name string, expire time.Duration, partNumbers []int) (*s3.AuthSignResult, error) { - // todo - return nil, nil -} diff --git a/pkg/common/db/s3/cos/cos.go b/pkg/common/db/s3/cos/cos.go index 619f142abe..a7c26fcc16 100644 --- a/pkg/common/db/s3/cos/cos.go +++ b/pkg/common/db/s3/cos/cos.go @@ -23,13 +23,13 @@ import ( "encoding/json" "errors" "fmt" + "github.com/OpenIMSDK/tools/errs" "net/http" "net/url" "strconv" "strings" "time" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/db/s3" "github.com/tencentyun/cos-go-sdk-v5" ) @@ -50,13 +50,15 @@ const ( const successCode = http.StatusOK -const ( -// videoSnapshotImagePng = "png" -// videoSnapshotImageJpg = "jpg" -) +type Config struct { + BucketURL string + SecretID string + SecretKey string + SessionToken string + PublicRead bool +} -func NewCos() (s3.Interface, error) { - conf := config.Config.Object.Cos +func NewCos(conf Config) (s3.Interface, error) { u, err := url.Parse(conf.BucketURL) if err != nil { panic(err) @@ -69,6 +71,7 @@ func NewCos() (s3.Interface, error) { }, }) return &Cos{ + publicRead: conf.PublicRead, copyURL: u.Host + "/", client: client, credential: client.GetCredential(), @@ -76,6 +79,7 @@ func NewCos() (s3.Interface, error) { } type Cos struct { + publicRead bool copyURL string client *cos.Client credential *cos.Credential @@ -226,7 +230,7 @@ func (c *Cos) CopyObject(ctx context.Context, src string, dst string) (*s3.CopyO } func (c *Cos) IsNotFound(err error) bool { - switch e := err.(type) { + switch e := errs.Unwrap(err).(type) { case *cos.ErrorResponse: return e.Response.StatusCode == http.StatusNotFound || e.Code == "NoSuchKey" default: @@ -327,7 +331,7 @@ func (c *Cos) AccessURL(ctx context.Context, name string, expire time.Duration, } func (c *Cos) getPresignedURL(ctx context.Context, name string, expire time.Duration, opt *cos.PresignedURLOptions) (*url.URL, error) { - if !config.Config.Object.Cos.PublicRead { + if !c.publicRead { return c.client.Object.GetPresignedURL(ctx, http.MethodGet, name, c.credential.SecretID, c.credential.SecretKey, expire, opt) } return c.client.Object.GetObjectURL(name), nil diff --git a/pkg/common/db/s3/minio/image.go b/pkg/common/db/s3/minio/image.go index f363f94b1c..71db1ea519 100644 --- a/pkg/common/db/s3/minio/image.go +++ b/pkg/common/db/s3/minio/image.go @@ -42,51 +42,79 @@ func ImageWidthHeight(img image.Image) (int, int) { return bounds.X, bounds.Y } -// resizeImage resizes an image to a specified maximum width and height, maintaining the aspect ratio. -// If both maxWidth and maxHeight are set to 0, the original image is returned. -// If both are non-zero, the image is scaled to fit within the constraints while maintaining aspect ratio. -// If only one of maxWidth or maxHeight is non-zero, the image is scaled accordingly. func resizeImage(img image.Image, maxWidth, maxHeight int) image.Image { bounds := img.Bounds() - imgWidth, imgHeight := bounds.Dx(), bounds.Dy() + imgWidth := bounds.Max.X + imgHeight := bounds.Max.Y - // Return original image if no resizing is needed. + // 计算缩放比例 + scaleWidth := float64(maxWidth) / float64(imgWidth) + scaleHeight := float64(maxHeight) / float64(imgHeight) + + // 如果都为0,则不缩放,返回原始图片 if maxWidth == 0 && maxHeight == 0 { return img } - var scale float64 = 1 + // 如果宽度和高度都大于0,则选择较小的缩放比例,以保持宽高比 if maxWidth > 0 && maxHeight > 0 { - scaleWidth := float64(maxWidth) / float64(imgWidth) - scaleHeight := float64(maxHeight) / float64(imgHeight) - // Choose the smaller scale to fit both constraints. - scale = min(scaleWidth, scaleHeight) - } else if maxWidth > 0 { - scale = float64(maxWidth) / float64(imgWidth) - } else if maxHeight > 0 { - scale = float64(maxHeight) / float64(imgHeight) + scale := scaleWidth + if scaleHeight < scaleWidth { + scale = scaleHeight + } + + // 计算缩略图尺寸 + thumbnailWidth := int(float64(imgWidth) * scale) + thumbnailHeight := int(float64(imgHeight) * scale) + + // 使用"image"库的Resample方法生成缩略图 + thumbnail := image.NewRGBA(image.Rect(0, 0, thumbnailWidth, thumbnailHeight)) + for y := 0; y < thumbnailHeight; y++ { + for x := 0; x < thumbnailWidth; x++ { + srcX := int(float64(x) / scale) + srcY := int(float64(y) / scale) + thumbnail.Set(x, y, img.At(srcX, srcY)) + } + } + + return thumbnail } - newWidth := int(float64(imgWidth) * scale) - newHeight := int(float64(imgHeight) * scale) + // 如果只指定了宽度或高度,则根据最大不超过的规则生成缩略图 + if maxWidth > 0 { + thumbnailWidth := maxWidth + thumbnailHeight := int(float64(imgHeight) * scaleWidth) - // Resize the image by creating a new image and manually copying pixels. - thumbnail := image.NewRGBA(image.Rect(0, 0, newWidth, newHeight)) - for y := 0; y < newHeight; y++ { - for x := 0; x < newWidth; x++ { - srcX := int(float64(x) / scale) - srcY := int(float64(y) / scale) - thumbnail.Set(x, y, img.At(srcX, srcY)) + // 使用"image"库的Resample方法生成缩略图 + thumbnail := image.NewRGBA(image.Rect(0, 0, thumbnailWidth, thumbnailHeight)) + for y := 0; y < thumbnailHeight; y++ { + for x := 0; x < thumbnailWidth; x++ { + srcX := int(float64(x) / scaleWidth) + srcY := int(float64(y) / scaleWidth) + thumbnail.Set(x, y, img.At(srcX, srcY)) + } } + + return thumbnail } - return thumbnail -} + if maxHeight > 0 { + thumbnailWidth := int(float64(imgWidth) * scaleHeight) + thumbnailHeight := maxHeight -// min returns the smaller of x or y. -func min(x, y float64) float64 { - if x < y { - return x + // 使用"image"库的Resample方法生成缩略图 + thumbnail := image.NewRGBA(image.Rect(0, 0, thumbnailWidth, thumbnailHeight)) + for y := 0; y < thumbnailHeight; y++ { + for x := 0; x < thumbnailWidth; x++ { + srcX := int(float64(x) / scaleHeight) + srcY := int(float64(y) / scaleHeight) + thumbnail.Set(x, y, img.At(srcX, srcY)) + } + } + + return thumbnail } - return y + + // 默认情况下,返回原始图片 + return img } diff --git a/pkg/common/db/s3/minio/minio.go b/pkg/common/db/s3/minio/minio.go index 1eb3257e11..cd77948d45 100644 --- a/pkg/common/db/s3/minio/minio.go +++ b/pkg/common/db/s3/minio/minio.go @@ -18,6 +18,7 @@ import ( "context" "errors" "fmt" + "github.com/OpenIMSDK/tools/errs" "io" "net/http" "net/url" @@ -33,7 +34,6 @@ import ( "github.com/minio/minio-go/v7" "github.com/minio/minio-go/v7/pkg/credentials" "github.com/minio/minio-go/v7/pkg/signer" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" "github.com/openimsdk/open-im-server/v3/pkg/common/db/s3" ) @@ -43,7 +43,7 @@ const ( ) const ( - minPartSize int64 = 1024 * 1024 * 5 // 1MB + minPartSize int64 = 1024 * 1024 * 5 // 5MB maxPartSize int64 = 1024 * 1024 * 1024 * 5 // 5GB maxNumSize int64 = 10000 ) @@ -57,13 +57,23 @@ const ( const successCode = http.StatusOK -func NewMinio(cache cache.MinioCache) (s3.Interface, error) { - u, err := url.Parse(config.Config.Object.Minio.Endpoint) +type Config struct { + Bucket string + Endpoint string + AccessKeyID string + SecretAccessKey string + SessionToken string + SignEndpoint string + PublicRead bool +} + +func NewMinio(cache cache.MinioCache, conf Config) (s3.Interface, error) { + u, err := url.Parse(conf.Endpoint) if err != nil { return nil, err } opts := &minio.Options{ - Creds: credentials.NewStaticV4(config.Config.Object.Minio.AccessKeyID, config.Config.Object.Minio.SecretAccessKey, config.Config.Object.Minio.SessionToken), + Creds: credentials.NewStaticV4(conf.AccessKeyID, conf.SecretAccessKey, conf.SessionToken), Secure: u.Scheme == "https", } client, err := minio.New(u.Host, opts) @@ -71,26 +81,27 @@ func NewMinio(cache cache.MinioCache) (s3.Interface, error) { return nil, err } m := &Minio{ - bucket: config.Config.Object.Minio.Bucket, + conf: conf, + bucket: conf.Bucket, core: &minio.Core{Client: client}, lock: &sync.Mutex{}, init: false, cache: cache, } - if config.Config.Object.Minio.SignEndpoint == "" || config.Config.Object.Minio.SignEndpoint == config.Config.Object.Minio.Endpoint { + if conf.SignEndpoint == "" || conf.SignEndpoint == conf.Endpoint { m.opts = opts m.sign = m.core.Client m.prefix = u.Path u.Path = "" - config.Config.Object.Minio.Endpoint = u.String() - m.signEndpoint = config.Config.Object.Minio.Endpoint + conf.Endpoint = u.String() + m.signEndpoint = conf.Endpoint } else { - su, err := url.Parse(config.Config.Object.Minio.SignEndpoint) + su, err := url.Parse(conf.SignEndpoint) if err != nil { return nil, err } m.opts = &minio.Options{ - Creds: credentials.NewStaticV4(config.Config.Object.Minio.AccessKeyID, config.Config.Object.Minio.SecretAccessKey, config.Config.Object.Minio.SessionToken), + Creds: credentials.NewStaticV4(conf.AccessKeyID, conf.SecretAccessKey, conf.SessionToken), Secure: su.Scheme == "https", } m.sign, err = minio.New(su.Host, m.opts) @@ -99,8 +110,8 @@ func NewMinio(cache cache.MinioCache) (s3.Interface, error) { } m.prefix = su.Path su.Path = "" - config.Config.Object.Minio.SignEndpoint = su.String() - m.signEndpoint = config.Config.Object.Minio.SignEndpoint + conf.SignEndpoint = su.String() + m.signEndpoint = conf.SignEndpoint } ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() @@ -111,6 +122,7 @@ func NewMinio(cache cache.MinioCache) (s3.Interface, error) { } type Minio struct { + conf Config bucket string signEndpoint string location string @@ -132,31 +144,30 @@ func (m *Minio) initMinio(ctx context.Context) error { if m.init { return nil } - conf := config.Config.Object.Minio - exists, err := m.core.Client.BucketExists(ctx, conf.Bucket) + exists, err := m.core.Client.BucketExists(ctx, m.conf.Bucket) if err != nil { return fmt.Errorf("check bucket exists error: %w", err) } if !exists { - if err = m.core.Client.MakeBucket(ctx, conf.Bucket, minio.MakeBucketOptions{}); err != nil { + if err = m.core.Client.MakeBucket(ctx, m.conf.Bucket, minio.MakeBucketOptions{}); err != nil { return fmt.Errorf("make bucket error: %w", err) } } - if conf.PublicRead { + if m.conf.PublicRead { policy := fmt.Sprintf( `{"Version": "2012-10-17","Statement": [{"Action": ["s3:GetObject","s3:PutObject"],"Effect": "Allow","Principal": {"AWS": ["*"]},"Resource": ["arn:aws:s3:::%s/*"],"Sid": ""}]}`, - conf.Bucket, + m.conf.Bucket, ) - if err = m.core.Client.SetBucketPolicy(ctx, conf.Bucket, policy); err != nil { + if err = m.core.Client.SetBucketPolicy(ctx, m.conf.Bucket, policy); err != nil { return err } } - m.location, err = m.core.Client.GetBucketLocation(ctx, conf.Bucket) + m.location, err = m.core.Client.GetBucketLocation(ctx, m.conf.Bucket) if err != nil { return err } func() { - if conf.SignEndpoint == "" || conf.SignEndpoint == conf.Endpoint { + if m.conf.SignEndpoint == "" || m.conf.SignEndpoint == m.conf.Endpoint { return } defer func() { @@ -176,7 +187,7 @@ func (m *Minio) initMinio(ctx context.Context) error { blc := reflect.ValueOf(m.sign).Elem().FieldByName("bucketLocCache") vblc := reflect.New(reflect.PtrTo(blc.Type())) *(*unsafe.Pointer)(vblc.UnsafePointer()) = unsafe.Pointer(blc.UnsafeAddr()) - vblc.Elem().Elem().Interface().(interface{ Set(string, string) }).Set(conf.Bucket, m.location) + vblc.Elem().Elem().Interface().(interface{ Set(string, string) }).Set(m.conf.Bucket, m.location) }() m.init = true return nil @@ -341,10 +352,7 @@ func (m *Minio) CopyObject(ctx context.Context, src string, dst string) (*s3.Cop } func (m *Minio) IsNotFound(err error) bool { - if err == nil { - return false - } - switch e := err.(type) { + switch e := errs.Unwrap(err).(type) { case minio.ErrorResponse: return e.StatusCode == http.StatusNotFound || e.Code == "NoSuchKey" case *minio.ErrorResponse: @@ -397,7 +405,7 @@ func (m *Minio) PresignedGetObject(ctx context.Context, name string, expire time rawURL *url.URL err error ) - if config.Config.Object.Minio.PublicRead { + if m.conf.PublicRead { rawURL, err = makeTargetURL(m.sign, m.bucket, name, m.location, false, query) } else { rawURL, err = m.sign.PresignedGetObject(ctx, m.bucket, name, expire, query) diff --git a/pkg/common/db/s3/oss/oss.go b/pkg/common/db/s3/oss/oss.go index 442f4e52fa..e485db2774 100644 --- a/pkg/common/db/s3/oss/oss.go +++ b/pkg/common/db/s3/oss/oss.go @@ -32,7 +32,6 @@ import ( "github.com/OpenIMSDK/tools/errs" "github.com/aliyun/aliyun-oss-go-sdk/oss" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/db/s3" ) @@ -52,13 +51,17 @@ const ( const successCode = http.StatusOK -/* const ( - videoSnapshotImagePng = "png" - videoSnapshotImageJpg = "jpg" -) */ +type Config struct { + Endpoint string + Bucket string + BucketURL string + AccessKeyID string + AccessKeySecret string + SessionToken string + PublicRead bool +} -func NewOSS() (s3.Interface, error) { - conf := config.Config.Object.Oss +func NewOSS(conf Config) (s3.Interface, error) { if conf.BucketURL == "" { return nil, errs.Wrap(errors.New("bucket url is empty")) } @@ -78,6 +81,7 @@ func NewOSS() (s3.Interface, error) { bucket: bucket, credentials: client.Config.GetCredentials(), um: *(*urlMaker)(reflect.ValueOf(bucket.Client.Conn).Elem().FieldByName("url").UnsafePointer()), + publicRead: conf.PublicRead, }, nil } @@ -86,6 +90,7 @@ type OSS struct { bucket *oss.Bucket credentials oss.Credentials um urlMaker + publicRead bool } func (o *OSS) Engine() string { @@ -236,7 +241,7 @@ func (o *OSS) CopyObject(ctx context.Context, src string, dst string) (*s3.CopyO } func (o *OSS) IsNotFound(err error) bool { - switch e := err.(type) { + switch e := errs.Unwrap(err).(type) { case oss.ServiceError: return e.StatusCode == http.StatusNotFound || e.Code == "NoSuchKey" case *oss.ServiceError: @@ -282,7 +287,6 @@ func (o *OSS) ListUploadedParts(ctx context.Context, uploadID string, name strin } func (o *OSS) AccessURL(ctx context.Context, name string, expire time.Duration, opt *s3.AccessURLOption) (string, error) { - publicRead := config.Config.Object.Oss.PublicRead var opts []oss.Option if opt != nil { if opt.Image != nil { @@ -310,7 +314,7 @@ func (o *OSS) AccessURL(ctx context.Context, name string, expire time.Duration, process += ",format," + format opts = append(opts, oss.Process(process)) } - if !publicRead { + if !o.publicRead { if opt.ContentType != "" { opts = append(opts, oss.ResponseContentType(opt.ContentType)) } @@ -324,7 +328,7 @@ func (o *OSS) AccessURL(ctx context.Context, name string, expire time.Duration, } else if expire < time.Second { expire = time.Second } - if !publicRead { + if !o.publicRead { return o.bucket.SignURL(name, http.MethodGet, int64(expire/time.Second), opts...) } rawParams, err := oss.GetRawParams(opts) diff --git a/pkg/common/db/unrelation/mongo.go b/pkg/common/db/unrelation/mongo.go index 09880fb374..363e978675 100644 --- a/pkg/common/db/unrelation/mongo.go +++ b/pkg/common/db/unrelation/mongo.go @@ -36,13 +36,14 @@ const ( ) type Mongo struct { - db *mongo.Client + db *mongo.Client + config *config.GlobalConfig } // NewMongo Initialize MongoDB connection. -func NewMongo() (*Mongo, error) { +func NewMongo(config *config.GlobalConfig) (*Mongo, error) { specialerror.AddReplace(mongo.ErrNoDocuments, errs.ErrRecordNotFound) - uri := buildMongoURI() + uri := buildMongoURI(config) var mongoClient *mongo.Client var err error @@ -56,7 +57,7 @@ func NewMongo() (*Mongo, error) { if err = mongoClient.Ping(ctx, nil); err != nil { return nil, errs.Wrap(err, uri) } - return &Mongo{db: mongoClient}, nil + return &Mongo{db: mongoClient, config: config}, nil } if shouldRetry(err) { time.Sleep(time.Second) // exponential backoff could be implemented here @@ -66,14 +67,14 @@ func NewMongo() (*Mongo, error) { return nil, errs.Wrap(err, uri) } -func buildMongoURI() string { +func buildMongoURI(config *config.GlobalConfig) string { uri := os.Getenv("MONGO_URI") if uri != "" { return uri } - if config.Config.Mongo.Uri != "" { - return config.Config.Mongo.Uri + if config.Mongo.Uri != "" { + return config.Mongo.Uri } username := os.Getenv("MONGO_OPENIM_USERNAME") @@ -84,21 +85,21 @@ func buildMongoURI() string { maxPoolSize := os.Getenv("MONGO_MAX_POOL_SIZE") if username == "" { - username = config.Config.Mongo.Username + username = config.Mongo.Username } if password == "" { - password = config.Config.Mongo.Password + password = config.Mongo.Password } if address == "" { - address = strings.Join(config.Config.Mongo.Address, ",") + address = strings.Join(config.Mongo.Address, ",") } else if port != "" { address = fmt.Sprintf("%s:%s", address, port) } if database == "" { - database = config.Config.Mongo.Database + database = config.Mongo.Database } if maxPoolSize == "" { - maxPoolSize = fmt.Sprint(config.Config.Mongo.MaxPoolSize) + maxPoolSize = fmt.Sprint(config.Mongo.MaxPoolSize) } uriFormat := "mongodb://%s/%s?maxPoolSize=%s" @@ -122,8 +123,8 @@ func (m *Mongo) GetClient() *mongo.Client { } // GetDatabase returns the specific database from MongoDB. -func (m *Mongo) GetDatabase() *mongo.Database { - return m.db.Database(config.Config.Mongo.Database) +func (m *Mongo) GetDatabase(database string) *mongo.Database { + return m.db.Database(database) } // CreateMsgIndex creates an index for messages in MongoDB. @@ -133,7 +134,7 @@ func (m *Mongo) CreateMsgIndex() error { // createMongoIndex creates an index in a MongoDB collection. func (m *Mongo) createMongoIndex(collection string, isUnique bool, keys ...string) error { - db := m.GetDatabase().Collection(collection) + db := m.GetDatabase(m.config.Mongo.Database).Collection(collection) opts := options.CreateIndexes().SetMaxTime(10 * time.Second) indexView := db.Indexes() diff --git a/pkg/common/discoveryregister/direct/directconn.go b/pkg/common/discoveryregister/direct/directconn.go index 2ae0de170b..ced2096026 100644 --- a/pkg/common/discoveryregister/direct/directconn.go +++ b/pkg/common/discoveryregister/direct/directconn.go @@ -27,17 +27,17 @@ import ( type ServiceAddresses map[string][]int -func getServiceAddresses() ServiceAddresses { +func getServiceAddresses(config *config2.GlobalConfig) ServiceAddresses { return ServiceAddresses{ - config2.Config.RpcRegisterName.OpenImUserName: config2.Config.RpcPort.OpenImUserPort, - config2.Config.RpcRegisterName.OpenImFriendName: config2.Config.RpcPort.OpenImFriendPort, - config2.Config.RpcRegisterName.OpenImMsgName: config2.Config.RpcPort.OpenImMessagePort, - config2.Config.RpcRegisterName.OpenImMessageGatewayName: config2.Config.LongConnSvr.OpenImMessageGatewayPort, - config2.Config.RpcRegisterName.OpenImGroupName: config2.Config.RpcPort.OpenImGroupPort, - config2.Config.RpcRegisterName.OpenImAuthName: config2.Config.RpcPort.OpenImAuthPort, - config2.Config.RpcRegisterName.OpenImPushName: config2.Config.RpcPort.OpenImPushPort, - config2.Config.RpcRegisterName.OpenImConversationName: config2.Config.RpcPort.OpenImConversationPort, - config2.Config.RpcRegisterName.OpenImThirdName: config2.Config.RpcPort.OpenImThirdPort, + config.RpcRegisterName.OpenImUserName: config.RpcPort.OpenImUserPort, + config.RpcRegisterName.OpenImFriendName: config.RpcPort.OpenImFriendPort, + config.RpcRegisterName.OpenImMsgName: config.RpcPort.OpenImMessagePort, + config.RpcRegisterName.OpenImMessageGatewayName: config.LongConnSvr.OpenImMessageGatewayPort, + config.RpcRegisterName.OpenImGroupName: config.RpcPort.OpenImGroupPort, + config.RpcRegisterName.OpenImAuthName: config.RpcPort.OpenImAuthPort, + config.RpcRegisterName.OpenImPushName: config.RpcPort.OpenImPushPort, + config.RpcRegisterName.OpenImConversationName: config.RpcPort.OpenImConversationPort, + config.RpcRegisterName.OpenImThirdName: config.RpcPort.OpenImThirdPort, } } @@ -46,6 +46,7 @@ type ConnDirect struct { currentServiceAddress string conns map[string][]*grpc.ClientConn resolverDirect *ResolverDirect + config *config2.GlobalConfig } func (cd *ConnDirect) GetClientLocalConns() map[string][]*grpc.ClientConn { @@ -80,10 +81,11 @@ func (cd *ConnDirect) Close() { } -func NewConnDirect() (*ConnDirect, error) { +func NewConnDirect(config *config2.GlobalConfig) (*ConnDirect, error) { return &ConnDirect{ conns: make(map[string][]*grpc.ClientConn), resolverDirect: NewResolverDirect(), + config: config, }, nil } @@ -93,12 +95,12 @@ func (cd *ConnDirect) GetConns(ctx context.Context, if conns, exists := cd.conns[serviceName]; exists { return conns, nil } - ports := getServiceAddresses()[serviceName] + ports := getServiceAddresses(cd.config)[serviceName] var connections []*grpc.ClientConn for _, port := range ports { - conn, err := cd.dialServiceWithoutResolver(ctx, fmt.Sprintf(config2.Config.Rpc.ListenIP+":%d", port), append(cd.additionalOpts, opts...)...) + conn, err := cd.dialServiceWithoutResolver(ctx, fmt.Sprintf(cd.config.Rpc.ListenIP+":%d", port), append(cd.additionalOpts, opts...)...) if err != nil { - fmt.Printf("connect to port %d failed,serviceName %s, IP %s\n", port, serviceName, config2.Config.Rpc.ListenIP) + fmt.Printf("connect to port %d failed,serviceName %s, IP %s\n", port, serviceName, cd.config.Rpc.ListenIP) } connections = append(connections, conn) } @@ -111,7 +113,7 @@ func (cd *ConnDirect) GetConns(ctx context.Context, func (cd *ConnDirect) GetConn(ctx context.Context, serviceName string, opts ...grpc.DialOption) (*grpc.ClientConn, error) { // Get service addresses - addresses := getServiceAddresses() + addresses := getServiceAddresses(cd.config) address, ok := addresses[serviceName] if !ok { return nil, errs.Wrap(errors.New("unknown service name"), "serviceName", serviceName) @@ -119,9 +121,9 @@ func (cd *ConnDirect) GetConn(ctx context.Context, serviceName string, opts ...g var result string for _, addr := range address { if result != "" { - result = result + "," + fmt.Sprintf(config2.Config.Rpc.ListenIP+":%d", addr) + result = result + "," + fmt.Sprintf(cd.config.Rpc.ListenIP+":%d", addr) } else { - result = fmt.Sprintf(config2.Config.Rpc.ListenIP+":%d", addr) + result = fmt.Sprintf(cd.config.Rpc.ListenIP+":%d", addr) } } // Try to dial a new connection diff --git a/pkg/common/discoveryregister/discoveryregister.go b/pkg/common/discoveryregister/discoveryregister.go index a21d8d62ac..c43583a807 100644 --- a/pkg/common/discoveryregister/discoveryregister.go +++ b/pkg/common/discoveryregister/discoveryregister.go @@ -16,6 +16,7 @@ package discoveryregister import ( "errors" + "github.com/openimsdk/open-im-server/v3/pkg/common/config" "os" "github.com/OpenIMSDK/tools/discoveryregistry" @@ -26,19 +27,19 @@ import ( ) // NewDiscoveryRegister creates a new service discovery and registry client based on the provided environment type. -func NewDiscoveryRegister(envType string) (discoveryregistry.SvcDiscoveryRegistry, error) { +func NewDiscoveryRegister(config *config.GlobalConfig) (discoveryregistry.SvcDiscoveryRegistry, error) { if os.Getenv("ENVS_DISCOVERY") != "" { - envType = os.Getenv("ENVS_DISCOVERY") + config.Envs.Discovery = os.Getenv("ENVS_DISCOVERY") } - switch envType { + switch config.Envs.Discovery { case "zookeeper": - return zookeeper.NewZookeeperDiscoveryRegister() + return zookeeper.NewZookeeperDiscoveryRegister(config) case "k8s": - return kubernetes.NewK8sDiscoveryRegister() + return kubernetes.NewK8sDiscoveryRegister(config.RpcRegisterName.OpenImMessageGatewayName) case "direct": - return direct.NewConnDirect() + return direct.NewConnDirect(config) default: return nil, errs.Wrap(errors.New("envType not correct")) } diff --git a/pkg/common/discoveryregister/discoveryregister_test.go b/pkg/common/discoveryregister/discoveryregister_test.go index e7a5fb276f..7d4fa53cd2 100644 --- a/pkg/common/discoveryregister/discoveryregister_test.go +++ b/pkg/common/discoveryregister/discoveryregister_test.go @@ -15,6 +15,7 @@ package discoveryregister import ( + "github.com/openimsdk/open-im-server/v3/pkg/common/config" "os" "testing" @@ -32,20 +33,23 @@ func setupTestEnvironment() { func TestNewDiscoveryRegister(t *testing.T) { setupTestEnvironment() - + conf := config.NewGlobalConfig() tests := []struct { envType string + gatewayName string expectedError bool expectedResult bool }{ - {"zookeeper", false, true}, - {"k8s", false, true}, // Assume that the k8s configuration is also set up correctly - {"direct", false, true}, - {"invalid", true, false}, + {"zookeeper", "MessageGateway", false, true}, + {"k8s", "MessageGateway", false, true}, + {"direct", "MessageGateway", false, true}, + {"invalid", "MessageGateway", true, false}, } for _, test := range tests { - client, err := NewDiscoveryRegister(test.envType) + conf.Envs.Discovery = test.envType + conf.RpcRegisterName.OpenImMessageGatewayName = test.gatewayName + client, err := NewDiscoveryRegister(conf) if test.expectedError { assert.Error(t, err) diff --git a/pkg/common/discoveryregister/kubernetes/kubernetes.go b/pkg/common/discoveryregister/kubernetes/kubernetes.go index 1292c64a87..b5d603fd17 100644 --- a/pkg/common/discoveryregister/kubernetes/kubernetes.go +++ b/pkg/common/discoveryregister/kubernetes/kubernetes.go @@ -22,11 +22,12 @@ import ( "strconv" "strings" - "github.com/OpenIMSDK/tools/discoveryregistry" - "github.com/OpenIMSDK/tools/log" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/stathat/consistent" + "google.golang.org/grpc" + + "github.com/OpenIMSDK/tools/discoveryregistry" + "github.com/OpenIMSDK/tools/log" ) // K8sDR represents the Kubernetes service discovery and registration client. @@ -34,11 +35,12 @@ type K8sDR struct { options []grpc.DialOption rpcRegisterAddr string gatewayHostConsistent *consistent.Consistent + gatewayName string } -func NewK8sDiscoveryRegister() (discoveryregistry.SvcDiscoveryRegistry, error) { +func NewK8sDiscoveryRegister(gatewayName string) (discoveryregistry.SvcDiscoveryRegistry, error) { gatewayConsistent := consistent.New() - gatewayHosts := getMsgGatewayHost(context.Background()) + gatewayHosts := getMsgGatewayHost(context.Background(), gatewayName) for _, v := range gatewayHosts { gatewayConsistent.Add(v) } @@ -46,10 +48,10 @@ func NewK8sDiscoveryRegister() (discoveryregistry.SvcDiscoveryRegistry, error) { } func (cli *K8sDR) Register(serviceName, host string, port int, opts ...grpc.DialOption) error { - if serviceName != config.Config.RpcRegisterName.OpenImMessageGatewayName { + if serviceName != cli.gatewayName { cli.rpcRegisterAddr = serviceName } else { - cli.rpcRegisterAddr = getSelfHost(context.Background()) + cli.rpcRegisterAddr = getSelfHost(context.Background(), cli.gatewayName) } return nil @@ -81,15 +83,15 @@ func (cli *K8sDR) GetUserIdHashGatewayHost(ctx context.Context, userId string) ( } return host, err } -func getSelfHost(ctx context.Context) string { +func getSelfHost(ctx context.Context, gatewayName string) string { port := 88 instance := "openimserver" selfPodName := os.Getenv("MY_POD_NAME") ns := os.Getenv("MY_POD_NAMESPACE") statefuleIndex := 0 - gatewayEnds := strings.Split(config.Config.RpcRegisterName.OpenImMessageGatewayName, ":") + gatewayEnds := strings.Split(gatewayName, ":") if len(gatewayEnds) != 2 { - log.ZError(ctx, "msggateway RpcRegisterName is error:config.Config.RpcRegisterName.OpenImMessageGatewayName", errors.New("config error")) + log.ZError(ctx, "msggateway RpcRegisterName is error:config.RpcRegisterName.OpenImMessageGatewayName", errors.New("config error")) } else { port, _ = strconv.Atoi(gatewayEnds[1]) } @@ -102,15 +104,15 @@ func getSelfHost(ctx context.Context) string { } // like openimserver-openim-msggateway-0.openimserver-openim-msggateway-headless.openim-lin.svc.cluster.local:88. -func getMsgGatewayHost(ctx context.Context) []string { +func getMsgGatewayHost(ctx context.Context, gatewayName string) []string { port := 88 instance := "openimserver" selfPodName := os.Getenv("MY_POD_NAME") replicas := os.Getenv("MY_MSGGATEWAY_REPLICACOUNT") ns := os.Getenv("MY_POD_NAMESPACE") - gatewayEnds := strings.Split(config.Config.RpcRegisterName.OpenImMessageGatewayName, ":") + gatewayEnds := strings.Split(gatewayName, ":") if len(gatewayEnds) != 2 { - log.ZError(ctx, "msggateway RpcRegisterName is error:config.Config.RpcRegisterName.OpenImMessageGatewayName", errors.New("config error")) + log.ZError(ctx, "msggateway RpcRegisterName is error:config.RpcRegisterName.OpenImMessageGatewayName", errors.New("config error")) } else { port, _ = strconv.Atoi(gatewayEnds[1]) } @@ -131,7 +133,7 @@ func (cli *K8sDR) GetConns(ctx context.Context, serviceName string, opts ...grpc // This conditional checks if the serviceName is not the OpenImMessageGatewayName. // It seems to handle a special case for the OpenImMessageGateway. - if serviceName != config.Config.RpcRegisterName.OpenImMessageGatewayName { + if serviceName != cli.gatewayName { // DialContext creates a client connection to the given target (serviceName) using the specified context. // 'cli.options' are likely default or common options for all connections in this struct. // 'opts...' allows for additional gRPC dial options to be passed and used. @@ -146,7 +148,7 @@ func (cli *K8sDR) GetConns(ctx context.Context, serviceName string, opts ...grpc // getMsgGatewayHost presumably retrieves hosts for the message gateway service. // The context is passed, likely for cancellation and timeout control. - gatewayHosts := getMsgGatewayHost(ctx) + gatewayHosts := getMsgGatewayHost(ctx, cli.gatewayName) // Iterating over the retrieved gateway hosts. for _, host := range gatewayHosts { diff --git a/pkg/common/discoveryregister/zookeeper/zookeeper.go b/pkg/common/discoveryregister/zookeeper/zookeeper.go index 5f9a3b6bda..0aa40a907c 100644 --- a/pkg/common/discoveryregister/zookeeper/zookeeper.go +++ b/pkg/common/discoveryregister/zookeeper/zookeeper.go @@ -28,11 +28,11 @@ import ( ) // NewZookeeperDiscoveryRegister creates a new instance of ZookeeperDR for Zookeeper service discovery and registration. -func NewZookeeperDiscoveryRegister() (discoveryregistry.SvcDiscoveryRegistry, error) { - schema := getEnv("ZOOKEEPER_SCHEMA", config.Config.Zookeeper.Schema) - zkAddr := getZkAddrFromEnv(config.Config.Zookeeper.ZkAddr) - username := getEnv("ZOOKEEPER_USERNAME", config.Config.Zookeeper.Username) - password := getEnv("ZOOKEEPER_PASSWORD", config.Config.Zookeeper.Password) +func NewZookeeperDiscoveryRegister(config *config.GlobalConfig) (discoveryregistry.SvcDiscoveryRegistry, error) { + schema := getEnv("ZOOKEEPER_SCHEMA", config.Zookeeper.Schema) + zkAddr := getZkAddrFromEnv(config.Zookeeper.ZkAddr) + username := getEnv("ZOOKEEPER_USERNAME", config.Zookeeper.Username) + password := getEnv("ZOOKEEPER_PASSWORD", config.Zookeeper.Password) zk, err := openkeeper.NewClient( zkAddr, @@ -46,10 +46,10 @@ func NewZookeeperDiscoveryRegister() (discoveryregistry.SvcDiscoveryRegistry, er if err != nil { uriFormat := "address:%s, username:%s, password:%s, schema:%s." errInfo := fmt.Sprintf(uriFormat, - config.Config.Zookeeper.ZkAddr, - config.Config.Zookeeper.Username, - config.Config.Zookeeper.Password, - config.Config.Zookeeper.Schema) + config.Zookeeper.ZkAddr, + config.Zookeeper.Username, + config.Zookeeper.Password, + config.Zookeeper.Schema) return nil, errs.Wrap(err, errInfo) } return zk, nil diff --git a/pkg/common/kafka/consumer.go b/pkg/common/kafka/consumer.go index d0e06d4823..664e5d4684 100644 --- a/pkg/common/kafka/consumer.go +++ b/pkg/common/kafka/consumer.go @@ -17,6 +17,8 @@ package kafka import ( "sync" + "github.com/openimsdk/open-im-server/v3/pkg/common/config" + "github.com/IBM/sarama" "github.com/OpenIMSDK/tools/errs" ) @@ -29,22 +31,31 @@ type Consumer struct { Consumer sarama.Consumer } -func NewKafkaConsumer(addr []string, topic string, kafkaConfig *sarama.Config) (*Consumer, error) { - p := Consumer{ - Topic: topic, - addr: addr, +func NewKafkaConsumer(addr []string, topic string, config *config.GlobalConfig) (*Consumer,error) { + p := Consumer{} + p.Topic = topic + p.addr = addr + consumerConfig := sarama.NewConfig() + if config.Kafka.Username != "" && config.Kafka.Password != "" { + consumerConfig.Net.SASL.Enable = true + consumerConfig.Net.SASL.User = config.Kafka.Username + consumerConfig.Net.SASL.Password = config.Kafka.Password } - - if kafkaConfig.Net.SASL.User != "" && kafkaConfig.Net.SASL.Password != "" { - kafkaConfig.Net.SASL.Enable = true + var tlsConfig *TLSConfig + if config.Kafka.TLS != nil { + tlsConfig = &TLSConfig{ + CACrt: config.Kafka.TLS.CACrt, + ClientCrt: config.Kafka.TLS.ClientCrt, + ClientKey: config.Kafka.TLS.ClientKey, + ClientKeyPwd: config.Kafka.TLS.ClientKeyPwd, + InsecureSkipVerify: false, + } } - - err := SetupTLSConfig(kafkaConfig) - if err != nil { - return nil, err + err:=SetupTLSConfig(consumerConfig, tlsConfig) + if err!=nil{ + return nil,err } - - consumer, err := sarama.NewConsumer(p.addr, kafkaConfig) + consumer, err := sarama.NewConsumer(p.addr, consumerConfig) if err != nil { return nil, errs.Wrap(err, "NewKafkaConsumer: creating consumer failed") } diff --git a/pkg/common/kafka/consumer_group.go b/pkg/common/kafka/consumer_group.go index 824c5be2e0..b6b4435ab8 100644 --- a/pkg/common/kafka/consumer_group.go +++ b/pkg/common/kafka/consumer_group.go @@ -17,12 +17,12 @@ package kafka import ( "context" "errors" - "strings" "github.com/IBM/sarama" "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/log" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" + + "strings" ) type MConsumerGroup struct { @@ -35,22 +35,25 @@ type MConsumerGroupConfig struct { KafkaVersion sarama.KafkaVersion OffsetsInitial int64 IsReturnErr bool + UserName string + Password string } -func NewMConsumerGroup(consumerConfig *MConsumerGroupConfig, topics, addrs []string, groupID string) (*MConsumerGroup, error) { +func NewMConsumerGroup(consumerConfig *MConsumerGroupConfig, topics, addrs []string, groupID string, tlsConfig *TLSConfig) (*MConsumerGroup, error) { consumerGroupConfig := sarama.NewConfig() consumerGroupConfig.Version = consumerConfig.KafkaVersion consumerGroupConfig.Consumer.Offsets.Initial = consumerConfig.OffsetsInitial consumerGroupConfig.Consumer.Return.Errors = consumerConfig.IsReturnErr - if config.Config.Kafka.Username != "" && config.Config.Kafka.Password != "" { + if consumerConfig.UserName != "" && consumerConfig.Password != "" { consumerGroupConfig.Net.SASL.Enable = true - consumerGroupConfig.Net.SASL.User = config.Config.Kafka.Username - consumerGroupConfig.Net.SASL.Password = config.Config.Kafka.Password + consumerGroupConfig.Net.SASL.User = consumerConfig.UserName + consumerGroupConfig.Net.SASL.Password = consumerConfig.Password } - SetupTLSConfig(consumerGroupConfig) + + SetupTLSConfig(consumerGroupConfig, tlsConfig) consumerGroup, err := sarama.NewConsumerGroup(addrs, groupID, consumerGroupConfig) if err != nil { - return nil, errs.Wrap(err, strings.Join(topics, ","), strings.Join(addrs, ","), groupID, config.Config.Kafka.Username, config.Config.Kafka.Password) + return nil, errs.Wrap(err, strings.Join(topics, ","), strings.Join(addrs, ","), groupID, consumerConfig.UserName, consumerConfig.Password) } return &MConsumerGroup{ diff --git a/pkg/common/kafka/producer.go b/pkg/common/kafka/producer.go index 4c2378c59e..afc53b35a2 100644 --- a/pkg/common/kafka/producer.go +++ b/pkg/common/kafka/producer.go @@ -22,12 +22,12 @@ import ( "strings" "time" + "github.com/OpenIMSDK/tools/errs" + "github.com/IBM/sarama" "github.com/OpenIMSDK/protocol/constant" - "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/mcontext" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" "google.golang.org/protobuf/proto" ) @@ -43,8 +43,15 @@ type Producer struct { producer sarama.SyncProducer } +type ProducerConfig struct { + ProducerAck string + CompressType string + Username string + Password string +} + // NewKafkaProducer initializes a new Kafka producer. -func NewKafkaProducer(addr []string, topic string) (*Producer, error) { +func NewKafkaProducer(addr []string, topic string, producerConfig *ProducerConfig, tlsConfig *TLSConfig) (*Producer, error) { p := Producer{ addr: addr, topic: topic, @@ -59,14 +66,14 @@ func NewKafkaProducer(addr []string, topic string) (*Producer, error) { p.config.Producer.Partitioner = sarama.NewHashPartitioner // Configure producer acknowledgement level - configureProducerAck(&p, config.Config.Kafka.ProducerAck) + configureProducerAck(&p, producerConfig.ProducerAck) // Configure message compression - configureCompression(&p, config.Config.Kafka.CompressType) + configureCompression(&p, producerConfig.CompressType) // Get Kafka configuration from environment variables or fallback to config file - kafkaUsername := getEnvOrConfig("KAFKA_USERNAME", config.Config.Kafka.Username) - kafkaPassword := getEnvOrConfig("KAFKA_PASSWORD", config.Config.Kafka.Password) + kafkaUsername := getEnvOrConfig("KAFKA_USERNAME", producerConfig.Username) + kafkaPassword := getEnvOrConfig("KAFKA_PASSWORD", producerConfig.Password) kafkaAddr := getKafkaAddrFromEnv(addr) // Updated to use the new function // Configure SASL authentication if credentials are provided @@ -80,7 +87,7 @@ func NewKafkaProducer(addr []string, topic string) (*Producer, error) { p.addr = kafkaAddr // Set up TLS configuration (if required) - SetupTLSConfig(p.config) + SetupTLSConfig(p.config, tlsConfig) // Create the producer with retries var err error diff --git a/pkg/common/kafka/util.go b/pkg/common/kafka/util.go index a94397819b..4e2a027143 100644 --- a/pkg/common/kafka/util.go +++ b/pkg/common/kafka/util.go @@ -20,19 +20,27 @@ import ( "strings" "github.com/IBM/sarama" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/tls" ) +type TLSConfig struct { + CACrt string + ClientCrt string + ClientKey string + ClientKeyPwd string + InsecureSkipVerify bool +} + // SetupTLSConfig set up the TLS config from config file. -func SetupTLSConfig(cfg *sarama.Config) error { - if config.Config.Kafka.TLS != nil { +func SetupTLSConfig(cfg *sarama.Config, tlsConfig *TLSConfig) error { + if tlsConfig != nil { cfg.Net.TLS.Enable = true tlsConfig, err := tls.NewTLSConfig( - config.Config.Kafka.TLS.ClientCrt, - config.Config.Kafka.TLS.ClientKey, - config.Config.Kafka.TLS.CACrt, - []byte(config.Config.Kafka.TLS.ClientKeyPwd), + tlsConfig.ClientCrt, + tlsConfig.ClientKey, + tlsConfig.CACrt, + []byte(tlsConfig.ClientKeyPwd), + tlsConfig.InsecureSkipVerify, ) if err != nil { return err diff --git a/pkg/common/prommetrics/prommetrics.go b/pkg/common/prommetrics/prommetrics.go index 52694168f9..9089e7b5fe 100644 --- a/pkg/common/prommetrics/prommetrics.go +++ b/pkg/common/prommetrics/prommetrics.go @@ -31,17 +31,17 @@ func NewGrpcPromObj(cusMetrics []prometheus.Collector) (*prometheus.Registry, *g return reg, grpcMetrics, nil } -func GetGrpcCusMetrics(registerName string) []prometheus.Collector { +func GetGrpcCusMetrics(registerName string, config *config2.GlobalConfig) []prometheus.Collector { switch registerName { - case config2.Config.RpcRegisterName.OpenImMessageGatewayName: + case config.RpcRegisterName.OpenImMessageGatewayName: return []prometheus.Collector{OnlineUserGauge} - case config2.Config.RpcRegisterName.OpenImMsgName: + case config.RpcRegisterName.OpenImMsgName: return []prometheus.Collector{SingleChatMsgProcessSuccessCounter, SingleChatMsgProcessFailedCounter, GroupChatMsgProcessSuccessCounter, GroupChatMsgProcessFailedCounter} case "Transfer": return []prometheus.Collector{MsgInsertRedisSuccessCounter, MsgInsertRedisFailedCounter, MsgInsertMongoSuccessCounter, MsgInsertMongoFailedCounter, SeqSetFailedCounter} - case config2.Config.RpcRegisterName.OpenImPushName: + case config.RpcRegisterName.OpenImPushName: return []prometheus.Collector{MsgOfflinePushFailedCounter} - case config2.Config.RpcRegisterName.OpenImAuthName: + case config.RpcRegisterName.OpenImAuthName: return []prometheus.Collector{UserLoginCounter} default: return nil diff --git a/pkg/common/prommetrics/prommetrics_test.go b/pkg/common/prommetrics/prommetrics_test.go index 1e48c63baf..eb6f3c7716 100644 --- a/pkg/common/prommetrics/prommetrics_test.go +++ b/pkg/common/prommetrics/prommetrics_test.go @@ -58,17 +58,20 @@ func TestNewGrpcPromObj(t *testing.T) { } func TestGetGrpcCusMetrics(t *testing.T) { + conf := config2.NewGlobalConfig() + + config2.InitConfig(conf, "../../config") // Test various cases based on the switch statement in the GetGrpcCusMetrics function. testCases := []struct { name string expected int // The expected number of metrics for each case. }{ - {config2.Config.RpcRegisterName.OpenImMessageGatewayName, 1}, + {conf.RpcRegisterName.OpenImMessageGatewayName, 1}, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - metrics := GetGrpcCusMetrics(tc.name) + metrics := GetGrpcCusMetrics(tc.name, conf) assert.Len(t, metrics, tc.expected) }) } diff --git a/pkg/common/startrpc/start.go b/pkg/common/startrpc/start.go index 1576762e8c..8af894ac0c 100644 --- a/pkg/common/startrpc/start.go +++ b/pkg/common/startrpc/start.go @@ -18,6 +18,7 @@ import ( "context" "errors" "fmt" + "github.com/openimsdk/open-im-server/v3/pkg/common/config" "net" "net/http" "os" @@ -27,19 +28,25 @@ import ( "syscall" "time" - "github.com/OpenIMSDK/tools/discoveryregistry" "github.com/OpenIMSDK/tools/errs" - "github.com/OpenIMSDK/tools/mw" - "github.com/OpenIMSDK/tools/network" - grpcprometheus "github.com/grpc-ecosystem/go-grpc-prometheus" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" - kdisc "github.com/openimsdk/open-im-server/v3/pkg/common/discoveryregister" - "github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics" + util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" + "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promhttp" + + config2 "github.com/openimsdk/open-im-server/v3/pkg/common/config" + "github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics" + + grpcprometheus "github.com/grpc-ecosystem/go-grpc-prometheus" "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" + + kdisc "github.com/openimsdk/open-im-server/v3/pkg/common/discoveryregister" + + "github.com/OpenIMSDK/tools/discoveryregistry" + "github.com/OpenIMSDK/tools/mw" + "github.com/OpenIMSDK/tools/network" ) // Start rpc server. @@ -47,37 +54,38 @@ func Start( rpcPort int, rpcRegisterName string, prometheusPort int, - rpcFn func(client discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) error, + config *config2.GlobalConfig, + rpcFn func(config *config.GlobalConfig, client discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) error, options ...grpc.ServerOption, ) error { fmt.Printf("start %s server, port: %d, prometheusPort: %d, OpenIM version: %s\n", - rpcRegisterName, rpcPort, prometheusPort, config.Version) - rpcTcpAddr := net.JoinHostPort(network.GetListenIP(config.Config.Rpc.ListenIP), strconv.Itoa(rpcPort)) + rpcRegisterName, rpcPort, prometheusPort, config2.Version) + rpcTcpAddr := net.JoinHostPort(network.GetListenIP(config.Rpc.ListenIP), strconv.Itoa(rpcPort)) listener, err := net.Listen( "tcp", rpcTcpAddr, ) if err != nil { - return errs.Wrap(err, "rpc start err", rpcTcpAddr) + return errs.Wrap(err, "listen err", rpcTcpAddr) } defer listener.Close() - client, err := kdisc.NewDiscoveryRegister(config.Config.Envs.Discovery) + client, err := kdisc.NewDiscoveryRegister(config) if err != nil { return err } defer client.Close() client.AddOption(mw.GrpcClient(), grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithDefaultServiceConfig(fmt.Sprintf(`{"LoadBalancingPolicy": "%s"}`, "round_robin"))) - registerIP, err := network.GetRpcRegisterIP(config.Config.Rpc.RegisterIP) + registerIP, err := network.GetRpcRegisterIP(config.Rpc.RegisterIP) if err != nil { return errs.Wrap(err) } var reg *prometheus.Registry var metric *grpcprometheus.ServerMetrics - if config.Config.Prometheus.Enable { - cusMetrics := prommetrics.GetGrpcCusMetrics(rpcRegisterName) + if config.Prometheus.Enable { + cusMetrics := prommetrics.GetGrpcCusMetrics(rpcRegisterName, config) reg, metric, _ = prommetrics.NewGrpcPromObj(cusMetrics) options = append(options, mw.GrpcServer(), grpc.StreamInterceptor(metric.StreamServerInterceptor()), grpc.UnaryInterceptor(metric.UnaryServerInterceptor())) @@ -91,7 +99,7 @@ func Start( once.Do(srv.GracefulStop) }() - err = rpcFn(client, srv) + err = rpcFn(config, client, srv) if err != nil { return err } @@ -111,7 +119,7 @@ func Start( httpServer *http.Server ) go func() { - if config.Config.Prometheus.Enable && prometheusPort != 0 { + if config.Prometheus.Enable && prometheusPort != 0 { metric.InitializeMetrics(srv) // Create a HTTP server for prometheus. httpServer = &http.Server{Handler: promhttp.HandlerFor(reg, promhttp.HandlerOpts{}), Addr: fmt.Sprintf("0.0.0.0:%d", prometheusPort)} diff --git a/pkg/common/startrpc/start_test.go b/pkg/common/startrpc/start_test.go index 481986e154..e5e37e2212 100644 --- a/pkg/common/startrpc/start_test.go +++ b/pkg/common/startrpc/start_test.go @@ -16,6 +16,7 @@ package startrpc import ( "fmt" + "github.com/openimsdk/open-im-server/v3/pkg/common/config" "net" "testing" "time" @@ -25,7 +26,7 @@ import ( ) // mockRpcFn is a mock gRPC function for testing. -func mockRpcFn(client discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) error { +func mockRpcFn(config *config.GlobalConfig, client discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) error { // Implement a mock gRPC service registration logic if needed return nil } @@ -40,7 +41,8 @@ func TestStart(t *testing.T) { doneChan := make(chan error, 1) go func() { - err := Start(testRpcPort, testRpcRegisterName, testPrometheusPort, mockRpcFn) + err := Start(testRpcPort, testRpcRegisterName, testPrometheusPort, + config.NewGlobalConfig(), mockRpcFn) doneChan <- err }() diff --git a/pkg/common/tls/tls.go b/pkg/common/tls/tls.go old mode 100644 new mode 100755 index a52f46df72..7369137583 --- a/pkg/common/tls/tls.go +++ b/pkg/common/tls/tls.go @@ -22,7 +22,6 @@ import ( "os" "github.com/OpenIMSDK/tools/errs" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" ) // decryptPEM decrypts a PEM block using a password. @@ -50,15 +49,14 @@ func readEncryptablePEMBlock(path string, pwd []byte) ([]byte, error) { } // NewTLSConfig setup the TLS config from general config file. -func NewTLSConfig(clientCertFile, clientKeyFile, caCertFile string, keyPwd []byte) (*tls.Config, error) { - var tlsConfig tls.Config +func NewTLSConfig(clientCertFile, clientKeyFile, caCertFile string, keyPwd []byte, insecureSkipVerify bool) (*tls.Config,error) { + tlsConfig := tls.Config{} if clientCertFile != "" && clientKeyFile != "" { certPEMBlock, err := os.ReadFile(clientCertFile) if err != nil { return nil, errs.Wrap(err, "NewTLSConfig: failed to read client cert file") } - keyPEMBlock, err := readEncryptablePEMBlock(clientKeyFile, keyPwd) if err != nil { return nil, err @@ -84,7 +82,7 @@ func NewTLSConfig(clientCertFile, clientKeyFile, caCertFile string, keyPwd []byt tlsConfig.RootCAs = caCertPool } - tlsConfig.InsecureSkipVerify = config.Config.Kafka.TLS.InsecureSkipVerify + tlsConfig.InsecureSkipVerify = insecureSkipVerify return &tlsConfig, nil } diff --git a/pkg/rpcclient/auth.go b/pkg/rpcclient/auth.go index bfd4b1119f..24597120fd 100644 --- a/pkg/rpcclient/auth.go +++ b/pkg/rpcclient/auth.go @@ -24,17 +24,18 @@ import ( "google.golang.org/grpc" ) -func NewAuth(discov discoveryregistry.SvcDiscoveryRegistry) *Auth { - conn, err := discov.GetConn(context.Background(), config.Config.RpcRegisterName.OpenImAuthName) +func NewAuth(discov discoveryregistry.SvcDiscoveryRegistry, config *config.GlobalConfig) *Auth { + conn, err := discov.GetConn(context.Background(), config.RpcRegisterName.OpenImAuthName) if err != nil { util.ExitWithError(err) } client := auth.NewAuthClient(conn) - return &Auth{discov: discov, conn: conn, Client: client} + return &Auth{discov: discov, conn: conn, Client: client, Config: config} } type Auth struct { conn grpc.ClientConnInterface Client auth.AuthClient discov discoveryregistry.SvcDiscoveryRegistry + Config *config.GlobalConfig } diff --git a/pkg/rpcclient/conversation.go b/pkg/rpcclient/conversation.go index ee9818f8fc..6981844b6b 100644 --- a/pkg/rpcclient/conversation.go +++ b/pkg/rpcclient/conversation.go @@ -30,21 +30,22 @@ type Conversation struct { Client pbconversation.ConversationClient conn grpc.ClientConnInterface discov discoveryregistry.SvcDiscoveryRegistry + Config *config.GlobalConfig } -func NewConversation(discov discoveryregistry.SvcDiscoveryRegistry) *Conversation { - conn, err := discov.GetConn(context.Background(), config.Config.RpcRegisterName.OpenImConversationName) +func NewConversation(discov discoveryregistry.SvcDiscoveryRegistry, config *config.GlobalConfig) *Conversation { + conn, err := discov.GetConn(context.Background(), config.RpcRegisterName.OpenImConversationName) if err != nil { util.ExitWithError(err) } client := pbconversation.NewConversationClient(conn) - return &Conversation{discov: discov, conn: conn, Client: client} + return &Conversation{discov: discov, conn: conn, Client: client, Config: config} } type ConversationRpcClient Conversation -func NewConversationRpcClient(discov discoveryregistry.SvcDiscoveryRegistry) ConversationRpcClient { - return ConversationRpcClient(*NewConversation(discov)) +func NewConversationRpcClient(discov discoveryregistry.SvcDiscoveryRegistry, config *config.GlobalConfig) ConversationRpcClient { + return ConversationRpcClient(*NewConversation(discov, config)) } func (c *ConversationRpcClient) GetSingleConversationRecvMsgOpt(ctx context.Context, userID, conversationID string) (int32, error) { diff --git a/pkg/rpcclient/friend.go b/pkg/rpcclient/friend.go index 5206165645..e1f6ed0764 100644 --- a/pkg/rpcclient/friend.go +++ b/pkg/rpcclient/friend.go @@ -29,21 +29,22 @@ type Friend struct { conn grpc.ClientConnInterface Client friend.FriendClient discov discoveryregistry.SvcDiscoveryRegistry + Config *config.GlobalConfig } -func NewFriend(discov discoveryregistry.SvcDiscoveryRegistry) *Friend { - conn, err := discov.GetConn(context.Background(), config.Config.RpcRegisterName.OpenImFriendName) +func NewFriend(discov discoveryregistry.SvcDiscoveryRegistry, config *config.GlobalConfig) *Friend { + conn, err := discov.GetConn(context.Background(), config.RpcRegisterName.OpenImFriendName) if err != nil { util.ExitWithError(err) } client := friend.NewFriendClient(conn) - return &Friend{discov: discov, conn: conn, Client: client} + return &Friend{discov: discov, conn: conn, Client: client, Config: config} } type FriendRpcClient Friend -func NewFriendRpcClient(discov discoveryregistry.SvcDiscoveryRegistry) FriendRpcClient { - return FriendRpcClient(*NewFriend(discov)) +func NewFriendRpcClient(discov discoveryregistry.SvcDiscoveryRegistry, config *config.GlobalConfig) FriendRpcClient { + return FriendRpcClient(*NewFriend(discov, config)) } func (f *FriendRpcClient) GetFriendsInfo( diff --git a/pkg/rpcclient/group.go b/pkg/rpcclient/group.go index bc9a3c75c3..7736378587 100644 --- a/pkg/rpcclient/group.go +++ b/pkg/rpcclient/group.go @@ -33,21 +33,22 @@ type Group struct { conn grpc.ClientConnInterface Client group.GroupClient discov discoveryregistry.SvcDiscoveryRegistry + Config *config.GlobalConfig } -func NewGroup(discov discoveryregistry.SvcDiscoveryRegistry) *Group { - conn, err := discov.GetConn(context.Background(), config.Config.RpcRegisterName.OpenImGroupName) +func NewGroup(discov discoveryregistry.SvcDiscoveryRegistry, config *config.GlobalConfig) *Group { + conn, err := discov.GetConn(context.Background(), config.RpcRegisterName.OpenImGroupName) if err != nil { util.ExitWithError(err) } client := group.NewGroupClient(conn) - return &Group{discov: discov, conn: conn, Client: client} + return &Group{discov: discov, conn: conn, Client: client, Config: config} } type GroupRpcClient Group -func NewGroupRpcClient(discov discoveryregistry.SvcDiscoveryRegistry) GroupRpcClient { - return GroupRpcClient(*NewGroup(discov)) +func NewGroupRpcClient(discov discoveryregistry.SvcDiscoveryRegistry, config *config.GlobalConfig) GroupRpcClient { + return GroupRpcClient(*NewGroup(discov, config)) } func (g *GroupRpcClient) GetGroupInfos( diff --git a/pkg/rpcclient/msg.go b/pkg/rpcclient/msg.go index e4008ed200..3db39925ed 100644 --- a/pkg/rpcclient/msg.go +++ b/pkg/rpcclient/msg.go @@ -17,6 +17,8 @@ package rpcclient import ( "context" "encoding/json" + "fmt" + "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/protocol/msg" @@ -29,47 +31,47 @@ import ( "google.golang.org/protobuf/proto" ) -func newContentTypeConf() map[int32]config.NotificationConf { +func newContentTypeConf(conf *config.GlobalConfig) map[int32]config.NotificationConf { return map[int32]config.NotificationConf{ // group - constant.GroupCreatedNotification: config.Config.Notification.GroupCreated, - constant.GroupInfoSetNotification: config.Config.Notification.GroupInfoSet, - constant.JoinGroupApplicationNotification: config.Config.Notification.JoinGroupApplication, - constant.MemberQuitNotification: config.Config.Notification.MemberQuit, - constant.GroupApplicationAcceptedNotification: config.Config.Notification.GroupApplicationAccepted, - constant.GroupApplicationRejectedNotification: config.Config.Notification.GroupApplicationRejected, - constant.GroupOwnerTransferredNotification: config.Config.Notification.GroupOwnerTransferred, - constant.MemberKickedNotification: config.Config.Notification.MemberKicked, - constant.MemberInvitedNotification: config.Config.Notification.MemberInvited, - constant.MemberEnterNotification: config.Config.Notification.MemberEnter, - constant.GroupDismissedNotification: config.Config.Notification.GroupDismissed, - constant.GroupMutedNotification: config.Config.Notification.GroupMuted, - constant.GroupCancelMutedNotification: config.Config.Notification.GroupCancelMuted, - constant.GroupMemberMutedNotification: config.Config.Notification.GroupMemberMuted, - constant.GroupMemberCancelMutedNotification: config.Config.Notification.GroupMemberCancelMuted, - constant.GroupMemberInfoSetNotification: config.Config.Notification.GroupMemberInfoSet, - constant.GroupMemberSetToAdminNotification: config.Config.Notification.GroupMemberSetToAdmin, - constant.GroupMemberSetToOrdinaryUserNotification: config.Config.Notification.GroupMemberSetToOrdinary, - constant.GroupInfoSetAnnouncementNotification: config.Config.Notification.GroupInfoSetAnnouncement, - constant.GroupInfoSetNameNotification: config.Config.Notification.GroupInfoSetName, + constant.GroupCreatedNotification: conf.Notification.GroupCreated, + constant.GroupInfoSetNotification: conf.Notification.GroupInfoSet, + constant.JoinGroupApplicationNotification: conf.Notification.JoinGroupApplication, + constant.MemberQuitNotification: conf.Notification.MemberQuit, + constant.GroupApplicationAcceptedNotification: conf.Notification.GroupApplicationAccepted, + constant.GroupApplicationRejectedNotification: conf.Notification.GroupApplicationRejected, + constant.GroupOwnerTransferredNotification: conf.Notification.GroupOwnerTransferred, + constant.MemberKickedNotification: conf.Notification.MemberKicked, + constant.MemberInvitedNotification: conf.Notification.MemberInvited, + constant.MemberEnterNotification: conf.Notification.MemberEnter, + constant.GroupDismissedNotification: conf.Notification.GroupDismissed, + constant.GroupMutedNotification: conf.Notification.GroupMuted, + constant.GroupCancelMutedNotification: conf.Notification.GroupCancelMuted, + constant.GroupMemberMutedNotification: conf.Notification.GroupMemberMuted, + constant.GroupMemberCancelMutedNotification: conf.Notification.GroupMemberCancelMuted, + constant.GroupMemberInfoSetNotification: conf.Notification.GroupMemberInfoSet, + constant.GroupMemberSetToAdminNotification: conf.Notification.GroupMemberSetToAdmin, + constant.GroupMemberSetToOrdinaryUserNotification: conf.Notification.GroupMemberSetToOrdinary, + constant.GroupInfoSetAnnouncementNotification: conf.Notification.GroupInfoSetAnnouncement, + constant.GroupInfoSetNameNotification: conf.Notification.GroupInfoSetName, // user - constant.UserInfoUpdatedNotification: config.Config.Notification.UserInfoUpdated, - constant.UserStatusChangeNotification: config.Config.Notification.UserStatusChanged, + constant.UserInfoUpdatedNotification: conf.Notification.UserInfoUpdated, + constant.UserStatusChangeNotification: conf.Notification.UserStatusChanged, // friend - constant.FriendApplicationNotification: config.Config.Notification.FriendApplicationAdded, - constant.FriendApplicationApprovedNotification: config.Config.Notification.FriendApplicationApproved, - constant.FriendApplicationRejectedNotification: config.Config.Notification.FriendApplicationRejected, - constant.FriendAddedNotification: config.Config.Notification.FriendAdded, - constant.FriendDeletedNotification: config.Config.Notification.FriendDeleted, - constant.FriendRemarkSetNotification: config.Config.Notification.FriendRemarkSet, - constant.BlackAddedNotification: config.Config.Notification.BlackAdded, - constant.BlackDeletedNotification: config.Config.Notification.BlackDeleted, - constant.FriendInfoUpdatedNotification: config.Config.Notification.FriendInfoUpdated, - constant.FriendsInfoUpdateNotification: config.Config.Notification.FriendInfoUpdated, //use the same FriendInfoUpdated + constant.FriendApplicationNotification: conf.Notification.FriendApplicationAdded, + constant.FriendApplicationApprovedNotification: conf.Notification.FriendApplicationApproved, + constant.FriendApplicationRejectedNotification: conf.Notification.FriendApplicationRejected, + constant.FriendAddedNotification: conf.Notification.FriendAdded, + constant.FriendDeletedNotification: conf.Notification.FriendDeleted, + constant.FriendRemarkSetNotification: conf.Notification.FriendRemarkSet, + constant.BlackAddedNotification: conf.Notification.BlackAdded, + constant.BlackDeletedNotification: conf.Notification.BlackDeleted, + constant.FriendInfoUpdatedNotification: conf.Notification.FriendInfoUpdated, + constant.FriendsInfoUpdateNotification: conf.Notification.FriendInfoUpdated, //use the same FriendInfoUpdated // conversation - constant.ConversationChangeNotification: config.Config.Notification.ConversationChanged, - constant.ConversationUnreadNotification: config.Config.Notification.ConversationChanged, - constant.ConversationPrivateChatNotification: config.Config.Notification.ConversationSetPrivate, + constant.ConversationChangeNotification: conf.Notification.ConversationChanged, + constant.ConversationUnreadNotification: conf.Notification.ConversationChanged, + constant.ConversationPrivateChatNotification: conf.Notification.ConversationSetPrivate, // msg constant.MsgRevokeNotification: {IsSendMsg: false, ReliabilityLevel: constant.ReliableNotificationNoMsg}, constant.HasReadReceipt: {IsSendMsg: false, ReliabilityLevel: constant.ReliableNotificationNoMsg}, @@ -127,21 +129,22 @@ type Message struct { conn grpc.ClientConnInterface Client msg.MsgClient discov discoveryregistry.SvcDiscoveryRegistry + Config *config.GlobalConfig } -func NewMessage(discov discoveryregistry.SvcDiscoveryRegistry) *Message { - conn, err := discov.GetConn(context.Background(), config.Config.RpcRegisterName.OpenImMsgName) +func NewMessage(discov discoveryregistry.SvcDiscoveryRegistry, config *config.GlobalConfig) *Message { + conn, err := discov.GetConn(context.Background(), config.RpcRegisterName.OpenImMsgName) if err != nil { panic(err) } client := msg.NewMsgClient(conn) - return &Message{discov: discov, conn: conn, Client: client} + return &Message{discov: discov, conn: conn, Client: client, Config: config} } type MessageRpcClient Message -func NewMessageRpcClient(discov discoveryregistry.SvcDiscoveryRegistry) MessageRpcClient { - return MessageRpcClient(*NewMessage(discov)) +func NewMessageRpcClient(discov discoveryregistry.SvcDiscoveryRegistry, config *config.GlobalConfig) MessageRpcClient { + return MessageRpcClient(*NewMessage(discov, config)) } // SendMsg sends a message through the gRPC client and returns the response. @@ -234,8 +237,8 @@ func WithUserRpcClient(userRpcClient *UserRpcClient) NotificationSenderOptions { } } -func NewNotificationSender(opts ...NotificationSenderOptions) *NotificationSender { - notificationSender := &NotificationSender{contentTypeConf: newContentTypeConf(), sessionTypeConf: newSessionTypeConf()} +func NewNotificationSender(config *config.GlobalConfig, opts ...NotificationSenderOptions) *NotificationSender { + notificationSender := &NotificationSender{contentTypeConf: newContentTypeConf(config), sessionTypeConf: newSessionTypeConf()} for _, opt := range opts { opt(notificationSender) } @@ -258,8 +261,8 @@ func (s *NotificationSender) NotificationWithSesstionType(ctx context.Context, s n := sdkws.NotificationElem{Detail: utils.StructToJsonString(m)} content, err := json.Marshal(&n) if err != nil { - log.ZError(ctx, "MsgClient Notification json.Marshal failed", err, "sendID", sendID, "recvID", recvID, "contentType", contentType, "msg", m) - return err + errInfo := fmt.Sprintf("MsgClient Notification json.Marshal failed, sendID:%s, recvID:%s, contentType:%d, msg:%s", sendID, recvID, contentType, m) + return errs.Wrap(err, errInfo) } notificationOpt := ¬ificationOpt{} for _, opt := range opts { @@ -271,7 +274,8 @@ func (s *NotificationSender) NotificationWithSesstionType(ctx context.Context, s if notificationOpt.WithRpcGetUsername && s.getUserInfo != nil { userInfo, err = s.getUserInfo(ctx, sendID) if err != nil { - log.ZWarn(ctx, "getUserInfo failed", err, "sendID", sendID) + errInfo := fmt.Sprintf("getUserInfo failed, sendID:%s", sendID) + return errs.Wrap(err, errInfo) } else { msg.SenderNickname = userInfo.Nickname msg.SenderFaceURL = userInfo.FaceURL @@ -303,10 +307,9 @@ func (s *NotificationSender) NotificationWithSesstionType(ctx context.Context, s msg.OfflinePushInfo = &offlineInfo req.MsgData = &msg _, err = s.sendMsg(ctx, &req) - if err == nil { - log.ZDebug(ctx, "MsgClient Notification SendMsg success", "req", &req) - } else { - log.ZError(ctx, "MsgClient Notification SendMsg failed", err, "req", &req) + if err != nil { + errInfo := fmt.Sprintf("MsgClient Notification SendMsg failed, req:%s", &req) + return errs.Wrap(err, errInfo) } return err } diff --git a/pkg/rpcclient/notification/conversation.go b/pkg/rpcclient/notification/conversation.go index b43e5494a9..115fb81a24 100644 --- a/pkg/rpcclient/notification/conversation.go +++ b/pkg/rpcclient/notification/conversation.go @@ -16,6 +16,7 @@ package notification import ( "context" + "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/protocol/sdkws" @@ -26,8 +27,8 @@ type ConversationNotificationSender struct { *rpcclient.NotificationSender } -func NewConversationNotificationSender(msgRpcClient *rpcclient.MessageRpcClient) *ConversationNotificationSender { - return &ConversationNotificationSender{rpcclient.NewNotificationSender(rpcclient.WithRpcClient(msgRpcClient))} +func NewConversationNotificationSender(config *config.GlobalConfig, msgRpcClient *rpcclient.MessageRpcClient) *ConversationNotificationSender { + return &ConversationNotificationSender{rpcclient.NewNotificationSender(config, rpcclient.WithRpcClient(msgRpcClient))} } // SetPrivate invote. diff --git a/pkg/rpcclient/notification/friend.go b/pkg/rpcclient/notification/friend.go index 9237111be8..31426da317 100644 --- a/pkg/rpcclient/notification/friend.go +++ b/pkg/rpcclient/notification/friend.go @@ -16,6 +16,7 @@ package notification import ( "context" + "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/OpenIMSDK/protocol/constant" pbfriend "github.com/OpenIMSDK/protocol/friend" @@ -80,11 +81,12 @@ func WithRpcFunc( } func NewFriendNotificationSender( + config *config.GlobalConfig, msgRpcClient *rpcclient.MessageRpcClient, opts ...friendNotificationSenderOptions, ) *FriendNotificationSender { f := &FriendNotificationSender{ - NotificationSender: rpcclient.NewNotificationSender(rpcclient.WithRpcClient(msgRpcClient)), + NotificationSender: rpcclient.NewNotificationSender(config, rpcclient.WithRpcClient(msgRpcClient)), } for _, opt := range opts { opt(f) diff --git a/pkg/rpcclient/notification/group.go b/pkg/rpcclient/notification/group.go index 1778a498d3..5500f4f433 100644 --- a/pkg/rpcclient/notification/group.go +++ b/pkg/rpcclient/notification/group.go @@ -17,6 +17,7 @@ package notification import ( "context" "fmt" + "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/OpenIMSDK/protocol/constant" pbgroup "github.com/OpenIMSDK/protocol/group" @@ -35,12 +36,14 @@ func NewGroupNotificationSender( db controller.GroupDatabase, msgRpcClient *rpcclient.MessageRpcClient, userRpcClient *rpcclient.UserRpcClient, + config *config.GlobalConfig, fn func(ctx context.Context, userIDs []string) ([]CommonUser, error), ) *GroupNotificationSender { return &GroupNotificationSender{ - NotificationSender: rpcclient.NewNotificationSender(rpcclient.WithRpcClient(msgRpcClient), rpcclient.WithUserRpcClient(userRpcClient)), + NotificationSender: rpcclient.NewNotificationSender(config, rpcclient.WithRpcClient(msgRpcClient), rpcclient.WithUserRpcClient(userRpcClient)), getUsersInfo: fn, db: db, + config: config, } } @@ -48,6 +51,7 @@ type GroupNotificationSender struct { *rpcclient.NotificationSender getUsersInfo func(ctx context.Context, userIDs []string) ([]CommonUser, error) db controller.GroupDatabase + config *config.GlobalConfig } func (g *GroupNotificationSender) PopulateGroupMember(ctx context.Context, members ...*relation.GroupMemberModel) error { @@ -243,21 +247,15 @@ func (g *GroupNotificationSender) groupMemberDB2PB(member *relation.GroupMemberM } */ func (g *GroupNotificationSender) fillOpUser(ctx context.Context, opUser **sdkws.GroupMemberFullInfo, groupID string) (err error) { - defer log.ZDebug(ctx, "return") - defer func() { - if err != nil { - log.ZError(ctx, utils.GetFuncName(1)+" failed", err) - } - }() if opUser == nil { return errs.ErrInternalServer.Wrap("**sdkws.GroupMemberFullInfo is nil") } if *opUser != nil { - return nil + return errs.ErrArgs.Wrap("*opUser is not nil") } userID := mcontext.GetOpUserID(ctx) if groupID != "" { - if authverify.IsManagerUserID(userID) { + if authverify.IsManagerUserID(userID, g.config) { *opUser = &sdkws.GroupMemberFullInfo{ GroupID: groupID, UserID: userID, @@ -265,11 +263,11 @@ func (g *GroupNotificationSender) fillOpUser(ctx context.Context, opUser **sdkws AppMangerLevel: constant.AppAdmin, } } else { - member, err2 := g.db.TakeGroupMember(ctx, groupID, userID) - if err2 == nil { + member, err := g.db.TakeGroupMember(ctx, groupID, userID) + if err == nil { *opUser = g.groupMemberDB2PB(member, 0) - } else if !errs.ErrRecordNotFound.Is(err2) { - return err2 + } else if !errs.ErrRecordNotFound.Is(err) { + return err } } } @@ -650,12 +648,6 @@ func (g *GroupNotificationSender) GroupCancelMutedNotification(ctx context.Conte } func (g *GroupNotificationSender) GroupMemberInfoSetNotification(ctx context.Context, groupID, groupMemberUserID string) (err error) { - defer log.ZDebug(ctx, "return") - defer func() { - if err != nil { - log.ZError(ctx, utils.GetFuncName(1)+" failed", err) - } - }() group, err := g.getGroupInfo(ctx, groupID) if err != nil { return err @@ -672,12 +664,6 @@ func (g *GroupNotificationSender) GroupMemberInfoSetNotification(ctx context.Con } func (g *GroupNotificationSender) GroupMemberSetToAdminNotification(ctx context.Context, groupID, groupMemberUserID string) (err error) { - defer log.ZDebug(ctx, "return") - defer func() { - if err != nil { - log.ZError(ctx, utils.GetFuncName(1)+" failed", err) - } - }() group, err := g.getGroupInfo(ctx, groupID) if err != nil { return err diff --git a/pkg/rpcclient/notification/msg.go b/pkg/rpcclient/notification/msg.go index 83280f80a6..19819e7b7c 100644 --- a/pkg/rpcclient/notification/msg.go +++ b/pkg/rpcclient/notification/msg.go @@ -16,6 +16,7 @@ package notification import ( "context" + "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/protocol/sdkws" @@ -26,8 +27,8 @@ type MsgNotificationSender struct { *rpcclient.NotificationSender } -func NewMsgNotificationSender(opts ...rpcclient.NotificationSenderOptions) *MsgNotificationSender { - return &MsgNotificationSender{rpcclient.NewNotificationSender(opts...)} +func NewMsgNotificationSender(config *config.GlobalConfig, opts ...rpcclient.NotificationSenderOptions) *MsgNotificationSender { + return &MsgNotificationSender{rpcclient.NewNotificationSender(config, opts...)} } func (m *MsgNotificationSender) UserDeleteMsgsNotification(ctx context.Context, userID, conversationID string, seqs []int64) error { diff --git a/pkg/rpcclient/notification/user.go b/pkg/rpcclient/notification/user.go index f94e59a33b..204b13e613 100644 --- a/pkg/rpcclient/notification/user.go +++ b/pkg/rpcclient/notification/user.go @@ -16,6 +16,7 @@ package notification import ( "context" + "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/protocol/sdkws" @@ -58,11 +59,12 @@ func WithUserFunc( } func NewUserNotificationSender( + config *config.GlobalConfig, msgRpcClient *rpcclient.MessageRpcClient, opts ...userNotificationSenderOptions, ) *UserNotificationSender { f := &UserNotificationSender{ - NotificationSender: rpcclient.NewNotificationSender(rpcclient.WithRpcClient(msgRpcClient)), + NotificationSender: rpcclient.NewNotificationSender(config, rpcclient.WithRpcClient(msgRpcClient)), } for _, opt := range opts { opt(f) diff --git a/pkg/rpcclient/push.go b/pkg/rpcclient/push.go index 2f540da81d..c0aa9efa4c 100644 --- a/pkg/rpcclient/push.go +++ b/pkg/rpcclient/push.go @@ -30,8 +30,8 @@ type Push struct { discov discoveryregistry.SvcDiscoveryRegistry } -func NewPush(discov discoveryregistry.SvcDiscoveryRegistry) *Push { - conn, err := discov.GetConn(context.Background(), config.Config.RpcRegisterName.OpenImPushName) +func NewPush(discov discoveryregistry.SvcDiscoveryRegistry, config *config.GlobalConfig) *Push { + conn, err := discov.GetConn(context.Background(), config.RpcRegisterName.OpenImPushName) if err != nil { util.ExitWithError(err) } @@ -44,8 +44,8 @@ func NewPush(discov discoveryregistry.SvcDiscoveryRegistry) *Push { type PushRpcClient Push -func NewPushRpcClient(discov discoveryregistry.SvcDiscoveryRegistry) PushRpcClient { - return PushRpcClient(*NewPush(discov)) +func NewPushRpcClient(discov discoveryregistry.SvcDiscoveryRegistry, config *config.GlobalConfig) PushRpcClient { + return PushRpcClient(*NewPush(discov, config)) } func (p *PushRpcClient) DelUserPushToken(ctx context.Context, req *push.DelUserPushTokenReq) (*push.DelUserPushTokenResp, error) { diff --git a/pkg/rpcclient/third.go b/pkg/rpcclient/third.go old mode 100644 new mode 100755 index be40335d5c..50d545a649 --- a/pkg/rpcclient/third.go +++ b/pkg/rpcclient/third.go @@ -16,13 +16,15 @@ package rpcclient import ( "context" + "github.com/OpenIMSDK/tools/errs" "net/url" - "github.com/OpenIMSDK/protocol/third" - "github.com/OpenIMSDK/tools/discoveryregistry" - "github.com/OpenIMSDK/tools/errs" "github.com/minio/minio-go/v7" "github.com/minio/minio-go/v7/pkg/credentials" + + "github.com/OpenIMSDK/protocol/third" + "github.com/OpenIMSDK/tools/discoveryregistry" + "github.com/openimsdk/open-im-server/v3/pkg/common/config" util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" "google.golang.org/grpc" @@ -33,47 +35,41 @@ type Third struct { Client third.ThirdClient discov discoveryregistry.SvcDiscoveryRegistry MinioClient *minio.Client + Config *config.GlobalConfig } -func NewThird(discov discoveryregistry.SvcDiscoveryRegistry) *Third { - conn, err := discov.GetConn(context.Background(), config.Config.RpcRegisterName.OpenImThirdName) +func NewThird(discov discoveryregistry.SvcDiscoveryRegistry, config *config.GlobalConfig) *Third { + conn, err := discov.GetConn(context.Background(), config.RpcRegisterName.OpenImThirdName) if err != nil { util.ExitWithError(err) } client := third.NewThirdClient(conn) - minioClient, err := minioInit() + minioClient, err := minioInit(config) if err != nil { util.ExitWithError(err) } - return &Third{discov: discov, Client: client, conn: conn, MinioClient: minioClient} + return &Third{discov: discov, Client: client, conn: conn, MinioClient: minioClient, Config: config} } -func minioInit() (*minio.Client, error) { - // Retrieve MinIO configuration details - endpoint := config.Config.Object.Minio.Endpoint - accessKeyID := config.Config.Object.Minio.AccessKeyID - secretAccessKey := config.Config.Object.Minio.SecretAccessKey - - // Parse the MinIO URL to determine if the connection should be secure - minioURL, err := url.Parse(endpoint) +func minioInit(config *config.GlobalConfig) (*minio.Client, error) { + minioClient := &minio.Client{} + initUrl := config.Object.Minio.Endpoint + minioUrl, err := url.Parse(initUrl) if err != nil { return nil, errs.Wrap(err, "minioInit: failed to parse MinIO endpoint URL") } - - // Determine the security of the connection based on the scheme - secure := minioURL.Scheme == "https" - - // Setup MinIO client options opts := &minio.Options{ - Creds: credentials.NewStaticV4(accessKeyID, secretAccessKey, ""), - Secure: secure, + Creds: credentials.NewStaticV4(config.Object.Minio.AccessKeyID, config.Object.Minio.SecretAccessKey, ""), + // Region: config.Credential.Minio.Location, } - - // Initialize MinIO client - minioClient, err := minio.New(minioURL.Host, opts) + if minioUrl.Scheme == "http" { + opts.Secure = false + } else if minioUrl.Scheme == "https" { + opts.Secure = true + } + minioClient, err = minio.New(minioUrl.Host, opts) if err != nil { return nil, errs.Wrap(err, "minioInit: failed to create MinIO client") } - return minioClient, nil } diff --git a/pkg/rpcclient/user.go b/pkg/rpcclient/user.go index a6c2021297..08ad41dc1a 100644 --- a/pkg/rpcclient/user.go +++ b/pkg/rpcclient/user.go @@ -34,16 +34,17 @@ type User struct { conn grpc.ClientConnInterface Client user.UserClient Discov discoveryregistry.SvcDiscoveryRegistry + Config *config.GlobalConfig } // NewUser initializes and returns a User instance based on the provided service discovery registry. -func NewUser(discov discoveryregistry.SvcDiscoveryRegistry) *User { - conn, err := discov.GetConn(context.Background(), config.Config.RpcRegisterName.OpenImUserName) +func NewUser(discov discoveryregistry.SvcDiscoveryRegistry, config *config.GlobalConfig) *User { + conn, err := discov.GetConn(context.Background(), config.RpcRegisterName.OpenImUserName) if err != nil { util.ExitWithError(err) } client := user.NewUserClient(conn) - return &User{Discov: discov, Client: client, conn: conn} + return &User{Discov: discov, Client: client, conn: conn, Config: config} } // UserRpcClient represents the structure for a User RPC client. @@ -56,8 +57,8 @@ func NewUserRpcClientByUser(user *User) *UserRpcClient { } // NewUserRpcClient initializes a UserRpcClient based on the provided service discovery registry. -func NewUserRpcClient(client discoveryregistry.SvcDiscoveryRegistry) UserRpcClient { - return UserRpcClient(*NewUser(client)) +func NewUserRpcClient(client discoveryregistry.SvcDiscoveryRegistry, config *config.GlobalConfig) UserRpcClient { + return UserRpcClient(*NewUser(client, config)) } // GetUsersInfo retrieves information for multiple users based on their user IDs. @@ -160,7 +161,7 @@ func (u *UserRpcClient) Access(ctx context.Context, ownerUserID string) error { if err != nil { return err } - return authverify.CheckAccessV3(ctx, ownerUserID) + return authverify.CheckAccessV3(ctx, ownerUserID, u.Config) } // GetAllUserIDs retrieves all user IDs with pagination options. diff --git a/tools/component/component.go b/tools/component/component.go index 6b879d7f8b..bb3a2d46f2 100644 --- a/tools/component/component.go +++ b/tools/component/component.go @@ -47,27 +47,33 @@ var ( cfgPath = flag.String("c", defaultCfgPath, "Path to the configuration file") ) -func initCfg() error { +func initCfg() (*config.GlobalConfig, error) { data, err := os.ReadFile(*cfgPath) if err != nil { - return err + return nil, errs.Wrap(err, "ReadFile unmarshal failed") } - return yaml.Unmarshal(data, &config.Config) + conf := config.NewGlobalConfig() + err = yaml.Unmarshal(data, &conf) + if err != nil { + return nil, errs.Wrap(err, "InitConfig unmarshal failed") + } + return conf, nil } type checkFunc struct { name string - function func() error + function func(*config.GlobalConfig) error flag bool + config *config.GlobalConfig } func main() { flag.Parse() - if err := initCfg(); err != nil { + conf, err := initCfg() + if err != nil { fmt.Printf("Read config failed: %v\n", err) - return } @@ -75,11 +81,11 @@ func main() { checks := []checkFunc{ //{name: "Mysql", function: checkMysql}, - {name: "Mongo", function: checkMongo}, - {name: "Redis", function: checkRedis}, - {name: "Minio", function: checkMinio}, - {name: "Zookeeper", function: checkZookeeper}, - {name: "Kafka", function: checkKafka}, + {name: "Mongo", function: checkMongo, config: conf}, + {name: "Redis", function: checkRedis, config: conf}, + {name: "Minio", function: checkMinio, config: conf}, + {name: "Zookeeper", function: checkZookeeper, config: conf}, + {name: "Kafka", function: checkKafka, config: conf}, } for i := 0; i < maxRetry; i++ { @@ -92,7 +98,7 @@ func main() { allSuccess := true for index, check := range checks { if !check.flag { - err = check.function() + err = check.function(check.config) if err != nil { component.ErrorPrint(fmt.Sprintf("Starting %s failed:%v.", check.name, err)) allSuccess = false @@ -112,30 +118,30 @@ func main() { } // checkMongo checks the MongoDB connection without retries -func checkMongo() error { - _, err := unrelation.NewMongo() +func checkMongo(config *config.GlobalConfig) error { + _, err := unrelation.NewMongo(config) return err } // checkRedis checks the Redis connection -func checkRedis() error { - _, err := cache.NewRedis() +func checkRedis(config *config.GlobalConfig) error { + _, err := cache.NewRedis(config) return err } // checkMinio checks the MinIO connection -func checkMinio() error { +func checkMinio(config *config.GlobalConfig) error { // Check if MinIO is enabled - if config.Config.Object.Enable != "minio" { + if config.Object.Enable != "minio" { return errs.Wrap(errors.New("minio.Enable is empty")) } minio := &component.Minio{ - ApiURL: config.Config.Object.ApiURL, - Endpoint: config.Config.Object.Minio.Endpoint, - AccessKeyID: config.Config.Object.Minio.AccessKeyID, - SecretAccessKey: config.Config.Object.Minio.SecretAccessKey, - SignEndpoint: config.Config.Object.Minio.SignEndpoint, + ApiURL: config.Object.ApiURL, + Endpoint: config.Object.Minio.Endpoint, + AccessKeyID: config.Object.Minio.AccessKeyID, + SecretAccessKey: config.Object.Minio.SecretAccessKey, + SignEndpoint: config.Object.Minio.SignEndpoint, UseSSL: getEnv("MINIO_USE_SSL", "false"), } err := component.CheckMinio(minio) @@ -143,18 +149,18 @@ func checkMinio() error { } // checkZookeeper checks the Zookeeper connection -func checkZookeeper() error { - _, err := zookeeper.NewZookeeperDiscoveryRegister() +func checkZookeeper(config *config.GlobalConfig) error { + _, err := zookeeper.NewZookeeperDiscoveryRegister(config) return err } // checkKafka checks the Kafka connection -func checkKafka() error { +func checkKafka(config *config.GlobalConfig) error { // Prioritize environment variables kafkaStu := &component.Kafka{ - Username: config.Config.Kafka.Username, - Password: config.Config.Kafka.Password, - Addr: config.Config.Kafka.Addr, + Username: config.Kafka.Username, + Password: config.Kafka.Password, + Addr: config.Kafka.Addr, } kafkaClient, err := component.CheckKafka(kafkaStu) @@ -170,9 +176,9 @@ func checkKafka() error { } requiredTopics := []string{ - config.Config.Kafka.MsgToMongo.Topic, - config.Config.Kafka.MsgToPush.Topic, - config.Config.Kafka.LatestMsgToRedis.Topic, + config.Kafka.MsgToMongo.Topic, + config.Kafka.MsgToPush.Topic, + config.Kafka.LatestMsgToRedis.Topic, } for _, requiredTopic := range requiredTopics { @@ -181,11 +187,25 @@ func checkKafka() error { } } + var tlsConfig *kafka.TLSConfig + if config.Kafka.TLS != nil { + tlsConfig = &kafka.TLSConfig{ + CACrt: config.Kafka.TLS.CACrt, + ClientCrt: config.Kafka.TLS.ClientCrt, + ClientKey: config.Kafka.TLS.ClientKey, + ClientKeyPwd: config.Kafka.TLS.ClientKeyPwd, + InsecureSkipVerify: config.Kafka.TLS.InsecureSkipVerify, + } + } + _, err = kafka.NewMConsumerGroup(&kafka.MConsumerGroupConfig{ KafkaVersion: sarama.V2_0_0_0, - OffsetsInitial: sarama.OffsetNewest, IsReturnErr: false, - }, []string{config.Config.Kafka.LatestMsgToRedis.Topic}, - config.Config.Kafka.Addr, config.Config.Kafka.ConsumerGroupID.MsgToRedis) + OffsetsInitial: sarama.OffsetNewest, + IsReturnErr: false, + UserName: config.Kafka.Username, + Password: config.Kafka.Password, + }, []string{config.Kafka.LatestMsgToRedis.Topic}, + config.Kafka.Addr, config.Kafka.ConsumerGroupID.MsgToRedis, tlsConfig) if err != nil { return err } @@ -193,8 +213,8 @@ func checkKafka() error { _, err = kafka.NewMConsumerGroup(&kafka.MConsumerGroupConfig{ KafkaVersion: sarama.V2_0_0_0, OffsetsInitial: sarama.OffsetNewest, IsReturnErr: false, - }, []string{config.Config.Kafka.MsgToPush.Topic}, - config.Config.Kafka.Addr, config.Config.Kafka.ConsumerGroupID.MsgToMongo) + }, []string{config.Kafka.MsgToPush.Topic}, + config.Kafka.Addr, config.Kafka.ConsumerGroupID.MsgToMongo, tlsConfig) if err != nil { return err } @@ -202,8 +222,8 @@ func checkKafka() error { kafka.NewMConsumerGroup(&kafka.MConsumerGroupConfig{ KafkaVersion: sarama.V2_0_0_0, OffsetsInitial: sarama.OffsetNewest, IsReturnErr: false, - }, []string{config.Config.Kafka.MsgToPush.Topic}, config.Config.Kafka.Addr, - config.Config.Kafka.ConsumerGroupID.MsgToPush) + }, []string{config.Kafka.MsgToPush.Topic}, config.Kafka.Addr, + config.Kafka.ConsumerGroupID.MsgToPush, tlsConfig) if err != nil { return err } diff --git a/tools/component/component_test.go b/tools/component/component_test.go index 4488c029e1..c56361b2c0 100644 --- a/tools/component/component_test.go +++ b/tools/component/component_test.go @@ -21,20 +21,11 @@ import ( "time" "github.com/redis/go-redis/v9" - - "github.com/openimsdk/open-im-server/v3/pkg/common/config" ) -// Mock for initCfg for testing purpose -func mockInitCfg() error { - config.Config.Mysql.Username = "root" - config.Config.Mysql.Password = "openIM123" - config.Config.Mysql.Address = []string{"127.0.0.1:13306"} - return nil -} - func TestRedis(t *testing.T) { - config.Config.Redis.Address = []string{ + conf, err := initCfg() + conf.Redis.Address = []string{ "172.16.8.142:7000", //"172.16.8.142:7000", "172.16.8.142:7001", "172.16.8.142:7002", "172.16.8.142:7003", "172.16.8.142:7004", "172.16.8.142:7005", } @@ -45,20 +36,20 @@ func TestRedis(t *testing.T) { redisClient.Close() } }() - if len(config.Config.Redis.Address) > 1 { + if len(conf.Redis.Address) > 1 { redisClient = redis.NewClusterClient(&redis.ClusterOptions{ - Addrs: config.Config.Redis.Address, - Username: config.Config.Redis.Username, - Password: config.Config.Redis.Password, + Addrs: conf.Redis.Address, + Username: conf.Redis.Username, + Password: conf.Redis.Password, }) } else { redisClient = redis.NewClient(&redis.Options{ - Addr: config.Config.Redis.Address[0], - Username: config.Config.Redis.Username, - Password: config.Config.Redis.Password, + Addr: conf.Redis.Address[0], + Username: conf.Redis.Username, + Password: conf.Redis.Password, }) } - _, err := redisClient.Ping(context.Background()).Result() + _, err = redisClient.Ping(context.Background()).Result() if err != nil { t.Fatal(err) } diff --git a/tools/up35/pkg/pkg.go b/tools/up35/pkg/pkg.go index b7e7c01f5d..1348172d2a 100644 --- a/tools/up35/pkg/pkg.go +++ b/tools/up35/pkg/pkg.go @@ -18,6 +18,7 @@ import ( "context" "errors" "fmt" + "github.com/OpenIMSDK/tools/errs" "log" "os" "reflect" @@ -45,36 +46,43 @@ const ( versionValue = 35 ) -func InitConfig(path string) error { +func InitConfig(path string) (*config.GlobalConfig, error) { data, err := os.ReadFile(path) if err != nil { - return err + return nil, errs.Wrap(err, "ReadFile unmarshal failed") } - return yaml.Unmarshal(data, &config.Config) + + conf := config.NewGlobalConfig() + err = yaml.Unmarshal(data, &conf) + if err != nil { + return nil, errs.Wrap(err, "InitConfig unmarshal failed") + } + return conf, nil } -func GetMysql() (*gorm.DB, error) { - conf := config.Config.Mysql +func GetMysql(config *config.GlobalConfig) (*gorm.DB, error) { + conf := config.Mysql mysqlDSN := fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=utf8mb4&parseTime=True&loc=Local", conf.Username, conf.Password, conf.Address[0], conf.Database) return gorm.Open(gormmysql.Open(mysqlDSN), &gorm.Config{Logger: logger.Discard}) } -func GetMongo() (*mongo.Database, error) { - mgo, err := unrelation.NewMongo() +func GetMongo(config *config.GlobalConfig) (*mongo.Database, error) { + mgo, err := unrelation.NewMongo(config) if err != nil { return nil, err } - return mgo.GetDatabase(), nil + return mgo.GetDatabase(config.Mongo.Database), nil } func Main(path string) error { - if err := InitConfig(path); err != nil { + conf, err := InitConfig(path) + if err != nil { return err } - if config.Config.Mysql == nil { + if conf.Mysql == nil { return nil } - mongoDB, err := GetMongo() + mongoDB, err := GetMongo(conf) if err != nil { return err } @@ -91,7 +99,7 @@ func Main(path string) error { default: return err } - mysqlDB, err := GetMysql() + mysqlDB, err := GetMysql(conf) if err != nil { if mysqlErr, ok := err.(*mysql.MySQLError); ok && mysqlErr.Number == 1049 { if err := SetMongoDataVersion(mongoDB, version.Value); err != nil { @@ -113,7 +121,7 @@ func Main(path string) error { func() error { return NewTask(mysqlDB, mongoDB, mgo.NewGroupMember, c.GroupMember) }, func() error { return NewTask(mysqlDB, mongoDB, mgo.NewGroupRequestMgo, c.GroupRequest) }, func() error { return NewTask(mysqlDB, mongoDB, mgo.NewConversationMongo, c.Conversation) }, - func() error { return NewTask(mysqlDB, mongoDB, mgo.NewS3Mongo, c.Object(config.Config.Object.Enable)) }, + func() error { return NewTask(mysqlDB, mongoDB, mgo.NewS3Mongo, c.Object(conf.Object.Enable)) }, func() error { return NewTask(mysqlDB, mongoDB, mgo.NewLogMongo, c.Log) }, func() error { return NewTask(mysqlDB, mongoDB, rtcmgo.NewSignal, c.SignalModel) }, From 532f6acb5d00f48a49cb90fdbd23ea5ac434cc29 Mon Sep 17 00:00:00 2001 From: Brabem <69128477+luhaoling@users.noreply.github.com> Date: Tue, 5 Mar 2024 18:09:50 +0800 Subject: [PATCH 084/188] fix: fix the component logic (#2001) * optimization: change the configuration file from being read globally to being read independently. * optimization: change the configuration file from being read globally to being read independently. * optimization: change the configuration file from being read globally to being read independently. * optimization: config file changed to dependency injection. * fix: replace global config with dependency injection * fix: replace global config with dependency injection * fix: import the enough param * fix: import the enough param * fix: import the enough param * fix: fix the component check of path * fix: fix the kafka of tls is nil problem * fix: fix the TLS.CACrt is nil error * fix: fix the valiable shadows problem * fix: fix the comflect * optimization: message remove options. * fix: fix the param pass error * fix: find error * fix: find error * fix: find eror * fix: find error * fix: find error * fix: del the undifined func * fix: find error * fix: fix the error * fix: pass config * fix: find error * fix: find error * fix: find error * fix: find error * fix: find error * fix: fix the config * fix: fix the error * fix: fix the config pass error * fix: fix the eror * fix: fix the error * fix: fix the error * fix: fix the error * fix: find error * fix: fix the error * fix: fix the config * fix: add return err * fix: fix the err2 * fix: err * fix: fix the func * fix: del the chinese comment * fix: fix the func * fix: fix the gateway_test logic * fix: s3 * test --------- Co-authored-by: Gordon <1432970085@qq.com> Co-authored-by: withchao <993506633@qq.com> --- go.mod | 2 +- go.sum | 4 +- tools/component/component.go | 134 +++++++++++++++++++++++++++++------ 3 files changed, 116 insertions(+), 24 deletions(-) diff --git a/go.mod b/go.mod index 30bfcf146d..556981a159 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.19 require ( firebase.google.com/go v3.13.0+incompatible github.com/OpenIMSDK/protocol v0.0.55 - github.com/OpenIMSDK/tools v0.0.36 + github.com/OpenIMSDK/tools v0.0.37 github.com/bwmarrin/snowflake v0.3.0 // indirect github.com/dtm-labs/rockscache v0.1.1 github.com/gin-gonic/gin v1.9.1 diff --git a/go.sum b/go.sum index 6277afac39..906eff45ed 100644 --- a/go.sum +++ b/go.sum @@ -20,8 +20,8 @@ github.com/IBM/sarama v1.42.2 h1:VoY4hVIZ+WQJ8G9KNY/SQlWguBQXQ9uvFPOnrcu8hEw= github.com/IBM/sarama v1.42.2/go.mod h1:FLPGUGwYqEs62hq2bVG6Io2+5n+pS6s/WOXVKWSLFtE= github.com/OpenIMSDK/protocol v0.0.55 h1:eBjg8DyuhxGmuCUjpoZjg6MJJJXU/xJ3xJwFhrn34yA= github.com/OpenIMSDK/protocol v0.0.55/go.mod h1:F25dFrwrIx3lkNoiuf6FkCfxuwf8L4Z8UIsdTHP/r0Y= -github.com/OpenIMSDK/tools v0.0.36 h1:BT0q64l4f3QJDW16Rc0uJYt1gQFkiPoUQYQ33vo0EcE= -github.com/OpenIMSDK/tools v0.0.36/go.mod h1:wBfR5CYmEyvxl03QJbTkhz1CluK6J4/lX0lviu8JAjE= +github.com/OpenIMSDK/tools v0.0.37 h1:qvDqmA4RbEJtPjZouWCkVuf/pjm6Y8nUrG5iH2gcnOg= +github.com/OpenIMSDK/tools v0.0.37/go.mod h1:wBfR5CYmEyvxl03QJbTkhz1CluK6J4/lX0lviu8JAjE= github.com/QcloudApi/qcloud_sign_golang v0.0.0-20141224014652-e4130a326409/go.mod h1:1pk82RBxDY/JZnPQrtqHlUFfCctgdorsd9M06fMynOM= github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7 h1:uSoVVbwJiQipAclBbw+8quDsfcvFjOpI5iCf4p/cqCs= github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs= diff --git a/tools/component/component.go b/tools/component/component.go index bb3a2d46f2..34d3dff6b3 100644 --- a/tools/component/component.go +++ b/tools/component/component.go @@ -19,14 +19,12 @@ import ( "flag" "fmt" "os" + "strconv" "strings" "time" "github.com/IBM/sarama" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/unrelation" - "github.com/openimsdk/open-im-server/v3/pkg/common/discoveryregister/zookeeper" "github.com/openimsdk/open-im-server/v3/pkg/common/kafka" "github.com/OpenIMSDK/tools/component" @@ -40,7 +38,7 @@ import ( const ( // defaultCfgPath is the default path of the configuration file. defaultCfgPath = "../../../../../config/config.yaml" - maxRetry = 300 + maxRetry = 100 ) var ( @@ -77,7 +75,11 @@ func main() { return } - configGetEnv() + err = configGetEnv(conf) + if err != nil { + fmt.Printf("configGetEnv failed,err:%v", err) + return + } checks := []checkFunc{ //{name: "Mysql", function: checkMysql}, @@ -100,9 +102,13 @@ func main() { if !check.flag { err = check.function(check.config) if err != nil { - component.ErrorPrint(fmt.Sprintf("Starting %s failed:%v.", check.name, err)) allSuccess = false - + component.ErrorPrint(fmt.Sprintf("Starting %s failed:%v.", check.name, errs.Unwrap(err).Error())) + if !strings.Contains(errs.Unwrap(err).Error(), "connection refused") && + !strings.Contains(errs.Unwrap(err).Error(), "timeout waiting") { + component.ErrorPrint("Some components started failed!") + os.Exit(-1) + } } else { checks[index].flag = true component.SuccessPrint(fmt.Sprintf("%s connected successfully", check.name)) @@ -115,23 +121,38 @@ func main() { return } } + component.ErrorPrint("Some components started failed!") + os.Exit(-1) } // checkMongo checks the MongoDB connection without retries func checkMongo(config *config.GlobalConfig) error { - _, err := unrelation.NewMongo(config) + mongoStu := &component.Mongo{ + URL: config.Mongo.Uri, + Address: config.Mongo.Address, + Database: config.Mongo.Database, + Username: config.Mongo.Username, + Password: config.Mongo.Password, + MaxPoolSize: config.Mongo.MaxPoolSize, + } + err := component.CheckMongo(mongoStu) + return err } // checkRedis checks the Redis connection func checkRedis(config *config.GlobalConfig) error { - _, err := cache.NewRedis(config) + redisStu := &component.Redis{ + Address: config.Redis.Address, + Username: config.Redis.Username, + Password: config.Redis.Password, + } + err := component.CheckRedis(redisStu) return err } // checkMinio checks the MinIO connection func checkMinio(config *config.GlobalConfig) error { - // Check if MinIO is enabled if config.Object.Enable != "minio" { return errs.Wrap(errors.New("minio.Enable is empty")) @@ -150,7 +171,13 @@ func checkMinio(config *config.GlobalConfig) error { // checkZookeeper checks the Zookeeper connection func checkZookeeper(config *config.GlobalConfig) error { - _, err := zookeeper.NewZookeeperDiscoveryRegister(config) + zkStu := &component.Zookeeper{ + Schema: config.Zookeeper.Schema, + ZkAddr: config.Zookeeper.ZkAddr, + Username: config.Zookeeper.Username, + Password: config.Zookeeper.Password, + } + err := component.CheckZookeeper(zkStu) return err } @@ -241,16 +268,38 @@ func isTopicPresent(topic string, topics []string) bool { return false } -func configGetEnv() { - config.Config.Object.Minio.AccessKeyID = getEnv("MINIO_ACCESS_KEY_ID", config.Config.Object.Minio.AccessKeyID) - config.Config.Object.Minio.SecretAccessKey = getEnv("MINIO_SECRET_ACCESS_KEY", config.Config.Object.Minio.SecretAccessKey) - config.Config.Mongo.Uri = getEnv("MONGO_URI", config.Config.Mongo.Uri) - config.Config.Mongo.Username = getEnv("MONGO_OPENIM_USERNAME", config.Config.Mongo.Username) - config.Config.Mongo.Password = getEnv("MONGO_OPENIM_PASSWORD", config.Config.Mongo.Password) - config.Config.Kafka.Username = getEnv("KAFKA_USERNAME", config.Config.Kafka.Username) - config.Config.Kafka.Password = getEnv("KAFKA_PASSWORD", config.Config.Kafka.Password) - config.Config.Kafka.Addr = strings.Split(getEnv("KAFKA_ADDRESS", strings.Join(config.Config.Kafka.Addr, ",")), ",") - config.Config.Object.Minio.Endpoint = getMinioAddr("MINIO_ENDPOINT", "MINIO_ADDRESS", "MINIO_PORT", config.Config.Object.Minio.Endpoint) +func configGetEnv(config *config.GlobalConfig) error { + config.Mongo.Uri = getEnv("MONGO_URI", config.Mongo.Uri) + config.Mongo.Username = getEnv("MONGO_OPENIM_USERNAME", config.Mongo.Username) + config.Mongo.Password = getEnv("MONGO_OPENIM_PASSWORD", config.Mongo.Password) + config.Mongo.Address = getArrEnv("MONGO_ADDRESS", "MONGO_PORT", config.Mongo.Address) + config.Mongo.Database = getEnv("MONGO_DATABASE", config.Mongo.Database) + maxPoolSize, err := getEnvInt("MONGO_DATABASE", config.Mongo.MaxPoolSize) + if err != nil { + return err + } + config.Mongo.MaxPoolSize = maxPoolSize + + config.Redis.Username = getEnv("REDIS_USERNAME", config.Redis.Username) + config.Redis.Password = getEnv("REDIS_PASSWORD", config.Redis.Password) + config.Redis.Address = getArrEnv("REDIS_ADDRESS", "REDIS_PASSWORD", config.Redis.Address) + + config.Object.ApiURL = getEnv("OBJECT_APIURL", config.Object.ApiURL) + config.Object.Minio.Endpoint = getEnv("MINIO_ENDPOINT", config.Object.Minio.Endpoint) + config.Object.Minio.AccessKeyID = getEnv("MINIO_ACCESS_KEY_ID", config.Object.Minio.AccessKeyID) + config.Object.Minio.SecretAccessKey = getEnv("MINIO_SECRET_ACCESS_KEY", config.Object.Minio.SecretAccessKey) + config.Object.Minio.SignEndpoint = getEnv("MINIO_SIGN_ENDPOINT", config.Object.Minio.SignEndpoint) + + config.Zookeeper.Schema = getEnv("ZOOKEEPER_SCHEMA", config.Zookeeper.Schema) + config.Zookeeper.ZkAddr = getArrEnv("ZOOKEEPER_ADDRESS", "ZOOKEEPER_PORT", config.Zookeeper.ZkAddr) + config.Zookeeper.Username = getEnv("ZOOKEEPER_USERNAME", config.Zookeeper.Username) + config.Zookeeper.Password = getEnv("ZOOKEEPER_PASSWORD", config.Zookeeper.Password) + + config.Kafka.Username = getEnv("KAFKA_USERNAME", config.Kafka.Username) + config.Kafka.Password = getEnv("KAFKA_PASSWORD", config.Kafka.Password) + config.Kafka.Addr = getArrEnv("KAFKA_ADDRESS", "KAFKA_PORT", config.Kafka.Addr) + config.Object.Minio.Endpoint = getMinioAddr("MINIO_ENDPOINT", "MINIO_ADDRESS", "MINIO_PORT", config.Object.Minio.Endpoint) + return nil } func getMinioAddr(key1, key2, key3, fallback string) string { @@ -272,3 +321,46 @@ func getEnv(key, fallback string) string { } return fallback } + +// Helper function to get environment variable or default value +func getEnvInt(key string, fallback int) (int, error) { + if value, exists := os.LookupEnv(key); exists { + val, err := strconv.Atoi(value) + if err != nil { + return 0, errs.Wrap(err, "string to int failed") + } + return val, nil + } + return fallback, nil +} + +func getArrEnv(key1, key2 string, fallback []string) []string { + address, addrExists := os.LookupEnv(key1) + port, portExists := os.LookupEnv(key2) + + if addrExists && portExists { + addresses := strings.Split(address, ",") + for i, addr := range addresses { + addresses[i] = addr + ":" + port + } + return addresses + } + + if addrExists && !portExists { + addresses := strings.Split(address, ",") + for i, addr := range addresses { + addresses[i] = addr + ":" + "0" + } + return addresses + } + + if !addrExists && portExists { + result := make([]string, len(fallback)) + for i, addr := range fallback { + add := strings.Split(addr, ":") + result[i] = add[0] + ":" + port + } + return result + } + return fallback +} From c7dad1a5c1aa5421e43325476623b5d6394a9c8a Mon Sep 17 00:00:00 2001 From: OpenIM Bot <124379614+kubbot@users.noreply.github.com> Date: Wed, 6 Mar 2024 15:58:05 +0800 Subject: [PATCH 085/188] cicd: bump League Patch (#2004) --- cmd/openim-api/main.go | 2 +- go.mod | 2 -- go.sum | 7 ----- internal/api/route.go | 28 ++++++++----------- internal/api/third.go | 3 +- internal/api/user.go | 1 - internal/msggateway/message_handler.go | 2 +- internal/msgtransfer/init.go | 7 ++++- internal/push/consumer_init.go | 1 + internal/push/offlinepush/fcm/push.go | 6 ++-- internal/push/push_rpc_server.go | 2 +- internal/rpc/conversation/conversaion.go | 2 +- internal/rpc/friend/friend.go | 27 +++++++----------- internal/rpc/group/group.go | 2 +- internal/rpc/msg/revoke.go | 4 +-- internal/rpc/msg/send.go | 5 ++-- internal/rpc/msg/server.go | 7 ++--- internal/rpc/third/third.go | 18 +++++------- internal/rpc/third/tool.go | 3 +- internal/rpc/user/user.go | 24 ++++++---------- internal/tools/cron_task.go | 9 +++--- internal/tools/cron_task_test.go | 5 ++-- pkg/common/cmd/api.go | 3 +- pkg/common/cmd/msg_gateway.go | 4 +-- pkg/common/cmd/msg_transfer.go | 4 +-- pkg/common/cmd/rpc.go | 11 +++----- pkg/common/db/cache/meta_cache.go | 6 ++-- pkg/common/db/cache/user.go | 8 ++---- pkg/common/db/controller/auth.go | 2 +- pkg/common/db/s3/cos/cos.go | 2 +- pkg/common/db/s3/minio/minio.go | 2 +- .../discoveryregister/discoveryregister.go | 2 +- .../discoveryregister_test.go | 3 +- .../kubernetes/kubernetes.go | 6 ++-- pkg/common/kafka/consumer.go | 11 ++++---- pkg/common/kafka/consumer_group.go | 3 +- pkg/common/kafka/producer.go | 3 +- pkg/common/startrpc/start.go | 22 ++++++--------- pkg/common/startrpc/start_test.go | 3 +- pkg/common/tls/tls.go | 2 +- pkg/rpcclient/msg.go | 2 +- pkg/rpcclient/notification/conversation.go | 2 +- pkg/rpcclient/notification/friend.go | 2 +- pkg/rpcclient/notification/group.go | 2 +- pkg/rpcclient/notification/msg.go | 2 +- pkg/rpcclient/notification/user.go | 2 +- pkg/rpcclient/third.go | 8 ++---- tools/up35/pkg/pkg.go | 3 +- 48 files changed, 114 insertions(+), 173 deletions(-) mode change 100755 => 100644 pkg/rpcclient/third.go diff --git a/cmd/openim-api/main.go b/cmd/openim-api/main.go index 9a307686d8..ee19a5c60d 100644 --- a/cmd/openim-api/main.go +++ b/cmd/openim-api/main.go @@ -15,10 +15,10 @@ package main import ( - util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" _ "net/http/pprof" "github.com/openimsdk/open-im-server/v3/pkg/common/cmd" + util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" ) func main() { diff --git a/go.mod b/go.mod index 556981a159..38443ba5a8 100644 --- a/go.mod +++ b/go.mod @@ -36,7 +36,6 @@ require github.com/google/uuid v1.6.0 require ( github.com/IBM/sarama v1.42.2 github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible - github.com/aws/aws-sdk-go v1.49.21 github.com/go-redis/redis v6.15.9+incompatible github.com/redis/go-redis/v9 v9.4.0 github.com/spf13/pflag v1.0.5 @@ -95,7 +94,6 @@ require ( github.com/jinzhu/copier v0.3.5 // indirect github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/now v1.1.5 // indirect - github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd // indirect github.com/klauspost/compress v1.17.4 // indirect diff --git a/go.sum b/go.sum index 906eff45ed..aa41279af0 100644 --- a/go.sum +++ b/go.sum @@ -31,8 +31,6 @@ github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= -github.com/aws/aws-sdk-go v1.49.21 h1:Rl8KW6HqkwzhATwvXhyr7vD4JFUMi7oXGAw9SrxxIFY= -github.com/aws/aws-sdk-go v1.49.21/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk= github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= @@ -205,10 +203,6 @@ github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= -github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= -github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= -github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= -github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= github.com/jonboulle/clockwork v0.4.0 h1:p4Cf1aMWXnXAUh8lVfewRBx1zaTSYKrKMF2g3ST4RZ4= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= @@ -538,7 +532,6 @@ gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= diff --git a/internal/api/route.go b/internal/api/route.go index ce8e3a62b3..92fa83fb0e 100644 --- a/internal/api/route.go +++ b/internal/api/route.go @@ -17,10 +17,6 @@ package api import ( "context" "fmt" - kdisc "github.com/openimsdk/open-im-server/v3/pkg/common/discoveryregister" - ginprom "github.com/openimsdk/open-im-server/v3/pkg/common/ginprometheus" - "github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics" - util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" "net" "net/http" "os" @@ -31,26 +27,26 @@ import ( "github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/tools/apiresp" + "github.com/OpenIMSDK/tools/discoveryregistry" "github.com/OpenIMSDK/tools/errs" + "github.com/OpenIMSDK/tools/log" + "github.com/OpenIMSDK/tools/mw" "github.com/OpenIMSDK/tools/tokenverify" - - "github.com/openimsdk/open-im-server/v3/pkg/authverify" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" - "github.com/gin-gonic/gin" "github.com/gin-gonic/gin/binding" "github.com/go-playground/validator/v10" + "github.com/openimsdk/open-im-server/v3/pkg/authverify" + "github.com/openimsdk/open-im-server/v3/pkg/common/config" + "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" + "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" + kdisc "github.com/openimsdk/open-im-server/v3/pkg/common/discoveryregister" + ginprom "github.com/openimsdk/open-im-server/v3/pkg/common/ginprometheus" + "github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics" + "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" + util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" "github.com/redis/go-redis/v9" "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" - - "github.com/OpenIMSDK/tools/discoveryregistry" - "github.com/OpenIMSDK/tools/log" - "github.com/OpenIMSDK/tools/mw" - - "github.com/openimsdk/open-im-server/v3/pkg/common/config" - "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" ) func Start(config *config.GlobalConfig, port int, proPort int) error { diff --git a/internal/api/third.go b/internal/api/third.go index 190e0d5403..30448ae4dd 100644 --- a/internal/api/third.go +++ b/internal/api/third.go @@ -19,12 +19,11 @@ import ( "net/http" "strconv" - "github.com/gin-gonic/gin" - "github.com/OpenIMSDK/protocol/third" "github.com/OpenIMSDK/tools/a2r" "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/mcontext" + "github.com/gin-gonic/gin" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" ) diff --git a/internal/api/user.go b/internal/api/user.go index 468432ee08..16b453e467 100644 --- a/internal/api/user.go +++ b/internal/api/user.go @@ -23,7 +23,6 @@ import ( "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/log" "github.com/gin-gonic/gin" - "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" ) diff --git a/internal/msggateway/message_handler.go b/internal/msggateway/message_handler.go index 208cd6bf7f..2fbdd5683e 100644 --- a/internal/msggateway/message_handler.go +++ b/internal/msggateway/message_handler.go @@ -16,7 +16,6 @@ package msggateway import ( "context" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" "sync" "github.com/OpenIMSDK/protocol/msg" @@ -26,6 +25,7 @@ import ( "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/utils" "github.com/go-playground/validator/v10" + "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" "google.golang.org/protobuf/proto" ) diff --git a/internal/msgtransfer/init.go b/internal/msgtransfer/init.go index 5e9e80663f..ee62db9c1a 100644 --- a/internal/msgtransfer/init.go +++ b/internal/msgtransfer/init.go @@ -92,7 +92,12 @@ func StartTransfer(config *config.GlobalConfig, prometheusPort int) error { return msgTransfer.Start(prometheusPort, config) } -func NewMsgTransfer(config *config.GlobalConfig, msgDatabase controller.CommonMsgDatabase, conversationRpcClient *rpcclient.ConversationRpcClient, groupRpcClient *rpcclient.GroupRpcClient) (*MsgTransfer, error) { +func NewMsgTransfer( + config *config.GlobalConfig, + msgDatabase controller.CommonMsgDatabase, + conversationRpcClient *rpcclient.ConversationRpcClient, + groupRpcClient *rpcclient.GroupRpcClient, +) (*MsgTransfer, error) { historyCH, err := NewOnlineHistoryRedisConsumerHandler(config, msgDatabase, conversationRpcClient, groupRpcClient) if err != nil { return nil, err diff --git a/internal/push/consumer_init.go b/internal/push/consumer_init.go index 4ad77de2c1..351b63f46d 100644 --- a/internal/push/consumer_init.go +++ b/internal/push/consumer_init.go @@ -16,6 +16,7 @@ package push import ( "context" + "github.com/openimsdk/open-im-server/v3/pkg/common/config" ) diff --git a/internal/push/offlinepush/fcm/push.go b/internal/push/offlinepush/fcm/push.go index 977254462c..ed65a5af60 100644 --- a/internal/push/offlinepush/fcm/push.go +++ b/internal/push/offlinepush/fcm/push.go @@ -20,14 +20,12 @@ import ( firebase "firebase.google.com/go" "firebase.google.com/go/messaging" - "github.com/redis/go-redis/v9" - "google.golang.org/api/option" - "github.com/OpenIMSDK/protocol/constant" - "github.com/openimsdk/open-im-server/v3/internal/push/offlinepush" "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" + "github.com/redis/go-redis/v9" + "google.golang.org/api/option" ) const SinglePushCountLimit = 400 diff --git a/internal/push/push_rpc_server.go b/internal/push/push_rpc_server.go index ed2a0b1ef6..2d2f953368 100644 --- a/internal/push/push_rpc_server.go +++ b/internal/push/push_rpc_server.go @@ -16,13 +16,13 @@ package push import ( "context" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/OpenIMSDK/protocol/constant" pbpush "github.com/OpenIMSDK/protocol/push" "github.com/OpenIMSDK/tools/discoveryregistry" "github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/utils" + "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" "github.com/openimsdk/open-im-server/v3/pkg/common/db/localcache" diff --git a/internal/rpc/conversation/conversaion.go b/internal/rpc/conversation/conversaion.go index cc08de2984..15e7998afa 100644 --- a/internal/rpc/conversation/conversaion.go +++ b/internal/rpc/conversation/conversaion.go @@ -17,7 +17,6 @@ package conversation import ( "context" "errors" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" "sort" "github.com/OpenIMSDK/protocol/constant" @@ -28,6 +27,7 @@ import ( "github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/tx" "github.com/OpenIMSDK/tools/utils" + "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/convert" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" diff --git a/internal/rpc/friend/friend.go b/internal/rpc/friend/friend.go index ffdeee98f0..6403a4159d 100644 --- a/internal/rpc/friend/friend.go +++ b/internal/rpc/friend/friend.go @@ -16,33 +16,26 @@ package friend import ( "context" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" - - "github.com/OpenIMSDK/tools/tx" - - "github.com/OpenIMSDK/protocol/sdkws" - - "github.com/openimsdk/open-im-server/v3/pkg/authverify" - - "github.com/OpenIMSDK/tools/log" - - "github.com/openimsdk/open-im-server/v3/pkg/common/convert" - "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" - - "google.golang.org/grpc" "github.com/OpenIMSDK/protocol/constant" pbfriend "github.com/OpenIMSDK/protocol/friend" + "github.com/OpenIMSDK/protocol/sdkws" registry "github.com/OpenIMSDK/tools/discoveryregistry" "github.com/OpenIMSDK/tools/errs" + "github.com/OpenIMSDK/tools/log" + "github.com/OpenIMSDK/tools/tx" "github.com/OpenIMSDK/tools/utils" - + "github.com/openimsdk/open-im-server/v3/pkg/authverify" + "github.com/openimsdk/open-im-server/v3/pkg/common/config" + "github.com/openimsdk/open-im-server/v3/pkg/common/convert" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" "github.com/openimsdk/open-im-server/v3/pkg/common/db/mgo" tablerelation "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" "github.com/openimsdk/open-im-server/v3/pkg/common/db/unrelation" + "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient/notification" + "google.golang.org/grpc" ) type friendServer struct { @@ -118,7 +111,7 @@ func Start(config *config.GlobalConfig, client registry.SvcDiscoveryRegistry, se // ok. func (s *friendServer) ApplyToAddFriend(ctx context.Context, req *pbfriend.ApplyToAddFriendReq) (resp *pbfriend.ApplyToAddFriendResp, err error) { resp = &pbfriend.ApplyToAddFriendResp{} - if err := authverify.CheckAccessV3(ctx, req.FromUserID,s.config); err != nil { + if err := authverify.CheckAccessV3(ctx, req.FromUserID, s.config); err != nil { return nil, err } if req.ToUserID == req.FromUserID { @@ -141,7 +134,7 @@ func (s *friendServer) ApplyToAddFriend(ctx context.Context, req *pbfriend.Apply return nil, err } s.notificationSender.FriendApplicationAddNotification(ctx, req) - if err = CallbackAfterAddFriend(ctx,s.config ,req); err != nil && err != errs.ErrCallbackContinue { + if err = CallbackAfterAddFriend(ctx, s.config, req); err != nil && err != errs.ErrCallbackContinue { return nil, err } return resp, nil diff --git a/internal/rpc/group/group.go b/internal/rpc/group/group.go index 325c1edce1..81299a6485 100644 --- a/internal/rpc/group/group.go +++ b/internal/rpc/group/group.go @@ -17,7 +17,6 @@ package group import ( "context" "fmt" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" "math/big" "math/rand" "strconv" @@ -38,6 +37,7 @@ import ( "github.com/OpenIMSDK/tools/utils" "github.com/openimsdk/open-im-server/v3/pkg/authverify" "github.com/openimsdk/open-im-server/v3/pkg/callbackstruct" + "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/convert" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" diff --git a/internal/rpc/msg/revoke.go b/internal/rpc/msg/revoke.go index 4f844369f7..5ac8804c26 100644 --- a/internal/rpc/msg/revoke.go +++ b/internal/rpc/msg/revoke.go @@ -19,8 +19,6 @@ import ( "encoding/json" "time" - "github.com/openimsdk/open-im-server/v3/pkg/authverify" - "github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/protocol/msg" "github.com/OpenIMSDK/protocol/sdkws" @@ -28,7 +26,7 @@ import ( "github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/mcontext" "github.com/OpenIMSDK/tools/utils" - + "github.com/openimsdk/open-im-server/v3/pkg/authverify" unrelationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/unrelation" ) diff --git a/internal/rpc/msg/send.go b/internal/rpc/msg/send.go index 4bac4d1e0a..949a880b9f 100644 --- a/internal/rpc/msg/send.go +++ b/internal/rpc/msg/send.go @@ -17,9 +17,6 @@ package msg import ( "context" - "github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics" - "github.com/openimsdk/open-im-server/v3/pkg/msgprocessor" - "github.com/OpenIMSDK/protocol/constant" pbconversation "github.com/OpenIMSDK/protocol/conversation" pbmsg "github.com/OpenIMSDK/protocol/msg" @@ -29,6 +26,8 @@ import ( "github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/mcontext" "github.com/OpenIMSDK/tools/utils" + "github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics" + "github.com/openimsdk/open-im-server/v3/pkg/msgprocessor" ) func (m *msgServer) SendMsg(ctx context.Context, req *pbmsg.SendMsgReq) (resp *pbmsg.SendMsgResp, error error) { diff --git a/internal/rpc/msg/server.go b/internal/rpc/msg/server.go index 5b7cd2f662..72e0b065a7 100644 --- a/internal/rpc/msg/server.go +++ b/internal/rpc/msg/server.go @@ -15,20 +15,17 @@ package msg import ( - "github.com/openimsdk/open-im-server/v3/pkg/common/config" - - "google.golang.org/grpc" - "github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/protocol/conversation" "github.com/OpenIMSDK/protocol/msg" "github.com/OpenIMSDK/tools/discoveryregistry" - + "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" "github.com/openimsdk/open-im-server/v3/pkg/common/db/localcache" "github.com/openimsdk/open-im-server/v3/pkg/common/db/unrelation" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" + "google.golang.org/grpc" ) type ( diff --git a/internal/rpc/third/third.go b/internal/rpc/third/third.go index 2bccb5c78f..f1bf2f86cc 100644 --- a/internal/rpc/third/third.go +++ b/internal/rpc/third/third.go @@ -20,23 +20,19 @@ import ( "net/url" "time" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/mgo" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/unrelation" - - "github.com/openimsdk/open-im-server/v3/pkg/common/db/s3" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/s3/cos" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/s3/minio" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/s3/oss" - - "google.golang.org/grpc" - "github.com/OpenIMSDK/protocol/third" "github.com/OpenIMSDK/tools/discoveryregistry" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" + "github.com/openimsdk/open-im-server/v3/pkg/common/db/mgo" + "github.com/openimsdk/open-im-server/v3/pkg/common/db/s3" + "github.com/openimsdk/open-im-server/v3/pkg/common/db/s3/cos" + "github.com/openimsdk/open-im-server/v3/pkg/common/db/s3/minio" + "github.com/openimsdk/open-im-server/v3/pkg/common/db/s3/oss" + "github.com/openimsdk/open-im-server/v3/pkg/common/db/unrelation" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" + "google.golang.org/grpc" ) func Start(config *config.GlobalConfig, client discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) error { diff --git a/internal/rpc/third/tool.go b/internal/rpc/third/tool.go index 6591134d62..d8491d3549 100644 --- a/internal/rpc/third/tool.go +++ b/internal/rpc/third/tool.go @@ -21,11 +21,10 @@ import ( "strings" "unicode/utf8" - "github.com/openimsdk/open-im-server/v3/pkg/authverify" - "github.com/OpenIMSDK/protocol/third" "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/mcontext" + "github.com/openimsdk/open-im-server/v3/pkg/authverify" ) func toPbMapArray(m map[string][]string) []*third.KeyValues { diff --git a/internal/rpc/user/user.go b/internal/rpc/user/user.go index 02e641d202..ae891b7ddd 100644 --- a/internal/rpc/user/user.go +++ b/internal/rpc/user/user.go @@ -21,34 +21,26 @@ import ( "strings" "time" - "github.com/OpenIMSDK/tools/pagination" - - "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" - - "github.com/OpenIMSDK/tools/tx" - - "github.com/openimsdk/open-im-server/v3/pkg/common/db/mgo" - "github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/protocol/sdkws" + pbuser "github.com/OpenIMSDK/protocol/user" + registry "github.com/OpenIMSDK/tools/discoveryregistry" "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/log" - + "github.com/OpenIMSDK/tools/pagination" + "github.com/OpenIMSDK/tools/tx" + "github.com/OpenIMSDK/tools/utils" "github.com/openimsdk/open-im-server/v3/pkg/authverify" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/unrelation" - - registry "github.com/OpenIMSDK/tools/discoveryregistry" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/convert" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" + "github.com/openimsdk/open-im-server/v3/pkg/common/db/mgo" + "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" tablerelation "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" + "github.com/openimsdk/open-im-server/v3/pkg/common/db/unrelation" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient/notification" - - pbuser "github.com/OpenIMSDK/protocol/user" - "github.com/OpenIMSDK/tools/utils" "google.golang.org/grpc" ) diff --git a/internal/tools/cron_task.go b/internal/tools/cron_task.go index ce87e9b900..7535e9b96d 100644 --- a/internal/tools/cron_task.go +++ b/internal/tools/cron_task.go @@ -23,11 +23,10 @@ import ( "time" "github.com/OpenIMSDK/tools/errs" - "github.com/redis/go-redis/v9" - "github.com/robfig/cron/v3" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" + "github.com/redis/go-redis/v9" + "github.com/robfig/cron/v3" ) func StartTask(config *config.GlobalConfig) error { @@ -48,13 +47,13 @@ func StartTask(config *config.GlobalConfig) error { // register cron tasks var crontab = cron.New() fmt.Printf("Start chatRecordsClearTime cron task, cron config: %s\n", config.ChatRecordsClearTime) - _, err = crontab.AddFunc(config.ChatRecordsClearTime, cronWrapFunc(config,rdb, "cron_clear_msg_and_fix_seq", msgTool.AllConversationClearMsgAndFixSeq)) + _, err = crontab.AddFunc(config.ChatRecordsClearTime, cronWrapFunc(config, rdb, "cron_clear_msg_and_fix_seq", msgTool.AllConversationClearMsgAndFixSeq)) if err != nil { return errs.Wrap(err) } fmt.Printf("Start msgDestruct cron task, cron config: %s\n", config.MsgDestructTime) - _, err = crontab.AddFunc(config.MsgDestructTime, cronWrapFunc(config,rdb, "cron_conversations_destruct_msgs", msgTool.ConversationsDestructMsgs)) + _, err = crontab.AddFunc(config.MsgDestructTime, cronWrapFunc(config, rdb, "cron_conversations_destruct_msgs", msgTool.ConversationsDestructMsgs)) if err != nil { return errs.Wrap(err, "cron_conversations_destruct_msgs") } diff --git a/internal/tools/cron_task_test.go b/internal/tools/cron_task_test.go index fcae5a5f68..17346b1c51 100644 --- a/internal/tools/cron_task_test.go +++ b/internal/tools/cron_task_test.go @@ -17,14 +17,15 @@ package tools import ( "flag" "fmt" - "github.com/OpenIMSDK/tools/errs" - "gopkg.in/yaml.v3" "math/rand" "os" "sync" "testing" "time" + "github.com/OpenIMSDK/tools/errs" + "gopkg.in/yaml.v3" + "github.com/redis/go-redis/v9" "github.com/robfig/cron/v3" "github.com/stretchr/testify/assert" diff --git a/pkg/common/cmd/api.go b/pkg/common/cmd/api.go index 859508ce3e..bee16fdad4 100644 --- a/pkg/common/cmd/api.go +++ b/pkg/common/cmd/api.go @@ -17,9 +17,8 @@ package cmd import ( "github.com/OpenIMSDK/protocol/constant" "github.com/openimsdk/open-im-server/v3/internal/api" - "github.com/spf13/cobra" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" + "github.com/spf13/cobra" ) type ApiCmd struct { diff --git a/pkg/common/cmd/msg_gateway.go b/pkg/common/cmd/msg_gateway.go index 3a939fa972..37aedd933d 100644 --- a/pkg/common/cmd/msg_gateway.go +++ b/pkg/common/cmd/msg_gateway.go @@ -17,11 +17,9 @@ package cmd import ( "log" - "github.com/spf13/cobra" - "github.com/OpenIMSDK/protocol/constant" - "github.com/openimsdk/open-im-server/v3/internal/msggateway" + "github.com/spf13/cobra" ) type MsgGatewayCmd struct { diff --git a/pkg/common/cmd/msg_transfer.go b/pkg/common/cmd/msg_transfer.go index e46b66b52d..d98154f3a3 100644 --- a/pkg/common/cmd/msg_transfer.go +++ b/pkg/common/cmd/msg_transfer.go @@ -16,10 +16,10 @@ package cmd import ( "fmt" - "github.com/OpenIMSDK/protocol/constant" - "github.com/spf13/cobra" + "github.com/OpenIMSDK/protocol/constant" "github.com/openimsdk/open-im-server/v3/internal/msgtransfer" + "github.com/spf13/cobra" ) type MsgTransferCmd struct { diff --git a/pkg/common/cmd/rpc.go b/pkg/common/cmd/rpc.go index 5199524e7b..9c6dbddd6f 100644 --- a/pkg/common/cmd/rpc.go +++ b/pkg/common/cmd/rpc.go @@ -16,17 +16,14 @@ package cmd import ( "errors" - "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/protocol/constant" - "github.com/spf13/cobra" - "google.golang.org/grpc" - - config2 "github.com/openimsdk/open-im-server/v3/pkg/common/config" - "github.com/OpenIMSDK/tools/discoveryregistry" - + "github.com/OpenIMSDK/tools/errs" + config2 "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/startrpc" + "github.com/spf13/cobra" + "google.golang.org/grpc" ) type rpcInitFuc func(config *config2.GlobalConfig, disCov discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) error diff --git a/pkg/common/db/cache/meta_cache.go b/pkg/common/db/cache/meta_cache.go index 1fbb6c3b66..00dadfff87 100644 --- a/pkg/common/db/cache/meta_cache.go +++ b/pkg/common/db/cache/meta_cache.go @@ -21,13 +21,11 @@ import ( "fmt" "time" - "github.com/OpenIMSDK/tools/mw/specialerror" - - "github.com/dtm-labs/rockscache" - "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/log" + "github.com/OpenIMSDK/tools/mw/specialerror" "github.com/OpenIMSDK/tools/utils" + "github.com/dtm-labs/rockscache" ) const ( diff --git a/pkg/common/db/cache/user.go b/pkg/common/db/cache/user.go index 34c220624a..837e7a5bc1 100644 --- a/pkg/common/db/cache/user.go +++ b/pkg/common/db/cache/user.go @@ -22,16 +22,12 @@ import ( "strconv" "time" - relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" - - "github.com/OpenIMSDK/tools/log" - "github.com/OpenIMSDK/protocol/constant" - "github.com/OpenIMSDK/protocol/user" "github.com/OpenIMSDK/tools/errs" - + "github.com/OpenIMSDK/tools/log" "github.com/dtm-labs/rockscache" + relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" "github.com/redis/go-redis/v9" ) diff --git a/pkg/common/db/controller/auth.go b/pkg/common/db/controller/auth.go index 19bea59818..7cafa1c487 100644 --- a/pkg/common/db/controller/auth.go +++ b/pkg/common/db/controller/auth.go @@ -16,13 +16,13 @@ package controller import ( "context" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/tokenverify" "github.com/golang-jwt/jwt/v4" "github.com/openimsdk/open-im-server/v3/pkg/authverify" + "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" ) diff --git a/pkg/common/db/s3/cos/cos.go b/pkg/common/db/s3/cos/cos.go index a7c26fcc16..9852d2a981 100644 --- a/pkg/common/db/s3/cos/cos.go +++ b/pkg/common/db/s3/cos/cos.go @@ -23,13 +23,13 @@ import ( "encoding/json" "errors" "fmt" - "github.com/OpenIMSDK/tools/errs" "net/http" "net/url" "strconv" "strings" "time" + "github.com/OpenIMSDK/tools/errs" "github.com/openimsdk/open-im-server/v3/pkg/common/db/s3" "github.com/tencentyun/cos-go-sdk-v5" ) diff --git a/pkg/common/db/s3/minio/minio.go b/pkg/common/db/s3/minio/minio.go index cd77948d45..10526998fb 100644 --- a/pkg/common/db/s3/minio/minio.go +++ b/pkg/common/db/s3/minio/minio.go @@ -18,7 +18,6 @@ import ( "context" "errors" "fmt" - "github.com/OpenIMSDK/tools/errs" "io" "net/http" "net/url" @@ -30,6 +29,7 @@ import ( "time" "unsafe" + "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/log" "github.com/minio/minio-go/v7" "github.com/minio/minio-go/v7/pkg/credentials" diff --git a/pkg/common/discoveryregister/discoveryregister.go b/pkg/common/discoveryregister/discoveryregister.go index c43583a807..d3acf85f69 100644 --- a/pkg/common/discoveryregister/discoveryregister.go +++ b/pkg/common/discoveryregister/discoveryregister.go @@ -16,11 +16,11 @@ package discoveryregister import ( "errors" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" "os" "github.com/OpenIMSDK/tools/discoveryregistry" "github.com/OpenIMSDK/tools/errs" + "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/discoveryregister/direct" "github.com/openimsdk/open-im-server/v3/pkg/common/discoveryregister/kubernetes" "github.com/openimsdk/open-im-server/v3/pkg/common/discoveryregister/zookeeper" diff --git a/pkg/common/discoveryregister/discoveryregister_test.go b/pkg/common/discoveryregister/discoveryregister_test.go index 7d4fa53cd2..08aa5d5d5e 100644 --- a/pkg/common/discoveryregister/discoveryregister_test.go +++ b/pkg/common/discoveryregister/discoveryregister_test.go @@ -15,10 +15,11 @@ package discoveryregister import ( - "github.com/openimsdk/open-im-server/v3/pkg/common/config" "os" "testing" + "github.com/openimsdk/open-im-server/v3/pkg/common/config" + "github.com/OpenIMSDK/tools/discoveryregistry" "github.com/stretchr/testify/assert" ) diff --git a/pkg/common/discoveryregister/kubernetes/kubernetes.go b/pkg/common/discoveryregister/kubernetes/kubernetes.go index b5d603fd17..83af53db07 100644 --- a/pkg/common/discoveryregister/kubernetes/kubernetes.go +++ b/pkg/common/discoveryregister/kubernetes/kubernetes.go @@ -22,12 +22,10 @@ import ( "strconv" "strings" - "github.com/stathat/consistent" - - "google.golang.org/grpc" - "github.com/OpenIMSDK/tools/discoveryregistry" "github.com/OpenIMSDK/tools/log" + "github.com/stathat/consistent" + "google.golang.org/grpc" ) // K8sDR represents the Kubernetes service discovery and registration client. diff --git a/pkg/common/kafka/consumer.go b/pkg/common/kafka/consumer.go index 664e5d4684..6627c21aea 100644 --- a/pkg/common/kafka/consumer.go +++ b/pkg/common/kafka/consumer.go @@ -17,10 +17,9 @@ package kafka import ( "sync" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" - "github.com/IBM/sarama" "github.com/OpenIMSDK/tools/errs" + "github.com/openimsdk/open-im-server/v3/pkg/common/config" ) type Consumer struct { @@ -31,7 +30,7 @@ type Consumer struct { Consumer sarama.Consumer } -func NewKafkaConsumer(addr []string, topic string, config *config.GlobalConfig) (*Consumer,error) { +func NewKafkaConsumer(addr []string, topic string, config *config.GlobalConfig) (*Consumer, error) { p := Consumer{} p.Topic = topic p.addr = addr @@ -51,9 +50,9 @@ func NewKafkaConsumer(addr []string, topic string, config *config.GlobalConfig) InsecureSkipVerify: false, } } - err:=SetupTLSConfig(consumerConfig, tlsConfig) - if err!=nil{ - return nil,err + err := SetupTLSConfig(consumerConfig, tlsConfig) + if err != nil { + return nil, err } consumer, err := sarama.NewConsumer(p.addr, consumerConfig) if err != nil { diff --git a/pkg/common/kafka/consumer_group.go b/pkg/common/kafka/consumer_group.go index b6b4435ab8..95794aacb7 100644 --- a/pkg/common/kafka/consumer_group.go +++ b/pkg/common/kafka/consumer_group.go @@ -17,12 +17,11 @@ package kafka import ( "context" "errors" + "strings" "github.com/IBM/sarama" "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/log" - - "strings" ) type MConsumerGroup struct { diff --git a/pkg/common/kafka/producer.go b/pkg/common/kafka/producer.go index afc53b35a2..8ee938b515 100644 --- a/pkg/common/kafka/producer.go +++ b/pkg/common/kafka/producer.go @@ -22,10 +22,9 @@ import ( "strings" "time" - "github.com/OpenIMSDK/tools/errs" - "github.com/IBM/sarama" "github.com/OpenIMSDK/protocol/constant" + "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/mcontext" "google.golang.org/protobuf/proto" diff --git a/pkg/common/startrpc/start.go b/pkg/common/startrpc/start.go index 8af894ac0c..bf95509d11 100644 --- a/pkg/common/startrpc/start.go +++ b/pkg/common/startrpc/start.go @@ -18,7 +18,6 @@ import ( "context" "errors" "fmt" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" "net" "net/http" "os" @@ -28,25 +27,20 @@ import ( "syscall" "time" + "github.com/OpenIMSDK/tools/discoveryregistry" "github.com/OpenIMSDK/tools/errs" - + "github.com/OpenIMSDK/tools/mw" + "github.com/OpenIMSDK/tools/network" + grpcprometheus "github.com/grpc-ecosystem/go-grpc-prometheus" + "github.com/openimsdk/open-im-server/v3/pkg/common/config" + config2 "github.com/openimsdk/open-im-server/v3/pkg/common/config" + kdisc "github.com/openimsdk/open-im-server/v3/pkg/common/discoveryregister" + "github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics" util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" - "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promhttp" - - config2 "github.com/openimsdk/open-im-server/v3/pkg/common/config" - "github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics" - - grpcprometheus "github.com/grpc-ecosystem/go-grpc-prometheus" "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" - - kdisc "github.com/openimsdk/open-im-server/v3/pkg/common/discoveryregister" - - "github.com/OpenIMSDK/tools/discoveryregistry" - "github.com/OpenIMSDK/tools/mw" - "github.com/OpenIMSDK/tools/network" ) // Start rpc server. diff --git a/pkg/common/startrpc/start_test.go b/pkg/common/startrpc/start_test.go index e5e37e2212..754fc9c502 100644 --- a/pkg/common/startrpc/start_test.go +++ b/pkg/common/startrpc/start_test.go @@ -16,11 +16,12 @@ package startrpc import ( "fmt" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" "net" "testing" "time" + "github.com/openimsdk/open-im-server/v3/pkg/common/config" + "github.com/OpenIMSDK/tools/discoveryregistry" "google.golang.org/grpc" ) diff --git a/pkg/common/tls/tls.go b/pkg/common/tls/tls.go index 7369137583..9666ed9c87 100755 --- a/pkg/common/tls/tls.go +++ b/pkg/common/tls/tls.go @@ -49,7 +49,7 @@ func readEncryptablePEMBlock(path string, pwd []byte) ([]byte, error) { } // NewTLSConfig setup the TLS config from general config file. -func NewTLSConfig(clientCertFile, clientKeyFile, caCertFile string, keyPwd []byte, insecureSkipVerify bool) (*tls.Config,error) { +func NewTLSConfig(clientCertFile, clientKeyFile, caCertFile string, keyPwd []byte, insecureSkipVerify bool) (*tls.Config, error) { tlsConfig := tls.Config{} if clientCertFile != "" && clientKeyFile != "" { diff --git a/pkg/rpcclient/msg.go b/pkg/rpcclient/msg.go index 3db39925ed..61679f28ac 100644 --- a/pkg/rpcclient/msg.go +++ b/pkg/rpcclient/msg.go @@ -18,12 +18,12 @@ import ( "context" "encoding/json" "fmt" - "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/protocol/msg" "github.com/OpenIMSDK/protocol/sdkws" "github.com/OpenIMSDK/tools/discoveryregistry" + "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/utils" "github.com/openimsdk/open-im-server/v3/pkg/common/config" diff --git a/pkg/rpcclient/notification/conversation.go b/pkg/rpcclient/notification/conversation.go index 115fb81a24..1544d6a1f7 100644 --- a/pkg/rpcclient/notification/conversation.go +++ b/pkg/rpcclient/notification/conversation.go @@ -16,10 +16,10 @@ package notification import ( "context" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/protocol/sdkws" + "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" ) diff --git a/pkg/rpcclient/notification/friend.go b/pkg/rpcclient/notification/friend.go index 31426da317..dafca055a1 100644 --- a/pkg/rpcclient/notification/friend.go +++ b/pkg/rpcclient/notification/friend.go @@ -16,12 +16,12 @@ package notification import ( "context" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/OpenIMSDK/protocol/constant" pbfriend "github.com/OpenIMSDK/protocol/friend" "github.com/OpenIMSDK/protocol/sdkws" "github.com/OpenIMSDK/tools/mcontext" + "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/convert" "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" diff --git a/pkg/rpcclient/notification/group.go b/pkg/rpcclient/notification/group.go index 5500f4f433..5fd794be29 100644 --- a/pkg/rpcclient/notification/group.go +++ b/pkg/rpcclient/notification/group.go @@ -17,7 +17,6 @@ package notification import ( "context" "fmt" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/OpenIMSDK/protocol/constant" pbgroup "github.com/OpenIMSDK/protocol/group" @@ -27,6 +26,7 @@ import ( "github.com/OpenIMSDK/tools/mcontext" "github.com/OpenIMSDK/tools/utils" "github.com/openimsdk/open-im-server/v3/pkg/authverify" + "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" diff --git a/pkg/rpcclient/notification/msg.go b/pkg/rpcclient/notification/msg.go index 19819e7b7c..beaef1d969 100644 --- a/pkg/rpcclient/notification/msg.go +++ b/pkg/rpcclient/notification/msg.go @@ -16,10 +16,10 @@ package notification import ( "context" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/protocol/sdkws" + "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" ) diff --git a/pkg/rpcclient/notification/user.go b/pkg/rpcclient/notification/user.go index 204b13e613..610967fd55 100644 --- a/pkg/rpcclient/notification/user.go +++ b/pkg/rpcclient/notification/user.go @@ -16,10 +16,10 @@ package notification import ( "context" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/protocol/sdkws" + "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" diff --git a/pkg/rpcclient/third.go b/pkg/rpcclient/third.go old mode 100755 new mode 100644 index 50d545a649..a1f8ae180a --- a/pkg/rpcclient/third.go +++ b/pkg/rpcclient/third.go @@ -16,15 +16,13 @@ package rpcclient import ( "context" - "github.com/OpenIMSDK/tools/errs" "net/url" - "github.com/minio/minio-go/v7" - "github.com/minio/minio-go/v7/pkg/credentials" - "github.com/OpenIMSDK/protocol/third" "github.com/OpenIMSDK/tools/discoveryregistry" - + "github.com/OpenIMSDK/tools/errs" + "github.com/minio/minio-go/v7" + "github.com/minio/minio-go/v7/pkg/credentials" "github.com/openimsdk/open-im-server/v3/pkg/common/config" util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" "google.golang.org/grpc" diff --git a/tools/up35/pkg/pkg.go b/tools/up35/pkg/pkg.go index 1348172d2a..49f471204b 100644 --- a/tools/up35/pkg/pkg.go +++ b/tools/up35/pkg/pkg.go @@ -18,12 +18,13 @@ import ( "context" "errors" "fmt" - "github.com/OpenIMSDK/tools/errs" "log" "os" "reflect" "strconv" + "github.com/OpenIMSDK/tools/errs" + "gopkg.in/yaml.v3" "github.com/go-sql-driver/mysql" From 52b8efba73522f8cbf0557a0f86f3a125387eeac Mon Sep 17 00:00:00 2001 From: Brabem <69128477+luhaoling@users.noreply.github.com> Date: Wed, 6 Mar 2024 16:20:07 +0800 Subject: [PATCH 086/188] fix: wrap the error of group user and thrid (#2005) * fix: wrap the error of group user and thrid * fix: del the chinese comment * fix: fix the make_lint error * fix: fix the ApiTest error --- internal/rpc/group/group.go | 8 ++++---- internal/rpc/third/s3.go | 4 ++-- internal/rpc/third/third.go | 7 ++++--- internal/rpc/user/user.go | 15 ++++++--------- pkg/common/db/cache/meta_cache.go | 4 ++-- pkg/common/db/cache/msg.go | 2 +- pkg/common/db/mgo/object.go | 3 ++- pkg/common/db/mgo/user.go | 14 +++++++------- pkg/common/db/s3/minio/image.go | 18 +++++++++--------- pkg/common/db/unrelation/mongo.go | 7 +++---- .../discoveryregister/direct/directconn.go | 4 ++-- pkg/rpcclient/msg.go | 5 +++-- tools/up35/pkg/pkg.go | 8 ++++---- 13 files changed, 49 insertions(+), 50 deletions(-) diff --git a/internal/rpc/group/group.go b/internal/rpc/group/group.go index 81299a6485..d44c79b45d 100644 --- a/internal/rpc/group/group.go +++ b/internal/rpc/group/group.go @@ -120,12 +120,12 @@ func (s *groupServer) NotificationUserInfoUpdate(ctx context.Context, req *pbgro groupIDs = append(groupIDs, member.GroupID) } for _, groupID := range groupIDs { - if err := s.Notification.GroupMemberInfoSetNotification(ctx, groupID, req.UserID); err != nil { - log.ZError(ctx, "NotificationUserInfoUpdate setGroupMemberInfo notification failed", err, "groupID", groupID) + if err = s.Notification.GroupMemberInfoSetNotification(ctx, groupID, req.UserID); err != nil { + return nil, err } } - if err := s.db.DeleteGroupMemberHash(ctx, groupIDs); err != nil { - log.ZError(ctx, "NotificationUserInfoUpdate DeleteGroupMemberHash", err, "groupID", groupIDs) + if err = s.db.DeleteGroupMemberHash(ctx, groupIDs); err != nil { + return nil, err } return &pbgroup.NotificationUserInfoUpdateResp{}, nil diff --git a/internal/rpc/third/s3.go b/internal/rpc/third/s3.go index 1975163e5e..f79b73a993 100644 --- a/internal/rpc/third/s3.go +++ b/internal/rpc/third/s3.go @@ -209,7 +209,7 @@ func (t *thirdServer) InitiateFormData(ctx context.Context, req *third.InitiateF } uid, err := uuid.NewRandom() if err != nil { - return nil, err + return nil, errs.Wrap(err, "uuid NewRandom failed") } if key == "" { date := time.Now().Format("20060102") @@ -224,7 +224,7 @@ func (t *thirdServer) InitiateFormData(ctx context.Context, req *third.InitiateF } mateData, err := json.Marshal(&mate) if err != nil { - return nil, err + return nil, errs.Wrap(err, "marshal failed") } resp, err := t.s3dataBase.FormData(ctx, key, req.Size, req.ContentType, duration) if err != nil { diff --git a/internal/rpc/third/third.go b/internal/rpc/third/third.go index f1bf2f86cc..5f6fc6c343 100644 --- a/internal/rpc/third/third.go +++ b/internal/rpc/third/third.go @@ -17,6 +17,7 @@ package third import ( "context" "fmt" + "github.com/OpenIMSDK/tools/errs" "net/url" "time" @@ -50,9 +51,9 @@ func Start(config *config.GlobalConfig, client discoveryregistry.SvcDiscoveryReg } apiURL := config.Object.ApiURL if apiURL == "" { - return fmt.Errorf("api url is empty") + return errs.Wrap(fmt.Errorf("api is empty")) } - if _, parseErr := url.Parse(config.Object.ApiURL); parseErr != nil { + if _, err := url.Parse(config.Object.ApiURL); err != nil { return err } if apiURL[len(apiURL)-1] != '/' { @@ -63,7 +64,7 @@ func Start(config *config.GlobalConfig, client discoveryregistry.SvcDiscoveryReg if err != nil { return err } - // 根据配置文件策略选择 oss 方式 + // Select the oss method according to the profile policy enable := config.Object.Enable var o s3.Interface switch enable { diff --git a/internal/rpc/user/user.go b/internal/rpc/user/user.go index ae891b7ddd..3d13cd7b6f 100644 --- a/internal/rpc/user/user.go +++ b/internal/rpc/user/user.go @@ -16,7 +16,7 @@ package user import ( "context" - "errors" + "fmt" "math/rand" "strings" "time" @@ -70,7 +70,7 @@ func Start(config *config.GlobalConfig, client registry.SvcDiscoveryRegistry, se } users := make([]*tablerelation.UserModel, 0) if len(config.IMAdmin.UserID) != len(config.IMAdmin.Nickname) { - return errors.New("len(s.config.AppNotificationAdmin.AppManagerUid) != len(s.config.AppNotificationAdmin.Nickname)") + return errs.Wrap(fmt.Errorf("the count of ImAdmin.UserID is not equal to the count of ImAdmin.Nickname")) } for k, v := range config.IMAdmin.UserID { users = append(users, &tablerelation.UserModel{UserID: v, Nickname: config.IMAdmin.Nickname[k], AppMangerLevel: constant.AppNotificationAdmin}) @@ -105,9 +105,6 @@ func (s *userServer) GetDesignateUsers(ctx context.Context, req *pbuser.GetDesig return nil, err } resp.UsersInfo = convert.UsersDB2Pb(users) - if err != nil { - return nil, err - } return resp, nil } @@ -131,7 +128,7 @@ func (s *userServer) UpdateUserInfo(ctx context.Context, req *pbuser.UpdateUserI } if req.UserInfo.Nickname != "" || req.UserInfo.FaceURL != "" { if err = s.groupRpcClient.NotificationUserInfoUpdate(ctx, req.UserInfo.UserID); err != nil { - log.ZError(ctx, "NotificationUserInfoUpdate", err) + return nil, err } } for _, friendID := range friends { @@ -141,7 +138,7 @@ func (s *userServer) UpdateUserInfo(ctx context.Context, req *pbuser.UpdateUserI return nil, err } if err = s.groupRpcClient.NotificationUserInfoUpdate(ctx, req.UserInfo.UserID); err != nil { - log.ZError(ctx, "NotificationUserInfoUpdate", err, "userID", req.UserInfo.UserID) + return nil, err } return resp, nil } @@ -166,7 +163,7 @@ func (s *userServer) UpdateUserInfoEx(ctx context.Context, req *pbuser.UpdateUse } if req.UserInfo.Nickname != nil || req.UserInfo.FaceURL != nil { if err := s.groupRpcClient.NotificationUserInfoUpdate(ctx, req.UserInfo.UserID); err != nil { - log.ZError(ctx, "NotificationUserInfoUpdate", err) + return nil, err } } for _, friendID := range friends { @@ -176,7 +173,7 @@ func (s *userServer) UpdateUserInfoEx(ctx context.Context, req *pbuser.UpdateUse return nil, err } if err := s.groupRpcClient.NotificationUserInfoUpdate(ctx, req.UserInfo.UserID); err != nil { - log.ZError(ctx, "NotificationUserInfoUpdate", err, "userID", req.UserInfo.UserID) + return nil, err } return resp, nil } diff --git a/pkg/common/db/cache/meta_cache.go b/pkg/common/db/cache/meta_cache.go index 00dadfff87..4d4f077b67 100644 --- a/pkg/common/db/cache/meta_cache.go +++ b/pkg/common/db/cache/meta_cache.go @@ -129,7 +129,7 @@ func getCache[T any](ctx context.Context, rcClient *rockscache.Client, key strin v, err := rcClient.Fetch2(ctx, key, expire, func() (s string, err error) { t, err = fn(ctx) if err != nil { - return "", errs.Wrap(err) + return "", err } bs, err := json.Marshal(t) if err != nil { @@ -204,7 +204,7 @@ func batchGetCache2[T any, K comparable]( fns func(ctx context.Context, key K) (T, error), ) ([]T, error) { if len(keys) == 0 { - return nil, errs.ErrArgs.Wrap("groupID is empty") + return nil, nil } res := make([]T, 0, len(keys)) for _, key := range keys { diff --git a/pkg/common/db/cache/msg.go b/pkg/common/db/cache/msg.go index 1266875f1a..9b488c1bfd 100644 --- a/pkg/common/db/cache/msg.go +++ b/pkg/common/db/cache/msg.go @@ -471,7 +471,7 @@ func (c *msgCache) ParallelSetMessageToCache(ctx context.Context, conversationID err := wg.Wait() if err != nil { - return 0, err + return 0, errs.Wrap(err, "wg.Wait failed") } return len(msgs), nil diff --git a/pkg/common/db/mgo/object.go b/pkg/common/db/mgo/object.go index 4c333afd61..a527fa60d5 100644 --- a/pkg/common/db/mgo/object.go +++ b/pkg/common/db/mgo/object.go @@ -16,6 +16,7 @@ package mgo import ( "context" + "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/mgoutil" "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" @@ -33,7 +34,7 @@ func NewS3Mongo(db *mongo.Database) (relation.ObjectInfoModelInterface, error) { Options: options.Index().SetUnique(true), }) if err != nil { - return nil, err + return nil, errs.Wrap(err) } return &S3Mongo{coll: coll}, nil } diff --git a/pkg/common/db/mgo/user.go b/pkg/common/db/mgo/user.go index dcdc14d4a0..9ca2eb1785 100644 --- a/pkg/common/db/mgo/user.go +++ b/pkg/common/db/mgo/user.go @@ -157,7 +157,7 @@ func (u *UserMgo) AddUserCommand(ctx context.Context, userID string, Type int32, } _, err := collection.InsertOne(ctx, doc) - return err + return errs.Wrap(err) } func (u *UserMgo) DeleteUserCommand(ctx context.Context, userID string, Type int32, UUID string) error { @@ -170,7 +170,7 @@ func (u *UserMgo) DeleteUserCommand(ctx context.Context, userID string, Type int // No records found to update return errs.Wrap(errs.ErrRecordNotFound) } - return err + return errs.Wrap(err) } func (u *UserMgo) UpdateUserCommand(ctx context.Context, userID string, Type int32, UUID string, val map[string]any) error { if len(val) == 0 { @@ -184,7 +184,7 @@ func (u *UserMgo) UpdateUserCommand(ctx context.Context, userID string, Type int result, err := collection.UpdateOne(ctx, filter, update) if err != nil { - return err + return errs.Wrap(err) } if result.MatchedCount == 0 { @@ -233,7 +233,7 @@ func (u *UserMgo) GetUserCommand(ctx context.Context, userID string, Type int32) } if err := cursor.Err(); err != nil { - return nil, err + return nil, errs.Wrap(err) } return commands, nil @@ -244,7 +244,7 @@ func (u *UserMgo) GetAllUserCommand(ctx context.Context, userID string) ([]*user cursor, err := collection.Find(ctx, filter) if err != nil { - return nil, err + return nil, errs.Wrap(err) } defer cursor.Close(ctx) @@ -261,7 +261,7 @@ func (u *UserMgo) GetAllUserCommand(ctx context.Context, userID string) ([]*user } if err := cursor.Decode(&document); err != nil { - return nil, err + return nil, errs.Wrap(err) } commandInfo := &user.AllCommandInfoResp{ @@ -276,7 +276,7 @@ func (u *UserMgo) GetAllUserCommand(ctx context.Context, userID string) ([]*user } if err := cursor.Err(); err != nil { - return nil, err + return nil, errs.Wrap(err) } return commands, nil } diff --git a/pkg/common/db/s3/minio/image.go b/pkg/common/db/s3/minio/image.go index 71db1ea519..3223993f43 100644 --- a/pkg/common/db/s3/minio/image.go +++ b/pkg/common/db/s3/minio/image.go @@ -47,27 +47,27 @@ func resizeImage(img image.Image, maxWidth, maxHeight int) image.Image { imgWidth := bounds.Max.X imgHeight := bounds.Max.Y - // 计算缩放比例 + // Calculating scaling scaleWidth := float64(maxWidth) / float64(imgWidth) scaleHeight := float64(maxHeight) / float64(imgHeight) - // 如果都为0,则不缩放,返回原始图片 + // If both are 0, then no scaling is done and the original image is returned if maxWidth == 0 && maxHeight == 0 { return img } - // 如果宽度和高度都大于0,则选择较小的缩放比例,以保持宽高比 + // If both width and height are greater than 0, select a smaller zoom ratio to maintain the aspect ratio if maxWidth > 0 && maxHeight > 0 { scale := scaleWidth if scaleHeight < scaleWidth { scale = scaleHeight } - // 计算缩略图尺寸 + // Calculate Thumbnail Size thumbnailWidth := int(float64(imgWidth) * scale) thumbnailHeight := int(float64(imgHeight) * scale) - // 使用"image"库的Resample方法生成缩略图 + // Thumbnails are generated using the Resample method of the "image" library. thumbnail := image.NewRGBA(image.Rect(0, 0, thumbnailWidth, thumbnailHeight)) for y := 0; y < thumbnailHeight; y++ { for x := 0; x < thumbnailWidth; x++ { @@ -80,12 +80,12 @@ func resizeImage(img image.Image, maxWidth, maxHeight int) image.Image { return thumbnail } - // 如果只指定了宽度或高度,则根据最大不超过的规则生成缩略图 + // If only width or height is specified, thumbnails are generated based on the maximum not to exceed rule if maxWidth > 0 { thumbnailWidth := maxWidth thumbnailHeight := int(float64(imgHeight) * scaleWidth) - // 使用"image"库的Resample方法生成缩略图 + // Thumbnails are generated using the Resample method of the "image" library. thumbnail := image.NewRGBA(image.Rect(0, 0, thumbnailWidth, thumbnailHeight)) for y := 0; y < thumbnailHeight; y++ { for x := 0; x < thumbnailWidth; x++ { @@ -102,7 +102,7 @@ func resizeImage(img image.Image, maxWidth, maxHeight int) image.Image { thumbnailWidth := int(float64(imgWidth) * scaleHeight) thumbnailHeight := maxHeight - // 使用"image"库的Resample方法生成缩略图 + // Thumbnails are generated using the Resample method of the "image" library. thumbnail := image.NewRGBA(image.Rect(0, 0, thumbnailWidth, thumbnailHeight)) for y := 0; y < thumbnailHeight; y++ { for x := 0; x < thumbnailWidth; x++ { @@ -115,6 +115,6 @@ func resizeImage(img image.Image, maxWidth, maxHeight int) image.Image { return thumbnail } - // 默认情况下,返回原始图片 + // By default, the original image is returned return img } diff --git a/pkg/common/db/unrelation/mongo.go b/pkg/common/db/unrelation/mongo.go index 363e978675..834e812375 100644 --- a/pkg/common/db/unrelation/mongo.go +++ b/pkg/common/db/unrelation/mongo.go @@ -102,12 +102,11 @@ func buildMongoURI(config *config.GlobalConfig) string { maxPoolSize = fmt.Sprint(config.Mongo.MaxPoolSize) } - uriFormat := "mongodb://%s/%s?maxPoolSize=%s" if username != "" && password != "" { - uriFormat = "mongodb://%s:%s@%s/%s?maxPoolSize=%s" - return fmt.Sprintf(uriFormat, username, password, address, database, maxPoolSize) + + return fmt.Sprintf("mongodb://%s:%s@%s/%s?maxPoolSize=%s", username, password, address, database, maxPoolSize) } - return fmt.Sprintf(uriFormat, address, database, maxPoolSize) + return fmt.Sprintf("mongodb://%s/%s?maxPoolSize=%s", address, database, maxPoolSize) } func shouldRetry(err error) bool { diff --git a/pkg/common/discoveryregister/direct/directconn.go b/pkg/common/discoveryregister/direct/directconn.go index ced2096026..df03825e51 100644 --- a/pkg/common/discoveryregister/direct/directconn.go +++ b/pkg/common/discoveryregister/direct/directconn.go @@ -100,7 +100,7 @@ func (cd *ConnDirect) GetConns(ctx context.Context, for _, port := range ports { conn, err := cd.dialServiceWithoutResolver(ctx, fmt.Sprintf(cd.config.Rpc.ListenIP+":%d", port), append(cd.additionalOpts, opts...)...) if err != nil { - fmt.Printf("connect to port %d failed,serviceName %s, IP %s\n", port, serviceName, cd.config.Rpc.ListenIP) + return nil, errs.Wrap(fmt.Errorf("connect to port %d failed,serviceName %s, IP %s", port, serviceName, cd.config.Rpc.ListenIP)) } connections = append(connections, conn) } @@ -166,7 +166,7 @@ func (cd *ConnDirect) dialServiceWithoutResolver(ctx context.Context, address st conn, err := grpc.DialContext(ctx, address, options...) if err != nil { - return nil, err + return nil, errs.Wrap(err) } return conn, nil } diff --git a/pkg/rpcclient/msg.go b/pkg/rpcclient/msg.go index 61679f28ac..4daf897a16 100644 --- a/pkg/rpcclient/msg.go +++ b/pkg/rpcclient/msg.go @@ -18,12 +18,13 @@ import ( "context" "encoding/json" "fmt" + "github.com/OpenIMSDK/tools/errs" + util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" "github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/protocol/msg" "github.com/OpenIMSDK/protocol/sdkws" "github.com/OpenIMSDK/tools/discoveryregistry" - "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/utils" "github.com/openimsdk/open-im-server/v3/pkg/common/config" @@ -135,7 +136,7 @@ type Message struct { func NewMessage(discov discoveryregistry.SvcDiscoveryRegistry, config *config.GlobalConfig) *Message { conn, err := discov.GetConn(context.Background(), config.RpcRegisterName.OpenImMsgName) if err != nil { - panic(err) + util.ExitWithError(err) } client := msg.NewMsgClient(conn) return &Message{discov: discov, conn: conn, Client: client, Config: config} diff --git a/tools/up35/pkg/pkg.go b/tools/up35/pkg/pkg.go index 49f471204b..54aef1ce96 100644 --- a/tools/up35/pkg/pkg.go +++ b/tools/up35/pkg/pkg.go @@ -161,7 +161,7 @@ func NewTask[A interface{ TableName() string }, B any, C any](gormDB *gorm.DB, m tableName := zero.TableName() coll, err := getColl(obj) if err != nil { - return fmt.Errorf("get mongo collection %s failed, err: %w", tableName, err) + return errs.Wrap(fmt.Errorf("get mongo collection %s failed, err: %w", tableName, err)) } var count int defer func() { @@ -174,7 +174,7 @@ func NewTask[A interface{ TableName() string }, B any, C any](gormDB *gorm.DB, m if mysqlErr, ok := err.(*mysql.MySQLError); ok && mysqlErr.Number == 1146 { return nil // table not exist } - return fmt.Errorf("find mysql table %s failed, err: %w", tableName, err) + return errs.Wrap(fmt.Errorf("find mysql table %s failed, err: %w", tableName, err)) } if len(res) == 0 { return nil @@ -184,7 +184,7 @@ func NewTask[A interface{ TableName() string }, B any, C any](gormDB *gorm.DB, m temp[i] = convert(res[i]) } if err := insertMany(coll, temp); err != nil { - return fmt.Errorf("insert mongo table %s failed, err: %w", tableName, err) + return errs.Wrap(fmt.Errorf("insert mongo table %s failed, err: %w", tableName, err)) } count += len(res) if len(res) < batch { @@ -197,7 +197,7 @@ func NewTask[A interface{ TableName() string }, B any, C any](gormDB *gorm.DB, m func insertMany(coll *mongo.Collection, objs []any) error { if _, err := coll.InsertMany(context.Background(), objs); err != nil { if !mongo.IsDuplicateKeyError(err) { - return err + return errs.Wrap(err) } } for i := range objs { From c79f46f8a34227dca35fc3dd8ea041705b038b43 Mon Sep 17 00:00:00 2001 From: skiffer-git <72860476+skiffer-git@users.noreply.github.com> Date: Wed, 6 Mar 2024 16:29:54 +0800 Subject: [PATCH 087/188] Optimize logs (#2007) * Optimize script logs * Optimize script logs * Optimize script logs * Optimize script logs * Optimize script logs * Optimize script logs * Optimize script logs * Optimize script logs * Optimize script logs * Optimize script logs * Optimize script logs * fix: wrap the error of group user and thrid (#2005) * fix: wrap the error of group user and thrid * fix: del the chinese comment * fix: fix the make_lint error * fix: fix the ApiTest error * Optimize script logs * Optimize script logs * Optimize script logs * Optimize script logs * Optimize script logs * Optimize script logs * Optimize script logs * Optimize script logs * Optimize script logs * Optimize script logs * Optimize script logs --------- Co-authored-by: Brabem <69128477+luhaoling@users.noreply.github.com> --- scripts/install/openim-api.sh | 4 +- scripts/install/openim-crontask.sh | 5 +- scripts/install/openim-msggateway.sh | 4 +- scripts/install/openim-msgtransfer.sh | 5 +- scripts/install/openim-push.sh | 4 +- scripts/install/openim-rpc.sh | 3 +- scripts/lib/logging.sh | 7 +- scripts/lib/util.sh | 95 ++++++++++++++------------- scripts/start-all.sh | 8 +-- 9 files changed, 73 insertions(+), 62 deletions(-) diff --git a/scripts/install/openim-api.sh b/scripts/install/openim-api.sh index 8a7b8d1f11..cd3d5eb080 100755 --- a/scripts/install/openim-api.sh +++ b/scripts/install/openim-api.sh @@ -88,8 +88,8 @@ function openim::api::start_service() { echo "Starting service with command: $cmd" - nohup $cmd >> "${LOG_FILE}" 2> >(tee -a "${STDERR_LOG_FILE}" "$TMP_LOG_FILE" >&2) & - + #nohup $cmd >> "${LOG_FILE}" 2> >(tee -a "${STDERR_LOG_FILE}" "$TMP_LOG_FILE" >&2) & + nohup ${cmd} >> "${LOG_FILE}" 2> >(tee -a "$TMP_LOG_FILE" | while read line; do echo -e "\e[31m${line}\e[0m"; done >&2) >/dev/null & if [ $? -ne 0 ]; then openim::log::error_exit "Failed to start ${binary_name} on port ${service_port}." return 1 diff --git a/scripts/install/openim-crontask.sh b/scripts/install/openim-crontask.sh index ae78a44dd4..1917010823 100755 --- a/scripts/install/openim-crontask.sh +++ b/scripts/install/openim-crontask.sh @@ -51,8 +51,9 @@ function openim::crontask::start() { openim::log::status "Start OpenIM Cron, path: ${OPENIM_CRONTASK_BINARY}" openim::log::status "start cron_task process, path: ${OPENIM_CRONTASK_BINARY}" - - nohup ${OPENIM_CRONTASK_BINARY} -c ${OPENIM_PUSH_CONFIG} >> ${LOG_FILE} 2> >(tee -a "${STDERR_LOG_FILE}" "$TMP_LOG_FILE" >&2) & + #nohup ${OPENIM_CRONTASK_BINARY} -c ${OPENIM_PUSH_CONFIG} >> ${LOG_FILE} 2> >(tee -a "${STDERR_LOG_FILE}" "$TMP_LOG_FILE" >&2) & + cmd="${OPENIM_CRONTASK_BINARY} -c ${OPENIM_PUSH_CONFIG}" + nohup ${cmd} >> "${LOG_FILE}" 2> >(tee -a "$TMP_LOG_FILE" | while read line; do echo -e "\e[31m${line}\e[0m"; done >&2) >/dev/null & return 0 } diff --git a/scripts/install/openim-msggateway.sh b/scripts/install/openim-msggateway.sh index 3eb9bb3495..25051aa6e0 100755 --- a/scripts/install/openim-msggateway.sh +++ b/scripts/install/openim-msggateway.sh @@ -61,8 +61,10 @@ function openim::msggateway::start() { if [[ -n "${MSG_GATEWAY_PROM_PORTS_ARRAY[$i]}" ]]; then PROMETHEUS_PORT_OPTION="--prometheus_port ${MSG_GATEWAY_PROM_PORTS_ARRAY[$i]}" fi + cmd="${OPENIM_MSGGATEWAY_BINARY} --port ${OPENIM_MSGGATEWAY_PORTS_ARRAY[$i]} --ws_port ${OPENIM_WS_PORTS_ARRAY[$i]} $PROMETHEUS_PORT_OPTION -c ${OPENIM_MSGGATEWAY_CONFIG}" + nohup ${cmd} >> "${LOG_FILE}" 2> >(tee -a "$TMP_LOG_FILE" | while read line; do echo -e "\e[31m${line}\e[0m"; done >&2) >/dev/null & + # nohup ${OPENIM_MSGGATEWAY_BINARY} --port ${OPENIM_MSGGATEWAY_PORTS_ARRAY[$i]} --ws_port ${OPENIM_WS_PORTS_ARRAY[$i]} $PROMETHEUS_PORT_OPTION -c ${OPENIM_MSGGATEWAY_CONFIG} >> ${LOG_FILE} 2> >(tee -a "${STDERR_LOG_FILE}" "$TMP_LOG_FILE" >&2) & - nohup ${OPENIM_MSGGATEWAY_BINARY} --port ${OPENIM_MSGGATEWAY_PORTS_ARRAY[$i]} --ws_port ${OPENIM_WS_PORTS_ARRAY[$i]} $PROMETHEUS_PORT_OPTION -c ${OPENIM_MSGGATEWAY_CONFIG} >> ${LOG_FILE} 2> >(tee -a "${STDERR_LOG_FILE}" "$TMP_LOG_FILE" >&2) & done return 0 } diff --git a/scripts/install/openim-msgtransfer.sh b/scripts/install/openim-msgtransfer.sh index 9fdf07fe20..23ce79c36f 100755 --- a/scripts/install/openim-msgtransfer.sh +++ b/scripts/install/openim-msgtransfer.sh @@ -57,10 +57,11 @@ function openim::msgtransfer::start() { openim::util::stop_services_on_ports ${PROMETHEUS_MSG_TRANSFER_PORT} PROMETHEUS_PORT_OPTION="--prometheus_port ${PROMETHEUS_MSG_TRANSFER_PORT}" fi - nohup ${OPENIM_MSGTRANSFER_BINARY} ${PROMETHEUS_PORT_OPTION} -c ${OPENIM_MSGTRANSFER_CONFIG} -n ${i} >> ${LOG_FILE} 2> >(tee -a "${STDERR_LOG_FILE}" "$TMP_LOG_FILE" >&2) & + cmd="${OPENIM_MSGTRANSFER_BINARY} ${PROMETHEUS_PORT_OPTION} -c ${OPENIM_MSGTRANSFER_CONFIG} -n ${i}" + nohup ${cmd} >> "${LOG_FILE}" 2> >(tee -a "$TMP_LOG_FILE" | while read line; do echo -e "\e[31m${line}\e[0m"; done >&2) >/dev/null & + #nohup ${OPENIM_MSGTRANSFER_BINARY} ${PROMETHEUS_PORT_OPTION} -c ${OPENIM_MSGTRANSFER_CONFIG} -n ${i} >> ${LOG_FILE} 2> >(tee -a "${STDERR_LOG_FILE}" "$TMP_LOG_FILE" >&2) & done return 0 - } function openim::msgtransfer::check() { diff --git a/scripts/install/openim-push.sh b/scripts/install/openim-push.sh index 8684f185c1..8dea4b1f15 100755 --- a/scripts/install/openim-push.sh +++ b/scripts/install/openim-push.sh @@ -71,7 +71,9 @@ function openim::push::start() { for (( i=0; i<${#OPENIM_PUSH_PORTS_ARRAY[@]}; i++ )); do openim::log::info "start push process, port: ${OPENIM_PUSH_PORTS_ARRAY[$i]}, prometheus port: ${PUSH_PROM_PORTS_ARRAY[$i]}" - nohup ${OPENIM_PUSH_BINARY} --port ${OPENIM_PUSH_PORTS_ARRAY[$i]} -c ${OPENIM_PUSH_CONFIG} --prometheus_port ${PUSH_PROM_PORTS_ARRAY[$i]} >> ${LOG_FILE} 2> >(tee -a "${STDERR_LOG_FILE}" "$TMP_LOG_FILE" >&2) & + cmd="${OPENIM_PUSH_BINARY} --port ${OPENIM_PUSH_PORTS_ARRAY[$i]} -c ${OPENIM_PUSH_CONFIG} --prometheus_port ${PUSH_PROM_PORTS_ARRAY[$i]}" + nohup ${cmd} >> "${LOG_FILE}" 2> >(tee -a "$TMP_LOG_FILE" | while read line; do echo -e "\e[31m${line}\e[0m"; done >&2) >/dev/null & + #nohup ${OPENIM_PUSH_BINARY} --port ${OPENIM_PUSH_PORTS_ARRAY[$i]} -c ${OPENIM_PUSH_CONFIG} --prometheus_port ${PUSH_PROM_PORTS_ARRAY[$i]} >> ${LOG_FILE} 2> >(tee -a "${STDERR_LOG_FILE}" "$TMP_LOG_FILE" >&2) & done return 0 diff --git a/scripts/install/openim-rpc.sh b/scripts/install/openim-rpc.sh index e7ee430d24..c3ac12449d 100755 --- a/scripts/install/openim-rpc.sh +++ b/scripts/install/openim-rpc.sh @@ -165,7 +165,8 @@ function openim::rpc::start_service() { printf "Specifying prometheus port: %s\n" "${prometheus_port}" cmd="${cmd} --prometheus_port ${prometheus_port}" fi - nohup ${cmd} >> "${LOG_FILE}" 2> >(tee -a "${STDERR_LOG_FILE}" "$TMP_LOG_FILE" >&2) & + #nohup ${cmd} >> "${LOG_FILE}" 2> >(tee -a "${STDERR_LOG_FILE}" "$TMP_LOG_FILE" >&2) & + nohup ${cmd} >> "${LOG_FILE}" 2> >(tee -a "$TMP_LOG_FILE" | while read line; do echo -e "\e[31m${line}\e[0m"; done >&2) >/dev/null & return 0 } diff --git a/scripts/lib/logging.sh b/scripts/lib/logging.sh index bef3b5961a..8d017b0777 100755 --- a/scripts/lib/logging.sh +++ b/scripts/lib/logging.sh @@ -237,4 +237,9 @@ function openim::log::test_log() { openim::log::error_exit "openim::log::error_exit" } -# openim::log::test_log \ No newline at end of file +# openim::log::test_log + +function openim::log::print_blue() { + echo -e "\033[0;36m$1\033[0m" +} + diff --git a/scripts/lib/util.sh b/scripts/lib/util.sh index 4322255bba..d84562c1d4 100755 --- a/scripts/lib/util.sh +++ b/scripts/lib/util.sh @@ -401,31 +401,32 @@ openim::util::check_process_names() { # Arrays to collect details of processes local not_started=() local started=() - - # Iterate over each given process name + + # Iterate over each given process name for process_name in "$@"; do - # Use `pgrep` to find process IDs related to the given process name - local pids=($(pgrep -f $process_name)) - - # Check if any process IDs were found - if [[ ${#pids[@]} -eq 0 ]]; then - not_started+=($process_name) - else - # If there are PIDs, loop through each one - for pid in "${pids[@]}"; do - local command=$(ps -p $pid -o cmd=) - local start_time=$(ps -p $pid -o lstart=) - local port=$(get_port $pid) - - # Check if port information was found for the PID - if [[ -z $port ]]; then - port="N/A" - fi - - started+=("Process $process_name - Command: $command, PID: $pid, Port: $port, Start time: $start_time") - done - fi - done + # Use `pgrep` to find process IDs related to the given process name + local pids=($(pgrep -f $process_name)) + + # Check if any process IDs were found + if [[ ${#pids[@]} -eq 0 ]]; then + not_started+=($process_name) + else + # If there are PIDs, loop through each one + for pid in "${pids[@]}"; do + local command=$(ps -p $pid -o cmd=) + local start_time=$(ps -p $pid -o lstart=) + local port=$(get_port $pid) + + # Check if port information was found for the PID + if [[ -z $port ]]; then + port="N/A" + fi + + started+=("Process $process_name - Command: $command, PID: $pid, Port: $port, Start time: $start_time") + done + fi + done + # Print information if [[ ${#not_started[@]} -ne 0 ]]; then @@ -1679,29 +1680,29 @@ openim::util::check_process_names() { echo "Checking processes: $*" # Iterate over each given process name - for process_name in "$@"; do - # Use `pgrep` to find process IDs related to the given process name - local pids=($(pgrep -f $process_name)) - - # Check if any process IDs were found - if [[ ${#pids[@]} -eq 0 ]]; then - not_started+=($process_name) - else - # If there are PIDs, loop through each one - for pid in "${pids[@]}"; do - local command=$(ps -p $pid -o cmd=) - local start_time=$(ps -p $pid -o lstart=) - local port=$(get_port $pid) - - # Check if port information was found for the PID - if [[ -z $port ]]; then - port="N/A" - fi - - started+=("Process $process_name - Command: $command, PID: $pid, Port: $port, Start time: $start_time") - done - fi - done + for process_name in "$@"; do + # Use `pgrep` to find process IDs related to the given process name + local pids=($(pgrep -f $process_name)) + + # Check if any process IDs were found + if [[ ${#pids[@]} -eq 0 ]]; then + not_started+=($process_name) + else + # If there are PIDs, loop through each one + for pid in "${pids[@]}"; do + local command=$(ps -p $pid -o cmd=) + local start_time=$(ps -p $pid -o lstart=) + local port=$(get_port $pid) + + # Check if port information was found for the PID + if [[ -z $port ]]; then + port="N/A" + fi + + started+=("Process $process_name - Command: $command, PID: $pid, Port: $port, Start time: $start_time") + done + fi + done # Print information if [[ ${#not_started[@]} -ne 0 ]]; then diff --git a/scripts/start-all.sh b/scripts/start-all.sh index 9a98bfca3a..c27f2010c6 100755 --- a/scripts/start-all.sh +++ b/scripts/start-all.sh @@ -37,7 +37,7 @@ function execute_start_scripts() { # Check if the script file exists and is executable. if [[ -x "$script_path" ]]; then - openim::log::info "Starting script: ${script_path##*/}" # Log the script name. + openim::log::print_blue "Starting script: ${script_path##*/}" # Log the script name. # Execute the script with the constructed argument. result=$("$script_path" "$arg") @@ -69,7 +69,7 @@ fi "${OPENIM_ROOT}"/scripts/init-config.sh --skip -echo "You need to start the following scripts in order: ${OPENIM_SERVER_SCRIPTARIES[@]}" +#openim::log::print_blue "Execute the following script in sequence: ${OPENIM_SERVER_SCRIPTARIES[@]}" # TODO Prelaunch tools, simple for now, can abstract functions later @@ -81,7 +81,7 @@ ${TOOLS_START_SCRIPTS_PATH} openim::tools::pre-start result=$("${OPENIM_ROOT}"/scripts/stop-all.sh) if [[ $? -ne 0 ]]; then - echo "+++ cat openim log file >>> ${LOG_FILE}" + openim::log::error "View the error logs from this startup. ${LOG_FILE} \n" openim::log::error "Some programs have not exited; the start process is aborted .\n $result" exit 1 fi @@ -95,7 +95,6 @@ sleep 2 result=$(. $(dirname ${BASH_SOURCE})/install/openim-msgtransfer.sh openim::msgtransfer::check) if [[ $? -ne 0 ]]; then - echo "+++ cat openim log file >>> ${LOG_FILE}" openim::log::error "The program may fail to start.\n $result" exit 1 fi @@ -103,7 +102,6 @@ fi result=$(openim::util::check_process_names ${OPENIM_ALL_SERVICE_LIBRARIES_NO_TRANSFER[@]}) if [[ $? -ne 0 ]]; then - echo "+++ cat openim log file >>> ${LOG_FILE}" openim::log::error "The program may fail to start.\n $result" exit 1 fi From 52ddc4f05bce1a9ef0eca2c61e8cb18be9cd4fd3 Mon Sep 17 00:00:00 2001 From: OpenIM-Gordon <46924906+FGadvancer@users.noreply.github.com> Date: Wed, 6 Mar 2024 19:04:31 +0800 Subject: [PATCH 088/188] fix: remove unnecessary error handling to avoid sending failed notifications. (#2009) --- pkg/rpcclient/notification/group.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/pkg/rpcclient/notification/group.go b/pkg/rpcclient/notification/group.go index 5fd794be29..c72aa839b2 100644 --- a/pkg/rpcclient/notification/group.go +++ b/pkg/rpcclient/notification/group.go @@ -250,9 +250,6 @@ func (g *GroupNotificationSender) fillOpUser(ctx context.Context, opUser **sdkws if opUser == nil { return errs.ErrInternalServer.Wrap("**sdkws.GroupMemberFullInfo is nil") } - if *opUser != nil { - return errs.ErrArgs.Wrap("*opUser is not nil") - } userID := mcontext.GetOpUserID(ctx) if groupID != "" { if authverify.IsManagerUserID(userID, g.config) { From 13d0883507be9fa915b80c9ca2ff5d7cda4511b4 Mon Sep 17 00:00:00 2001 From: OpenIM-Gordon <46924906+FGadvancer@users.noreply.github.com> Date: Wed, 6 Mar 2024 20:53:36 +0800 Subject: [PATCH 089/188] fix: remove unnecessary error handling to avoid sending nil resp. (#2010) * fix: remove unnecessary error handling to avoid sending failed notifications. * fix: remove unnecessary error handling to avoid sending nil resp. --- internal/rpc/group/group.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/rpc/group/group.go b/internal/rpc/group/group.go index d44c79b45d..4be8fab0cb 100644 --- a/internal/rpc/group/group.go +++ b/internal/rpc/group/group.go @@ -757,7 +757,7 @@ func (s *groupServer) GroupApplicationResponse(ctx context.Context, req *pbgroup return nil, errs.ErrGroupRequestHandled.Wrap("group request already processed") } var inGroup bool - if _, takeErr := s.db.TakeGroupMember(ctx, req.GroupID, req.FromUserID); takeErr == nil { + if _, err := s.db.TakeGroupMember(ctx, req.GroupID, req.FromUserID); err == nil { inGroup = true // Already in group } else if !s.IsNotFound(err) { return nil, err From 38f685bd01b793d49d5d4e1cdc9b95500662dedf Mon Sep 17 00:00:00 2001 From: skiffer-git <72860476+skiffer-git@users.noreply.github.com> Date: Thu, 7 Mar 2024 12:24:45 +0800 Subject: [PATCH 090/188] Optimizing Docker Log Output Detection (#2014) * Optimize script logs * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection --- scripts/check-all.sh | 5 +++++ scripts/docker-start-all.sh | 10 +--------- scripts/lib/logging.sh | 6 ++++++ scripts/start-all.sh | 8 ++++++++ 4 files changed, 20 insertions(+), 9 deletions(-) diff --git a/scripts/check-all.sh b/scripts/check-all.sh index a9b07d65b3..1d05f838b4 100755 --- a/scripts/check-all.sh +++ b/scripts/check-all.sh @@ -26,6 +26,11 @@ OPENIM_ROOT=$(dirname "${BASH_SOURCE[0]}")/.. source "${OPENIM_ROOT}/scripts/install/common.sh" +if grep -q docker /proc/1/cgroup; then + exec > ${DOCKER_LOG_FILE} 2>&1 +fi + + OPENIM_VERBOSE=4 openim::log::info "\n# Begin to check all openim service" diff --git a/scripts/docker-start-all.sh b/scripts/docker-start-all.sh index c47069e3bf..4c9b7308f8 100755 --- a/scripts/docker-start-all.sh +++ b/scripts/docker-start-all.sh @@ -23,15 +23,7 @@ OPENIM_ROOT=$(dirname "${BASH_SOURCE[0]}")/.. source "${OPENIM_ROOT}/scripts/install/common.sh" - openim::log::info "\n# Use Docker to start all openim service" - trap 'openim::util::onCtrlC' INT - "${OPENIM_ROOT}"/scripts/start-all.sh - -sleep 5 - -"${OPENIM_ROOT}"/scripts/check-all.sh - -tail -f ${LOG_FILE} +tail -f ${DOCKER_LOG_FILE} diff --git a/scripts/lib/logging.sh b/scripts/lib/logging.sh index 8d017b0777..0d51135418 100755 --- a/scripts/lib/logging.sh +++ b/scripts/lib/logging.sh @@ -36,6 +36,12 @@ if [[ ! -d "${OPENIM_OUTPUT}/logs" ]]; then touch "$TMP_LOG_FILE" fi +if [[ ! -f "$DOCKER_LOG_FILE" ]]; then + touch "$DOCKER_LOG_FILE" +fi + + + # Define the logging function function echo_log() { if $ENABLE_LOGGING; then diff --git a/scripts/start-all.sh b/scripts/start-all.sh index c27f2010c6..fcf9496cc4 100755 --- a/scripts/start-all.sh +++ b/scripts/start-all.sh @@ -17,12 +17,17 @@ #FIXME The full names of the shell scripts that need to be started are placed in the `need_to_start_server_shell` array. +#!/bin/bash + + + OPENIM_ROOT=$(dirname "${BASH_SOURCE[0]}")/.. source "${OPENIM_ROOT}/scripts/install/common.sh" + # Function to execute the scripts. function execute_start_scripts() { for script_path in "${OPENIM_SERVER_SCRIPT_START_LIST[@]}"; do @@ -57,6 +62,9 @@ function execute_start_scripts() { +if grep -q docker /proc/1/cgroup; then + exec > ${DOCKER_LOG_FILE} 2>&1 +fi From 39647b33da1224ce12c894c3ed2d1249a0498862 Mon Sep 17 00:00:00 2001 From: skiffer-git <72860476+skiffer-git@users.noreply.github.com> Date: Thu, 7 Mar 2024 15:40:25 +0800 Subject: [PATCH 091/188] Optimizing Docker Log Output (#2018) * Optimize script logs * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection --- scripts/check-all.sh | 6 +++--- scripts/lib/logging.sh | 2 +- scripts/lib/util.sh | 9 +++++++++ scripts/start-all.sh | 2 +- 4 files changed, 14 insertions(+), 5 deletions(-) diff --git a/scripts/check-all.sh b/scripts/check-all.sh index 1d05f838b4..8e89af79d3 100755 --- a/scripts/check-all.sh +++ b/scripts/check-all.sh @@ -26,8 +26,8 @@ OPENIM_ROOT=$(dirname "${BASH_SOURCE[0]}")/.. source "${OPENIM_ROOT}/scripts/install/common.sh" -if grep -q docker /proc/1/cgroup; then - exec > ${DOCKER_LOG_FILE} 2>&1 +if openim::util::is_running_in_container; then + exec >> ${DOCKER_LOG_FILE} 2>&1 fi @@ -75,7 +75,7 @@ if grep -qE 'docker|kubepods' /proc/1/cgroup || [ -f /.dockerenv ]; then openim::color::echo ${COLOR_CYAN} "Environment in the interior of the container" else openim::color::echo ${COLOR_CYAN} "The environment is outside the container" - openim::util::check_ports ${OPENIM_DEPENDENCY_PORT_LISTARIES[@]} || return 0 + openim::util::check_ports ${OPENIM_DEPENDENCY_PORT_LISTARIES[@]} fi if [[ $? -ne 0 ]]; then diff --git a/scripts/lib/logging.sh b/scripts/lib/logging.sh index 0d51135418..fec71b19d9 100755 --- a/scripts/lib/logging.sh +++ b/scripts/lib/logging.sh @@ -28,7 +28,7 @@ fi LOG_FILE="${OPENIM_OUTPUT}/logs/openim-$(date '+%Y%m%d').log" STDERR_LOG_FILE="${OPENIM_OUTPUT}/logs/openim-error-$(date '+%Y%m%d').log" TMP_LOG_FILE="${OPENIM_OUTPUT}/logs/openim-tmp-$(date '+%Y%m%d').log" - +DOCKER_LOG_FILE="${OPENIM_OUTPUT}/logs/openim-docker.log" if [[ ! -d "${OPENIM_OUTPUT}/logs" ]]; then mkdir -p "${OPENIM_OUTPUT}/logs" touch "$LOG_FILE" diff --git a/scripts/lib/util.sh b/scripts/lib/util.sh index d84562c1d4..e9908ae662 100755 --- a/scripts/lib/util.sh +++ b/scripts/lib/util.sh @@ -2866,6 +2866,15 @@ function openim::util::gen_os_arch() { +function openim::util::is_running_in_container() { + if grep -qE 'docker|kubepods' /proc/1/cgroup || [ -f /.dockerenv ]; then + return 0 + else + return 1 + fi +} + + function openim::util::check_process_names_for_stop() { local all_stopped=true for service in "${OPENIM_ALL_SERVICE_LIBRARIES[@]}"; do diff --git a/scripts/start-all.sh b/scripts/start-all.sh index fcf9496cc4..419c16628f 100755 --- a/scripts/start-all.sh +++ b/scripts/start-all.sh @@ -62,7 +62,7 @@ function execute_start_scripts() { -if grep -q docker /proc/1/cgroup; then +if openim::util::is_running_in_container; then exec > ${DOCKER_LOG_FILE} 2>&1 fi From a84162815a1c56edcda80d13ada7bed37e96a34e Mon Sep 17 00:00:00 2001 From: OpenIM Bot <124379614+kubbot@users.noreply.github.com> Date: Thu, 7 Mar 2024 19:38:20 +0800 Subject: [PATCH 092/188] cicd: bump League Patch (#2012) --- internal/rpc/third/third.go | 2 +- pkg/common/db/mgo/object.go | 2 +- pkg/rpcclient/msg.go | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/internal/rpc/third/third.go b/internal/rpc/third/third.go index 5f6fc6c343..928fb0f42c 100644 --- a/internal/rpc/third/third.go +++ b/internal/rpc/third/third.go @@ -17,12 +17,12 @@ package third import ( "context" "fmt" - "github.com/OpenIMSDK/tools/errs" "net/url" "time" "github.com/OpenIMSDK/protocol/third" "github.com/OpenIMSDK/tools/discoveryregistry" + "github.com/OpenIMSDK/tools/errs" "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" diff --git a/pkg/common/db/mgo/object.go b/pkg/common/db/mgo/object.go index a527fa60d5..e9d639f198 100644 --- a/pkg/common/db/mgo/object.go +++ b/pkg/common/db/mgo/object.go @@ -16,8 +16,8 @@ package mgo import ( "context" - "github.com/OpenIMSDK/tools/errs" + "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/mgoutil" "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" "go.mongodb.org/mongo-driver/bson" diff --git a/pkg/rpcclient/msg.go b/pkg/rpcclient/msg.go index 4daf897a16..54a4671a3d 100644 --- a/pkg/rpcclient/msg.go +++ b/pkg/rpcclient/msg.go @@ -18,16 +18,16 @@ import ( "context" "encoding/json" "fmt" - "github.com/OpenIMSDK/tools/errs" - util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" "github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/protocol/msg" "github.com/OpenIMSDK/protocol/sdkws" "github.com/OpenIMSDK/tools/discoveryregistry" + "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/utils" "github.com/openimsdk/open-im-server/v3/pkg/common/config" + util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" "google.golang.org/grpc" "google.golang.org/protobuf/proto" ) From a1f0eb2e3eb49551ddc6e1a757f6e8c6d74a45ee Mon Sep 17 00:00:00 2001 From: skiffer-git <72860476+skiffer-git@users.noreply.github.com> Date: Fri, 8 Mar 2024 08:56:22 +0800 Subject: [PATCH 093/188] Exit with code 1 when the check script fails (#2022) * Optimize script logs * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Exit with code 1 when the check script fails --- scripts/check-all.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/check-all.sh b/scripts/check-all.sh index 8e89af79d3..d410233845 100755 --- a/scripts/check-all.sh +++ b/scripts/check-all.sh @@ -104,6 +104,7 @@ if [[ $? -ne 0 ]]; then echo "+++ cat openim log file >>> ${LOG_FILE}" openim::log::error "check process failed.\n " echo "$result" + exit 1 else openim::log::success "All openim services are running normally! " fi From a93615d3e0645cf45931ab299d6b51691e6d1f30 Mon Sep 17 00:00:00 2001 From: OpenIM Bot <124379614+kubbot@users.noreply.github.com> Date: Fri, 8 Mar 2024 10:28:48 +0800 Subject: [PATCH 094/188] cicd: bump League Patch (#2025) --- CHANGELOG/CHANGELOG-3.6.md | 20 ++++++++++++++++++++ pkg/common/config/version | 2 +- 2 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 CHANGELOG/CHANGELOG-3.6.md diff --git a/CHANGELOG/CHANGELOG-3.6.md b/CHANGELOG/CHANGELOG-3.6.md new file mode 100644 index 0000000000..214d583401 --- /dev/null +++ b/CHANGELOG/CHANGELOG-3.6.md @@ -0,0 +1,20 @@ +# Version logging for OpenIM + + + + + + +## [Unreleased] + + + +## v3.6.0 - 2024-03-07 +### Reverts +- update etcd to v3.5.2 ([#206](https://github.com/openimsdk/open-im-server/issues/206)) + +### Pull Requests +- Merge branch 'tuoyun' + + +[Unreleased]: https://github.com/openimsdk/open-im-server/compare/v3.6.0...HEAD diff --git a/pkg/common/config/version b/pkg/common/config/version index d5c0c99142..40c341bdcd 100644 --- a/pkg/common/config/version +++ b/pkg/common/config/version @@ -1 +1 @@ -3.5.1 +3.6.0 From 42482e7eb45cf01a54fc5b4051503c8f31d33509 Mon Sep 17 00:00:00 2001 From: skiffer-git <72860476+skiffer-git@users.noreply.github.com> Date: Fri, 8 Mar 2024 12:19:04 +0800 Subject: [PATCH 095/188] Execute after the component check succeeds && minio.Enable is not configured to use MinIO (#2026) * Exit with code 1 when the check script fails * Exit with code 1 when the check script fails * Exit with code 1 when the check script fails * Exit with code 1 when the check script fails * Handle the return value of pre-start * Handle the return value of pre-start * Handle the return value of pre-start * minio.Enable is not configured to use MinIO, therefore the image server is not checked * minio.Enable is not configured to use MinIO, therefore the image server is not checked * minio.Enable is not configured to use MinIO, therefore the image server is not checked * minio.Enable is not configured to use MinIO, therefore the image server is not checked --- scripts/install/openim-tools.sh | 25 +++++++++++++++++++------ scripts/start-all.sh | 12 ++++++++++-- tools/component/component.go | 24 +++++++++++++++++++++--- 3 files changed, 50 insertions(+), 11 deletions(-) diff --git a/scripts/install/openim-tools.sh b/scripts/install/openim-tools.sh index 4eb722c6e3..0032642210 100755 --- a/scripts/install/openim-tools.sh +++ b/scripts/install/openim-tools.sh @@ -101,7 +101,16 @@ function openim::tools::start_service() { cmd="${cmd} --prometheus_port ${prometheus_port}" fi openim::log::status "Starting binary ${binary_name}..." - ${cmd} | tee -a "${LOG_FILE}" + ${cmd} >>"${LOG_FILE}" 2> >(tee -a "${LOG_FILE}" >&2) + local status=$? + + if [ $status -eq 0 ]; then + openim::log::info "Service ${binary_name} started successfully." + return 0 + else + openim::log::error "Failed to start service ${binary_name}." + return 1 + fi } function openim::tools::start() { @@ -115,11 +124,15 @@ function openim::tools::start() { function openim::tools::pre-start() { - openim::log::info "Preparing to start OpenIM Tools..." - for tool in "${OPENIM_TOOLS_PRE_START_NAME_LISTARIES[@]}"; do - openim::log::info "Starting tool ${tool}..." - openim::tools::start_service ${tool} ${OPNEIM_CONFIG} - done + openim::log::info "Preparing to start OpenIM Tools..." + for tool in "${OPENIM_TOOLS_PRE_START_NAME_LISTARIES[@]}"; do + openim::log::info "Starting tool ${tool}..." + if ! openim::tools::start_service ${tool} ${OPNEIM_CONFIG}; then + openim::log::error "Failed to start ${tool}, aborting..." + return 1 + fi + done + openim::log::info "All tools started successfully." } function openim::tools::post-start() { diff --git a/scripts/start-all.sh b/scripts/start-all.sh index 419c16628f..aac4b18372 100755 --- a/scripts/start-all.sh +++ b/scripts/start-all.sh @@ -83,10 +83,18 @@ fi # TODO Prelaunch tools, simple for now, can abstract functions later TOOLS_START_SCRIPTS_PATH=${START_SCRIPTS_PATH}/openim-tools.sh -openim::log::status "\n## Pre Starting OpenIM services" -${TOOLS_START_SCRIPTS_PATH} openim::tools::pre-start +openim::log::print_blue "\n## Pre Starting OpenIM services" + +if ! ${TOOLS_START_SCRIPTS_PATH} openim::tools::pre-start; then + openim::log::error "Pre Starting OpenIM services failed, aborting..." + exit 1 +fi + + +openim::log::print_blue "Pre Starting OpenIM services processed successfully" + result=$("${OPENIM_ROOT}"/scripts/stop-all.sh) if [[ $? -ne 0 ]]; then openim::log::error "View the error logs from this startup. ${LOG_FILE} \n" diff --git a/tools/component/component.go b/tools/component/component.go index 34d3dff6b3..e3b5b1956f 100644 --- a/tools/component/component.go +++ b/tools/component/component.go @@ -102,7 +102,14 @@ func main() { if !check.flag { err = check.function(check.config) if err != nil { - allSuccess = false + if errors.Is(err, errMinioNotEnabled) { + fmt.Println(err.Error()) + checks[index].flag = true + } + if errors.Is(err, errSignEndPoint) { + fmt.Fprintf(os.Stderr, err.Error()) + checks[index].flag = true + } component.ErrorPrint(fmt.Sprintf("Starting %s failed:%v.", check.name, errs.Unwrap(err).Error())) if !strings.Contains(errs.Unwrap(err).Error(), "connection refused") && !strings.Contains(errs.Unwrap(err).Error(), "timeout waiting") { @@ -125,6 +132,11 @@ func main() { os.Exit(-1) } +var errMinioNotEnabled = errors.New("minio.Enable is not configured to use MinIO") + +var errSignEndPoint = errors.New("minio.signEndPoint contains 127.0.0.1, causing issues with image sending") +var errApiURL = errors.New("object.apiURL contains 127.0.0.1, causing issues with image sending") + // checkMongo checks the MongoDB connection without retries func checkMongo(config *config.GlobalConfig) error { mongoStu := &component.Mongo{ @@ -153,10 +165,16 @@ func checkRedis(config *config.GlobalConfig) error { // checkMinio checks the MinIO connection func checkMinio(config *config.GlobalConfig) error { - // Check if MinIO is enabled + if strings.Contains(config.Object.ApiURL, "127.0.0.1") { + return errs.Wrap(errApiURL, "config.Object.ApiURL: "+config.Object.ApiURL) + } if config.Object.Enable != "minio" { - return errs.Wrap(errors.New("minio.Enable is empty")) + return errs.Wrap(errMinioNotEnabled, "config.Object.Enable: "+config.Object.Enable) + } + if strings.Contains(config.Object.Minio.Endpoint, "127.0.0.1") { + return errs.Wrap(errSignEndPoint, "config.Object.Minio.Endpoint: "+config.Object.Minio.Endpoint) } + minio := &component.Minio{ ApiURL: config.Object.ApiURL, Endpoint: config.Object.Minio.Endpoint, From 16799648dc6d278b1706d4a0c78640097a7d862f Mon Sep 17 00:00:00 2001 From: skiffer-git <72860476+skiffer-git@users.noreply.github.com> Date: Fri, 8 Mar 2024 14:06:27 +0800 Subject: [PATCH 096/188] del log (#2030) --- scripts/install/openim-tools.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/install/openim-tools.sh b/scripts/install/openim-tools.sh index 0032642210..04cd70adfc 100755 --- a/scripts/install/openim-tools.sh +++ b/scripts/install/openim-tools.sh @@ -101,7 +101,7 @@ function openim::tools::start_service() { cmd="${cmd} --prometheus_port ${prometheus_port}" fi openim::log::status "Starting binary ${binary_name}..." - ${cmd} >>"${LOG_FILE}" 2> >(tee -a "${LOG_FILE}" >&2) + ${cmd} local status=$? if [ $status -eq 0 ]; then From 291443dd6b6edcf253b48f97f5ec87b5b5545b62 Mon Sep 17 00:00:00 2001 From: skiffer-git <72860476+skiffer-git@users.noreply.github.com> Date: Fri, 8 Mar 2024 16:29:26 +0800 Subject: [PATCH 097/188] Error not handled (#2040) * delete * add context deadline exceeded * Error not handled * Error not handled * Error not handled * Error not handled --- scripts/lib/util.sh | 61 ------------------------------------ tools/component/component.go | 31 ++++++++++-------- 2 files changed, 18 insertions(+), 74 deletions(-) diff --git a/scripts/lib/util.sh b/scripts/lib/util.sh index e9908ae662..f66971252b 100755 --- a/scripts/lib/util.sh +++ b/scripts/lib/util.sh @@ -1808,68 +1808,7 @@ openim::util::stop_services_on_ports() { # Usage: # openim::util::stop_services_with_name nginx apache # The function returns a status of 1 if any service couldn't be stopped. -openim::util::stop_services_with_name() { - # An array to collect names of processes that couldn't be stopped. - local not_stopped=() - - # An array to collect information about processes that were stopped. - local stopped=() - - echo "Stopping services with names: $*" - # Iterate over each given service name. - for server_name in "$@"; do - # Use the `pgrep` command to find process IDs related to the given service name. - local pids=$(pgrep -f "$server_name") - - # If no process was found with the name, add it to the not_stopped list - if [[ -z $pids ]]; then - not_stopped+=("$server_name") - continue - fi - local stopped_this_time=false - for pid in $pids; do - # Exclude the PID of the current script - if [[ "$pid" == "$$" ]]; then - continue - fi - - # If there's a Process ID, it means the service with the name is running. - if [[ -n $pid ]]; then - # Try to stop the service by killing its process. - if kill -10 $pid 2>/dev/null; then - stopped_this_time=true - fi - fi - done - - if $stopped_this_time; then - stopped+=("$server_name") - else - not_stopped+=("$server_name") - fi - done - - # Print information about services whose processes couldn't be stopped. - if [[ ${#not_stopped[@]} -ne 0 ]]; then - echo "Services that couldn't be stopped:" - for name in "${not_stopped[@]}"; do - openim::log::status "Failed to stop the $name service." - done - fi - - # Print information about services whose processes were successfully stopped. - if [[ ${#stopped[@]} -ne 0 ]]; then - echo - echo "Stopped services:" - for name in "${stopped[@]}"; do - echo "Successfully stopped the $name service." - done - fi - - openim::log::success "All specified services were stopped." - echo "" -} # sleep 333333& # sleep 444444& # ps -ef | grep "sleep" diff --git a/tools/component/component.go b/tools/component/component.go index e3b5b1956f..c7c135549e 100644 --- a/tools/component/component.go +++ b/tools/component/component.go @@ -102,19 +102,24 @@ func main() { if !check.flag { err = check.function(check.config) if err != nil { - if errors.Is(err, errMinioNotEnabled) { - fmt.Println(err.Error()) - checks[index].flag = true - } - if errors.Is(err, errSignEndPoint) { - fmt.Fprintf(os.Stderr, err.Error()) - checks[index].flag = true + if check.name == "Minio" { + if errors.Is(err, errMinioNotEnabled) { + fmt.Println(err.Error(), " check ", check.name) + checks[index].flag = true + } + if errors.Is(err, errSignEndPoint) { + fmt.Fprintf(os.Stderr, err.Error(), " check ", check.name) + checks[index].flag = true + } } + component.ErrorPrint(fmt.Sprintf("Starting %s failed:%v.", check.name, errs.Unwrap(err).Error())) - if !strings.Contains(errs.Unwrap(err).Error(), "connection refused") && - !strings.Contains(errs.Unwrap(err).Error(), "timeout waiting") { - component.ErrorPrint("Some components started failed!") - os.Exit(-1) + if strings.Contains(errs.Unwrap(err).Error(), "connection refused") || + strings.Contains(errs.Unwrap(err).Error(), "timeout") || + strings.Contains(errs.Unwrap(err).Error(), "context deadline exceeded") { + component.ErrorPrint(fmt.Sprintf("try check connection %s", check.name)) + allSuccess = false + break } } else { checks[index].flag = true @@ -258,13 +263,13 @@ func checkKafka(config *config.GlobalConfig) error { _, err = kafka.NewMConsumerGroup(&kafka.MConsumerGroupConfig{ KafkaVersion: sarama.V2_0_0_0, OffsetsInitial: sarama.OffsetNewest, IsReturnErr: false, - }, []string{config.Kafka.MsgToPush.Topic}, + }, []string{config.Kafka.MsgToMongo.Topic}, config.Kafka.Addr, config.Kafka.ConsumerGroupID.MsgToMongo, tlsConfig) if err != nil { return err } - kafka.NewMConsumerGroup(&kafka.MConsumerGroupConfig{ + _, err = kafka.NewMConsumerGroup(&kafka.MConsumerGroupConfig{ KafkaVersion: sarama.V2_0_0_0, OffsetsInitial: sarama.OffsetNewest, IsReturnErr: false, }, []string{config.Kafka.MsgToPush.Topic}, config.Kafka.Addr, From b9cf40034c6ffea297b798e92abac669e4bc1016 Mon Sep 17 00:00:00 2001 From: chao <48119764+withchao@users.noreply.github.com> Date: Fri, 8 Mar 2024 16:30:47 +0800 Subject: [PATCH 098/188] feat: add local cache for high frequency reads (#2036) * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * fix: mongo * fix: mongo * fix: mongo * openim.yaml * localcache * localcache * localcache * localcache * localcache * localcache * localcache * localcache * localcache * local cache * local cache * local cache * local cache * fix: GroupApplicationAcceptedNotification * fix: GroupApplicationAcceptedNotification * fix: NotificationUserInfoUpdate * feat: cache add single-flight and timing-wheel. * feat: local cache * feat: local cache * feat: local cache * feat: cache add single-flight and timing-wheel. * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * refactor: refactor the code of push and optimization. * cicd: robot automated Change * refactor: rename cache. * merge * fix: refactor project dir avoid import cycle. * update tools * merge * feat: conversation FindRecvMsgNotNotifyUserIDs * feat: conversation FindRecvMsgNotNotifyUserIDs * feat: conversation FindRecvMsgNotNotifyUserIDs * merge * merge the latest main --------- Co-authored-by: Gordon <46924906+FGadvancer@users.noreply.github.com> Co-authored-by: withchao --- deployments/templates/config.yaml | 36 +++++ go.mod | 4 + go.sum | 8 ++ internal/msggateway/callback.go | 6 +- internal/msggateway/hub_server.go | 27 ++-- internal/push/push_rpc_server.go | 6 +- internal/push/push_to_client.go | 8 +- internal/rpc/conversation/conversaion.go | 34 ++--- internal/rpc/friend/friend.go | 19 ++- internal/rpc/msg/as_read.go | 6 +- internal/rpc/msg/revoke.go | 9 +- internal/rpc/msg/send.go | 3 +- internal/rpc/msg/server.go | 21 ++- internal/rpc/msg/statistics.go | 4 +- internal/rpc/msg/sync_msg.go | 8 +- internal/rpc/msg/verify.go | 35 +++-- pkg/common/cachekey/black.go | 15 ++ pkg/common/cachekey/conversation.go | 44 ++++++ pkg/common/cachekey/friend.go | 24 ++++ pkg/common/cachekey/group.go | 45 ++++++ pkg/common/cachekey/user.go | 14 ++ pkg/common/config/config.go | 30 ++++ pkg/common/config/parse_test.go | 12 ++ pkg/common/db/cache/black.go | 15 +- pkg/common/db/cache/config.go | 66 +++++++++ pkg/common/db/cache/conversation.go | 51 ++++--- pkg/common/db/cache/friend.go | 26 ++-- pkg/common/db/cache/group.go | 44 +++--- pkg/common/db/cache/meta_cache.go | 65 +++++---- pkg/common/db/cache/msg.go | 20 +-- pkg/common/db/cache/user.go | 21 +-- pkg/common/db/localcache/conversation.go | 86 ----------- pkg/common/db/localcache/doc.go | 15 -- pkg/common/db/localcache/group.go | 77 ---------- pkg/common/db/localcache/meta_local_cache.go | 15 -- pkg/common/db/mgo/conversation.go | 10 +- pkg/common/db/table/relation/conversation.go | 2 +- pkg/common/redispubsub/redispubliser.go | 16 +++ pkg/common/redispubsub/redissubscriber.go | 34 +++++ pkg/localcache/cache.go | 112 +++++++++++++++ pkg/localcache/cache_test.go | 79 ++++++++++ pkg/localcache/go.mod | 5 + pkg/localcache/link/link.go | 109 ++++++++++++++ pkg/localcache/link/link_test.go | 20 +++ pkg/localcache/lru/lru.go | 20 +++ pkg/localcache/lru/lru_expiration.go | 78 ++++++++++ pkg/localcache/lru/lru_lazy.go | 90 ++++++++++++ pkg/localcache/lru/lru_lazy_test.go | 104 ++++++++++++++ pkg/localcache/lru/lru_slot.go | 37 +++++ pkg/localcache/option.go | 121 ++++++++++++++++ pkg/localcache/tool.go | 9 ++ pkg/rpccache/common.go | 20 +++ pkg/rpccache/conversation.go | 112 +++++++++++++++ pkg/rpccache/friend.go | 66 +++++++++ pkg/rpccache/group.go | 143 +++++++++++++++++++ pkg/rpccache/subscriber.go | 23 +++ pkg/rpccache/user.go | 97 +++++++++++++ pkg/rpcclient/conversation.go | 16 +++ pkg/rpcclient/friend.go | 2 +- pkg/rpcclient/group.go | 4 +- 60 files changed, 1859 insertions(+), 389 deletions(-) create mode 100644 pkg/common/cachekey/black.go create mode 100644 pkg/common/cachekey/conversation.go create mode 100644 pkg/common/cachekey/friend.go create mode 100644 pkg/common/cachekey/group.go create mode 100644 pkg/common/cachekey/user.go create mode 100644 pkg/common/db/cache/config.go delete mode 100644 pkg/common/db/localcache/conversation.go delete mode 100644 pkg/common/db/localcache/doc.go delete mode 100644 pkg/common/db/localcache/group.go delete mode 100644 pkg/common/db/localcache/meta_local_cache.go create mode 100644 pkg/common/redispubsub/redispubliser.go create mode 100644 pkg/common/redispubsub/redissubscriber.go create mode 100644 pkg/localcache/cache.go create mode 100644 pkg/localcache/cache_test.go create mode 100644 pkg/localcache/go.mod create mode 100644 pkg/localcache/link/link.go create mode 100644 pkg/localcache/link/link_test.go create mode 100644 pkg/localcache/lru/lru.go create mode 100644 pkg/localcache/lru/lru_expiration.go create mode 100644 pkg/localcache/lru/lru_lazy.go create mode 100644 pkg/localcache/lru/lru_lazy_test.go create mode 100644 pkg/localcache/lru/lru_slot.go create mode 100644 pkg/localcache/option.go create mode 100644 pkg/localcache/tool.go create mode 100644 pkg/rpccache/common.go create mode 100644 pkg/rpccache/conversation.go create mode 100644 pkg/rpccache/friend.go create mode 100644 pkg/rpccache/group.go create mode 100644 pkg/rpccache/subscriber.go create mode 100644 pkg/rpccache/user.go diff --git a/deployments/templates/config.yaml b/deployments/templates/config.yaml index 0aa6e68d6b..5da6d5d0b1 100644 --- a/deployments/templates/config.yaml +++ b/deployments/templates/config.yaml @@ -535,3 +535,39 @@ prometheus: rtcPrometheusPort: [ ${RTC_PROM_PORT} ] thirdPrometheusPort: [ ${THIRD_PROM_PORT} ] messageTransferPrometheusPort: [ ${MSG_TRANSFER_PROM_PORT} ] # List of ports + +###################### LocalCache configuration information ###################### +# topic: redis subscriber channel +# slotNum: number of slots, multiple slots can prevent too many keys from competing for a lock +# slotSize: number of slots, the number of cached keys per slot, the overall cache quantity is slotNum * slotSize +# successExpire: successful cache time seconds +# failedExpire: failed cache time seconds +# disable local caching and annotate topic, slotNum, and slotSize +localCache: + user: + topic: DELETE_CACHE_USER + slotNum: 100 + slotSize: 2000 + successExpire: 300 + failedExpire: 5 + + group: + topic: DELETE_CACHE_GROUP + slotNum: 100 + slotSize: 2000 + successExpire: 300 + failedExpire: 5 + + friend: + topic: DELETE_CACHE_FRIEND + slotNum: 100 + slotSize: 2000 + successExpire: 300 + failedExpire: 5 + + conversation: + topic: DELETE_CACHE_CONVERSATION + slotNum: 100 + slotSize: 2000 + successExpire: 300 + failedExpire: 5 \ No newline at end of file diff --git a/go.mod b/go.mod index 38443ba5a8..10f08fa533 100644 --- a/go.mod +++ b/go.mod @@ -18,6 +18,7 @@ require ( github.com/minio/minio-go/v7 v7.0.67 github.com/mitchellh/mapstructure v1.5.0 github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 // indirect + github.com/openimsdk/localcache v0.0.1 github.com/pkg/errors v0.9.1 // indirect github.com/prometheus/client_golang v1.18.0 github.com/robfig/cron/v3 v3.0.1 @@ -84,6 +85,7 @@ require ( github.com/hashicorp/errwrap v1.0.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/hashicorp/go-uuid v1.0.3 // indirect + github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect github.com/jcmturner/aescts/v2 v2.0.0 // indirect @@ -162,3 +164,5 @@ require ( golang.org/x/crypto v0.19.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect ) + +replace github.com/openimsdk/localcache => ./pkg/localcache diff --git a/go.sum b/go.sum index aa41279af0..0bba2d65fc 100644 --- a/go.sum +++ b/go.sum @@ -16,6 +16,12 @@ cloud.google.com/go/storage v1.36.0/go.mod h1:M6M/3V/D3KpzMTJyPOR/HU6n2Si5QdaXYE firebase.google.com/go v3.13.0+incompatible h1:3TdYC3DDi6aHn20qoRkxwGqNgdjtblwVAyRLQwGn/+4= firebase.google.com/go v3.13.0+incompatible/go.mod h1:xlah6XbEyW6tbfSklcfe5FHJIwjt8toICdV5Wh9ptHs= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/IBM/sarama v1.41.3 h1:MWBEJ12vHC8coMjdEXFq/6ftO6DUZnQlFYcxtOJFa7c= +github.com/IBM/sarama v1.41.3/go.mod h1:Xxho9HkHd4K/MDUo/T/sOqwtX/17D33++E9Wib6hUdQ= +github.com/OpenIMSDK/protocol v0.0.53 h1:PtePLTqMYRHjWSf8XIL3x5JRC3YoySTMA6tRKfbUjQY= +github.com/OpenIMSDK/protocol v0.0.53/go.mod h1:F25dFrwrIx3lkNoiuf6FkCfxuwf8L4Z8UIsdTHP/r0Y= +github.com/OpenIMSDK/tools v0.0.29 h1:NS4PEwYl9sX3SWsMjDOLVxMo3LcTWREMr+2cjzWjcqc= +github.com/OpenIMSDK/tools v0.0.29/go.mod h1:eg+q4A34Qmu73xkY0mt37FHGMCMfC6CtmOnm0kFEGFI= github.com/IBM/sarama v1.42.2 h1:VoY4hVIZ+WQJ8G9KNY/SQlWguBQXQ9uvFPOnrcu8hEw= github.com/IBM/sarama v1.42.2/go.mod h1:FLPGUGwYqEs62hq2bVG6Io2+5n+pS6s/WOXVKWSLFtE= github.com/OpenIMSDK/protocol v0.0.55 h1:eBjg8DyuhxGmuCUjpoZjg6MJJJXU/xJ3xJwFhrn34yA= @@ -178,6 +184,8 @@ github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9 github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= +github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= diff --git a/internal/msggateway/callback.go b/internal/msggateway/callback.go index ab8c1f51fd..afb83bcc48 100644 --- a/internal/msggateway/callback.go +++ b/internal/msggateway/callback.go @@ -100,7 +100,7 @@ func CallbackUserKickOff(ctx context.Context, globalConfig *config.GlobalConfig, // func callbackUserOnline(operationID, userID string, platformID int, token string, isAppBackground bool, connID // string) cbApi.CommonCallbackResp { // callbackResp := cbApi.CommonCallbackResp{OperationID: operationID} -// if !config.Config.Callback.CallbackUserOnline.Enable { +// if !config.Config.Callback.CallbackUserOnline.WithEnable { // return callbackResp // } // callbackUserOnlineReq := cbApi.CallbackUserOnlineReq{ @@ -129,7 +129,7 @@ func CallbackUserKickOff(ctx context.Context, globalConfig *config.GlobalConfig, //} //func callbackUserOffline(operationID, userID string, platformID int, connID string) cbApi.CommonCallbackResp { // callbackResp := cbApi.CommonCallbackResp{OperationID: operationID} -// if !config.Config.Callback.CallbackUserOffline.Enable { +// if !config.Config.Callback.CallbackUserOffline.WithEnable { // return callbackResp // } // callbackOfflineReq := cbApi.CallbackUserOfflineReq{ @@ -156,7 +156,7 @@ func CallbackUserKickOff(ctx context.Context, globalConfig *config.GlobalConfig, //} //func callbackUserKickOff(operationID string, userID string, platformID int) cbApi.CommonCallbackResp { // callbackResp := cbApi.CommonCallbackResp{OperationID: operationID} -// if !config.Config.Callback.CallbackUserKickOff.Enable { +// if !config.Config.Callback.CallbackUserKickOff.WithEnable { // return callbackResp // } // callbackUserKickOffReq := cbApi.CallbackUserKickOffReq{ diff --git a/internal/msggateway/hub_server.go b/internal/msggateway/hub_server.go index 739c4232ff..1465655615 100644 --- a/internal/msggateway/hub_server.go +++ b/internal/msggateway/hub_server.go @@ -23,7 +23,6 @@ import ( "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/mcontext" - "github.com/OpenIMSDK/tools/utils" "github.com/openimsdk/open-im-server/v3/pkg/authverify" "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" @@ -58,22 +57,25 @@ type Server struct { rpcPort int prometheusPort int LongConnServer LongConnServer - pushTerminal []int config *config.GlobalConfig + pushTerminal map[int]struct{} } func (s *Server) SetLongConnServer(LongConnServer LongConnServer) { s.LongConnServer = LongConnServer } -func NewServer(rpcPort int, proPort int, longConnServer LongConnServer, config *config.GlobalConfig) *Server { - return &Server{ +func NewServer(rpcPort int, proPort int, longConnServer LongConnServer, conf *config.GlobalConfig) *Server { + s := &Server{ rpcPort: rpcPort, prometheusPort: proPort, LongConnServer: longConnServer, - pushTerminal: []int{constant.IOSPlatformID, constant.AndroidPlatformID}, - config: config, + pushTerminal: make(map[int]struct{}), + config: conf, } + s.pushTerminal[constant.IOSPlatformID] = struct{}{} + s.pushTerminal[constant.AndroidPlatformID] = struct{}{} + return s } func (s *Server) OnlinePushMsg( @@ -127,13 +129,9 @@ func (s *Server) OnlineBatchPushOneMsg( panic("implement me") } -func (s *Server) SuperGroupOnlineBatchPushOneMsg( - ctx context.Context, - req *msggateway.OnlineBatchPushOneMsgReq, +func (s *Server) SuperGroupOnlineBatchPushOneMsg(ctx context.Context, req *msggateway.OnlineBatchPushOneMsgReq, ) (*msggateway.OnlineBatchPushOneMsgResp, error) { - var singleUserResults []*msggateway.SingleMsgToUserResults - for _, v := range req.PushToUserIDs { var resp []*msggateway.SingleMsgToUserPlatform results := &msggateway.SingleMsgToUserResults{ @@ -154,23 +152,22 @@ func (s *Server) SuperGroupOnlineBatchPushOneMsg( } userPlatform := &msggateway.SingleMsgToUserPlatform{ - RecvID: v, RecvPlatFormID: int32(client.PlatformID), } if !client.IsBackground || (client.IsBackground && client.PlatformID != constant.IOSPlatformID) { err := client.PushMessage(ctx, req.MsgData) if err != nil { - userPlatform.ResultCode = -2 + userPlatform.ResultCode = int64(errs.ErrPushMsgErr.Code()) resp = append(resp, userPlatform) } else { - if utils.IsContainInt(client.PlatformID, s.pushTerminal) { + if _, ok := s.pushTerminal[client.PlatformID]; ok { results.OnlinePush = true resp = append(resp, userPlatform) } } } else { - userPlatform.ResultCode = -3 + userPlatform.ResultCode = int64(errs.ErrIOSBackgroundPushErr.Code()) resp = append(resp, userPlatform) } } diff --git a/internal/push/push_rpc_server.go b/internal/push/push_rpc_server.go index 2d2f953368..d5d4c92425 100644 --- a/internal/push/push_rpc_server.go +++ b/internal/push/push_rpc_server.go @@ -16,6 +16,7 @@ package push import ( "context" + "github.com/openimsdk/open-im-server/v3/pkg/rpccache" "github.com/OpenIMSDK/protocol/constant" pbpush "github.com/OpenIMSDK/protocol/push" @@ -25,7 +26,6 @@ import ( "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/localcache" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" "google.golang.org/grpc" ) @@ -51,8 +51,8 @@ func Start(config *config.GlobalConfig, client discoveryregistry.SvcDiscoveryReg client, offlinePusher, database, - localcache.NewGroupLocalCache(&groupRpcClient), - localcache.NewConversationLocalCache(&conversationRpcClient), + rpccache.NewGroupLocalCache(groupRpcClient, rdb), + rpccache.NewConversationLocalCache(conversationRpcClient, rdb), &conversationRpcClient, &groupRpcClient, &msgRpcClient, diff --git a/internal/push/push_to_client.go b/internal/push/push_to_client.go index 49bce70ab0..2bf17eaf94 100644 --- a/internal/push/push_to_client.go +++ b/internal/push/push_to_client.go @@ -18,6 +18,7 @@ import ( "context" "encoding/json" "errors" + "github.com/openimsdk/open-im-server/v3/pkg/rpccache" "sync" "github.com/OpenIMSDK/protocol/constant" @@ -36,7 +37,6 @@ import ( "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/localcache" "github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics" "github.com/openimsdk/open-im-server/v3/pkg/msgprocessor" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" @@ -49,8 +49,8 @@ type Pusher struct { database controller.PushDatabase discov discoveryregistry.SvcDiscoveryRegistry offlinePusher offlinepush.OfflinePusher - groupLocalCache *localcache.GroupLocalCache - conversationLocalCache *localcache.ConversationLocalCache + groupLocalCache *rpccache.GroupLocalCache + conversationLocalCache *rpccache.ConversationLocalCache msgRpcClient *rpcclient.MessageRpcClient conversationRpcClient *rpcclient.ConversationRpcClient groupRpcClient *rpcclient.GroupRpcClient @@ -59,7 +59,7 @@ type Pusher struct { var errNoOfflinePusher = errors.New("no offlinePusher is configured") func NewPusher(config *config.GlobalConfig, discov discoveryregistry.SvcDiscoveryRegistry, offlinePusher offlinepush.OfflinePusher, database controller.PushDatabase, - groupLocalCache *localcache.GroupLocalCache, conversationLocalCache *localcache.ConversationLocalCache, + groupLocalCache *rpccache.GroupLocalCache, conversationLocalCache *rpccache.ConversationLocalCache, conversationRpcClient *rpcclient.ConversationRpcClient, groupRpcClient *rpcclient.GroupRpcClient, msgRpcClient *rpcclient.MessageRpcClient, ) *Pusher { return &Pusher{ diff --git a/internal/rpc/conversation/conversaion.go b/internal/rpc/conversation/conversaion.go index 15e7998afa..81b4d9d45d 100644 --- a/internal/rpc/conversation/conversaion.go +++ b/internal/rpc/conversation/conversaion.go @@ -48,14 +48,6 @@ type conversationServer struct { config *config.GlobalConfig } -func (c *conversationServer) GetConversationNotReceiveMessageUserIDs( - ctx context.Context, - req *pbconversation.GetConversationNotReceiveMessageUserIDsReq, -) (*pbconversation.GetConversationNotReceiveMessageUserIDsResp, error) { - //TODO implement me - panic("implement me") -} - func Start(config *config.GlobalConfig, client discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) error { rdb, err := cache.NewRedis(config) if err != nil { @@ -96,11 +88,11 @@ func (c *conversationServer) GetConversation(ctx context.Context, req *pbconvers return resp, nil } -func (m *conversationServer) GetSortedConversationList(ctx context.Context, req *pbconversation.GetSortedConversationListReq) (resp *pbconversation.GetSortedConversationListResp, err error) { +func (c *conversationServer) GetSortedConversationList(ctx context.Context, req *pbconversation.GetSortedConversationListReq) (resp *pbconversation.GetSortedConversationListResp, err error) { log.ZDebug(ctx, "GetSortedConversationList", "seqs", req, "userID", req.UserID) var conversationIDs []string if len(req.ConversationIDs) == 0 { - conversationIDs, err = m.conversationDatabase.GetConversationIDs(ctx, req.UserID) + conversationIDs, err = c.conversationDatabase.GetConversationIDs(ctx, req.UserID) if err != nil { return nil, err } @@ -108,7 +100,7 @@ func (m *conversationServer) GetSortedConversationList(ctx context.Context, req conversationIDs = req.ConversationIDs } - conversations, err := m.conversationDatabase.FindConversations(ctx, req.UserID, conversationIDs) + conversations, err := c.conversationDatabase.FindConversations(ctx, req.UserID, conversationIDs) if err != nil { return nil, err } @@ -116,22 +108,22 @@ func (m *conversationServer) GetSortedConversationList(ctx context.Context, req return nil, errs.ErrRecordNotFound.Wrap() } - maxSeqs, err := m.msgRpcClient.GetMaxSeqs(ctx, conversationIDs) + maxSeqs, err := c.msgRpcClient.GetMaxSeqs(ctx, conversationIDs) if err != nil { return nil, err } - chatLogs, err := m.msgRpcClient.GetMsgByConversationIDs(ctx, conversationIDs, maxSeqs) + chatLogs, err := c.msgRpcClient.GetMsgByConversationIDs(ctx, conversationIDs, maxSeqs) if err != nil { return nil, err } - conversationMsg, err := m.getConversationInfo(ctx, chatLogs, req.UserID) + conversationMsg, err := c.getConversationInfo(ctx, chatLogs, req.UserID) if err != nil { return nil, err } - hasReadSeqs, err := m.msgRpcClient.GetHasReadSeqs(ctx, req.UserID, conversationIDs) + hasReadSeqs, err := c.msgRpcClient.GetHasReadSeqs(ctx, req.UserID, conversationIDs) if err != nil { return nil, err } @@ -163,8 +155,8 @@ func (m *conversationServer) GetSortedConversationList(ctx context.Context, req UnreadTotal: unreadTotal, } - m.conversationSort(conversation_isPinTime, resp, conversation_unreadCount, conversationMsg) - m.conversationSort(conversation_notPinTime, resp, conversation_unreadCount, conversationMsg) + c.conversationSort(conversation_isPinTime, resp, conversation_unreadCount, conversationMsg) + c.conversationSort(conversation_notPinTime, resp, conversation_unreadCount, conversationMsg) resp.ConversationElems = utils.Paginate(resp.ConversationElems, int(req.Pagination.GetPageNumber()), int(req.Pagination.GetShowNumber())) return resp, nil @@ -535,3 +527,11 @@ func (c *conversationServer) getConversationInfo( } return conversationMsg, nil } + +func (c *conversationServer) GetConversationNotReceiveMessageUserIDs(ctx context.Context, req *pbconversation.GetConversationNotReceiveMessageUserIDsReq) (*pbconversation.GetConversationNotReceiveMessageUserIDsResp, error) { + userIDs, err := c.conversationDatabase.GetConversationNotReceiveMessageUserIDs(ctx, req.ConversationID) + if err != nil { + return nil, err + } + return &pbconversation.GetConversationNotReceiveMessageUserIDsResp{UserIDs: userIDs}, nil +} diff --git a/internal/rpc/friend/friend.go b/internal/rpc/friend/friend.go index 6403a4159d..9466c52245 100644 --- a/internal/rpc/friend/friend.go +++ b/internal/rpc/friend/friend.go @@ -16,26 +16,31 @@ package friend import ( "context" + "github.com/OpenIMSDK/tools/tx" + + "github.com/OpenIMSDK/protocol/sdkws" + + "github.com/openimsdk/open-im-server/v3/pkg/authverify" + + "github.com/OpenIMSDK/tools/log" + + "github.com/openimsdk/open-im-server/v3/pkg/common/convert" + "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" + + "google.golang.org/grpc" "github.com/OpenIMSDK/protocol/constant" pbfriend "github.com/OpenIMSDK/protocol/friend" - "github.com/OpenIMSDK/protocol/sdkws" registry "github.com/OpenIMSDK/tools/discoveryregistry" "github.com/OpenIMSDK/tools/errs" - "github.com/OpenIMSDK/tools/log" - "github.com/OpenIMSDK/tools/tx" "github.com/OpenIMSDK/tools/utils" - "github.com/openimsdk/open-im-server/v3/pkg/authverify" "github.com/openimsdk/open-im-server/v3/pkg/common/config" - "github.com/openimsdk/open-im-server/v3/pkg/common/convert" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" "github.com/openimsdk/open-im-server/v3/pkg/common/db/mgo" tablerelation "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" "github.com/openimsdk/open-im-server/v3/pkg/common/db/unrelation" - "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient/notification" - "google.golang.org/grpc" ) type friendServer struct { diff --git a/internal/rpc/msg/as_read.go b/internal/rpc/msg/as_read.go index f16fdc62f7..ef7c72368d 100644 --- a/internal/rpc/msg/as_read.go +++ b/internal/rpc/msg/as_read.go @@ -41,7 +41,7 @@ func (m *msgServer) GetConversationsHasReadAndMaxSeq(ctx context.Context, req *m if err != nil { return nil, err } - conversations, err := m.Conversation.GetConversations(ctx, req.UserID, conversationIDs) + conversations, err := m.ConversationLocalCache.GetConversations(ctx, req.UserID, conversationIDs) if err != nil { return nil, err } @@ -104,7 +104,7 @@ func (m *msgServer) MarkMsgsAsRead( if hasReadSeq > maxSeq { return nil, errs.ErrArgs.Wrap("hasReadSeq must not be bigger than maxSeq") } - conversation, err := m.Conversation.GetConversation(ctx, req.UserID, req.ConversationID) + conversation, err := m.ConversationLocalCache.GetConversation(ctx, req.UserID, req.ConversationID) if err != nil { return } @@ -144,7 +144,7 @@ func (m *msgServer) MarkConversationAsRead( ctx context.Context, req *msg.MarkConversationAsReadReq, ) (resp *msg.MarkConversationAsReadResp, err error) { - conversation, err := m.Conversation.GetConversation(ctx, req.UserID, req.ConversationID) + conversation, err := m.ConversationLocalCache.GetConversation(ctx, req.UserID, req.ConversationID) if err != nil { return nil, err } diff --git a/internal/rpc/msg/revoke.go b/internal/rpc/msg/revoke.go index 5ac8804c26..99690b0cc7 100644 --- a/internal/rpc/msg/revoke.go +++ b/internal/rpc/msg/revoke.go @@ -44,7 +44,7 @@ func (m *msgServer) RevokeMsg(ctx context.Context, req *msg.RevokeMsgReq) (*msg. if err := authverify.CheckAccessV3(ctx, req.UserID, m.config); err != nil { return nil, err } - user, err := m.User.GetUserInfo(ctx, req.UserID) + user, err := m.UserLocalCache.GetUserInfo(ctx, req.UserID) if err != nil { return nil, err } @@ -70,12 +70,7 @@ func (m *msgServer) RevokeMsg(ctx context.Context, req *msg.RevokeMsgReq) (*msg. } role = user.AppMangerLevel case constant.SuperGroupChatType: - members, err := m.Group.GetGroupMemberInfoMap( - ctx, - msgs[0].GroupID, - utils.Distinct([]string{req.UserID, msgs[0].SendID}), - true, - ) + members, err := m.GroupLocalCache.GetGroupMemberInfoMap(ctx, msgs[0].GroupID, utils.Distinct([]string{req.UserID, msgs[0].SendID})) if err != nil { return nil, err } diff --git a/internal/rpc/msg/send.go b/internal/rpc/msg/send.go index 949a880b9f..ea59c40cff 100644 --- a/internal/rpc/msg/send.go +++ b/internal/rpc/msg/send.go @@ -97,7 +97,7 @@ func (m *msgServer) setConversationAtInfo(nctx context.Context, msg *sdkws.MsgDa } tagAll := utils.IsContain(constant.AtAllString, msg.AtUserIDList) if tagAll { - memberUserIDList, err := m.Group.GetGroupMemberIDs(ctx, msg.GroupID) + memberUserIDList, err := m.GroupLocalCache.GetGroupMemberIDs(ctx, msg.GroupID) if err != nil { log.ZWarn(ctx, "GetGroupMemberIDs", err) return @@ -143,6 +143,7 @@ func (m *msgServer) sendMsgNotification( } func (m *msgServer) sendMsgSingleChat(ctx context.Context, req *pbmsg.SendMsgReq) (resp *pbmsg.SendMsgResp, err error) { + log.ZDebug(ctx, "sendMsgSingleChat return") if err := m.messageVerification(ctx, req); err != nil { return nil, err } diff --git a/internal/rpc/msg/server.go b/internal/rpc/msg/server.go index 72e0b065a7..6212dea032 100644 --- a/internal/rpc/msg/server.go +++ b/internal/rpc/msg/server.go @@ -15,6 +15,8 @@ package msg import ( + "github.com/openimsdk/open-im-server/v3/pkg/rpccache" + "github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/protocol/conversation" "github.com/OpenIMSDK/protocol/msg" @@ -22,7 +24,6 @@ import ( "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/localcache" "github.com/openimsdk/open-im-server/v3/pkg/common/db/unrelation" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" "google.golang.org/grpc" @@ -33,12 +34,11 @@ type ( msgServer struct { RegisterCenter discoveryregistry.SvcDiscoveryRegistry MsgDatabase controller.CommonMsgDatabase - Group *rpcclient.GroupRpcClient - User *rpcclient.UserRpcClient Conversation *rpcclient.ConversationRpcClient - friend *rpcclient.FriendRpcClient - GroupLocalCache *localcache.GroupLocalCache - ConversationLocalCache *localcache.ConversationLocalCache + UserLocalCache *rpccache.UserLocalCache + FriendLocalCache *rpccache.FriendLocalCache + GroupLocalCache *rpccache.GroupLocalCache + ConversationLocalCache *rpccache.ConversationLocalCache Handlers MessageInterceptorChain notificationSender *rpcclient.NotificationSender config *config.GlobalConfig @@ -84,13 +84,12 @@ func Start(config *config.GlobalConfig, client discoveryregistry.SvcDiscoveryReg } s := &msgServer{ Conversation: &conversationClient, - User: &userRpcClient, - Group: &groupRpcClient, MsgDatabase: msgDatabase, RegisterCenter: client, - GroupLocalCache: localcache.NewGroupLocalCache(&groupRpcClient), - ConversationLocalCache: localcache.NewConversationLocalCache(&conversationClient), - friend: &friendRpcClient, + UserLocalCache: rpccache.NewUserLocalCache(userRpcClient, rdb), + GroupLocalCache: rpccache.NewGroupLocalCache(groupRpcClient, rdb), + ConversationLocalCache: rpccache.NewConversationLocalCache(conversationClient, rdb), + FriendLocalCache: rpccache.NewFriendLocalCache(friendRpcClient, rdb), config: config, } s.notificationSender = rpcclient.NewNotificationSender(config, rpcclient.WithLocalSendMsg(s.SendMsg)) diff --git a/internal/rpc/msg/statistics.go b/internal/rpc/msg/statistics.go index d7d33459b0..e62954dea4 100644 --- a/internal/rpc/msg/statistics.go +++ b/internal/rpc/msg/statistics.go @@ -40,7 +40,7 @@ func (m *msgServer) GetActiveUser(ctx context.Context, req *msg.GetActiveUserReq var pbUsers []*msg.ActiveUser if len(users) > 0 { userIDs := utils.Slice(users, func(e *unrelation.UserCount) string { return e.UserID }) - userMap, err := m.User.GetUsersInfoMap(ctx, userIDs) + userMap, err := m.UserLocalCache.GetUsersInfoMap(ctx, userIDs) if err != nil { return nil, err } @@ -82,7 +82,7 @@ func (m *msgServer) GetActiveGroup(ctx context.Context, req *msg.GetActiveGroupR var pbgroups []*msg.ActiveGroup if len(groups) > 0 { groupIDs := utils.Slice(groups, func(e *unrelation.GroupCount) string { return e.GroupID }) - resp, err := m.Group.GetGroupInfos(ctx, groupIDs, false) + resp, err := m.GroupLocalCache.GetGroupInfos(ctx, groupIDs) if err != nil { return nil, err } diff --git a/internal/rpc/msg/sync_msg.go b/internal/rpc/msg/sync_msg.go index b714da375f..6fa4a0c9d1 100644 --- a/internal/rpc/msg/sync_msg.go +++ b/internal/rpc/msg/sync_msg.go @@ -35,7 +35,7 @@ func (m *msgServer) PullMessageBySeqs( resp.NotificationMsgs = make(map[string]*sdkws.PullMsgs) for _, seq := range req.SeqRanges { if !msgprocessor.IsNotification(seq.ConversationID) { - conversation, err := m.Conversation.GetConversation(ctx, req.UserID, seq.ConversationID) + conversation, err := m.ConversationLocalCache.GetConversation(ctx, req.UserID, seq.ConversationID) if err != nil { log.ZError(ctx, "GetConversation error", err, "conversationID", seq.ConversationID) continue @@ -138,7 +138,7 @@ func (m *msgServer) SearchMessage(ctx context.Context, req *msg.SearchMessageReq } } if len(sendIDs) != 0 { - sendInfos, err := m.User.GetUsersInfo(ctx, sendIDs) + sendInfos, err := m.UserLocalCache.GetUsersInfo(ctx, sendIDs) if err != nil { return nil, err } @@ -147,7 +147,7 @@ func (m *msgServer) SearchMessage(ctx context.Context, req *msg.SearchMessageReq } } if len(recvIDs) != 0 { - recvInfos, err := m.User.GetUsersInfo(ctx, recvIDs) + recvInfos, err := m.UserLocalCache.GetUsersInfo(ctx, recvIDs) if err != nil { return nil, err } @@ -156,7 +156,7 @@ func (m *msgServer) SearchMessage(ctx context.Context, req *msg.SearchMessageReq } } if len(groupIDs) != 0 { - groupInfos, err := m.Group.GetGroupInfos(ctx, groupIDs, true) + groupInfos, err := m.GroupLocalCache.GetGroupInfos(ctx, groupIDs) if err != nil { return nil, err } diff --git a/internal/rpc/msg/verify.go b/internal/rpc/msg/verify.go index d72e4923ee..318464cf82 100644 --- a/internal/rpc/msg/verify.go +++ b/internal/rpc/msg/verify.go @@ -16,6 +16,7 @@ package msg import ( "context" + "github.com/OpenIMSDK/tools/log" "math/rand" "strconv" "time" @@ -59,15 +60,15 @@ func (m *msgServer) messageVerification(ctx context.Context, data *msg.SendMsgRe data.MsgData.ContentType >= constant.NotificationBegin { return nil } - black, err := m.friend.IsBlocked(ctx, data.MsgData.SendID, data.MsgData.RecvID) + black, err := m.FriendLocalCache.IsBlack(ctx, data.MsgData.SendID, data.MsgData.RecvID) if err != nil { return err } if black { return errs.ErrBlockedByPeer.Wrap() } - if *m.config.MessageVerify.FriendVerify { - friend, err := m.friend.IsFriend(ctx, data.MsgData.SendID, data.MsgData.RecvID) + if m.config.MessageVerify.FriendVerify != nil && *m.config.MessageVerify.FriendVerify { + friend, err := m.FriendLocalCache.IsFriend(ctx, data.MsgData.SendID, data.MsgData.RecvID) if err != nil { return err } @@ -78,7 +79,7 @@ func (m *msgServer) messageVerification(ctx context.Context, data *msg.SendMsgRe } return nil case constant.SuperGroupChatType: - groupInfo, err := m.Group.GetGroupInfoCache(ctx, data.MsgData.GroupID) + groupInfo, err := m.GroupLocalCache.GetGroupInfo(ctx, data.MsgData.GroupID) if err != nil { return err } @@ -99,17 +100,17 @@ func (m *msgServer) messageVerification(ctx context.Context, data *msg.SendMsgRe data.MsgData.ContentType >= constant.NotificationBegin { return nil } - // memberIDs, err := m.GroupLocalCache.GetGroupMemberIDs(ctx, data.MsgData.GroupID) - // if err != nil { - // return err - // } - // if !utils.IsContain(data.MsgData.SendID, memberIDs) { - // return errs.ErrNotInGroupYet.Wrap() - // } + memberIDs, err := m.GroupLocalCache.GetGroupMemberIDMap(ctx, data.MsgData.GroupID) + if err != nil { + return err + } + if _, ok := memberIDs[data.MsgData.SendID]; !ok { + return errs.ErrNotInGroupYet.Wrap() + } - groupMemberInfo, err := m.Group.GetGroupMemberCache(ctx, data.MsgData.GroupID, data.MsgData.SendID) + groupMemberInfo, err := m.GroupLocalCache.GetGroupMember(ctx, data.MsgData.GroupID, data.MsgData.SendID) if err != nil { - if err == errs.ErrRecordNotFound { + if errs.ErrRecordNotFound.Is(err) { return errs.ErrNotInGroupYet.Wrap(err.Error()) } return err @@ -157,6 +158,9 @@ func (m *msgServer) encapsulateMsgData(msg *sdkws.MsgData) { case constant.Custom: fallthrough case constant.Quote: + utils.SetSwitchFromOptions(msg.Options, constant.IsConversationUpdate, true) + utils.SetSwitchFromOptions(msg.Options, constant.IsUnreadCount, true) + utils.SetSwitchFromOptions(msg.Options, constant.IsSenderSync, true) case constant.Revoke: utils.SetSwitchFromOptions(msg.Options, constant.IsUnreadCount, false) utils.SetSwitchFromOptions(msg.Options, constant.IsOfflinePush, false) @@ -187,7 +191,8 @@ func (m *msgServer) modifyMessageByUserMessageReceiveOpt( sessionType int, pb *msg.SendMsgReq, ) (bool, error) { - opt, err := m.User.GetUserGlobalMsgRecvOpt(ctx, userID) + defer log.ZDebug(ctx, "modifyMessageByUserMessageReceiveOpt return") + opt, err := m.UserLocalCache.GetUserGlobalMsgRecvOpt(ctx, userID) if err != nil { return false, err } @@ -203,7 +208,7 @@ func (m *msgServer) modifyMessageByUserMessageReceiveOpt( return true, nil } // conversationID := utils.GetConversationIDBySessionType(conversationID, sessionType) - singleOpt, err := m.Conversation.GetSingleConversationRecvMsgOpt(ctx, userID, conversationID) + singleOpt, err := m.ConversationLocalCache.GetSingleConversationRecvMsgOpt(ctx, userID, conversationID) if errs.ErrRecordNotFound.Is(err) { return true, nil } else if err != nil { diff --git a/pkg/common/cachekey/black.go b/pkg/common/cachekey/black.go new file mode 100644 index 0000000000..527ad14dc2 --- /dev/null +++ b/pkg/common/cachekey/black.go @@ -0,0 +1,15 @@ +package cachekey + +const ( + BlackIDsKey = "BLACK_IDS:" + IsBlackKey = "IS_BLACK:" // local cache +) + +func GetBlackIDsKey(ownerUserID string) string { + return BlackIDsKey + ownerUserID + +} + +func GetIsBlackIDsKey(possibleBlackUserID, userID string) string { + return IsBlackKey + userID + "-" + possibleBlackUserID +} diff --git a/pkg/common/cachekey/conversation.go b/pkg/common/cachekey/conversation.go new file mode 100644 index 0000000000..665ca11c6c --- /dev/null +++ b/pkg/common/cachekey/conversation.go @@ -0,0 +1,44 @@ +package cachekey + +const ( + ConversationKey = "CONVERSATION:" + ConversationIDsKey = "CONVERSATION_IDS:" + ConversationIDsHashKey = "CONVERSATION_IDS_HASH:" + ConversationHasReadSeqKey = "CONVERSATION_HAS_READ_SEQ:" + RecvMsgOptKey = "RECV_MSG_OPT:" + SuperGroupRecvMsgNotNotifyUserIDsKey = "SUPER_GROUP_RECV_MSG_NOT_NOTIFY_USER_IDS:" + SuperGroupRecvMsgNotNotifyUserIDsHashKey = "SUPER_GROUP_RECV_MSG_NOT_NOTIFY_USER_IDS_HASH:" + ConversationNotReceiveMessageUserIDsKey = "CONVERSATION_NOT_RECEIVE_MESSAGE_USER_IDS:" +) + +func GetConversationKey(ownerUserID, conversationID string) string { + return ConversationKey + ownerUserID + ":" + conversationID +} + +func GetConversationIDsKey(ownerUserID string) string { + return ConversationIDsKey + ownerUserID +} + +func GetSuperGroupRecvNotNotifyUserIDsKey(groupID string) string { + return SuperGroupRecvMsgNotNotifyUserIDsKey + groupID +} + +func GetRecvMsgOptKey(ownerUserID, conversationID string) string { + return RecvMsgOptKey + ownerUserID + ":" + conversationID +} + +func GetSuperGroupRecvNotNotifyUserIDsHashKey(groupID string) string { + return SuperGroupRecvMsgNotNotifyUserIDsHashKey + groupID +} + +func GetConversationHasReadSeqKey(ownerUserID, conversationID string) string { + return ConversationHasReadSeqKey + ownerUserID + ":" + conversationID +} + +func GetConversationNotReceiveMessageUserIDsKey(conversationID string) string { + return ConversationNotReceiveMessageUserIDsKey + conversationID +} + +func GetUserConversationIDsHashKey(ownerUserID string) string { + return ConversationIDsHashKey + ownerUserID +} diff --git a/pkg/common/cachekey/friend.go b/pkg/common/cachekey/friend.go new file mode 100644 index 0000000000..f37c9da37d --- /dev/null +++ b/pkg/common/cachekey/friend.go @@ -0,0 +1,24 @@ +package cachekey + +const ( + FriendIDsKey = "FRIEND_IDS:" + TwoWayFriendsIDsKey = "COMMON_FRIENDS_IDS:" + FriendKey = "FRIEND_INFO:" + IsFriendKey = "IS_FRIEND:" // local cache key +) + +func GetFriendIDsKey(ownerUserID string) string { + return FriendIDsKey + ownerUserID +} + +func GetTwoWayFriendsIDsKey(ownerUserID string) string { + return TwoWayFriendsIDsKey + ownerUserID +} + +func GetFriendKey(ownerUserID, friendUserID string) string { + return FriendKey + ownerUserID + "-" + friendUserID +} + +func GetIsFriendKey(possibleFriendUserID, userID string) string { + return IsFriendKey + possibleFriendUserID + "-" + userID +} diff --git a/pkg/common/cachekey/group.go b/pkg/common/cachekey/group.go new file mode 100644 index 0000000000..1dcf0ffcef --- /dev/null +++ b/pkg/common/cachekey/group.go @@ -0,0 +1,45 @@ +package cachekey + +import ( + "strconv" + "time" +) + +const ( + groupExpireTime = time.Second * 60 * 60 * 12 + GroupInfoKey = "GROUP_INFO:" + GroupMemberIDsKey = "GROUP_MEMBER_IDS:" + GroupMembersHashKey = "GROUP_MEMBERS_HASH2:" + GroupMemberInfoKey = "GROUP_MEMBER_INFO:" + JoinedGroupsKey = "JOIN_GROUPS_KEY:" + GroupMemberNumKey = "GROUP_MEMBER_NUM_CACHE:" + GroupRoleLevelMemberIDsKey = "GROUP_ROLE_LEVEL_MEMBER_IDS:" +) + +func GetGroupInfoKey(groupID string) string { + return GroupInfoKey + groupID +} + +func GetJoinedGroupsKey(userID string) string { + return JoinedGroupsKey + userID +} + +func GetGroupMembersHashKey(groupID string) string { + return GroupMembersHashKey + groupID +} + +func GetGroupMemberIDsKey(groupID string) string { + return GroupMemberIDsKey + groupID +} + +func GetGroupMemberInfoKey(groupID, userID string) string { + return GroupMemberInfoKey + groupID + "-" + userID +} + +func GetGroupMemberNumKey(groupID string) string { + return GroupMemberNumKey + groupID +} + +func GetGroupRoleLevelMemberIDsKey(groupID string, roleLevel int32) string { + return GroupRoleLevelMemberIDsKey + groupID + "-" + strconv.Itoa(int(roleLevel)) +} diff --git a/pkg/common/cachekey/user.go b/pkg/common/cachekey/user.go new file mode 100644 index 0000000000..3fb877e222 --- /dev/null +++ b/pkg/common/cachekey/user.go @@ -0,0 +1,14 @@ +package cachekey + +const ( + UserInfoKey = "USER_INFO:" + UserGlobalRecvMsgOptKey = "USER_GLOBAL_RECV_MSG_OPT_KEY:" +) + +func GetUserInfoKey(userID string) string { + return UserInfoKey + userID +} + +func GetUserGlobalRecvMsgOptKey(userID string) string { + return UserGlobalRecvMsgOptKey + userID +} diff --git a/pkg/common/config/config.go b/pkg/common/config/config.go index ac42395bf1..8bc8713551 100644 --- a/pkg/common/config/config.go +++ b/pkg/common/config/config.go @@ -16,6 +16,7 @@ package config import ( "bytes" + "time" "github.com/OpenIMSDK/tools/discoveryregistry" "gopkg.in/yaml.v3" @@ -266,6 +267,8 @@ type GlobalConfig struct { FriendVerify *bool `yaml:"friendVerify"` } `yaml:"messageVerify"` + LocalCache localCache `yaml:"localCache"` + IOSPush struct { PushSound string `yaml:"pushSound"` BadgeCount bool `yaml:"badgeCount"` @@ -382,6 +385,33 @@ type notification struct { ConversationSetPrivate NotificationConf `yaml:"conversationSetPrivate"` } +type LocalCache struct { + Topic string `yaml:"topic"` + SlotNum int `yaml:"slotNum"` + SlotSize int `yaml:"slotSize"` + SuccessExpire int `yaml:"successExpire"` // second + FailedExpire int `yaml:"failedExpire"` // second +} + +func (l LocalCache) Failed() time.Duration { + return time.Second * time.Duration(l.FailedExpire) +} + +func (l LocalCache) Success() time.Duration { + return time.Second * time.Duration(l.SuccessExpire) +} + +func (l LocalCache) Enable() bool { + return l.Topic != "" && l.SlotNum > 0 && l.SlotSize > 0 +} + +type localCache struct { + User LocalCache `yaml:"user"` + Group LocalCache `yaml:"group"` + Friend LocalCache `yaml:"friend"` + Conversation LocalCache `yaml:"conversation"` +} + func (c *GlobalConfig) GetServiceNames() []string { return []string{ c.RpcRegisterName.OpenImUserName, diff --git a/pkg/common/config/parse_test.go b/pkg/common/config/parse_test.go index 84dee1165a..9b964a2777 100644 --- a/pkg/common/config/parse_test.go +++ b/pkg/common/config/parse_test.go @@ -16,6 +16,8 @@ package config import ( _ "embed" + "fmt" + "gopkg.in/yaml.v3" "reflect" "testing" @@ -116,3 +118,13 @@ func TestInitConfig(t *testing.T) { }) } } + +func TestName(t *testing.T) { + Config.LocalCache.Friend.Topic = "friend" + Config.LocalCache.Friend.SlotNum = 500 + Config.LocalCache.Friend.SlotSize = 20000 + + data, _ := yaml.Marshal(&Config) + + fmt.Println(string(data)) +} diff --git a/pkg/common/db/cache/black.go b/pkg/common/db/cache/black.go index c8cf2ddd38..fd743e9179 100644 --- a/pkg/common/db/cache/black.go +++ b/pkg/common/db/cache/black.go @@ -16,6 +16,9 @@ package cache import ( "context" + "github.com/OpenIMSDK/tools/log" + "github.com/openimsdk/open-im-server/v3/pkg/common/cachekey" + "github.com/openimsdk/open-im-server/v3/pkg/common/config" "time" "github.com/dtm-labs/rockscache" @@ -47,11 +50,15 @@ type BlackCacheRedis struct { func NewBlackCacheRedis(rdb redis.UniversalClient, blackDB relationtb.BlackModelInterface, options rockscache.Options) BlackCache { rcClient := rockscache.NewClient(rdb, options) - + mc := NewMetaCacheRedis(rcClient) + b := config.Config.LocalCache.Friend + log.ZDebug(context.Background(), "black local cache init", "Topic", b.Topic, "SlotNum", b.SlotNum, "SlotSize", b.SlotSize, "enable", b.Enable()) + mc.SetTopic(b.Topic) + mc.SetRawRedisClient(rdb) return &BlackCacheRedis{ expireTime: blackExpireTime, rcClient: rcClient, - metaCache: NewMetaCacheRedis(rcClient), + metaCache: mc, blackDB: blackDB, } } @@ -61,12 +68,12 @@ func (b *BlackCacheRedis) NewCache() BlackCache { expireTime: b.expireTime, rcClient: b.rcClient, blackDB: b.blackDB, - metaCache: NewMetaCacheRedis(b.rcClient, b.metaCache.GetPreDelKeys()...), + metaCache: b.Copy(), } } func (b *BlackCacheRedis) getBlackIDsKey(ownerUserID string) string { - return blackIDsKey + ownerUserID + return cachekey.GetBlackIDsKey(ownerUserID) } func (b *BlackCacheRedis) GetBlackIDs(ctx context.Context, userID string) (blackIDs []string, err error) { diff --git a/pkg/common/db/cache/config.go b/pkg/common/db/cache/config.go new file mode 100644 index 0000000000..7599d8a115 --- /dev/null +++ b/pkg/common/db/cache/config.go @@ -0,0 +1,66 @@ +package cache + +import ( + "github.com/openimsdk/open-im-server/v3/pkg/common/cachekey" + "github.com/openimsdk/open-im-server/v3/pkg/common/config" + "strings" + "sync" +) + +var ( + once sync.Once + subscribe map[string][]string +) + +func getPublishKey(topic string, key []string) []string { + if topic == "" || len(key) == 0 { + return nil + } + once.Do(func() { + list := []struct { + Local config.LocalCache + Keys []string + }{ + { + Local: config.Config.LocalCache.User, + Keys: []string{cachekey.UserInfoKey, cachekey.UserGlobalRecvMsgOptKey}, + }, + { + Local: config.Config.LocalCache.Group, + Keys: []string{cachekey.GroupMemberIDsKey, cachekey.GroupInfoKey, cachekey.GroupMemberInfoKey}, + }, + { + Local: config.Config.LocalCache.Friend, + Keys: []string{cachekey.FriendIDsKey, cachekey.BlackIDsKey}, + }, + { + Local: config.Config.LocalCache.Conversation, + Keys: []string{cachekey.ConversationKey, cachekey.ConversationIDsKey, cachekey.ConversationNotReceiveMessageUserIDsKey}, + }, + } + subscribe = make(map[string][]string) + for _, v := range list { + if v.Local.Enable() { + subscribe[v.Local.Topic] = v.Keys + } + } + }) + prefix, ok := subscribe[topic] + if !ok { + return nil + } + res := make([]string, 0, len(key)) + for _, k := range key { + var exist bool + for _, p := range prefix { + if strings.HasPrefix(k, p) { + exist = true + break + } + } + if exist { + res = append(res, k) + } + } + return res +} diff --git a/pkg/common/db/cache/conversation.go b/pkg/common/db/cache/conversation.go index 90e4003638..ef725642c7 100644 --- a/pkg/common/db/cache/conversation.go +++ b/pkg/common/db/cache/conversation.go @@ -16,6 +16,9 @@ package cache import ( "context" + "github.com/OpenIMSDK/tools/log" + "github.com/openimsdk/open-im-server/v3/pkg/common/cachekey" + "github.com/openimsdk/open-im-server/v3/pkg/common/config" "math/big" "strings" "time" @@ -27,14 +30,14 @@ import ( ) const ( - conversationKey = "CONVERSATION:" - conversationIDsKey = "CONVERSATION_IDS:" - conversationIDsHashKey = "CONVERSATION_IDS_HASH:" - conversationHasReadSeqKey = "CONVERSATION_HAS_READ_SEQ:" - recvMsgOptKey = "RECV_MSG_OPT:" - superGroupRecvMsgNotNotifyUserIDsKey = "SUPER_GROUP_RECV_MSG_NOT_NOTIFY_USER_IDS:" - superGroupRecvMsgNotNotifyUserIDsHashKey = "SUPER_GROUP_RECV_MSG_NOT_NOTIFY_USER_IDS_HASH:" - conversationNotReceiveMessageUserIDsKey = "CONVERSATION_NOT_RECEIVE_MESSAGE_USER_IDS:" + //conversationKey = "CONVERSATION:" + //conversationIDsKey = "CONVERSATION_IDS:" + //conversationIDsHashKey = "CONVERSATION_IDS_HASH:" + //conversationHasReadSeqKey = "CONVERSATION_HAS_READ_SEQ:" + //recvMsgOptKey = "RECV_MSG_OPT:" + //superGroupRecvMsgNotNotifyUserIDsKey = "SUPER_GROUP_RECV_MSG_NOT_NOTIFY_USER_IDS:" + //superGroupRecvMsgNotNotifyUserIDsHashKey = "SUPER_GROUP_RECV_MSG_NOT_NOTIFY_USER_IDS_HASH:" + //conversationNotReceiveMessageUserIDsKey = "CONVERSATION_NOT_RECEIVE_MESSAGE_USER_IDS:" conversationExpireTime = time.Second * 60 * 60 * 12 ) @@ -81,10 +84,14 @@ type ConversationCache interface { func NewConversationRedis(rdb redis.UniversalClient, opts rockscache.Options, db relationtb.ConversationModelInterface) ConversationCache { rcClient := rockscache.NewClient(rdb, opts) - + mc := NewMetaCacheRedis(rcClient) + c := config.Config.LocalCache.Conversation + log.ZDebug(context.Background(), "black local cache init", "Topic", c.Topic, "SlotNum", c.SlotNum, "SlotSize", c.SlotSize, "enable", c.Enable()) + mc.SetTopic(c.Topic) + mc.SetRawRedisClient(rdb) return &ConversationRedisCache{ rcClient: rcClient, - metaCache: NewMetaCacheRedis(rcClient), + metaCache: mc, conversationDB: db, expireTime: conversationExpireTime, } @@ -115,38 +122,42 @@ type ConversationRedisCache struct { func (c *ConversationRedisCache) NewCache() ConversationCache { return &ConversationRedisCache{ rcClient: c.rcClient, - metaCache: NewMetaCacheRedis(c.rcClient, c.metaCache.GetPreDelKeys()...), + metaCache: c.Copy(), conversationDB: c.conversationDB, expireTime: c.expireTime, } } func (c *ConversationRedisCache) getConversationKey(ownerUserID, conversationID string) string { - return conversationKey + ownerUserID + ":" + conversationID + return cachekey.GetConversationKey(ownerUserID, conversationID) } func (c *ConversationRedisCache) getConversationIDsKey(ownerUserID string) string { - return conversationIDsKey + ownerUserID + return cachekey.GetConversationIDsKey(ownerUserID) } func (c *ConversationRedisCache) getSuperGroupRecvNotNotifyUserIDsKey(groupID string) string { - return superGroupRecvMsgNotNotifyUserIDsKey + groupID + return cachekey.GetSuperGroupRecvNotNotifyUserIDsKey(groupID) } func (c *ConversationRedisCache) getRecvMsgOptKey(ownerUserID, conversationID string) string { - return recvMsgOptKey + ownerUserID + ":" + conversationID + return cachekey.GetRecvMsgOptKey(ownerUserID, conversationID) } func (c *ConversationRedisCache) getSuperGroupRecvNotNotifyUserIDsHashKey(groupID string) string { - return superGroupRecvMsgNotNotifyUserIDsHashKey + groupID + return cachekey.GetSuperGroupRecvNotNotifyUserIDsHashKey(groupID) } func (c *ConversationRedisCache) getConversationHasReadSeqKey(ownerUserID, conversationID string) string { - return conversationHasReadSeqKey + ownerUserID + ":" + conversationID + return cachekey.GetConversationHasReadSeqKey(ownerUserID, conversationID) } func (c *ConversationRedisCache) getConversationNotReceiveMessageUserIDsKey(conversationID string) string { - return conversationNotReceiveMessageUserIDsKey + conversationID + return cachekey.GetConversationNotReceiveMessageUserIDsKey(conversationID) +} + +func (c *ConversationRedisCache) getUserConversationIDsHashKey(ownerUserID string) string { + return cachekey.GetUserConversationIDsHashKey(ownerUserID) } func (c *ConversationRedisCache) GetUserConversationIDs(ctx context.Context, ownerUserID string) ([]string, error) { @@ -166,10 +177,6 @@ func (c *ConversationRedisCache) DelConversationIDs(userIDs ...string) Conversat return cache } -func (c *ConversationRedisCache) getUserConversationIDsHashKey(ownerUserID string) string { - return conversationIDsHashKey + ownerUserID -} - func (c *ConversationRedisCache) GetUserConversationIDsHash(ctx context.Context, ownerUserID string) (hash uint64, err error) { return getCache( ctx, diff --git a/pkg/common/db/cache/friend.go b/pkg/common/db/cache/friend.go index a160837ba2..30b8bf7eaf 100644 --- a/pkg/common/db/cache/friend.go +++ b/pkg/common/db/cache/friend.go @@ -16,6 +16,9 @@ package cache import ( "context" + "github.com/OpenIMSDK/tools/log" + "github.com/openimsdk/open-im-server/v3/pkg/common/cachekey" + "github.com/openimsdk/open-im-server/v3/pkg/common/config" "time" "github.com/OpenIMSDK/tools/utils" @@ -25,10 +28,10 @@ import ( ) const ( - friendExpireTime = time.Second * 60 * 60 * 12 - friendIDsKey = "FRIEND_IDS:" - TwoWayFriendsIDsKey = "COMMON_FRIENDS_IDS:" - friendKey = "FRIEND_INFO:" + friendExpireTime = time.Second * 60 * 60 * 12 + //friendIDsKey = "FRIEND_IDS:" + //TwoWayFriendsIDsKey = "COMMON_FRIENDS_IDS:" + //friendKey = "FRIEND_INFO:" ) // FriendCache is an interface for caching friend-related data. @@ -58,8 +61,13 @@ type FriendCacheRedis struct { func NewFriendCacheRedis(rdb redis.UniversalClient, friendDB relationtb.FriendModelInterface, options rockscache.Options) FriendCache { rcClient := rockscache.NewClient(rdb, options) + mc := NewMetaCacheRedis(rcClient) + f := config.Config.LocalCache.Friend + log.ZDebug(context.Background(), "friend local cache init", "Topic", f.Topic, "SlotNum", f.SlotNum, "SlotSize", f.SlotSize, "enable", f.Enable()) + mc.SetTopic(f.Topic) + mc.SetRawRedisClient(rdb) return &FriendCacheRedis{ - metaCache: NewMetaCacheRedis(rcClient), + metaCache: mc, friendDB: friendDB, expireTime: friendExpireTime, rcClient: rcClient, @@ -70,7 +78,7 @@ func NewFriendCacheRedis(rdb redis.UniversalClient, friendDB relationtb.FriendMo func (f *FriendCacheRedis) NewCache() FriendCache { return &FriendCacheRedis{ rcClient: f.rcClient, - metaCache: NewMetaCacheRedis(f.rcClient, f.metaCache.GetPreDelKeys()...), + metaCache: f.Copy(), friendDB: f.friendDB, expireTime: f.expireTime, } @@ -78,17 +86,17 @@ func (f *FriendCacheRedis) NewCache() FriendCache { // getFriendIDsKey returns the key for storing friend IDs in the cache. func (f *FriendCacheRedis) getFriendIDsKey(ownerUserID string) string { - return friendIDsKey + ownerUserID + return cachekey.GetFriendIDsKey(ownerUserID) } // getTwoWayFriendsIDsKey returns the key for storing two-way friend IDs in the cache. func (f *FriendCacheRedis) getTwoWayFriendsIDsKey(ownerUserID string) string { - return TwoWayFriendsIDsKey + ownerUserID + return cachekey.GetTwoWayFriendsIDsKey(ownerUserID) } // getFriendKey returns the key for storing friend info in the cache. func (f *FriendCacheRedis) getFriendKey(ownerUserID, friendUserID string) string { - return friendKey + ownerUserID + "-" + friendUserID + return cachekey.GetFriendKey(ownerUserID, friendUserID) } // GetFriendIDs retrieves friend IDs from the cache or the database if not found. diff --git a/pkg/common/db/cache/group.go b/pkg/common/db/cache/group.go index 4a5266db5d..37b21ae902 100644 --- a/pkg/common/db/cache/group.go +++ b/pkg/common/db/cache/group.go @@ -17,7 +17,8 @@ package cache import ( "context" "fmt" - "strconv" + "github.com/openimsdk/open-im-server/v3/pkg/common/cachekey" + "github.com/openimsdk/open-im-server/v3/pkg/common/config" "time" "github.com/OpenIMSDK/protocol/constant" @@ -30,15 +31,14 @@ import ( ) const ( - groupExpireTime = time.Second * 60 * 60 * 12 - groupInfoKey = "GROUP_INFO:" - groupMemberIDsKey = "GROUP_MEMBER_IDS:" - groupMembersHashKey = "GROUP_MEMBERS_HASH2:" - groupMemberInfoKey = "GROUP_MEMBER_INFO:" - //groupOwnerInfoKey = "GROUP_OWNER_INFO:". - joinedGroupsKey = "JOIN_GROUPS_KEY:" - groupMemberNumKey = "GROUP_MEMBER_NUM_CACHE:" - groupRoleLevelMemberIDsKey = "GROUP_ROLE_LEVEL_MEMBER_IDS:" + groupExpireTime = time.Second * 60 * 60 * 12 + //groupInfoKey = "GROUP_INFO:" + //groupMemberIDsKey = "GROUP_MEMBER_IDS:" + //groupMembersHashKey = "GROUP_MEMBERS_HASH2:" + //groupMemberInfoKey = "GROUP_MEMBER_INFO:" + //joinedGroupsKey = "JOIN_GROUPS_KEY:" + //groupMemberNumKey = "GROUP_MEMBER_NUM_CACHE:" + //groupRoleLevelMemberIDsKey = "GROUP_ROLE_LEVEL_MEMBER_IDS:" ) type GroupHash interface { @@ -101,12 +101,16 @@ func NewGroupCacheRedis( opts rockscache.Options, ) GroupCache { rcClient := rockscache.NewClient(rdb, opts) - + mc := NewMetaCacheRedis(rcClient) + g := config.Config.LocalCache.Group + mc.SetTopic(g.Topic) + log.ZDebug(context.Background(), "group local cache init", "Topic", g.Topic, "SlotNum", g.SlotNum, "SlotSize", g.SlotSize, "enable", g.Enable()) + mc.SetRawRedisClient(rdb) return &GroupCacheRedis{ rcClient: rcClient, expireTime: groupExpireTime, groupDB: groupDB, groupMemberDB: groupMemberDB, groupRequestDB: groupRequestDB, groupHash: hashCode, - metaCache: NewMetaCacheRedis(rcClient), + metaCache: mc, } } @@ -117,36 +121,36 @@ func (g *GroupCacheRedis) NewCache() GroupCache { groupDB: g.groupDB, groupMemberDB: g.groupMemberDB, groupRequestDB: g.groupRequestDB, - metaCache: NewMetaCacheRedis(g.rcClient, g.metaCache.GetPreDelKeys()...), + metaCache: g.Copy(), } } func (g *GroupCacheRedis) getGroupInfoKey(groupID string) string { - return groupInfoKey + groupID + return cachekey.GetGroupInfoKey(groupID) } func (g *GroupCacheRedis) getJoinedGroupsKey(userID string) string { - return joinedGroupsKey + userID + return cachekey.GetJoinedGroupsKey(userID) } func (g *GroupCacheRedis) getGroupMembersHashKey(groupID string) string { - return groupMembersHashKey + groupID + return cachekey.GetGroupMembersHashKey(groupID) } func (g *GroupCacheRedis) getGroupMemberIDsKey(groupID string) string { - return groupMemberIDsKey + groupID + return cachekey.GetGroupMemberIDsKey(groupID) } func (g *GroupCacheRedis) getGroupMemberInfoKey(groupID, userID string) string { - return groupMemberInfoKey + groupID + "-" + userID + return cachekey.GetGroupMemberInfoKey(groupID, userID) } func (g *GroupCacheRedis) getGroupMemberNumKey(groupID string) string { - return groupMemberNumKey + groupID + return cachekey.GetGroupMemberNumKey(groupID) } func (g *GroupCacheRedis) getGroupRoleLevelMemberIDsKey(groupID string, roleLevel int32) string { - return groupRoleLevelMemberIDsKey + groupID + "-" + strconv.Itoa(int(roleLevel)) + return cachekey.GetGroupRoleLevelMemberIDsKey(groupID, roleLevel) } func (g *GroupCacheRedis) GetGroupIndex(group *relationtb.GroupModel, keys []string) (int, error) { diff --git a/pkg/common/db/cache/meta_cache.go b/pkg/common/db/cache/meta_cache.go index 4d4f077b67..b148513814 100644 --- a/pkg/common/db/cache/meta_cache.go +++ b/pkg/common/db/cache/meta_cache.go @@ -18,6 +18,7 @@ import ( "context" "encoding/json" "errors" + "github.com/redis/go-redis/v9" "fmt" "time" @@ -43,6 +44,9 @@ type metaCache interface { AddKeys(keys ...string) ClearKeys() GetPreDelKeys() []string + SetTopic(topic string) + SetRawRedisClient(cli redis.UniversalClient) + Copy() metaCache } func NewMetaCacheRedis(rcClient *rockscache.Client, keys ...string) metaCache { @@ -50,10 +54,36 @@ func NewMetaCacheRedis(rcClient *rockscache.Client, keys ...string) metaCache { } type metaCacheRedis struct { + topic string rcClient *rockscache.Client keys []string maxRetryTimes int retryInterval time.Duration + redisClient redis.UniversalClient +} + +func (m *metaCacheRedis) Copy() metaCache { + var keys []string + if len(m.keys) > 0 { + keys = make([]string, 0, len(m.keys)*2) + keys = append(keys, m.keys...) + } + return &metaCacheRedis{ + topic: m.topic, + rcClient: m.rcClient, + keys: keys, + maxRetryTimes: m.maxRetryTimes, + retryInterval: m.retryInterval, + redisClient: redisClient, + } +} + +func (m *metaCacheRedis) SetTopic(topic string) { + m.topic = topic +} + +func (m *metaCacheRedis) SetRawRedisClient(cli redis.UniversalClient) { + m.redisClient = cli } func (m *metaCacheRedis) ExecDel(ctx context.Context, distinct ...bool) error { @@ -61,7 +91,7 @@ func (m *metaCacheRedis) ExecDel(ctx context.Context, distinct ...bool) error { m.keys = utils.Distinct(m.keys) } if len(m.keys) > 0 { - log.ZDebug(ctx, "delete cache", "keys", m.keys) + log.ZDebug(ctx, "delete cache", "topic", m.topic, "keys", m.keys) for _, key := range m.keys { for i := 0; i < m.maxRetryTimes; i++ { if err := m.rcClient.TagAsDeleted(key); err != nil { @@ -71,31 +101,18 @@ func (m *metaCacheRedis) ExecDel(ctx context.Context, distinct ...bool) error { } break } - - //retryTimes := 0 - //for { - // m.rcClient.TagAsDeleted() - // if err := m.rcClient.TagAsDeletedBatch2(ctx, []string{key}); err != nil { - // if retryTimes >= m.maxRetryTimes { - // err = errs.ErrInternalServer.Wrap( - // fmt.Sprintf( - // "delete cache error: %v, keys: %v, retry times %d, please check redis server", - // err, - // key, - // retryTimes, - // ), - // ) - // log.ZWarn(ctx, "delete cache failed, please handle keys", err, "keys", key) - // return err - // } - // retryTimes++ - // } else { - // break - // } - //} + } + if pk := getPublishKey(m.topic, m.keys); len(pk) > 0 { + data, err := json.Marshal(pk) + if err != nil { + log.ZError(ctx, "keys json marshal failed", err, "topic", m.topic, "keys", pk) + } else { + if err := m.redisClient.Publish(ctx, m.topic, string(data)).Err(); err != nil { + log.ZError(ctx, "redis publish cache delete error", err, "topic", m.topic, "keys", pk) + } + } } } - return nil } diff --git a/pkg/common/db/cache/msg.go b/pkg/common/db/cache/msg.go index 9b488c1bfd..eb79fdb704 100644 --- a/pkg/common/db/cache/msg.go +++ b/pkg/common/db/cache/msg.go @@ -38,12 +38,12 @@ const ( conversationUserMinSeq = "CON_USER_MIN_SEQ:" hasReadSeq = "HAS_READ_SEQ:" - appleDeviceToken = "DEVICE_TOKEN" - getuiToken = "GETUI_TOKEN" - getuiTaskID = "GETUI_TASK_ID" - signalCache = "SIGNAL_CACHE:" - signalListCache = "SIGNAL_LIST_CACHE:" - FCM_TOKEN = "FCM_TOKEN:" + //appleDeviceToken = "DEVICE_TOKEN" + getuiToken = "GETUI_TOKEN" + getuiTaskID = "GETUI_TASK_ID" + //signalCache = "SIGNAL_CACHE:" + //signalListCache = "SIGNAL_LIST_CACHE:" + FCM_TOKEN = "FCM_TOKEN:" messageCache = "MESSAGE_CACHE:" messageDelUserList = "MESSAGE_DEL_USER_LIST:" @@ -143,6 +143,10 @@ func (c *msgCache) getHasReadSeqKey(conversationID string, userID string) string return hasReadSeq + userID + ":" + conversationID } +func (c *msgCache) getConversationUserMinSeqKey(conversationID, userID string) string { + return conversationUserMinSeq + conversationID + "u:" + userID +} + func (c *msgCache) setSeq(ctx context.Context, conversationID string, seq int64, getkey func(conversationID string) string) error { return errs.Wrap(c.rdb.Set(ctx, getkey(conversationID), seq, 0).Err()) } @@ -208,10 +212,6 @@ func (c *msgCache) GetMinSeq(ctx context.Context, conversationID string) (int64, return c.getSeq(ctx, conversationID, c.getMinSeqKey) } -func (c *msgCache) getConversationUserMinSeqKey(conversationID, userID string) string { - return conversationUserMinSeq + conversationID + "u:" + userID -} - func (c *msgCache) GetConversationUserMinSeq(ctx context.Context, conversationID string, userID string) (int64, error) { val, err := c.rdb.Get(ctx, c.getConversationUserMinSeqKey(conversationID, userID)).Int64() if err != nil { diff --git a/pkg/common/db/cache/user.go b/pkg/common/db/cache/user.go index 837e7a5bc1..c081731ce4 100644 --- a/pkg/common/db/cache/user.go +++ b/pkg/common/db/cache/user.go @@ -18,6 +18,8 @@ import ( "context" "encoding/json" "errors" + "github.com/openimsdk/open-im-server/v3/pkg/common/cachekey" + "github.com/openimsdk/open-im-server/v3/pkg/common/config" "hash/crc32" "strconv" "time" @@ -32,8 +34,8 @@ import ( ) const ( - userExpireTime = time.Second * 60 * 60 * 12 - userInfoKey = "USER_INFO:" + userExpireTime = time.Second * 60 * 60 * 12 + //userInfoKey = "USER_INFO:" userGlobalRecvMsgOptKey = "USER_GLOBAL_RECV_MSG_OPT_KEY:" olineStatusKey = "ONLINE_STATUS:" userOlineStatusExpireTime = time.Second * 60 * 60 * 24 @@ -68,7 +70,11 @@ func NewUserCacheRedis( options rockscache.Options, ) UserCache { rcClient := rockscache.NewClient(rdb, options) - + mc := NewMetaCacheRedis(rcClient) + u := config.Config.LocalCache.User + log.ZDebug(context.Background(), "user local cache init", "Topic", u.Topic, "SlotNum", u.SlotNum, "SlotSize", u.SlotSize, "enable", u.Enable()) + mc.SetTopic(u.Topic) + mc.SetRawRedisClient(rdb) return &UserCacheRedis{ rdb: rdb, metaCache: NewMetaCacheRedis(rcClient), @@ -81,7 +87,7 @@ func NewUserCacheRedis( func (u *UserCacheRedis) NewCache() UserCache { return &UserCacheRedis{ rdb: u.rdb, - metaCache: NewMetaCacheRedis(u.rcClient, u.metaCache.GetPreDelKeys()...), + metaCache: u.Copy(), userDB: u.userDB, expireTime: u.expireTime, rcClient: u.rcClient, @@ -89,18 +95,17 @@ func (u *UserCacheRedis) NewCache() UserCache { } func (u *UserCacheRedis) getUserInfoKey(userID string) string { - return userInfoKey + userID + return cachekey.GetUserInfoKey(userID) } func (u *UserCacheRedis) getUserGlobalRecvMsgOptKey(userID string) string { - return userGlobalRecvMsgOptKey + userID + return cachekey.GetUserGlobalRecvMsgOptKey(userID) } func (u *UserCacheRedis) GetUserInfo(ctx context.Context, userID string) (userInfo *relationtb.UserModel, err error) { return getCache(ctx, u.rcClient, u.getUserInfoKey(userID), u.expireTime, func(ctx context.Context) (*relationtb.UserModel, error) { return u.userDB.Take(ctx, userID) - }, - ) + }) } func (u *UserCacheRedis) GetUsersInfo(ctx context.Context, userIDs []string) ([]*relationtb.UserModel, error) { diff --git a/pkg/common/db/localcache/conversation.go b/pkg/common/db/localcache/conversation.go deleted file mode 100644 index 9147fd3ce0..0000000000 --- a/pkg/common/db/localcache/conversation.go +++ /dev/null @@ -1,86 +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 localcache - -import ( - "context" - "sync" - - "github.com/OpenIMSDK/protocol/conversation" - "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" -) - -type ConversationLocalCache struct { - lock sync.Mutex - superGroupRecvMsgNotNotifyUserIDs map[string]Hash - conversationIDs map[string]Hash - client *rpcclient.ConversationRpcClient -} - -type Hash struct { - hash uint64 - ids []string -} - -func NewConversationLocalCache(client *rpcclient.ConversationRpcClient) *ConversationLocalCache { - return &ConversationLocalCache{ - superGroupRecvMsgNotNotifyUserIDs: make(map[string]Hash), - conversationIDs: make(map[string]Hash), - client: client, - } -} - -func (g *ConversationLocalCache) GetRecvMsgNotNotifyUserIDs(ctx context.Context, groupID string) ([]string, error) { - resp, err := g.client.Client.GetRecvMsgNotNotifyUserIDs(ctx, &conversation.GetRecvMsgNotNotifyUserIDsReq{ - GroupID: groupID, - }) - if err != nil { - return nil, err - } - return resp.UserIDs, nil -} - -func (g *ConversationLocalCache) GetConversationIDs(ctx context.Context, userID string) ([]string, error) { - resp, err := g.client.Client.GetUserConversationIDsHash(ctx, &conversation.GetUserConversationIDsHashReq{ - OwnerUserID: userID, - }) - if err != nil { - return nil, err - } - - g.lock.Lock() - hash, ok := g.conversationIDs[userID] - g.lock.Unlock() - - if !ok || hash.hash != resp.Hash { - conversationIDsResp, err := g.client.Client.GetConversationIDs(ctx, &conversation.GetConversationIDsReq{ - UserID: userID, - }) - if err != nil { - return nil, err - } - - g.lock.Lock() - defer g.lock.Unlock() - g.conversationIDs[userID] = Hash{ - hash: resp.Hash, - ids: conversationIDsResp.ConversationIDs, - } - - return conversationIDsResp.ConversationIDs, nil - } - - return hash.ids, nil -} diff --git a/pkg/common/db/localcache/doc.go b/pkg/common/db/localcache/doc.go deleted file mode 100644 index d349373eee..0000000000 --- a/pkg/common/db/localcache/doc.go +++ /dev/null @@ -1,15 +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 localcache // import "github.com/openimsdk/open-im-server/v3/pkg/common/db/localcache" diff --git a/pkg/common/db/localcache/group.go b/pkg/common/db/localcache/group.go deleted file mode 100644 index 0fdea86424..0000000000 --- a/pkg/common/db/localcache/group.go +++ /dev/null @@ -1,77 +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 localcache - -import ( - "context" - "sync" - - "github.com/OpenIMSDK/protocol/group" - "github.com/OpenIMSDK/tools/errs" - "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" -) - -type GroupLocalCache struct { - lock sync.Mutex - cache map[string]GroupMemberIDsHash - client *rpcclient.GroupRpcClient -} - -type GroupMemberIDsHash struct { - memberListHash uint64 - userIDs []string -} - -func NewGroupLocalCache(client *rpcclient.GroupRpcClient) *GroupLocalCache { - return &GroupLocalCache{ - cache: make(map[string]GroupMemberIDsHash, 0), - client: client, - } -} - -func (g *GroupLocalCache) GetGroupMemberIDs(ctx context.Context, groupID string) ([]string, error) { - resp, err := g.client.Client.GetGroupAbstractInfo(ctx, &group.GetGroupAbstractInfoReq{ - GroupIDs: []string{groupID}, - }) - if err != nil { - return nil, err - } - if len(resp.GroupAbstractInfos) < 1 { - return nil, errs.ErrGroupIDNotFound - } - - g.lock.Lock() - localHashInfo, ok := g.cache[groupID] - if ok && localHashInfo.memberListHash == resp.GroupAbstractInfos[0].GroupMemberListHash { - g.lock.Unlock() - return localHashInfo.userIDs, nil - } - g.lock.Unlock() - - groupMembersResp, err := g.client.Client.GetGroupMemberUserIDs(ctx, &group.GetGroupMemberUserIDsReq{ - GroupID: groupID, - }) - if err != nil { - return nil, err - } - - g.lock.Lock() - defer g.lock.Unlock() - g.cache[groupID] = GroupMemberIDsHash{ - memberListHash: resp.GroupAbstractInfos[0].GroupMemberListHash, - userIDs: groupMembersResp.UserIDs, - } - return g.cache[groupID].userIDs, nil -} diff --git a/pkg/common/db/localcache/meta_local_cache.go b/pkg/common/db/localcache/meta_local_cache.go deleted file mode 100644 index ed9389c27f..0000000000 --- a/pkg/common/db/localcache/meta_local_cache.go +++ /dev/null @@ -1,15 +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 localcache diff --git a/pkg/common/db/mgo/conversation.go b/pkg/common/db/mgo/conversation.go index 35e8a28e6a..bc37ed7591 100644 --- a/pkg/common/db/mgo/conversation.go +++ b/pkg/common/db/mgo/conversation.go @@ -96,8 +96,14 @@ func (c *ConversationMgo) FindUserIDAllConversations(ctx context.Context, userID return mgoutil.Find[*relation.ConversationModel](ctx, c.coll, bson.M{"owner_user_id": userID}) } -func (c *ConversationMgo) FindRecvMsgNotNotifyUserIDs(ctx context.Context, groupID string) ([]string, error) { - return mgoutil.Find[string](ctx, c.coll, bson.M{"group_id": groupID, "recv_msg_opt": constant.ReceiveNotNotifyMessage}, options.Find().SetProjection(bson.M{"_id": 0, "owner_user_id": 1})) +func (c *ConversationMgo) FindRecvMsgUserIDs(ctx context.Context, conversationID string, recvOpts []int) ([]string, error) { + var filter any + if len(recvOpts) == 0 { + filter = bson.M{"conversation_id": conversationID} + } else { + filter = bson.M{"conversation_id": conversationID, "recv_msg_opt": bson.M{"$in": recvOpts}} + } + return mgoutil.Find[string](ctx, c.coll, filter, options.Find().SetProjection(bson.M{"_id": 0, "owner_user_id": 1})) } func (c *ConversationMgo) GetUserRecvMsgOpt(ctx context.Context, ownerUserID, conversationID string) (opt int, err error) { diff --git a/pkg/common/db/table/relation/conversation.go b/pkg/common/db/table/relation/conversation.go index e0a5268caa..583e41c0f2 100644 --- a/pkg/common/db/table/relation/conversation.go +++ b/pkg/common/db/table/relation/conversation.go @@ -53,7 +53,7 @@ type ConversationModelInterface interface { Take(ctx context.Context, userID, conversationID string) (conversation *ConversationModel, err error) FindConversationID(ctx context.Context, userID string, conversationIDs []string) (existConversationID []string, err error) FindUserIDAllConversations(ctx context.Context, userID string) (conversations []*ConversationModel, err error) - FindRecvMsgNotNotifyUserIDs(ctx context.Context, groupID string) ([]string, error) + FindRecvMsgUserIDs(ctx context.Context, conversationID string, recvOpts []int) ([]string, error) GetUserRecvMsgOpt(ctx context.Context, ownerUserID, conversationID string) (opt int, err error) GetAllConversationIDs(ctx context.Context) ([]string, error) GetAllConversationIDsNumber(ctx context.Context) (int64, error) diff --git a/pkg/common/redispubsub/redispubliser.go b/pkg/common/redispubsub/redispubliser.go new file mode 100644 index 0000000000..822b25bf9d --- /dev/null +++ b/pkg/common/redispubsub/redispubliser.go @@ -0,0 +1,16 @@ +package redispubsub + +import "github.com/redis/go-redis/v9" + +type Publisher struct { + client redis.UniversalClient + channel string +} + +func NewPublisher(client redis.UniversalClient, channel string) *Publisher { + return &Publisher{client: client, channel: channel} +} + +func (p *Publisher) Publish(message string) error { + return p.client.Publish(ctx, p.channel, message).Err() +} diff --git a/pkg/common/redispubsub/redissubscriber.go b/pkg/common/redispubsub/redissubscriber.go new file mode 100644 index 0000000000..a7029a9932 --- /dev/null +++ b/pkg/common/redispubsub/redissubscriber.go @@ -0,0 +1,34 @@ +package redispubsub + +import ( + "context" + "github.com/redis/go-redis/v9" +) + +var ctx = context.Background() + +type Subscriber struct { + client redis.UniversalClient + channel string +} + +func NewSubscriber(client redis.UniversalClient, channel string) *Subscriber { + return &Subscriber{client: client, channel: channel} +} + +func (s *Subscriber) OnMessage(ctx context.Context, callback func(string)) error { + messageChannel := s.client.Subscribe(ctx, s.channel).Channel() + + go func() { + for { + select { + case <-ctx.Done(): + return + case msg := <-messageChannel: + callback(msg.Payload) + } + } + }() + + return nil +} diff --git a/pkg/localcache/cache.go b/pkg/localcache/cache.go new file mode 100644 index 0000000000..4b405b46ac --- /dev/null +++ b/pkg/localcache/cache.go @@ -0,0 +1,112 @@ +package localcache + +import ( + "context" + "github.com/openimsdk/localcache/link" + "github.com/openimsdk/localcache/lru" + "hash/fnv" + "unsafe" +) + +type Cache[V any] interface { + Get(ctx context.Context, key string, fetch func(ctx context.Context) (V, error)) (V, error) + GetLink(ctx context.Context, key string, fetch func(ctx context.Context) (V, error), link ...string) (V, error) + Del(ctx context.Context, key ...string) + DelLocal(ctx context.Context, key ...string) + Stop() +} + +func New[V any](opts ...Option) Cache[V] { + opt := defaultOption() + for _, o := range opts { + o(opt) + } + + c := cache[V]{opt: opt} + if opt.localSlotNum > 0 && opt.localSlotSize > 0 { + createSimpleLRU := func() lru.LRU[string, V] { + if opt.expirationEvict { + return lru.NewExpirationLRU[string, V](opt.localSlotSize, opt.localSuccessTTL, opt.localFailedTTL, opt.target, c.onEvict) + } else { + return lru.NewLayLRU[string, V](opt.localSlotSize, opt.localSuccessTTL, opt.localFailedTTL, opt.target, c.onEvict) + } + } + if opt.localSlotNum == 1 { + c.local = createSimpleLRU() + } else { + c.local = lru.NewSlotLRU[string, V](opt.localSlotNum, func(key string) uint64 { + h := fnv.New64a() + h.Write(*(*[]byte)(unsafe.Pointer(&key))) + return h.Sum64() + }, createSimpleLRU) + } + if opt.linkSlotNum > 0 { + c.link = link.New(opt.linkSlotNum) + } + } + return &c +} + +type cache[V any] struct { + opt *option + link link.Link + local lru.LRU[string, V] +} + +func (c *cache[V]) onEvict(key string, value V) { + if c.link != nil { + lks := c.link.Del(key) + for k := range lks { + if key != k { // prevent deadlock + c.local.Del(k) + } + } + } +} + +func (c *cache[V]) del(key ...string) { + if c.local == nil { + return + } + for _, k := range key { + c.local.Del(k) + if c.link != nil { + lks := c.link.Del(k) + for k := range lks { + c.local.Del(k) + } + } + } +} + +func (c *cache[V]) Get(ctx context.Context, key string, fetch func(ctx context.Context) (V, error)) (V, error) { + return c.GetLink(ctx, key, fetch) +} + +func (c *cache[V]) GetLink(ctx context.Context, key string, fetch func(ctx context.Context) (V, error), link ...string) (V, error) { + if c.local != nil { + return c.local.Get(key, func() (V, error) { + if len(link) > 0 { + c.link.Link(key, link...) + } + return fetch(ctx) + }) + } else { + return fetch(ctx) + } +} + +func (c *cache[V]) Del(ctx context.Context, key ...string) { + for _, fn := range c.opt.delFn { + fn(ctx, key...) + } + c.del(key...) +} + +func (c *cache[V]) DelLocal(ctx context.Context, key ...string) { + c.del(key...) +} + +func (c *cache[V]) Stop() { + c.local.Stop() +} diff --git a/pkg/localcache/cache_test.go b/pkg/localcache/cache_test.go new file mode 100644 index 0000000000..c497b7b4ab --- /dev/null +++ b/pkg/localcache/cache_test.go @@ -0,0 +1,79 @@ +package localcache + +import ( + "context" + "fmt" + "math/rand" + "sync" + "sync/atomic" + "testing" + "time" +) + +func TestName(t *testing.T) { + c := New[string](WithExpirationEvict()) + //c := New[string]() + ctx := context.Background() + + const ( + num = 10000 + tNum = 10000 + kNum = 100000 + pNum = 100 + ) + + getKey := func(v uint64) string { + return fmt.Sprintf("key_%d", v%kNum) + } + + start := time.Now() + t.Log("start", start) + + var ( + get atomic.Int64 + del atomic.Int64 + ) + + incrGet := func() { + if v := get.Add(1); v%pNum == 0 { + //t.Log("#get count", v/pNum) + } + } + incrDel := func() { + if v := del.Add(1); v%pNum == 0 { + //t.Log("@del count", v/pNum) + } + } + + var wg sync.WaitGroup + + for i := 0; i < tNum; i++ { + wg.Add(2) + go func() { + defer wg.Done() + for i := 0; i < num; i++ { + c.Get(ctx, getKey(rand.Uint64()), func(ctx context.Context) (string, error) { + return fmt.Sprintf("index_%d", i), nil + }) + incrGet() + } + }() + + go func() { + defer wg.Done() + time.Sleep(time.Second / 10) + for i := 0; i < num; i++ { + c.Del(ctx, getKey(rand.Uint64())) + incrDel() + } + }() + } + + wg.Wait() + end := time.Now() + t.Log("end", end) + t.Log("time", end.Sub(start)) + t.Log("get", get.Load()) + t.Log("del", del.Load()) + // 137.35s +} diff --git a/pkg/localcache/go.mod b/pkg/localcache/go.mod new file mode 100644 index 0000000000..5f0793042e --- /dev/null +++ b/pkg/localcache/go.mod @@ -0,0 +1,5 @@ +module github.com/openimsdk/localcache + +go 1.19 + +require github.com/hashicorp/golang-lru/v2 v2.0.7 diff --git a/pkg/localcache/link/link.go b/pkg/localcache/link/link.go new file mode 100644 index 0000000000..4f238907b9 --- /dev/null +++ b/pkg/localcache/link/link.go @@ -0,0 +1,109 @@ +package link + +import ( + "hash/fnv" + "sync" + "unsafe" +) + +type Link interface { + Link(key string, link ...string) + Del(key string) map[string]struct{} +} + +func newLinkKey() *linkKey { + return &linkKey{ + data: make(map[string]map[string]struct{}), + } +} + +type linkKey struct { + lock sync.Mutex + data map[string]map[string]struct{} +} + +func (x *linkKey) link(key string, link ...string) { + x.lock.Lock() + defer x.lock.Unlock() + v, ok := x.data[key] + if !ok { + v = make(map[string]struct{}) + x.data[key] = v + } + for _, k := range link { + v[k] = struct{}{} + } +} + +func (x *linkKey) del(key string) map[string]struct{} { + x.lock.Lock() + defer x.lock.Unlock() + ks, ok := x.data[key] + if !ok { + return nil + } + delete(x.data, key) + return ks +} + +func New(n int) Link { + if n <= 0 { + panic("must be greater than 0") + } + slots := make([]*linkKey, n) + for i := 0; i < len(slots); i++ { + slots[i] = newLinkKey() + } + return &slot{ + n: uint64(n), + slots: slots, + } +} + +type slot struct { + n uint64 + slots []*linkKey +} + +func (x *slot) index(s string) uint64 { + h := fnv.New64a() + _, _ = h.Write(*(*[]byte)(unsafe.Pointer(&s))) + return h.Sum64() % x.n +} + +func (x *slot) Link(key string, link ...string) { + if len(link) == 0 { + return + } + mk := key + lks := make([]string, len(link)) + for i, k := range link { + lks[i] = k + } + x.slots[x.index(mk)].link(mk, lks...) + for _, lk := range lks { + x.slots[x.index(lk)].link(lk, mk) + } +} + +func (x *slot) Del(key string) map[string]struct{} { + return x.delKey(key) +} + +func (x *slot) delKey(k string) map[string]struct{} { + del := make(map[string]struct{}) + stack := []string{k} + for len(stack) > 0 { + curr := stack[len(stack)-1] + stack = stack[:len(stack)-1] + if _, ok := del[curr]; ok { + continue + } + del[curr] = struct{}{} + childKeys := x.slots[x.index(curr)].del(curr) + for ck := range childKeys { + stack = append(stack, ck) + } + } + return del +} diff --git a/pkg/localcache/link/link_test.go b/pkg/localcache/link/link_test.go new file mode 100644 index 0000000000..ed684e6939 --- /dev/null +++ b/pkg/localcache/link/link_test.go @@ -0,0 +1,20 @@ +package link + +import ( + "testing" +) + +func TestName(t *testing.T) { + + v := New(1) + + //v.Link("a:1", "b:1", "c:1", "d:1") + v.Link("a:1", "b:1", "c:1") + v.Link("z:1", "b:1") + + //v.DelKey("a:1") + v.Del("z:1") + + t.Log(v) + +} diff --git a/pkg/localcache/lru/lru.go b/pkg/localcache/lru/lru.go new file mode 100644 index 0000000000..2995ec028d --- /dev/null +++ b/pkg/localcache/lru/lru.go @@ -0,0 +1,20 @@ +package lru + +import "github.com/hashicorp/golang-lru/v2/simplelru" + +type EvictCallback[K comparable, V any] simplelru.EvictCallback[K, V] + +type LRU[K comparable, V any] interface { + Get(key K, fetch func() (V, error)) (V, error) + Del(key K) bool + Stop() +} + +type Target interface { + IncrGetHit() + IncrGetSuccess() + IncrGetFailed() + + IncrDelHit() + IncrDelNotFound() +} diff --git a/pkg/localcache/lru/lru_expiration.go b/pkg/localcache/lru/lru_expiration.go new file mode 100644 index 0000000000..3cf61f0616 --- /dev/null +++ b/pkg/localcache/lru/lru_expiration.go @@ -0,0 +1,78 @@ +package lru + +import ( + "github.com/hashicorp/golang-lru/v2/expirable" + "sync" + "time" +) + +func NewExpirationLRU[K comparable, V any](size int, successTTL, failedTTL time.Duration, target Target, onEvict EvictCallback[K, V]) LRU[K, V] { + var cb expirable.EvictCallback[K, *expirationLruItem[V]] + if onEvict != nil { + cb = func(key K, value *expirationLruItem[V]) { + onEvict(key, value.value) + } + } + core := expirable.NewLRU[K, *expirationLruItem[V]](size, cb, successTTL) + return &ExpirationLRU[K, V]{ + core: core, + successTTL: successTTL, + failedTTL: failedTTL, + target: target, + } +} + +type expirationLruItem[V any] struct { + lock sync.RWMutex + err error + value V +} + +type ExpirationLRU[K comparable, V any] struct { + lock sync.Mutex + core *expirable.LRU[K, *expirationLruItem[V]] + successTTL time.Duration + failedTTL time.Duration + target Target +} + +func (x *ExpirationLRU[K, V]) Get(key K, fetch func() (V, error)) (V, error) { + x.lock.Lock() + v, ok := x.core.Get(key) + if ok { + x.lock.Unlock() + x.target.IncrGetSuccess() + v.lock.RLock() + defer v.lock.RUnlock() + return v.value, v.err + } else { + v = &expirationLruItem[V]{} + x.core.Add(key, v) + v.lock.Lock() + x.lock.Unlock() + defer v.lock.Unlock() + v.value, v.err = fetch() + if v.err == nil { + x.target.IncrGetSuccess() + } else { + x.target.IncrGetFailed() + x.core.Remove(key) + } + return v.value, v.err + } +} + +func (x *ExpirationLRU[K, V]) Del(key K) bool { + x.lock.Lock() + ok := x.core.Remove(key) + x.lock.Unlock() + if ok { + x.target.IncrDelHit() + } else { + x.target.IncrDelNotFound() + } + return ok +} + +func (x *ExpirationLRU[K, V]) Stop() { +} diff --git a/pkg/localcache/lru/lru_lazy.go b/pkg/localcache/lru/lru_lazy.go new file mode 100644 index 0000000000..a9270ea4a8 --- /dev/null +++ b/pkg/localcache/lru/lru_lazy.go @@ -0,0 +1,90 @@ +package lru + +import ( + "github.com/hashicorp/golang-lru/v2/simplelru" + "sync" + "time" +) + +type layLruItem[V any] struct { + lock sync.Mutex + expires int64 + err error + value V +} + +func NewLayLRU[K comparable, V any](size int, successTTL, failedTTL time.Duration, target Target, onEvict EvictCallback[K, V]) *LayLRU[K, V] { + var cb simplelru.EvictCallback[K, *layLruItem[V]] + if onEvict != nil { + cb = func(key K, value *layLruItem[V]) { + onEvict(key, value.value) + } + } + core, err := simplelru.NewLRU[K, *layLruItem[V]](size, cb) + if err != nil { + panic(err) + } + return &LayLRU[K, V]{ + core: core, + successTTL: successTTL, + failedTTL: failedTTL, + target: target, + } +} + +type LayLRU[K comparable, V any] struct { + lock sync.Mutex + core *simplelru.LRU[K, *layLruItem[V]] + successTTL time.Duration + failedTTL time.Duration + target Target +} + +func (x *LayLRU[K, V]) Get(key K, fetch func() (V, error)) (V, error) { + x.lock.Lock() + v, ok := x.core.Get(key) + if ok { + x.lock.Unlock() + v.lock.Lock() + expires, value, err := v.expires, v.value, v.err + if expires != 0 && expires > time.Now().UnixMilli() { + v.lock.Unlock() + x.target.IncrGetHit() + return value, err + } + } else { + v = &layLruItem[V]{} + x.core.Add(key, v) + v.lock.Lock() + x.lock.Unlock() + } + defer v.lock.Unlock() + if v.expires > time.Now().UnixMilli() { + return v.value, v.err + } + v.value, v.err = fetch() + if v.err == nil { + v.expires = time.Now().Add(x.successTTL).UnixMilli() + x.target.IncrGetSuccess() + } else { + v.expires = time.Now().Add(x.failedTTL).UnixMilli() + x.target.IncrGetFailed() + } + return v.value, v.err +} + +func (x *LayLRU[K, V]) Del(key K) bool { + x.lock.Lock() + ok := x.core.Remove(key) + x.lock.Unlock() + if ok { + x.target.IncrDelHit() + } else { + x.target.IncrDelNotFound() + } + return ok +} + +func (x *LayLRU[K, V]) Stop() { + +} diff --git a/pkg/localcache/lru/lru_lazy_test.go b/pkg/localcache/lru/lru_lazy_test.go new file mode 100644 index 0000000000..09fd04cd3b --- /dev/null +++ b/pkg/localcache/lru/lru_lazy_test.go @@ -0,0 +1,104 @@ +package lru + +import ( + "fmt" + "hash/fnv" + "sync" + "sync/atomic" + "testing" + "time" + "unsafe" +) + +type cacheTarget struct { + getHit int64 + getSuccess int64 + getFailed int64 + delHit int64 + delNotFound int64 +} + +func (r *cacheTarget) IncrGetHit() { + atomic.AddInt64(&r.getHit, 1) +} + +func (r *cacheTarget) IncrGetSuccess() { + atomic.AddInt64(&r.getSuccess, 1) +} + +func (r *cacheTarget) IncrGetFailed() { + atomic.AddInt64(&r.getFailed, 1) +} + +func (r *cacheTarget) IncrDelHit() { + atomic.AddInt64(&r.delHit, 1) +} + +func (r *cacheTarget) IncrDelNotFound() { + atomic.AddInt64(&r.delNotFound, 1) +} + +func (r *cacheTarget) String() string { + return fmt.Sprintf("getHit: %d, getSuccess: %d, getFailed: %d, delHit: %d, delNotFound: %d", r.getHit, r.getSuccess, r.getFailed, r.delHit, r.delNotFound) +} + +func TestName(t *testing.T) { + target := &cacheTarget{} + l := NewSlotLRU[string, string](100, func(k string) uint64 { + h := fnv.New64a() + h.Write(*(*[]byte)(unsafe.Pointer(&k))) + return h.Sum64() + }, func() LRU[string, string] { + return NewExpirationLRU[string, string](100, time.Second*60, time.Second, target, nil) + }) + //l := NewInertiaLRU[string, string](1000, time.Second*20, time.Second*5, target) + + fn := func(key string, n int, fetch func() (string, error)) { + for i := 0; i < n; i++ { + //v, err := l.Get(key, fetch) + //if err == nil { + // t.Log("key", key, "value", v) + //} else { + // t.Error("key", key, err) + //} + v, err := l.Get(key, fetch) + //time.Sleep(time.Second / 100) + func(v ...any) {}(v, err) + } + } + + tmp := make(map[string]struct{}) + + var wg sync.WaitGroup + for i := 0; i < 10000; i++ { + wg.Add(1) + key := fmt.Sprintf("key_%d", i%200) + tmp[key] = struct{}{} + go func() { + defer wg.Done() + //t.Log(key) + fn(key, 10000, func() (string, error) { + //time.Sleep(time.Second * 3) + //t.Log(time.Now(), "key", key, "fetch") + //if rand.Uint32()%5 == 0 { + // return "value_" + key, nil + //} + //return "", errors.New("rand error") + return "value_" + key, nil + }) + }() + + //wg.Add(1) + //go func() { + // defer wg.Done() + // for i := 0; i < 10; i++ { + // l.Del(key) + // time.Sleep(time.Second / 3) + // } + //}() + } + wg.Wait() + t.Log(len(tmp)) + t.Log(target.String()) + +} diff --git a/pkg/localcache/lru/lru_slot.go b/pkg/localcache/lru/lru_slot.go new file mode 100644 index 0000000000..c1b8b94d07 --- /dev/null +++ b/pkg/localcache/lru/lru_slot.go @@ -0,0 +1,37 @@ +package lru + +func NewSlotLRU[K comparable, V any](slotNum int, hash func(K) uint64, create func() LRU[K, V]) LRU[K, V] { + x := &slotLRU[K, V]{ + n: uint64(slotNum), + slots: make([]LRU[K, V], slotNum), + hash: hash, + } + for i := 0; i < slotNum; i++ { + x.slots[i] = create() + } + return x +} + +type slotLRU[K comparable, V any] struct { + n uint64 + slots []LRU[K, V] + hash func(k K) uint64 +} + +func (x *slotLRU[K, V]) getIndex(k K) uint64 { + return x.hash(k) % x.n +} + +func (x *slotLRU[K, V]) Get(key K, fetch func() (V, error)) (V, error) { + return x.slots[x.getIndex(key)].Get(key, fetch) +} + +func (x *slotLRU[K, V]) Del(key K) bool { + return x.slots[x.getIndex(key)].Del(key) +} + +func (x *slotLRU[K, V]) Stop() { + for _, slot := range x.slots { + slot.Stop() + } +} diff --git a/pkg/localcache/option.go b/pkg/localcache/option.go new file mode 100644 index 0000000000..ecb5da0e63 --- /dev/null +++ b/pkg/localcache/option.go @@ -0,0 +1,121 @@ +package localcache + +import ( + "context" + "github.com/openimsdk/localcache/lru" + "time" +) + +func defaultOption() *option { + return &option{ + localSlotNum: 500, + localSlotSize: 20000, + linkSlotNum: 500, + expirationEvict: false, + localSuccessTTL: time.Minute, + localFailedTTL: time.Second * 5, + delFn: make([]func(ctx context.Context, key ...string), 0, 2), + target: emptyTarget{}, + } +} + +type option struct { + localSlotNum int + localSlotSize int + linkSlotNum int + // expirationEvict: true means that the cache will be actively cleared when the timer expires, + // false means that the cache will be lazily deleted. + expirationEvict bool + localSuccessTTL time.Duration + localFailedTTL time.Duration + delFn []func(ctx context.Context, key ...string) + target lru.Target +} + +type Option func(o *option) + +func WithExpirationEvict() Option { + return func(o *option) { + o.expirationEvict = true + } +} + +func WithLazy() Option { + return func(o *option) { + o.expirationEvict = false + } +} + +func WithLocalDisable() Option { + return WithLinkSlotNum(0) +} + +func WithLinkDisable() Option { + return WithLinkSlotNum(0) +} + +func WithLinkSlotNum(linkSlotNum int) Option { + return func(o *option) { + o.linkSlotNum = linkSlotNum + } +} + +func WithLocalSlotNum(localSlotNum int) Option { + return func(o *option) { + o.localSlotNum = localSlotNum + } +} + +func WithLocalSlotSize(localSlotSize int) Option { + return func(o *option) { + o.localSlotSize = localSlotSize + } +} + +func WithLocalSuccessTTL(localSuccessTTL time.Duration) Option { + if localSuccessTTL < 0 { + panic("localSuccessTTL should be greater than 0") + } + return func(o *option) { + o.localSuccessTTL = localSuccessTTL + } +} + +func WithLocalFailedTTL(localFailedTTL time.Duration) Option { + if localFailedTTL < 0 { + panic("localFailedTTL should be greater than 0") + } + return func(o *option) { + o.localFailedTTL = localFailedTTL + } +} + +func WithTarget(target lru.Target) Option { + if target == nil { + panic("target should not be nil") + } + return func(o *option) { + o.target = target + } +} + +func WithDeleteKeyBefore(fn func(ctx context.Context, key ...string)) Option { + if fn == nil { + panic("fn should not be nil") + } + return func(o *option) { + o.delFn = append(o.delFn, fn) + } +} + +type emptyTarget struct{} + +func (e emptyTarget) IncrGetHit() {} + +func (e emptyTarget) IncrGetSuccess() {} + +func (e emptyTarget) IncrGetFailed() {} + +func (e emptyTarget) IncrDelHit() {} + +func (e emptyTarget) IncrDelNotFound() {} diff --git a/pkg/localcache/tool.go b/pkg/localcache/tool.go new file mode 100644 index 0000000000..ea35908233 --- /dev/null +++ b/pkg/localcache/tool.go @@ -0,0 +1,9 @@ +package localcache + +func AnyValue[V any](v any, err error) (V, error) { + if err != nil { + var zero V + return zero, err + } + return v.(V), nil +} diff --git a/pkg/rpccache/common.go b/pkg/rpccache/common.go new file mode 100644 index 0000000000..6dc826e305 --- /dev/null +++ b/pkg/rpccache/common.go @@ -0,0 +1,20 @@ +package rpccache + +func newListMap[V comparable](values []V, err error) (*listMap[V], error) { + if err != nil { + return nil, err + } + lm := &listMap[V]{ + List: values, + Map: make(map[V]struct{}, len(values)), + } + for _, value := range values { + lm.Map[value] = struct{}{} + } + return lm, nil +} + +type listMap[V comparable] struct { + List []V + Map map[V]struct{} +} diff --git a/pkg/rpccache/conversation.go b/pkg/rpccache/conversation.go new file mode 100644 index 0000000000..ae77b29b70 --- /dev/null +++ b/pkg/rpccache/conversation.go @@ -0,0 +1,112 @@ +package rpccache + +import ( + "context" + pbconversation "github.com/OpenIMSDK/protocol/conversation" + "github.com/OpenIMSDK/tools/errs" + "github.com/OpenIMSDK/tools/log" + "github.com/openimsdk/localcache" + "github.com/openimsdk/open-im-server/v3/pkg/common/cachekey" + "github.com/openimsdk/open-im-server/v3/pkg/common/config" + "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" + "github.com/redis/go-redis/v9" +) + +func NewConversationLocalCache(client rpcclient.ConversationRpcClient, cli redis.UniversalClient) *ConversationLocalCache { + lc := config.Config.LocalCache.Conversation + log.ZDebug(context.Background(), "ConversationLocalCache", "topic", lc.Topic, "slotNum", lc.SlotNum, "slotSize", lc.SlotSize, "enable", lc.Enable()) + x := &ConversationLocalCache{ + client: client, + local: localcache.New[any]( + localcache.WithLocalSlotNum(lc.SlotNum), + localcache.WithLocalSlotSize(lc.SlotSize), + localcache.WithLinkSlotNum(lc.SlotNum), + localcache.WithLocalSuccessTTL(lc.Success()), + localcache.WithLocalFailedTTL(lc.Failed()), + ), + } + if lc.Enable() { + go subscriberRedisDeleteCache(context.Background(), cli, lc.Topic, x.local.DelLocal) + } + return x +} + +type ConversationLocalCache struct { + client rpcclient.ConversationRpcClient + local localcache.Cache[any] +} + +func (c *ConversationLocalCache) GetConversationIDs(ctx context.Context, ownerUserID string) (val []string, err error) { + log.ZDebug(ctx, "ConversationLocalCache GetConversationIDs req", "ownerUserID", ownerUserID) + defer func() { + if err == nil { + log.ZDebug(ctx, "ConversationLocalCache GetConversationIDs return", "value", val) + } else { + log.ZError(ctx, "ConversationLocalCache GetConversationIDs return", err) + } + }() + return localcache.AnyValue[[]string](c.local.Get(ctx, cachekey.GetConversationIDsKey(ownerUserID), func(ctx context.Context) (any, error) { + log.ZDebug(ctx, "ConversationLocalCache GetConversationIDs rpc", "ownerUserID", ownerUserID) + return c.client.GetConversationIDs(ctx, ownerUserID) + })) +} + +func (c *ConversationLocalCache) GetConversation(ctx context.Context, userID, conversationID string) (val *pbconversation.Conversation, err error) { + log.ZDebug(ctx, "ConversationLocalCache GetConversation req", "userID", userID, "conversationID", conversationID) + defer func() { + if err == nil { + log.ZDebug(ctx, "ConversationLocalCache GetConversation return", "value", val) + } else { + log.ZError(ctx, "ConversationLocalCache GetConversation return", err) + } + }() + return localcache.AnyValue[*pbconversation.Conversation](c.local.Get(ctx, cachekey.GetConversationKey(userID, conversationID), func(ctx context.Context) (any, error) { + log.ZDebug(ctx, "ConversationLocalCache GetConversation rpc", "userID", userID, "conversationID", conversationID) + return c.client.GetConversation(ctx, userID, conversationID) + })) +} + +func (c *ConversationLocalCache) GetSingleConversationRecvMsgOpt(ctx context.Context, userID, conversationID string) (int32, error) { + conv, err := c.GetConversation(ctx, userID, conversationID) + if err != nil { + return 0, err + } + return conv.RecvMsgOpt, nil +} + +func (c *ConversationLocalCache) GetConversations(ctx context.Context, ownerUserID string, conversationIDs []string) ([]*pbconversation.Conversation, error) { + conversations := make([]*pbconversation.Conversation, 0, len(conversationIDs)) + for _, conversationID := range conversationIDs { + conversation, err := c.GetConversation(ctx, ownerUserID, conversationID) + if err != nil { + if errs.ErrRecordNotFound.Is(err) { + continue + } + return nil, err + } + conversations = append(conversations, conversation) + } + return conversations, nil +} + +func (c *ConversationLocalCache) getConversationNotReceiveMessageUserIDs(ctx context.Context, conversationID string) (*listMap[string], error) { + return localcache.AnyValue[*listMap[string]](c.local.Get(ctx, cachekey.GetConversationNotReceiveMessageUserIDsKey(conversationID), func(ctx context.Context) (any, error) { + return newListMap(c.client.GetConversationNotReceiveMessageUserIDs(ctx, conversationID)) + })) +} + +func (c *ConversationLocalCache) GetConversationNotReceiveMessageUserIDs(ctx context.Context, conversationID string) ([]string, error) { + res, err := c.getConversationNotReceiveMessageUserIDs(ctx, conversationID) + if err != nil { + return nil, err + } + return res.List, nil +} + +func (c *ConversationLocalCache) GetConversationNotReceiveMessageUserIDMap(ctx context.Context, conversationID string) (map[string]struct{}, error) { + res, err := c.getConversationNotReceiveMessageUserIDs(ctx, conversationID) + if err != nil { + return nil, err + } + return res.Map, nil +} diff --git a/pkg/rpccache/friend.go b/pkg/rpccache/friend.go new file mode 100644 index 0000000000..66694f6181 --- /dev/null +++ b/pkg/rpccache/friend.go @@ -0,0 +1,66 @@ +package rpccache + +import ( + "context" + "github.com/OpenIMSDK/tools/log" + "github.com/openimsdk/localcache" + "github.com/openimsdk/open-im-server/v3/pkg/common/cachekey" + "github.com/openimsdk/open-im-server/v3/pkg/common/config" + "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" + "github.com/redis/go-redis/v9" +) + +func NewFriendLocalCache(client rpcclient.FriendRpcClient, cli redis.UniversalClient) *FriendLocalCache { + lc := config.Config.LocalCache.Friend + log.ZDebug(context.Background(), "FriendLocalCache", "topic", lc.Topic, "slotNum", lc.SlotNum, "slotSize", lc.SlotSize, "enable", lc.Enable()) + x := &FriendLocalCache{ + client: client, + local: localcache.New[any]( + localcache.WithLocalSlotNum(lc.SlotNum), + localcache.WithLocalSlotSize(lc.SlotSize), + localcache.WithLinkSlotNum(lc.SlotNum), + localcache.WithLocalSuccessTTL(lc.Success()), + localcache.WithLocalFailedTTL(lc.Failed()), + ), + } + if lc.Enable() { + go subscriberRedisDeleteCache(context.Background(), cli, lc.Topic, x.local.DelLocal) + } + return x +} + +type FriendLocalCache struct { + client rpcclient.FriendRpcClient + local localcache.Cache[any] +} + +func (f *FriendLocalCache) IsFriend(ctx context.Context, possibleFriendUserID, userID string) (val bool, err error) { + log.ZDebug(ctx, "FriendLocalCache IsFriend req", "possibleFriendUserID", possibleFriendUserID, "userID", userID) + defer func() { + if err == nil { + log.ZDebug(ctx, "FriendLocalCache IsFriend return", "value", val) + } else { + log.ZError(ctx, "FriendLocalCache IsFriend return", err) + } + }() + return localcache.AnyValue[bool](f.local.GetLink(ctx, cachekey.GetIsFriendKey(possibleFriendUserID, userID), func(ctx context.Context) (any, error) { + log.ZDebug(ctx, "FriendLocalCache IsFriend rpc", "possibleFriendUserID", possibleFriendUserID, "userID", userID) + return f.client.IsFriend(ctx, possibleFriendUserID, userID) + }, cachekey.GetFriendIDsKey(possibleFriendUserID))) +} + +// IsBlack possibleBlackUserID selfUserID +func (f *FriendLocalCache) IsBlack(ctx context.Context, possibleBlackUserID, userID string) (val bool, err error) { + log.ZDebug(ctx, "FriendLocalCache IsBlack req", "possibleBlackUserID", possibleBlackUserID, "userID", userID) + defer func() { + if err == nil { + log.ZDebug(ctx, "FriendLocalCache IsBlack return", "value", val) + } else { + log.ZError(ctx, "FriendLocalCache IsBlack return", err) + } + }() + return localcache.AnyValue[bool](f.local.GetLink(ctx, cachekey.GetIsBlackIDsKey(possibleBlackUserID, userID), func(ctx context.Context) (any, error) { + log.ZDebug(ctx, "FriendLocalCache IsBlack rpc", "possibleBlackUserID", possibleBlackUserID, "userID", userID) + return f.client.IsBlack(ctx, possibleBlackUserID, userID) + }, cachekey.GetBlackIDsKey(userID))) +} diff --git a/pkg/rpccache/group.go b/pkg/rpccache/group.go new file mode 100644 index 0000000000..b3c666da4a --- /dev/null +++ b/pkg/rpccache/group.go @@ -0,0 +1,143 @@ +package rpccache + +import ( + "context" + "github.com/OpenIMSDK/protocol/sdkws" + "github.com/OpenIMSDK/tools/errs" + "github.com/OpenIMSDK/tools/log" + "github.com/openimsdk/localcache" + "github.com/openimsdk/open-im-server/v3/pkg/common/cachekey" + "github.com/openimsdk/open-im-server/v3/pkg/common/config" + "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" + "github.com/redis/go-redis/v9" +) + +func NewGroupLocalCache(client rpcclient.GroupRpcClient, cli redis.UniversalClient) *GroupLocalCache { + lc := config.Config.LocalCache.Group + log.ZDebug(context.Background(), "GroupLocalCache", "topic", lc.Topic, "slotNum", lc.SlotNum, "slotSize", lc.SlotSize, "enable", lc.Enable()) + x := &GroupLocalCache{ + client: client, + local: localcache.New[any]( + localcache.WithLocalSlotNum(lc.SlotNum), + localcache.WithLocalSlotSize(lc.SlotSize), + localcache.WithLinkSlotNum(lc.SlotNum), + localcache.WithLocalSuccessTTL(lc.Success()), + localcache.WithLocalFailedTTL(lc.Failed()), + ), + } + if lc.Enable() { + go subscriberRedisDeleteCache(context.Background(), cli, lc.Topic, x.local.DelLocal) + } + return x +} + +type GroupLocalCache struct { + client rpcclient.GroupRpcClient + local localcache.Cache[any] +} + +func (g *GroupLocalCache) getGroupMemberIDs(ctx context.Context, groupID string) (val *listMap[string], err error) { + log.ZDebug(ctx, "GroupLocalCache getGroupMemberIDs req", "groupID", groupID) + defer func() { + if err == nil { + log.ZDebug(ctx, "GroupLocalCache getGroupMemberIDs return", "value", val) + } else { + log.ZError(ctx, "GroupLocalCache getGroupMemberIDs return", err) + } + }() + return localcache.AnyValue[*listMap[string]](g.local.Get(ctx, cachekey.GetGroupMemberIDsKey(groupID), func(ctx context.Context) (any, error) { + log.ZDebug(ctx, "GroupLocalCache getGroupMemberIDs rpc", "groupID", groupID) + return newListMap(g.client.GetGroupMemberIDs(ctx, groupID)) + })) +} + +func (g *GroupLocalCache) GetGroupMember(ctx context.Context, groupID, userID string) (val *sdkws.GroupMemberFullInfo, err error) { + log.ZDebug(ctx, "GroupLocalCache GetGroupInfo req", "groupID", groupID, "userID", userID) + defer func() { + if err == nil { + log.ZDebug(ctx, "GroupLocalCache GetGroupInfo return", "value", val) + } else { + log.ZError(ctx, "GroupLocalCache GetGroupInfo return", err) + } + }() + return localcache.AnyValue[*sdkws.GroupMemberFullInfo](g.local.Get(ctx, cachekey.GetGroupMemberInfoKey(groupID, userID), func(ctx context.Context) (any, error) { + log.ZDebug(ctx, "GroupLocalCache GetGroupInfo rpc", "groupID", groupID, "userID", userID) + return g.client.GetGroupMemberCache(ctx, groupID, userID) + })) +} + +func (g *GroupLocalCache) GetGroupInfo(ctx context.Context, groupID string) (val *sdkws.GroupInfo, err error) { + log.ZDebug(ctx, "GroupLocalCache GetGroupInfo req", "groupID", groupID) + defer func() { + if err == nil { + log.ZDebug(ctx, "GroupLocalCache GetGroupInfo return", "value", val) + } else { + log.ZError(ctx, "GroupLocalCache GetGroupInfo return", err) + } + }() + return localcache.AnyValue[*sdkws.GroupInfo](g.local.Get(ctx, cachekey.GetGroupInfoKey(groupID), func(ctx context.Context) (any, error) { + log.ZDebug(ctx, "GroupLocalCache GetGroupInfo rpc", "groupID", groupID) + return g.client.GetGroupInfoCache(ctx, groupID) + })) +} + +func (g *GroupLocalCache) GetGroupMemberIDs(ctx context.Context, groupID string) ([]string, error) { + res, err := g.getGroupMemberIDs(ctx, groupID) + if err != nil { + return nil, err + } + return res.List, nil +} + +func (g *GroupLocalCache) GetGroupMemberIDMap(ctx context.Context, groupID string) (map[string]struct{}, error) { + res, err := g.getGroupMemberIDs(ctx, groupID) + if err != nil { + return nil, err + } + return res.Map, nil +} + +func (g *GroupLocalCache) GetGroupInfos(ctx context.Context, groupIDs []string) ([]*sdkws.GroupInfo, error) { + groupInfos := make([]*sdkws.GroupInfo, 0, len(groupIDs)) + for _, groupID := range groupIDs { + groupInfo, err := g.GetGroupInfo(ctx, groupID) + if err != nil { + if errs.ErrRecordNotFound.Is(err) { + continue + } + return nil, err + } + groupInfos = append(groupInfos, groupInfo) + } + return groupInfos, nil +} + +func (g *GroupLocalCache) GetGroupMembers(ctx context.Context, groupID string, userIDs []string) ([]*sdkws.GroupMemberFullInfo, error) { + members := make([]*sdkws.GroupMemberFullInfo, 0, len(userIDs)) + for _, userID := range userIDs { + member, err := g.GetGroupMember(ctx, groupID, userID) + if err != nil { + if errs.ErrRecordNotFound.Is(err) { + continue + } + return nil, err + } + members = append(members, member) + } + return members, nil +} + +func (g *GroupLocalCache) GetGroupMemberInfoMap(ctx context.Context, groupID string, userIDs []string) (map[string]*sdkws.GroupMemberFullInfo, error) { + members := make(map[string]*sdkws.GroupMemberFullInfo) + for _, userID := range userIDs { + member, err := g.GetGroupMember(ctx, groupID, userID) + if err != nil { + if errs.ErrRecordNotFound.Is(err) { + continue + } + return nil, err + } + members[userID] = member + } + return members, nil +} diff --git a/pkg/rpccache/subscriber.go b/pkg/rpccache/subscriber.go new file mode 100644 index 0000000000..571ff6d2db --- /dev/null +++ b/pkg/rpccache/subscriber.go @@ -0,0 +1,23 @@ +package rpccache + +import ( + "context" + "encoding/json" + "github.com/OpenIMSDK/tools/log" + "github.com/redis/go-redis/v9" +) + +func subscriberRedisDeleteCache(ctx context.Context, client redis.UniversalClient, channel string, del func(ctx context.Context, key ...string)) { + for message := range client.Subscribe(ctx, channel).Channel() { + log.ZDebug(ctx, "subscriberRedisDeleteCache", "channel", channel, "payload", message.Payload) + var keys []string + if err := json.Unmarshal([]byte(message.Payload), &keys); err != nil { + log.ZError(ctx, "subscriberRedisDeleteCache json.Unmarshal error", err) + continue + } + if len(keys) == 0 { + continue + } + del(ctx, keys...) + } +} diff --git a/pkg/rpccache/user.go b/pkg/rpccache/user.go new file mode 100644 index 0000000000..7d6cd5c7e3 --- /dev/null +++ b/pkg/rpccache/user.go @@ -0,0 +1,97 @@ +package rpccache + +import ( + "context" + "github.com/OpenIMSDK/protocol/sdkws" + "github.com/OpenIMSDK/tools/errs" + "github.com/OpenIMSDK/tools/log" + "github.com/openimsdk/localcache" + "github.com/openimsdk/open-im-server/v3/pkg/common/cachekey" + "github.com/openimsdk/open-im-server/v3/pkg/common/config" + "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" + "github.com/redis/go-redis/v9" +) + +func NewUserLocalCache(client rpcclient.UserRpcClient, cli redis.UniversalClient) *UserLocalCache { + lc := config.Config.LocalCache.User + log.ZDebug(context.Background(), "UserLocalCache", "topic", lc.Topic, "slotNum", lc.SlotNum, "slotSize", lc.SlotSize, "enable", lc.Enable()) + x := &UserLocalCache{ + client: client, + local: localcache.New[any]( + localcache.WithLocalSlotNum(lc.SlotNum), + localcache.WithLocalSlotSize(lc.SlotSize), + localcache.WithLinkSlotNum(lc.SlotNum), + localcache.WithLocalSuccessTTL(lc.Success()), + localcache.WithLocalFailedTTL(lc.Failed()), + ), + } + if lc.Enable() { + go subscriberRedisDeleteCache(context.Background(), cli, lc.Topic, x.local.DelLocal) + } + return x +} + +type UserLocalCache struct { + client rpcclient.UserRpcClient + local localcache.Cache[any] +} + +func (u *UserLocalCache) GetUserInfo(ctx context.Context, userID string) (val *sdkws.UserInfo, err error) { + log.ZDebug(ctx, "UserLocalCache GetUserInfo req", "userID", userID) + defer func() { + if err == nil { + log.ZDebug(ctx, "UserLocalCache GetUserInfo return", "value", val) + } else { + log.ZError(ctx, "UserLocalCache GetUserInfo return", err) + } + }() + return localcache.AnyValue[*sdkws.UserInfo](u.local.Get(ctx, cachekey.GetUserInfoKey(userID), func(ctx context.Context) (any, error) { + log.ZDebug(ctx, "UserLocalCache GetUserInfo rpc", "userID", userID) + return u.client.GetUserInfo(ctx, userID) + })) +} + +func (u *UserLocalCache) GetUserGlobalMsgRecvOpt(ctx context.Context, userID string) (val int32, err error) { + log.ZDebug(ctx, "UserLocalCache GetUserGlobalMsgRecvOpt req", "userID", userID) + defer func() { + if err == nil { + log.ZDebug(ctx, "UserLocalCache GetUserGlobalMsgRecvOpt return", "value", val) + } else { + log.ZError(ctx, "UserLocalCache GetUserGlobalMsgRecvOpt return", err) + } + }() + return localcache.AnyValue[int32](u.local.Get(ctx, cachekey.GetUserGlobalRecvMsgOptKey(userID), func(ctx context.Context) (any, error) { + log.ZDebug(ctx, "UserLocalCache GetUserGlobalMsgRecvOpt rpc", "userID", userID) + return u.client.GetUserGlobalMsgRecvOpt(ctx, userID) + })) +} + +func (u *UserLocalCache) GetUsersInfo(ctx context.Context, userIDs []string) ([]*sdkws.UserInfo, error) { + users := make([]*sdkws.UserInfo, 0, len(userIDs)) + for _, userID := range userIDs { + user, err := u.GetUserInfo(ctx, userID) + if err != nil { + if errs.ErrRecordNotFound.Is(err) { + continue + } + return nil, err + } + users = append(users, user) + } + return users, nil +} + +func (u *UserLocalCache) GetUsersInfoMap(ctx context.Context, userIDs []string) (map[string]*sdkws.UserInfo, error) { + users := make(map[string]*sdkws.UserInfo, len(userIDs)) + for _, userID := range userIDs { + user, err := u.GetUserInfo(ctx, userID) + if err != nil { + if errs.ErrRecordNotFound.Is(err) { + continue + } + return nil, err + } + users[userID] = user + } + return users, nil +} diff --git a/pkg/rpcclient/conversation.go b/pkg/rpcclient/conversation.go index 6981844b6b..127e029e16 100644 --- a/pkg/rpcclient/conversation.go +++ b/pkg/rpcclient/conversation.go @@ -114,6 +114,14 @@ func (c *ConversationRpcClient) GetConversationsByConversationID(ctx context.Con return resp.Conversations, nil } +func (c *ConversationRpcClient) GetConversationOfflinePushUserIDs(ctx context.Context, conversationID string, userIDs []string) ([]string, error) { + resp, err := c.Client.GetConversationOfflinePushUserIDs(ctx, &pbconversation.GetConversationOfflinePushUserIDsReq{ConversationID: conversationID, UserIDs: userIDs}) + if err != nil { + return nil, err + } + return resp.UserIDs, nil +} + func (c *ConversationRpcClient) GetConversations(ctx context.Context, ownerUserID string, conversationIDs []string) ([]*pbconversation.Conversation, error) { if len(conversationIDs) == 0 { return nil, nil @@ -127,3 +135,11 @@ func (c *ConversationRpcClient) GetConversations(ctx context.Context, ownerUserI } return resp.Conversations, nil } + +func (c *ConversationRpcClient) GetConversationNotReceiveMessageUserIDs(ctx context.Context, conversationID string) ([]string, error) { + resp, err := c.Client.GetConversationNotReceiveMessageUserIDs(ctx, &pbconversation.GetConversationNotReceiveMessageUserIDsReq{ConversationID: conversationID}) + if err != nil { + return nil, err + } + return resp.UserIDs, nil +} diff --git a/pkg/rpcclient/friend.go b/pkg/rpcclient/friend.go index e1f6ed0764..5a5f38698d 100644 --- a/pkg/rpcclient/friend.go +++ b/pkg/rpcclient/friend.go @@ -80,7 +80,7 @@ func (f *FriendRpcClient) GetFriendIDs(ctx context.Context, ownerUserID string) return resp.FriendIDs, nil } -func (b *FriendRpcClient) IsBlocked(ctx context.Context, possibleBlackUserID, userID string) (bool, error) { +func (b *FriendRpcClient) IsBlack(ctx context.Context, possibleBlackUserID, userID string) (bool, error) { r, err := b.Client.IsBlack(ctx, &friend.IsBlackReq{UserID1: possibleBlackUserID, UserID2: userID}) if err != nil { return false, err diff --git a/pkg/rpcclient/group.go b/pkg/rpcclient/group.go index 7736378587..ec7aab6957 100644 --- a/pkg/rpcclient/group.go +++ b/pkg/rpcclient/group.go @@ -26,11 +26,9 @@ import ( "github.com/OpenIMSDK/tools/utils" "github.com/openimsdk/open-im-server/v3/pkg/common/config" util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" - "google.golang.org/grpc" ) type Group struct { - conn grpc.ClientConnInterface Client group.GroupClient discov discoveryregistry.SvcDiscoveryRegistry Config *config.GlobalConfig @@ -42,7 +40,7 @@ func NewGroup(discov discoveryregistry.SvcDiscoveryRegistry, config *config.Glob util.ExitWithError(err) } client := group.NewGroupClient(conn) - return &Group{discov: discov, conn: conn, Client: client, Config: config} + return &Group{discov: discov, Client: client, Config: config} } type GroupRpcClient Group From 057884311a1b4f6800919628338429ce79778272 Mon Sep 17 00:00:00 2001 From: skiffer-git <72860476+skiffer-git@users.noreply.github.com> Date: Fri, 8 Mar 2024 17:09:19 +0800 Subject: [PATCH 099/188] Fix bug Remove duplicate function definitions (#2033) * delete * delete log --- scripts/lib/util.sh | 4 ---- 1 file changed, 4 deletions(-) diff --git a/scripts/lib/util.sh b/scripts/lib/util.sh index f66971252b..7bcfbad970 100755 --- a/scripts/lib/util.sh +++ b/scripts/lib/util.sh @@ -1795,10 +1795,6 @@ openim::util::stop_services_on_ports() { return 0 fi } -# nc -l -p 12345 -# nc -l -p 123456 -# ps -ef | grep "nc -l" -# openim::util::stop_services_on_ports 1234 12345 # The `openim::util::stop_services_with_name` function stops services with specified names. From 2acdfde56e72d62f1153cab3249f8218e1415b3d Mon Sep 17 00:00:00 2001 From: skiffer-git <72860476+skiffer-git@users.noreply.github.com> Date: Fri, 8 Mar 2024 17:21:50 +0800 Subject: [PATCH 100/188] Fix bug configGetEnv failed,err:string to int failed: strconv.Atoi: parsing "openim_v3": invalid syntaxr (#2044) * delete * add context deadline exceeded * Error not handled * Error not handled * Error not handled * Error not handled * configGetEnv failed,err:string to int failed: strconv.Atoi: parsing "openim_v3": invalid syntaxr --- config/templates/env.template | 1 + deployments/templates/env-template.yaml | 1 + scripts/start-all.sh | 2 +- tools/component/component.go | 4 ++-- 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/config/templates/env.template b/config/templates/env.template index b4f9c868de..7a095b2bbd 100644 --- a/config/templates/env.template +++ b/config/templates/env.template @@ -118,6 +118,7 @@ MONGO_OPENIM_PASSWORD=openIM123 # Default: MONGO_DATABASE=openim_v3 MONGO_DATABASE=openim_v3 +MONGO_MAX_POOL_SIZE=100 # ----- Redis Configuration ----- # Port on which Redis in-memory data structure store is running. diff --git a/deployments/templates/env-template.yaml b/deployments/templates/env-template.yaml index 1044dd6bcc..85619b4220 100644 --- a/deployments/templates/env-template.yaml +++ b/deployments/templates/env-template.yaml @@ -118,6 +118,7 @@ MONGO_OPENIM_PASSWORD=${MONGO_OPENIM_PASSWORD} # Default: MONGO_DATABASE=openim_v3 MONGO_DATABASE=${MONGO_DATABASE} +MONGO_MAX_POOL_SIZE=${MONGO_MAX_POOL_SIZE} # ----- Redis Configuration ----- # Port on which Redis in-memory data structure store is running. diff --git a/scripts/start-all.sh b/scripts/start-all.sh index aac4b18372..9529950329 100755 --- a/scripts/start-all.sh +++ b/scripts/start-all.sh @@ -63,7 +63,7 @@ function execute_start_scripts() { if openim::util::is_running_in_container; then - exec > ${DOCKER_LOG_FILE} 2>&1 + exec >> ${DOCKER_LOG_FILE} 2>&1 fi diff --git a/tools/component/component.go b/tools/component/component.go index c7c135549e..0532030ffe 100644 --- a/tools/component/component.go +++ b/tools/component/component.go @@ -297,9 +297,9 @@ func configGetEnv(config *config.GlobalConfig) error { config.Mongo.Password = getEnv("MONGO_OPENIM_PASSWORD", config.Mongo.Password) config.Mongo.Address = getArrEnv("MONGO_ADDRESS", "MONGO_PORT", config.Mongo.Address) config.Mongo.Database = getEnv("MONGO_DATABASE", config.Mongo.Database) - maxPoolSize, err := getEnvInt("MONGO_DATABASE", config.Mongo.MaxPoolSize) + maxPoolSize, err := getEnvInt("MONGO_MAX_POOL_SIZE", config.Mongo.MaxPoolSize) if err != nil { - return err + return errs.Wrap(err, "MONGO_MAX_POOL_SIZE") } config.Mongo.MaxPoolSize = maxPoolSize From fabcb5317fdebca731e8d34b5eb29121ac8f35d4 Mon Sep 17 00:00:00 2001 From: skiffer-git <72860476+skiffer-git@users.noreply.github.com> Date: Fri, 8 Mar 2024 20:19:33 +0800 Subject: [PATCH 101/188] delete log (#2047) --- tools/component/component.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/component/component.go b/tools/component/component.go index 0532030ffe..6893ebf2ca 100644 --- a/tools/component/component.go +++ b/tools/component/component.go @@ -77,7 +77,7 @@ func main() { err = configGetEnv(conf) if err != nil { - fmt.Printf("configGetEnv failed,err:%v", err) + fmt.Printf("configGetEnv failed, err:%v", err) return } From 8d212251079a5364e43493b1d8be77daa7242f11 Mon Sep 17 00:00:00 2001 From: skiffer-git <72860476+skiffer-git@users.noreply.github.com> Date: Fri, 8 Mar 2024 23:19:47 +0800 Subject: [PATCH 102/188] Bug: component check (#2053) * delete * add context deadline exceeded * Error not handled * Error not handled * Error not handled * Error not handled * configGetEnv failed,err:string to int failed: strconv.Atoi: parsing "openim_v3": invalid syntaxr * test Signed-off-by: unknown <44203734@qq.com> * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check --------- Signed-off-by: unknown <44203734@qq.com> --- tools/component/component.go | 31 +++++++++++-------------------- 1 file changed, 11 insertions(+), 20 deletions(-) diff --git a/tools/component/component.go b/tools/component/component.go index 6893ebf2ca..256f87038d 100644 --- a/tools/component/component.go +++ b/tools/component/component.go @@ -31,7 +31,6 @@ import ( "github.com/OpenIMSDK/tools/errs" "github.com/openimsdk/open-im-server/v3/pkg/common/config" - "gopkg.in/yaml.v3" ) @@ -94,7 +93,7 @@ func main() { if i != 0 { time.Sleep(1 * time.Second) } - fmt.Printf("Checking components Round %v...\n", i+1) + fmt.Printf("Checking components round %v...\n", i+1) var err error allSuccess := true @@ -103,28 +102,20 @@ func main() { err = check.function(check.config) if err != nil { if check.name == "Minio" { - if errors.Is(err, errMinioNotEnabled) { - fmt.Println(err.Error(), " check ", check.name) - checks[index].flag = true - } - if errors.Is(err, errSignEndPoint) { + if errors.Is(err, errMinioNotEnabled) || + errors.Is(err, errSignEndPoint) || + errors.Is(err, errApiURL) { fmt.Fprintf(os.Stderr, err.Error(), " check ", check.name) checks[index].flag = true + continue } } - - component.ErrorPrint(fmt.Sprintf("Starting %s failed:%v.", check.name, errs.Unwrap(err).Error())) - if strings.Contains(errs.Unwrap(err).Error(), "connection refused") || - strings.Contains(errs.Unwrap(err).Error(), "timeout") || - strings.Contains(errs.Unwrap(err).Error(), "context deadline exceeded") { - component.ErrorPrint(fmt.Sprintf("try check connection %s", check.name)) - allSuccess = false - break - } - } else { - checks[index].flag = true - component.SuccessPrint(fmt.Sprintf("%s connected successfully", check.name)) + allSuccess = false + component.ErrorPrint(fmt.Sprintf("Check component: %s failed:%v.", check.name, err.Error())) + break } + checks[index].flag = true + component.SuccessPrint(fmt.Sprintf("%s connected successfully", check.name)) } } @@ -133,7 +124,7 @@ func main() { return } } - component.ErrorPrint("Some components started failed!") + component.ErrorPrint("Some components checked failed!") os.Exit(-1) } From fdaad704e02e2e459e52646779ed15aaeac2a9fb Mon Sep 17 00:00:00 2001 From: skiffer-git <72860476+skiffer-git@users.noreply.github.com> Date: Sat, 9 Mar 2024 00:41:54 +0800 Subject: [PATCH 103/188] Bug: component check (#2056) * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * fix: mongo * fix: mongo * fix: mongo * openim.yaml * localcache * localcache * localcache * localcache * localcache * localcache * localcache * localcache * localcache * local cache * local cache * local cache * local cache * fix: GroupApplicationAcceptedNotification * fix: GroupApplicationAcceptedNotification * fix: NotificationUserInfoUpdate * feat: cache add single-flight and timing-wheel. * feat: local cache * feat: local cache * feat: local cache * feat: cache add single-flight and timing-wheel. * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * refactor: refactor the code of push and optimization. * cicd: robot automated Change * refactor: rename cache. * merge * fix: refactor project dir avoid import cycle. * update tools * merge * feat: conversation FindRecvMsgNotNotifyUserIDs * feat: conversation FindRecvMsgNotNotifyUserIDs * feat: conversation FindRecvMsgNotNotifyUserIDs * merge * merge the latest main * Exit with code 1 when the check script fails (#2023) * Optimize script logs * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Exit with code 1 when the check script fails * Execute after the component check succeeds && minio.Enable is not configured to use MinIO (#2027) * Exit with code 1 when the check script fails (#2022) * Optimize script logs * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Exit with code 1 when the check script fails * Exit with code 1 when the check script fails * Exit with code 1 when the check script fails * Exit with code 1 when the check script fails * Exit with code 1 when the check script fails * Handle the return value of pre-start * Handle the return value of pre-start * Handle the return value of pre-start * minio.Enable is not configured to use MinIO, therefore the image server is not checked * minio.Enable is not configured to use MinIO, therefore the image server is not checked * minio.Enable is not configured to use MinIO, therefore the image server is not checked * minio.Enable is not configured to use MinIO, therefore the image server is not checked * Log redirection causes incorrect program exit status. (#2031) * Exit with code 1 when the check script fails (#2022) * Optimize script logs * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Exit with code 1 when the check script fails * cicd: bump League Patch (#2025) * Execute after the component check succeeds && minio.Enable is not configured to use MinIO (#2026) * Exit with code 1 when the check script fails * Exit with code 1 when the check script fails * Exit with code 1 when the check script fails * Exit with code 1 when the check script fails * Handle the return value of pre-start * Handle the return value of pre-start * Handle the return value of pre-start * minio.Enable is not configured to use MinIO, therefore the image server is not checked * minio.Enable is not configured to use MinIO, therefore the image server is not checked * minio.Enable is not configured to use MinIO, therefore the image server is not checked * minio.Enable is not configured to use MinIO, therefore the image server is not checked * Log redirection causes incorrect program exit status. --------- Co-authored-by: OpenIM Bot <124379614+kubbot@users.noreply.github.com> * delete * add context deadline exceeded * Error not handled * Error not handled * Error not handled * Error not handled * Fix bug Remove duplicate function definitions (#2034) * Exit with code 1 when the check script fails (#2022) * Optimize script logs * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Exit with code 1 when the check script fails * delete * delete log * configGetEnv failed,err:string to int failed: strconv.Atoi: parsing "openim_v3": invalid syntaxr * Fix bug configGetEnv failed,err:string to int failed: strconv.Atoi: parsing "openim_v3": invalid syntaxr (#2045) * Error not handled (#2040) * delete * add context deadline exceeded * Error not handled * Error not handled * Error not handled * Error not handled * feat: add local cache for high frequency reads (#2036) * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * fix: mongo * fix: mongo * fix: mongo * openim.yaml * localcache * localcache * localcache * localcache * localcache * localcache * localcache * localcache * localcache * local cache * local cache * local cache * local cache * fix: GroupApplicationAcceptedNotification * fix: GroupApplicationAcceptedNotification * fix: NotificationUserInfoUpdate * feat: cache add single-flight and timing-wheel. * feat: local cache * feat: local cache * feat: local cache * feat: cache add single-flight and timing-wheel. * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * refactor: refactor the code of push and optimization. * cicd: robot automated Change * refactor: rename cache. * merge * fix: refactor project dir avoid import cycle. * update tools * merge * feat: conversation FindRecvMsgNotNotifyUserIDs * feat: conversation FindRecvMsgNotNotifyUserIDs * feat: conversation FindRecvMsgNotNotifyUserIDs * merge * merge the latest main --------- Co-authored-by: Gordon <46924906+FGadvancer@users.noreply.github.com> Co-authored-by: withchao * configGetEnv failed,err:string to int failed: strconv.Atoi: parsing "openim_v3": invalid syntaxr --------- Co-authored-by: chao <48119764+withchao@users.noreply.github.com> Co-authored-by: Gordon <46924906+FGadvancer@users.noreply.github.com> Co-authored-by: withchao * Feature: delete log for update images (#2050) * Error not handled (#2040) * delete * add context deadline exceeded * Error not handled * Error not handled * Error not handled * Error not handled * feat: add local cache for high frequency reads (#2036) * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * fix: mongo * fix: mongo * fix: mongo * openim.yaml * localcache * localcache * localcache * localcache * localcache * localcache * localcache * localcache * localcache * local cache * local cache * local cache * local cache * fix: GroupApplicationAcceptedNotification * fix: GroupApplicationAcceptedNotification * fix: NotificationUserInfoUpdate * feat: cache add single-flight and timing-wheel. * feat: local cache * feat: local cache * feat: local cache * feat: cache add single-flight and timing-wheel. * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * refactor: refactor the code of push and optimization. * cicd: robot automated Change * refactor: rename cache. * merge * fix: refactor project dir avoid import cycle. * update tools * merge * feat: conversation FindRecvMsgNotNotifyUserIDs * feat: conversation FindRecvMsgNotNotifyUserIDs * feat: conversation FindRecvMsgNotNotifyUserIDs * merge * merge the latest main --------- Co-authored-by: Gordon <46924906+FGadvancer@users.noreply.github.com> Co-authored-by: withchao * Fix bug Remove duplicate function definitions (#2033) * delete * delete log * Fix bug configGetEnv failed,err:string to int failed: strconv.Atoi: parsing "openim_v3": invalid syntaxr (#2044) * delete * add context deadline exceeded * Error not handled * Error not handled * Error not handled * Error not handled * configGetEnv failed,err:string to int failed: strconv.Atoi: parsing "openim_v3": invalid syntaxr * delete log (#2047) * delete log --------- Co-authored-by: chao <48119764+withchao@users.noreply.github.com> Co-authored-by: Gordon <46924906+FGadvancer@users.noreply.github.com> Co-authored-by: withchao * test Signed-off-by: unknown <44203734@qq.com> * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check --------- Signed-off-by: unknown <44203734@qq.com> Co-authored-by: withchao <993506633@qq.com> Co-authored-by: chao <48119764+withchao@users.noreply.github.com> Co-authored-by: Gordon <46924906+FGadvancer@users.noreply.github.com> Co-authored-by: withchao Co-authored-by: OpenIM Bot <124379614+kubbot@users.noreply.github.com> --- go.sum | 6 ------ scripts/install/openim-tools.sh | 6 ++++++ tools/component/component.go | 18 +++++++++--------- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/go.sum b/go.sum index 0bba2d65fc..230c142c6c 100644 --- a/go.sum +++ b/go.sum @@ -16,12 +16,6 @@ cloud.google.com/go/storage v1.36.0/go.mod h1:M6M/3V/D3KpzMTJyPOR/HU6n2Si5QdaXYE firebase.google.com/go v3.13.0+incompatible h1:3TdYC3DDi6aHn20qoRkxwGqNgdjtblwVAyRLQwGn/+4= firebase.google.com/go v3.13.0+incompatible/go.mod h1:xlah6XbEyW6tbfSklcfe5FHJIwjt8toICdV5Wh9ptHs= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/IBM/sarama v1.41.3 h1:MWBEJ12vHC8coMjdEXFq/6ftO6DUZnQlFYcxtOJFa7c= -github.com/IBM/sarama v1.41.3/go.mod h1:Xxho9HkHd4K/MDUo/T/sOqwtX/17D33++E9Wib6hUdQ= -github.com/OpenIMSDK/protocol v0.0.53 h1:PtePLTqMYRHjWSf8XIL3x5JRC3YoySTMA6tRKfbUjQY= -github.com/OpenIMSDK/protocol v0.0.53/go.mod h1:F25dFrwrIx3lkNoiuf6FkCfxuwf8L4Z8UIsdTHP/r0Y= -github.com/OpenIMSDK/tools v0.0.29 h1:NS4PEwYl9sX3SWsMjDOLVxMo3LcTWREMr+2cjzWjcqc= -github.com/OpenIMSDK/tools v0.0.29/go.mod h1:eg+q4A34Qmu73xkY0mt37FHGMCMfC6CtmOnm0kFEGFI= github.com/IBM/sarama v1.42.2 h1:VoY4hVIZ+WQJ8G9KNY/SQlWguBQXQ9uvFPOnrcu8hEw= github.com/IBM/sarama v1.42.2/go.mod h1:FLPGUGwYqEs62hq2bVG6Io2+5n+pS6s/WOXVKWSLFtE= github.com/OpenIMSDK/protocol v0.0.55 h1:eBjg8DyuhxGmuCUjpoZjg6MJJJXU/xJ3xJwFhrn34yA= diff --git a/scripts/install/openim-tools.sh b/scripts/install/openim-tools.sh index 04cd70adfc..6f25a0bd8a 100755 --- a/scripts/install/openim-tools.sh +++ b/scripts/install/openim-tools.sh @@ -101,7 +101,13 @@ function openim::tools::start_service() { cmd="${cmd} --prometheus_port ${prometheus_port}" fi openim::log::status "Starting binary ${binary_name}..." + + + ${cmd} + + + local status=$? if [ $status -eq 0 ]; then diff --git a/tools/component/component.go b/tools/component/component.go index 256f87038d..f9170db878 100644 --- a/tools/component/component.go +++ b/tools/component/component.go @@ -101,6 +101,8 @@ func main() { if !check.flag { err = check.function(check.config) if err != nil { + allSuccess = false + component.ErrorPrint(fmt.Sprintf("Check component: %s, failed: %s", check.name, err.Error())) if check.name == "Minio" { if errors.Is(err, errMinioNotEnabled) || errors.Is(err, errSignEndPoint) || @@ -109,16 +111,14 @@ func main() { checks[index].flag = true continue } + break } - allSuccess = false - component.ErrorPrint(fmt.Sprintf("Check component: %s failed:%v.", check.name, err.Error())) - break + } else { + checks[index].flag = true + component.SuccessPrint(fmt.Sprintf("%s connected successfully", check.name)) } - checks[index].flag = true - component.SuccessPrint(fmt.Sprintf("%s connected successfully", check.name)) } } - if allSuccess { component.SuccessPrint("All components started successfully!") return @@ -162,13 +162,13 @@ func checkRedis(config *config.GlobalConfig) error { // checkMinio checks the MinIO connection func checkMinio(config *config.GlobalConfig) error { if strings.Contains(config.Object.ApiURL, "127.0.0.1") { - return errs.Wrap(errApiURL, "config.Object.ApiURL: "+config.Object.ApiURL) + return errs.Wrap(errApiURL) } if config.Object.Enable != "minio" { - return errs.Wrap(errMinioNotEnabled, "config.Object.Enable: "+config.Object.Enable) + return errs.Wrap(errMinioNotEnabled) } if strings.Contains(config.Object.Minio.Endpoint, "127.0.0.1") { - return errs.Wrap(errSignEndPoint, "config.Object.Minio.Endpoint: "+config.Object.Minio.Endpoint) + return errs.Wrap(errSignEndPoint) } minio := &component.Minio{ From 500ebc356d86c3dc228dff82a18fe45f9bb1b47d Mon Sep 17 00:00:00 2001 From: skiffer-git <72860476+skiffer-git@users.noreply.github.com> Date: Sat, 9 Mar 2024 12:56:54 +0800 Subject: [PATCH 104/188] Fix bug delete data conversion (#2059) * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * fix: mongo * fix: mongo * fix: mongo * openim.yaml * localcache * localcache * localcache * localcache * localcache * localcache * localcache * localcache * localcache * local cache * local cache * local cache * local cache * fix: GroupApplicationAcceptedNotification * fix: GroupApplicationAcceptedNotification * fix: NotificationUserInfoUpdate * feat: cache add single-flight and timing-wheel. * feat: local cache * feat: local cache * feat: local cache * feat: cache add single-flight and timing-wheel. * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * refactor: refactor the code of push and optimization. * cicd: robot automated Change * refactor: rename cache. * merge * fix: refactor project dir avoid import cycle. * update tools * merge * feat: conversation FindRecvMsgNotNotifyUserIDs * feat: conversation FindRecvMsgNotNotifyUserIDs * feat: conversation FindRecvMsgNotNotifyUserIDs * merge * merge the latest main * Exit with code 1 when the check script fails (#2023) * Optimize script logs * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Exit with code 1 when the check script fails * Execute after the component check succeeds && minio.Enable is not configured to use MinIO (#2027) * Exit with code 1 when the check script fails (#2022) * Optimize script logs * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Exit with code 1 when the check script fails * Exit with code 1 when the check script fails * Exit with code 1 when the check script fails * Exit with code 1 when the check script fails * Exit with code 1 when the check script fails * Handle the return value of pre-start * Handle the return value of pre-start * Handle the return value of pre-start * minio.Enable is not configured to use MinIO, therefore the image server is not checked * minio.Enable is not configured to use MinIO, therefore the image server is not checked * minio.Enable is not configured to use MinIO, therefore the image server is not checked * minio.Enable is not configured to use MinIO, therefore the image server is not checked * Log redirection causes incorrect program exit status. (#2031) * Exit with code 1 when the check script fails (#2022) * Optimize script logs * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Exit with code 1 when the check script fails * cicd: bump League Patch (#2025) * Execute after the component check succeeds && minio.Enable is not configured to use MinIO (#2026) * Exit with code 1 when the check script fails * Exit with code 1 when the check script fails * Exit with code 1 when the check script fails * Exit with code 1 when the check script fails * Handle the return value of pre-start * Handle the return value of pre-start * Handle the return value of pre-start * minio.Enable is not configured to use MinIO, therefore the image server is not checked * minio.Enable is not configured to use MinIO, therefore the image server is not checked * minio.Enable is not configured to use MinIO, therefore the image server is not checked * minio.Enable is not configured to use MinIO, therefore the image server is not checked * Log redirection causes incorrect program exit status. --------- Co-authored-by: OpenIM Bot <124379614+kubbot@users.noreply.github.com> * delete * add context deadline exceeded * Error not handled * Error not handled * Error not handled * Error not handled * Fix bug Remove duplicate function definitions (#2034) * Exit with code 1 when the check script fails (#2022) * Optimize script logs * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Exit with code 1 when the check script fails * delete * delete log * configGetEnv failed,err:string to int failed: strconv.Atoi: parsing "openim_v3": invalid syntaxr * Fix bug configGetEnv failed,err:string to int failed: strconv.Atoi: parsing "openim_v3": invalid syntaxr (#2045) * Error not handled (#2040) * delete * add context deadline exceeded * Error not handled * Error not handled * Error not handled * Error not handled * feat: add local cache for high frequency reads (#2036) * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * fix: mongo * fix: mongo * fix: mongo * openim.yaml * localcache * localcache * localcache * localcache * localcache * localcache * localcache * localcache * localcache * local cache * local cache * local cache * local cache * fix: GroupApplicationAcceptedNotification * fix: GroupApplicationAcceptedNotification * fix: NotificationUserInfoUpdate * feat: cache add single-flight and timing-wheel. * feat: local cache * feat: local cache * feat: local cache * feat: cache add single-flight and timing-wheel. * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * refactor: refactor the code of push and optimization. * cicd: robot automated Change * refactor: rename cache. * merge * fix: refactor project dir avoid import cycle. * update tools * merge * feat: conversation FindRecvMsgNotNotifyUserIDs * feat: conversation FindRecvMsgNotNotifyUserIDs * feat: conversation FindRecvMsgNotNotifyUserIDs * merge * merge the latest main --------- Co-authored-by: Gordon <46924906+FGadvancer@users.noreply.github.com> Co-authored-by: withchao * configGetEnv failed,err:string to int failed: strconv.Atoi: parsing "openim_v3": invalid syntaxr --------- Co-authored-by: chao <48119764+withchao@users.noreply.github.com> Co-authored-by: Gordon <46924906+FGadvancer@users.noreply.github.com> Co-authored-by: withchao * Feature: delete log for update images (#2050) * Error not handled (#2040) * delete * add context deadline exceeded * Error not handled * Error not handled * Error not handled * Error not handled * feat: add local cache for high frequency reads (#2036) * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * fix: mongo * fix: mongo * fix: mongo * openim.yaml * localcache * localcache * localcache * localcache * localcache * localcache * localcache * localcache * localcache * local cache * local cache * local cache * local cache * fix: GroupApplicationAcceptedNotification * fix: GroupApplicationAcceptedNotification * fix: NotificationUserInfoUpdate * feat: cache add single-flight and timing-wheel. * feat: local cache * feat: local cache * feat: local cache * feat: cache add single-flight and timing-wheel. * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * refactor: refactor the code of push and optimization. * cicd: robot automated Change * refactor: rename cache. * merge * fix: refactor project dir avoid import cycle. * update tools * merge * feat: conversation FindRecvMsgNotNotifyUserIDs * feat: conversation FindRecvMsgNotNotifyUserIDs * feat: conversation FindRecvMsgNotNotifyUserIDs * merge * merge the latest main --------- Co-authored-by: Gordon <46924906+FGadvancer@users.noreply.github.com> Co-authored-by: withchao * Fix bug Remove duplicate function definitions (#2033) * delete * delete log * Fix bug configGetEnv failed,err:string to int failed: strconv.Atoi: parsing "openim_v3": invalid syntaxr (#2044) * delete * add context deadline exceeded * Error not handled * Error not handled * Error not handled * Error not handled * configGetEnv failed,err:string to int failed: strconv.Atoi: parsing "openim_v3": invalid syntaxr * delete log (#2047) * delete log --------- Co-authored-by: chao <48119764+withchao@users.noreply.github.com> Co-authored-by: Gordon <46924906+FGadvancer@users.noreply.github.com> Co-authored-by: withchao * test Signed-off-by: unknown <44203734@qq.com> * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * Bug: component check (#2054) * Error not handled (#2040) * delete * add context deadline exceeded * Error not handled * Error not handled * Error not handled * Error not handled * feat: add local cache for high frequency reads (#2036) * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * fix: mongo * fix: mongo * fix: mongo * openim.yaml * localcache * localcache * localcache * localcache * localcache * localcache * localcache * localcache * localcache * local cache * local cache * local cache * local cache * fix: GroupApplicationAcceptedNotification * fix: GroupApplicationAcceptedNotification * fix: NotificationUserInfoUpdate * feat: cache add single-flight and timing-wheel. * feat: local cache * feat: local cache * feat: local cache * feat: cache add single-flight and timing-wheel. * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * refactor: refactor the code of push and optimization. * cicd: robot automated Change * refactor: rename cache. * merge * fix: refactor project dir avoid import cycle. * update tools * merge * feat: conversation FindRecvMsgNotNotifyUserIDs * feat: conversation FindRecvMsgNotNotifyUserIDs * feat: conversation FindRecvMsgNotNotifyUserIDs * merge * merge the latest main --------- Co-authored-by: Gordon <46924906+FGadvancer@users.noreply.github.com> Co-authored-by: withchao * configGetEnv failed,err:string to int failed: strconv.Atoi: parsing "openim_v3": invalid syntaxr * Fix bug Remove duplicate function definitions (#2033) * delete * delete log * Fix bug configGetEnv failed,err:string to int failed: strconv.Atoi: parsing "openim_v3": invalid syntaxr (#2044) * delete * add context deadline exceeded * Error not handled * Error not handled * Error not handled * Error not handled * configGetEnv failed,err:string to int failed: strconv.Atoi: parsing "openim_v3": invalid syntaxr * delete log (#2047) * test Signed-off-by: unknown <44203734@qq.com> * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check --------- Signed-off-by: unknown <44203734@qq.com> Co-authored-by: chao <48119764+withchao@users.noreply.github.com> Co-authored-by: Gordon <46924906+FGadvancer@users.noreply.github.com> Co-authored-by: withchao * Delete Data Conversion Tool * Delete Data Conversion Tool * Delete Data Conversion Tool * Delete Data Conversion Tool * Delete Data Conversion Tool * Delete Data Conversion Tool * Delete Data Conversion Tool * Delete Data Conversion Tool * Delete Data Conversion Tool * delete data conversion tool * delete data conversion tool * delete data conversion tool --------- Signed-off-by: unknown <44203734@qq.com> Co-authored-by: withchao <993506633@qq.com> Co-authored-by: chao <48119764+withchao@users.noreply.github.com> Co-authored-by: Gordon <46924906+FGadvancer@users.noreply.github.com> Co-authored-by: withchao Co-authored-by: OpenIM Bot <124379614+kubbot@users.noreply.github.com> --- Dockerfile | 3 +- go.work | 2 - scripts/init-config.sh | 6 + scripts/install/openim-tools.sh | 1 - tools/component/component.go | 24 +- tools/data-conversion/README.md | 98 - .../chat/cmd/conversion-chat/chat.go | 77 - .../chat/conversion/conversion.go | 167 - tools/data-conversion/chat/v2/admin.go | 77 - tools/data-conversion/chat/v2/chat.go | 109 - tools/data-conversion/chat/v3/admin/admin.go | 34 - tools/data-conversion/chat/v3/admin/applet.go | 37 - .../chat/v3/admin/client_config.go | 25 - .../chat/v3/admin/forbidden_account.go | 31 - .../chat/v3/admin/invitation_register.go | 30 - .../chat/v3/admin/ip_forbidden.go | 31 - .../chat/v3/admin/limit_user_login_ip.go | 30 - .../chat/v3/admin/register_add_friend.go | 29 - .../chat/v3/admin/register_add_group.go | 29 - tools/data-conversion/chat/v3/chat/account.go | 32 - .../data-conversion/chat/v3/chat/attribute.go | 43 - .../data-conversion/chat/v3/chat/register.go | 34 - .../chat/v3/chat/user_login_record.go | 32 - tools/data-conversion/go.mod | 72 - tools/data-conversion/go.sum | 207 - .../cmd/conversion-msg/conversion-msg.go | 227 - .../cmd/conversion-mysql/conversion-mysql.go | 87 - tools/data-conversion/openim/common/config.go | 65 - .../data-conversion/openim/common/console.go | 29 - tools/data-conversion/openim/mysql/cmd.go | 68 - .../openim/mysql/conversion/conversion.go | 125 - .../openim/mysql/v2/model_struct.go | 105 - .../data-conversion/openim/mysql/v3/black.go | 49 - .../openim/mysql/v3/chatlog.go | 51 - .../openim/mysql/v3/conversation.go | 73 - tools/data-conversion/openim/mysql/v3/doc.go | 15 - .../data-conversion/openim/mysql/v3/friend.go | 67 - .../openim/mysql/v3/friend_request.go | 70 - .../data-conversion/openim/mysql/v3/group.go | 67 - .../openim/mysql/v3/group_member.go | 74 - .../openim/mysql/v3/group_request.go | 61 - tools/data-conversion/openim/mysql/v3/log.go | 43 - .../data-conversion/openim/mysql/v3/object.go | 45 - tools/data-conversion/openim/mysql/v3/user.go | 87 - .../data-conversion/openim/mysql/v3/utils.go | 36 - .../openim/proto/msg/msg.pb.go | 3161 -------- .../openim/proto/msg/msg.proto | 329 - .../openim/proto/sdk_ws/wrappers.proto | 123 - .../openim/proto/sdk_ws/ws.pb.go | 6622 ----------------- .../openim/proto/sdk_ws/ws.proto | 754 -- tools/data-conversion/utils/find_insert.go | 119 - tools/data-conversion/utils/time.go | 28 - tools/up35/README.md | 67 - tools/up35/go.mod | 3 - tools/up35/go.sum | 125 - tools/up35/pkg/convert.go | 242 - .../pkg/internal/rtc/mongo/mgo/meeting.go | 102 - .../rtc/mongo/mgo/meeting_invitation.go | 97 - .../internal/rtc/mongo/mgo/meeting_record.go | 48 - .../up35/pkg/internal/rtc/mongo/mgo/signal.go | 105 - .../rtc/mongo/mgo/signal_invitation.go | 94 - .../pkg/internal/rtc/mongo/table/meeting.go | 66 - .../pkg/internal/rtc/mongo/table/signal.go | 88 - tools/up35/pkg/internal/rtc/mysql/meeting.go | 54 - tools/up35/pkg/internal/rtc/mysql/signal.go | 57 - tools/up35/pkg/pkg.go | 230 - tools/up35/up35.go | 34 - 67 files changed, 28 insertions(+), 15224 deletions(-) delete mode 100644 tools/data-conversion/README.md delete mode 100644 tools/data-conversion/chat/cmd/conversion-chat/chat.go delete mode 100644 tools/data-conversion/chat/conversion/conversion.go delete mode 100644 tools/data-conversion/chat/v2/admin.go delete mode 100644 tools/data-conversion/chat/v2/chat.go delete mode 100644 tools/data-conversion/chat/v3/admin/admin.go delete mode 100644 tools/data-conversion/chat/v3/admin/applet.go delete mode 100644 tools/data-conversion/chat/v3/admin/client_config.go delete mode 100644 tools/data-conversion/chat/v3/admin/forbidden_account.go delete mode 100644 tools/data-conversion/chat/v3/admin/invitation_register.go delete mode 100644 tools/data-conversion/chat/v3/admin/ip_forbidden.go delete mode 100644 tools/data-conversion/chat/v3/admin/limit_user_login_ip.go delete mode 100644 tools/data-conversion/chat/v3/admin/register_add_friend.go delete mode 100644 tools/data-conversion/chat/v3/admin/register_add_group.go delete mode 100644 tools/data-conversion/chat/v3/chat/account.go delete mode 100644 tools/data-conversion/chat/v3/chat/attribute.go delete mode 100644 tools/data-conversion/chat/v3/chat/register.go delete mode 100644 tools/data-conversion/chat/v3/chat/user_login_record.go delete mode 100644 tools/data-conversion/go.mod delete mode 100644 tools/data-conversion/go.sum delete mode 100644 tools/data-conversion/openim/cmd/conversion-msg/conversion-msg.go delete mode 100644 tools/data-conversion/openim/cmd/conversion-mysql/conversion-mysql.go delete mode 100644 tools/data-conversion/openim/common/config.go delete mode 100644 tools/data-conversion/openim/common/console.go delete mode 100644 tools/data-conversion/openim/mysql/cmd.go delete mode 100644 tools/data-conversion/openim/mysql/conversion/conversion.go delete mode 100644 tools/data-conversion/openim/mysql/v2/model_struct.go delete mode 100644 tools/data-conversion/openim/mysql/v3/black.go delete mode 100644 tools/data-conversion/openim/mysql/v3/chatlog.go delete mode 100644 tools/data-conversion/openim/mysql/v3/conversation.go delete mode 100644 tools/data-conversion/openim/mysql/v3/doc.go delete mode 100644 tools/data-conversion/openim/mysql/v3/friend.go delete mode 100644 tools/data-conversion/openim/mysql/v3/friend_request.go delete mode 100644 tools/data-conversion/openim/mysql/v3/group.go delete mode 100644 tools/data-conversion/openim/mysql/v3/group_member.go delete mode 100644 tools/data-conversion/openim/mysql/v3/group_request.go delete mode 100644 tools/data-conversion/openim/mysql/v3/log.go delete mode 100644 tools/data-conversion/openim/mysql/v3/object.go delete mode 100644 tools/data-conversion/openim/mysql/v3/user.go delete mode 100644 tools/data-conversion/openim/mysql/v3/utils.go delete mode 100644 tools/data-conversion/openim/proto/msg/msg.pb.go delete mode 100644 tools/data-conversion/openim/proto/msg/msg.proto delete mode 100644 tools/data-conversion/openim/proto/sdk_ws/wrappers.proto delete mode 100644 tools/data-conversion/openim/proto/sdk_ws/ws.pb.go delete mode 100644 tools/data-conversion/openim/proto/sdk_ws/ws.proto delete mode 100644 tools/data-conversion/utils/find_insert.go delete mode 100644 tools/data-conversion/utils/time.go delete mode 100644 tools/up35/README.md delete mode 100644 tools/up35/go.mod delete mode 100644 tools/up35/go.sum delete mode 100644 tools/up35/pkg/convert.go delete mode 100644 tools/up35/pkg/internal/rtc/mongo/mgo/meeting.go delete mode 100644 tools/up35/pkg/internal/rtc/mongo/mgo/meeting_invitation.go delete mode 100644 tools/up35/pkg/internal/rtc/mongo/mgo/meeting_record.go delete mode 100644 tools/up35/pkg/internal/rtc/mongo/mgo/signal.go delete mode 100644 tools/up35/pkg/internal/rtc/mongo/mgo/signal_invitation.go delete mode 100644 tools/up35/pkg/internal/rtc/mongo/table/meeting.go delete mode 100644 tools/up35/pkg/internal/rtc/mongo/table/signal.go delete mode 100644 tools/up35/pkg/internal/rtc/mysql/meeting.go delete mode 100644 tools/up35/pkg/internal/rtc/mysql/signal.go delete mode 100644 tools/up35/pkg/pkg.go delete mode 100644 tools/up35/up35.go diff --git a/Dockerfile b/Dockerfile index 32639af7a3..b07ff520e8 100644 --- a/Dockerfile +++ b/Dockerfile @@ -10,8 +10,7 @@ ENV GOPROXY=$GOPROXY # Set up the working directory WORKDIR /openim/openim-server -COPY go.mod go.sum ./ -RUN go mod download + # Copy all files to the container ADD . . diff --git a/go.work b/go.work index be67ce842d..8dc91a6319 100644 --- a/go.work +++ b/go.work @@ -6,13 +6,11 @@ use ( ./tools/codescan ./tools/changelog ./tools/component - ./tools/data-conversion ./tools/formitychecker ./tools/imctl ./tools/infra ./tools/ncpu ./tools/openim-web - ./tools/up35 ./tools/url2im ./tools/versionchecker ./tools/yamlfmt diff --git a/scripts/init-config.sh b/scripts/init-config.sh index c7cf163202..c5b21d061b 100755 --- a/scripts/init-config.sh +++ b/scripts/init-config.sh @@ -150,6 +150,12 @@ process_file() { exit 1 fi if [[ -n "${env_cmd}" ]]; then + + { + printf "debugggggggggggggggggggg file: %s template: %s\n" "${ENV_FILE}" "${template}" + } | tee /tmp/debug.log + + eval "$env_cmd ${OPENIM_ROOT}/scripts/genconfig.sh '${ENV_FILE}' '${template}' > '${output_file}'" || { openim::log::error "Error processing template file ${template}" exit 1 diff --git a/scripts/install/openim-tools.sh b/scripts/install/openim-tools.sh index 6f25a0bd8a..7f6e1f52b5 100755 --- a/scripts/install/openim-tools.sh +++ b/scripts/install/openim-tools.sh @@ -58,7 +58,6 @@ openim::tools::pre_start_name() { local targets=( ncpu component - up35 ) echo "${targets[@]}" } diff --git a/tools/component/component.go b/tools/component/component.go index f9170db878..e0d753c3fe 100644 --- a/tools/component/component.go +++ b/tools/component/component.go @@ -65,6 +65,23 @@ type checkFunc struct { config *config.GlobalConfig } +// colorErrPrint prints formatted string in red to stderr +func colorErrPrint(msg string) { + // ANSI escape code for red text + const redColor = "\033[31m" + // ANSI escape code to reset color + const resetColor = "\033[0m" + msg = redColor + msg + resetColor + // Print to stderr in red + fmt.Fprintf(os.Stderr, "%s\n", msg) +} + +func colorSuccessPrint(format string, a ...interface{}) { + // ANSI escape code for green text is \033[32m + // \033[0m resets the color + fmt.Printf("\033[32m"+format+"\033[0m", a...) +} + func main() { flag.Parse() @@ -102,22 +119,23 @@ func main() { err = check.function(check.config) if err != nil { allSuccess = false - component.ErrorPrint(fmt.Sprintf("Check component: %s, failed: %s", check.name, err.Error())) + colorErrPrint(fmt.Sprintf("Check component: %s, failed: %v", check.name, err.Error())) + if check.name == "Minio" { if errors.Is(err, errMinioNotEnabled) || errors.Is(err, errSignEndPoint) || errors.Is(err, errApiURL) { - fmt.Fprintf(os.Stderr, err.Error(), " check ", check.name) checks[index].flag = true continue } - break + break } } else { checks[index].flag = true component.SuccessPrint(fmt.Sprintf("%s connected successfully", check.name)) } } + } if allSuccess { component.SuccessPrint("All components started successfully!") diff --git a/tools/data-conversion/README.md b/tools/data-conversion/README.md deleted file mode 100644 index 71387af7fe..0000000000 --- a/tools/data-conversion/README.md +++ /dev/null @@ -1,98 +0,0 @@ -# OpenIM V2 至 V3 数据迁移指南 - -该指南提供了从 OpenIM V2 迁移至 V3 的详细步骤。请确保在开始迁移过程之前,熟悉所有步骤,并按照指南准确执行。 - -+ [OpenIM Chat](https://github.com/OpenIMSDK/chat) -+ [OpenIM Server](https://github.com/OpenIMSDK/Open-IM-Server) - - - -### 1. 数据备份 - -在开始数据迁移之前,强烈建议备份所有相关的数据以防止任何可能的数据丢失。 - -### 2. 迁移 OpenIM MySQL 数据 - -+ 位置: `open-im-server/tools/data-conversion/openim/cmd/conversion-mysql.go` -+ 配置 `conversion-mysql.go` 文件中的数据库信息。 -+ 手动创建 V3 版本的数据库,并确保字符集为 `utf8mb4`。 - -```bash -// V2 数据库配置 -var ( - usernameV2 = "root" - passwordV2 = "openIM" - addrV2 = "127.0.0.1:13306" - databaseV2 = "openIM_v2" -) - -// V3 数据库配置 -var ( - usernameV3 = "root" - passwordV3 = "openIM123" - addrV3 = "127.0.0.1:13306" - databaseV3 = "openim_v3" -) -``` - -**执行数据迁移命令:** - -```bash -make build BINS="conversion-mysql" -``` - -启动的二进制在 `_output/bin/tools` 中 - - -### 3. 转换聊天消息(可选) - -+ 只支持转换存储在 Kafka 中的消息。 -+ 位置: `open-im-server/tools/data-conversion/openim/conversion-msg/conversion-msg.go` -+ 配置 `msg.go` 文件中的消息和服务器信息。 - -```bash -var ( - topic = "ws2ms_chat" // V2 版本 Kafka 主题 - kafkaAddr = "127.0.0.1:9092" // V2 版本 Kafka 地址 - rpcAddr = "127.0.0.1:10130" // V3 版本 RPC 地址 - adminUserID = "openIM123456" // V3 版本管理员用户ID - concurrency = 4 // 并发数量 -) -``` - -**执行数据迁移命令:** - -```bash -make build BINS="conversion-msg" -``` - -### 4. 转换业务服务器数据 - -+ 只支持转换存储在 Kafka 中的消息。 -+ 位置: `open-im-server/tools/data-conversion/chat/cmd/conversion-chat/chat.go` -+ 需要手动创建 V3 版本的数据库,并确保字符集为 `utf8mb4`。 -+ 配置 `main.go` 文件中的数据库信息。 - -```bash -// V2 数据库配置 -var ( - usernameV2 = "root" - passwordV2 = "openIM" - addrV2 = "127.0.0.1:13306" - databaseV2 = "admin_chat" -) - -// V3 数据库配置 -var ( - usernameV3 = "root" - passwordV3 = "openIM123" - addrV3 = "127.0.0.1:13306" - databaseV3 = "openim_enterprise" -) -``` - -**执行数据迁移命令:** - -```bash -make build BINS="conversion-chat" -``` diff --git a/tools/data-conversion/chat/cmd/conversion-chat/chat.go b/tools/data-conversion/chat/cmd/conversion-chat/chat.go deleted file mode 100644 index f68b71b16b..0000000000 --- a/tools/data-conversion/chat/cmd/conversion-chat/chat.go +++ /dev/null @@ -1,77 +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 main - -import ( - "fmt" - "log" - - "gorm.io/driver/mysql" - "gorm.io/gorm" - "gorm.io/gorm/logger" - - "github.com/openimsdk/open-im-server/v3/tools/data-conversion/chat/conversion" - "github.com/openimsdk/open-im-server/v3/tools/data-conversion/utils" -) - -func main() { - var ( - usernameV2 = "root" // Username for MySQL v2 version - passwordV2 = "openIM" // Password for MySQL v2 version - addrV2 = "127.0.0.1:13306" // Address for MySQL v2 version - databaseV2 = "admin_chat" // Database name for MySQL v2 version - ) - - var ( - usernameV3 = "root" // Username for MySQL v3 version - passwordV3 = "openIM123" // Password for MySQL v3 version - addrV3 = "127.0.0.1:13306" // Address for MySQL v3 version - databaseV3 = "openim_enterprise" // Database name for MySQL v3 version - ) - - var concurrency = 1 // Concurrency quantity - - log.SetFlags(log.LstdFlags | log.Llongfile) - dsnV2 := fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=utf8mb4&parseTime=True&loc=Local", usernameV2, passwordV2, addrV2, databaseV2) - dsnV3 := fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=utf8mb4&parseTime=True&loc=Local", usernameV3, passwordV3, addrV3, databaseV3) - dbV2, err := gorm.Open(mysql.Open(dsnV2), &gorm.Config{Logger: logger.Discard}) - if err != nil { - log.Println("open v2 db failed", err) - return - } - dbV3, err := gorm.Open(mysql.Open(dsnV3), &gorm.Config{Logger: logger.Discard}) - if err != nil { - log.Println("open v3 db failed", err) - return - } - - var tasks utils.TakeList - - tasks.Append(func() (string, error) { return utils.FindAndInsert(dbV2, dbV3, conversion.Account) }) - tasks.Append(func() (string, error) { return utils.FindAndInsert(dbV2, dbV3, conversion.Attribute) }) - tasks.Append(func() (string, error) { return utils.FindAndInsert(dbV2, dbV3, conversion.Register) }) - tasks.Append(func() (string, error) { return utils.FindAndInsert(dbV2, dbV3, conversion.UserLoginRecord) }) - tasks.Append(func() (string, error) { return utils.FindAndInsert(dbV2, dbV3, conversion.Admin) }) - tasks.Append(func() (string, error) { return utils.FindAndInsert(dbV2, dbV3, conversion.Applet) }) - tasks.Append(func() (string, error) { return utils.FindAndInsert(dbV2, dbV3, conversion.ForbiddenAccount) }) - tasks.Append(func() (string, error) { return utils.FindAndInsert(dbV2, dbV3, conversion.InvitationRegister) }) - tasks.Append(func() (string, error) { return utils.FindAndInsert(dbV2, dbV3, conversion.IPForbidden) }) - tasks.Append(func() (string, error) { return utils.FindAndInsert(dbV2, dbV3, conversion.LimitUserLoginIP) }) - tasks.Append(func() (string, error) { return utils.FindAndInsert(dbV2, dbV3, conversion.RegisterAddFriend) }) - tasks.Append(func() (string, error) { return utils.FindAndInsert(dbV2, dbV3, conversion.RegisterAddGroup) }) - - utils.RunTask(concurrency, tasks) - -} diff --git a/tools/data-conversion/chat/conversion/conversion.go b/tools/data-conversion/chat/conversion/conversion.go deleted file mode 100644 index 084fff59ca..0000000000 --- a/tools/data-conversion/chat/conversion/conversion.go +++ /dev/null @@ -1,167 +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 conversion - -import ( - v2 "github.com/openimsdk/open-im-server/v3/tools/data-conversion/chat/v2" - "github.com/openimsdk/open-im-server/v3/tools/data-conversion/chat/v3/admin" - "github.com/openimsdk/open-im-server/v3/tools/data-conversion/chat/v3/chat" - "github.com/openimsdk/open-im-server/v3/tools/data-conversion/utils" -) - -// ########## chat ########## - -func Account(v v2.Account) (chat.Account, bool) { - utils.InitTime(&v.CreateTime, &v.ChangeTime) - return chat.Account{ - UserID: v.UserID, - Password: v.Password, - CreateTime: v.CreateTime, - ChangeTime: v.ChangeTime, - OperatorUserID: v.OperatorUserID, - }, true -} - -func Attribute(v v2.Attribute) (chat.Attribute, bool) { - utils.InitTime(&v.CreateTime, &v.ChangeTime, &v.BirthTime) - return chat.Attribute{ - UserID: v.UserID, - Account: v.Account, - PhoneNumber: v.PhoneNumber, - AreaCode: v.AreaCode, - Email: v.Email, - Nickname: v.Nickname, - FaceURL: v.FaceURL, - Gender: v.Gender, - CreateTime: v.CreateTime, - ChangeTime: v.ChangeTime, - BirthTime: v.BirthTime, - Level: v.Level, - AllowVibration: v.AllowVibration, - AllowBeep: v.AllowBeep, - AllowAddFriend: v.AllowAddFriend, - GlobalRecvMsgOpt: 0, - }, true -} - -func Register(v v2.Register) (chat.Register, bool) { - utils.InitTime(&v.CreateTime) - return chat.Register{ - UserID: v.UserID, - DeviceID: v.DeviceID, - IP: v.IP, - Platform: v.Platform, - AccountType: v.AccountType, - Mode: v.Mode, - CreateTime: v.CreateTime, - }, true -} - -func UserLoginRecord(v v2.UserLoginRecord) (chat.UserLoginRecord, bool) { - utils.InitTime(&v.LoginTime) - return chat.UserLoginRecord{ - UserID: v.UserID, - LoginTime: v.LoginTime, - IP: v.IP, - DeviceID: v.DeviceID, - Platform: v.Platform, - }, true -} - -// ########## admin ########## - -func Admin(v v2.Admin) (admin.Admin, bool) { - utils.InitTime(&v.CreateTime) - return admin.Admin{ - Account: v.Account, - Password: v.Password, - FaceURL: v.FaceURL, - Nickname: v.Nickname, - UserID: v.UserID, - Level: v.Level, - CreateTime: v.CreateTime, - }, true -} - -func Applet(v v2.Applet) (admin.Applet, bool) { - utils.InitTime(&v.CreateTime) - return admin.Applet{ - ID: v.ID, - Name: v.Name, - AppID: v.AppID, - Icon: v.Icon, - URL: v.URL, - MD5: v.MD5, - Size: v.Size, - Version: v.Version, - Priority: v.Priority, - Status: v.Status, - CreateTime: v.CreateTime, - }, true -} - -func ForbiddenAccount(v v2.ForbiddenAccount) (admin.ForbiddenAccount, bool) { - utils.InitTime(&v.CreateTime) - return admin.ForbiddenAccount{ - UserID: v.UserID, - Reason: v.Reason, - OperatorUserID: v.OperatorUserID, - CreateTime: v.CreateTime, - }, true -} - -func InvitationRegister(v v2.InvitationRegister) (admin.InvitationRegister, bool) { - utils.InitTime(&v.CreateTime) - return admin.InvitationRegister{ - InvitationCode: v.InvitationCode, - UsedByUserID: v.UsedByUserID, - CreateTime: v.CreateTime, - }, true -} - -func IPForbidden(v v2.IPForbidden) (admin.IPForbidden, bool) { - utils.InitTime(&v.CreateTime) - return admin.IPForbidden{ - IP: v.IP, - LimitRegister: v.LimitRegister > 0, - LimitLogin: v.LimitLogin > 0, - CreateTime: v.CreateTime, - }, true -} - -func LimitUserLoginIP(v v2.LimitUserLoginIP) (admin.LimitUserLoginIP, bool) { - utils.InitTime(&v.CreateTime) - return admin.LimitUserLoginIP{ - UserID: v.UserID, - IP: v.IP, - CreateTime: v.CreateTime, - }, true -} - -func RegisterAddFriend(v v2.RegisterAddFriend) (admin.RegisterAddFriend, bool) { - utils.InitTime(&v.CreateTime) - return admin.RegisterAddFriend{ - UserID: v.UserID, - CreateTime: v.CreateTime, - }, true -} - -func RegisterAddGroup(v v2.RegisterAddGroup) (admin.RegisterAddGroup, bool) { - utils.InitTime(&v.CreateTime) - return admin.RegisterAddGroup{ - GroupID: v.GroupID, - CreateTime: v.CreateTime, - }, true -} diff --git a/tools/data-conversion/chat/v2/admin.go b/tools/data-conversion/chat/v2/admin.go deleted file mode 100644 index 20cf22a366..0000000000 --- a/tools/data-conversion/chat/v2/admin.go +++ /dev/null @@ -1,77 +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 v2 - -import ( - "time" -) - -// AppVersion manages PC client versions -type AppVersion struct { - Version string `gorm:"column:version;size:64" json:"version"` - Type int `gorm:"column:type;primary_key" json:"type"` - UpdateTime int `gorm:"column:update_time" json:"update_time"` - ForceUpdate bool `gorm:"column:force_update" json:"force_update"` - FileName string `gorm:"column:file_name" json:"file_name"` - YamlName string `gorm:"column:yaml_name" json:"yaml_name"` - UpdateLog string `gorm:"column:update_log" json:"update_log"` -} - -// Admin manages backend administrators -type Admin struct { - Account string `gorm:"column:account;primary_key;type:char(64)" json:"account"` - Password string `gorm:"column:Password;type:char(64)" json:"password"` - FaceURL string `gorm:"column:FaceURL;type:char(64)" json:"faceURL"` - Nickname string `gorm:"column:Nickname;type:char(64)" json:"nickname"` - UserID string `gorm:"column:UserID;type:char(64)" json:"userID"` //openIM userID - Level int32 `gorm:"column:level;default:1" json:"level"` - CreateTime time.Time `gorm:"column:create_time" json:"createTime"` -} - -// RegisterAddFriend specifies default friends when registering -type RegisterAddFriend struct { - UserID string `gorm:"column:user_id;primary_key;type:char(64)" json:"userID"` - CreateTime time.Time `gorm:"column:create_time" json:"createTime"` -} - -// RegisterAddGroup specifies default groups when registering -type RegisterAddGroup struct { - GroupID string `gorm:"column:group_id;primary_key;type:char(64)" json:"userID"` - CreateTime time.Time `gorm:"column:create_time" json:"createTime"` -} - -// ClientInitConfig contains system-related configuration items -type ClientInitConfig struct { - DiscoverPageURL string `gorm:"column:discover_page_url;size:128" json:"discoverPageURL"` - OrdinaryUserAddFriend int32 `gorm:"column:ordinary_user_add_friend; default:1" json:"ordinaryUserAddFriend"` - BossUserID string `gorm:"column:boss_user_id;type:char(64)" json:"bossUserID"` - AdminURL string `gorm:"column:admin_url;type:char(128)" json:"adminURL"` - AllowSendMsgNotFriend int32 `gorm:"column:allow_send_msg_not_friend;default:1" json:"allowSendMsgNotFriend"` - NeedInvitationCodeRegister int32 `gorm:"column:need_invitation_code_register;default:0" json:"needInvitationCodeRegister"` -} - -type Applet struct { - ID string `gorm:"column:id;primary_key;size:64"` - Name string `gorm:"column:name;uniqueIndex;size:64"` - AppID string `gorm:"column:app_id;uniqueIndex;size:255"` - Icon string `gorm:"column:icon;size:255"` - URL string `gorm:"column:url;size:255"` - MD5 string `gorm:"column:md5;size:255"` - Size int64 `gorm:"column:size"` - Version string `gorm:"column:version;size:64"` - Priority uint32 `gorm:"column:priority;size:64"` - Status uint8 `gorm:"column:status"` - CreateTime time.Time `gorm:"column:create_time;autoCreateTime;size:64"` -} diff --git a/tools/data-conversion/chat/v2/chat.go b/tools/data-conversion/chat/v2/chat.go deleted file mode 100644 index 4e0a0c04a1..0000000000 --- a/tools/data-conversion/chat/v2/chat.go +++ /dev/null @@ -1,109 +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 v2 - -import ( - "time" -) - -// Register Registration information sheet -type Register struct { - UserID string `gorm:"column:user_id;primary_key;type:char(64)" json:"userID"` - DeviceID string `gorm:"column:device_id;type:varchar(255)" json:"deviceID"` - IP string `gorm:"column:ip;type:varchar(32)" json:"ip"` - Platform string `gorm:"column:platform;type:varchar(32)" json:"platform"` - AccountType string `gorm:"column:account_type;type:varchar(32)" json:"accountType"` //email phone account - Mode string `gorm:"column:mode;type:varchar(32)"` //user admin - CreateTime time.Time `gorm:"column:create_time" json:"createTime"` -} - -// Account username and password table -type Account struct { - UserID string `gorm:"column:user_id;primary_key;type:char(64)" json:"userID"` - Password string `gorm:"column:password;type:varchar(255)" json:"password"` - CreateTime time.Time `gorm:"column:create_time" json:"createTime"` - ChangeTime time.Time `gorm:"column:change_time" json:"changeTime"` - OperatorUserID string `gorm:"column:operator_user_id;type:varchar(64)" json:"operatorUserID"` -} - -// Attribute user information table -type Attribute struct { - UserID string `gorm:"column:user_id;primary_key;type:char(64)" json:"userID"` - Account string `gorm:"column:account;type:char(64)" json:"account"` - PhoneNumber string `gorm:"column:phone_number;type:varchar(32)" json:"phoneNumber"` - AreaCode string `gorm:"column:area_code;type:varchar(8)" json:"areaCode"` - Email string `gorm:"column:email;type:varchar(64)" json:"email"` - Nickname string `gorm:"column:nickname;type:varchar(64)" json:"nickname"` - FaceURL string `gorm:"column:face_url;type:varchar(255)" json:"faceURL"` - Gender int32 `gorm:"column:gender" json:"gender"` - Birth uint32 `gorm:"column:birth" json:"birth"` - CreateTime time.Time `gorm:"column:create_time" json:"createTime"` - ChangeTime time.Time `gorm:"column:change_time" json:"changeTime"` - BirthTime time.Time `gorm:"column:birth_time" json:"birthTime"` - Level int32 `gorm:"column:level;default:1" json:"level"` - AllowVibration int32 `gorm:"column:allow_vibration;default:1" json:"allowVibration"` - AllowBeep int32 `gorm:"column:allow_beep;default:1" json:"allowBeep"` - AllowAddFriend int32 `gorm:"column:allow_add_friend;default:1" json:"allowAddFriend"` -} - -// User friend relationship table -type ForbiddenAccount struct { - UserID string `gorm:"column:user_id;index:userID;primary_key;type:char(64)" json:"userID"` - CreateTime time.Time `gorm:"column:create_time" json:"createTime"` - Reason string `gorm:"column:reason;type:varchar(255)" json:"reason"` - OperatorUserID string `gorm:"column:operator_user_id;type:varchar(255)" json:"operatorUserID"` -} - -// user login record table -type UserLoginRecord struct { - UserID string `gorm:"column:user_id;size:64" json:"userID"` - LoginTime time.Time `gorm:"column:login_time" json:"loginTime"` - IP string `gorm:"column:ip;type:varchar(32)" json:"ip"` - DeviceID string `gorm:"column:device_id;type:varchar(255)" json:"deviceID"` - Platform string `gorm:"column:platform;type:varchar(32)" json:"platform"` -} - -// ip login registration is prohibited -type IPForbidden struct { - IP string `gorm:"column:ip;primary_key;type:char(32)" json:"ip"` - LimitRegister int32 `gorm:"column:limit_register" json:"limitRegister"` - LimitLogin int32 `gorm:"column:limit_login" json:"limitLogin"` - CreateTime time.Time `gorm:"column:create_time" json:"createTime"` -} - -// Restrict userids to certain ip addresses -type LimitUserLoginIP struct { - UserID string `gorm:"column:user_id;primary_key;type:char(64)" json:"userID"` - IP string `gorm:"column:ip;primary_key;type:char(32)" json:"ip"` - CreateTime time.Time `gorm:"column:create_time" json:"createTime"` -} - -// The invitation code is registered for use -type InvitationRegister struct { - InvitationCode string `gorm:"column:invitation_code;primary_key;type:char(32)" json:"invitationCode"` - CreateTime time.Time `gorm:"column:create_time" json:"createTime"` - UsedByUserID string `gorm:"column:user_id;index:userID;type:char(64)" json:"usedByUserID"` -} - -type SignalRecord struct { - FileName string `gorm:"column:file_name;primary_key;type:char(128)" json:"fileName"` - MediaType string `gorm:"column:media_type;type:char(64);index:media_type_index" json:"mediaType"` - RoomType string `gorm:"column:room_type;type:char(20)" json:"roomType"` - SenderID string `gorm:"column:sender_id;type:char(64);index:sender_id_index" json:"senderID"` - RecvID string `gorm:"column:recv_id;type:char(64);index:recv_id_index" json:"recvID"` - GroupID string `gorm:"column:group_id;type:char(64)" json:"groupID"` - DownloadURL string `gorm:"column:download_url;type:text" json:"downloadURL"` - CreateTime time.Time `gorm:"create_time;index:create_time_index" json:"createTime"` -} diff --git a/tools/data-conversion/chat/v3/admin/admin.go b/tools/data-conversion/chat/v3/admin/admin.go deleted file mode 100644 index 90bd7f8f76..0000000000 --- a/tools/data-conversion/chat/v3/admin/admin.go +++ /dev/null @@ -1,34 +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. - -package admin - -import ( - "time" -) - -// Admin Background administrator. -type Admin struct { - Account string `gorm:"column:account;primary_key;type:varchar(64)"` - Password string `gorm:"column:password;type:varchar(64)"` - FaceURL string `gorm:"column:face_url;type:varchar(255)"` - Nickname string `gorm:"column:nickname;type:varchar(64)"` - UserID string `gorm:"column:user_id;type:varchar(64)"` // openIM userID - Level int32 `gorm:"column:level;default:1" ` - CreateTime time.Time `gorm:"column:create_time"` -} - -func (Admin) TableName() string { - return "admins" -} diff --git a/tools/data-conversion/chat/v3/admin/applet.go b/tools/data-conversion/chat/v3/admin/applet.go deleted file mode 100644 index 5f97cf365b..0000000000 --- a/tools/data-conversion/chat/v3/admin/applet.go +++ /dev/null @@ -1,37 +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. - -package admin - -import ( - "time" -) - -type Applet struct { - ID string `gorm:"column:id;primary_key;size:64"` - Name string `gorm:"column:name;size:64"` - AppID string `gorm:"column:app_id;uniqueIndex;size:255"` - Icon string `gorm:"column:icon;size:255"` - URL string `gorm:"column:url;size:255"` - MD5 string `gorm:"column:md5;size:255"` - Size int64 `gorm:"column:size"` - Version string `gorm:"column:version;size:64"` - Priority uint32 `gorm:"column:priority;size:64"` - Status uint8 `gorm:"column:status"` - CreateTime time.Time `gorm:"column:create_time;autoCreateTime;size:64"` -} - -func (Applet) TableName() string { - return "applets" -} diff --git a/tools/data-conversion/chat/v3/admin/client_config.go b/tools/data-conversion/chat/v3/admin/client_config.go deleted file mode 100644 index 48869fceb4..0000000000 --- a/tools/data-conversion/chat/v3/admin/client_config.go +++ /dev/null @@ -1,25 +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. - -package admin - -// ClientConfig Client related configuration items. -type ClientConfig struct { - Key string `gorm:"column:key;primary_key;type:varchar(255)"` - Value string `gorm:"column:value;not null;type:text"` -} - -func (ClientConfig) TableName() string { - return "client_config" -} diff --git a/tools/data-conversion/chat/v3/admin/forbidden_account.go b/tools/data-conversion/chat/v3/admin/forbidden_account.go deleted file mode 100644 index e081256994..0000000000 --- a/tools/data-conversion/chat/v3/admin/forbidden_account.go +++ /dev/null @@ -1,31 +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. - -package admin - -import ( - "time" -) - -// ForbiddenAccount forbidden account. -type ForbiddenAccount struct { - UserID string `gorm:"column:user_id;index:userID;primary_key;type:char(64)"` - Reason string `gorm:"column:reason;type:varchar(255)" ` - OperatorUserID string `gorm:"column:operator_user_id;type:varchar(255)"` - CreateTime time.Time `gorm:"column:create_time" ` -} - -func (ForbiddenAccount) TableName() string { - return "forbidden_accounts" -} diff --git a/tools/data-conversion/chat/v3/admin/invitation_register.go b/tools/data-conversion/chat/v3/admin/invitation_register.go deleted file mode 100644 index 4b71ccfe04..0000000000 --- a/tools/data-conversion/chat/v3/admin/invitation_register.go +++ /dev/null @@ -1,30 +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. - -package admin - -import ( - "time" -) - -// The invitation code is registered for use. -type InvitationRegister struct { - InvitationCode string `gorm:"column:invitation_code;primary_key;type:char(32)"` - UsedByUserID string `gorm:"column:user_id;index:userID;type:char(64)"` - CreateTime time.Time `gorm:"column:create_time"` -} - -func (InvitationRegister) TableName() string { - return "invitation_registers" -} diff --git a/tools/data-conversion/chat/v3/admin/ip_forbidden.go b/tools/data-conversion/chat/v3/admin/ip_forbidden.go deleted file mode 100644 index 886924abb2..0000000000 --- a/tools/data-conversion/chat/v3/admin/ip_forbidden.go +++ /dev/null @@ -1,31 +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. - -package admin - -import ( - "time" -) - -// ip login registration is prohibited. -type IPForbidden struct { - IP string `gorm:"column:ip;primary_key;type:char(32)"` - LimitRegister bool `gorm:"column:limit_register"` - LimitLogin bool `gorm:"column:limit_login"` - CreateTime time.Time `gorm:"column:create_time"` -} - -func (IPForbidden) TableName() string { - return "ip_forbiddens" -} diff --git a/tools/data-conversion/chat/v3/admin/limit_user_login_ip.go b/tools/data-conversion/chat/v3/admin/limit_user_login_ip.go deleted file mode 100644 index 0eaa5bc1e7..0000000000 --- a/tools/data-conversion/chat/v3/admin/limit_user_login_ip.go +++ /dev/null @@ -1,30 +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. - -package admin - -import ( - "time" -) - -// Restrict userids to certain ip addresses. -type LimitUserLoginIP struct { - UserID string `gorm:"column:user_id;primary_key;type:char(64)"` - IP string `gorm:"column:ip;primary_key;type:char(32)"` - CreateTime time.Time `gorm:"column:create_time" ` -} - -func (LimitUserLoginIP) TableName() string { - return "limit_user_login_ips" -} diff --git a/tools/data-conversion/chat/v3/admin/register_add_friend.go b/tools/data-conversion/chat/v3/admin/register_add_friend.go deleted file mode 100644 index 8281f64853..0000000000 --- a/tools/data-conversion/chat/v3/admin/register_add_friend.go +++ /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. - -package admin - -import ( - "time" -) - -// RegisterAddFriend Indicates the default friend when registering. -type RegisterAddFriend struct { - UserID string `gorm:"column:user_id;primary_key;type:char(64)"` - CreateTime time.Time `gorm:"column:create_time"` -} - -func (RegisterAddFriend) TableName() string { - return "register_add_friends" -} diff --git a/tools/data-conversion/chat/v3/admin/register_add_group.go b/tools/data-conversion/chat/v3/admin/register_add_group.go deleted file mode 100644 index 1204ff97bf..0000000000 --- a/tools/data-conversion/chat/v3/admin/register_add_group.go +++ /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. - -package admin - -import ( - "time" -) - -// RegisterAddGroup Indicates the default group for registration. -type RegisterAddGroup struct { - GroupID string `gorm:"column:group_id;primary_key;type:char(64)"` - CreateTime time.Time `gorm:"column:create_time"` -} - -func (RegisterAddGroup) TableName() string { - return "register_add_groups" -} diff --git a/tools/data-conversion/chat/v3/chat/account.go b/tools/data-conversion/chat/v3/chat/account.go deleted file mode 100644 index 6d01c20e24..0000000000 --- a/tools/data-conversion/chat/v3/chat/account.go +++ /dev/null @@ -1,32 +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. - -package chat - -import ( - "time" -) - -// Account Account password table. -type Account struct { - UserID string `gorm:"column:user_id;primary_key;type:char(64)"` - Password string `gorm:"column:password;type:varchar(32)"` - CreateTime time.Time `gorm:"column:create_time;autoCreateTime"` - ChangeTime time.Time `gorm:"column:change_time;autoUpdateTime"` - OperatorUserID string `gorm:"column:operator_user_id;type:varchar(64)"` -} - -func (Account) TableName() string { - return "accounts" -} diff --git a/tools/data-conversion/chat/v3/chat/attribute.go b/tools/data-conversion/chat/v3/chat/attribute.go deleted file mode 100644 index 23de217bd3..0000000000 --- a/tools/data-conversion/chat/v3/chat/attribute.go +++ /dev/null @@ -1,43 +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. - -package chat - -import ( - "time" -) - -// Attribute Indicates the user attribute table. -type Attribute struct { - UserID string `gorm:"column:user_id;primary_key;type:char(64)"` - Account string `gorm:"column:account;type:char(64)"` - PhoneNumber string `gorm:"column:phone_number;type:varchar(32)"` - AreaCode string `gorm:"column:area_code;type:varchar(8)"` - Email string `gorm:"column:email;type:varchar(64)" ` - Nickname string `gorm:"column:nickname;type:varchar(64)" ` - FaceURL string `gorm:"column:face_url;type:varchar(255)" ` - Gender int32 `gorm:"column:gender"` - CreateTime time.Time `gorm:"column:create_time"` - ChangeTime time.Time `gorm:"column:change_time"` - BirthTime time.Time `gorm:"column:birth_time"` - Level int32 `gorm:"column:level;default:1"` - AllowVibration int32 `gorm:"column:allow_vibration;default:1"` - AllowBeep int32 `gorm:"column:allow_beep;default:1"` - AllowAddFriend int32 `gorm:"column:allow_add_friend;default:1"` - GlobalRecvMsgOpt int32 `gorm:"column:global_recv_msg_opt;default:0"` -} - -func (Attribute) TableName() string { - return "attributes" -} diff --git a/tools/data-conversion/chat/v3/chat/register.go b/tools/data-conversion/chat/v3/chat/register.go deleted file mode 100644 index 29e5cb698e..0000000000 --- a/tools/data-conversion/chat/v3/chat/register.go +++ /dev/null @@ -1,34 +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. - -package chat - -import ( - "time" -) - -// Register Indicates the registration information. -type Register struct { - UserID string `gorm:"column:user_id;primary_key;type:char(64)"` - DeviceID string `gorm:"column:device_id;type:varchar(255)"` - IP string `gorm:"column:ip;type:varchar(64)"` - Platform string `gorm:"column:platform;type:varchar(32)"` - AccountType string `gorm:"column:account_type;type:varchar(32)"` // email phone account - Mode string `gorm:"column:mode;type:varchar(32)"` // user admin - CreateTime time.Time `gorm:"column:create_time"` -} - -func (Register) TableName() string { - return "registers" -} diff --git a/tools/data-conversion/chat/v3/chat/user_login_record.go b/tools/data-conversion/chat/v3/chat/user_login_record.go deleted file mode 100644 index 31e57b6ce6..0000000000 --- a/tools/data-conversion/chat/v3/chat/user_login_record.go +++ /dev/null @@ -1,32 +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. - -package chat - -import ( - "time" -) - -// User login information table. -type UserLoginRecord struct { - UserID string `gorm:"column:user_id;size:64"` - LoginTime time.Time `gorm:"column:login_time"` - IP string `gorm:"column:ip;type:varchar(32)"` - DeviceID string `gorm:"column:device_id;type:varchar(255)"` - Platform string `gorm:"column:platform;type:varchar(32)"` -} - -func (UserLoginRecord) TableName() string { - return "user_login_records" -} diff --git a/tools/data-conversion/go.mod b/tools/data-conversion/go.mod deleted file mode 100644 index 9637559236..0000000000 --- a/tools/data-conversion/go.mod +++ /dev/null @@ -1,72 +0,0 @@ -module github.com/openimsdk/open-im-server/v3/tools/data-conversion - -go 1.19 - -require ( - github.com/IBM/sarama v1.42.1 - github.com/OpenIMSDK/protocol v0.0.33 - github.com/OpenIMSDK/tools v0.0.20 - github.com/golang/protobuf v1.5.3 - github.com/openimsdk/open-im-server/v3 v3.4.0 - golang.org/x/net v0.19.0 - google.golang.org/grpc v1.60.0 - google.golang.org/protobuf v1.31.0 - gorm.io/driver/mysql v1.5.2 - gorm.io/gorm v1.25.5 -) - -require ( - github.com/bwmarrin/snowflake v0.3.0 // indirect - github.com/bytedance/sonic v1.9.1 // indirect - github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect - github.com/davecgh/go-spew v1.1.1 // indirect - github.com/eapache/go-resiliency v1.4.0 // indirect - github.com/eapache/go-xerial-snappy v0.0.0-20230731223053-c322873962e3 // indirect - github.com/eapache/queue v1.1.0 // indirect - github.com/gabriel-vasile/mimetype v1.4.2 // indirect - github.com/gin-contrib/sse v0.1.0 // indirect - github.com/gin-gonic/gin v1.9.1 // 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.15.5 // indirect - github.com/go-sql-driver/mysql v1.7.1 // indirect - github.com/goccy/go-json v0.10.2 // indirect - github.com/golang/snappy v0.0.4 // indirect - github.com/hashicorp/errwrap v1.0.0 // indirect - github.com/hashicorp/go-multierror v1.1.1 // indirect - github.com/hashicorp/go-uuid v1.0.3 // indirect - github.com/jcmturner/aescts/v2 v2.0.0 // indirect - github.com/jcmturner/dnsutils/v2 v2.0.0 // indirect - github.com/jcmturner/gofork v1.7.6 // indirect - github.com/jcmturner/gokrb5/v8 v8.4.4 // indirect - github.com/jcmturner/rpc/v2 v2.0.3 // indirect - github.com/jinzhu/copier v0.4.0 // indirect - github.com/jinzhu/inflection v1.0.0 // indirect - github.com/jinzhu/now v1.1.5 // indirect - github.com/json-iterator/go v1.1.12 // indirect - github.com/klauspost/compress v1.16.7 // indirect - github.com/klauspost/cpuid/v2 v2.2.5 // indirect - github.com/leodido/go-urn v1.2.4 // indirect - github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible // indirect - github.com/lestrrat-go/strftime v1.0.6 // 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/nfnt/resize v0.0.0-20180221191011-83c6a9932646 // indirect - github.com/pelletier/go-toml/v2 v2.0.8 // indirect - github.com/pierrec/lz4/v4 v4.1.18 // indirect - github.com/pkg/errors v0.9.1 // indirect - github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect - github.com/twitchyliquid64/golang-asm v0.15.1 // indirect - github.com/ugorji/go/codec v1.2.11 // indirect - go.uber.org/atomic v1.7.0 // indirect - go.uber.org/multierr v1.6.0 // indirect - go.uber.org/zap v1.24.0 // indirect - golang.org/x/arch v0.3.0 // indirect - golang.org/x/crypto v0.17.0 // indirect - golang.org/x/image v0.13.0 // indirect - golang.org/x/sys v0.15.0 // indirect - golang.org/x/text v0.14.0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20231012201019-e917dd12ba7a // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect -) diff --git a/tools/data-conversion/go.sum b/tools/data-conversion/go.sum deleted file mode 100644 index d6dc23742f..0000000000 --- a/tools/data-conversion/go.sum +++ /dev/null @@ -1,207 +0,0 @@ -github.com/IBM/sarama v1.42.1 h1:wugyWa15TDEHh2kvq2gAy1IHLjEjuYOYgXz/ruC/OSQ= -github.com/IBM/sarama v1.42.1/go.mod h1:Xxho9HkHd4K/MDUo/T/sOqwtX/17D33++E9Wib6hUdQ= -github.com/OpenIMSDK/protocol v0.0.33 h1:T07KWD0jt7IRlrYRujCa+eXmfgcSi8sRgLL8t2ZlHQA= -github.com/OpenIMSDK/protocol v0.0.33/go.mod h1:F25dFrwrIx3lkNoiuf6FkCfxuwf8L4Z8UIsdTHP/r0Y= -github.com/OpenIMSDK/tools v0.0.20 h1:zBTjQZRJ5lR1FIzP9mtWyAvh5dKsmJXQugi4p8X/97k= -github.com/OpenIMSDK/tools v0.0.20/go.mod h1:eg+q4A34Qmu73xkY0mt37FHGMCMfC6CtmOnm0kFEGFI= -github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= -github.com/bwmarrin/snowflake v0.3.0 h1:xm67bEhkKh6ij1790JB83OujPR5CzNe8QuQqAgISZN0= -github.com/bwmarrin/snowflake v0.3.0/go.mod h1:NdZxfVWX+oR6y2K0o6qAYv6gIOP9rjG0/E9WsDpxqwE= -github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= -github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s= -github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= -github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= -github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams= -github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/eapache/go-resiliency v1.4.0 h1:3OK9bWpPk5q6pbFAaYSEwD9CLUSHG8bnZuqX2yMt3B0= -github.com/eapache/go-resiliency v1.4.0/go.mod h1:5yPzW0MIvSe0JDsv0v+DvcjEv2FyD6iZYSs1ZI+iQho= -github.com/eapache/go-xerial-snappy v0.0.0-20230731223053-c322873962e3 h1:Oy0F4ALJ04o5Qqpdz8XLIpNA3WM/iSIXqxtqo7UGVws= -github.com/eapache/go-xerial-snappy v0.0.0-20230731223053-c322873962e3/go.mod h1:YvSRo5mw33fLEx1+DlK6L2VV43tJt5Eyel9n9XBcR+0= -github.com/eapache/queue v1.1.0 h1:YOEu7KNc61ntiQlcEeUIoDTJ2o8mQznoNvUhiigpIqc= -github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= -github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= -github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= -github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= -github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= -github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= -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-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= -github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= -github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= -github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= -github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= -github.com/go-playground/validator/v10 v10.15.5 h1:LEBecTWb/1j5TNY1YYG2RcOUN3R7NLylN+x8TTueE24= -github.com/go-playground/validator/v10 v10.15.5/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= -github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= -github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI= -github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= -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/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= -github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= -github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= -github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= -github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= -github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= -github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= -github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= -github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= -github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= -github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/jcmturner/aescts/v2 v2.0.0 h1:9YKLH6ey7H4eDBXW8khjYslgyqG2xZikXP0EQFKrle8= -github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs= -github.com/jcmturner/dnsutils/v2 v2.0.0 h1:lltnkeZGL0wILNvrNiVCR6Ro5PGU/SeBvVO/8c/iPbo= -github.com/jcmturner/dnsutils/v2 v2.0.0/go.mod h1:b0TnjGOvI/n42bZa+hmXL+kFJZsFT7G4t3HTlQ184QM= -github.com/jcmturner/gofork v1.7.6 h1:QH0l3hzAU1tfT3rZCnW5zXl+orbkNMMRGJfdJjHVETg= -github.com/jcmturner/gofork v1.7.6/go.mod h1:1622LH6i/EZqLloHfE7IeZ0uEJwMSUyQ/nDd82IeqRo= -github.com/jcmturner/goidentity/v6 v6.0.1 h1:VKnZd2oEIMorCTsFBnJWbExfNN7yZr3EhJAxwOkZg6o= -github.com/jcmturner/goidentity/v6 v6.0.1/go.mod h1:X1YW3bgtvwAXju7V3LCIMpY0Gbxyjn/mY9zx4tFonSg= -github.com/jcmturner/gokrb5/v8 v8.4.4 h1:x1Sv4HaTpepFkXbt2IkL29DXRf8sOfZXo8eRKh687T8= -github.com/jcmturner/gokrb5/v8 v8.4.4/go.mod h1:1btQEpgT6k+unzCwX1KdWMEwPPkkgBtP+F6aCACiMrs= -github.com/jcmturner/rpc/v2 v2.0.3 h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZY= -github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc= -github.com/jinzhu/copier v0.4.0 h1:w3ciUoD19shMCRargcpm0cm91ytaBhDvuRpz1ODO/U8= -github.com/jinzhu/copier v0.4.0/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg= -github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= -github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= -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/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= -github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= -github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I= -github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= -github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= -github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg= -github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= -github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= -github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= -github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q= -github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= -github.com/lestrrat-go/envload v0.0.0-20180220234015-a3eb8ddeffcc h1:RKf14vYWi2ttpEmkA4aQ3j4u9dStX2t4M8UM6qqNsG8= -github.com/lestrrat-go/envload v0.0.0-20180220234015-a3eb8ddeffcc/go.mod h1:kopuH9ugFRkIXf3YoqHKyrJ9YfUFsckUU9S7B+XP+is= -github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible h1:Y6sqxHMyB1D2YSzWkLibYKgg+SwmyFU9dF2hn6MdTj4= -github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible/go.mod h1:ZQnN8lSECaebrkQytbHj4xNgtg8CR7RYXnPok8e0EHA= -github.com/lestrrat-go/strftime v1.0.6 h1:CFGsDEt1pOpFNU+TJB0nhz9jl+K0hZSLE205AhTIGQQ= -github.com/lestrrat-go/strftime v1.0.6/go.mod h1:f7jQKgV5nnJpYgdEasS+/y7EsTb8ykN2z68n3TtcTaw= -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/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= -github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ= -github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8= -github.com/openimsdk/open-im-server/v3 v3.4.0 h1:e7nslaWEHYc5xD1A3zHtnhbIWgfgtJSnPGHIqwjARaE= -github.com/openimsdk/open-im-server/v3 v3.4.0/go.mod h1:HKqjLZSMjD7ec59VV694Yfqnj9SIVotzDSPWgAei2Tg= -github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ= -github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4= -github.com/pierrec/lz4/v4 v4.1.18 h1:xaKrnTkyoqfh1YItXl56+6KJNVYWlEEPuAQW9xsplYQ= -github.com/pierrec/lz4/v4 v4.1.18/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= -github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= -github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 h1:N/ElC8H3+5XpJzTSTfLsJV/mx9Q9g7kxmchpfZyxgzM= -github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= -github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= -github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= -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/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= -go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= -go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= -go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= -go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60= -go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= -golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= -golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k= -golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= -golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= -golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= -golang.org/x/image v0.13.0 h1:3cge/F/QTkNLauhf2QoE9zp+7sr+ZcL4HnoZmdwg9sg= -golang.org/x/image v0.13.0/go.mod h1:6mmbMOeV28HuMTgA6OSRkdXKYw/t5W9Uwn2Yv1r3Yxk= -golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c= -golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/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.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= -golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/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= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -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/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231012201019-e917dd12ba7a h1:a2MQQVoTo96JC9PMGtGBymLp7+/RzpFc2yX/9WfFg1c= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231012201019-e917dd12ba7a/go.mod h1:4cYg8o5yUbm77w8ZX00LhMVNl/YVBFJRYWDc0uYWMs0= -google.golang.org/grpc v1.60.0 h1:6FQAR0kM31P6MRdeluor2w2gPaS4SVNrD/DNTxrQ15k= -google.golang.org/grpc v1.60.0/go.mod h1:OlCHIeLYqSSsLi6i49B5QGdzaMZK9+M7LXN2FKz4eGM= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= -google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -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/driver/mysql v1.5.2 h1:QC2HRskSE75wBuOxe0+iCkyJZ+RqpudsQtqkp+IMuXs= -gorm.io/driver/mysql v1.5.2/go.mod h1:pQLhh1Ut/WUAySdTHwBpBv6+JKcj+ua4ZFx1QQTBzb8= -gorm.io/gorm v1.25.2-0.20230530020048-26663ab9bf55/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k= -gorm.io/gorm v1.25.5 h1:zR9lOiiYf09VNh5Q1gphfyia1JpiClIWG9hQaxB/mls= -gorm.io/gorm v1.25.5/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8= -rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= diff --git a/tools/data-conversion/openim/cmd/conversion-msg/conversion-msg.go b/tools/data-conversion/openim/cmd/conversion-msg/conversion-msg.go deleted file mode 100644 index 416fdcb9f8..0000000000 --- a/tools/data-conversion/openim/cmd/conversion-msg/conversion-msg.go +++ /dev/null @@ -1,227 +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 main - -import ( - "context" - "encoding/json" - "log" - "sync" - "sync/atomic" - "time" - - "github.com/IBM/sarama" - "github.com/OpenIMSDK/protocol/constant" - "github.com/OpenIMSDK/protocol/msg" - "github.com/OpenIMSDK/protocol/sdkws" - "github.com/OpenIMSDK/tools/mw" - "github.com/golang/protobuf/proto" - "google.golang.org/grpc" - "google.golang.org/grpc/credentials/insecure" - - "github.com/openimsdk/open-im-server/v3/pkg/apistruct" - pbmsg "github.com/openimsdk/open-im-server/v3/tools/data-conversion/openim/proto/msg" -) - -func main() { - - var ( - // The Kafka topic for ws2ms_chat in version 2 configuration - topic = "ws2ms_chat" - - // The Kafka address in version 2 configuration - kafkaAddr = "127.0.0.1:9092" - - // The RPC address in version 3 configuration - rpcAddr = "127.0.0.1:10130" - - // The administrator userID in version 3 - adminUserID = "openIM123456" - - // The number of concurrent processes - concurrency = 1 - ) - - getRpcConn := func() (*grpc.ClientConn, error) { - ctx, cancel := context.WithTimeout(context.Background(), time.Second*10) - defer cancel() - return grpc.DialContext(ctx, rpcAddr, grpc.WithTransportCredentials(insecure.NewCredentials()), mw.GrpcClient()) - } - conn, err := getRpcConn() - if err != nil { - log.Println("get rpc conn", err) - return - } - defer conn.Close() - - msgClient := msg.NewMsgClient(conn) - - conf := sarama.NewConfig() - conf.Consumer.Offsets.Initial = sarama.OffsetOldest - - consumer, err := sarama.NewConsumer([]string{kafkaAddr}, conf) - if err != nil { - log.Println("kafka consumer conn", err) - return - } - partitions, err := consumer.Partitions(topic) // Get all partitions according to topic - if err != nil { - log.Println("kafka partitions", err) - return - } - - if len(partitions) == 0 { - log.Println("kafka partitions is empty") - return - } - log.Println("kafka partitions", partitions) - - msgCh := make(chan *pbmsg.MsgDataToMQ, concurrency*2) - - var kfkWg sync.WaitGroup - - distinct := make(map[string]struct{}) - var lock sync.Mutex - - for _, partition := range partitions { - kfkWg.Add(1) - go func(partition int32) { - defer kfkWg.Done() - pc, err := consumer.ConsumePartition(topic, partition, sarama.OffsetOldest) - if err != nil { - log.Printf("kafka Consume Partition %d failed %s\n", partition, err) - return - } - defer pc.Close() - ch := pc.Messages() - for { - select { - case <-time.After(time.Second * 10): // 10s Shuts down when the data cannot be read - return - case message, ok := <-ch: - if !ok { - return - } - msgFromMQV2 := pbmsg.MsgDataToMQ{} - err := proto.Unmarshal(message.Value, &msgFromMQV2) - if err != nil { - log.Printf("kafka msg partition %d offset %d unmarshal failed %s\n", message.Partition, message.Offset, message.Value) - continue - } - if msgFromMQV2.MsgData == nil || msgFromMQV2.OperationID == "" { - continue - } - if msgFromMQV2.MsgData.ContentType < constant.ContentTypeBegin || msgFromMQV2.MsgData.ContentType > constant.AdvancedText { - continue - } - lock.Lock() - _, exist := distinct[msgFromMQV2.MsgData.ClientMsgID] - if !exist { - distinct[msgFromMQV2.MsgData.ClientMsgID] = struct{}{} - } - lock.Unlock() - if exist { - continue - } - msgCh <- &msgFromMQV2 - } - } - }(partition) - } - - go func() { - kfkWg.Wait() - close(msgCh) - }() - - var msgWg sync.WaitGroup - - var ( - success int64 - failed int64 - ) - for i := 0; i < concurrency; i++ { - msgWg.Add(1) - go func() { - defer msgWg.Done() - for message := range msgCh { - HandlerV2Msg(msgClient, adminUserID, message, &success, &failed) - } - }() - } - - msgWg.Wait() - log.Printf("total %d success %d failed %d\n", success+failed, success, failed) -} - -func HandlerV2Msg(msgClient msg.MsgClient, adminUserID string, msgFromMQV2 *pbmsg.MsgDataToMQ, success *int64, failed *int64) { - msgData := &sdkws.MsgData{ - SendID: msgFromMQV2.MsgData.SendID, - RecvID: msgFromMQV2.MsgData.RecvID, - GroupID: msgFromMQV2.MsgData.GroupID, - ClientMsgID: msgFromMQV2.MsgData.ClientMsgID, - ServerMsgID: msgFromMQV2.MsgData.ServerMsgID, - SenderPlatformID: msgFromMQV2.MsgData.SenderPlatformID, - SenderNickname: msgFromMQV2.MsgData.SenderNickname, - SenderFaceURL: msgFromMQV2.MsgData.SenderFaceURL, - SessionType: msgFromMQV2.MsgData.SessionType, - MsgFrom: msgFromMQV2.MsgData.MsgFrom, - ContentType: msgFromMQV2.MsgData.ContentType, - SendTime: msgFromMQV2.MsgData.SendTime, - CreateTime: msgFromMQV2.MsgData.CreateTime, - Status: msgFromMQV2.MsgData.Status, - IsRead: false, - Options: msgFromMQV2.MsgData.Options, - AtUserIDList: msgFromMQV2.MsgData.AtUserIDList, - AttachedInfo: msgFromMQV2.MsgData.AttachedInfo, - Ex: msgFromMQV2.MsgData.Ex, - } - - if msgFromMQV2.MsgData.OfflinePushInfo != nil { - msgData.OfflinePushInfo = &sdkws.OfflinePushInfo{ - Title: msgFromMQV2.MsgData.OfflinePushInfo.Title, - Desc: msgFromMQV2.MsgData.OfflinePushInfo.Desc, - Ex: msgFromMQV2.MsgData.OfflinePushInfo.Ex, - IOSPushSound: msgFromMQV2.MsgData.OfflinePushInfo.IOSPushSound, - IOSBadgeCount: msgFromMQV2.MsgData.OfflinePushInfo.IOSBadgeCount, - SignalInfo: "", - } - } - switch msgData.ContentType { - case constant.Text: - data, err := json.Marshal(apistruct.TextElem{ - Content: string(msgFromMQV2.MsgData.Content), - }) - if err != nil { - return - } - msgData.Content = data - default: - msgData.Content = msgFromMQV2.MsgData.Content - } - ctx, cancel := context.WithTimeout(context.Background(), time.Second*10) - defer cancel() - ctx = context.WithValue(context.Background(), constant.OperationID, msgFromMQV2.OperationID) - ctx = context.WithValue(ctx, constant.OpUserID, adminUserID) - - resp, err := msgClient.SendMsg(ctx, &msg.SendMsgReq{MsgData: msgData}) - if err != nil { - atomic.AddInt64(failed, 1) - log.Printf("send msg %+v failed %s\n", msgData, err) - return - } - atomic.AddInt64(success, 1) - log.Printf("send msg success %+v resp %+v\n", msgData, resp) -} diff --git a/tools/data-conversion/openim/cmd/conversion-mysql/conversion-mysql.go b/tools/data-conversion/openim/cmd/conversion-mysql/conversion-mysql.go deleted file mode 100644 index 08fa4ca553..0000000000 --- a/tools/data-conversion/openim/cmd/conversion-mysql/conversion-mysql.go +++ /dev/null @@ -1,87 +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 main - -import ( - "fmt" - "log" - - "gorm.io/driver/mysql" - "gorm.io/gorm" - "gorm.io/gorm/logger" - - "github.com/openimsdk/open-im-server/v3/tools/data-conversion/openim/mysql/conversion" - "github.com/openimsdk/open-im-server/v3/tools/data-conversion/utils" -) - -func main() { - - var ( - // MySQL username for version 2 - usernameV2 = "root" - - // MySQL password for version 2 - passwordV2 = "openIM" - - // MySQL address for version 2 - addrV2 = "127.0.0.1:13306" - - // MySQL database name for version 2 - databaseV2 = "openIM_v2" - ) - - var ( - // MySQL username for version 3 - usernameV3 = "root" - - // MySQL password for version 3 - passwordV3 = "openIM123" - - // MySQL address for version 3 - addrV3 = "127.0.0.1:13306" - - // MySQL database name for version 3 - databaseV3 = "openim_v3" - ) - - // The number of concurrent processes - var concurrency = 1 - - log.SetFlags(log.LstdFlags | log.Llongfile) - dsnV2 := fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=utf8mb4&parseTime=True&loc=Local", usernameV2, passwordV2, addrV2, databaseV2) - dsnV3 := fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=utf8mb4&parseTime=True&loc=Local", usernameV3, passwordV3, addrV3, databaseV3) - dbV2, err := gorm.Open(mysql.Open(dsnV2), &gorm.Config{Logger: logger.Discard}) - if err != nil { - log.Println("open v2 db failed", err) - return - } - dbV3, err := gorm.Open(mysql.Open(dsnV3), &gorm.Config{Logger: logger.Discard}) - if err != nil { - log.Println("open v3 db failed", err) - return - } - - var tasks utils.TakeList - - tasks.Append(func() (string, error) { return utils.FindAndInsert(dbV2, dbV3, conversion.Friend) }) - tasks.Append(func() (string, error) { return utils.FindAndInsert(dbV2, dbV3, conversion.FriendRequest) }) - tasks.Append(func() (string, error) { return utils.FindAndInsert(dbV2, dbV3, conversion.Group) }) - tasks.Append(func() (string, error) { return utils.FindAndInsert(dbV2, dbV3, conversion.GroupMember) }) - tasks.Append(func() (string, error) { return utils.FindAndInsert(dbV2, dbV3, conversion.GroupRequest) }) - tasks.Append(func() (string, error) { return utils.FindAndInsert(dbV2, dbV3, conversion.User) }) - - utils.RunTask(concurrency, tasks) - -} diff --git a/tools/data-conversion/openim/common/config.go b/tools/data-conversion/openim/common/config.go deleted file mode 100644 index e993038d13..0000000000 --- a/tools/data-conversion/openim/common/config.go +++ /dev/null @@ -1,65 +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 common - -// =================================== V2 ===================================== -// MySQL -// V2. -const ( - UsernameV2 = "root" - PasswordV2 = "openIM" - IpV2 = "121.5.182.23:13306" - DatabaseV2 = "openIM_v2" -) - -// V2 chat. -const ( - ChatUsernameV2 = "root" - ChatPasswordV2 = "openIM" - ChatIpV2 = "121.5.182.23:13306" - ChatDatabaseV2 = "admin_chat" -) - -// Kafka. -const ( - Topic = "ws2ms_chat" - KafkaAddr = "121.5.182.23:9092" -) - -// =================================== V3 ===================================== -// V3. -const ( - UsernameV3 = "root" - PasswordV3 = "openIM123" - IpV3 = "43.134.63.160:13306" - DatabaseV3 = "openim_v3" -) - -// V3 chat. -const ( - ChatUsernameV3 = "root" - ChatPasswordV3 = "openIM123" - ChatIpV3 = "43.134.63.160:13306" - ChatDatabaseV3 = "openim_enterprise" -) - -// Zookeeper. -const ( - ZkAddr = "43.134.63.160:12181" - ZKSchema = "openim" - ZKUsername = "" - ZKPassword = "" - MsgRpcName = "Msg" -) diff --git a/tools/data-conversion/openim/common/console.go b/tools/data-conversion/openim/common/console.go deleted file mode 100644 index b739a8c4cd..0000000000 --- a/tools/data-conversion/openim/common/console.go +++ /dev/null @@ -1,29 +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 common - -import "fmt" - -func ErrorPrint(s string) { - fmt.Printf("\x1b[%dm%v\x1b[0m\n", 31, s) -} - -func SuccessPrint(s string) { - fmt.Printf("\x1b[%dm%v\x1b[0m\n", 32, s) -} - -func WarningPrint(s string) { - fmt.Printf("\x1b[%dmWarning: But %v\x1b[0m\n", 33, s) -} diff --git a/tools/data-conversion/openim/mysql/cmd.go b/tools/data-conversion/openim/mysql/cmd.go deleted file mode 100644 index ab3857fba7..0000000000 --- a/tools/data-conversion/openim/mysql/cmd.go +++ /dev/null @@ -1,68 +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 mysql - -import ( - "fmt" - "log" - - "gorm.io/driver/mysql" - "gorm.io/gorm" - "gorm.io/gorm/logger" - - "github.com/openimsdk/open-im-server/v3/tools/data-conversion/openim/mysql/conversion" - "github.com/openimsdk/open-im-server/v3/tools/data-conversion/utils" -) - -func Cmd() { - var ( - usernameV2 = "root" - passwordV2 = "openIM" - addrV2 = "121.5.182.23:13306" - databaseV2 = "openIM_v2" - ) - - var ( - usernameV3 = "root" - passwordV3 = "openIM123" - addrV3 = "203.56.175.233:13306" - databaseV3 = "openim_v3" - ) - log.SetFlags(log.LstdFlags | log.Llongfile) - dsnV2 := fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=utf8mb4&parseTime=True&loc=Local", usernameV2, passwordV2, addrV2, databaseV2) - dsnV3 := fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=utf8mb4&parseTime=True&loc=Local", usernameV3, passwordV3, addrV3, databaseV3) - dbV2, err := gorm.Open(mysql.Open(dsnV2), &gorm.Config{Logger: logger.Discard}) - if err != nil { - log.Println("open v2 db failed", err) - return - } - dbV3, err := gorm.Open(mysql.Open(dsnV3), &gorm.Config{Logger: logger.Discard}) - if err != nil { - log.Println("open v3 db failed", err) - return - } - - var tasks utils.TakeList - - tasks.Append(func() (string, error) { return utils.FindAndInsert(dbV2, dbV3, conversion.Friend) }) - tasks.Append(func() (string, error) { return utils.FindAndInsert(dbV2, dbV3, conversion.FriendRequest) }) - tasks.Append(func() (string, error) { return utils.FindAndInsert(dbV2, dbV3, conversion.Group) }) - tasks.Append(func() (string, error) { return utils.FindAndInsert(dbV2, dbV3, conversion.GroupMember) }) - tasks.Append(func() (string, error) { return utils.FindAndInsert(dbV2, dbV3, conversion.GroupRequest) }) - tasks.Append(func() (string, error) { return utils.FindAndInsert(dbV2, dbV3, conversion.User) }) - - utils.RunTask(4, tasks) - -} diff --git a/tools/data-conversion/openim/mysql/conversion/conversion.go b/tools/data-conversion/openim/mysql/conversion/conversion.go deleted file mode 100644 index f371654dfb..0000000000 --- a/tools/data-conversion/openim/mysql/conversion/conversion.go +++ /dev/null @@ -1,125 +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 conversion - -import ( - "github.com/OpenIMSDK/protocol/constant" - - v2 "github.com/openimsdk/open-im-server/v3/tools/data-conversion/openim/mysql/v2" - v3 "github.com/openimsdk/open-im-server/v3/tools/data-conversion/openim/mysql/v3" - "github.com/openimsdk/open-im-server/v3/tools/data-conversion/utils" -) - -func Friend(v v2.Friend) (v3.FriendModel, bool) { - utils.InitTime(&v.CreateTime) - return v3.FriendModel{ - OwnerUserID: v.OwnerUserID, - FriendUserID: v.FriendUserID, - Remark: v.Remark, - CreateTime: v.CreateTime, - AddSource: v.AddSource, - OperatorUserID: v.OperatorUserID, - Ex: v.Ex, - }, true -} - -func FriendRequest(v v2.FriendRequest) (v3.FriendRequestModel, bool) { - utils.InitTime(&v.CreateTime, &v.HandleTime) - return v3.FriendRequestModel{ - FromUserID: v.FromUserID, - ToUserID: v.ToUserID, - HandleResult: v.HandleResult, - ReqMsg: v.ReqMsg, - CreateTime: v.CreateTime, - HandlerUserID: v.HandlerUserID, - HandleMsg: v.HandleMsg, - HandleTime: v.HandleTime, - Ex: v.Ex, - }, true -} - -func Group(v v2.Group) (v3.GroupModel, bool) { - switch v.GroupType { - case constant.WorkingGroup, constant.NormalGroup: - v.GroupType = constant.WorkingGroup - default: - return v3.GroupModel{}, false - } - utils.InitTime(&v.CreateTime, &v.NotificationUpdateTime) - return v3.GroupModel{ - GroupID: v.GroupID, - GroupName: v.GroupName, - Notification: v.Notification, - Introduction: v.Introduction, - FaceURL: v.FaceURL, - CreateTime: v.CreateTime, - Ex: v.Ex, - Status: v.Status, - CreatorUserID: v.CreatorUserID, - GroupType: v.GroupType, - NeedVerification: v.NeedVerification, - LookMemberInfo: v.LookMemberInfo, - ApplyMemberFriend: v.ApplyMemberFriend, - NotificationUpdateTime: v.NotificationUpdateTime, - NotificationUserID: v.NotificationUserID, - }, true -} - -func GroupMember(v v2.GroupMember) (v3.GroupMemberModel, bool) { - utils.InitTime(&v.JoinTime, &v.MuteEndTime) - return v3.GroupMemberModel{ - GroupID: v.GroupID, - UserID: v.UserID, - Nickname: v.Nickname, - FaceURL: v.FaceURL, - RoleLevel: v.RoleLevel, - JoinTime: v.JoinTime, - JoinSource: v.JoinSource, - InviterUserID: v.InviterUserID, - OperatorUserID: v.OperatorUserID, - MuteEndTime: v.MuteEndTime, - Ex: v.Ex, - }, true -} - -func GroupRequest(v v2.GroupRequest) (v3.GroupRequestModel, bool) { - utils.InitTime(&v.ReqTime, &v.HandledTime) - return v3.GroupRequestModel{ - UserID: v.UserID, - GroupID: v.GroupID, - HandleResult: v.HandleResult, - ReqMsg: v.ReqMsg, - HandledMsg: v.HandledMsg, - ReqTime: v.ReqTime, - HandleUserID: v.HandleUserID, - HandledTime: v.HandledTime, - JoinSource: v.JoinSource, - InviterUserID: v.InviterUserID, - Ex: v.Ex, - }, true -} - -func User(v v2.User) (v3.UserModel, bool) { - utils.InitTime(&v.CreateTime) - return v3.UserModel{ - UserID: v.UserID, - Nickname: v.Nickname, - FaceURL: v.FaceURL, - Ex: v.Ex, - CreateTime: v.CreateTime, - AppMangerLevel: v.AppMangerLevel, - GlobalRecvMsgOpt: v.GlobalRecvMsgOpt, - }, true -} diff --git a/tools/data-conversion/openim/mysql/v2/model_struct.go b/tools/data-conversion/openim/mysql/v2/model_struct.go deleted file mode 100644 index f05b849774..0000000000 --- a/tools/data-conversion/openim/mysql/v2/model_struct.go +++ /dev/null @@ -1,105 +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 db - -import "time" - -type Friend struct { - OwnerUserID string `gorm:"column:owner_user_id;primary_key;size:64"` - FriendUserID string `gorm:"column:friend_user_id;primary_key;size:64"` - Remark string `gorm:"column:remark;size:255"` - CreateTime time.Time `gorm:"column:create_time"` - AddSource int32 `gorm:"column:add_source"` - OperatorUserID string `gorm:"column:operator_user_id;size:64"` - Ex string `gorm:"column:ex;size:1024"` -} - -type FriendRequest struct { - FromUserID string `gorm:"column:from_user_id;primary_key;size:64"` - ToUserID string `gorm:"column:to_user_id;primary_key;size:64"` - HandleResult int32 `gorm:"column:handle_result"` - ReqMsg string `gorm:"column:req_msg;size:255"` - CreateTime time.Time `gorm:"column:create_time"` - HandlerUserID string `gorm:"column:handler_user_id;size:64"` - HandleMsg string `gorm:"column:handle_msg;size:255"` - HandleTime time.Time `gorm:"column:handle_time"` - Ex string `gorm:"column:ex;size:1024"` -} - -func (FriendRequest) TableName() string { - return "friend_requests" -} - -type Group struct { - GroupID string `gorm:"column:group_id;primary_key;size:64" json:"groupID" binding:"required"` - GroupName string `gorm:"column:name;size:255" json:"groupName"` - Notification string `gorm:"column:notification;size:255" json:"notification"` - Introduction string `gorm:"column:introduction;size:255" json:"introduction"` - FaceURL string `gorm:"column:face_url;size:255" json:"faceURL"` - CreateTime time.Time `gorm:"column:create_time;index:create_time"` - Ex string `gorm:"column:ex" json:"ex;size:1024"` - Status int32 `gorm:"column:status"` - CreatorUserID string `gorm:"column:creator_user_id;size:64"` - GroupType int32 `gorm:"column:group_type"` - NeedVerification int32 `gorm:"column:need_verification"` - LookMemberInfo int32 `gorm:"column:look_member_info" json:"lookMemberInfo"` - ApplyMemberFriend int32 `gorm:"column:apply_member_friend" json:"applyMemberFriend"` - NotificationUpdateTime time.Time `gorm:"column:notification_update_time"` - NotificationUserID string `gorm:"column:notification_user_id;size:64"` -} - -type GroupMember struct { - GroupID string `gorm:"column:group_id;primary_key;size:64"` - UserID string `gorm:"column:user_id;primary_key;size:64"` - Nickname string `gorm:"column:nickname;size:255"` - FaceURL string `gorm:"column:user_group_face_url;size:255"` - RoleLevel int32 `gorm:"column:role_level"` - JoinTime time.Time `gorm:"column:join_time"` - JoinSource int32 `gorm:"column:join_source"` - InviterUserID string `gorm:"column:inviter_user_id;size:64"` - OperatorUserID string `gorm:"column:operator_user_id;size:64"` - MuteEndTime time.Time `gorm:"column:mute_end_time"` - Ex string `gorm:"column:ex;size:1024"` -} - -type GroupRequest struct { - UserID string `gorm:"column:user_id;primary_key;size:64"` - GroupID string `gorm:"column:group_id;primary_key;size:64"` - HandleResult int32 `gorm:"column:handle_result"` - ReqMsg string `gorm:"column:req_msg;size:1024"` - HandledMsg string `gorm:"column:handle_msg;size:1024"` - ReqTime time.Time `gorm:"column:req_time"` - HandleUserID string `gorm:"column:handle_user_id;size:64"` - HandledTime time.Time `gorm:"column:handle_time"` - JoinSource int32 `gorm:"column:join_source"` - InviterUserID string `gorm:"column:inviter_user_id;size:64"` - Ex string `gorm:"column:ex;size:1024"` -} - -type User struct { - UserID string `gorm:"column:user_id;primary_key;size:64"` - Nickname string `gorm:"column:name;size:255"` - FaceURL string `gorm:"column:face_url;size:255"` - Gender int32 `gorm:"column:gender"` - PhoneNumber string `gorm:"column:phone_number;size:32"` - Birth time.Time `gorm:"column:birth"` - Email string `gorm:"column:email;size:64"` - Ex string `gorm:"column:ex;size:1024"` - CreateTime time.Time `gorm:"column:create_time;index:create_time"` - AppMangerLevel int32 `gorm:"column:app_manger_level"` - GlobalRecvMsgOpt int32 `gorm:"column:global_recv_msg_opt"` - - status int32 `gorm:"column:status"` -} diff --git a/tools/data-conversion/openim/mysql/v3/black.go b/tools/data-conversion/openim/mysql/v3/black.go deleted file mode 100644 index 59dd12122c..0000000000 --- a/tools/data-conversion/openim/mysql/v3/black.go +++ /dev/null @@ -1,49 +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 relation - -import ( - "context" - "time" -) - -const ( - BlackModelTableName = "blacks" -) - -type BlackModel struct { - OwnerUserID string `gorm:"column:owner_user_id;primary_key;size:64"` - BlockUserID string `gorm:"column:block_user_id;primary_key;size:64"` - CreateTime time.Time `gorm:"column:create_time"` - AddSource int32 `gorm:"column:add_source"` - OperatorUserID string `gorm:"column:operator_user_id;size:64"` - Ex string `gorm:"column:ex;size:1024"` -} - -func (BlackModel) TableName() string { - return BlackModelTableName -} - -type BlackModelInterface interface { - Create(ctx context.Context, blacks []*BlackModel) (err error) - Delete(ctx context.Context, blacks []*BlackModel) (err error) - UpdateByMap(ctx context.Context, ownerUserID, blockUserID string, args map[string]interface{}) (err error) - Update(ctx context.Context, blacks []*BlackModel) (err error) - Find(ctx context.Context, blacks []*BlackModel) (blackList []*BlackModel, err error) - Take(ctx context.Context, ownerUserID, blockUserID string) (black *BlackModel, err error) - FindOwnerBlacks(ctx context.Context, ownerUserID string, pageNumber, showNumber int32) (blacks []*BlackModel, total int64, err error) - FindOwnerBlackInfos(ctx context.Context, ownerUserID string, userIDs []string) (blacks []*BlackModel, err error) - FindBlackUserIDs(ctx context.Context, ownerUserID string) (blackUserIDs []string, err error) -} diff --git a/tools/data-conversion/openim/mysql/v3/chatlog.go b/tools/data-conversion/openim/mysql/v3/chatlog.go deleted file mode 100644 index 810de3db3b..0000000000 --- a/tools/data-conversion/openim/mysql/v3/chatlog.go +++ /dev/null @@ -1,51 +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 relation - -import ( - "time" - - pbmsg "github.com/OpenIMSDK/protocol/msg" -) - -const ( - ChatLogModelTableName = "chat_logs" -) - -type ChatLogModel struct { - ServerMsgID string `gorm:"column:server_msg_id;primary_key;type:char(64)" json:"serverMsgID"` - ClientMsgID string `gorm:"column:client_msg_id;type:char(64)" json:"clientMsgID"` - SendID string `gorm:"column:send_id;type:char(64);index:send_id,priority:2" json:"sendID"` - RecvID string `gorm:"column:recv_id;type:char(64);index:recv_id,priority:2" json:"recvID"` - SenderPlatformID int32 `gorm:"column:sender_platform_id" json:"senderPlatformID"` - SenderNickname string `gorm:"column:sender_nick_name;type:varchar(255)" json:"senderNickname"` - SenderFaceURL string `gorm:"column:sender_face_url;type:varchar(255);" json:"senderFaceURL"` - SessionType int32 `gorm:"column:session_type;index:session_type,priority:2;index:session_type_alone" json:"sessionType"` - MsgFrom int32 `gorm:"column:msg_from" json:"msgFrom"` - ContentType int32 `gorm:"column:content_type;index:content_type,priority:2;index:content_type_alone" json:"contentType"` - Content string `gorm:"column:content;type:varchar(3000)" json:"content"` - Status int32 `gorm:"column:status" json:"status"` - SendTime time.Time `gorm:"column:send_time;index:sendTime;index:content_type,priority:1;index:session_type,priority:1;index:recv_id,priority:1;index:send_id,priority:1" json:"sendTime"` - CreateTime time.Time `gorm:"column:create_time" json:"createTime"` - Ex string `gorm:"column:ex;type:varchar(1024)" json:"ex"` -} - -func (ChatLogModel) TableName() string { - return ChatLogModelTableName -} - -type ChatLogModelInterface interface { - Create(msg *pbmsg.MsgDataToMQ) error -} diff --git a/tools/data-conversion/openim/mysql/v3/conversation.go b/tools/data-conversion/openim/mysql/v3/conversation.go deleted file mode 100644 index e9680873fb..0000000000 --- a/tools/data-conversion/openim/mysql/v3/conversation.go +++ /dev/null @@ -1,73 +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 relation - -import ( - "context" - "time" -) - -const ( - conversationModelTableName = "conversations" -) - -type ConversationModel struct { - OwnerUserID string `gorm:"column:owner_user_id;primary_key;type:char(128)" json:"OwnerUserID"` - ConversationID string `gorm:"column:conversation_id;primary_key;type:char(128)" json:"conversationID"` - ConversationType int32 `gorm:"column:conversation_type" json:"conversationType"` - UserID string `gorm:"column:user_id;type:char(64)" json:"userID"` - GroupID string `gorm:"column:group_id;type:char(128)" json:"groupID"` - RecvMsgOpt int32 `gorm:"column:recv_msg_opt" json:"recvMsgOpt"` - IsPinned bool `gorm:"column:is_pinned" json:"isPinned"` - IsPrivateChat bool `gorm:"column:is_private_chat" json:"isPrivateChat"` - BurnDuration int32 `gorm:"column:burn_duration;default:30" json:"burnDuration"` - GroupAtType int32 `gorm:"column:group_at_type" json:"groupAtType"` - AttachedInfo string `gorm:"column:attached_info;type:varchar(1024)" json:"attachedInfo"` - Ex string `gorm:"column:ex;type:varchar(1024)" json:"ex"` - MaxSeq int64 `gorm:"column:max_seq" json:"maxSeq"` - MinSeq int64 `gorm:"column:min_seq" json:"minSeq"` - CreateTime time.Time `gorm:"column:create_time;index:create_time;autoCreateTime"` - IsMsgDestruct bool `gorm:"column:is_msg_destruct;default:false"` - MsgDestructTime int64 `gorm:"column:msg_destruct_time;default:604800"` - LatestMsgDestructTime time.Time `gorm:"column:latest_msg_destruct_time;autoCreateTime"` -} - -func (ConversationModel) TableName() string { - return conversationModelTableName -} - -type ConversationModelInterface interface { - Create(ctx context.Context, conversations []*ConversationModel) (err error) - Delete(ctx context.Context, groupIDs []string) (err error) - UpdateByMap(ctx context.Context, userIDs []string, conversationID string, args map[string]interface{}) (rows int64, err error) - Update(ctx context.Context, conversation *ConversationModel) (err error) - Find(ctx context.Context, ownerUserID string, conversationIDs []string) (conversations []*ConversationModel, err error) - FindUserID(ctx context.Context, userIDs []string, conversationIDs []string) ([]string, error) - FindUserIDAllConversationID(ctx context.Context, userID string) ([]string, error) - Take(ctx context.Context, userID, conversationID string) (conversation *ConversationModel, err error) - FindConversationID(ctx context.Context, userID string, conversationIDs []string) (existConversationID []string, err error) - FindUserIDAllConversations(ctx context.Context, userID string) (conversations []*ConversationModel, err error) - FindRecvMsgNotNotifyUserIDs(ctx context.Context, groupID string) ([]string, error) - GetUserRecvMsgOpt(ctx context.Context, ownerUserID, conversationID string) (opt int, err error) - FindSuperGroupRecvMsgNotNotifyUserIDs(ctx context.Context, groupID string) ([]string, error) - GetAllConversationIDs(ctx context.Context) ([]string, error) - GetAllConversationIDsNumber(ctx context.Context) (int64, error) - PageConversationIDs(ctx context.Context, pageNumber, showNumber int32) (conversationIDs []string, err error) - GetUserAllHasReadSeqs(ctx context.Context, ownerUserID string) (hashReadSeqs map[string]int64, err error) - GetConversationsByConversationID(ctx context.Context, conversationIDs []string) ([]*ConversationModel, error) - GetConversationIDsNeedDestruct(ctx context.Context) ([]*ConversationModel, error) - GetConversationNotReceiveMessageUserIDs(ctx context.Context, conversationID string) ([]string, error) - NewTx(tx any) ConversationModelInterface -} diff --git a/tools/data-conversion/openim/mysql/v3/doc.go b/tools/data-conversion/openim/mysql/v3/doc.go deleted file mode 100644 index 32185c8c7e..0000000000 --- a/tools/data-conversion/openim/mysql/v3/doc.go +++ /dev/null @@ -1,15 +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 relation // import "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" diff --git a/tools/data-conversion/openim/mysql/v3/friend.go b/tools/data-conversion/openim/mysql/v3/friend.go deleted file mode 100644 index 4f3fb6bdfc..0000000000 --- a/tools/data-conversion/openim/mysql/v3/friend.go +++ /dev/null @@ -1,67 +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 relation - -import ( - "context" - "time" -) - -const ( - FriendModelTableName = "friends" -) - -type FriendModel struct { - OwnerUserID string `gorm:"column:owner_user_id;primary_key;size:64"` - FriendUserID string `gorm:"column:friend_user_id;primary_key;size:64"` - Remark string `gorm:"column:remark;size:255"` - CreateTime time.Time `gorm:"column:create_time;autoCreateTime"` - AddSource int32 `gorm:"column:add_source"` - OperatorUserID string `gorm:"column:operator_user_id;size:64"` - Ex string `gorm:"column:ex;size:1024"` -} - -func (FriendModel) TableName() string { - return FriendModelTableName -} - -type FriendModelInterface interface { - // Create inserts multiple friend records. - Create(ctx context.Context, friends []*FriendModel) error - // Delete removes specified friends for an owner user. - Delete(ctx context.Context, ownerUserID string, friendUserIDs []string) error - // UpdateByMap updates a single friend's information for an owner user based on a map of arguments. Zero values are updated. - UpdateByMap(ctx context.Context, ownerUserID string, friendUserID string, args map[string]interface{}) error - // Update modifies the information of friends, excluding zero values. - Update(ctx context.Context, friends []*FriendModel) error - // UpdateRemark updates the remark for a friend, supporting zero values. - UpdateRemark(ctx context.Context, ownerUserID, friendUserID, remark string) error - // Take retrieves a single friend's information. Returns an error if not found. - Take(ctx context.Context, ownerUserID, friendUserID string) (*FriendModel, error) - // FindUserState finds the friendship status between two users, returning both if a mutual friendship exists. - FindUserState(ctx context.Context, userID1, userID2 string) ([]*FriendModel, error) - // FindFriends retrieves a list of friends for an owner, not returning an error for non-existent friendUserIDs. - FindFriends(ctx context.Context, ownerUserID string, friendUserIDs []string) ([]*FriendModel, error) - // FindReversalFriends finds who has added the specified user as a friend, not returning an error for non-existent ownerUserIDs. - FindReversalFriends(ctx context.Context, friendUserID string, ownerUserIDs []string) ([]*FriendModel, error) - // FindOwnerFriends paginates through the friends list of an owner user. - FindOwnerFriends(ctx context.Context, ownerUserID string, pageNumber, showNumber int32) ([]*FriendModel, int64, error) - // FindInWhoseFriends paginates through users who have added the specified user as a friend. - FindInWhoseFriends(ctx context.Context, friendUserID string, pageNumber, showNumber int32) ([]*FriendModel, int64, error) - // FindFriendUserIDs retrieves a list of friend user IDs for an owner user. - FindFriendUserIDs(ctx context.Context, ownerUserID string) ([]string, error) - // NewTx creates a new transactional instance of the FriendModelInterface. - NewTx(tx any) FriendModelInterface -} diff --git a/tools/data-conversion/openim/mysql/v3/friend_request.go b/tools/data-conversion/openim/mysql/v3/friend_request.go deleted file mode 100644 index 4fc5ba7c1d..0000000000 --- a/tools/data-conversion/openim/mysql/v3/friend_request.go +++ /dev/null @@ -1,70 +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 relation - -import ( - "context" - "time" -) - -const FriendRequestModelTableName = "friend_requests" - -type FriendRequestModel struct { - FromUserID string `gorm:"column:from_user_id;primary_key;size:64"` - ToUserID string `gorm:"column:to_user_id;primary_key;size:64"` - HandleResult int32 `gorm:"column:handle_result"` - ReqMsg string `gorm:"column:req_msg;size:255"` - CreateTime time.Time `gorm:"column:create_time; autoCreateTime"` - HandlerUserID string `gorm:"column:handler_user_id;size:64"` - HandleMsg string `gorm:"column:handle_msg;size:255"` - HandleTime time.Time `gorm:"column:handle_time"` - Ex string `gorm:"column:ex;size:1024"` -} - -func (FriendRequestModel) TableName() string { - return FriendRequestModelTableName -} - -type FriendRequestModelInterface interface { - // Insert multiple records - Create(ctx context.Context, friendRequests []*FriendRequestModel) (err error) - - // Delete a record - Delete(ctx context.Context, fromUserID, toUserID string) (err error) - - // Update records with zero values based on a map of changes - UpdateByMap(ctx context.Context, formUserID, toUserID string, args map[string]interface{}) (err error) - - // Update multiple records (non-zero values) - Update(ctx context.Context, friendRequest *FriendRequestModel) (err error) - - // Find a friend request sent to a specific user; does not return an error if not found - Find(ctx context.Context, fromUserID, toUserID string) (friendRequest *FriendRequestModel, err error) - - // Alias for Find (retrieves a friend request between two users) - Take(ctx context.Context, fromUserID, toUserID string) (friendRequest *FriendRequestModel, err error) - - // Get a list of friend requests received by `toUserID` - FindToUserID(ctx context.Context, toUserID string, pageNumber, showNumber int32) (friendRequests []*FriendRequestModel, total int64, err error) - - // Get a list of friend requests sent by `fromUserID` - FindFromUserID(ctx context.Context, fromUserID string, pageNumber, showNumber int32) (friendRequests []*FriendRequestModel, total int64, err error) - - // Find all friend requests between two users (both directions) - FindBothFriendRequests(ctx context.Context, fromUserID, toUserID string) (friends []*FriendRequestModel, err error) - - // Create a new transaction - NewTx(tx any) FriendRequestModelInterface -} diff --git a/tools/data-conversion/openim/mysql/v3/group.go b/tools/data-conversion/openim/mysql/v3/group.go deleted file mode 100644 index ccf61266ae..0000000000 --- a/tools/data-conversion/openim/mysql/v3/group.go +++ /dev/null @@ -1,67 +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 relation - -import ( - "context" - "time" -) - -const ( - GroupModelTableName = "groups" -) - -type GroupModel struct { - GroupID string `gorm:"column:group_id;primary_key;size:64" json:"groupID" binding:"required"` - GroupName string `gorm:"column:name;size:255" json:"groupName"` - Notification string `gorm:"column:notification;size:255" json:"notification"` - Introduction string `gorm:"column:introduction;size:255" json:"introduction"` - FaceURL string `gorm:"column:face_url;size:255" json:"faceURL"` - CreateTime time.Time `gorm:"column:create_time;index:create_time;autoCreateTime"` - Ex string `gorm:"column:ex" json:"ex;size:1024"` - Status int32 `gorm:"column:status"` - CreatorUserID string `gorm:"column:creator_user_id;size:64"` - GroupType int32 `gorm:"column:group_type"` - NeedVerification int32 `gorm:"column:need_verification"` - LookMemberInfo int32 `gorm:"column:look_member_info" json:"lookMemberInfo"` - ApplyMemberFriend int32 `gorm:"column:apply_member_friend" json:"applyMemberFriend"` - NotificationUpdateTime time.Time `gorm:"column:notification_update_time"` - NotificationUserID string `gorm:"column:notification_user_id;size:64"` -} - -func (GroupModel) TableName() string { - return GroupModelTableName -} - -type GroupModelInterface interface { - NewTx(tx any) GroupModelInterface - Create(ctx context.Context, groups []*GroupModel) (err error) - UpdateMap(ctx context.Context, groupID string, args map[string]interface{}) (err error) - UpdateStatus(ctx context.Context, groupID string, status int32) (err error) - Find(ctx context.Context, groupIDs []string) (groups []*GroupModel, err error) - FindNotDismissedGroup(ctx context.Context, groupIDs []string) (groups []*GroupModel, err error) - Take(ctx context.Context, groupID string) (group *GroupModel, err error) - Search( - ctx context.Context, - keyword string, - pageNumber, showNumber int32, - ) (total uint32, groups []*GroupModel, err error) - // GetGroupIDsByCreatorUserID retrieves a list of group IDs created by the specified user. - GetGroupIDsByGroupType(ctx context.Context, groupType int) (groupIDs []string, err error) - // CountTotal retrieves the total number of groups. - CountTotal(ctx context.Context, before *time.Time) (count int64, err error) - // CountRangeEverydayTotal retrieves the total number of groups created every day within the specified time range. - CountRangeEverydayTotal(ctx context.Context, start time.Time, end time.Time) (map[string]int64, error) -} diff --git a/tools/data-conversion/openim/mysql/v3/group_member.go b/tools/data-conversion/openim/mysql/v3/group_member.go deleted file mode 100644 index bfde728345..0000000000 --- a/tools/data-conversion/openim/mysql/v3/group_member.go +++ /dev/null @@ -1,74 +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 relation - -import ( - "context" - "time" -) - -const ( - GroupMemberModelTableName = "group_members" -) - -type GroupMemberModel struct { - GroupID string `gorm:"column:group_id;primary_key;size:64"` - UserID string `gorm:"column:user_id;primary_key;size:64"` - Nickname string `gorm:"column:nickname;size:255"` - FaceURL string `gorm:"column:user_group_face_url;size:255"` - RoleLevel int32 `gorm:"column:role_level"` - JoinTime time.Time `gorm:"column:join_time"` - JoinSource int32 `gorm:"column:join_source"` - InviterUserID string `gorm:"column:inviter_user_id;size:64"` - OperatorUserID string `gorm:"column:operator_user_id;size:64"` - MuteEndTime time.Time `gorm:"column:mute_end_time"` - Ex string `gorm:"column:ex;size:1024"` -} - -func (GroupMemberModel) TableName() string { - return GroupMemberModelTableName -} - -type GroupMemberModelInterface interface { - NewTx(tx any) GroupMemberModelInterface - Create(ctx context.Context, groupMembers []*GroupMemberModel) (err error) - Delete(ctx context.Context, groupID string, userIDs []string) (err error) - DeleteGroup(ctx context.Context, groupIDs []string) (err error) - Update(ctx context.Context, groupID string, userID string, data map[string]any) (err error) - UpdateRoleLevel(ctx context.Context, groupID string, userID string, roleLevel int32) (rowsAffected int64, err error) - Find( - ctx context.Context, - groupIDs []string, - userIDs []string, - roleLevels []int32, - ) (groupMembers []*GroupMemberModel, err error) - FindMemberUserID(ctx context.Context, groupID string) (userIDs []string, err error) - Take(ctx context.Context, groupID string, userID string) (groupMember *GroupMemberModel, err error) - TakeOwner(ctx context.Context, groupID string) (groupMember *GroupMemberModel, err error) - SearchMember( - ctx context.Context, - keyword string, - groupIDs []string, - userIDs []string, - roleLevels []int32, - pageNumber, showNumber int32, - ) (total uint32, groupList []*GroupMemberModel, err error) - MapGroupMemberNum(ctx context.Context, groupIDs []string) (count map[string]uint32, err error) - FindJoinUserID(ctx context.Context, groupIDs []string) (groupUsers map[string][]string, err error) - FindUserJoinedGroupID(ctx context.Context, userID string) (groupIDs []string, err error) - TakeGroupMemberNum(ctx context.Context, groupID string) (count int64, err error) - FindUsersJoinedGroupID(ctx context.Context, userIDs []string) (map[string][]string, error) - FindUserManagedGroupID(ctx context.Context, userID string) (groupIDs []string, err error) -} diff --git a/tools/data-conversion/openim/mysql/v3/group_request.go b/tools/data-conversion/openim/mysql/v3/group_request.go deleted file mode 100644 index 063b83938f..0000000000 --- a/tools/data-conversion/openim/mysql/v3/group_request.go +++ /dev/null @@ -1,61 +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 relation - -import ( - "context" - "time" -) - -const ( - GroupRequestModelTableName = "group_requests" -) - -type GroupRequestModel struct { - UserID string `gorm:"column:user_id;primary_key;size:64"` - GroupID string `gorm:"column:group_id;primary_key;size:64"` - HandleResult int32 `gorm:"column:handle_result"` - ReqMsg string `gorm:"column:req_msg;size:1024"` - HandledMsg string `gorm:"column:handle_msg;size:1024"` - ReqTime time.Time `gorm:"column:req_time"` - HandleUserID string `gorm:"column:handle_user_id;size:64"` - HandledTime time.Time `gorm:"column:handle_time"` - JoinSource int32 `gorm:"column:join_source"` - InviterUserID string `gorm:"column:inviter_user_id;size:64"` - Ex string `gorm:"column:ex;size:1024"` -} - -func (GroupRequestModel) TableName() string { - return GroupRequestModelTableName -} - -type GroupRequestModelInterface interface { - NewTx(tx any) GroupRequestModelInterface - Create(ctx context.Context, groupRequests []*GroupRequestModel) (err error) - Delete(ctx context.Context, groupID string, userID string) (err error) - UpdateHandler(ctx context.Context, groupID string, userID string, handledMsg string, handleResult int32) (err error) - Take(ctx context.Context, groupID string, userID string) (groupRequest *GroupRequestModel, err error) - FindGroupRequests(ctx context.Context, groupID string, userIDs []string) (int64, []*GroupRequestModel, error) - Page( - ctx context.Context, - userID string, - pageNumber, showNumber int32, - ) (total uint32, groups []*GroupRequestModel, err error) - PageGroup( - ctx context.Context, - groupIDs []string, - pageNumber, showNumber int32, - ) (total uint32, groups []*GroupRequestModel, err error) -} diff --git a/tools/data-conversion/openim/mysql/v3/log.go b/tools/data-conversion/openim/mysql/v3/log.go deleted file mode 100644 index 22198ca7c7..0000000000 --- a/tools/data-conversion/openim/mysql/v3/log.go +++ /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. - -package relation - -import ( - "context" - "time" -) - -type Log struct { - LogID string `gorm:"column:log_id;primary_key;type:char(64)"` - Platform string `gorm:"column:platform;type:varchar(32)"` - UserID string `gorm:"column:user_id;type:char(64)"` - CreateTime time.Time `gorm:"index:,sort:desc"` - Url string `gorm:"column:url;type varchar(255)"` - FileName string `gorm:"column:filename;type varchar(255)"` - SystemType string `gorm:"column:system_type;type varchar(255)"` - Version string `gorm:"column:version;type varchar(255)"` - Ex string `gorm:"column:ex;type varchar(255)"` -} - -func (Log) TableName() string { - return "logs" -} - -type LogInterface interface { - Create(ctx context.Context, log []*Log) error - Search(ctx context.Context, keyword string, start time.Time, end time.Time, pageNumber int32, showNumber int32) (uint32, []*Log, error) - Delete(ctx context.Context, logID []string, userID string) error - Get(ctx context.Context, logIDs []string, userID string) ([]*Log, error) -} diff --git a/tools/data-conversion/openim/mysql/v3/object.go b/tools/data-conversion/openim/mysql/v3/object.go deleted file mode 100644 index 0ed4130a64..0000000000 --- a/tools/data-conversion/openim/mysql/v3/object.go +++ /dev/null @@ -1,45 +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 relation - -import ( - "context" - "time" -) - -const ( - ObjectInfoModelTableName = "object" -) - -type ObjectModel struct { - Name string `gorm:"column:name;primary_key"` - UserID string `gorm:"column:user_id"` - Hash string `gorm:"column:hash"` - Key string `gorm:"column:key"` - Size int64 `gorm:"column:size"` - ContentType string `gorm:"column:content_type"` - Cause string `gorm:"column:cause"` - CreateTime time.Time `gorm:"column:create_time"` -} - -func (ObjectModel) TableName() string { - return ObjectInfoModelTableName -} - -type ObjectInfoModelInterface interface { - NewTx(tx any) ObjectInfoModelInterface - SetObject(ctx context.Context, obj *ObjectModel) error - Take(ctx context.Context, name string) (*ObjectModel, error) -} diff --git a/tools/data-conversion/openim/mysql/v3/user.go b/tools/data-conversion/openim/mysql/v3/user.go deleted file mode 100644 index 4096899330..0000000000 --- a/tools/data-conversion/openim/mysql/v3/user.go +++ /dev/null @@ -1,87 +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 relation - -import ( - "context" - "time" -) - -const ( - UserModelTableName = "users" -) - -type UserModel struct { - UserID string `gorm:"column:user_id;primary_key;size:64"` - Nickname string `gorm:"column:name;size:255"` - FaceURL string `gorm:"column:face_url;size:255"` - Ex string `gorm:"column:ex;size:1024"` - CreateTime time.Time `gorm:"column:create_time;index:create_time;autoCreateTime"` - AppMangerLevel int32 `gorm:"column:app_manger_level;default:1"` - GlobalRecvMsgOpt int32 `gorm:"column:global_recv_msg_opt"` -} - -func (u *UserModel) GetNickname() string { - return u.Nickname -} - -func (u *UserModel) GetFaceURL() string { - return u.FaceURL -} - -func (u *UserModel) GetUserID() string { - return u.UserID -} - -func (u *UserModel) GetEx() string { - return u.Ex -} - -func (UserModel) TableName() string { - return UserModelTableName -} - -// UserModelInterface defines the operations available for managing user models. -type UserModelInterface interface { - // Create inserts a new user or multiple users into the database. - Create(ctx context.Context, users []*UserModel) (err error) - - // UpdateByMap updates a user's information based on a map of changes. - UpdateByMap(ctx context.Context, userID string, args map[string]interface{}) (err error) - - // Update modifies a user's information in the database. - Update(ctx context.Context, user *UserModel) (err error) - - // Find retrieves information for a list of users by their IDs. If a user does not exist, it is simply skipped without returning an error. - Find(ctx context.Context, userIDs []string) (users []*UserModel, err error) - - // Take retrieves a specific user's information by their ID. Returns an error if the user does not exist. - Take(ctx context.Context, userID string) (user *UserModel, err error) - - // Page retrieves a paginated list of users and the total count of users. If no users exist, returns an empty list without an error. - Page(ctx context.Context, pageNumber, showNumber int32) (users []*UserModel, count int64, err error) - - // GetAllUserID retrieves all user IDs in a paginated manner. - GetAllUserID(ctx context.Context, pageNumber, showNumber int32) (userIDs []string, err error) - - // GetUserGlobalRecvMsgOpt retrieves a user's global message receiving option. - GetUserGlobalRecvMsgOpt(ctx context.Context, userID string) (opt int, err error) - - // CountTotal returns the total number of users before a specified time. - CountTotal(ctx context.Context, before *time.Time) (count int64, err error) - - // CountRangeEverydayTotal calculates the daily increment of users within a specified time range. - CountRangeEverydayTotal(ctx context.Context, start time.Time, end time.Time) (map[string]int64, error) -} diff --git a/tools/data-conversion/openim/mysql/v3/utils.go b/tools/data-conversion/openim/mysql/v3/utils.go deleted file mode 100644 index c944eae8b9..0000000000 --- a/tools/data-conversion/openim/mysql/v3/utils.go +++ /dev/null @@ -1,36 +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 relation - -import ( - "gorm.io/gorm" - - "github.com/OpenIMSDK/tools/utils" -) - -type BatchUpdateGroupMember struct { - GroupID string - UserID string - Map map[string]any -} - -type GroupSimpleUserID struct { - Hash uint64 - MemberNum uint32 -} - -func IsNotFound(err error) bool { - return utils.Unwrap(err) == gorm.ErrRecordNotFound -} diff --git a/tools/data-conversion/openim/proto/msg/msg.pb.go b/tools/data-conversion/openim/proto/msg/msg.pb.go deleted file mode 100644 index a0a6cdf021..0000000000 --- a/tools/data-conversion/openim/proto/msg/msg.pb.go +++ /dev/null @@ -1,3161 +0,0 @@ -// Code generated by protoc-gen-go. DO NOT EDIT. -// source: msg/msg.proto - -package msg // import "Open_IM/pkg/proto/msg" - -import ( - proto "github.com/golang/protobuf/proto" - sdk_ws "github.com/openimsdk/open-im-server/v3/tools/data-conversion/openim/proto/sdk_ws" -) -import fmt "fmt" -import math "math" -import wrapperspb "google.golang.org/protobuf/types/known/wrapperspb" - -import ( - context "golang.org/x/net/context" - grpc "google.golang.org/grpc" -) - -// Reference imports to suppress errors if they are not otherwise used. -var _ = proto.Marshal -var _ = fmt.Errorf -var _ = math.Inf - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the proto package it is being compiled against. -// A compilation error at this line likely means your copy of the -// proto package needs to be updated. -const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package - -type MsgDataToMQ struct { - Token string `protobuf:"bytes,1,opt,name=token" json:"token,omitempty"` - OperationID string `protobuf:"bytes,2,opt,name=operationID" json:"operationID,omitempty"` - MsgData *sdk_ws.MsgData `protobuf:"bytes,3,opt,name=msgData" json:"msgData,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *MsgDataToMQ) Reset() { *m = MsgDataToMQ{} } -func (m *MsgDataToMQ) String() string { return proto.CompactTextString(m) } -func (*MsgDataToMQ) ProtoMessage() {} -func (*MsgDataToMQ) Descriptor() ([]byte, []int) { - return fileDescriptor_msg_53ecdffb017d9c40, []int{0} -} -func (m *MsgDataToMQ) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_MsgDataToMQ.Unmarshal(m, b) -} -func (m *MsgDataToMQ) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_MsgDataToMQ.Marshal(b, m, deterministic) -} -func (dst *MsgDataToMQ) XXX_Merge(src proto.Message) { - xxx_messageInfo_MsgDataToMQ.Merge(dst, src) -} -func (m *MsgDataToMQ) XXX_Size() int { - return xxx_messageInfo_MsgDataToMQ.Size(m) -} -func (m *MsgDataToMQ) XXX_DiscardUnknown() { - xxx_messageInfo_MsgDataToMQ.DiscardUnknown(m) -} - -var xxx_messageInfo_MsgDataToMQ proto.InternalMessageInfo - -func (m *MsgDataToMQ) GetToken() string { - if m != nil { - return m.Token - } - return "" -} - -func (m *MsgDataToMQ) GetOperationID() string { - if m != nil { - return m.OperationID - } - return "" -} - -func (m *MsgDataToMQ) GetMsgData() *sdk_ws.MsgData { - if m != nil { - return m.MsgData - } - return nil -} - -type MsgDataToDB struct { - MsgData *sdk_ws.MsgData `protobuf:"bytes,1,opt,name=msgData" json:"msgData,omitempty"` - OperationID string `protobuf:"bytes,2,opt,name=operationID" json:"operationID,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *MsgDataToDB) Reset() { *m = MsgDataToDB{} } -func (m *MsgDataToDB) String() string { return proto.CompactTextString(m) } -func (*MsgDataToDB) ProtoMessage() {} -func (*MsgDataToDB) Descriptor() ([]byte, []int) { - return fileDescriptor_msg_53ecdffb017d9c40, []int{1} -} -func (m *MsgDataToDB) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_MsgDataToDB.Unmarshal(m, b) -} -func (m *MsgDataToDB) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_MsgDataToDB.Marshal(b, m, deterministic) -} -func (dst *MsgDataToDB) XXX_Merge(src proto.Message) { - xxx_messageInfo_MsgDataToDB.Merge(dst, src) -} -func (m *MsgDataToDB) XXX_Size() int { - return xxx_messageInfo_MsgDataToDB.Size(m) -} -func (m *MsgDataToDB) XXX_DiscardUnknown() { - xxx_messageInfo_MsgDataToDB.DiscardUnknown(m) -} - -var xxx_messageInfo_MsgDataToDB proto.InternalMessageInfo - -func (m *MsgDataToDB) GetMsgData() *sdk_ws.MsgData { - if m != nil { - return m.MsgData - } - return nil -} - -func (m *MsgDataToDB) GetOperationID() string { - if m != nil { - return m.OperationID - } - return "" -} - -type PushMsgDataToMQ struct { - OperationID string `protobuf:"bytes,1,opt,name=OperationID" json:"OperationID,omitempty"` - MsgData *sdk_ws.MsgData `protobuf:"bytes,2,opt,name=msgData" json:"msgData,omitempty"` - PushToUserID string `protobuf:"bytes,3,opt,name=pushToUserID" json:"pushToUserID,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *PushMsgDataToMQ) Reset() { *m = PushMsgDataToMQ{} } -func (m *PushMsgDataToMQ) String() string { return proto.CompactTextString(m) } -func (*PushMsgDataToMQ) ProtoMessage() {} -func (*PushMsgDataToMQ) Descriptor() ([]byte, []int) { - return fileDescriptor_msg_53ecdffb017d9c40, []int{2} -} -func (m *PushMsgDataToMQ) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_PushMsgDataToMQ.Unmarshal(m, b) -} -func (m *PushMsgDataToMQ) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_PushMsgDataToMQ.Marshal(b, m, deterministic) -} -func (dst *PushMsgDataToMQ) XXX_Merge(src proto.Message) { - xxx_messageInfo_PushMsgDataToMQ.Merge(dst, src) -} -func (m *PushMsgDataToMQ) XXX_Size() int { - return xxx_messageInfo_PushMsgDataToMQ.Size(m) -} -func (m *PushMsgDataToMQ) XXX_DiscardUnknown() { - xxx_messageInfo_PushMsgDataToMQ.DiscardUnknown(m) -} - -var xxx_messageInfo_PushMsgDataToMQ proto.InternalMessageInfo - -func (m *PushMsgDataToMQ) GetOperationID() string { - if m != nil { - return m.OperationID - } - return "" -} - -func (m *PushMsgDataToMQ) GetMsgData() *sdk_ws.MsgData { - if m != nil { - return m.MsgData - } - return nil -} - -func (m *PushMsgDataToMQ) GetPushToUserID() string { - if m != nil { - return m.PushToUserID - } - return "" -} - -type MsgDataToMongoByMQ struct { - LastSeq uint64 `protobuf:"varint,1,opt,name=lastSeq" json:"lastSeq,omitempty"` - AggregationID string `protobuf:"bytes,2,opt,name=aggregationID" json:"aggregationID,omitempty"` - MessageList []*MsgDataToMQ `protobuf:"bytes,3,rep,name=messageList" json:"messageList,omitempty"` - TriggerID string `protobuf:"bytes,4,opt,name=triggerID" json:"triggerID,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *MsgDataToMongoByMQ) Reset() { *m = MsgDataToMongoByMQ{} } -func (m *MsgDataToMongoByMQ) String() string { return proto.CompactTextString(m) } -func (*MsgDataToMongoByMQ) ProtoMessage() {} -func (*MsgDataToMongoByMQ) Descriptor() ([]byte, []int) { - return fileDescriptor_msg_53ecdffb017d9c40, []int{3} -} -func (m *MsgDataToMongoByMQ) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_MsgDataToMongoByMQ.Unmarshal(m, b) -} -func (m *MsgDataToMongoByMQ) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_MsgDataToMongoByMQ.Marshal(b, m, deterministic) -} -func (dst *MsgDataToMongoByMQ) XXX_Merge(src proto.Message) { - xxx_messageInfo_MsgDataToMongoByMQ.Merge(dst, src) -} -func (m *MsgDataToMongoByMQ) XXX_Size() int { - return xxx_messageInfo_MsgDataToMongoByMQ.Size(m) -} -func (m *MsgDataToMongoByMQ) XXX_DiscardUnknown() { - xxx_messageInfo_MsgDataToMongoByMQ.DiscardUnknown(m) -} - -var xxx_messageInfo_MsgDataToMongoByMQ proto.InternalMessageInfo - -func (m *MsgDataToMongoByMQ) GetLastSeq() uint64 { - if m != nil { - return m.LastSeq - } - return 0 -} - -func (m *MsgDataToMongoByMQ) GetAggregationID() string { - if m != nil { - return m.AggregationID - } - return "" -} - -func (m *MsgDataToMongoByMQ) GetMessageList() []*MsgDataToMQ { - if m != nil { - return m.MessageList - } - return nil -} - -func (m *MsgDataToMongoByMQ) GetTriggerID() string { - if m != nil { - return m.TriggerID - } - return "" -} - -// message PullMessageReq { -// string UserID = 1; -// int64 SeqBegin = 2; -// int64 SeqEnd = 3; -// string OperationID = 4; -// } -// -// message PullMessageResp { -// int32 ErrCode = 1; -// string ErrMsg = 2; -// int64 MaxSeq = 3; -// int64 MinSeq = 4; -// repeated GatherFormat SingleUserMsg = 5; -// repeated GatherFormat GroupUserMsg = 6; -// } -// -// message PullMessageBySeqListReq{ -// string UserID = 1; -// string OperationID = 2; -// repeated int64 seqList =3; -// } -type GetMaxAndMinSeqReq struct { - UserID string `protobuf:"bytes,1,opt,name=UserID" json:"UserID,omitempty"` - OperationID string `protobuf:"bytes,2,opt,name=OperationID" json:"OperationID,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *GetMaxAndMinSeqReq) Reset() { *m = GetMaxAndMinSeqReq{} } -func (m *GetMaxAndMinSeqReq) String() string { return proto.CompactTextString(m) } -func (*GetMaxAndMinSeqReq) ProtoMessage() {} -func (*GetMaxAndMinSeqReq) Descriptor() ([]byte, []int) { - return fileDescriptor_msg_53ecdffb017d9c40, []int{4} -} -func (m *GetMaxAndMinSeqReq) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_GetMaxAndMinSeqReq.Unmarshal(m, b) -} -func (m *GetMaxAndMinSeqReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_GetMaxAndMinSeqReq.Marshal(b, m, deterministic) -} -func (dst *GetMaxAndMinSeqReq) XXX_Merge(src proto.Message) { - xxx_messageInfo_GetMaxAndMinSeqReq.Merge(dst, src) -} -func (m *GetMaxAndMinSeqReq) XXX_Size() int { - return xxx_messageInfo_GetMaxAndMinSeqReq.Size(m) -} -func (m *GetMaxAndMinSeqReq) XXX_DiscardUnknown() { - xxx_messageInfo_GetMaxAndMinSeqReq.DiscardUnknown(m) -} - -var xxx_messageInfo_GetMaxAndMinSeqReq proto.InternalMessageInfo - -func (m *GetMaxAndMinSeqReq) GetUserID() string { - if m != nil { - return m.UserID - } - return "" -} - -func (m *GetMaxAndMinSeqReq) GetOperationID() string { - if m != nil { - return m.OperationID - } - return "" -} - -type GetMaxAndMinSeqResp struct { - ErrCode int32 `protobuf:"varint,1,opt,name=ErrCode" json:"ErrCode,omitempty"` - ErrMsg string `protobuf:"bytes,2,opt,name=ErrMsg" json:"ErrMsg,omitempty"` - MaxSeq uint32 `protobuf:"varint,3,opt,name=MaxSeq" json:"MaxSeq,omitempty"` - MinSeq uint32 `protobuf:"varint,4,opt,name=MinSeq" json:"MinSeq,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *GetMaxAndMinSeqResp) Reset() { *m = GetMaxAndMinSeqResp{} } -func (m *GetMaxAndMinSeqResp) String() string { return proto.CompactTextString(m) } -func (*GetMaxAndMinSeqResp) ProtoMessage() {} -func (*GetMaxAndMinSeqResp) Descriptor() ([]byte, []int) { - return fileDescriptor_msg_53ecdffb017d9c40, []int{5} -} -func (m *GetMaxAndMinSeqResp) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_GetMaxAndMinSeqResp.Unmarshal(m, b) -} -func (m *GetMaxAndMinSeqResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_GetMaxAndMinSeqResp.Marshal(b, m, deterministic) -} -func (dst *GetMaxAndMinSeqResp) XXX_Merge(src proto.Message) { - xxx_messageInfo_GetMaxAndMinSeqResp.Merge(dst, src) -} -func (m *GetMaxAndMinSeqResp) XXX_Size() int { - return xxx_messageInfo_GetMaxAndMinSeqResp.Size(m) -} -func (m *GetMaxAndMinSeqResp) XXX_DiscardUnknown() { - xxx_messageInfo_GetMaxAndMinSeqResp.DiscardUnknown(m) -} - -var xxx_messageInfo_GetMaxAndMinSeqResp proto.InternalMessageInfo - -func (m *GetMaxAndMinSeqResp) GetErrCode() int32 { - if m != nil { - return m.ErrCode - } - return 0 -} - -func (m *GetMaxAndMinSeqResp) GetErrMsg() string { - if m != nil { - return m.ErrMsg - } - return "" -} - -func (m *GetMaxAndMinSeqResp) GetMaxSeq() uint32 { - if m != nil { - return m.MaxSeq - } - return 0 -} - -func (m *GetMaxAndMinSeqResp) GetMinSeq() uint32 { - if m != nil { - return m.MinSeq - } - return 0 -} - -type SendMsgReq struct { - Token string `protobuf:"bytes,1,opt,name=token" json:"token,omitempty"` - OperationID string `protobuf:"bytes,2,opt,name=operationID" json:"operationID,omitempty"` - MsgData *sdk_ws.MsgData `protobuf:"bytes,3,opt,name=msgData" json:"msgData,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *SendMsgReq) Reset() { *m = SendMsgReq{} } -func (m *SendMsgReq) String() string { return proto.CompactTextString(m) } -func (*SendMsgReq) ProtoMessage() {} -func (*SendMsgReq) Descriptor() ([]byte, []int) { - return fileDescriptor_msg_53ecdffb017d9c40, []int{6} -} -func (m *SendMsgReq) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_SendMsgReq.Unmarshal(m, b) -} -func (m *SendMsgReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_SendMsgReq.Marshal(b, m, deterministic) -} -func (dst *SendMsgReq) XXX_Merge(src proto.Message) { - xxx_messageInfo_SendMsgReq.Merge(dst, src) -} -func (m *SendMsgReq) XXX_Size() int { - return xxx_messageInfo_SendMsgReq.Size(m) -} -func (m *SendMsgReq) XXX_DiscardUnknown() { - xxx_messageInfo_SendMsgReq.DiscardUnknown(m) -} - -var xxx_messageInfo_SendMsgReq proto.InternalMessageInfo - -func (m *SendMsgReq) GetToken() string { - if m != nil { - return m.Token - } - return "" -} - -func (m *SendMsgReq) GetOperationID() string { - if m != nil { - return m.OperationID - } - return "" -} - -func (m *SendMsgReq) GetMsgData() *sdk_ws.MsgData { - if m != nil { - return m.MsgData - } - return nil -} - -type SendMsgResp struct { - ErrCode int32 `protobuf:"varint,1,opt,name=errCode" json:"errCode,omitempty"` - ErrMsg string `protobuf:"bytes,2,opt,name=errMsg" json:"errMsg,omitempty"` - ServerMsgID string `protobuf:"bytes,4,opt,name=serverMsgID" json:"serverMsgID,omitempty"` - ClientMsgID string `protobuf:"bytes,5,opt,name=clientMsgID" json:"clientMsgID,omitempty"` - SendTime int64 `protobuf:"varint,6,opt,name=sendTime" json:"sendTime,omitempty"` - Ex string `protobuf:"bytes,7,opt,name=ex" json:"ex,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *SendMsgResp) Reset() { *m = SendMsgResp{} } -func (m *SendMsgResp) String() string { return proto.CompactTextString(m) } -func (*SendMsgResp) ProtoMessage() {} -func (*SendMsgResp) Descriptor() ([]byte, []int) { - return fileDescriptor_msg_53ecdffb017d9c40, []int{7} -} -func (m *SendMsgResp) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_SendMsgResp.Unmarshal(m, b) -} -func (m *SendMsgResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_SendMsgResp.Marshal(b, m, deterministic) -} -func (dst *SendMsgResp) XXX_Merge(src proto.Message) { - xxx_messageInfo_SendMsgResp.Merge(dst, src) -} -func (m *SendMsgResp) XXX_Size() int { - return xxx_messageInfo_SendMsgResp.Size(m) -} -func (m *SendMsgResp) XXX_DiscardUnknown() { - xxx_messageInfo_SendMsgResp.DiscardUnknown(m) -} - -var xxx_messageInfo_SendMsgResp proto.InternalMessageInfo - -func (m *SendMsgResp) GetErrCode() int32 { - if m != nil { - return m.ErrCode - } - return 0 -} - -func (m *SendMsgResp) GetErrMsg() string { - if m != nil { - return m.ErrMsg - } - return "" -} - -func (m *SendMsgResp) GetServerMsgID() string { - if m != nil { - return m.ServerMsgID - } - return "" -} - -func (m *SendMsgResp) GetClientMsgID() string { - if m != nil { - return m.ClientMsgID - } - return "" -} - -func (m *SendMsgResp) GetSendTime() int64 { - if m != nil { - return m.SendTime - } - return 0 -} - -func (m *SendMsgResp) GetEx() string { - if m != nil { - return m.Ex - } - return "" -} - -type ClearMsgReq struct { - UserID string `protobuf:"bytes,1,opt,name=userID" json:"userID,omitempty"` - OpUserID string `protobuf:"bytes,2,opt,name=opUserID" json:"opUserID,omitempty"` - OperationID string `protobuf:"bytes,3,opt,name=operationID" json:"operationID,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *ClearMsgReq) Reset() { *m = ClearMsgReq{} } -func (m *ClearMsgReq) String() string { return proto.CompactTextString(m) } -func (*ClearMsgReq) ProtoMessage() {} -func (*ClearMsgReq) Descriptor() ([]byte, []int) { - return fileDescriptor_msg_53ecdffb017d9c40, []int{8} -} -func (m *ClearMsgReq) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_ClearMsgReq.Unmarshal(m, b) -} -func (m *ClearMsgReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_ClearMsgReq.Marshal(b, m, deterministic) -} -func (dst *ClearMsgReq) XXX_Merge(src proto.Message) { - xxx_messageInfo_ClearMsgReq.Merge(dst, src) -} -func (m *ClearMsgReq) XXX_Size() int { - return xxx_messageInfo_ClearMsgReq.Size(m) -} -func (m *ClearMsgReq) XXX_DiscardUnknown() { - xxx_messageInfo_ClearMsgReq.DiscardUnknown(m) -} - -var xxx_messageInfo_ClearMsgReq proto.InternalMessageInfo - -func (m *ClearMsgReq) GetUserID() string { - if m != nil { - return m.UserID - } - return "" -} - -func (m *ClearMsgReq) GetOpUserID() string { - if m != nil { - return m.OpUserID - } - return "" -} - -func (m *ClearMsgReq) GetOperationID() string { - if m != nil { - return m.OperationID - } - return "" -} - -type ClearMsgResp struct { - ErrCode int32 `protobuf:"varint,1,opt,name=errCode" json:"errCode,omitempty"` - ErrMsg string `protobuf:"bytes,2,opt,name=errMsg" json:"errMsg,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *ClearMsgResp) Reset() { *m = ClearMsgResp{} } -func (m *ClearMsgResp) String() string { return proto.CompactTextString(m) } -func (*ClearMsgResp) ProtoMessage() {} -func (*ClearMsgResp) Descriptor() ([]byte, []int) { - return fileDescriptor_msg_53ecdffb017d9c40, []int{9} -} -func (m *ClearMsgResp) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_ClearMsgResp.Unmarshal(m, b) -} -func (m *ClearMsgResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_ClearMsgResp.Marshal(b, m, deterministic) -} -func (dst *ClearMsgResp) XXX_Merge(src proto.Message) { - xxx_messageInfo_ClearMsgResp.Merge(dst, src) -} -func (m *ClearMsgResp) XXX_Size() int { - return xxx_messageInfo_ClearMsgResp.Size(m) -} -func (m *ClearMsgResp) XXX_DiscardUnknown() { - xxx_messageInfo_ClearMsgResp.DiscardUnknown(m) -} - -var xxx_messageInfo_ClearMsgResp proto.InternalMessageInfo - -func (m *ClearMsgResp) GetErrCode() int32 { - if m != nil { - return m.ErrCode - } - return 0 -} - -func (m *ClearMsgResp) GetErrMsg() string { - if m != nil { - return m.ErrMsg - } - return "" -} - -type SetMsgMinSeqReq struct { - UserID string `protobuf:"bytes,1,opt,name=userID" json:"userID,omitempty"` - GroupID string `protobuf:"bytes,2,opt,name=groupID" json:"groupID,omitempty"` - MinSeq uint32 `protobuf:"varint,3,opt,name=minSeq" json:"minSeq,omitempty"` - OperationID string `protobuf:"bytes,4,opt,name=operationID" json:"operationID,omitempty"` - OpUserID string `protobuf:"bytes,5,opt,name=opUserID" json:"opUserID,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *SetMsgMinSeqReq) Reset() { *m = SetMsgMinSeqReq{} } -func (m *SetMsgMinSeqReq) String() string { return proto.CompactTextString(m) } -func (*SetMsgMinSeqReq) ProtoMessage() {} -func (*SetMsgMinSeqReq) Descriptor() ([]byte, []int) { - return fileDescriptor_msg_53ecdffb017d9c40, []int{10} -} -func (m *SetMsgMinSeqReq) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_SetMsgMinSeqReq.Unmarshal(m, b) -} -func (m *SetMsgMinSeqReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_SetMsgMinSeqReq.Marshal(b, m, deterministic) -} -func (dst *SetMsgMinSeqReq) XXX_Merge(src proto.Message) { - xxx_messageInfo_SetMsgMinSeqReq.Merge(dst, src) -} -func (m *SetMsgMinSeqReq) XXX_Size() int { - return xxx_messageInfo_SetMsgMinSeqReq.Size(m) -} -func (m *SetMsgMinSeqReq) XXX_DiscardUnknown() { - xxx_messageInfo_SetMsgMinSeqReq.DiscardUnknown(m) -} - -var xxx_messageInfo_SetMsgMinSeqReq proto.InternalMessageInfo - -func (m *SetMsgMinSeqReq) GetUserID() string { - if m != nil { - return m.UserID - } - return "" -} - -func (m *SetMsgMinSeqReq) GetGroupID() string { - if m != nil { - return m.GroupID - } - return "" -} - -func (m *SetMsgMinSeqReq) GetMinSeq() uint32 { - if m != nil { - return m.MinSeq - } - return 0 -} - -func (m *SetMsgMinSeqReq) GetOperationID() string { - if m != nil { - return m.OperationID - } - return "" -} - -func (m *SetMsgMinSeqReq) GetOpUserID() string { - if m != nil { - return m.OpUserID - } - return "" -} - -type SetMsgMinSeqResp struct { - ErrCode int32 `protobuf:"varint,1,opt,name=errCode" json:"errCode,omitempty"` - ErrMsg string `protobuf:"bytes,2,opt,name=errMsg" json:"errMsg,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *SetMsgMinSeqResp) Reset() { *m = SetMsgMinSeqResp{} } -func (m *SetMsgMinSeqResp) String() string { return proto.CompactTextString(m) } -func (*SetMsgMinSeqResp) ProtoMessage() {} -func (*SetMsgMinSeqResp) Descriptor() ([]byte, []int) { - return fileDescriptor_msg_53ecdffb017d9c40, []int{11} -} -func (m *SetMsgMinSeqResp) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_SetMsgMinSeqResp.Unmarshal(m, b) -} -func (m *SetMsgMinSeqResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_SetMsgMinSeqResp.Marshal(b, m, deterministic) -} -func (dst *SetMsgMinSeqResp) XXX_Merge(src proto.Message) { - xxx_messageInfo_SetMsgMinSeqResp.Merge(dst, src) -} -func (m *SetMsgMinSeqResp) XXX_Size() int { - return xxx_messageInfo_SetMsgMinSeqResp.Size(m) -} -func (m *SetMsgMinSeqResp) XXX_DiscardUnknown() { - xxx_messageInfo_SetMsgMinSeqResp.DiscardUnknown(m) -} - -var xxx_messageInfo_SetMsgMinSeqResp proto.InternalMessageInfo - -func (m *SetMsgMinSeqResp) GetErrCode() int32 { - if m != nil { - return m.ErrCode - } - return 0 -} - -func (m *SetMsgMinSeqResp) GetErrMsg() string { - if m != nil { - return m.ErrMsg - } - return "" -} - -type SetSendMsgStatusReq struct { - OperationID string `protobuf:"bytes,1,opt,name=operationID" json:"operationID,omitempty"` - Status int32 `protobuf:"varint,2,opt,name=status" json:"status,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *SetSendMsgStatusReq) Reset() { *m = SetSendMsgStatusReq{} } -func (m *SetSendMsgStatusReq) String() string { return proto.CompactTextString(m) } -func (*SetSendMsgStatusReq) ProtoMessage() {} -func (*SetSendMsgStatusReq) Descriptor() ([]byte, []int) { - return fileDescriptor_msg_53ecdffb017d9c40, []int{12} -} -func (m *SetSendMsgStatusReq) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_SetSendMsgStatusReq.Unmarshal(m, b) -} -func (m *SetSendMsgStatusReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_SetSendMsgStatusReq.Marshal(b, m, deterministic) -} -func (dst *SetSendMsgStatusReq) XXX_Merge(src proto.Message) { - xxx_messageInfo_SetSendMsgStatusReq.Merge(dst, src) -} -func (m *SetSendMsgStatusReq) XXX_Size() int { - return xxx_messageInfo_SetSendMsgStatusReq.Size(m) -} -func (m *SetSendMsgStatusReq) XXX_DiscardUnknown() { - xxx_messageInfo_SetSendMsgStatusReq.DiscardUnknown(m) -} - -var xxx_messageInfo_SetSendMsgStatusReq proto.InternalMessageInfo - -func (m *SetSendMsgStatusReq) GetOperationID() string { - if m != nil { - return m.OperationID - } - return "" -} - -func (m *SetSendMsgStatusReq) GetStatus() int32 { - if m != nil { - return m.Status - } - return 0 -} - -type SetSendMsgStatusResp struct { - ErrCode int32 `protobuf:"varint,1,opt,name=errCode" json:"errCode,omitempty"` - ErrMsg string `protobuf:"bytes,2,opt,name=errMsg" json:"errMsg,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *SetSendMsgStatusResp) Reset() { *m = SetSendMsgStatusResp{} } -func (m *SetSendMsgStatusResp) String() string { return proto.CompactTextString(m) } -func (*SetSendMsgStatusResp) ProtoMessage() {} -func (*SetSendMsgStatusResp) Descriptor() ([]byte, []int) { - return fileDescriptor_msg_53ecdffb017d9c40, []int{13} -} -func (m *SetSendMsgStatusResp) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_SetSendMsgStatusResp.Unmarshal(m, b) -} -func (m *SetSendMsgStatusResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_SetSendMsgStatusResp.Marshal(b, m, deterministic) -} -func (dst *SetSendMsgStatusResp) XXX_Merge(src proto.Message) { - xxx_messageInfo_SetSendMsgStatusResp.Merge(dst, src) -} -func (m *SetSendMsgStatusResp) XXX_Size() int { - return xxx_messageInfo_SetSendMsgStatusResp.Size(m) -} -func (m *SetSendMsgStatusResp) XXX_DiscardUnknown() { - xxx_messageInfo_SetSendMsgStatusResp.DiscardUnknown(m) -} - -var xxx_messageInfo_SetSendMsgStatusResp proto.InternalMessageInfo - -func (m *SetSendMsgStatusResp) GetErrCode() int32 { - if m != nil { - return m.ErrCode - } - return 0 -} - -func (m *SetSendMsgStatusResp) GetErrMsg() string { - if m != nil { - return m.ErrMsg - } - return "" -} - -type GetSendMsgStatusReq struct { - OperationID string `protobuf:"bytes,1,opt,name=operationID" json:"operationID,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *GetSendMsgStatusReq) Reset() { *m = GetSendMsgStatusReq{} } -func (m *GetSendMsgStatusReq) String() string { return proto.CompactTextString(m) } -func (*GetSendMsgStatusReq) ProtoMessage() {} -func (*GetSendMsgStatusReq) Descriptor() ([]byte, []int) { - return fileDescriptor_msg_53ecdffb017d9c40, []int{14} -} -func (m *GetSendMsgStatusReq) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_GetSendMsgStatusReq.Unmarshal(m, b) -} -func (m *GetSendMsgStatusReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_GetSendMsgStatusReq.Marshal(b, m, deterministic) -} -func (dst *GetSendMsgStatusReq) XXX_Merge(src proto.Message) { - xxx_messageInfo_GetSendMsgStatusReq.Merge(dst, src) -} -func (m *GetSendMsgStatusReq) XXX_Size() int { - return xxx_messageInfo_GetSendMsgStatusReq.Size(m) -} -func (m *GetSendMsgStatusReq) XXX_DiscardUnknown() { - xxx_messageInfo_GetSendMsgStatusReq.DiscardUnknown(m) -} - -var xxx_messageInfo_GetSendMsgStatusReq proto.InternalMessageInfo - -func (m *GetSendMsgStatusReq) GetOperationID() string { - if m != nil { - return m.OperationID - } - return "" -} - -type GetSendMsgStatusResp struct { - ErrCode int32 `protobuf:"varint,1,opt,name=errCode" json:"errCode,omitempty"` - ErrMsg string `protobuf:"bytes,2,opt,name=errMsg" json:"errMsg,omitempty"` - Status int32 `protobuf:"varint,3,opt,name=status" json:"status,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *GetSendMsgStatusResp) Reset() { *m = GetSendMsgStatusResp{} } -func (m *GetSendMsgStatusResp) String() string { return proto.CompactTextString(m) } -func (*GetSendMsgStatusResp) ProtoMessage() {} -func (*GetSendMsgStatusResp) Descriptor() ([]byte, []int) { - return fileDescriptor_msg_53ecdffb017d9c40, []int{15} -} -func (m *GetSendMsgStatusResp) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_GetSendMsgStatusResp.Unmarshal(m, b) -} -func (m *GetSendMsgStatusResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_GetSendMsgStatusResp.Marshal(b, m, deterministic) -} -func (dst *GetSendMsgStatusResp) XXX_Merge(src proto.Message) { - xxx_messageInfo_GetSendMsgStatusResp.Merge(dst, src) -} -func (m *GetSendMsgStatusResp) XXX_Size() int { - return xxx_messageInfo_GetSendMsgStatusResp.Size(m) -} -func (m *GetSendMsgStatusResp) XXX_DiscardUnknown() { - xxx_messageInfo_GetSendMsgStatusResp.DiscardUnknown(m) -} - -var xxx_messageInfo_GetSendMsgStatusResp proto.InternalMessageInfo - -func (m *GetSendMsgStatusResp) GetErrCode() int32 { - if m != nil { - return m.ErrCode - } - return 0 -} - -func (m *GetSendMsgStatusResp) GetErrMsg() string { - if m != nil { - return m.ErrMsg - } - return "" -} - -func (m *GetSendMsgStatusResp) GetStatus() int32 { - if m != nil { - return m.Status - } - return 0 -} - -type DelSuperGroupMsgReq struct { - OpUserID string `protobuf:"bytes,1,opt,name=opUserID" json:"opUserID,omitempty"` - UserID string `protobuf:"bytes,2,opt,name=userID" json:"userID,omitempty"` - GroupID string `protobuf:"bytes,3,opt,name=groupID" json:"groupID,omitempty"` - OperationID string `protobuf:"bytes,4,opt,name=operationID" json:"operationID,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *DelSuperGroupMsgReq) Reset() { *m = DelSuperGroupMsgReq{} } -func (m *DelSuperGroupMsgReq) String() string { return proto.CompactTextString(m) } -func (*DelSuperGroupMsgReq) ProtoMessage() {} -func (*DelSuperGroupMsgReq) Descriptor() ([]byte, []int) { - return fileDescriptor_msg_53ecdffb017d9c40, []int{16} -} -func (m *DelSuperGroupMsgReq) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_DelSuperGroupMsgReq.Unmarshal(m, b) -} -func (m *DelSuperGroupMsgReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_DelSuperGroupMsgReq.Marshal(b, m, deterministic) -} -func (dst *DelSuperGroupMsgReq) XXX_Merge(src proto.Message) { - xxx_messageInfo_DelSuperGroupMsgReq.Merge(dst, src) -} -func (m *DelSuperGroupMsgReq) XXX_Size() int { - return xxx_messageInfo_DelSuperGroupMsgReq.Size(m) -} -func (m *DelSuperGroupMsgReq) XXX_DiscardUnknown() { - xxx_messageInfo_DelSuperGroupMsgReq.DiscardUnknown(m) -} - -var xxx_messageInfo_DelSuperGroupMsgReq proto.InternalMessageInfo - -func (m *DelSuperGroupMsgReq) GetOpUserID() string { - if m != nil { - return m.OpUserID - } - return "" -} - -func (m *DelSuperGroupMsgReq) GetUserID() string { - if m != nil { - return m.UserID - } - return "" -} - -func (m *DelSuperGroupMsgReq) GetGroupID() string { - if m != nil { - return m.GroupID - } - return "" -} - -func (m *DelSuperGroupMsgReq) GetOperationID() string { - if m != nil { - return m.OperationID - } - return "" -} - -type DelSuperGroupMsgResp struct { - ErrCode int32 `protobuf:"varint,1,opt,name=errCode" json:"errCode,omitempty"` - ErrMsg string `protobuf:"bytes,2,opt,name=errMsg" json:"errMsg,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *DelSuperGroupMsgResp) Reset() { *m = DelSuperGroupMsgResp{} } -func (m *DelSuperGroupMsgResp) String() string { return proto.CompactTextString(m) } -func (*DelSuperGroupMsgResp) ProtoMessage() {} -func (*DelSuperGroupMsgResp) Descriptor() ([]byte, []int) { - return fileDescriptor_msg_53ecdffb017d9c40, []int{17} -} -func (m *DelSuperGroupMsgResp) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_DelSuperGroupMsgResp.Unmarshal(m, b) -} -func (m *DelSuperGroupMsgResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_DelSuperGroupMsgResp.Marshal(b, m, deterministic) -} -func (dst *DelSuperGroupMsgResp) XXX_Merge(src proto.Message) { - xxx_messageInfo_DelSuperGroupMsgResp.Merge(dst, src) -} -func (m *DelSuperGroupMsgResp) XXX_Size() int { - return xxx_messageInfo_DelSuperGroupMsgResp.Size(m) -} -func (m *DelSuperGroupMsgResp) XXX_DiscardUnknown() { - xxx_messageInfo_DelSuperGroupMsgResp.DiscardUnknown(m) -} - -var xxx_messageInfo_DelSuperGroupMsgResp proto.InternalMessageInfo - -func (m *DelSuperGroupMsgResp) GetErrCode() int32 { - if m != nil { - return m.ErrCode - } - return 0 -} - -func (m *DelSuperGroupMsgResp) GetErrMsg() string { - if m != nil { - return m.ErrMsg - } - return "" -} - -type GetSuperGroupMsgReq struct { - OperationID string `protobuf:"bytes,1,opt,name=operationID" json:"operationID,omitempty"` - Seq uint32 `protobuf:"varint,2,opt,name=Seq" json:"Seq,omitempty"` - GroupID string `protobuf:"bytes,3,opt,name=groupID" json:"groupID,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *GetSuperGroupMsgReq) Reset() { *m = GetSuperGroupMsgReq{} } -func (m *GetSuperGroupMsgReq) String() string { return proto.CompactTextString(m) } -func (*GetSuperGroupMsgReq) ProtoMessage() {} -func (*GetSuperGroupMsgReq) Descriptor() ([]byte, []int) { - return fileDescriptor_msg_53ecdffb017d9c40, []int{18} -} -func (m *GetSuperGroupMsgReq) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_GetSuperGroupMsgReq.Unmarshal(m, b) -} -func (m *GetSuperGroupMsgReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_GetSuperGroupMsgReq.Marshal(b, m, deterministic) -} -func (dst *GetSuperGroupMsgReq) XXX_Merge(src proto.Message) { - xxx_messageInfo_GetSuperGroupMsgReq.Merge(dst, src) -} -func (m *GetSuperGroupMsgReq) XXX_Size() int { - return xxx_messageInfo_GetSuperGroupMsgReq.Size(m) -} -func (m *GetSuperGroupMsgReq) XXX_DiscardUnknown() { - xxx_messageInfo_GetSuperGroupMsgReq.DiscardUnknown(m) -} - -var xxx_messageInfo_GetSuperGroupMsgReq proto.InternalMessageInfo - -func (m *GetSuperGroupMsgReq) GetOperationID() string { - if m != nil { - return m.OperationID - } - return "" -} - -func (m *GetSuperGroupMsgReq) GetSeq() uint32 { - if m != nil { - return m.Seq - } - return 0 -} - -func (m *GetSuperGroupMsgReq) GetGroupID() string { - if m != nil { - return m.GroupID - } - return "" -} - -type GetSuperGroupMsgResp struct { - ErrCode int32 `protobuf:"varint,1,opt,name=errCode" json:"errCode,omitempty"` - ErrMsg string `protobuf:"bytes,2,opt,name=errMsg" json:"errMsg,omitempty"` - MsgData *sdk_ws.MsgData `protobuf:"bytes,3,opt,name=msgData" json:"msgData,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *GetSuperGroupMsgResp) Reset() { *m = GetSuperGroupMsgResp{} } -func (m *GetSuperGroupMsgResp) String() string { return proto.CompactTextString(m) } -func (*GetSuperGroupMsgResp) ProtoMessage() {} -func (*GetSuperGroupMsgResp) Descriptor() ([]byte, []int) { - return fileDescriptor_msg_53ecdffb017d9c40, []int{19} -} -func (m *GetSuperGroupMsgResp) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_GetSuperGroupMsgResp.Unmarshal(m, b) -} -func (m *GetSuperGroupMsgResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_GetSuperGroupMsgResp.Marshal(b, m, deterministic) -} -func (dst *GetSuperGroupMsgResp) XXX_Merge(src proto.Message) { - xxx_messageInfo_GetSuperGroupMsgResp.Merge(dst, src) -} -func (m *GetSuperGroupMsgResp) XXX_Size() int { - return xxx_messageInfo_GetSuperGroupMsgResp.Size(m) -} -func (m *GetSuperGroupMsgResp) XXX_DiscardUnknown() { - xxx_messageInfo_GetSuperGroupMsgResp.DiscardUnknown(m) -} - -var xxx_messageInfo_GetSuperGroupMsgResp proto.InternalMessageInfo - -func (m *GetSuperGroupMsgResp) GetErrCode() int32 { - if m != nil { - return m.ErrCode - } - return 0 -} - -func (m *GetSuperGroupMsgResp) GetErrMsg() string { - if m != nil { - return m.ErrMsg - } - return "" -} - -func (m *GetSuperGroupMsgResp) GetMsgData() *sdk_ws.MsgData { - if m != nil { - return m.MsgData - } - return nil -} - -type GetWriteDiffMsgReq struct { - OperationID string `protobuf:"bytes,1,opt,name=operationID" json:"operationID,omitempty"` - Seq uint32 `protobuf:"varint,2,opt,name=Seq" json:"Seq,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *GetWriteDiffMsgReq) Reset() { *m = GetWriteDiffMsgReq{} } -func (m *GetWriteDiffMsgReq) String() string { return proto.CompactTextString(m) } -func (*GetWriteDiffMsgReq) ProtoMessage() {} -func (*GetWriteDiffMsgReq) Descriptor() ([]byte, []int) { - return fileDescriptor_msg_53ecdffb017d9c40, []int{20} -} -func (m *GetWriteDiffMsgReq) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_GetWriteDiffMsgReq.Unmarshal(m, b) -} -func (m *GetWriteDiffMsgReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_GetWriteDiffMsgReq.Marshal(b, m, deterministic) -} -func (dst *GetWriteDiffMsgReq) XXX_Merge(src proto.Message) { - xxx_messageInfo_GetWriteDiffMsgReq.Merge(dst, src) -} -func (m *GetWriteDiffMsgReq) XXX_Size() int { - return xxx_messageInfo_GetWriteDiffMsgReq.Size(m) -} -func (m *GetWriteDiffMsgReq) XXX_DiscardUnknown() { - xxx_messageInfo_GetWriteDiffMsgReq.DiscardUnknown(m) -} - -var xxx_messageInfo_GetWriteDiffMsgReq proto.InternalMessageInfo - -func (m *GetWriteDiffMsgReq) GetOperationID() string { - if m != nil { - return m.OperationID - } - return "" -} - -func (m *GetWriteDiffMsgReq) GetSeq() uint32 { - if m != nil { - return m.Seq - } - return 0 -} - -type GetWriteDiffMsgResp struct { - ErrCode int32 `protobuf:"varint,1,opt,name=errCode" json:"errCode,omitempty"` - ErrMsg string `protobuf:"bytes,2,opt,name=errMsg" json:"errMsg,omitempty"` - MsgData *sdk_ws.MsgData `protobuf:"bytes,3,opt,name=msgData" json:"msgData,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *GetWriteDiffMsgResp) Reset() { *m = GetWriteDiffMsgResp{} } -func (m *GetWriteDiffMsgResp) String() string { return proto.CompactTextString(m) } -func (*GetWriteDiffMsgResp) ProtoMessage() {} -func (*GetWriteDiffMsgResp) Descriptor() ([]byte, []int) { - return fileDescriptor_msg_53ecdffb017d9c40, []int{21} -} -func (m *GetWriteDiffMsgResp) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_GetWriteDiffMsgResp.Unmarshal(m, b) -} -func (m *GetWriteDiffMsgResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_GetWriteDiffMsgResp.Marshal(b, m, deterministic) -} -func (dst *GetWriteDiffMsgResp) XXX_Merge(src proto.Message) { - xxx_messageInfo_GetWriteDiffMsgResp.Merge(dst, src) -} -func (m *GetWriteDiffMsgResp) XXX_Size() int { - return xxx_messageInfo_GetWriteDiffMsgResp.Size(m) -} -func (m *GetWriteDiffMsgResp) XXX_DiscardUnknown() { - xxx_messageInfo_GetWriteDiffMsgResp.DiscardUnknown(m) -} - -var xxx_messageInfo_GetWriteDiffMsgResp proto.InternalMessageInfo - -func (m *GetWriteDiffMsgResp) GetErrCode() int32 { - if m != nil { - return m.ErrCode - } - return 0 -} - -func (m *GetWriteDiffMsgResp) GetErrMsg() string { - if m != nil { - return m.ErrMsg - } - return "" -} - -func (m *GetWriteDiffMsgResp) GetMsgData() *sdk_ws.MsgData { - if m != nil { - return m.MsgData - } - return nil -} - -type ModifyMessageReactionExtensionsReq struct { - OperationID string `protobuf:"bytes,1,opt,name=operationID" json:"operationID,omitempty"` - SourceID string `protobuf:"bytes,2,opt,name=sourceID" json:"sourceID,omitempty"` - OpUserID string `protobuf:"bytes,3,opt,name=opUserID" json:"opUserID,omitempty"` - SessionType int32 `protobuf:"varint,4,opt,name=sessionType" json:"sessionType,omitempty"` - ReactionExtensionList map[string]*sdk_ws.KeyValue `protobuf:"bytes,5,rep,name=reactionExtensionList" json:"reactionExtensionList,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` - ClientMsgID string `protobuf:"bytes,6,opt,name=clientMsgID" json:"clientMsgID,omitempty"` - Ex *wrapperspb.StringValue `protobuf:"bytes,7,opt,name=ex" json:"ex,omitempty"` - AttachedInfo *wrapperspb.StringValue `protobuf:"bytes,8,opt,name=attachedInfo" json:"attachedInfo,omitempty"` - IsReact bool `protobuf:"varint,9,opt,name=isReact" json:"isReact,omitempty"` - IsExternalExtensions bool `protobuf:"varint,10,opt,name=isExternalExtensions" json:"isExternalExtensions,omitempty"` - MsgFirstModifyTime int64 `protobuf:"varint,11,opt,name=msgFirstModifyTime" json:"msgFirstModifyTime,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *ModifyMessageReactionExtensionsReq) Reset() { *m = ModifyMessageReactionExtensionsReq{} } -func (m *ModifyMessageReactionExtensionsReq) String() string { return proto.CompactTextString(m) } -func (*ModifyMessageReactionExtensionsReq) ProtoMessage() {} -func (*ModifyMessageReactionExtensionsReq) Descriptor() ([]byte, []int) { - return fileDescriptor_msg_53ecdffb017d9c40, []int{22} -} -func (m *ModifyMessageReactionExtensionsReq) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_ModifyMessageReactionExtensionsReq.Unmarshal(m, b) -} -func (m *ModifyMessageReactionExtensionsReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_ModifyMessageReactionExtensionsReq.Marshal(b, m, deterministic) -} -func (dst *ModifyMessageReactionExtensionsReq) XXX_Merge(src proto.Message) { - xxx_messageInfo_ModifyMessageReactionExtensionsReq.Merge(dst, src) -} -func (m *ModifyMessageReactionExtensionsReq) XXX_Size() int { - return xxx_messageInfo_ModifyMessageReactionExtensionsReq.Size(m) -} -func (m *ModifyMessageReactionExtensionsReq) XXX_DiscardUnknown() { - xxx_messageInfo_ModifyMessageReactionExtensionsReq.DiscardUnknown(m) -} - -var xxx_messageInfo_ModifyMessageReactionExtensionsReq proto.InternalMessageInfo - -func (m *ModifyMessageReactionExtensionsReq) GetOperationID() string { - if m != nil { - return m.OperationID - } - return "" -} - -func (m *ModifyMessageReactionExtensionsReq) GetSourceID() string { - if m != nil { - return m.SourceID - } - return "" -} - -func (m *ModifyMessageReactionExtensionsReq) GetOpUserID() string { - if m != nil { - return m.OpUserID - } - return "" -} - -func (m *ModifyMessageReactionExtensionsReq) GetSessionType() int32 { - if m != nil { - return m.SessionType - } - return 0 -} - -func (m *ModifyMessageReactionExtensionsReq) GetReactionExtensionList() map[string]*sdk_ws.KeyValue { - if m != nil { - return m.ReactionExtensionList - } - return nil -} - -func (m *ModifyMessageReactionExtensionsReq) GetClientMsgID() string { - if m != nil { - return m.ClientMsgID - } - return "" -} - -func (m *ModifyMessageReactionExtensionsReq) GetEx() *wrapperspb.StringValue { - if m != nil { - return m.Ex - } - return nil -} - -func (m *ModifyMessageReactionExtensionsReq) GetAttachedInfo() *wrapperspb.StringValue { - if m != nil { - return m.AttachedInfo - } - return nil -} - -func (m *ModifyMessageReactionExtensionsReq) GetIsReact() bool { - if m != nil { - return m.IsReact - } - return false -} - -func (m *ModifyMessageReactionExtensionsReq) GetIsExternalExtensions() bool { - if m != nil { - return m.IsExternalExtensions - } - return false -} - -func (m *ModifyMessageReactionExtensionsReq) GetMsgFirstModifyTime() int64 { - if m != nil { - return m.MsgFirstModifyTime - } - return 0 -} - -type SetMessageReactionExtensionsReq struct { - OperationID string `protobuf:"bytes,1,opt,name=operationID" json:"operationID,omitempty"` - SourceID string `protobuf:"bytes,2,opt,name=sourceID" json:"sourceID,omitempty"` - OpUserID string `protobuf:"bytes,3,opt,name=opUserID" json:"opUserID,omitempty"` - OpUserIDPlatformID int32 `protobuf:"varint,4,opt,name=opUserIDPlatformID" json:"opUserIDPlatformID,omitempty"` - SessionType int32 `protobuf:"varint,5,opt,name=sessionType" json:"sessionType,omitempty"` - ReactionExtensionList map[string]*sdk_ws.KeyValue `protobuf:"bytes,6,rep,name=reactionExtensionList" json:"reactionExtensionList,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` - ClientMsgID string `protobuf:"bytes,7,opt,name=clientMsgID" json:"clientMsgID,omitempty"` - Ex *wrapperspb.StringValue `protobuf:"bytes,8,opt,name=ex" json:"ex,omitempty"` - AttachedInfo *wrapperspb.StringValue `protobuf:"bytes,9,opt,name=attachedInfo" json:"attachedInfo,omitempty"` - IsReact bool `protobuf:"varint,10,opt,name=isReact" json:"isReact,omitempty"` - IsExternalExtensions bool `protobuf:"varint,11,opt,name=isExternalExtensions" json:"isExternalExtensions,omitempty"` - MsgFirstModifyTime int64 `protobuf:"varint,12,opt,name=msgFirstModifyTime" json:"msgFirstModifyTime,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *SetMessageReactionExtensionsReq) Reset() { *m = SetMessageReactionExtensionsReq{} } -func (m *SetMessageReactionExtensionsReq) String() string { return proto.CompactTextString(m) } -func (*SetMessageReactionExtensionsReq) ProtoMessage() {} -func (*SetMessageReactionExtensionsReq) Descriptor() ([]byte, []int) { - return fileDescriptor_msg_53ecdffb017d9c40, []int{23} -} -func (m *SetMessageReactionExtensionsReq) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_SetMessageReactionExtensionsReq.Unmarshal(m, b) -} -func (m *SetMessageReactionExtensionsReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_SetMessageReactionExtensionsReq.Marshal(b, m, deterministic) -} -func (dst *SetMessageReactionExtensionsReq) XXX_Merge(src proto.Message) { - xxx_messageInfo_SetMessageReactionExtensionsReq.Merge(dst, src) -} -func (m *SetMessageReactionExtensionsReq) XXX_Size() int { - return xxx_messageInfo_SetMessageReactionExtensionsReq.Size(m) -} -func (m *SetMessageReactionExtensionsReq) XXX_DiscardUnknown() { - xxx_messageInfo_SetMessageReactionExtensionsReq.DiscardUnknown(m) -} - -var xxx_messageInfo_SetMessageReactionExtensionsReq proto.InternalMessageInfo - -func (m *SetMessageReactionExtensionsReq) GetOperationID() string { - if m != nil { - return m.OperationID - } - return "" -} - -func (m *SetMessageReactionExtensionsReq) GetSourceID() string { - if m != nil { - return m.SourceID - } - return "" -} - -func (m *SetMessageReactionExtensionsReq) GetOpUserID() string { - if m != nil { - return m.OpUserID - } - return "" -} - -func (m *SetMessageReactionExtensionsReq) GetOpUserIDPlatformID() int32 { - if m != nil { - return m.OpUserIDPlatformID - } - return 0 -} - -func (m *SetMessageReactionExtensionsReq) GetSessionType() int32 { - if m != nil { - return m.SessionType - } - return 0 -} - -func (m *SetMessageReactionExtensionsReq) GetReactionExtensionList() map[string]*sdk_ws.KeyValue { - if m != nil { - return m.ReactionExtensionList - } - return nil -} - -func (m *SetMessageReactionExtensionsReq) GetClientMsgID() string { - if m != nil { - return m.ClientMsgID - } - return "" -} - -func (m *SetMessageReactionExtensionsReq) GetEx() *wrapperspb.StringValue { - if m != nil { - return m.Ex - } - return nil -} - -func (m *SetMessageReactionExtensionsReq) GetAttachedInfo() *wrapperspb.StringValue { - if m != nil { - return m.AttachedInfo - } - return nil -} - -func (m *SetMessageReactionExtensionsReq) GetIsReact() bool { - if m != nil { - return m.IsReact - } - return false -} - -func (m *SetMessageReactionExtensionsReq) GetIsExternalExtensions() bool { - if m != nil { - return m.IsExternalExtensions - } - return false -} - -func (m *SetMessageReactionExtensionsReq) GetMsgFirstModifyTime() int64 { - if m != nil { - return m.MsgFirstModifyTime - } - return 0 -} - -type SetMessageReactionExtensionsResp struct { - ErrCode int32 `protobuf:"varint,1,opt,name=errCode" json:"errCode,omitempty"` - ErrMsg string `protobuf:"bytes,2,opt,name=errMsg" json:"errMsg,omitempty"` - ClientMsgID string `protobuf:"bytes,3,opt,name=clientMsgID" json:"clientMsgID,omitempty"` - MsgFirstModifyTime int64 `protobuf:"varint,4,opt,name=msgFirstModifyTime" json:"msgFirstModifyTime,omitempty"` - IsReact bool `protobuf:"varint,5,opt,name=isReact" json:"isReact,omitempty"` - Result []*KeyValueResp `protobuf:"bytes,6,rep,name=result" json:"result,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *SetMessageReactionExtensionsResp) Reset() { *m = SetMessageReactionExtensionsResp{} } -func (m *SetMessageReactionExtensionsResp) String() string { return proto.CompactTextString(m) } -func (*SetMessageReactionExtensionsResp) ProtoMessage() {} -func (*SetMessageReactionExtensionsResp) Descriptor() ([]byte, []int) { - return fileDescriptor_msg_53ecdffb017d9c40, []int{24} -} -func (m *SetMessageReactionExtensionsResp) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_SetMessageReactionExtensionsResp.Unmarshal(m, b) -} -func (m *SetMessageReactionExtensionsResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_SetMessageReactionExtensionsResp.Marshal(b, m, deterministic) -} -func (dst *SetMessageReactionExtensionsResp) XXX_Merge(src proto.Message) { - xxx_messageInfo_SetMessageReactionExtensionsResp.Merge(dst, src) -} -func (m *SetMessageReactionExtensionsResp) XXX_Size() int { - return xxx_messageInfo_SetMessageReactionExtensionsResp.Size(m) -} -func (m *SetMessageReactionExtensionsResp) XXX_DiscardUnknown() { - xxx_messageInfo_SetMessageReactionExtensionsResp.DiscardUnknown(m) -} - -var xxx_messageInfo_SetMessageReactionExtensionsResp proto.InternalMessageInfo - -func (m *SetMessageReactionExtensionsResp) GetErrCode() int32 { - if m != nil { - return m.ErrCode - } - return 0 -} - -func (m *SetMessageReactionExtensionsResp) GetErrMsg() string { - if m != nil { - return m.ErrMsg - } - return "" -} - -func (m *SetMessageReactionExtensionsResp) GetClientMsgID() string { - if m != nil { - return m.ClientMsgID - } - return "" -} - -func (m *SetMessageReactionExtensionsResp) GetMsgFirstModifyTime() int64 { - if m != nil { - return m.MsgFirstModifyTime - } - return 0 -} - -func (m *SetMessageReactionExtensionsResp) GetIsReact() bool { - if m != nil { - return m.IsReact - } - return false -} - -func (m *SetMessageReactionExtensionsResp) GetResult() []*KeyValueResp { - if m != nil { - return m.Result - } - return nil -} - -type AddMessageReactionExtensionsReq struct { - OperationID string `protobuf:"bytes,1,opt,name=operationID" json:"operationID,omitempty"` - SourceID string `protobuf:"bytes,2,opt,name=sourceID" json:"sourceID,omitempty"` - OpUserID string `protobuf:"bytes,3,opt,name=opUserID" json:"opUserID,omitempty"` - OpUserIDPlatformID int32 `protobuf:"varint,4,opt,name=opUserIDPlatformID" json:"opUserIDPlatformID,omitempty"` - SessionType int32 `protobuf:"varint,5,opt,name=sessionType" json:"sessionType,omitempty"` - ReactionExtensionList map[string]*sdk_ws.KeyValue `protobuf:"bytes,6,rep,name=reactionExtensionList" json:"reactionExtensionList,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` - ClientMsgID string `protobuf:"bytes,7,opt,name=clientMsgID" json:"clientMsgID,omitempty"` - Ex *wrapperspb.StringValue `protobuf:"bytes,8,opt,name=ex" json:"ex,omitempty"` - AttachedInfo *wrapperspb.StringValue `protobuf:"bytes,9,opt,name=attachedInfo" json:"attachedInfo,omitempty"` - IsReact bool `protobuf:"varint,10,opt,name=isReact" json:"isReact,omitempty"` - IsExternalExtensions bool `protobuf:"varint,11,opt,name=isExternalExtensions" json:"isExternalExtensions,omitempty"` - MsgFirstModifyTime int64 `protobuf:"varint,12,opt,name=msgFirstModifyTime" json:"msgFirstModifyTime,omitempty"` - Seq uint32 `protobuf:"varint,13,opt,name=seq" json:"seq,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *AddMessageReactionExtensionsReq) Reset() { *m = AddMessageReactionExtensionsReq{} } -func (m *AddMessageReactionExtensionsReq) String() string { return proto.CompactTextString(m) } -func (*AddMessageReactionExtensionsReq) ProtoMessage() {} -func (*AddMessageReactionExtensionsReq) Descriptor() ([]byte, []int) { - return fileDescriptor_msg_53ecdffb017d9c40, []int{25} -} -func (m *AddMessageReactionExtensionsReq) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_AddMessageReactionExtensionsReq.Unmarshal(m, b) -} -func (m *AddMessageReactionExtensionsReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_AddMessageReactionExtensionsReq.Marshal(b, m, deterministic) -} -func (dst *AddMessageReactionExtensionsReq) XXX_Merge(src proto.Message) { - xxx_messageInfo_AddMessageReactionExtensionsReq.Merge(dst, src) -} -func (m *AddMessageReactionExtensionsReq) XXX_Size() int { - return xxx_messageInfo_AddMessageReactionExtensionsReq.Size(m) -} -func (m *AddMessageReactionExtensionsReq) XXX_DiscardUnknown() { - xxx_messageInfo_AddMessageReactionExtensionsReq.DiscardUnknown(m) -} - -var xxx_messageInfo_AddMessageReactionExtensionsReq proto.InternalMessageInfo - -func (m *AddMessageReactionExtensionsReq) GetOperationID() string { - if m != nil { - return m.OperationID - } - return "" -} - -func (m *AddMessageReactionExtensionsReq) GetSourceID() string { - if m != nil { - return m.SourceID - } - return "" -} - -func (m *AddMessageReactionExtensionsReq) GetOpUserID() string { - if m != nil { - return m.OpUserID - } - return "" -} - -func (m *AddMessageReactionExtensionsReq) GetOpUserIDPlatformID() int32 { - if m != nil { - return m.OpUserIDPlatformID - } - return 0 -} - -func (m *AddMessageReactionExtensionsReq) GetSessionType() int32 { - if m != nil { - return m.SessionType - } - return 0 -} - -func (m *AddMessageReactionExtensionsReq) GetReactionExtensionList() map[string]*sdk_ws.KeyValue { - if m != nil { - return m.ReactionExtensionList - } - return nil -} - -func (m *AddMessageReactionExtensionsReq) GetClientMsgID() string { - if m != nil { - return m.ClientMsgID - } - return "" -} - -func (m *AddMessageReactionExtensionsReq) GetEx() *wrapperspb.StringValue { - if m != nil { - return m.Ex - } - return nil -} - -func (m *AddMessageReactionExtensionsReq) GetAttachedInfo() *wrapperspb.StringValue { - if m != nil { - return m.AttachedInfo - } - return nil -} - -func (m *AddMessageReactionExtensionsReq) GetIsReact() bool { - if m != nil { - return m.IsReact - } - return false -} - -func (m *AddMessageReactionExtensionsReq) GetIsExternalExtensions() bool { - if m != nil { - return m.IsExternalExtensions - } - return false -} - -func (m *AddMessageReactionExtensionsReq) GetMsgFirstModifyTime() int64 { - if m != nil { - return m.MsgFirstModifyTime - } - return 0 -} - -func (m *AddMessageReactionExtensionsReq) GetSeq() uint32 { - if m != nil { - return m.Seq - } - return 0 -} - -type AddMessageReactionExtensionsResp struct { - ErrCode int32 `protobuf:"varint,1,opt,name=errCode" json:"errCode,omitempty"` - ErrMsg string `protobuf:"bytes,2,opt,name=errMsg" json:"errMsg,omitempty"` - ClientMsgID string `protobuf:"bytes,3,opt,name=clientMsgID" json:"clientMsgID,omitempty"` - MsgFirstModifyTime int64 `protobuf:"varint,4,opt,name=msgFirstModifyTime" json:"msgFirstModifyTime,omitempty"` - IsReact bool `protobuf:"varint,5,opt,name=isReact" json:"isReact,omitempty"` - Result []*KeyValueResp `protobuf:"bytes,6,rep,name=result" json:"result,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *AddMessageReactionExtensionsResp) Reset() { *m = AddMessageReactionExtensionsResp{} } -func (m *AddMessageReactionExtensionsResp) String() string { return proto.CompactTextString(m) } -func (*AddMessageReactionExtensionsResp) ProtoMessage() {} -func (*AddMessageReactionExtensionsResp) Descriptor() ([]byte, []int) { - return fileDescriptor_msg_53ecdffb017d9c40, []int{26} -} -func (m *AddMessageReactionExtensionsResp) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_AddMessageReactionExtensionsResp.Unmarshal(m, b) -} -func (m *AddMessageReactionExtensionsResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_AddMessageReactionExtensionsResp.Marshal(b, m, deterministic) -} -func (dst *AddMessageReactionExtensionsResp) XXX_Merge(src proto.Message) { - xxx_messageInfo_AddMessageReactionExtensionsResp.Merge(dst, src) -} -func (m *AddMessageReactionExtensionsResp) XXX_Size() int { - return xxx_messageInfo_AddMessageReactionExtensionsResp.Size(m) -} -func (m *AddMessageReactionExtensionsResp) XXX_DiscardUnknown() { - xxx_messageInfo_AddMessageReactionExtensionsResp.DiscardUnknown(m) -} - -var xxx_messageInfo_AddMessageReactionExtensionsResp proto.InternalMessageInfo - -func (m *AddMessageReactionExtensionsResp) GetErrCode() int32 { - if m != nil { - return m.ErrCode - } - return 0 -} - -func (m *AddMessageReactionExtensionsResp) GetErrMsg() string { - if m != nil { - return m.ErrMsg - } - return "" -} - -func (m *AddMessageReactionExtensionsResp) GetClientMsgID() string { - if m != nil { - return m.ClientMsgID - } - return "" -} - -func (m *AddMessageReactionExtensionsResp) GetMsgFirstModifyTime() int64 { - if m != nil { - return m.MsgFirstModifyTime - } - return 0 -} - -func (m *AddMessageReactionExtensionsResp) GetIsReact() bool { - if m != nil { - return m.IsReact - } - return false -} - -func (m *AddMessageReactionExtensionsResp) GetResult() []*KeyValueResp { - if m != nil { - return m.Result - } - return nil -} - -type GetMessageListReactionExtensionsReq struct { - OperationID string `protobuf:"bytes,1,opt,name=operationID" json:"operationID,omitempty"` - OpUserID string `protobuf:"bytes,2,opt,name=opUserID" json:"opUserID,omitempty"` - SourceID string `protobuf:"bytes,3,opt,name=sourceID" json:"sourceID,omitempty"` - SessionType int32 `protobuf:"varint,4,opt,name=sessionType" json:"sessionType,omitempty"` - IsExternalExtensions bool `protobuf:"varint,5,opt,name=isExternalExtensions" json:"isExternalExtensions,omitempty"` - TypeKeyList []string `protobuf:"bytes,6,rep,name=typeKeyList" json:"typeKeyList,omitempty"` - MessageReactionKeyList []*GetMessageListReactionExtensionsReq_MessageReactionKey `protobuf:"bytes,7,rep,name=messageReactionKeyList" json:"messageReactionKeyList,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *GetMessageListReactionExtensionsReq) Reset() { *m = GetMessageListReactionExtensionsReq{} } -func (m *GetMessageListReactionExtensionsReq) String() string { return proto.CompactTextString(m) } -func (*GetMessageListReactionExtensionsReq) ProtoMessage() {} -func (*GetMessageListReactionExtensionsReq) Descriptor() ([]byte, []int) { - return fileDescriptor_msg_53ecdffb017d9c40, []int{27} -} -func (m *GetMessageListReactionExtensionsReq) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_GetMessageListReactionExtensionsReq.Unmarshal(m, b) -} -func (m *GetMessageListReactionExtensionsReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_GetMessageListReactionExtensionsReq.Marshal(b, m, deterministic) -} -func (dst *GetMessageListReactionExtensionsReq) XXX_Merge(src proto.Message) { - xxx_messageInfo_GetMessageListReactionExtensionsReq.Merge(dst, src) -} -func (m *GetMessageListReactionExtensionsReq) XXX_Size() int { - return xxx_messageInfo_GetMessageListReactionExtensionsReq.Size(m) -} -func (m *GetMessageListReactionExtensionsReq) XXX_DiscardUnknown() { - xxx_messageInfo_GetMessageListReactionExtensionsReq.DiscardUnknown(m) -} - -var xxx_messageInfo_GetMessageListReactionExtensionsReq proto.InternalMessageInfo - -func (m *GetMessageListReactionExtensionsReq) GetOperationID() string { - if m != nil { - return m.OperationID - } - return "" -} - -func (m *GetMessageListReactionExtensionsReq) GetOpUserID() string { - if m != nil { - return m.OpUserID - } - return "" -} - -func (m *GetMessageListReactionExtensionsReq) GetSourceID() string { - if m != nil { - return m.SourceID - } - return "" -} - -func (m *GetMessageListReactionExtensionsReq) GetSessionType() int32 { - if m != nil { - return m.SessionType - } - return 0 -} - -func (m *GetMessageListReactionExtensionsReq) GetIsExternalExtensions() bool { - if m != nil { - return m.IsExternalExtensions - } - return false -} - -func (m *GetMessageListReactionExtensionsReq) GetTypeKeyList() []string { - if m != nil { - return m.TypeKeyList - } - return nil -} - -func (m *GetMessageListReactionExtensionsReq) GetMessageReactionKeyList() []*GetMessageListReactionExtensionsReq_MessageReactionKey { - if m != nil { - return m.MessageReactionKeyList - } - return nil -} - -type GetMessageListReactionExtensionsReq_MessageReactionKey struct { - ClientMsgID string `protobuf:"bytes,1,opt,name=clientMsgID" json:"clientMsgID,omitempty"` - MsgFirstModifyTime int64 `protobuf:"varint,2,opt,name=msgFirstModifyTime" json:"msgFirstModifyTime,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *GetMessageListReactionExtensionsReq_MessageReactionKey) Reset() { - *m = GetMessageListReactionExtensionsReq_MessageReactionKey{} -} -func (m *GetMessageListReactionExtensionsReq_MessageReactionKey) String() string { - return proto.CompactTextString(m) -} -func (*GetMessageListReactionExtensionsReq_MessageReactionKey) ProtoMessage() {} -func (*GetMessageListReactionExtensionsReq_MessageReactionKey) Descriptor() ([]byte, []int) { - return fileDescriptor_msg_53ecdffb017d9c40, []int{27, 0} -} -func (m *GetMessageListReactionExtensionsReq_MessageReactionKey) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_GetMessageListReactionExtensionsReq_MessageReactionKey.Unmarshal(m, b) -} -func (m *GetMessageListReactionExtensionsReq_MessageReactionKey) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_GetMessageListReactionExtensionsReq_MessageReactionKey.Marshal(b, m, deterministic) -} -func (dst *GetMessageListReactionExtensionsReq_MessageReactionKey) XXX_Merge(src proto.Message) { - xxx_messageInfo_GetMessageListReactionExtensionsReq_MessageReactionKey.Merge(dst, src) -} -func (m *GetMessageListReactionExtensionsReq_MessageReactionKey) XXX_Size() int { - return xxx_messageInfo_GetMessageListReactionExtensionsReq_MessageReactionKey.Size(m) -} -func (m *GetMessageListReactionExtensionsReq_MessageReactionKey) XXX_DiscardUnknown() { - xxx_messageInfo_GetMessageListReactionExtensionsReq_MessageReactionKey.DiscardUnknown(m) -} - -var xxx_messageInfo_GetMessageListReactionExtensionsReq_MessageReactionKey proto.InternalMessageInfo - -func (m *GetMessageListReactionExtensionsReq_MessageReactionKey) GetClientMsgID() string { - if m != nil { - return m.ClientMsgID - } - return "" -} - -func (m *GetMessageListReactionExtensionsReq_MessageReactionKey) GetMsgFirstModifyTime() int64 { - if m != nil { - return m.MsgFirstModifyTime - } - return 0 -} - -type GetMessageListReactionExtensionsResp struct { - ErrCode int32 `protobuf:"varint,1,opt,name=errCode" json:"errCode,omitempty"` - ErrMsg string `protobuf:"bytes,2,opt,name=errMsg" json:"errMsg,omitempty"` - SingleMessageResult []*SingleMessageExtensionResult `protobuf:"bytes,3,rep,name=singleMessageResult" json:"singleMessageResult,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *GetMessageListReactionExtensionsResp) Reset() { *m = GetMessageListReactionExtensionsResp{} } -func (m *GetMessageListReactionExtensionsResp) String() string { return proto.CompactTextString(m) } -func (*GetMessageListReactionExtensionsResp) ProtoMessage() {} -func (*GetMessageListReactionExtensionsResp) Descriptor() ([]byte, []int) { - return fileDescriptor_msg_53ecdffb017d9c40, []int{28} -} -func (m *GetMessageListReactionExtensionsResp) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_GetMessageListReactionExtensionsResp.Unmarshal(m, b) -} -func (m *GetMessageListReactionExtensionsResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_GetMessageListReactionExtensionsResp.Marshal(b, m, deterministic) -} -func (dst *GetMessageListReactionExtensionsResp) XXX_Merge(src proto.Message) { - xxx_messageInfo_GetMessageListReactionExtensionsResp.Merge(dst, src) -} -func (m *GetMessageListReactionExtensionsResp) XXX_Size() int { - return xxx_messageInfo_GetMessageListReactionExtensionsResp.Size(m) -} -func (m *GetMessageListReactionExtensionsResp) XXX_DiscardUnknown() { - xxx_messageInfo_GetMessageListReactionExtensionsResp.DiscardUnknown(m) -} - -var xxx_messageInfo_GetMessageListReactionExtensionsResp proto.InternalMessageInfo - -func (m *GetMessageListReactionExtensionsResp) GetErrCode() int32 { - if m != nil { - return m.ErrCode - } - return 0 -} - -func (m *GetMessageListReactionExtensionsResp) GetErrMsg() string { - if m != nil { - return m.ErrMsg - } - return "" -} - -func (m *GetMessageListReactionExtensionsResp) GetSingleMessageResult() []*SingleMessageExtensionResult { - if m != nil { - return m.SingleMessageResult - } - return nil -} - -type SingleMessageExtensionResult struct { - ErrCode int32 `protobuf:"varint,1,opt,name=errCode" json:"errCode,omitempty"` - ErrMsg string `protobuf:"bytes,2,opt,name=errMsg" json:"errMsg,omitempty"` - ReactionExtensionList map[string]*sdk_ws.KeyValue `protobuf:"bytes,3,rep,name=reactionExtensionList" json:"reactionExtensionList,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` - ClientMsgID string `protobuf:"bytes,4,opt,name=clientMsgID" json:"clientMsgID,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *SingleMessageExtensionResult) Reset() { *m = SingleMessageExtensionResult{} } -func (m *SingleMessageExtensionResult) String() string { return proto.CompactTextString(m) } -func (*SingleMessageExtensionResult) ProtoMessage() {} -func (*SingleMessageExtensionResult) Descriptor() ([]byte, []int) { - return fileDescriptor_msg_53ecdffb017d9c40, []int{29} -} -func (m *SingleMessageExtensionResult) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_SingleMessageExtensionResult.Unmarshal(m, b) -} -func (m *SingleMessageExtensionResult) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_SingleMessageExtensionResult.Marshal(b, m, deterministic) -} -func (dst *SingleMessageExtensionResult) XXX_Merge(src proto.Message) { - xxx_messageInfo_SingleMessageExtensionResult.Merge(dst, src) -} -func (m *SingleMessageExtensionResult) XXX_Size() int { - return xxx_messageInfo_SingleMessageExtensionResult.Size(m) -} -func (m *SingleMessageExtensionResult) XXX_DiscardUnknown() { - xxx_messageInfo_SingleMessageExtensionResult.DiscardUnknown(m) -} - -var xxx_messageInfo_SingleMessageExtensionResult proto.InternalMessageInfo - -func (m *SingleMessageExtensionResult) GetErrCode() int32 { - if m != nil { - return m.ErrCode - } - return 0 -} - -func (m *SingleMessageExtensionResult) GetErrMsg() string { - if m != nil { - return m.ErrMsg - } - return "" -} - -func (m *SingleMessageExtensionResult) GetReactionExtensionList() map[string]*sdk_ws.KeyValue { - if m != nil { - return m.ReactionExtensionList - } - return nil -} - -func (m *SingleMessageExtensionResult) GetClientMsgID() string { - if m != nil { - return m.ClientMsgID - } - return "" -} - -type ModifyMessageReactionExtensionsResp struct { - ErrCode int32 `protobuf:"varint,1,opt,name=errCode" json:"errCode,omitempty"` - ErrMsg string `protobuf:"bytes,2,opt,name=errMsg" json:"errMsg,omitempty"` - SuccessList []*ExtendMsgResp `protobuf:"bytes,3,rep,name=successList" json:"successList,omitempty"` - FailedList []*ExtendMsgResp `protobuf:"bytes,4,rep,name=failedList" json:"failedList,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *ModifyMessageReactionExtensionsResp) Reset() { *m = ModifyMessageReactionExtensionsResp{} } -func (m *ModifyMessageReactionExtensionsResp) String() string { return proto.CompactTextString(m) } -func (*ModifyMessageReactionExtensionsResp) ProtoMessage() {} -func (*ModifyMessageReactionExtensionsResp) Descriptor() ([]byte, []int) { - return fileDescriptor_msg_53ecdffb017d9c40, []int{30} -} -func (m *ModifyMessageReactionExtensionsResp) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_ModifyMessageReactionExtensionsResp.Unmarshal(m, b) -} -func (m *ModifyMessageReactionExtensionsResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_ModifyMessageReactionExtensionsResp.Marshal(b, m, deterministic) -} -func (dst *ModifyMessageReactionExtensionsResp) XXX_Merge(src proto.Message) { - xxx_messageInfo_ModifyMessageReactionExtensionsResp.Merge(dst, src) -} -func (m *ModifyMessageReactionExtensionsResp) XXX_Size() int { - return xxx_messageInfo_ModifyMessageReactionExtensionsResp.Size(m) -} -func (m *ModifyMessageReactionExtensionsResp) XXX_DiscardUnknown() { - xxx_messageInfo_ModifyMessageReactionExtensionsResp.DiscardUnknown(m) -} - -var xxx_messageInfo_ModifyMessageReactionExtensionsResp proto.InternalMessageInfo - -func (m *ModifyMessageReactionExtensionsResp) GetErrCode() int32 { - if m != nil { - return m.ErrCode - } - return 0 -} - -func (m *ModifyMessageReactionExtensionsResp) GetErrMsg() string { - if m != nil { - return m.ErrMsg - } - return "" -} - -func (m *ModifyMessageReactionExtensionsResp) GetSuccessList() []*ExtendMsgResp { - if m != nil { - return m.SuccessList - } - return nil -} - -func (m *ModifyMessageReactionExtensionsResp) GetFailedList() []*ExtendMsgResp { - if m != nil { - return m.FailedList - } - return nil -} - -type DeleteMessageListReactionExtensionsReq struct { - OperationID string `protobuf:"bytes,1,opt,name=operationID" json:"operationID,omitempty"` - OpUserID string `protobuf:"bytes,2,opt,name=opUserID" json:"opUserID,omitempty"` - SourceID string `protobuf:"bytes,3,opt,name=sourceID" json:"sourceID,omitempty"` - OpUserIDPlatformID int32 `protobuf:"varint,4,opt,name=opUserIDPlatformID" json:"opUserIDPlatformID,omitempty"` - SessionType int32 `protobuf:"varint,5,opt,name=sessionType" json:"sessionType,omitempty"` - ClientMsgID string `protobuf:"bytes,6,opt,name=clientMsgID" json:"clientMsgID,omitempty"` - IsExternalExtensions bool `protobuf:"varint,7,opt,name=isExternalExtensions" json:"isExternalExtensions,omitempty"` - MsgFirstModifyTime int64 `protobuf:"varint,8,opt,name=msgFirstModifyTime" json:"msgFirstModifyTime,omitempty"` - ReactionExtensionList []*sdk_ws.KeyValue `protobuf:"bytes,9,rep,name=reactionExtensionList" json:"reactionExtensionList,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *DeleteMessageListReactionExtensionsReq) Reset() { - *m = DeleteMessageListReactionExtensionsReq{} -} -func (m *DeleteMessageListReactionExtensionsReq) String() string { return proto.CompactTextString(m) } -func (*DeleteMessageListReactionExtensionsReq) ProtoMessage() {} -func (*DeleteMessageListReactionExtensionsReq) Descriptor() ([]byte, []int) { - return fileDescriptor_msg_53ecdffb017d9c40, []int{31} -} -func (m *DeleteMessageListReactionExtensionsReq) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_DeleteMessageListReactionExtensionsReq.Unmarshal(m, b) -} -func (m *DeleteMessageListReactionExtensionsReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_DeleteMessageListReactionExtensionsReq.Marshal(b, m, deterministic) -} -func (dst *DeleteMessageListReactionExtensionsReq) XXX_Merge(src proto.Message) { - xxx_messageInfo_DeleteMessageListReactionExtensionsReq.Merge(dst, src) -} -func (m *DeleteMessageListReactionExtensionsReq) XXX_Size() int { - return xxx_messageInfo_DeleteMessageListReactionExtensionsReq.Size(m) -} -func (m *DeleteMessageListReactionExtensionsReq) XXX_DiscardUnknown() { - xxx_messageInfo_DeleteMessageListReactionExtensionsReq.DiscardUnknown(m) -} - -var xxx_messageInfo_DeleteMessageListReactionExtensionsReq proto.InternalMessageInfo - -func (m *DeleteMessageListReactionExtensionsReq) GetOperationID() string { - if m != nil { - return m.OperationID - } - return "" -} - -func (m *DeleteMessageListReactionExtensionsReq) GetOpUserID() string { - if m != nil { - return m.OpUserID - } - return "" -} - -func (m *DeleteMessageListReactionExtensionsReq) GetSourceID() string { - if m != nil { - return m.SourceID - } - return "" -} - -func (m *DeleteMessageListReactionExtensionsReq) GetOpUserIDPlatformID() int32 { - if m != nil { - return m.OpUserIDPlatformID - } - return 0 -} - -func (m *DeleteMessageListReactionExtensionsReq) GetSessionType() int32 { - if m != nil { - return m.SessionType - } - return 0 -} - -func (m *DeleteMessageListReactionExtensionsReq) GetClientMsgID() string { - if m != nil { - return m.ClientMsgID - } - return "" -} - -func (m *DeleteMessageListReactionExtensionsReq) GetIsExternalExtensions() bool { - if m != nil { - return m.IsExternalExtensions - } - return false -} - -func (m *DeleteMessageListReactionExtensionsReq) GetMsgFirstModifyTime() int64 { - if m != nil { - return m.MsgFirstModifyTime - } - return 0 -} - -func (m *DeleteMessageListReactionExtensionsReq) GetReactionExtensionList() []*sdk_ws.KeyValue { - if m != nil { - return m.ReactionExtensionList - } - return nil -} - -type DeleteMessageListReactionExtensionsResp struct { - ErrCode int32 `protobuf:"varint,1,opt,name=errCode" json:"errCode,omitempty"` - ErrMsg string `protobuf:"bytes,2,opt,name=errMsg" json:"errMsg,omitempty"` - Result []*KeyValueResp `protobuf:"bytes,6,rep,name=result" json:"result,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *DeleteMessageListReactionExtensionsResp) Reset() { - *m = DeleteMessageListReactionExtensionsResp{} -} -func (m *DeleteMessageListReactionExtensionsResp) String() string { return proto.CompactTextString(m) } -func (*DeleteMessageListReactionExtensionsResp) ProtoMessage() {} -func (*DeleteMessageListReactionExtensionsResp) Descriptor() ([]byte, []int) { - return fileDescriptor_msg_53ecdffb017d9c40, []int{32} -} -func (m *DeleteMessageListReactionExtensionsResp) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_DeleteMessageListReactionExtensionsResp.Unmarshal(m, b) -} -func (m *DeleteMessageListReactionExtensionsResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_DeleteMessageListReactionExtensionsResp.Marshal(b, m, deterministic) -} -func (dst *DeleteMessageListReactionExtensionsResp) XXX_Merge(src proto.Message) { - xxx_messageInfo_DeleteMessageListReactionExtensionsResp.Merge(dst, src) -} -func (m *DeleteMessageListReactionExtensionsResp) XXX_Size() int { - return xxx_messageInfo_DeleteMessageListReactionExtensionsResp.Size(m) -} -func (m *DeleteMessageListReactionExtensionsResp) XXX_DiscardUnknown() { - xxx_messageInfo_DeleteMessageListReactionExtensionsResp.DiscardUnknown(m) -} - -var xxx_messageInfo_DeleteMessageListReactionExtensionsResp proto.InternalMessageInfo - -func (m *DeleteMessageListReactionExtensionsResp) GetErrCode() int32 { - if m != nil { - return m.ErrCode - } - return 0 -} - -func (m *DeleteMessageListReactionExtensionsResp) GetErrMsg() string { - if m != nil { - return m.ErrMsg - } - return "" -} - -func (m *DeleteMessageListReactionExtensionsResp) GetResult() []*KeyValueResp { - if m != nil { - return m.Result - } - return nil -} - -type ExtendMsgResp struct { - ExtendMsg *ExtendMsg `protobuf:"bytes,1,opt,name=extendMsg" json:"extendMsg,omitempty"` - ErrCode int32 `protobuf:"varint,2,opt,name=errCode" json:"errCode,omitempty"` - ErrMsg string `protobuf:"bytes,3,opt,name=errMsg" json:"errMsg,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *ExtendMsgResp) Reset() { *m = ExtendMsgResp{} } -func (m *ExtendMsgResp) String() string { return proto.CompactTextString(m) } -func (*ExtendMsgResp) ProtoMessage() {} -func (*ExtendMsgResp) Descriptor() ([]byte, []int) { - return fileDescriptor_msg_53ecdffb017d9c40, []int{33} -} -func (m *ExtendMsgResp) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_ExtendMsgResp.Unmarshal(m, b) -} -func (m *ExtendMsgResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_ExtendMsgResp.Marshal(b, m, deterministic) -} -func (dst *ExtendMsgResp) XXX_Merge(src proto.Message) { - xxx_messageInfo_ExtendMsgResp.Merge(dst, src) -} -func (m *ExtendMsgResp) XXX_Size() int { - return xxx_messageInfo_ExtendMsgResp.Size(m) -} -func (m *ExtendMsgResp) XXX_DiscardUnknown() { - xxx_messageInfo_ExtendMsgResp.DiscardUnknown(m) -} - -var xxx_messageInfo_ExtendMsgResp proto.InternalMessageInfo - -func (m *ExtendMsgResp) GetExtendMsg() *ExtendMsg { - if m != nil { - return m.ExtendMsg - } - return nil -} - -func (m *ExtendMsgResp) GetErrCode() int32 { - if m != nil { - return m.ErrCode - } - return 0 -} - -func (m *ExtendMsgResp) GetErrMsg() string { - if m != nil { - return m.ErrMsg - } - return "" -} - -type ExtendMsg struct { - ReactionExtensionList map[string]*KeyValueResp `protobuf:"bytes,1,rep,name=reactionExtensionList" json:"reactionExtensionList,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` - ClientMsgID string `protobuf:"bytes,2,opt,name=clientMsgID" json:"clientMsgID,omitempty"` - MsgFirstModifyTime int64 `protobuf:"varint,3,opt,name=msgFirstModifyTime" json:"msgFirstModifyTime,omitempty"` - AttachedInfo string `protobuf:"bytes,4,opt,name=attachedInfo" json:"attachedInfo,omitempty"` - Ex string `protobuf:"bytes,5,opt,name=ex" json:"ex,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *ExtendMsg) Reset() { *m = ExtendMsg{} } -func (m *ExtendMsg) String() string { return proto.CompactTextString(m) } -func (*ExtendMsg) ProtoMessage() {} -func (*ExtendMsg) Descriptor() ([]byte, []int) { - return fileDescriptor_msg_53ecdffb017d9c40, []int{34} -} -func (m *ExtendMsg) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_ExtendMsg.Unmarshal(m, b) -} -func (m *ExtendMsg) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_ExtendMsg.Marshal(b, m, deterministic) -} -func (dst *ExtendMsg) XXX_Merge(src proto.Message) { - xxx_messageInfo_ExtendMsg.Merge(dst, src) -} -func (m *ExtendMsg) XXX_Size() int { - return xxx_messageInfo_ExtendMsg.Size(m) -} -func (m *ExtendMsg) XXX_DiscardUnknown() { - xxx_messageInfo_ExtendMsg.DiscardUnknown(m) -} - -var xxx_messageInfo_ExtendMsg proto.InternalMessageInfo - -func (m *ExtendMsg) GetReactionExtensionList() map[string]*KeyValueResp { - if m != nil { - return m.ReactionExtensionList - } - return nil -} - -func (m *ExtendMsg) GetClientMsgID() string { - if m != nil { - return m.ClientMsgID - } - return "" -} - -func (m *ExtendMsg) GetMsgFirstModifyTime() int64 { - if m != nil { - return m.MsgFirstModifyTime - } - return 0 -} - -func (m *ExtendMsg) GetAttachedInfo() string { - if m != nil { - return m.AttachedInfo - } - return "" -} - -func (m *ExtendMsg) GetEx() string { - if m != nil { - return m.Ex - } - return "" -} - -type KeyValueResp struct { - KeyValue *sdk_ws.KeyValue `protobuf:"bytes,1,opt,name=keyValue" json:"keyValue,omitempty"` - ErrCode int32 `protobuf:"varint,2,opt,name=errCode" json:"errCode,omitempty"` - ErrMsg string `protobuf:"bytes,3,opt,name=errMsg" json:"errMsg,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *KeyValueResp) Reset() { *m = KeyValueResp{} } -func (m *KeyValueResp) String() string { return proto.CompactTextString(m) } -func (*KeyValueResp) ProtoMessage() {} -func (*KeyValueResp) Descriptor() ([]byte, []int) { - return fileDescriptor_msg_53ecdffb017d9c40, []int{35} -} -func (m *KeyValueResp) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_KeyValueResp.Unmarshal(m, b) -} -func (m *KeyValueResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_KeyValueResp.Marshal(b, m, deterministic) -} -func (dst *KeyValueResp) XXX_Merge(src proto.Message) { - xxx_messageInfo_KeyValueResp.Merge(dst, src) -} -func (m *KeyValueResp) XXX_Size() int { - return xxx_messageInfo_KeyValueResp.Size(m) -} -func (m *KeyValueResp) XXX_DiscardUnknown() { - xxx_messageInfo_KeyValueResp.DiscardUnknown(m) -} - -var xxx_messageInfo_KeyValueResp proto.InternalMessageInfo - -func (m *KeyValueResp) GetKeyValue() *sdk_ws.KeyValue { - if m != nil { - return m.KeyValue - } - return nil -} - -func (m *KeyValueResp) GetErrCode() int32 { - if m != nil { - return m.ErrCode - } - return 0 -} - -func (m *KeyValueResp) GetErrMsg() string { - if m != nil { - return m.ErrMsg - } - return "" -} - -type MsgDataToModifyByMQ struct { - AggregationID string `protobuf:"bytes,1,opt,name=aggregationID" json:"aggregationID,omitempty"` - MessageList []*MsgDataToMQ `protobuf:"bytes,2,rep,name=messageList" json:"messageList,omitempty"` - TriggerID string `protobuf:"bytes,3,opt,name=triggerID" json:"triggerID,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *MsgDataToModifyByMQ) Reset() { *m = MsgDataToModifyByMQ{} } -func (m *MsgDataToModifyByMQ) String() string { return proto.CompactTextString(m) } -func (*MsgDataToModifyByMQ) ProtoMessage() {} -func (*MsgDataToModifyByMQ) Descriptor() ([]byte, []int) { - return fileDescriptor_msg_53ecdffb017d9c40, []int{36} -} -func (m *MsgDataToModifyByMQ) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_MsgDataToModifyByMQ.Unmarshal(m, b) -} -func (m *MsgDataToModifyByMQ) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_MsgDataToModifyByMQ.Marshal(b, m, deterministic) -} -func (dst *MsgDataToModifyByMQ) XXX_Merge(src proto.Message) { - xxx_messageInfo_MsgDataToModifyByMQ.Merge(dst, src) -} -func (m *MsgDataToModifyByMQ) XXX_Size() int { - return xxx_messageInfo_MsgDataToModifyByMQ.Size(m) -} -func (m *MsgDataToModifyByMQ) XXX_DiscardUnknown() { - xxx_messageInfo_MsgDataToModifyByMQ.DiscardUnknown(m) -} - -var xxx_messageInfo_MsgDataToModifyByMQ proto.InternalMessageInfo - -func (m *MsgDataToModifyByMQ) GetAggregationID() string { - if m != nil { - return m.AggregationID - } - return "" -} - -func (m *MsgDataToModifyByMQ) GetMessageList() []*MsgDataToMQ { - if m != nil { - return m.MessageList - } - return nil -} - -func (m *MsgDataToModifyByMQ) GetTriggerID() string { - if m != nil { - return m.TriggerID - } - return "" -} - -func init() { - proto.RegisterType((*MsgDataToMQ)(nil), "msg.MsgDataToMQ") - proto.RegisterType((*MsgDataToDB)(nil), "msg.MsgDataToDB") - proto.RegisterType((*PushMsgDataToMQ)(nil), "msg.PushMsgDataToMQ") - proto.RegisterType((*MsgDataToMongoByMQ)(nil), "msg.MsgDataToMongoByMQ") - proto.RegisterType((*GetMaxAndMinSeqReq)(nil), "msg.GetMaxAndMinSeqReq") - proto.RegisterType((*GetMaxAndMinSeqResp)(nil), "msg.GetMaxAndMinSeqResp") - proto.RegisterType((*SendMsgReq)(nil), "msg.SendMsgReq") - proto.RegisterType((*SendMsgResp)(nil), "msg.SendMsgResp") - proto.RegisterType((*ClearMsgReq)(nil), "msg.ClearMsgReq") - proto.RegisterType((*ClearMsgResp)(nil), "msg.ClearMsgResp") - proto.RegisterType((*SetMsgMinSeqReq)(nil), "msg.SetMsgMinSeqReq") - proto.RegisterType((*SetMsgMinSeqResp)(nil), "msg.SetMsgMinSeqResp") - proto.RegisterType((*SetSendMsgStatusReq)(nil), "msg.SetSendMsgStatusReq") - proto.RegisterType((*SetSendMsgStatusResp)(nil), "msg.SetSendMsgStatusResp") - proto.RegisterType((*GetSendMsgStatusReq)(nil), "msg.GetSendMsgStatusReq") - proto.RegisterType((*GetSendMsgStatusResp)(nil), "msg.GetSendMsgStatusResp") - proto.RegisterType((*DelSuperGroupMsgReq)(nil), "msg.DelSuperGroupMsgReq") - proto.RegisterType((*DelSuperGroupMsgResp)(nil), "msg.DelSuperGroupMsgResp") - proto.RegisterType((*GetSuperGroupMsgReq)(nil), "msg.GetSuperGroupMsgReq") - proto.RegisterType((*GetSuperGroupMsgResp)(nil), "msg.GetSuperGroupMsgResp") - proto.RegisterType((*GetWriteDiffMsgReq)(nil), "msg.GetWriteDiffMsgReq") - proto.RegisterType((*GetWriteDiffMsgResp)(nil), "msg.GetWriteDiffMsgResp") - proto.RegisterType((*ModifyMessageReactionExtensionsReq)(nil), "msg.ModifyMessageReactionExtensionsReq") - proto.RegisterMapType((map[string]*sdk_ws.KeyValue)(nil), "msg.ModifyMessageReactionExtensionsReq.ReactionExtensionListEntry") - proto.RegisterType((*SetMessageReactionExtensionsReq)(nil), "msg.SetMessageReactionExtensionsReq") - proto.RegisterMapType((map[string]*sdk_ws.KeyValue)(nil), "msg.SetMessageReactionExtensionsReq.ReactionExtensionListEntry") - proto.RegisterType((*SetMessageReactionExtensionsResp)(nil), "msg.SetMessageReactionExtensionsResp") - proto.RegisterType((*AddMessageReactionExtensionsReq)(nil), "msg.AddMessageReactionExtensionsReq") - proto.RegisterMapType((map[string]*sdk_ws.KeyValue)(nil), "msg.AddMessageReactionExtensionsReq.ReactionExtensionListEntry") - proto.RegisterType((*AddMessageReactionExtensionsResp)(nil), "msg.AddMessageReactionExtensionsResp") - proto.RegisterType((*GetMessageListReactionExtensionsReq)(nil), "msg.GetMessageListReactionExtensionsReq") - proto.RegisterType((*GetMessageListReactionExtensionsReq_MessageReactionKey)(nil), "msg.GetMessageListReactionExtensionsReq.MessageReactionKey") - proto.RegisterType((*GetMessageListReactionExtensionsResp)(nil), "msg.GetMessageListReactionExtensionsResp") - proto.RegisterType((*SingleMessageExtensionResult)(nil), "msg.SingleMessageExtensionResult") - proto.RegisterMapType((map[string]*sdk_ws.KeyValue)(nil), "msg.SingleMessageExtensionResult.ReactionExtensionListEntry") - proto.RegisterType((*ModifyMessageReactionExtensionsResp)(nil), "msg.ModifyMessageReactionExtensionsResp") - proto.RegisterType((*DeleteMessageListReactionExtensionsReq)(nil), "msg.DeleteMessageListReactionExtensionsReq") - proto.RegisterType((*DeleteMessageListReactionExtensionsResp)(nil), "msg.DeleteMessageListReactionExtensionsResp") - proto.RegisterType((*ExtendMsgResp)(nil), "msg.ExtendMsgResp") - proto.RegisterType((*ExtendMsg)(nil), "msg.ExtendMsg") - proto.RegisterMapType((map[string]*KeyValueResp)(nil), "msg.ExtendMsg.ReactionExtensionListEntry") - proto.RegisterType((*KeyValueResp)(nil), "msg.KeyValueResp") - proto.RegisterType((*MsgDataToModifyByMQ)(nil), "msg.MsgDataToModifyByMQ") -} - -// Reference imports to suppress errors if they are not otherwise used. -var _ context.Context -var _ grpc.ClientConn - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the grpc package it is being compiled against. -const _ = grpc.SupportPackageIsVersion4 - -// Client API for Msg service - -type MsgClient interface { - GetMaxAndMinSeq(ctx context.Context, in *sdk_ws.GetMaxAndMinSeqReq, opts ...grpc.CallOption) (*sdk_ws.GetMaxAndMinSeqResp, error) - PullMessageBySeqList(ctx context.Context, in *sdk_ws.PullMessageBySeqListReq, opts ...grpc.CallOption) (*sdk_ws.PullMessageBySeqListResp, error) - SendMsg(ctx context.Context, in *SendMsgReq, opts ...grpc.CallOption) (*SendMsgResp, error) - DelMsgList(ctx context.Context, in *sdk_ws.DelMsgListReq, opts ...grpc.CallOption) (*sdk_ws.DelMsgListResp, error) - DelSuperGroupMsg(ctx context.Context, in *DelSuperGroupMsgReq, opts ...grpc.CallOption) (*DelSuperGroupMsgResp, error) - ClearMsg(ctx context.Context, in *ClearMsgReq, opts ...grpc.CallOption) (*ClearMsgResp, error) - SetMsgMinSeq(ctx context.Context, in *SetMsgMinSeqReq, opts ...grpc.CallOption) (*SetMsgMinSeqResp, error) - SetSendMsgStatus(ctx context.Context, in *SetSendMsgStatusReq, opts ...grpc.CallOption) (*SetSendMsgStatusResp, error) - GetSendMsgStatus(ctx context.Context, in *GetSendMsgStatusReq, opts ...grpc.CallOption) (*GetSendMsgStatusResp, error) - GetSuperGroupMsg(ctx context.Context, in *GetSuperGroupMsgReq, opts ...grpc.CallOption) (*GetSuperGroupMsgResp, error) - GetWriteDiffMsg(ctx context.Context, in *GetWriteDiffMsgReq, opts ...grpc.CallOption) (*GetWriteDiffMsgResp, error) - // modify msg - SetMessageReactionExtensions(ctx context.Context, in *SetMessageReactionExtensionsReq, opts ...grpc.CallOption) (*SetMessageReactionExtensionsResp, error) - GetMessageListReactionExtensions(ctx context.Context, in *GetMessageListReactionExtensionsReq, opts ...grpc.CallOption) (*GetMessageListReactionExtensionsResp, error) - AddMessageReactionExtensions(ctx context.Context, in *AddMessageReactionExtensionsReq, opts ...grpc.CallOption) (*AddMessageReactionExtensionsResp, error) - DeleteMessageReactionExtensions(ctx context.Context, in *DeleteMessageListReactionExtensionsReq, opts ...grpc.CallOption) (*DeleteMessageListReactionExtensionsResp, error) -} - -type msgClient struct { - cc *grpc.ClientConn -} - -func NewMsgClient(cc *grpc.ClientConn) MsgClient { - return &msgClient{cc} -} - -func (c *msgClient) GetMaxAndMinSeq(ctx context.Context, in *sdk_ws.GetMaxAndMinSeqReq, opts ...grpc.CallOption) (*sdk_ws.GetMaxAndMinSeqResp, error) { - out := new(sdk_ws.GetMaxAndMinSeqResp) - err := grpc.Invoke(ctx, "/msg.msg/GetMaxAndMinSeq", in, out, c.cc, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *msgClient) PullMessageBySeqList(ctx context.Context, in *sdk_ws.PullMessageBySeqListReq, opts ...grpc.CallOption) (*sdk_ws.PullMessageBySeqListResp, error) { - out := new(sdk_ws.PullMessageBySeqListResp) - err := grpc.Invoke(ctx, "/msg.msg/PullMessageBySeqList", in, out, c.cc, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *msgClient) SendMsg(ctx context.Context, in *SendMsgReq, opts ...grpc.CallOption) (*SendMsgResp, error) { - out := new(SendMsgResp) - err := grpc.Invoke(ctx, "/msg.msg/SendMsg", in, out, c.cc, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *msgClient) DelMsgList(ctx context.Context, in *sdk_ws.DelMsgListReq, opts ...grpc.CallOption) (*sdk_ws.DelMsgListResp, error) { - out := new(sdk_ws.DelMsgListResp) - err := grpc.Invoke(ctx, "/msg.msg/DelMsgList", in, out, c.cc, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *msgClient) DelSuperGroupMsg(ctx context.Context, in *DelSuperGroupMsgReq, opts ...grpc.CallOption) (*DelSuperGroupMsgResp, error) { - out := new(DelSuperGroupMsgResp) - err := grpc.Invoke(ctx, "/msg.msg/DelSuperGroupMsg", in, out, c.cc, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *msgClient) ClearMsg(ctx context.Context, in *ClearMsgReq, opts ...grpc.CallOption) (*ClearMsgResp, error) { - out := new(ClearMsgResp) - err := grpc.Invoke(ctx, "/msg.msg/ClearMsg", in, out, c.cc, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *msgClient) SetMsgMinSeq(ctx context.Context, in *SetMsgMinSeqReq, opts ...grpc.CallOption) (*SetMsgMinSeqResp, error) { - out := new(SetMsgMinSeqResp) - err := grpc.Invoke(ctx, "/msg.msg/SetMsgMinSeq", in, out, c.cc, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *msgClient) SetSendMsgStatus(ctx context.Context, in *SetSendMsgStatusReq, opts ...grpc.CallOption) (*SetSendMsgStatusResp, error) { - out := new(SetSendMsgStatusResp) - err := grpc.Invoke(ctx, "/msg.msg/SetSendMsgStatus", in, out, c.cc, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *msgClient) GetSendMsgStatus(ctx context.Context, in *GetSendMsgStatusReq, opts ...grpc.CallOption) (*GetSendMsgStatusResp, error) { - out := new(GetSendMsgStatusResp) - err := grpc.Invoke(ctx, "/msg.msg/GetSendMsgStatus", in, out, c.cc, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *msgClient) GetSuperGroupMsg(ctx context.Context, in *GetSuperGroupMsgReq, opts ...grpc.CallOption) (*GetSuperGroupMsgResp, error) { - out := new(GetSuperGroupMsgResp) - err := grpc.Invoke(ctx, "/msg.msg/GetSuperGroupMsg", in, out, c.cc, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *msgClient) GetWriteDiffMsg(ctx context.Context, in *GetWriteDiffMsgReq, opts ...grpc.CallOption) (*GetWriteDiffMsgResp, error) { - out := new(GetWriteDiffMsgResp) - err := grpc.Invoke(ctx, "/msg.msg/GetWriteDiffMsg", in, out, c.cc, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *msgClient) SetMessageReactionExtensions(ctx context.Context, in *SetMessageReactionExtensionsReq, opts ...grpc.CallOption) (*SetMessageReactionExtensionsResp, error) { - out := new(SetMessageReactionExtensionsResp) - err := grpc.Invoke(ctx, "/msg.msg/SetMessageReactionExtensions", in, out, c.cc, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *msgClient) GetMessageListReactionExtensions(ctx context.Context, in *GetMessageListReactionExtensionsReq, opts ...grpc.CallOption) (*GetMessageListReactionExtensionsResp, error) { - out := new(GetMessageListReactionExtensionsResp) - err := grpc.Invoke(ctx, "/msg.msg/GetMessageListReactionExtensions", in, out, c.cc, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *msgClient) AddMessageReactionExtensions(ctx context.Context, in *AddMessageReactionExtensionsReq, opts ...grpc.CallOption) (*AddMessageReactionExtensionsResp, error) { - out := new(AddMessageReactionExtensionsResp) - err := grpc.Invoke(ctx, "/msg.msg/AddMessageReactionExtensions", in, out, c.cc, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *msgClient) DeleteMessageReactionExtensions(ctx context.Context, in *DeleteMessageListReactionExtensionsReq, opts ...grpc.CallOption) (*DeleteMessageListReactionExtensionsResp, error) { - out := new(DeleteMessageListReactionExtensionsResp) - err := grpc.Invoke(ctx, "/msg.msg/DeleteMessageReactionExtensions", in, out, c.cc, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -// Server API for Msg service - -type MsgServer interface { - GetMaxAndMinSeq(context.Context, *sdk_ws.GetMaxAndMinSeqReq) (*sdk_ws.GetMaxAndMinSeqResp, error) - PullMessageBySeqList(context.Context, *sdk_ws.PullMessageBySeqListReq) (*sdk_ws.PullMessageBySeqListResp, error) - SendMsg(context.Context, *SendMsgReq) (*SendMsgResp, error) - DelMsgList(context.Context, *sdk_ws.DelMsgListReq) (*sdk_ws.DelMsgListResp, error) - DelSuperGroupMsg(context.Context, *DelSuperGroupMsgReq) (*DelSuperGroupMsgResp, error) - ClearMsg(context.Context, *ClearMsgReq) (*ClearMsgResp, error) - SetMsgMinSeq(context.Context, *SetMsgMinSeqReq) (*SetMsgMinSeqResp, error) - SetSendMsgStatus(context.Context, *SetSendMsgStatusReq) (*SetSendMsgStatusResp, error) - GetSendMsgStatus(context.Context, *GetSendMsgStatusReq) (*GetSendMsgStatusResp, error) - GetSuperGroupMsg(context.Context, *GetSuperGroupMsgReq) (*GetSuperGroupMsgResp, error) - GetWriteDiffMsg(context.Context, *GetWriteDiffMsgReq) (*GetWriteDiffMsgResp, error) - // modify msg - SetMessageReactionExtensions(context.Context, *SetMessageReactionExtensionsReq) (*SetMessageReactionExtensionsResp, error) - GetMessageListReactionExtensions(context.Context, *GetMessageListReactionExtensionsReq) (*GetMessageListReactionExtensionsResp, error) - AddMessageReactionExtensions(context.Context, *AddMessageReactionExtensionsReq) (*AddMessageReactionExtensionsResp, error) - DeleteMessageReactionExtensions(context.Context, *DeleteMessageListReactionExtensionsReq) (*DeleteMessageListReactionExtensionsResp, error) -} - -func RegisterMsgServer(s *grpc.Server, srv MsgServer) { - s.RegisterService(&_Msg_serviceDesc, srv) -} - -func _Msg_GetMaxAndMinSeq_Handler(srv any, ctx context.Context, dec func(any) error, interceptor grpc.UnaryServerInterceptor) (any, error) { - in := new(sdk_ws.GetMaxAndMinSeqReq) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(MsgServer).GetMaxAndMinSeq(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/msg.msg/GetMaxAndMinSeq", - } - handler := func(ctx context.Context, req any) (any, error) { - return srv.(MsgServer).GetMaxAndMinSeq(ctx, req.(*sdk_ws.GetMaxAndMinSeqReq)) - } - return interceptor(ctx, in, info, handler) -} - -func _Msg_PullMessageBySeqList_Handler(srv any, ctx context.Context, dec func(any) error, interceptor grpc.UnaryServerInterceptor) (any, error) { - in := new(sdk_ws.PullMessageBySeqListReq) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(MsgServer).PullMessageBySeqList(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/msg.msg/PullMessageBySeqList", - } - handler := func(ctx context.Context, req any) (any, error) { - return srv.(MsgServer).PullMessageBySeqList(ctx, req.(*sdk_ws.PullMessageBySeqListReq)) - } - return interceptor(ctx, in, info, handler) -} - -func _Msg_SendMsg_Handler(srv any, ctx context.Context, dec func(any) error, interceptor grpc.UnaryServerInterceptor) (any, error) { - in := new(SendMsgReq) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(MsgServer).SendMsg(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/msg.msg/SendMsg", - } - handler := func(ctx context.Context, req any) (any, error) { - return srv.(MsgServer).SendMsg(ctx, req.(*SendMsgReq)) - } - return interceptor(ctx, in, info, handler) -} - -func _Msg_DelMsgList_Handler(srv any, ctx context.Context, dec func(any) error, interceptor grpc.UnaryServerInterceptor) (any, error) { - in := new(sdk_ws.DelMsgListReq) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(MsgServer).DelMsgList(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/msg.msg/DelMsgList", - } - handler := func(ctx context.Context, req any) (any, error) { - return srv.(MsgServer).DelMsgList(ctx, req.(*sdk_ws.DelMsgListReq)) - } - return interceptor(ctx, in, info, handler) -} - -func _Msg_DelSuperGroupMsg_Handler(srv any, ctx context.Context, dec func(any) error, interceptor grpc.UnaryServerInterceptor) (any, error) { - in := new(DelSuperGroupMsgReq) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(MsgServer).DelSuperGroupMsg(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/msg.msg/DelSuperGroupMsg", - } - handler := func(ctx context.Context, req any) (any, error) { - return srv.(MsgServer).DelSuperGroupMsg(ctx, req.(*DelSuperGroupMsgReq)) - } - return interceptor(ctx, in, info, handler) -} - -func _Msg_ClearMsg_Handler(srv any, ctx context.Context, dec func(any) error, interceptor grpc.UnaryServerInterceptor) (any, error) { - in := new(ClearMsgReq) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(MsgServer).ClearMsg(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/msg.msg/ClearMsg", - } - handler := func(ctx context.Context, req any) (any, error) { - return srv.(MsgServer).ClearMsg(ctx, req.(*ClearMsgReq)) - } - return interceptor(ctx, in, info, handler) -} - -func _Msg_SetMsgMinSeq_Handler(srv any, ctx context.Context, dec func(any) error, interceptor grpc.UnaryServerInterceptor) (any, error) { - in := new(SetMsgMinSeqReq) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(MsgServer).SetMsgMinSeq(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/msg.msg/SetMsgMinSeq", - } - handler := func(ctx context.Context, req any) (any, error) { - return srv.(MsgServer).SetMsgMinSeq(ctx, req.(*SetMsgMinSeqReq)) - } - return interceptor(ctx, in, info, handler) -} - -func _Msg_SetSendMsgStatus_Handler(srv any, ctx context.Context, dec func(any) error, interceptor grpc.UnaryServerInterceptor) (any, error) { - in := new(SetSendMsgStatusReq) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(MsgServer).SetSendMsgStatus(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/msg.msg/SetSendMsgStatus", - } - handler := func(ctx context.Context, req any) (any, error) { - return srv.(MsgServer).SetSendMsgStatus(ctx, req.(*SetSendMsgStatusReq)) - } - return interceptor(ctx, in, info, handler) -} - -func _Msg_GetSendMsgStatus_Handler(srv any, ctx context.Context, dec func(any) error, interceptor grpc.UnaryServerInterceptor) (any, error) { - in := new(GetSendMsgStatusReq) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(MsgServer).GetSendMsgStatus(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/msg.msg/GetSendMsgStatus", - } - handler := func(ctx context.Context, req any) (any, error) { - return srv.(MsgServer).GetSendMsgStatus(ctx, req.(*GetSendMsgStatusReq)) - } - return interceptor(ctx, in, info, handler) -} - -func _Msg_GetSuperGroupMsg_Handler(srv any, ctx context.Context, dec func(any) error, interceptor grpc.UnaryServerInterceptor) (any, error) { - in := new(GetSuperGroupMsgReq) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(MsgServer).GetSuperGroupMsg(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/msg.msg/GetSuperGroupMsg", - } - handler := func(ctx context.Context, req any) (any, error) { - return srv.(MsgServer).GetSuperGroupMsg(ctx, req.(*GetSuperGroupMsgReq)) - } - return interceptor(ctx, in, info, handler) -} - -func _Msg_GetWriteDiffMsg_Handler(srv any, ctx context.Context, dec func(any) error, interceptor grpc.UnaryServerInterceptor) (any, error) { - in := new(GetWriteDiffMsgReq) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(MsgServer).GetWriteDiffMsg(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/msg.msg/GetWriteDiffMsg", - } - handler := func(ctx context.Context, req any) (any, error) { - return srv.(MsgServer).GetWriteDiffMsg(ctx, req.(*GetWriteDiffMsgReq)) - } - return interceptor(ctx, in, info, handler) -} - -func _Msg_SetMessageReactionExtensions_Handler(srv any, ctx context.Context, dec func(any) error, interceptor grpc.UnaryServerInterceptor) (any, error) { - in := new(SetMessageReactionExtensionsReq) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(MsgServer).SetMessageReactionExtensions(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/msg.msg/SetMessageReactionExtensions", - } - handler := func(ctx context.Context, req any) (any, error) { - return srv.(MsgServer).SetMessageReactionExtensions(ctx, req.(*SetMessageReactionExtensionsReq)) - } - return interceptor(ctx, in, info, handler) -} - -func _Msg_GetMessageListReactionExtensions_Handler(srv any, ctx context.Context, dec func(any) error, interceptor grpc.UnaryServerInterceptor) (any, error) { - in := new(GetMessageListReactionExtensionsReq) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(MsgServer).GetMessageListReactionExtensions(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/msg.msg/GetMessageListReactionExtensions", - } - handler := func(ctx context.Context, req any) (any, error) { - return srv.(MsgServer).GetMessageListReactionExtensions(ctx, req.(*GetMessageListReactionExtensionsReq)) - } - return interceptor(ctx, in, info, handler) -} - -func _Msg_AddMessageReactionExtensions_Handler(srv any, ctx context.Context, dec func(any) error, interceptor grpc.UnaryServerInterceptor) (any, error) { - in := new(AddMessageReactionExtensionsReq) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(MsgServer).AddMessageReactionExtensions(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/msg.msg/AddMessageReactionExtensions", - } - handler := func(ctx context.Context, req any) (any, error) { - return srv.(MsgServer).AddMessageReactionExtensions(ctx, req.(*AddMessageReactionExtensionsReq)) - } - return interceptor(ctx, in, info, handler) -} - -func _Msg_DeleteMessageReactionExtensions_Handler(srv any, ctx context.Context, dec func(any) error, interceptor grpc.UnaryServerInterceptor) (any, error) { - in := new(DeleteMessageListReactionExtensionsReq) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(MsgServer).DeleteMessageReactionExtensions(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/msg.msg/DeleteMessageReactionExtensions", - } - handler := func(ctx context.Context, req any) (any, error) { - return srv.(MsgServer).DeleteMessageReactionExtensions(ctx, req.(*DeleteMessageListReactionExtensionsReq)) - } - return interceptor(ctx, in, info, handler) -} - -var _Msg_serviceDesc = grpc.ServiceDesc{ - ServiceName: "msg.msg", - HandlerType: (*MsgServer)(nil), - Methods: []grpc.MethodDesc{ - { - MethodName: "GetMaxAndMinSeq", - Handler: _Msg_GetMaxAndMinSeq_Handler, - }, - { - MethodName: "PullMessageBySeqList", - Handler: _Msg_PullMessageBySeqList_Handler, - }, - { - MethodName: "SendMsg", - Handler: _Msg_SendMsg_Handler, - }, - { - MethodName: "DelMsgList", - Handler: _Msg_DelMsgList_Handler, - }, - { - MethodName: "DelSuperGroupMsg", - Handler: _Msg_DelSuperGroupMsg_Handler, - }, - { - MethodName: "ClearMsg", - Handler: _Msg_ClearMsg_Handler, - }, - { - MethodName: "SetMsgMinSeq", - Handler: _Msg_SetMsgMinSeq_Handler, - }, - { - MethodName: "SetSendMsgStatus", - Handler: _Msg_SetSendMsgStatus_Handler, - }, - { - MethodName: "GetSendMsgStatus", - Handler: _Msg_GetSendMsgStatus_Handler, - }, - { - MethodName: "GetSuperGroupMsg", - Handler: _Msg_GetSuperGroupMsg_Handler, - }, - { - MethodName: "GetWriteDiffMsg", - Handler: _Msg_GetWriteDiffMsg_Handler, - }, - { - MethodName: "SetMessageReactionExtensions", - Handler: _Msg_SetMessageReactionExtensions_Handler, - }, - { - MethodName: "GetMessageListReactionExtensions", - Handler: _Msg_GetMessageListReactionExtensions_Handler, - }, - { - MethodName: "AddMessageReactionExtensions", - Handler: _Msg_AddMessageReactionExtensions_Handler, - }, - { - MethodName: "DeleteMessageReactionExtensions", - Handler: _Msg_DeleteMessageReactionExtensions_Handler, - }, - }, - Streams: []grpc.StreamDesc{}, - Metadata: "msg/msg.proto", -} - -func init() { proto.RegisterFile("msg/msg.proto", fileDescriptor_msg_53ecdffb017d9c40) } - -var fileDescriptor_msg_53ecdffb017d9c40 = []byte{ - // 1785 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x5a, 0x4f, 0x6f, 0xdb, 0xc8, - 0x15, 0x07, 0x45, 0x53, 0xb2, 0x9e, 0xec, 0xb5, 0x77, 0xec, 0x75, 0xb5, 0x5c, 0x03, 0xd1, 0x72, - 0xb3, 0x1b, 0xa7, 0x49, 0x64, 0xd4, 0x2d, 0x90, 0xa2, 0x29, 0xd0, 0xc4, 0x91, 0xab, 0x18, 0xa9, - 0xea, 0x98, 0x72, 0x5b, 0xa0, 0x3d, 0x38, 0x8c, 0x34, 0x62, 0x08, 0x4b, 0x24, 0xcd, 0xa1, 0x62, - 0xab, 0xff, 0x0e, 0x05, 0xda, 0x5b, 0x0e, 0x3d, 0xf6, 0x0b, 0xf4, 0x16, 0xf4, 0x03, 0xf4, 0xd4, - 0x0f, 0x10, 0xf4, 0xd2, 0x6f, 0xd1, 0x2f, 0x51, 0xcc, 0x0c, 0x29, 0x0d, 0xff, 0x89, 0xb4, 0x1c, - 0x38, 0x40, 0xdb, 0x9b, 0x66, 0xe6, 0xcd, 0x9b, 0xf7, 0x7b, 0xef, 0xf7, 0x66, 0x86, 0xf3, 0x04, - 0xab, 0x23, 0x62, 0xee, 0x8e, 0x88, 0xd9, 0x74, 0x3d, 0xc7, 0x77, 0x90, 0x3c, 0x22, 0xa6, 0xba, - 0x73, 0xe4, 0x62, 0xfb, 0xc1, 0x61, 0xe7, 0x41, 0x17, 0x7b, 0x6f, 0xb0, 0xb7, 0xeb, 0x9e, 0x99, - 0xbb, 0x6c, 0x78, 0x97, 0xf4, 0xcf, 0x4e, 0x2f, 0xc8, 0xee, 0x05, 0xe1, 0xe2, 0x6a, 0x33, 0x57, - 0xd2, 0x33, 0x5c, 0x17, 0x7b, 0x81, 0xbc, 0xf6, 0x1b, 0xa8, 0x75, 0x88, 0xd9, 0x32, 0x7c, 0xe3, - 0xc4, 0xe9, 0x1c, 0xa3, 0x4d, 0x50, 0x7c, 0xe7, 0x0c, 0xdb, 0x75, 0xa9, 0x21, 0xed, 0x54, 0x75, - 0xde, 0x40, 0x0d, 0xa8, 0x39, 0x2e, 0xf6, 0x0c, 0xdf, 0x72, 0xec, 0xc3, 0x56, 0xbd, 0xc4, 0xc6, - 0xc4, 0x2e, 0xf4, 0x3d, 0xa8, 0x8c, 0xb8, 0x9a, 0xba, 0xdc, 0x90, 0x76, 0x6a, 0x7b, 0x6a, 0x93, - 0x30, 0x03, 0x4e, 0x0d, 0xd7, 0x3a, 0x75, 0x0d, 0xcf, 0x18, 0x91, 0x66, 0xb0, 0x90, 0x1e, 0x8a, - 0x6a, 0x58, 0x58, 0xbc, 0xb5, 0x2f, 0x2a, 0x91, 0x0a, 0x2b, 0xc9, 0x37, 0x4e, 0x7b, 0x2b, 0xc1, - 0xda, 0x8b, 0x31, 0x79, 0x2d, 0x02, 0x6d, 0x40, 0xed, 0x48, 0x98, 0xc5, 0xe1, 0x8a, 0x5d, 0xa2, - 0x35, 0xa5, 0xe2, 0xd6, 0x68, 0xb0, 0xe2, 0x8e, 0xc9, 0xeb, 0x13, 0xe7, 0x67, 0x04, 0x7b, 0x87, - 0x2d, 0xe6, 0x8d, 0xaa, 0x1e, 0xe9, 0xd3, 0xfe, 0x2a, 0x01, 0x9a, 0xd9, 0xe2, 0xd8, 0xa6, 0xb3, - 0x3f, 0xe9, 0x1c, 0xa3, 0x3a, 0x54, 0x86, 0x06, 0xf1, 0xbb, 0xf8, 0x9c, 0x99, 0xb3, 0xa4, 0x87, - 0x4d, 0x74, 0x1b, 0x56, 0x0d, 0xd3, 0xf4, 0xb0, 0x19, 0x05, 0x19, 0xed, 0x44, 0x7b, 0x50, 0x1b, - 0x61, 0x42, 0x0c, 0x13, 0xff, 0xc4, 0x22, 0x7e, 0x5d, 0x6e, 0xc8, 0x3b, 0xb5, 0xbd, 0xf5, 0x26, - 0xa5, 0x92, 0x80, 0x5c, 0x17, 0x85, 0xd0, 0x36, 0x54, 0x7d, 0xcf, 0x32, 0x4d, 0x66, 0xeb, 0x12, - 0xd3, 0x3a, 0xeb, 0xd0, 0x7e, 0x0a, 0xa8, 0x8d, 0xfd, 0x8e, 0x71, 0xf9, 0xc4, 0xee, 0x77, 0x2c, - 0xbb, 0x8b, 0xcf, 0x75, 0x7c, 0x8e, 0xb6, 0xa0, 0x1c, 0x80, 0xe3, 0x5e, 0x0b, 0x5a, 0x71, 0x97, - 0x96, 0x12, 0x2e, 0xd5, 0x2e, 0x60, 0x23, 0xa1, 0x8f, 0xb8, 0x14, 0xf8, 0x81, 0xe7, 0x3d, 0x75, - 0xfa, 0x98, 0x69, 0x54, 0xf4, 0xb0, 0x49, 0x97, 0x3a, 0xf0, 0xbc, 0x0e, 0x31, 0x03, 0x6d, 0x41, - 0x8b, 0xf6, 0x77, 0x8c, 0x4b, 0xea, 0x29, 0xea, 0xdf, 0x55, 0x3d, 0x68, 0xb1, 0x7e, 0xa6, 0x97, - 0x61, 0xa1, 0xfd, 0xac, 0xa5, 0xfd, 0x1a, 0xa0, 0x8b, 0xed, 0x7e, 0x87, 0x98, 0x14, 0xc0, 0xcd, - 0x92, 0xfc, 0x6f, 0x12, 0xd4, 0xa6, 0x8b, 0x73, 0xb4, 0x38, 0x8a, 0x16, 0xcf, 0xd0, 0xe2, 0x08, - 0x5a, 0xde, 0xa2, 0x96, 0xf1, 0x75, 0x3a, 0xc4, 0x9c, 0x86, 0x49, 0xec, 0xa2, 0x12, 0xbd, 0xa1, - 0x85, 0x6d, 0x9f, 0x4b, 0x28, 0x5c, 0x42, 0xe8, 0x42, 0x2a, 0x2c, 0x13, 0x6c, 0xf7, 0x4f, 0xac, - 0x11, 0xae, 0x97, 0x1b, 0xd2, 0x8e, 0xac, 0x4f, 0xdb, 0xe8, 0x13, 0x28, 0xe1, 0xcb, 0x7a, 0x85, - 0x4d, 0x2a, 0xe1, 0x4b, 0xad, 0x07, 0xb5, 0xa7, 0x43, 0x6c, 0x78, 0x81, 0xbb, 0xb6, 0xa0, 0x3c, - 0x8e, 0xc4, 0x9b, 0xb7, 0xa8, 0x4a, 0xc7, 0x0d, 0x98, 0xc0, 0x0d, 0x9e, 0xb6, 0xe3, 0xce, 0x94, - 0x93, 0x49, 0xf9, 0x18, 0x56, 0x66, 0x8b, 0x2c, 0xe2, 0x16, 0xed, 0x2f, 0x12, 0xac, 0x75, 0x31, - 0xc5, 0x17, 0xe1, 0x66, 0xaa, 0xad, 0x75, 0xa8, 0x98, 0x9e, 0x33, 0x76, 0xa7, 0xa6, 0x86, 0x4d, - 0x3a, 0x63, 0xc4, 0x29, 0x13, 0x50, 0x89, 0xb7, 0xe2, 0x08, 0x96, 0x92, 0x74, 0x10, 0xf1, 0x2b, - 0x51, 0xfc, 0x5a, 0x0b, 0xd6, 0xa3, 0xa6, 0x2d, 0x84, 0xf0, 0x08, 0x36, 0xba, 0xd8, 0x0f, 0xc8, - 0xd3, 0xf5, 0x0d, 0x7f, 0x4c, 0xf4, 0xa4, 0x69, 0x52, 0xd2, 0xb4, 0x2d, 0x28, 0x13, 0x26, 0xce, - 0x14, 0x2a, 0x7a, 0xd0, 0xd2, 0x9e, 0xc1, 0x66, 0x52, 0xe1, 0x42, 0xa6, 0x3d, 0x64, 0xa9, 0x7c, - 0x75, 0xd3, 0xb4, 0x97, 0xb0, 0xd9, 0xfe, 0x20, 0x26, 0x08, 0x20, 0xe5, 0x08, 0xc8, 0x3f, 0x4a, - 0xb0, 0xd1, 0xc2, 0xc3, 0xee, 0xd8, 0xc5, 0x5e, 0x9b, 0x46, 0x39, 0xe0, 0xb1, 0x18, 0x2f, 0x29, - 0xc6, 0xd7, 0x19, 0x6f, 0x4a, 0x59, 0xbc, 0x91, 0xa3, 0xbc, 0xc9, 0xe5, 0x07, 0x75, 0x76, 0xd2, - 0x8c, 0x85, 0x9c, 0xdd, 0xe3, 0xce, 0x8e, 0x03, 0xca, 0xe7, 0xc1, 0x3a, 0xc8, 0x94, 0xd9, 0x25, - 0xc6, 0x6c, 0xfa, 0x33, 0x1b, 0x90, 0xf6, 0x7b, 0x1e, 0x98, 0xeb, 0x9b, 0xbb, 0xe0, 0x3e, 0xf9, - 0x8c, 0x1d, 0x36, 0xbf, 0xf0, 0x2c, 0x1f, 0xb7, 0xac, 0xc1, 0x60, 0x71, 0x8c, 0xda, 0xef, 0x98, - 0xbb, 0xa2, 0x9a, 0x6e, 0x10, 0xc8, 0x9f, 0x15, 0xd0, 0x3a, 0x4e, 0xdf, 0x1a, 0x4c, 0x3a, 0xfc, - 0xa4, 0xd5, 0xb1, 0xd1, 0xa3, 0xc6, 0x1e, 0x5c, 0xfa, 0xd8, 0x26, 0x96, 0x63, 0x17, 0xcc, 0x62, - 0xba, 0x67, 0x3b, 0x63, 0xaf, 0x87, 0x67, 0x1b, 0x6c, 0xd8, 0x8e, 0x90, 0x59, 0x4e, 0x6e, 0xbe, - 0x04, 0x13, 0xba, 0xd0, 0xc9, 0xc4, 0xc5, 0x8c, 0x9a, 0x8a, 0x2e, 0x76, 0xa1, 0x4b, 0xf8, 0xcc, - 0x8b, 0x1b, 0xc5, 0x2e, 0x0d, 0x0a, 0xbb, 0x34, 0xec, 0xf3, 0x4b, 0x43, 0x2e, 0x86, 0xa6, 0x9e, - 0xa6, 0xe4, 0xc0, 0xf6, 0xbd, 0x89, 0x9e, 0xbe, 0x40, 0xfc, 0xa4, 0x2a, 0x27, 0x4f, 0xaa, 0xfb, - 0xd3, 0xd3, 0xa8, 0xb6, 0xb7, 0xdd, 0x34, 0x1d, 0xc7, 0x1c, 0x62, 0x7e, 0x59, 0x7d, 0x35, 0x1e, - 0x34, 0xbb, 0xbe, 0x67, 0xd9, 0xe6, 0xcf, 0x8d, 0xe1, 0x18, 0xd3, 0xb3, 0x0a, 0x3d, 0x86, 0x15, - 0xc3, 0xf7, 0x8d, 0xde, 0x6b, 0xdc, 0x3f, 0xb4, 0x07, 0x4e, 0x7d, 0xb9, 0xc0, 0xbc, 0xc8, 0x0c, - 0x4a, 0x0b, 0x8b, 0x30, 0x20, 0xf5, 0x6a, 0x43, 0xda, 0x59, 0xd6, 0xc3, 0x26, 0xda, 0x83, 0x4d, - 0x8b, 0x50, 0xf3, 0x3d, 0xdb, 0x18, 0xce, 0x80, 0xd7, 0x81, 0x89, 0xa5, 0x8e, 0xa1, 0x26, 0xa0, - 0x11, 0x31, 0x7f, 0x6c, 0x79, 0xc4, 0xe7, 0xfe, 0x63, 0x27, 0x6e, 0x8d, 0x9d, 0xb8, 0x29, 0x23, - 0x2a, 0x06, 0x35, 0xdb, 0x89, 0x94, 0xdb, 0x67, 0x78, 0x12, 0x70, 0x83, 0xfe, 0x44, 0xdf, 0x01, - 0xe5, 0x0d, 0x05, 0x11, 0xdc, 0x49, 0xbf, 0x48, 0x21, 0xe4, 0x73, 0x3c, 0xe1, 0x38, 0xb9, 0xe4, - 0x0f, 0x4a, 0xdf, 0x97, 0xb4, 0xbf, 0x2b, 0x70, 0x8b, 0x1e, 0x48, 0x1f, 0x87, 0x90, 0x4d, 0x40, - 0xe1, 0xef, 0x17, 0x43, 0xc3, 0x1f, 0x38, 0xde, 0x28, 0xd8, 0x32, 0x15, 0x3d, 0x65, 0x24, 0x4e, - 0x60, 0x25, 0x49, 0xe0, 0x71, 0x16, 0x81, 0xcb, 0x8c, 0xc0, 0x3f, 0x62, 0x04, 0xce, 0x01, 0x7c, - 0x7d, 0xf6, 0x56, 0xb2, 0xd8, 0xbb, 0xbc, 0x20, 0x7b, 0xab, 0xd7, 0x61, 0x2f, 0x14, 0x63, 0x6f, - 0xed, 0xca, 0xec, 0x5d, 0xf9, 0xd8, 0xec, 0xfd, 0xb7, 0x04, 0x8d, 0xf9, 0xc1, 0x5c, 0xf4, 0x5e, - 0x2d, 0x46, 0x53, 0x4e, 0x46, 0x33, 0xdd, 0x1f, 0x4b, 0x59, 0xfe, 0x10, 0xa3, 0xa1, 0x44, 0xa3, - 0x71, 0x17, 0xca, 0x1e, 0x26, 0xe3, 0x61, 0xc8, 0xd0, 0x4f, 0x19, 0x43, 0xa7, 0x60, 0x31, 0x71, - 0xf5, 0x40, 0x40, 0x7b, 0xaf, 0xc0, 0xad, 0x27, 0xfd, 0xfe, 0xff, 0x56, 0xae, 0xe6, 0x00, 0xfe, - 0x7f, 0xae, 0x5e, 0x37, 0x57, 0x69, 0x36, 0x12, 0x7c, 0x5e, 0x5f, 0xe5, 0xf7, 0x24, 0x82, 0xcf, - 0x6f, 0x32, 0x7b, 0xe7, 0x87, 0xf7, 0xbf, 0x29, 0x7b, 0xff, 0x25, 0xc3, 0x57, 0xed, 0xe9, 0x5e, - 0x45, 0xdd, 0x79, 0x8d, 0x0c, 0xce, 0xfc, 0xbe, 0x16, 0xb3, 0x5b, 0x8e, 0x65, 0x77, 0xfe, 0xf5, - 0x2f, 0x8b, 0x6e, 0xca, 0x1c, 0xba, 0x35, 0xa0, 0xe6, 0x4f, 0x5c, 0xfc, 0x1c, 0x4f, 0xa6, 0xb9, - 0x5b, 0xd5, 0xc5, 0x2e, 0x44, 0x60, 0x6b, 0x14, 0x8d, 0x71, 0x28, 0x5c, 0x61, 0x4e, 0x7b, 0xc4, - 0x9c, 0x56, 0xc0, 0x37, 0xcd, 0x4e, 0x42, 0x8d, 0x9e, 0xa1, 0x5a, 0x1d, 0x00, 0x4a, 0x4a, 0xc7, - 0xb9, 0x21, 0x15, 0xe5, 0x46, 0x29, 0x8b, 0x1b, 0xda, 0x3b, 0x09, 0x6e, 0xe7, 0x9b, 0xbe, 0x10, - 0x91, 0xbb, 0xb0, 0x41, 0x2c, 0xdb, 0x1c, 0xe2, 0x29, 0x10, 0xc6, 0x34, 0xfe, 0x7e, 0xf7, 0x25, - 0xbf, 0xc9, 0x88, 0xe3, 0xd3, 0x05, 0xb9, 0xa0, 0x9e, 0x36, 0x5b, 0x7b, 0x5f, 0x82, 0xed, 0x79, - 0xb3, 0x16, 0xb0, 0xd3, 0xcb, 0xda, 0xc7, 0xb9, 0xa5, 0x3f, 0xcc, 0xb5, 0xf4, 0xfa, 0x9b, 0xf8, - 0x52, 0x22, 0x90, 0x37, 0xb5, 0x89, 0xfd, 0x43, 0x82, 0xaf, 0x72, 0x3f, 0x88, 0x16, 0xfc, 0xc8, - 0xac, 0x91, 0x71, 0xaf, 0x87, 0x09, 0x11, 0x9c, 0x89, 0x98, 0x33, 0x99, 0xee, 0xf0, 0xe1, 0x50, - 0x17, 0xc5, 0xd0, 0x1e, 0xc0, 0xc0, 0xb0, 0x86, 0xb8, 0xcf, 0x26, 0x2d, 0x65, 0x4e, 0x12, 0xa4, - 0xb4, 0x77, 0x32, 0x7c, 0xd3, 0xc2, 0x43, 0xec, 0xe3, 0x8f, 0xb8, 0x3b, 0x7d, 0xf8, 0xfb, 0x45, - 0xfe, 0x27, 0x65, 0xd6, 0x7e, 0x57, 0xb9, 0xf2, 0xf1, 0xba, 0x9c, 0x79, 0x78, 0x1c, 0x67, 0x65, - 0x47, 0x95, 0xc5, 0x66, 0x2e, 0xcf, 0xd2, 0x67, 0x6a, 0x7f, 0x92, 0xe0, 0x4e, 0xa1, 0x78, 0x2d, - 0xc4, 0xbb, 0x2b, 0x9c, 0x69, 0x0e, 0xac, 0x46, 0x58, 0x85, 0xee, 0x43, 0x15, 0x87, 0x1d, 0x41, - 0xad, 0xe6, 0x93, 0x18, 0xf9, 0x66, 0x02, 0xa2, 0x6d, 0xa5, 0x2c, 0xdb, 0xe4, 0xc8, 0x83, 0xd7, - 0x3f, 0x4b, 0x50, 0x9d, 0xaa, 0x42, 0xa7, 0x59, 0xae, 0x95, 0x98, 0xe1, 0x77, 0xa3, 0x2b, 0x5f, - 0x7f, 0x97, 0x29, 0x15, 0x3d, 0x2e, 0xe4, 0x4c, 0x36, 0x68, 0xb1, 0xcb, 0x22, 0xdf, 0xb8, 0xa2, - 0xd7, 0x41, 0xfe, 0xec, 0xae, 0x84, 0xcf, 0xee, 0xea, 0xaf, 0xae, 0xb8, 0x93, 0xdd, 0x89, 0xee, - 0x64, 0x29, 0xf1, 0x13, 0xf6, 0xaf, 0x09, 0xac, 0x88, 0x43, 0xe8, 0x21, 0x2c, 0x9f, 0x05, 0xed, - 0x20, 0x80, 0x73, 0x19, 0x3a, 0x15, 0x5e, 0x20, 0x98, 0x6f, 0x25, 0xd8, 0x10, 0xca, 0x5d, 0xd4, - 0x47, 0xac, 0xde, 0x95, 0xa8, 0x6a, 0x49, 0x05, 0xaa, 0x5a, 0xa5, 0x2b, 0x57, 0xb5, 0xe4, 0x58, - 0x55, 0x6b, 0xef, 0x0f, 0x00, 0xf2, 0x88, 0x98, 0xe8, 0x25, 0xac, 0xc5, 0xaa, 0x51, 0xe8, 0xeb, - 0x14, 0x1f, 0x24, 0x2b, 0x60, 0xea, 0x37, 0x45, 0xc4, 0x88, 0x8b, 0x1c, 0xd8, 0x7c, 0x31, 0x1e, - 0x0e, 0x83, 0xec, 0xdd, 0x9f, 0x74, 0xf1, 0x39, 0xb3, 0xef, 0xdb, 0x29, 0xf3, 0xd3, 0x04, 0xe9, - 0x5a, 0xf7, 0x0a, 0xcb, 0xb2, 0xbc, 0xac, 0x04, 0x2f, 0xeb, 0x68, 0x2d, 0x78, 0x02, 0x09, 0xab, - 0x5e, 0xea, 0x7a, 0xb4, 0x83, 0xb8, 0xe8, 0x18, 0xa0, 0x85, 0x87, 0x1d, 0x62, 0xf2, 0x24, 0x48, - 0x59, 0x68, 0x36, 0x4c, 0x35, 0x7c, 0x99, 0x23, 0x41, 0x5c, 0xd4, 0x86, 0xf5, 0xf8, 0x9b, 0x37, - 0xaa, 0xb3, 0x85, 0x53, 0x5e, 0xe4, 0xd5, 0xcf, 0x33, 0x46, 0x88, 0x8b, 0x76, 0x61, 0x39, 0x2c, - 0x0f, 0x21, 0x6e, 0xb9, 0x50, 0x92, 0x52, 0x3f, 0x8d, 0xf5, 0x10, 0x17, 0x3d, 0x82, 0x15, 0xb1, - 0xe2, 0x82, 0x36, 0xa7, 0x4f, 0x40, 0x42, 0x7d, 0x48, 0xfd, 0x2c, 0xa5, 0x97, 0x9b, 0x1d, 0xaf, - 0x8b, 0x04, 0x66, 0xa7, 0xd4, 0x5f, 0x02, 0xb3, 0x53, 0x0b, 0x29, 0x6d, 0x58, 0x6f, 0xa7, 0x2b, - 0x6a, 0x67, 0x2a, 0x6a, 0xcf, 0x51, 0x94, 0xe2, 0xc8, 0x94, 0x4a, 0x80, 0xa0, 0x28, 0xe1, 0xc8, - 0x16, 0x63, 0xb9, 0xf8, 0x18, 0x8e, 0xbe, 0x15, 0x4a, 0xc7, 0x1e, 0xdb, 0xd5, 0x7a, 0xfa, 0x00, - 0x71, 0xd1, 0x19, 0x6c, 0xcf, 0x7b, 0x80, 0x41, 0xb7, 0x8b, 0x3c, 0xb8, 0xa9, 0x5f, 0x17, 0x90, - 0x22, 0x2e, 0xba, 0x80, 0x46, 0xde, 0x55, 0x1b, 0xed, 0x14, 0xfd, 0x98, 0x50, 0xef, 0x16, 0x94, - 0xe4, 0x28, 0xe7, 0x7d, 0xa8, 0x06, 0x28, 0x73, 0x9e, 0x2a, 0x02, 0x94, 0xb9, 0x5f, 0xbc, 0xbf, - 0x85, 0x5b, 0x91, 0xc3, 0x3d, 0x65, 0xbd, 0x7b, 0x61, 0x7e, 0x14, 0xb8, 0xb2, 0xa9, 0xf7, 0x8b, - 0x0b, 0x13, 0x77, 0xff, 0x8b, 0x5f, 0x7e, 0x7e, 0xe4, 0x62, 0xfb, 0xf4, 0xb0, 0x23, 0xfc, 0x45, - 0x64, 0x44, 0xcc, 0x47, 0x23, 0x62, 0xbe, 0x2a, 0xb3, 0xe6, 0x77, 0xff, 0x13, 0x00, 0x00, 0xff, - 0xff, 0x4c, 0x17, 0xe7, 0xd8, 0x8b, 0x22, 0x00, 0x00, -} diff --git a/tools/data-conversion/openim/proto/msg/msg.proto b/tools/data-conversion/openim/proto/msg/msg.proto deleted file mode 100644 index 3149a73374..0000000000 --- a/tools/data-conversion/openim/proto/msg/msg.proto +++ /dev/null @@ -1,329 +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. - -syntax = "proto3"; -import "Open-IM-Server/pkg/proto/sdk_ws/ws.proto"; -import "Open-IM-Server/pkg/proto/sdk_ws/wrappers.proto"; -option go_package = "Open_IM/pkg/proto/msg;msg"; -package msg; - -message MsgDataToMQ{ - string token =1; - string operationID = 2; - server_api_params.MsgData msgData = 3; -} - - -message MsgDataToDB { - server_api_params.MsgData msgData = 1; - string operationID = 2; - -} -message PushMsgDataToMQ{ - string OperationID = 1; - server_api_params.MsgData msgData = 2; - string pushToUserID = 3; -} -message MsgDataToMongoByMQ{ - uint64 lastSeq =1; - string aggregationID = 2; - repeated MsgDataToMQ messageList = 3; - string triggerID = 4; - - -} - -//message PullMessageReq { -// string UserID = 1; -// int64 SeqBegin = 2; -// int64 SeqEnd = 3; -// string OperationID = 4; -//} -// -//message PullMessageResp { -// int32 ErrCode = 1; -// string ErrMsg = 2; -// int64 MaxSeq = 3; -// int64 MinSeq = 4; -// repeated GatherFormat SingleUserMsg = 5; -// repeated GatherFormat GroupUserMsg = 6; -//} -//message PullMessageBySeqListReq{ -// string UserID = 1; -// string OperationID = 2; -// repeated int64 seqList =3; -//} -message GetMaxAndMinSeqReq { - string UserID = 1; - string OperationID = 2; -} -message GetMaxAndMinSeqResp { - int32 ErrCode = 1; - string ErrMsg = 2; - uint32 MaxSeq = 3; - uint32 MinSeq = 4; -} - -message SendMsgReq { - -string token =1; -string operationID = 2; -server_api_params.MsgData msgData = 3; - - -} - -message SendMsgResp { - int32 errCode = 1; - string errMsg = 2; - string serverMsgID = 4; - string clientMsgID = 5; - int64 sendTime = 6; - string ex = 7; -} - - -message ClearMsgReq{ - string userID = 1; - string opUserID = 2; - string operationID = 3; -} - - -message ClearMsgResp{ - int32 errCode = 1; - string errMsg = 2; -} - -message SetMsgMinSeqReq{ - string userID = 1; - string groupID = 2; - uint32 minSeq = 3; - string operationID = 4; - string opUserID = 5; -} -message SetMsgMinSeqResp{ - int32 errCode = 1; - string errMsg = 2; -} - -message SetSendMsgStatusReq{ - string operationID = 1; - int32 status = 2; -} - -message SetSendMsgStatusResp{ - int32 errCode = 1; - string errMsg = 2; -} - -message GetSendMsgStatusReq{ - string operationID = 1; -} - -message GetSendMsgStatusResp{ - int32 errCode = 1; - string errMsg = 2; - int32 status = 3; -} -message DelSuperGroupMsgReq{ - string opUserID = 1; - string userID = 2; - string groupID = 3; - string operationID = 4; -} -message DelSuperGroupMsgResp{ - int32 errCode = 1; - string errMsg = 2; -} -message GetSuperGroupMsgReq{ - string operationID = 1; - uint32 Seq = 2; - string groupID = 3; - -} -message GetSuperGroupMsgResp{ - int32 errCode = 1; - string errMsg = 2; - server_api_params.MsgData msgData = 3; -} -message GetWriteDiffMsgReq{ - string operationID = 1; - uint32 Seq = 2; - - } -message GetWriteDiffMsgResp{ - int32 errCode = 1; - string errMsg = 2; - server_api_params.MsgData msgData = 3; -} - -message ModifyMessageReactionExtensionsReq { - string operationID = 1; - string sourceID = 2; - string opUserID = 3; - int32 sessionType = 4; - map reactionExtensionList = 5; - string clientMsgID = 6; - google.protobuf.StringValue ex = 7; - google.protobuf.StringValue attachedInfo = 8; - bool isReact = 9; - bool isExternalExtensions = 10; - int64 msgFirstModifyTime = 11; -} -message SetMessageReactionExtensionsReq { - string operationID = 1; - string sourceID = 2; - string opUserID = 3; - int32 opUserIDPlatformID = 4; - int32 sessionType = 5; - map reactionExtensionList = 6; - string clientMsgID = 7; - google.protobuf.StringValue ex = 8; - google.protobuf.StringValue attachedInfo = 9; - bool isReact = 10; - bool isExternalExtensions = 11; - int64 msgFirstModifyTime = 12; -} -message SetMessageReactionExtensionsResp { - int32 errCode = 1; - string errMsg = 2; - string clientMsgID = 3; - int64 msgFirstModifyTime = 4; - bool isReact = 5; - repeated KeyValueResp result = 6; -} -message AddMessageReactionExtensionsReq { - string operationID = 1; - string sourceID = 2; - string opUserID = 3; - int32 opUserIDPlatformID = 4; - int32 sessionType = 5; - map reactionExtensionList = 6; - string clientMsgID = 7; - google.protobuf.StringValue ex = 8; - google.protobuf.StringValue attachedInfo = 9; - bool isReact = 10; - bool isExternalExtensions = 11; - int64 msgFirstModifyTime = 12; - uint32 seq = 13; -} -message AddMessageReactionExtensionsResp { - int32 errCode = 1; - string errMsg = 2; - string clientMsgID = 3; - int64 msgFirstModifyTime = 4; - bool isReact = 5; - repeated KeyValueResp result = 6; -} - - -message GetMessageListReactionExtensionsReq { - string operationID = 1; - string opUserID = 2; - string sourceID = 3; - int32 sessionType = 4; - bool isExternalExtensions = 5; - message MessageReactionKey { - string clientMsgID = 1; - int64 msgFirstModifyTime = 2; - } - repeated string typeKeyList = 6; - repeated MessageReactionKey messageReactionKeyList = 7; -} -message GetMessageListReactionExtensionsResp{ - int32 errCode = 1; - string errMsg = 2; - repeated SingleMessageExtensionResult singleMessageResult =3; - -} -message SingleMessageExtensionResult { - int32 errCode = 1; - string errMsg = 2; - map reactionExtensionList = 3; - string clientMsgID = 4; -} - - -message ModifyMessageReactionExtensionsResp { - int32 errCode = 1; - string errMsg = 2; - repeated ExtendMsgResp successList = 3; - repeated ExtendMsgResp failedList = 4; -} - -message DeleteMessageListReactionExtensionsReq { - string operationID = 1; - string opUserID = 2; - string sourceID = 3; - int32 opUserIDPlatformID = 4; - int32 sessionType = 5; - string clientMsgID = 6; - bool isExternalExtensions = 7; - int64 msgFirstModifyTime = 8; - repeated server_api_params.KeyValue reactionExtensionList = 9; -} - -message DeleteMessageListReactionExtensionsResp { - int32 errCode = 1; - string errMsg = 2; - repeated KeyValueResp result = 6; -} - -message ExtendMsgResp { - ExtendMsg extendMsg = 1; - int32 errCode = 2; - string errMsg = 3; -} - -message ExtendMsg { - map reactionExtensionList = 1; - string clientMsgID = 2; - int64 msgFirstModifyTime = 3; - string attachedInfo = 4; - string ex = 5; -} - -message KeyValueResp { - server_api_params.KeyValue keyValue = 1; - int32 errCode = 2; - string errMsg = 3; -} - -message MsgDataToModifyByMQ{ - string aggregationID = 1; - repeated MsgDataToMQ messageList = 2; - string triggerID = 3; -} - - -service msg { - rpc GetMaxAndMinSeq(server_api_params.GetMaxAndMinSeqReq) returns(server_api_params.GetMaxAndMinSeqResp); - rpc PullMessageBySeqList(server_api_params.PullMessageBySeqListReq) returns(server_api_params.PullMessageBySeqListResp); - rpc SendMsg(SendMsgReq) returns(SendMsgResp); - rpc DelMsgList(server_api_params.DelMsgListReq) returns(server_api_params.DelMsgListResp); - rpc DelSuperGroupMsg(DelSuperGroupMsgReq) returns(DelSuperGroupMsgResp); - rpc ClearMsg(ClearMsgReq) returns(ClearMsgResp); - rpc SetMsgMinSeq(SetMsgMinSeqReq) returns(SetMsgMinSeqResp); - rpc SetSendMsgStatus(SetSendMsgStatusReq) returns(SetSendMsgStatusResp); - rpc GetSendMsgStatus(GetSendMsgStatusReq) returns(GetSendMsgStatusResp); - rpc GetSuperGroupMsg(GetSuperGroupMsgReq) returns(GetSuperGroupMsgResp); - rpc GetWriteDiffMsg(GetWriteDiffMsgReq) returns(GetWriteDiffMsgResp); - - // modify msg - rpc SetMessageReactionExtensions(SetMessageReactionExtensionsReq) returns(SetMessageReactionExtensionsResp); - rpc GetMessageListReactionExtensions(GetMessageListReactionExtensionsReq) returns(GetMessageListReactionExtensionsResp); - rpc AddMessageReactionExtensions(AddMessageReactionExtensionsReq) returns(AddMessageReactionExtensionsResp); - rpc DeleteMessageReactionExtensions(DeleteMessageListReactionExtensionsReq) returns(DeleteMessageListReactionExtensionsResp); -} diff --git a/tools/data-conversion/openim/proto/sdk_ws/wrappers.proto b/tools/data-conversion/openim/proto/sdk_ws/wrappers.proto deleted file mode 100644 index c571f09687..0000000000 --- a/tools/data-conversion/openim/proto/sdk_ws/wrappers.proto +++ /dev/null @@ -1,123 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// Wrappers for primitive (non-message) types. These types are useful -// for embedding primitives in the `google.protobuf.Any` type and for places -// where we need to distinguish between the absence of a primitive -// typed field and its default value. -// -// These wrappers have no meaningful use within repeated fields as they lack -// the ability to detect presence on individual elements. -// These wrappers have no meaningful use within a map or a oneof since -// individual entries of a map or fields of a oneof can already detect presence. - -syntax = "proto3"; - -package google.protobuf; - -option csharp_namespace = "Google.Protobuf.WellKnownTypes"; -option cc_enable_arenas = true; -option go_package = "google.golang.org/protobuf/types/known/wrapperspb"; -option java_package = "com.google.protobuf"; -option java_outer_classname = "WrappersProto"; -option java_multiple_files = true; -option objc_class_prefix = "GPB"; - -// Wrapper message for `double`. -// -// The JSON representation for `DoubleValue` is JSON number. -message DoubleValue { - // The double value. - double value = 1; -} - -// Wrapper message for `float`. -// -// The JSON representation for `FloatValue` is JSON number. -message FloatValue { - // The float value. - float value = 1; -} - -// Wrapper message for `int64`. -// -// The JSON representation for `Int64Value` is JSON string. -message Int64Value { - // The int64 value. - int64 value = 1; -} - -// Wrapper message for `uint64`. -// -// The JSON representation for `UInt64Value` is JSON string. -message UInt64Value { - // The uint64 value. - uint64 value = 1; -} - -// Wrapper message for `int32`. -// -// The JSON representation for `Int32Value` is JSON number. -message Int32Value { - // The int32 value. - int32 value = 1; -} - -// Wrapper message for `uint32`. -// -// The JSON representation for `UInt32Value` is JSON number. -message UInt32Value { - // The uint32 value. - uint32 value = 1; -} - -// Wrapper message for `bool`. -// -// The JSON representation for `BoolValue` is JSON `true` and `false`. -message BoolValue { - // The bool value. - bool value = 1; -} - -// Wrapper message for `string`. -// -// The JSON representation for `StringValue` is JSON string. -message StringValue { - // The string value. - string value = 1; -} - -// Wrapper message for `bytes`. -// -// The JSON representation for `BytesValue` is JSON string. -message BytesValue { - // The bytes value. - bytes value = 1; -} \ No newline at end of file diff --git a/tools/data-conversion/openim/proto/sdk_ws/ws.pb.go b/tools/data-conversion/openim/proto/sdk_ws/ws.pb.go deleted file mode 100644 index 94b6f9be6b..0000000000 --- a/tools/data-conversion/openim/proto/sdk_ws/ws.pb.go +++ /dev/null @@ -1,6622 +0,0 @@ -// Code generated by protoc-gen-go. DO NOT EDIT. -// source: sdk_ws/ws.proto - -package server_api_params // import "Open_IM/pkg/proto/sdk_ws" - -import proto "github.com/golang/protobuf/proto" -import fmt "fmt" -import math "math" -import wrapperspb "google.golang.org/protobuf/types/known/wrapperspb" - -// Reference imports to suppress errors if they are not otherwise used. -var _ = proto.Marshal -var _ = fmt.Errorf -var _ = math.Inf - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the proto package it is being compiled against. -// A compilation error at this line likely means your copy of the -// proto package needs to be updated. -const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package - -type GroupInfo struct { - GroupID string `protobuf:"bytes,1,opt,name=groupID" json:"groupID,omitempty"` - GroupName string `protobuf:"bytes,2,opt,name=groupName" json:"groupName,omitempty"` - Notification string `protobuf:"bytes,3,opt,name=notification" json:"notification,omitempty"` - Introduction string `protobuf:"bytes,4,opt,name=introduction" json:"introduction,omitempty"` - FaceURL string `protobuf:"bytes,5,opt,name=faceURL" json:"faceURL,omitempty"` - OwnerUserID string `protobuf:"bytes,6,opt,name=ownerUserID" json:"ownerUserID,omitempty"` - CreateTime uint32 `protobuf:"varint,7,opt,name=createTime" json:"createTime,omitempty"` - MemberCount uint32 `protobuf:"varint,8,opt,name=memberCount" json:"memberCount,omitempty"` - Ex string `protobuf:"bytes,9,opt,name=ex" json:"ex,omitempty"` - Status int32 `protobuf:"varint,10,opt,name=status" json:"status,omitempty"` - CreatorUserID string `protobuf:"bytes,11,opt,name=creatorUserID" json:"creatorUserID,omitempty"` - GroupType int32 `protobuf:"varint,12,opt,name=groupType" json:"groupType,omitempty"` - NeedVerification int32 `protobuf:"varint,13,opt,name=needVerification" json:"needVerification,omitempty"` - LookMemberInfo int32 `protobuf:"varint,14,opt,name=lookMemberInfo" json:"lookMemberInfo,omitempty"` - ApplyMemberFriend int32 `protobuf:"varint,15,opt,name=applyMemberFriend" json:"applyMemberFriend,omitempty"` - NotificationUpdateTime uint32 `protobuf:"varint,16,opt,name=notificationUpdateTime" json:"notificationUpdateTime,omitempty"` - NotificationUserID string `protobuf:"bytes,17,opt,name=notificationUserID" json:"notificationUserID,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *GroupInfo) Reset() { *m = GroupInfo{} } -func (m *GroupInfo) String() string { return proto.CompactTextString(m) } -func (*GroupInfo) ProtoMessage() {} -func (*GroupInfo) Descriptor() ([]byte, []int) { - return fileDescriptor_ws_bc78a4975e7e5f46, []int{0} -} -func (m *GroupInfo) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_GroupInfo.Unmarshal(m, b) -} -func (m *GroupInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_GroupInfo.Marshal(b, m, deterministic) -} -func (dst *GroupInfo) XXX_Merge(src proto.Message) { - xxx_messageInfo_GroupInfo.Merge(dst, src) -} -func (m *GroupInfo) XXX_Size() int { - return xxx_messageInfo_GroupInfo.Size(m) -} -func (m *GroupInfo) XXX_DiscardUnknown() { - xxx_messageInfo_GroupInfo.DiscardUnknown(m) -} - -var xxx_messageInfo_GroupInfo proto.InternalMessageInfo - -func (m *GroupInfo) GetGroupID() string { - if m != nil { - return m.GroupID - } - return "" -} - -func (m *GroupInfo) GetGroupName() string { - if m != nil { - return m.GroupName - } - return "" -} - -func (m *GroupInfo) GetNotification() string { - if m != nil { - return m.Notification - } - return "" -} - -func (m *GroupInfo) GetIntroduction() string { - if m != nil { - return m.Introduction - } - return "" -} - -func (m *GroupInfo) GetFaceURL() string { - if m != nil { - return m.FaceURL - } - return "" -} - -func (m *GroupInfo) GetOwnerUserID() string { - if m != nil { - return m.OwnerUserID - } - return "" -} - -func (m *GroupInfo) GetCreateTime() uint32 { - if m != nil { - return m.CreateTime - } - return 0 -} - -func (m *GroupInfo) GetMemberCount() uint32 { - if m != nil { - return m.MemberCount - } - return 0 -} - -func (m *GroupInfo) GetEx() string { - if m != nil { - return m.Ex - } - return "" -} - -func (m *GroupInfo) GetStatus() int32 { - if m != nil { - return m.Status - } - return 0 -} - -func (m *GroupInfo) GetCreatorUserID() string { - if m != nil { - return m.CreatorUserID - } - return "" -} - -func (m *GroupInfo) GetGroupType() int32 { - if m != nil { - return m.GroupType - } - return 0 -} - -func (m *GroupInfo) GetNeedVerification() int32 { - if m != nil { - return m.NeedVerification - } - return 0 -} - -func (m *GroupInfo) GetLookMemberInfo() int32 { - if m != nil { - return m.LookMemberInfo - } - return 0 -} - -func (m *GroupInfo) GetApplyMemberFriend() int32 { - if m != nil { - return m.ApplyMemberFriend - } - return 0 -} - -func (m *GroupInfo) GetNotificationUpdateTime() uint32 { - if m != nil { - return m.NotificationUpdateTime - } - return 0 -} - -func (m *GroupInfo) GetNotificationUserID() string { - if m != nil { - return m.NotificationUserID - } - return "" -} - -type GroupInfoForSet struct { - GroupID string `protobuf:"bytes,1,opt,name=groupID" json:"groupID,omitempty"` - GroupName string `protobuf:"bytes,2,opt,name=groupName" json:"groupName,omitempty"` - Notification string `protobuf:"bytes,3,opt,name=notification" json:"notification,omitempty"` - Introduction string `protobuf:"bytes,4,opt,name=introduction" json:"introduction,omitempty"` - FaceURL string `protobuf:"bytes,5,opt,name=faceURL" json:"faceURL,omitempty"` - Ex string `protobuf:"bytes,6,opt,name=ex" json:"ex,omitempty"` - NeedVerification *wrapperspb.Int32Value `protobuf:"bytes,7,opt,name=needVerification" json:"needVerification,omitempty"` - LookMemberInfo *wrapperspb.Int32Value `protobuf:"bytes,8,opt,name=lookMemberInfo" json:"lookMemberInfo,omitempty"` - ApplyMemberFriend *wrapperspb.Int32Value `protobuf:"bytes,9,opt,name=applyMemberFriend" json:"applyMemberFriend,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *GroupInfoForSet) Reset() { *m = GroupInfoForSet{} } -func (m *GroupInfoForSet) String() string { return proto.CompactTextString(m) } -func (*GroupInfoForSet) ProtoMessage() {} -func (*GroupInfoForSet) Descriptor() ([]byte, []int) { - return fileDescriptor_ws_bc78a4975e7e5f46, []int{1} -} -func (m *GroupInfoForSet) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_GroupInfoForSet.Unmarshal(m, b) -} -func (m *GroupInfoForSet) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_GroupInfoForSet.Marshal(b, m, deterministic) -} -func (dst *GroupInfoForSet) XXX_Merge(src proto.Message) { - xxx_messageInfo_GroupInfoForSet.Merge(dst, src) -} -func (m *GroupInfoForSet) XXX_Size() int { - return xxx_messageInfo_GroupInfoForSet.Size(m) -} -func (m *GroupInfoForSet) XXX_DiscardUnknown() { - xxx_messageInfo_GroupInfoForSet.DiscardUnknown(m) -} - -var xxx_messageInfo_GroupInfoForSet proto.InternalMessageInfo - -func (m *GroupInfoForSet) GetGroupID() string { - if m != nil { - return m.GroupID - } - return "" -} - -func (m *GroupInfoForSet) GetGroupName() string { - if m != nil { - return m.GroupName - } - return "" -} - -func (m *GroupInfoForSet) GetNotification() string { - if m != nil { - return m.Notification - } - return "" -} - -func (m *GroupInfoForSet) GetIntroduction() string { - if m != nil { - return m.Introduction - } - return "" -} - -func (m *GroupInfoForSet) GetFaceURL() string { - if m != nil { - return m.FaceURL - } - return "" -} - -func (m *GroupInfoForSet) GetEx() string { - if m != nil { - return m.Ex - } - return "" -} - -func (m *GroupInfoForSet) GetNeedVerification() *wrapperspb.Int32Value { - if m != nil { - return m.NeedVerification - } - return nil -} - -func (m *GroupInfoForSet) GetLookMemberInfo() *wrapperspb.Int32Value { - if m != nil { - return m.LookMemberInfo - } - return nil -} - -func (m *GroupInfoForSet) GetApplyMemberFriend() *wrapperspb.Int32Value { - if m != nil { - return m.ApplyMemberFriend - } - return nil -} - -type GroupMemberFullInfo struct { - GroupID string `protobuf:"bytes,1,opt,name=groupID" json:"groupID,omitempty"` - UserID string `protobuf:"bytes,2,opt,name=userID" json:"userID,omitempty"` - RoleLevel int32 `protobuf:"varint,3,opt,name=roleLevel" json:"roleLevel,omitempty"` - JoinTime int32 `protobuf:"varint,4,opt,name=joinTime" json:"joinTime,omitempty"` - Nickname string `protobuf:"bytes,5,opt,name=nickname" json:"nickname,omitempty"` - FaceURL string `protobuf:"bytes,6,opt,name=faceURL" json:"faceURL,omitempty"` - AppMangerLevel int32 `protobuf:"varint,7,opt,name=appMangerLevel" json:"appMangerLevel,omitempty"` - JoinSource int32 `protobuf:"varint,8,opt,name=joinSource" json:"joinSource,omitempty"` - OperatorUserID string `protobuf:"bytes,9,opt,name=operatorUserID" json:"operatorUserID,omitempty"` - Ex string `protobuf:"bytes,10,opt,name=ex" json:"ex,omitempty"` - MuteEndTime uint32 `protobuf:"varint,11,opt,name=muteEndTime" json:"muteEndTime,omitempty"` - InviterUserID string `protobuf:"bytes,12,opt,name=inviterUserID" json:"inviterUserID,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *GroupMemberFullInfo) Reset() { *m = GroupMemberFullInfo{} } -func (m *GroupMemberFullInfo) String() string { return proto.CompactTextString(m) } -func (*GroupMemberFullInfo) ProtoMessage() {} -func (*GroupMemberFullInfo) Descriptor() ([]byte, []int) { - return fileDescriptor_ws_bc78a4975e7e5f46, []int{2} -} -func (m *GroupMemberFullInfo) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_GroupMemberFullInfo.Unmarshal(m, b) -} -func (m *GroupMemberFullInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_GroupMemberFullInfo.Marshal(b, m, deterministic) -} -func (dst *GroupMemberFullInfo) XXX_Merge(src proto.Message) { - xxx_messageInfo_GroupMemberFullInfo.Merge(dst, src) -} -func (m *GroupMemberFullInfo) XXX_Size() int { - return xxx_messageInfo_GroupMemberFullInfo.Size(m) -} -func (m *GroupMemberFullInfo) XXX_DiscardUnknown() { - xxx_messageInfo_GroupMemberFullInfo.DiscardUnknown(m) -} - -var xxx_messageInfo_GroupMemberFullInfo proto.InternalMessageInfo - -func (m *GroupMemberFullInfo) GetGroupID() string { - if m != nil { - return m.GroupID - } - return "" -} - -func (m *GroupMemberFullInfo) GetUserID() string { - if m != nil { - return m.UserID - } - return "" -} - -func (m *GroupMemberFullInfo) GetRoleLevel() int32 { - if m != nil { - return m.RoleLevel - } - return 0 -} - -func (m *GroupMemberFullInfo) GetJoinTime() int32 { - if m != nil { - return m.JoinTime - } - return 0 -} - -func (m *GroupMemberFullInfo) GetNickname() string { - if m != nil { - return m.Nickname - } - return "" -} - -func (m *GroupMemberFullInfo) GetFaceURL() string { - if m != nil { - return m.FaceURL - } - return "" -} - -func (m *GroupMemberFullInfo) GetAppMangerLevel() int32 { - if m != nil { - return m.AppMangerLevel - } - return 0 -} - -func (m *GroupMemberFullInfo) GetJoinSource() int32 { - if m != nil { - return m.JoinSource - } - return 0 -} - -func (m *GroupMemberFullInfo) GetOperatorUserID() string { - if m != nil { - return m.OperatorUserID - } - return "" -} - -func (m *GroupMemberFullInfo) GetEx() string { - if m != nil { - return m.Ex - } - return "" -} - -func (m *GroupMemberFullInfo) GetMuteEndTime() uint32 { - if m != nil { - return m.MuteEndTime - } - return 0 -} - -func (m *GroupMemberFullInfo) GetInviterUserID() string { - if m != nil { - return m.InviterUserID - } - return "" -} - -type PublicUserInfo struct { - UserID string `protobuf:"bytes,1,opt,name=userID" json:"userID,omitempty"` - Nickname string `protobuf:"bytes,2,opt,name=nickname" json:"nickname,omitempty"` - FaceURL string `protobuf:"bytes,3,opt,name=faceURL" json:"faceURL,omitempty"` - Gender int32 `protobuf:"varint,4,opt,name=gender" json:"gender,omitempty"` - Ex string `protobuf:"bytes,5,opt,name=ex" json:"ex,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *PublicUserInfo) Reset() { *m = PublicUserInfo{} } -func (m *PublicUserInfo) String() string { return proto.CompactTextString(m) } -func (*PublicUserInfo) ProtoMessage() {} -func (*PublicUserInfo) Descriptor() ([]byte, []int) { - return fileDescriptor_ws_bc78a4975e7e5f46, []int{3} -} -func (m *PublicUserInfo) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_PublicUserInfo.Unmarshal(m, b) -} -func (m *PublicUserInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_PublicUserInfo.Marshal(b, m, deterministic) -} -func (dst *PublicUserInfo) XXX_Merge(src proto.Message) { - xxx_messageInfo_PublicUserInfo.Merge(dst, src) -} -func (m *PublicUserInfo) XXX_Size() int { - return xxx_messageInfo_PublicUserInfo.Size(m) -} -func (m *PublicUserInfo) XXX_DiscardUnknown() { - xxx_messageInfo_PublicUserInfo.DiscardUnknown(m) -} - -var xxx_messageInfo_PublicUserInfo proto.InternalMessageInfo - -func (m *PublicUserInfo) GetUserID() string { - if m != nil { - return m.UserID - } - return "" -} - -func (m *PublicUserInfo) GetNickname() string { - if m != nil { - return m.Nickname - } - return "" -} - -func (m *PublicUserInfo) GetFaceURL() string { - if m != nil { - return m.FaceURL - } - return "" -} - -func (m *PublicUserInfo) GetGender() int32 { - if m != nil { - return m.Gender - } - return 0 -} - -func (m *PublicUserInfo) GetEx() string { - if m != nil { - return m.Ex - } - return "" -} - -type UserInfo struct { - UserID string `protobuf:"bytes,1,opt,name=userID" json:"userID,omitempty"` - Nickname string `protobuf:"bytes,2,opt,name=nickname" json:"nickname,omitempty"` - FaceURL string `protobuf:"bytes,3,opt,name=faceURL" json:"faceURL,omitempty"` - Gender int32 `protobuf:"varint,4,opt,name=gender" json:"gender,omitempty"` - PhoneNumber string `protobuf:"bytes,5,opt,name=phoneNumber" json:"phoneNumber,omitempty"` - Birth uint32 `protobuf:"varint,6,opt,name=birth" json:"birth,omitempty"` - Email string `protobuf:"bytes,7,opt,name=email" json:"email,omitempty"` - Ex string `protobuf:"bytes,8,opt,name=ex" json:"ex,omitempty"` - CreateTime uint32 `protobuf:"varint,9,opt,name=createTime" json:"createTime,omitempty"` - AppMangerLevel int32 `protobuf:"varint,10,opt,name=appMangerLevel" json:"appMangerLevel,omitempty"` - GlobalRecvMsgOpt int32 `protobuf:"varint,11,opt,name=globalRecvMsgOpt" json:"globalRecvMsgOpt,omitempty"` - BirthStr string `protobuf:"bytes,12,opt,name=birthStr" json:"birthStr,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *UserInfo) Reset() { *m = UserInfo{} } -func (m *UserInfo) String() string { return proto.CompactTextString(m) } -func (*UserInfo) ProtoMessage() {} -func (*UserInfo) Descriptor() ([]byte, []int) { - return fileDescriptor_ws_bc78a4975e7e5f46, []int{4} -} -func (m *UserInfo) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_UserInfo.Unmarshal(m, b) -} -func (m *UserInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_UserInfo.Marshal(b, m, deterministic) -} -func (dst *UserInfo) XXX_Merge(src proto.Message) { - xxx_messageInfo_UserInfo.Merge(dst, src) -} -func (m *UserInfo) XXX_Size() int { - return xxx_messageInfo_UserInfo.Size(m) -} -func (m *UserInfo) XXX_DiscardUnknown() { - xxx_messageInfo_UserInfo.DiscardUnknown(m) -} - -var xxx_messageInfo_UserInfo proto.InternalMessageInfo - -func (m *UserInfo) GetUserID() string { - if m != nil { - return m.UserID - } - return "" -} - -func (m *UserInfo) GetNickname() string { - if m != nil { - return m.Nickname - } - return "" -} - -func (m *UserInfo) GetFaceURL() string { - if m != nil { - return m.FaceURL - } - return "" -} - -func (m *UserInfo) GetGender() int32 { - if m != nil { - return m.Gender - } - return 0 -} - -func (m *UserInfo) GetPhoneNumber() string { - if m != nil { - return m.PhoneNumber - } - return "" -} - -func (m *UserInfo) GetBirth() uint32 { - if m != nil { - return m.Birth - } - return 0 -} - -func (m *UserInfo) GetEmail() string { - if m != nil { - return m.Email - } - return "" -} - -func (m *UserInfo) GetEx() string { - if m != nil { - return m.Ex - } - return "" -} - -func (m *UserInfo) GetCreateTime() uint32 { - if m != nil { - return m.CreateTime - } - return 0 -} - -func (m *UserInfo) GetAppMangerLevel() int32 { - if m != nil { - return m.AppMangerLevel - } - return 0 -} - -func (m *UserInfo) GetGlobalRecvMsgOpt() int32 { - if m != nil { - return m.GlobalRecvMsgOpt - } - return 0 -} - -func (m *UserInfo) GetBirthStr() string { - if m != nil { - return m.BirthStr - } - return "" -} - -type FriendInfo struct { - OwnerUserID string `protobuf:"bytes,1,opt,name=ownerUserID" json:"ownerUserID,omitempty"` - Remark string `protobuf:"bytes,2,opt,name=remark" json:"remark,omitempty"` - CreateTime uint32 `protobuf:"varint,3,opt,name=createTime" json:"createTime,omitempty"` - FriendUser *UserInfo `protobuf:"bytes,4,opt,name=friendUser" json:"friendUser,omitempty"` - AddSource int32 `protobuf:"varint,5,opt,name=addSource" json:"addSource,omitempty"` - OperatorUserID string `protobuf:"bytes,6,opt,name=operatorUserID" json:"operatorUserID,omitempty"` - Ex string `protobuf:"bytes,7,opt,name=ex" json:"ex,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *FriendInfo) Reset() { *m = FriendInfo{} } -func (m *FriendInfo) String() string { return proto.CompactTextString(m) } -func (*FriendInfo) ProtoMessage() {} -func (*FriendInfo) Descriptor() ([]byte, []int) { - return fileDescriptor_ws_bc78a4975e7e5f46, []int{5} -} -func (m *FriendInfo) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_FriendInfo.Unmarshal(m, b) -} -func (m *FriendInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_FriendInfo.Marshal(b, m, deterministic) -} -func (dst *FriendInfo) XXX_Merge(src proto.Message) { - xxx_messageInfo_FriendInfo.Merge(dst, src) -} -func (m *FriendInfo) XXX_Size() int { - return xxx_messageInfo_FriendInfo.Size(m) -} -func (m *FriendInfo) XXX_DiscardUnknown() { - xxx_messageInfo_FriendInfo.DiscardUnknown(m) -} - -var xxx_messageInfo_FriendInfo proto.InternalMessageInfo - -func (m *FriendInfo) GetOwnerUserID() string { - if m != nil { - return m.OwnerUserID - } - return "" -} - -func (m *FriendInfo) GetRemark() string { - if m != nil { - return m.Remark - } - return "" -} - -func (m *FriendInfo) GetCreateTime() uint32 { - if m != nil { - return m.CreateTime - } - return 0 -} - -func (m *FriendInfo) GetFriendUser() *UserInfo { - if m != nil { - return m.FriendUser - } - return nil -} - -func (m *FriendInfo) GetAddSource() int32 { - if m != nil { - return m.AddSource - } - return 0 -} - -func (m *FriendInfo) GetOperatorUserID() string { - if m != nil { - return m.OperatorUserID - } - return "" -} - -func (m *FriendInfo) GetEx() string { - if m != nil { - return m.Ex - } - return "" -} - -type BlackInfo struct { - OwnerUserID string `protobuf:"bytes,1,opt,name=ownerUserID" json:"ownerUserID,omitempty"` - CreateTime uint32 `protobuf:"varint,2,opt,name=createTime" json:"createTime,omitempty"` - BlackUserInfo *PublicUserInfo `protobuf:"bytes,3,opt,name=blackUserInfo" json:"blackUserInfo,omitempty"` - AddSource int32 `protobuf:"varint,4,opt,name=addSource" json:"addSource,omitempty"` - OperatorUserID string `protobuf:"bytes,5,opt,name=operatorUserID" json:"operatorUserID,omitempty"` - Ex string `protobuf:"bytes,6,opt,name=ex" json:"ex,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *BlackInfo) Reset() { *m = BlackInfo{} } -func (m *BlackInfo) String() string { return proto.CompactTextString(m) } -func (*BlackInfo) ProtoMessage() {} -func (*BlackInfo) Descriptor() ([]byte, []int) { - return fileDescriptor_ws_bc78a4975e7e5f46, []int{6} -} -func (m *BlackInfo) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_BlackInfo.Unmarshal(m, b) -} -func (m *BlackInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_BlackInfo.Marshal(b, m, deterministic) -} -func (dst *BlackInfo) XXX_Merge(src proto.Message) { - xxx_messageInfo_BlackInfo.Merge(dst, src) -} -func (m *BlackInfo) XXX_Size() int { - return xxx_messageInfo_BlackInfo.Size(m) -} -func (m *BlackInfo) XXX_DiscardUnknown() { - xxx_messageInfo_BlackInfo.DiscardUnknown(m) -} - -var xxx_messageInfo_BlackInfo proto.InternalMessageInfo - -func (m *BlackInfo) GetOwnerUserID() string { - if m != nil { - return m.OwnerUserID - } - return "" -} - -func (m *BlackInfo) GetCreateTime() uint32 { - if m != nil { - return m.CreateTime - } - return 0 -} - -func (m *BlackInfo) GetBlackUserInfo() *PublicUserInfo { - if m != nil { - return m.BlackUserInfo - } - return nil -} - -func (m *BlackInfo) GetAddSource() int32 { - if m != nil { - return m.AddSource - } - return 0 -} - -func (m *BlackInfo) GetOperatorUserID() string { - if m != nil { - return m.OperatorUserID - } - return "" -} - -func (m *BlackInfo) GetEx() string { - if m != nil { - return m.Ex - } - return "" -} - -type GroupRequest struct { - UserInfo *PublicUserInfo `protobuf:"bytes,1,opt,name=userInfo" json:"userInfo,omitempty"` - GroupInfo *GroupInfo `protobuf:"bytes,2,opt,name=groupInfo" json:"groupInfo,omitempty"` - HandleResult int32 `protobuf:"varint,3,opt,name=handleResult" json:"handleResult,omitempty"` - ReqMsg string `protobuf:"bytes,4,opt,name=reqMsg" json:"reqMsg,omitempty"` - HandleMsg string `protobuf:"bytes,5,opt,name=handleMsg" json:"handleMsg,omitempty"` - ReqTime uint32 `protobuf:"varint,6,opt,name=reqTime" json:"reqTime,omitempty"` - HandleUserID string `protobuf:"bytes,7,opt,name=handleUserID" json:"handleUserID,omitempty"` - HandleTime uint32 `protobuf:"varint,8,opt,name=handleTime" json:"handleTime,omitempty"` - Ex string `protobuf:"bytes,9,opt,name=ex" json:"ex,omitempty"` - JoinSource int32 `protobuf:"varint,10,opt,name=joinSource" json:"joinSource,omitempty"` - InviterUserID string `protobuf:"bytes,11,opt,name=inviterUserID" json:"inviterUserID,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *GroupRequest) Reset() { *m = GroupRequest{} } -func (m *GroupRequest) String() string { return proto.CompactTextString(m) } -func (*GroupRequest) ProtoMessage() {} -func (*GroupRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_ws_bc78a4975e7e5f46, []int{7} -} -func (m *GroupRequest) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_GroupRequest.Unmarshal(m, b) -} -func (m *GroupRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_GroupRequest.Marshal(b, m, deterministic) -} -func (dst *GroupRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_GroupRequest.Merge(dst, src) -} -func (m *GroupRequest) XXX_Size() int { - return xxx_messageInfo_GroupRequest.Size(m) -} -func (m *GroupRequest) XXX_DiscardUnknown() { - xxx_messageInfo_GroupRequest.DiscardUnknown(m) -} - -var xxx_messageInfo_GroupRequest proto.InternalMessageInfo - -func (m *GroupRequest) GetUserInfo() *PublicUserInfo { - if m != nil { - return m.UserInfo - } - return nil -} - -func (m *GroupRequest) GetGroupInfo() *GroupInfo { - if m != nil { - return m.GroupInfo - } - return nil -} - -func (m *GroupRequest) GetHandleResult() int32 { - if m != nil { - return m.HandleResult - } - return 0 -} - -func (m *GroupRequest) GetReqMsg() string { - if m != nil { - return m.ReqMsg - } - return "" -} - -func (m *GroupRequest) GetHandleMsg() string { - if m != nil { - return m.HandleMsg - } - return "" -} - -func (m *GroupRequest) GetReqTime() uint32 { - if m != nil { - return m.ReqTime - } - return 0 -} - -func (m *GroupRequest) GetHandleUserID() string { - if m != nil { - return m.HandleUserID - } - return "" -} - -func (m *GroupRequest) GetHandleTime() uint32 { - if m != nil { - return m.HandleTime - } - return 0 -} - -func (m *GroupRequest) GetEx() string { - if m != nil { - return m.Ex - } - return "" -} - -func (m *GroupRequest) GetJoinSource() int32 { - if m != nil { - return m.JoinSource - } - return 0 -} - -func (m *GroupRequest) GetInviterUserID() string { - if m != nil { - return m.InviterUserID - } - return "" -} - -type FriendRequest struct { - FromUserID string `protobuf:"bytes,1,opt,name=fromUserID" json:"fromUserID,omitempty"` - FromNickname string `protobuf:"bytes,2,opt,name=fromNickname" json:"fromNickname,omitempty"` - FromFaceURL string `protobuf:"bytes,3,opt,name=fromFaceURL" json:"fromFaceURL,omitempty"` - FromGender int32 `protobuf:"varint,4,opt,name=fromGender" json:"fromGender,omitempty"` - ToUserID string `protobuf:"bytes,5,opt,name=toUserID" json:"toUserID,omitempty"` - ToNickname string `protobuf:"bytes,6,opt,name=toNickname" json:"toNickname,omitempty"` - ToFaceURL string `protobuf:"bytes,7,opt,name=toFaceURL" json:"toFaceURL,omitempty"` - ToGender int32 `protobuf:"varint,8,opt,name=toGender" json:"toGender,omitempty"` - HandleResult int32 `protobuf:"varint,9,opt,name=handleResult" json:"handleResult,omitempty"` - ReqMsg string `protobuf:"bytes,10,opt,name=reqMsg" json:"reqMsg,omitempty"` - CreateTime uint32 `protobuf:"varint,11,opt,name=createTime" json:"createTime,omitempty"` - HandlerUserID string `protobuf:"bytes,12,opt,name=handlerUserID" json:"handlerUserID,omitempty"` - HandleMsg string `protobuf:"bytes,13,opt,name=handleMsg" json:"handleMsg,omitempty"` - HandleTime uint32 `protobuf:"varint,14,opt,name=handleTime" json:"handleTime,omitempty"` - Ex string `protobuf:"bytes,15,opt,name=ex" json:"ex,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *FriendRequest) Reset() { *m = FriendRequest{} } -func (m *FriendRequest) String() string { return proto.CompactTextString(m) } -func (*FriendRequest) ProtoMessage() {} -func (*FriendRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_ws_bc78a4975e7e5f46, []int{8} -} -func (m *FriendRequest) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_FriendRequest.Unmarshal(m, b) -} -func (m *FriendRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_FriendRequest.Marshal(b, m, deterministic) -} -func (dst *FriendRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_FriendRequest.Merge(dst, src) -} -func (m *FriendRequest) XXX_Size() int { - return xxx_messageInfo_FriendRequest.Size(m) -} -func (m *FriendRequest) XXX_DiscardUnknown() { - xxx_messageInfo_FriendRequest.DiscardUnknown(m) -} - -var xxx_messageInfo_FriendRequest proto.InternalMessageInfo - -func (m *FriendRequest) GetFromUserID() string { - if m != nil { - return m.FromUserID - } - return "" -} - -func (m *FriendRequest) GetFromNickname() string { - if m != nil { - return m.FromNickname - } - return "" -} - -func (m *FriendRequest) GetFromFaceURL() string { - if m != nil { - return m.FromFaceURL - } - return "" -} - -func (m *FriendRequest) GetFromGender() int32 { - if m != nil { - return m.FromGender - } - return 0 -} - -func (m *FriendRequest) GetToUserID() string { - if m != nil { - return m.ToUserID - } - return "" -} - -func (m *FriendRequest) GetToNickname() string { - if m != nil { - return m.ToNickname - } - return "" -} - -func (m *FriendRequest) GetToFaceURL() string { - if m != nil { - return m.ToFaceURL - } - return "" -} - -func (m *FriendRequest) GetToGender() int32 { - if m != nil { - return m.ToGender - } - return 0 -} - -func (m *FriendRequest) GetHandleResult() int32 { - if m != nil { - return m.HandleResult - } - return 0 -} - -func (m *FriendRequest) GetReqMsg() string { - if m != nil { - return m.ReqMsg - } - return "" -} - -func (m *FriendRequest) GetCreateTime() uint32 { - if m != nil { - return m.CreateTime - } - return 0 -} - -func (m *FriendRequest) GetHandlerUserID() string { - if m != nil { - return m.HandlerUserID - } - return "" -} - -func (m *FriendRequest) GetHandleMsg() string { - if m != nil { - return m.HandleMsg - } - return "" -} - -func (m *FriendRequest) GetHandleTime() uint32 { - if m != nil { - return m.HandleTime - } - return 0 -} - -func (m *FriendRequest) GetEx() string { - if m != nil { - return m.Ex - } - return "" -} - -type Department struct { - DepartmentID string `protobuf:"bytes,1,opt,name=departmentID" json:"departmentID,omitempty"` - FaceURL string `protobuf:"bytes,2,opt,name=faceURL" json:"faceURL,omitempty"` - Name string `protobuf:"bytes,3,opt,name=name" json:"name,omitempty"` - ParentID string `protobuf:"bytes,4,opt,name=parentID" json:"parentID,omitempty"` - Order int32 `protobuf:"varint,5,opt,name=order" json:"order,omitempty"` - DepartmentType int32 `protobuf:"varint,6,opt,name=departmentType" json:"departmentType,omitempty"` - CreateTime uint32 `protobuf:"varint,7,opt,name=createTime" json:"createTime,omitempty"` - SubDepartmentNum uint32 `protobuf:"varint,8,opt,name=subDepartmentNum" json:"subDepartmentNum,omitempty"` - MemberNum uint32 `protobuf:"varint,9,opt,name=memberNum" json:"memberNum,omitempty"` - Ex string `protobuf:"bytes,10,opt,name=ex" json:"ex,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *Department) Reset() { *m = Department{} } -func (m *Department) String() string { return proto.CompactTextString(m) } -func (*Department) ProtoMessage() {} -func (*Department) Descriptor() ([]byte, []int) { - return fileDescriptor_ws_bc78a4975e7e5f46, []int{9} -} -func (m *Department) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_Department.Unmarshal(m, b) -} -func (m *Department) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_Department.Marshal(b, m, deterministic) -} -func (dst *Department) XXX_Merge(src proto.Message) { - xxx_messageInfo_Department.Merge(dst, src) -} -func (m *Department) XXX_Size() int { - return xxx_messageInfo_Department.Size(m) -} -func (m *Department) XXX_DiscardUnknown() { - xxx_messageInfo_Department.DiscardUnknown(m) -} - -var xxx_messageInfo_Department proto.InternalMessageInfo - -func (m *Department) GetDepartmentID() string { - if m != nil { - return m.DepartmentID - } - return "" -} - -func (m *Department) GetFaceURL() string { - if m != nil { - return m.FaceURL - } - return "" -} - -func (m *Department) GetName() string { - if m != nil { - return m.Name - } - return "" -} - -func (m *Department) GetParentID() string { - if m != nil { - return m.ParentID - } - return "" -} - -func (m *Department) GetOrder() int32 { - if m != nil { - return m.Order - } - return 0 -} - -func (m *Department) GetDepartmentType() int32 { - if m != nil { - return m.DepartmentType - } - return 0 -} - -func (m *Department) GetCreateTime() uint32 { - if m != nil { - return m.CreateTime - } - return 0 -} - -func (m *Department) GetSubDepartmentNum() uint32 { - if m != nil { - return m.SubDepartmentNum - } - return 0 -} - -func (m *Department) GetMemberNum() uint32 { - if m != nil { - return m.MemberNum - } - return 0 -} - -func (m *Department) GetEx() string { - if m != nil { - return m.Ex - } - return "" -} - -type OrganizationUser struct { - UserID string `protobuf:"bytes,1,opt,name=userID" json:"userID,omitempty"` - Nickname string `protobuf:"bytes,2,opt,name=nickname" json:"nickname,omitempty"` - EnglishName string `protobuf:"bytes,3,opt,name=englishName" json:"englishName,omitempty"` - FaceURL string `protobuf:"bytes,4,opt,name=faceURL" json:"faceURL,omitempty"` - Gender int32 `protobuf:"varint,5,opt,name=gender" json:"gender,omitempty"` - Mobile string `protobuf:"bytes,6,opt,name=mobile" json:"mobile,omitempty"` - Telephone string `protobuf:"bytes,7,opt,name=telephone" json:"telephone,omitempty"` - Birth uint32 `protobuf:"varint,8,opt,name=birth" json:"birth,omitempty"` - Email string `protobuf:"bytes,9,opt,name=email" json:"email,omitempty"` - CreateTime uint32 `protobuf:"varint,10,opt,name=createTime" json:"createTime,omitempty"` - Ex string `protobuf:"bytes,11,opt,name=ex" json:"ex,omitempty"` - BirthStr string `protobuf:"bytes,12,opt,name=birthStr" json:"birthStr,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *OrganizationUser) Reset() { *m = OrganizationUser{} } -func (m *OrganizationUser) String() string { return proto.CompactTextString(m) } -func (*OrganizationUser) ProtoMessage() {} -func (*OrganizationUser) Descriptor() ([]byte, []int) { - return fileDescriptor_ws_bc78a4975e7e5f46, []int{10} -} -func (m *OrganizationUser) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_OrganizationUser.Unmarshal(m, b) -} -func (m *OrganizationUser) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_OrganizationUser.Marshal(b, m, deterministic) -} -func (dst *OrganizationUser) XXX_Merge(src proto.Message) { - xxx_messageInfo_OrganizationUser.Merge(dst, src) -} -func (m *OrganizationUser) XXX_Size() int { - return xxx_messageInfo_OrganizationUser.Size(m) -} -func (m *OrganizationUser) XXX_DiscardUnknown() { - xxx_messageInfo_OrganizationUser.DiscardUnknown(m) -} - -var xxx_messageInfo_OrganizationUser proto.InternalMessageInfo - -func (m *OrganizationUser) GetUserID() string { - if m != nil { - return m.UserID - } - return "" -} - -func (m *OrganizationUser) GetNickname() string { - if m != nil { - return m.Nickname - } - return "" -} - -func (m *OrganizationUser) GetEnglishName() string { - if m != nil { - return m.EnglishName - } - return "" -} - -func (m *OrganizationUser) GetFaceURL() string { - if m != nil { - return m.FaceURL - } - return "" -} - -func (m *OrganizationUser) GetGender() int32 { - if m != nil { - return m.Gender - } - return 0 -} - -func (m *OrganizationUser) GetMobile() string { - if m != nil { - return m.Mobile - } - return "" -} - -func (m *OrganizationUser) GetTelephone() string { - if m != nil { - return m.Telephone - } - return "" -} - -func (m *OrganizationUser) GetBirth() uint32 { - if m != nil { - return m.Birth - } - return 0 -} - -func (m *OrganizationUser) GetEmail() string { - if m != nil { - return m.Email - } - return "" -} - -func (m *OrganizationUser) GetCreateTime() uint32 { - if m != nil { - return m.CreateTime - } - return 0 -} - -func (m *OrganizationUser) GetEx() string { - if m != nil { - return m.Ex - } - return "" -} - -func (m *OrganizationUser) GetBirthStr() string { - if m != nil { - return m.BirthStr - } - return "" -} - -type DepartmentMember struct { - UserID string `protobuf:"bytes,1,opt,name=userID" json:"userID,omitempty"` - DepartmentID string `protobuf:"bytes,2,opt,name=departmentID" json:"departmentID,omitempty"` - Order int32 `protobuf:"varint,3,opt,name=order" json:"order,omitempty"` - Position string `protobuf:"bytes,4,opt,name=position" json:"position,omitempty"` - Leader int32 `protobuf:"varint,5,opt,name=leader" json:"leader,omitempty"` - Status int32 `protobuf:"varint,6,opt,name=status" json:"status,omitempty"` - Ex string `protobuf:"bytes,7,opt,name=ex" json:"ex,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *DepartmentMember) Reset() { *m = DepartmentMember{} } -func (m *DepartmentMember) String() string { return proto.CompactTextString(m) } -func (*DepartmentMember) ProtoMessage() {} -func (*DepartmentMember) Descriptor() ([]byte, []int) { - return fileDescriptor_ws_bc78a4975e7e5f46, []int{11} -} -func (m *DepartmentMember) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_DepartmentMember.Unmarshal(m, b) -} -func (m *DepartmentMember) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_DepartmentMember.Marshal(b, m, deterministic) -} -func (dst *DepartmentMember) XXX_Merge(src proto.Message) { - xxx_messageInfo_DepartmentMember.Merge(dst, src) -} -func (m *DepartmentMember) XXX_Size() int { - return xxx_messageInfo_DepartmentMember.Size(m) -} -func (m *DepartmentMember) XXX_DiscardUnknown() { - xxx_messageInfo_DepartmentMember.DiscardUnknown(m) -} - -var xxx_messageInfo_DepartmentMember proto.InternalMessageInfo - -func (m *DepartmentMember) GetUserID() string { - if m != nil { - return m.UserID - } - return "" -} - -func (m *DepartmentMember) GetDepartmentID() string { - if m != nil { - return m.DepartmentID - } - return "" -} - -func (m *DepartmentMember) GetOrder() int32 { - if m != nil { - return m.Order - } - return 0 -} - -func (m *DepartmentMember) GetPosition() string { - if m != nil { - return m.Position - } - return "" -} - -func (m *DepartmentMember) GetLeader() int32 { - if m != nil { - return m.Leader - } - return 0 -} - -func (m *DepartmentMember) GetStatus() int32 { - if m != nil { - return m.Status - } - return 0 -} - -func (m *DepartmentMember) GetEx() string { - if m != nil { - return m.Ex - } - return "" -} - -type UserDepartmentMember struct { - OrganizationUser *OrganizationUser `protobuf:"bytes,1,opt,name=organizationUser" json:"organizationUser,omitempty"` - DepartmentMember *DepartmentMember `protobuf:"bytes,2,opt,name=departmentMember" json:"departmentMember,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *UserDepartmentMember) Reset() { *m = UserDepartmentMember{} } -func (m *UserDepartmentMember) String() string { return proto.CompactTextString(m) } -func (*UserDepartmentMember) ProtoMessage() {} -func (*UserDepartmentMember) Descriptor() ([]byte, []int) { - return fileDescriptor_ws_bc78a4975e7e5f46, []int{12} -} -func (m *UserDepartmentMember) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_UserDepartmentMember.Unmarshal(m, b) -} -func (m *UserDepartmentMember) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_UserDepartmentMember.Marshal(b, m, deterministic) -} -func (dst *UserDepartmentMember) XXX_Merge(src proto.Message) { - xxx_messageInfo_UserDepartmentMember.Merge(dst, src) -} -func (m *UserDepartmentMember) XXX_Size() int { - return xxx_messageInfo_UserDepartmentMember.Size(m) -} -func (m *UserDepartmentMember) XXX_DiscardUnknown() { - xxx_messageInfo_UserDepartmentMember.DiscardUnknown(m) -} - -var xxx_messageInfo_UserDepartmentMember proto.InternalMessageInfo - -func (m *UserDepartmentMember) GetOrganizationUser() *OrganizationUser { - if m != nil { - return m.OrganizationUser - } - return nil -} - -func (m *UserDepartmentMember) GetDepartmentMember() *DepartmentMember { - if m != nil { - return m.DepartmentMember - } - return nil -} - -type UserInDepartment struct { - OrganizationUser *OrganizationUser `protobuf:"bytes,1,opt,name=organizationUser" json:"organizationUser,omitempty"` - DepartmentMemberList []*DepartmentMember `protobuf:"bytes,2,rep,name=departmentMemberList" json:"departmentMemberList,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *UserInDepartment) Reset() { *m = UserInDepartment{} } -func (m *UserInDepartment) String() string { return proto.CompactTextString(m) } -func (*UserInDepartment) ProtoMessage() {} -func (*UserInDepartment) Descriptor() ([]byte, []int) { - return fileDescriptor_ws_bc78a4975e7e5f46, []int{13} -} -func (m *UserInDepartment) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_UserInDepartment.Unmarshal(m, b) -} -func (m *UserInDepartment) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_UserInDepartment.Marshal(b, m, deterministic) -} -func (dst *UserInDepartment) XXX_Merge(src proto.Message) { - xxx_messageInfo_UserInDepartment.Merge(dst, src) -} -func (m *UserInDepartment) XXX_Size() int { - return xxx_messageInfo_UserInDepartment.Size(m) -} -func (m *UserInDepartment) XXX_DiscardUnknown() { - xxx_messageInfo_UserInDepartment.DiscardUnknown(m) -} - -var xxx_messageInfo_UserInDepartment proto.InternalMessageInfo - -func (m *UserInDepartment) GetOrganizationUser() *OrganizationUser { - if m != nil { - return m.OrganizationUser - } - return nil -} - -func (m *UserInDepartment) GetDepartmentMemberList() []*DepartmentMember { - if m != nil { - return m.DepartmentMemberList - } - return nil -} - -// /////////////////////////////////base end///////////////////////////////////// -type PullMessageBySeqListReq struct { - UserID string `protobuf:"bytes,1,opt,name=userID" json:"userID,omitempty"` - OperationID string `protobuf:"bytes,2,opt,name=operationID" json:"operationID,omitempty"` - SeqList []uint32 `protobuf:"varint,3,rep,packed,name=seqList" json:"seqList,omitempty"` - GroupSeqList map[string]*SeqList `protobuf:"bytes,4,rep,name=groupSeqList" json:"groupSeqList,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *PullMessageBySeqListReq) Reset() { *m = PullMessageBySeqListReq{} } -func (m *PullMessageBySeqListReq) String() string { return proto.CompactTextString(m) } -func (*PullMessageBySeqListReq) ProtoMessage() {} -func (*PullMessageBySeqListReq) Descriptor() ([]byte, []int) { - return fileDescriptor_ws_bc78a4975e7e5f46, []int{14} -} -func (m *PullMessageBySeqListReq) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_PullMessageBySeqListReq.Unmarshal(m, b) -} -func (m *PullMessageBySeqListReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_PullMessageBySeqListReq.Marshal(b, m, deterministic) -} -func (dst *PullMessageBySeqListReq) XXX_Merge(src proto.Message) { - xxx_messageInfo_PullMessageBySeqListReq.Merge(dst, src) -} -func (m *PullMessageBySeqListReq) XXX_Size() int { - return xxx_messageInfo_PullMessageBySeqListReq.Size(m) -} -func (m *PullMessageBySeqListReq) XXX_DiscardUnknown() { - xxx_messageInfo_PullMessageBySeqListReq.DiscardUnknown(m) -} - -var xxx_messageInfo_PullMessageBySeqListReq proto.InternalMessageInfo - -func (m *PullMessageBySeqListReq) GetUserID() string { - if m != nil { - return m.UserID - } - return "" -} - -func (m *PullMessageBySeqListReq) GetOperationID() string { - if m != nil { - return m.OperationID - } - return "" -} - -func (m *PullMessageBySeqListReq) GetSeqList() []uint32 { - if m != nil { - return m.SeqList - } - return nil -} - -func (m *PullMessageBySeqListReq) GetGroupSeqList() map[string]*SeqList { - if m != nil { - return m.GroupSeqList - } - return nil -} - -type SeqList struct { - SeqList []uint32 `protobuf:"varint,1,rep,packed,name=seqList" json:"seqList,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *SeqList) Reset() { *m = SeqList{} } -func (m *SeqList) String() string { return proto.CompactTextString(m) } -func (*SeqList) ProtoMessage() {} -func (*SeqList) Descriptor() ([]byte, []int) { - return fileDescriptor_ws_bc78a4975e7e5f46, []int{15} -} -func (m *SeqList) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_SeqList.Unmarshal(m, b) -} -func (m *SeqList) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_SeqList.Marshal(b, m, deterministic) -} -func (dst *SeqList) XXX_Merge(src proto.Message) { - xxx_messageInfo_SeqList.Merge(dst, src) -} -func (m *SeqList) XXX_Size() int { - return xxx_messageInfo_SeqList.Size(m) -} -func (m *SeqList) XXX_DiscardUnknown() { - xxx_messageInfo_SeqList.DiscardUnknown(m) -} - -var xxx_messageInfo_SeqList proto.InternalMessageInfo - -func (m *SeqList) GetSeqList() []uint32 { - if m != nil { - return m.SeqList - } - return nil -} - -type MsgDataList struct { - MsgDataList []*MsgData `protobuf:"bytes,1,rep,name=msgDataList" json:"msgDataList,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *MsgDataList) Reset() { *m = MsgDataList{} } -func (m *MsgDataList) String() string { return proto.CompactTextString(m) } -func (*MsgDataList) ProtoMessage() {} -func (*MsgDataList) Descriptor() ([]byte, []int) { - return fileDescriptor_ws_bc78a4975e7e5f46, []int{16} -} -func (m *MsgDataList) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_MsgDataList.Unmarshal(m, b) -} -func (m *MsgDataList) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_MsgDataList.Marshal(b, m, deterministic) -} -func (dst *MsgDataList) XXX_Merge(src proto.Message) { - xxx_messageInfo_MsgDataList.Merge(dst, src) -} -func (m *MsgDataList) XXX_Size() int { - return xxx_messageInfo_MsgDataList.Size(m) -} -func (m *MsgDataList) XXX_DiscardUnknown() { - xxx_messageInfo_MsgDataList.DiscardUnknown(m) -} - -var xxx_messageInfo_MsgDataList proto.InternalMessageInfo - -func (m *MsgDataList) GetMsgDataList() []*MsgData { - if m != nil { - return m.MsgDataList - } - return nil -} - -type PullMessageBySeqListResp struct { - ErrCode int32 `protobuf:"varint,1,opt,name=errCode" json:"errCode,omitempty"` - ErrMsg string `protobuf:"bytes,2,opt,name=errMsg" json:"errMsg,omitempty"` - List []*MsgData `protobuf:"bytes,3,rep,name=list" json:"list,omitempty"` - GroupMsgDataList map[string]*MsgDataList `protobuf:"bytes,4,rep,name=groupMsgDataList" json:"groupMsgDataList,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *PullMessageBySeqListResp) Reset() { *m = PullMessageBySeqListResp{} } -func (m *PullMessageBySeqListResp) String() string { return proto.CompactTextString(m) } -func (*PullMessageBySeqListResp) ProtoMessage() {} -func (*PullMessageBySeqListResp) Descriptor() ([]byte, []int) { - return fileDescriptor_ws_bc78a4975e7e5f46, []int{17} -} -func (m *PullMessageBySeqListResp) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_PullMessageBySeqListResp.Unmarshal(m, b) -} -func (m *PullMessageBySeqListResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_PullMessageBySeqListResp.Marshal(b, m, deterministic) -} -func (dst *PullMessageBySeqListResp) XXX_Merge(src proto.Message) { - xxx_messageInfo_PullMessageBySeqListResp.Merge(dst, src) -} -func (m *PullMessageBySeqListResp) XXX_Size() int { - return xxx_messageInfo_PullMessageBySeqListResp.Size(m) -} -func (m *PullMessageBySeqListResp) XXX_DiscardUnknown() { - xxx_messageInfo_PullMessageBySeqListResp.DiscardUnknown(m) -} - -var xxx_messageInfo_PullMessageBySeqListResp proto.InternalMessageInfo - -func (m *PullMessageBySeqListResp) GetErrCode() int32 { - if m != nil { - return m.ErrCode - } - return 0 -} - -func (m *PullMessageBySeqListResp) GetErrMsg() string { - if m != nil { - return m.ErrMsg - } - return "" -} - -func (m *PullMessageBySeqListResp) GetList() []*MsgData { - if m != nil { - return m.List - } - return nil -} - -func (m *PullMessageBySeqListResp) GetGroupMsgDataList() map[string]*MsgDataList { - if m != nil { - return m.GroupMsgDataList - } - return nil -} - -type GetMaxAndMinSeqReq struct { - GroupIDList []string `protobuf:"bytes,1,rep,name=groupIDList" json:"groupIDList,omitempty"` - UserID string `protobuf:"bytes,2,opt,name=userID" json:"userID,omitempty"` - OperationID string `protobuf:"bytes,3,opt,name=operationID" json:"operationID,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *GetMaxAndMinSeqReq) Reset() { *m = GetMaxAndMinSeqReq{} } -func (m *GetMaxAndMinSeqReq) String() string { return proto.CompactTextString(m) } -func (*GetMaxAndMinSeqReq) ProtoMessage() {} -func (*GetMaxAndMinSeqReq) Descriptor() ([]byte, []int) { - return fileDescriptor_ws_bc78a4975e7e5f46, []int{18} -} -func (m *GetMaxAndMinSeqReq) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_GetMaxAndMinSeqReq.Unmarshal(m, b) -} -func (m *GetMaxAndMinSeqReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_GetMaxAndMinSeqReq.Marshal(b, m, deterministic) -} -func (dst *GetMaxAndMinSeqReq) XXX_Merge(src proto.Message) { - xxx_messageInfo_GetMaxAndMinSeqReq.Merge(dst, src) -} -func (m *GetMaxAndMinSeqReq) XXX_Size() int { - return xxx_messageInfo_GetMaxAndMinSeqReq.Size(m) -} -func (m *GetMaxAndMinSeqReq) XXX_DiscardUnknown() { - xxx_messageInfo_GetMaxAndMinSeqReq.DiscardUnknown(m) -} - -var xxx_messageInfo_GetMaxAndMinSeqReq proto.InternalMessageInfo - -func (m *GetMaxAndMinSeqReq) GetGroupIDList() []string { - if m != nil { - return m.GroupIDList - } - return nil -} - -func (m *GetMaxAndMinSeqReq) GetUserID() string { - if m != nil { - return m.UserID - } - return "" -} - -func (m *GetMaxAndMinSeqReq) GetOperationID() string { - if m != nil { - return m.OperationID - } - return "" -} - -type MaxAndMinSeq struct { - MaxSeq uint32 `protobuf:"varint,1,opt,name=maxSeq" json:"maxSeq,omitempty"` - MinSeq uint32 `protobuf:"varint,2,opt,name=minSeq" json:"minSeq,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *MaxAndMinSeq) Reset() { *m = MaxAndMinSeq{} } -func (m *MaxAndMinSeq) String() string { return proto.CompactTextString(m) } -func (*MaxAndMinSeq) ProtoMessage() {} -func (*MaxAndMinSeq) Descriptor() ([]byte, []int) { - return fileDescriptor_ws_bc78a4975e7e5f46, []int{19} -} -func (m *MaxAndMinSeq) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_MaxAndMinSeq.Unmarshal(m, b) -} -func (m *MaxAndMinSeq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_MaxAndMinSeq.Marshal(b, m, deterministic) -} -func (dst *MaxAndMinSeq) XXX_Merge(src proto.Message) { - xxx_messageInfo_MaxAndMinSeq.Merge(dst, src) -} -func (m *MaxAndMinSeq) XXX_Size() int { - return xxx_messageInfo_MaxAndMinSeq.Size(m) -} -func (m *MaxAndMinSeq) XXX_DiscardUnknown() { - xxx_messageInfo_MaxAndMinSeq.DiscardUnknown(m) -} - -var xxx_messageInfo_MaxAndMinSeq proto.InternalMessageInfo - -func (m *MaxAndMinSeq) GetMaxSeq() uint32 { - if m != nil { - return m.MaxSeq - } - return 0 -} - -func (m *MaxAndMinSeq) GetMinSeq() uint32 { - if m != nil { - return m.MinSeq - } - return 0 -} - -type GetMaxAndMinSeqResp struct { - MaxSeq uint32 `protobuf:"varint,1,opt,name=maxSeq" json:"maxSeq,omitempty"` - MinSeq uint32 `protobuf:"varint,2,opt,name=minSeq" json:"minSeq,omitempty"` - ErrCode int32 `protobuf:"varint,3,opt,name=errCode" json:"errCode,omitempty"` - ErrMsg string `protobuf:"bytes,4,opt,name=errMsg" json:"errMsg,omitempty"` - GroupMaxAndMinSeq map[string]*MaxAndMinSeq `protobuf:"bytes,5,rep,name=groupMaxAndMinSeq" json:"groupMaxAndMinSeq,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *GetMaxAndMinSeqResp) Reset() { *m = GetMaxAndMinSeqResp{} } -func (m *GetMaxAndMinSeqResp) String() string { return proto.CompactTextString(m) } -func (*GetMaxAndMinSeqResp) ProtoMessage() {} -func (*GetMaxAndMinSeqResp) Descriptor() ([]byte, []int) { - return fileDescriptor_ws_bc78a4975e7e5f46, []int{20} -} -func (m *GetMaxAndMinSeqResp) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_GetMaxAndMinSeqResp.Unmarshal(m, b) -} -func (m *GetMaxAndMinSeqResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_GetMaxAndMinSeqResp.Marshal(b, m, deterministic) -} -func (dst *GetMaxAndMinSeqResp) XXX_Merge(src proto.Message) { - xxx_messageInfo_GetMaxAndMinSeqResp.Merge(dst, src) -} -func (m *GetMaxAndMinSeqResp) XXX_Size() int { - return xxx_messageInfo_GetMaxAndMinSeqResp.Size(m) -} -func (m *GetMaxAndMinSeqResp) XXX_DiscardUnknown() { - xxx_messageInfo_GetMaxAndMinSeqResp.DiscardUnknown(m) -} - -var xxx_messageInfo_GetMaxAndMinSeqResp proto.InternalMessageInfo - -func (m *GetMaxAndMinSeqResp) GetMaxSeq() uint32 { - if m != nil { - return m.MaxSeq - } - return 0 -} - -func (m *GetMaxAndMinSeqResp) GetMinSeq() uint32 { - if m != nil { - return m.MinSeq - } - return 0 -} - -func (m *GetMaxAndMinSeqResp) GetErrCode() int32 { - if m != nil { - return m.ErrCode - } - return 0 -} - -func (m *GetMaxAndMinSeqResp) GetErrMsg() string { - if m != nil { - return m.ErrMsg - } - return "" -} - -func (m *GetMaxAndMinSeqResp) GetGroupMaxAndMinSeq() map[string]*MaxAndMinSeq { - if m != nil { - return m.GroupMaxAndMinSeq - } - return nil -} - -type UserSendMsgResp struct { - ServerMsgID string `protobuf:"bytes,1,opt,name=serverMsgID" json:"serverMsgID,omitempty"` - ClientMsgID string `protobuf:"bytes,2,opt,name=clientMsgID" json:"clientMsgID,omitempty"` - SendTime int64 `protobuf:"varint,3,opt,name=sendTime" json:"sendTime,omitempty"` - Ex string `protobuf:"bytes,4,opt,name=ex" json:"ex,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *UserSendMsgResp) Reset() { *m = UserSendMsgResp{} } -func (m *UserSendMsgResp) String() string { return proto.CompactTextString(m) } -func (*UserSendMsgResp) ProtoMessage() {} -func (*UserSendMsgResp) Descriptor() ([]byte, []int) { - return fileDescriptor_ws_bc78a4975e7e5f46, []int{21} -} -func (m *UserSendMsgResp) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_UserSendMsgResp.Unmarshal(m, b) -} -func (m *UserSendMsgResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_UserSendMsgResp.Marshal(b, m, deterministic) -} -func (dst *UserSendMsgResp) XXX_Merge(src proto.Message) { - xxx_messageInfo_UserSendMsgResp.Merge(dst, src) -} -func (m *UserSendMsgResp) XXX_Size() int { - return xxx_messageInfo_UserSendMsgResp.Size(m) -} -func (m *UserSendMsgResp) XXX_DiscardUnknown() { - xxx_messageInfo_UserSendMsgResp.DiscardUnknown(m) -} - -var xxx_messageInfo_UserSendMsgResp proto.InternalMessageInfo - -func (m *UserSendMsgResp) GetServerMsgID() string { - if m != nil { - return m.ServerMsgID - } - return "" -} - -func (m *UserSendMsgResp) GetClientMsgID() string { - if m != nil { - return m.ClientMsgID - } - return "" -} - -func (m *UserSendMsgResp) GetSendTime() int64 { - if m != nil { - return m.SendTime - } - return 0 -} - -func (m *UserSendMsgResp) GetEx() string { - if m != nil { - return m.Ex - } - return "" -} - -type MsgData struct { - SendID string `protobuf:"bytes,1,opt,name=sendID" json:"sendID,omitempty"` - RecvID string `protobuf:"bytes,2,opt,name=recvID" json:"recvID,omitempty"` - GroupID string `protobuf:"bytes,3,opt,name=groupID" json:"groupID,omitempty"` - ClientMsgID string `protobuf:"bytes,4,opt,name=clientMsgID" json:"clientMsgID,omitempty"` - ServerMsgID string `protobuf:"bytes,5,opt,name=serverMsgID" json:"serverMsgID,omitempty"` - SenderPlatformID int32 `protobuf:"varint,6,opt,name=senderPlatformID" json:"senderPlatformID,omitempty"` - SenderNickname string `protobuf:"bytes,7,opt,name=senderNickname" json:"senderNickname,omitempty"` - SenderFaceURL string `protobuf:"bytes,8,opt,name=senderFaceURL" json:"senderFaceURL,omitempty"` - SessionType int32 `protobuf:"varint,9,opt,name=sessionType" json:"sessionType,omitempty"` - MsgFrom int32 `protobuf:"varint,10,opt,name=msgFrom" json:"msgFrom,omitempty"` - ContentType int32 `protobuf:"varint,11,opt,name=contentType" json:"contentType,omitempty"` - Content []byte `protobuf:"bytes,12,opt,name=content,proto3" json:"content,omitempty"` - Seq uint32 `protobuf:"varint,14,opt,name=seq" json:"seq,omitempty"` - SendTime int64 `protobuf:"varint,15,opt,name=sendTime" json:"sendTime,omitempty"` - CreateTime int64 `protobuf:"varint,16,opt,name=createTime" json:"createTime,omitempty"` - Status int32 `protobuf:"varint,17,opt,name=status" json:"status,omitempty"` - Options map[string]bool `protobuf:"bytes,18,rep,name=options" json:"options,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"varint,2,opt,name=value"` - OfflinePushInfo *OfflinePushInfo `protobuf:"bytes,19,opt,name=offlinePushInfo" json:"offlinePushInfo,omitempty"` - AtUserIDList []string `protobuf:"bytes,20,rep,name=atUserIDList" json:"atUserIDList,omitempty"` - MsgDataList []byte `protobuf:"bytes,21,opt,name=msgDataList,proto3" json:"msgDataList,omitempty"` - AttachedInfo string `protobuf:"bytes,22,opt,name=attachedInfo" json:"attachedInfo,omitempty"` - Ex string `protobuf:"bytes,23,opt,name=ex" json:"ex,omitempty"` - IsReact bool `protobuf:"varint,40,opt,name=isReact" json:"isReact,omitempty"` - IsExternalExtensions bool `protobuf:"varint,41,opt,name=isExternalExtensions" json:"isExternalExtensions,omitempty"` - MsgFirstModifyTime int64 `protobuf:"varint,42,opt,name=msgFirstModifyTime" json:"msgFirstModifyTime,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *MsgData) Reset() { *m = MsgData{} } -func (m *MsgData) String() string { return proto.CompactTextString(m) } -func (*MsgData) ProtoMessage() {} -func (*MsgData) Descriptor() ([]byte, []int) { - return fileDescriptor_ws_bc78a4975e7e5f46, []int{22} -} -func (m *MsgData) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_MsgData.Unmarshal(m, b) -} -func (m *MsgData) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_MsgData.Marshal(b, m, deterministic) -} -func (dst *MsgData) XXX_Merge(src proto.Message) { - xxx_messageInfo_MsgData.Merge(dst, src) -} -func (m *MsgData) XXX_Size() int { - return xxx_messageInfo_MsgData.Size(m) -} -func (m *MsgData) XXX_DiscardUnknown() { - xxx_messageInfo_MsgData.DiscardUnknown(m) -} - -var xxx_messageInfo_MsgData proto.InternalMessageInfo - -func (m *MsgData) GetSendID() string { - if m != nil { - return m.SendID - } - return "" -} - -func (m *MsgData) GetRecvID() string { - if m != nil { - return m.RecvID - } - return "" -} - -func (m *MsgData) GetGroupID() string { - if m != nil { - return m.GroupID - } - return "" -} - -func (m *MsgData) GetClientMsgID() string { - if m != nil { - return m.ClientMsgID - } - return "" -} - -func (m *MsgData) GetServerMsgID() string { - if m != nil { - return m.ServerMsgID - } - return "" -} - -func (m *MsgData) GetSenderPlatformID() int32 { - if m != nil { - return m.SenderPlatformID - } - return 0 -} - -func (m *MsgData) GetSenderNickname() string { - if m != nil { - return m.SenderNickname - } - return "" -} - -func (m *MsgData) GetSenderFaceURL() string { - if m != nil { - return m.SenderFaceURL - } - return "" -} - -func (m *MsgData) GetSessionType() int32 { - if m != nil { - return m.SessionType - } - return 0 -} - -func (m *MsgData) GetMsgFrom() int32 { - if m != nil { - return m.MsgFrom - } - return 0 -} - -func (m *MsgData) GetContentType() int32 { - if m != nil { - return m.ContentType - } - return 0 -} - -func (m *MsgData) GetContent() []byte { - if m != nil { - return m.Content - } - return nil -} - -func (m *MsgData) GetSeq() uint32 { - if m != nil { - return m.Seq - } - return 0 -} - -func (m *MsgData) GetSendTime() int64 { - if m != nil { - return m.SendTime - } - return 0 -} - -func (m *MsgData) GetCreateTime() int64 { - if m != nil { - return m.CreateTime - } - return 0 -} - -func (m *MsgData) GetStatus() int32 { - if m != nil { - return m.Status - } - return 0 -} - -func (m *MsgData) GetOptions() map[string]bool { - if m != nil { - return m.Options - } - return nil -} - -func (m *MsgData) GetOfflinePushInfo() *OfflinePushInfo { - if m != nil { - return m.OfflinePushInfo - } - return nil -} - -func (m *MsgData) GetAtUserIDList() []string { - if m != nil { - return m.AtUserIDList - } - return nil -} - -func (m *MsgData) GetMsgDataList() []byte { - if m != nil { - return m.MsgDataList - } - return nil -} - -func (m *MsgData) GetAttachedInfo() string { - if m != nil { - return m.AttachedInfo - } - return "" -} - -func (m *MsgData) GetEx() string { - if m != nil { - return m.Ex - } - return "" -} - -func (m *MsgData) GetIsReact() bool { - if m != nil { - return m.IsReact - } - return false -} - -func (m *MsgData) GetIsExternalExtensions() bool { - if m != nil { - return m.IsExternalExtensions - } - return false -} - -func (m *MsgData) GetMsgFirstModifyTime() int64 { - if m != nil { - return m.MsgFirstModifyTime - } - return 0 -} - -type OfflinePushInfo struct { - Title string `protobuf:"bytes,1,opt,name=title" json:"title,omitempty"` - Desc string `protobuf:"bytes,2,opt,name=desc" json:"desc,omitempty"` - Ex string `protobuf:"bytes,3,opt,name=ex" json:"ex,omitempty"` - IOSPushSound string `protobuf:"bytes,4,opt,name=iOSPushSound" json:"iOSPushSound,omitempty"` - IOSBadgeCount bool `protobuf:"varint,5,opt,name=iOSBadgeCount" json:"iOSBadgeCount,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *OfflinePushInfo) Reset() { *m = OfflinePushInfo{} } -func (m *OfflinePushInfo) String() string { return proto.CompactTextString(m) } -func (*OfflinePushInfo) ProtoMessage() {} -func (*OfflinePushInfo) Descriptor() ([]byte, []int) { - return fileDescriptor_ws_bc78a4975e7e5f46, []int{23} -} -func (m *OfflinePushInfo) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_OfflinePushInfo.Unmarshal(m, b) -} -func (m *OfflinePushInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_OfflinePushInfo.Marshal(b, m, deterministic) -} -func (dst *OfflinePushInfo) XXX_Merge(src proto.Message) { - xxx_messageInfo_OfflinePushInfo.Merge(dst, src) -} -func (m *OfflinePushInfo) XXX_Size() int { - return xxx_messageInfo_OfflinePushInfo.Size(m) -} -func (m *OfflinePushInfo) XXX_DiscardUnknown() { - xxx_messageInfo_OfflinePushInfo.DiscardUnknown(m) -} - -var xxx_messageInfo_OfflinePushInfo proto.InternalMessageInfo - -func (m *OfflinePushInfo) GetTitle() string { - if m != nil { - return m.Title - } - return "" -} - -func (m *OfflinePushInfo) GetDesc() string { - if m != nil { - return m.Desc - } - return "" -} - -func (m *OfflinePushInfo) GetEx() string { - if m != nil { - return m.Ex - } - return "" -} - -func (m *OfflinePushInfo) GetIOSPushSound() string { - if m != nil { - return m.IOSPushSound - } - return "" -} - -func (m *OfflinePushInfo) GetIOSBadgeCount() bool { - if m != nil { - return m.IOSBadgeCount - } - return false -} - -type TipsComm struct { - Detail []byte `protobuf:"bytes,1,opt,name=detail,proto3" json:"detail,omitempty"` - DefaultTips string `protobuf:"bytes,2,opt,name=defaultTips" json:"defaultTips,omitempty"` - JsonDetail string `protobuf:"bytes,3,opt,name=jsonDetail" json:"jsonDetail,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *TipsComm) Reset() { *m = TipsComm{} } -func (m *TipsComm) String() string { return proto.CompactTextString(m) } -func (*TipsComm) ProtoMessage() {} -func (*TipsComm) Descriptor() ([]byte, []int) { - return fileDescriptor_ws_bc78a4975e7e5f46, []int{24} -} -func (m *TipsComm) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_TipsComm.Unmarshal(m, b) -} -func (m *TipsComm) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_TipsComm.Marshal(b, m, deterministic) -} -func (dst *TipsComm) XXX_Merge(src proto.Message) { - xxx_messageInfo_TipsComm.Merge(dst, src) -} -func (m *TipsComm) XXX_Size() int { - return xxx_messageInfo_TipsComm.Size(m) -} -func (m *TipsComm) XXX_DiscardUnknown() { - xxx_messageInfo_TipsComm.DiscardUnknown(m) -} - -var xxx_messageInfo_TipsComm proto.InternalMessageInfo - -func (m *TipsComm) GetDetail() []byte { - if m != nil { - return m.Detail - } - return nil -} - -func (m *TipsComm) GetDefaultTips() string { - if m != nil { - return m.DefaultTips - } - return "" -} - -func (m *TipsComm) GetJsonDetail() string { - if m != nil { - return m.JsonDetail - } - return "" -} - -// OnGroupCreated() -type GroupCreatedTips struct { - Group *GroupInfo `protobuf:"bytes,1,opt,name=group" json:"group,omitempty"` - OpUser *GroupMemberFullInfo `protobuf:"bytes,2,opt,name=opUser" json:"opUser,omitempty"` - MemberList []*GroupMemberFullInfo `protobuf:"bytes,3,rep,name=memberList" json:"memberList,omitempty"` - OperationTime int64 `protobuf:"varint,4,opt,name=operationTime" json:"operationTime,omitempty"` - GroupOwnerUser *GroupMemberFullInfo `protobuf:"bytes,5,opt,name=groupOwnerUser" json:"groupOwnerUser,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *GroupCreatedTips) Reset() { *m = GroupCreatedTips{} } -func (m *GroupCreatedTips) String() string { return proto.CompactTextString(m) } -func (*GroupCreatedTips) ProtoMessage() {} -func (*GroupCreatedTips) Descriptor() ([]byte, []int) { - return fileDescriptor_ws_bc78a4975e7e5f46, []int{25} -} -func (m *GroupCreatedTips) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_GroupCreatedTips.Unmarshal(m, b) -} -func (m *GroupCreatedTips) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_GroupCreatedTips.Marshal(b, m, deterministic) -} -func (dst *GroupCreatedTips) XXX_Merge(src proto.Message) { - xxx_messageInfo_GroupCreatedTips.Merge(dst, src) -} -func (m *GroupCreatedTips) XXX_Size() int { - return xxx_messageInfo_GroupCreatedTips.Size(m) -} -func (m *GroupCreatedTips) XXX_DiscardUnknown() { - xxx_messageInfo_GroupCreatedTips.DiscardUnknown(m) -} - -var xxx_messageInfo_GroupCreatedTips proto.InternalMessageInfo - -func (m *GroupCreatedTips) GetGroup() *GroupInfo { - if m != nil { - return m.Group - } - return nil -} - -func (m *GroupCreatedTips) GetOpUser() *GroupMemberFullInfo { - if m != nil { - return m.OpUser - } - return nil -} - -func (m *GroupCreatedTips) GetMemberList() []*GroupMemberFullInfo { - if m != nil { - return m.MemberList - } - return nil -} - -func (m *GroupCreatedTips) GetOperationTime() int64 { - if m != nil { - return m.OperationTime - } - return 0 -} - -func (m *GroupCreatedTips) GetGroupOwnerUser() *GroupMemberFullInfo { - if m != nil { - return m.GroupOwnerUser - } - return nil -} - -// OnGroupInfoSet() -type GroupInfoSetTips struct { - OpUser *GroupMemberFullInfo `protobuf:"bytes,1,opt,name=opUser" json:"opUser,omitempty"` - MuteTime int64 `protobuf:"varint,2,opt,name=muteTime" json:"muteTime,omitempty"` - Group *GroupInfo `protobuf:"bytes,3,opt,name=group" json:"group,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *GroupInfoSetTips) Reset() { *m = GroupInfoSetTips{} } -func (m *GroupInfoSetTips) String() string { return proto.CompactTextString(m) } -func (*GroupInfoSetTips) ProtoMessage() {} -func (*GroupInfoSetTips) Descriptor() ([]byte, []int) { - return fileDescriptor_ws_bc78a4975e7e5f46, []int{26} -} -func (m *GroupInfoSetTips) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_GroupInfoSetTips.Unmarshal(m, b) -} -func (m *GroupInfoSetTips) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_GroupInfoSetTips.Marshal(b, m, deterministic) -} -func (dst *GroupInfoSetTips) XXX_Merge(src proto.Message) { - xxx_messageInfo_GroupInfoSetTips.Merge(dst, src) -} -func (m *GroupInfoSetTips) XXX_Size() int { - return xxx_messageInfo_GroupInfoSetTips.Size(m) -} -func (m *GroupInfoSetTips) XXX_DiscardUnknown() { - xxx_messageInfo_GroupInfoSetTips.DiscardUnknown(m) -} - -var xxx_messageInfo_GroupInfoSetTips proto.InternalMessageInfo - -func (m *GroupInfoSetTips) GetOpUser() *GroupMemberFullInfo { - if m != nil { - return m.OpUser - } - return nil -} - -func (m *GroupInfoSetTips) GetMuteTime() int64 { - if m != nil { - return m.MuteTime - } - return 0 -} - -func (m *GroupInfoSetTips) GetGroup() *GroupInfo { - if m != nil { - return m.Group - } - return nil -} - -// OnJoinGroupApplication() -type JoinGroupApplicationTips struct { - Group *GroupInfo `protobuf:"bytes,1,opt,name=group" json:"group,omitempty"` - Applicant *PublicUserInfo `protobuf:"bytes,2,opt,name=applicant" json:"applicant,omitempty"` - ReqMsg string `protobuf:"bytes,3,opt,name=reqMsg" json:"reqMsg,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *JoinGroupApplicationTips) Reset() { *m = JoinGroupApplicationTips{} } -func (m *JoinGroupApplicationTips) String() string { return proto.CompactTextString(m) } -func (*JoinGroupApplicationTips) ProtoMessage() {} -func (*JoinGroupApplicationTips) Descriptor() ([]byte, []int) { - return fileDescriptor_ws_bc78a4975e7e5f46, []int{27} -} -func (m *JoinGroupApplicationTips) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_JoinGroupApplicationTips.Unmarshal(m, b) -} -func (m *JoinGroupApplicationTips) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_JoinGroupApplicationTips.Marshal(b, m, deterministic) -} -func (dst *JoinGroupApplicationTips) XXX_Merge(src proto.Message) { - xxx_messageInfo_JoinGroupApplicationTips.Merge(dst, src) -} -func (m *JoinGroupApplicationTips) XXX_Size() int { - return xxx_messageInfo_JoinGroupApplicationTips.Size(m) -} -func (m *JoinGroupApplicationTips) XXX_DiscardUnknown() { - xxx_messageInfo_JoinGroupApplicationTips.DiscardUnknown(m) -} - -var xxx_messageInfo_JoinGroupApplicationTips proto.InternalMessageInfo - -func (m *JoinGroupApplicationTips) GetGroup() *GroupInfo { - if m != nil { - return m.Group - } - return nil -} - -func (m *JoinGroupApplicationTips) GetApplicant() *PublicUserInfo { - if m != nil { - return m.Applicant - } - return nil -} - -func (m *JoinGroupApplicationTips) GetReqMsg() string { - if m != nil { - return m.ReqMsg - } - return "" -} - -// OnQuitGroup() -// -// Actively leave the group -type MemberQuitTips struct { - Group *GroupInfo `protobuf:"bytes,1,opt,name=group" json:"group,omitempty"` - QuitUser *GroupMemberFullInfo `protobuf:"bytes,2,opt,name=quitUser" json:"quitUser,omitempty"` - OperationTime int64 `protobuf:"varint,3,opt,name=operationTime" json:"operationTime,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *MemberQuitTips) Reset() { *m = MemberQuitTips{} } -func (m *MemberQuitTips) String() string { return proto.CompactTextString(m) } -func (*MemberQuitTips) ProtoMessage() {} -func (*MemberQuitTips) Descriptor() ([]byte, []int) { - return fileDescriptor_ws_bc78a4975e7e5f46, []int{28} -} -func (m *MemberQuitTips) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_MemberQuitTips.Unmarshal(m, b) -} -func (m *MemberQuitTips) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_MemberQuitTips.Marshal(b, m, deterministic) -} -func (dst *MemberQuitTips) XXX_Merge(src proto.Message) { - xxx_messageInfo_MemberQuitTips.Merge(dst, src) -} -func (m *MemberQuitTips) XXX_Size() int { - return xxx_messageInfo_MemberQuitTips.Size(m) -} -func (m *MemberQuitTips) XXX_DiscardUnknown() { - xxx_messageInfo_MemberQuitTips.DiscardUnknown(m) -} - -var xxx_messageInfo_MemberQuitTips proto.InternalMessageInfo - -func (m *MemberQuitTips) GetGroup() *GroupInfo { - if m != nil { - return m.Group - } - return nil -} - -func (m *MemberQuitTips) GetQuitUser() *GroupMemberFullInfo { - if m != nil { - return m.QuitUser - } - return nil -} - -func (m *MemberQuitTips) GetOperationTime() int64 { - if m != nil { - return m.OperationTime - } - return 0 -} - -// OnApplicationGroupAccepted() -type GroupApplicationAcceptedTips struct { - Group *GroupInfo `protobuf:"bytes,1,opt,name=group" json:"group,omitempty"` - OpUser *GroupMemberFullInfo `protobuf:"bytes,2,opt,name=opUser" json:"opUser,omitempty"` - HandleMsg string `protobuf:"bytes,4,opt,name=handleMsg" json:"handleMsg,omitempty"` - ReceiverAs int32 `protobuf:"varint,5,opt,name=receiverAs" json:"receiverAs,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *GroupApplicationAcceptedTips) Reset() { *m = GroupApplicationAcceptedTips{} } -func (m *GroupApplicationAcceptedTips) String() string { return proto.CompactTextString(m) } -func (*GroupApplicationAcceptedTips) ProtoMessage() {} -func (*GroupApplicationAcceptedTips) Descriptor() ([]byte, []int) { - return fileDescriptor_ws_bc78a4975e7e5f46, []int{29} -} -func (m *GroupApplicationAcceptedTips) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_GroupApplicationAcceptedTips.Unmarshal(m, b) -} -func (m *GroupApplicationAcceptedTips) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_GroupApplicationAcceptedTips.Marshal(b, m, deterministic) -} -func (dst *GroupApplicationAcceptedTips) XXX_Merge(src proto.Message) { - xxx_messageInfo_GroupApplicationAcceptedTips.Merge(dst, src) -} -func (m *GroupApplicationAcceptedTips) XXX_Size() int { - return xxx_messageInfo_GroupApplicationAcceptedTips.Size(m) -} -func (m *GroupApplicationAcceptedTips) XXX_DiscardUnknown() { - xxx_messageInfo_GroupApplicationAcceptedTips.DiscardUnknown(m) -} - -var xxx_messageInfo_GroupApplicationAcceptedTips proto.InternalMessageInfo - -func (m *GroupApplicationAcceptedTips) GetGroup() *GroupInfo { - if m != nil { - return m.Group - } - return nil -} - -func (m *GroupApplicationAcceptedTips) GetOpUser() *GroupMemberFullInfo { - if m != nil { - return m.OpUser - } - return nil -} - -func (m *GroupApplicationAcceptedTips) GetHandleMsg() string { - if m != nil { - return m.HandleMsg - } - return "" -} - -func (m *GroupApplicationAcceptedTips) GetReceiverAs() int32 { - if m != nil { - return m.ReceiverAs - } - return 0 -} - -// OnApplicationGroupRejected() -type GroupApplicationRejectedTips struct { - Group *GroupInfo `protobuf:"bytes,1,opt,name=group" json:"group,omitempty"` - OpUser *GroupMemberFullInfo `protobuf:"bytes,2,opt,name=opUser" json:"opUser,omitempty"` - HandleMsg string `protobuf:"bytes,4,opt,name=handleMsg" json:"handleMsg,omitempty"` - ReceiverAs int32 `protobuf:"varint,5,opt,name=receiverAs" json:"receiverAs,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *GroupApplicationRejectedTips) Reset() { *m = GroupApplicationRejectedTips{} } -func (m *GroupApplicationRejectedTips) String() string { return proto.CompactTextString(m) } -func (*GroupApplicationRejectedTips) ProtoMessage() {} -func (*GroupApplicationRejectedTips) Descriptor() ([]byte, []int) { - return fileDescriptor_ws_bc78a4975e7e5f46, []int{30} -} -func (m *GroupApplicationRejectedTips) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_GroupApplicationRejectedTips.Unmarshal(m, b) -} -func (m *GroupApplicationRejectedTips) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_GroupApplicationRejectedTips.Marshal(b, m, deterministic) -} -func (dst *GroupApplicationRejectedTips) XXX_Merge(src proto.Message) { - xxx_messageInfo_GroupApplicationRejectedTips.Merge(dst, src) -} -func (m *GroupApplicationRejectedTips) XXX_Size() int { - return xxx_messageInfo_GroupApplicationRejectedTips.Size(m) -} -func (m *GroupApplicationRejectedTips) XXX_DiscardUnknown() { - xxx_messageInfo_GroupApplicationRejectedTips.DiscardUnknown(m) -} - -var xxx_messageInfo_GroupApplicationRejectedTips proto.InternalMessageInfo - -func (m *GroupApplicationRejectedTips) GetGroup() *GroupInfo { - if m != nil { - return m.Group - } - return nil -} - -func (m *GroupApplicationRejectedTips) GetOpUser() *GroupMemberFullInfo { - if m != nil { - return m.OpUser - } - return nil -} - -func (m *GroupApplicationRejectedTips) GetHandleMsg() string { - if m != nil { - return m.HandleMsg - } - return "" -} - -func (m *GroupApplicationRejectedTips) GetReceiverAs() int32 { - if m != nil { - return m.ReceiverAs - } - return 0 -} - -// OnTransferGroupOwner() -type GroupOwnerTransferredTips struct { - Group *GroupInfo `protobuf:"bytes,1,opt,name=group" json:"group,omitempty"` - OpUser *GroupMemberFullInfo `protobuf:"bytes,2,opt,name=opUser" json:"opUser,omitempty"` - NewGroupOwner *GroupMemberFullInfo `protobuf:"bytes,3,opt,name=newGroupOwner" json:"newGroupOwner,omitempty"` - OperationTime int64 `protobuf:"varint,4,opt,name=operationTime" json:"operationTime,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *GroupOwnerTransferredTips) Reset() { *m = GroupOwnerTransferredTips{} } -func (m *GroupOwnerTransferredTips) String() string { return proto.CompactTextString(m) } -func (*GroupOwnerTransferredTips) ProtoMessage() {} -func (*GroupOwnerTransferredTips) Descriptor() ([]byte, []int) { - return fileDescriptor_ws_bc78a4975e7e5f46, []int{31} -} -func (m *GroupOwnerTransferredTips) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_GroupOwnerTransferredTips.Unmarshal(m, b) -} -func (m *GroupOwnerTransferredTips) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_GroupOwnerTransferredTips.Marshal(b, m, deterministic) -} -func (dst *GroupOwnerTransferredTips) XXX_Merge(src proto.Message) { - xxx_messageInfo_GroupOwnerTransferredTips.Merge(dst, src) -} -func (m *GroupOwnerTransferredTips) XXX_Size() int { - return xxx_messageInfo_GroupOwnerTransferredTips.Size(m) -} -func (m *GroupOwnerTransferredTips) XXX_DiscardUnknown() { - xxx_messageInfo_GroupOwnerTransferredTips.DiscardUnknown(m) -} - -var xxx_messageInfo_GroupOwnerTransferredTips proto.InternalMessageInfo - -func (m *GroupOwnerTransferredTips) GetGroup() *GroupInfo { - if m != nil { - return m.Group - } - return nil -} - -func (m *GroupOwnerTransferredTips) GetOpUser() *GroupMemberFullInfo { - if m != nil { - return m.OpUser - } - return nil -} - -func (m *GroupOwnerTransferredTips) GetNewGroupOwner() *GroupMemberFullInfo { - if m != nil { - return m.NewGroupOwner - } - return nil -} - -func (m *GroupOwnerTransferredTips) GetOperationTime() int64 { - if m != nil { - return m.OperationTime - } - return 0 -} - -// OnMemberKicked() -type MemberKickedTips struct { - Group *GroupInfo `protobuf:"bytes,1,opt,name=group" json:"group,omitempty"` - OpUser *GroupMemberFullInfo `protobuf:"bytes,2,opt,name=opUser" json:"opUser,omitempty"` - KickedUserList []*GroupMemberFullInfo `protobuf:"bytes,3,rep,name=kickedUserList" json:"kickedUserList,omitempty"` - OperationTime int64 `protobuf:"varint,4,opt,name=operationTime" json:"operationTime,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *MemberKickedTips) Reset() { *m = MemberKickedTips{} } -func (m *MemberKickedTips) String() string { return proto.CompactTextString(m) } -func (*MemberKickedTips) ProtoMessage() {} -func (*MemberKickedTips) Descriptor() ([]byte, []int) { - return fileDescriptor_ws_bc78a4975e7e5f46, []int{32} -} -func (m *MemberKickedTips) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_MemberKickedTips.Unmarshal(m, b) -} -func (m *MemberKickedTips) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_MemberKickedTips.Marshal(b, m, deterministic) -} -func (dst *MemberKickedTips) XXX_Merge(src proto.Message) { - xxx_messageInfo_MemberKickedTips.Merge(dst, src) -} -func (m *MemberKickedTips) XXX_Size() int { - return xxx_messageInfo_MemberKickedTips.Size(m) -} -func (m *MemberKickedTips) XXX_DiscardUnknown() { - xxx_messageInfo_MemberKickedTips.DiscardUnknown(m) -} - -var xxx_messageInfo_MemberKickedTips proto.InternalMessageInfo - -func (m *MemberKickedTips) GetGroup() *GroupInfo { - if m != nil { - return m.Group - } - return nil -} - -func (m *MemberKickedTips) GetOpUser() *GroupMemberFullInfo { - if m != nil { - return m.OpUser - } - return nil -} - -func (m *MemberKickedTips) GetKickedUserList() []*GroupMemberFullInfo { - if m != nil { - return m.KickedUserList - } - return nil -} - -func (m *MemberKickedTips) GetOperationTime() int64 { - if m != nil { - return m.OperationTime - } - return 0 -} - -// OnMemberInvited() -type MemberInvitedTips struct { - Group *GroupInfo `protobuf:"bytes,1,opt,name=group" json:"group,omitempty"` - OpUser *GroupMemberFullInfo `protobuf:"bytes,2,opt,name=opUser" json:"opUser,omitempty"` - InvitedUserList []*GroupMemberFullInfo `protobuf:"bytes,3,rep,name=invitedUserList" json:"invitedUserList,omitempty"` - OperationTime int64 `protobuf:"varint,4,opt,name=operationTime" json:"operationTime,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *MemberInvitedTips) Reset() { *m = MemberInvitedTips{} } -func (m *MemberInvitedTips) String() string { return proto.CompactTextString(m) } -func (*MemberInvitedTips) ProtoMessage() {} -func (*MemberInvitedTips) Descriptor() ([]byte, []int) { - return fileDescriptor_ws_bc78a4975e7e5f46, []int{33} -} -func (m *MemberInvitedTips) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_MemberInvitedTips.Unmarshal(m, b) -} -func (m *MemberInvitedTips) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_MemberInvitedTips.Marshal(b, m, deterministic) -} -func (dst *MemberInvitedTips) XXX_Merge(src proto.Message) { - xxx_messageInfo_MemberInvitedTips.Merge(dst, src) -} -func (m *MemberInvitedTips) XXX_Size() int { - return xxx_messageInfo_MemberInvitedTips.Size(m) -} -func (m *MemberInvitedTips) XXX_DiscardUnknown() { - xxx_messageInfo_MemberInvitedTips.DiscardUnknown(m) -} - -var xxx_messageInfo_MemberInvitedTips proto.InternalMessageInfo - -func (m *MemberInvitedTips) GetGroup() *GroupInfo { - if m != nil { - return m.Group - } - return nil -} - -func (m *MemberInvitedTips) GetOpUser() *GroupMemberFullInfo { - if m != nil { - return m.OpUser - } - return nil -} - -func (m *MemberInvitedTips) GetInvitedUserList() []*GroupMemberFullInfo { - if m != nil { - return m.InvitedUserList - } - return nil -} - -func (m *MemberInvitedTips) GetOperationTime() int64 { - if m != nil { - return m.OperationTime - } - return 0 -} - -// Actively join the group -type MemberEnterTips struct { - Group *GroupInfo `protobuf:"bytes,1,opt,name=group" json:"group,omitempty"` - EntrantUser *GroupMemberFullInfo `protobuf:"bytes,2,opt,name=entrantUser" json:"entrantUser,omitempty"` - OperationTime int64 `protobuf:"varint,3,opt,name=operationTime" json:"operationTime,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *MemberEnterTips) Reset() { *m = MemberEnterTips{} } -func (m *MemberEnterTips) String() string { return proto.CompactTextString(m) } -func (*MemberEnterTips) ProtoMessage() {} -func (*MemberEnterTips) Descriptor() ([]byte, []int) { - return fileDescriptor_ws_bc78a4975e7e5f46, []int{34} -} -func (m *MemberEnterTips) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_MemberEnterTips.Unmarshal(m, b) -} -func (m *MemberEnterTips) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_MemberEnterTips.Marshal(b, m, deterministic) -} -func (dst *MemberEnterTips) XXX_Merge(src proto.Message) { - xxx_messageInfo_MemberEnterTips.Merge(dst, src) -} -func (m *MemberEnterTips) XXX_Size() int { - return xxx_messageInfo_MemberEnterTips.Size(m) -} -func (m *MemberEnterTips) XXX_DiscardUnknown() { - xxx_messageInfo_MemberEnterTips.DiscardUnknown(m) -} - -var xxx_messageInfo_MemberEnterTips proto.InternalMessageInfo - -func (m *MemberEnterTips) GetGroup() *GroupInfo { - if m != nil { - return m.Group - } - return nil -} - -func (m *MemberEnterTips) GetEntrantUser() *GroupMemberFullInfo { - if m != nil { - return m.EntrantUser - } - return nil -} - -func (m *MemberEnterTips) GetOperationTime() int64 { - if m != nil { - return m.OperationTime - } - return 0 -} - -type GroupDismissedTips struct { - Group *GroupInfo `protobuf:"bytes,1,opt,name=group" json:"group,omitempty"` - OpUser *GroupMemberFullInfo `protobuf:"bytes,2,opt,name=opUser" json:"opUser,omitempty"` - OperationTime int64 `protobuf:"varint,3,opt,name=operationTime" json:"operationTime,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *GroupDismissedTips) Reset() { *m = GroupDismissedTips{} } -func (m *GroupDismissedTips) String() string { return proto.CompactTextString(m) } -func (*GroupDismissedTips) ProtoMessage() {} -func (*GroupDismissedTips) Descriptor() ([]byte, []int) { - return fileDescriptor_ws_bc78a4975e7e5f46, []int{35} -} -func (m *GroupDismissedTips) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_GroupDismissedTips.Unmarshal(m, b) -} -func (m *GroupDismissedTips) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_GroupDismissedTips.Marshal(b, m, deterministic) -} -func (dst *GroupDismissedTips) XXX_Merge(src proto.Message) { - xxx_messageInfo_GroupDismissedTips.Merge(dst, src) -} -func (m *GroupDismissedTips) XXX_Size() int { - return xxx_messageInfo_GroupDismissedTips.Size(m) -} -func (m *GroupDismissedTips) XXX_DiscardUnknown() { - xxx_messageInfo_GroupDismissedTips.DiscardUnknown(m) -} - -var xxx_messageInfo_GroupDismissedTips proto.InternalMessageInfo - -func (m *GroupDismissedTips) GetGroup() *GroupInfo { - if m != nil { - return m.Group - } - return nil -} - -func (m *GroupDismissedTips) GetOpUser() *GroupMemberFullInfo { - if m != nil { - return m.OpUser - } - return nil -} - -func (m *GroupDismissedTips) GetOperationTime() int64 { - if m != nil { - return m.OperationTime - } - return 0 -} - -type GroupMemberMutedTips struct { - Group *GroupInfo `protobuf:"bytes,1,opt,name=group" json:"group,omitempty"` - OpUser *GroupMemberFullInfo `protobuf:"bytes,2,opt,name=opUser" json:"opUser,omitempty"` - OperationTime int64 `protobuf:"varint,3,opt,name=operationTime" json:"operationTime,omitempty"` - MutedUser *GroupMemberFullInfo `protobuf:"bytes,4,opt,name=mutedUser" json:"mutedUser,omitempty"` - MutedSeconds uint32 `protobuf:"varint,5,opt,name=mutedSeconds" json:"mutedSeconds,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *GroupMemberMutedTips) Reset() { *m = GroupMemberMutedTips{} } -func (m *GroupMemberMutedTips) String() string { return proto.CompactTextString(m) } -func (*GroupMemberMutedTips) ProtoMessage() {} -func (*GroupMemberMutedTips) Descriptor() ([]byte, []int) { - return fileDescriptor_ws_bc78a4975e7e5f46, []int{36} -} -func (m *GroupMemberMutedTips) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_GroupMemberMutedTips.Unmarshal(m, b) -} -func (m *GroupMemberMutedTips) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_GroupMemberMutedTips.Marshal(b, m, deterministic) -} -func (dst *GroupMemberMutedTips) XXX_Merge(src proto.Message) { - xxx_messageInfo_GroupMemberMutedTips.Merge(dst, src) -} -func (m *GroupMemberMutedTips) XXX_Size() int { - return xxx_messageInfo_GroupMemberMutedTips.Size(m) -} -func (m *GroupMemberMutedTips) XXX_DiscardUnknown() { - xxx_messageInfo_GroupMemberMutedTips.DiscardUnknown(m) -} - -var xxx_messageInfo_GroupMemberMutedTips proto.InternalMessageInfo - -func (m *GroupMemberMutedTips) GetGroup() *GroupInfo { - if m != nil { - return m.Group - } - return nil -} - -func (m *GroupMemberMutedTips) GetOpUser() *GroupMemberFullInfo { - if m != nil { - return m.OpUser - } - return nil -} - -func (m *GroupMemberMutedTips) GetOperationTime() int64 { - if m != nil { - return m.OperationTime - } - return 0 -} - -func (m *GroupMemberMutedTips) GetMutedUser() *GroupMemberFullInfo { - if m != nil { - return m.MutedUser - } - return nil -} - -func (m *GroupMemberMutedTips) GetMutedSeconds() uint32 { - if m != nil { - return m.MutedSeconds - } - return 0 -} - -type GroupMemberCancelMutedTips struct { - Group *GroupInfo `protobuf:"bytes,1,opt,name=group" json:"group,omitempty"` - OpUser *GroupMemberFullInfo `protobuf:"bytes,2,opt,name=opUser" json:"opUser,omitempty"` - OperationTime int64 `protobuf:"varint,3,opt,name=operationTime" json:"operationTime,omitempty"` - MutedUser *GroupMemberFullInfo `protobuf:"bytes,4,opt,name=mutedUser" json:"mutedUser,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *GroupMemberCancelMutedTips) Reset() { *m = GroupMemberCancelMutedTips{} } -func (m *GroupMemberCancelMutedTips) String() string { return proto.CompactTextString(m) } -func (*GroupMemberCancelMutedTips) ProtoMessage() {} -func (*GroupMemberCancelMutedTips) Descriptor() ([]byte, []int) { - return fileDescriptor_ws_bc78a4975e7e5f46, []int{37} -} -func (m *GroupMemberCancelMutedTips) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_GroupMemberCancelMutedTips.Unmarshal(m, b) -} -func (m *GroupMemberCancelMutedTips) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_GroupMemberCancelMutedTips.Marshal(b, m, deterministic) -} -func (dst *GroupMemberCancelMutedTips) XXX_Merge(src proto.Message) { - xxx_messageInfo_GroupMemberCancelMutedTips.Merge(dst, src) -} -func (m *GroupMemberCancelMutedTips) XXX_Size() int { - return xxx_messageInfo_GroupMemberCancelMutedTips.Size(m) -} -func (m *GroupMemberCancelMutedTips) XXX_DiscardUnknown() { - xxx_messageInfo_GroupMemberCancelMutedTips.DiscardUnknown(m) -} - -var xxx_messageInfo_GroupMemberCancelMutedTips proto.InternalMessageInfo - -func (m *GroupMemberCancelMutedTips) GetGroup() *GroupInfo { - if m != nil { - return m.Group - } - return nil -} - -func (m *GroupMemberCancelMutedTips) GetOpUser() *GroupMemberFullInfo { - if m != nil { - return m.OpUser - } - return nil -} - -func (m *GroupMemberCancelMutedTips) GetOperationTime() int64 { - if m != nil { - return m.OperationTime - } - return 0 -} - -func (m *GroupMemberCancelMutedTips) GetMutedUser() *GroupMemberFullInfo { - if m != nil { - return m.MutedUser - } - return nil -} - -type GroupMutedTips struct { - Group *GroupInfo `protobuf:"bytes,1,opt,name=group" json:"group,omitempty"` - OpUser *GroupMemberFullInfo `protobuf:"bytes,2,opt,name=opUser" json:"opUser,omitempty"` - OperationTime int64 `protobuf:"varint,3,opt,name=operationTime" json:"operationTime,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *GroupMutedTips) Reset() { *m = GroupMutedTips{} } -func (m *GroupMutedTips) String() string { return proto.CompactTextString(m) } -func (*GroupMutedTips) ProtoMessage() {} -func (*GroupMutedTips) Descriptor() ([]byte, []int) { - return fileDescriptor_ws_bc78a4975e7e5f46, []int{38} -} -func (m *GroupMutedTips) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_GroupMutedTips.Unmarshal(m, b) -} -func (m *GroupMutedTips) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_GroupMutedTips.Marshal(b, m, deterministic) -} -func (dst *GroupMutedTips) XXX_Merge(src proto.Message) { - xxx_messageInfo_GroupMutedTips.Merge(dst, src) -} -func (m *GroupMutedTips) XXX_Size() int { - return xxx_messageInfo_GroupMutedTips.Size(m) -} -func (m *GroupMutedTips) XXX_DiscardUnknown() { - xxx_messageInfo_GroupMutedTips.DiscardUnknown(m) -} - -var xxx_messageInfo_GroupMutedTips proto.InternalMessageInfo - -func (m *GroupMutedTips) GetGroup() *GroupInfo { - if m != nil { - return m.Group - } - return nil -} - -func (m *GroupMutedTips) GetOpUser() *GroupMemberFullInfo { - if m != nil { - return m.OpUser - } - return nil -} - -func (m *GroupMutedTips) GetOperationTime() int64 { - if m != nil { - return m.OperationTime - } - return 0 -} - -type GroupCancelMutedTips struct { - Group *GroupInfo `protobuf:"bytes,1,opt,name=group" json:"group,omitempty"` - OpUser *GroupMemberFullInfo `protobuf:"bytes,2,opt,name=opUser" json:"opUser,omitempty"` - OperationTime int64 `protobuf:"varint,3,opt,name=operationTime" json:"operationTime,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *GroupCancelMutedTips) Reset() { *m = GroupCancelMutedTips{} } -func (m *GroupCancelMutedTips) String() string { return proto.CompactTextString(m) } -func (*GroupCancelMutedTips) ProtoMessage() {} -func (*GroupCancelMutedTips) Descriptor() ([]byte, []int) { - return fileDescriptor_ws_bc78a4975e7e5f46, []int{39} -} -func (m *GroupCancelMutedTips) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_GroupCancelMutedTips.Unmarshal(m, b) -} -func (m *GroupCancelMutedTips) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_GroupCancelMutedTips.Marshal(b, m, deterministic) -} -func (dst *GroupCancelMutedTips) XXX_Merge(src proto.Message) { - xxx_messageInfo_GroupCancelMutedTips.Merge(dst, src) -} -func (m *GroupCancelMutedTips) XXX_Size() int { - return xxx_messageInfo_GroupCancelMutedTips.Size(m) -} -func (m *GroupCancelMutedTips) XXX_DiscardUnknown() { - xxx_messageInfo_GroupCancelMutedTips.DiscardUnknown(m) -} - -var xxx_messageInfo_GroupCancelMutedTips proto.InternalMessageInfo - -func (m *GroupCancelMutedTips) GetGroup() *GroupInfo { - if m != nil { - return m.Group - } - return nil -} - -func (m *GroupCancelMutedTips) GetOpUser() *GroupMemberFullInfo { - if m != nil { - return m.OpUser - } - return nil -} - -func (m *GroupCancelMutedTips) GetOperationTime() int64 { - if m != nil { - return m.OperationTime - } - return 0 -} - -type GroupMemberInfoSetTips struct { - Group *GroupInfo `protobuf:"bytes,1,opt,name=group" json:"group,omitempty"` - OpUser *GroupMemberFullInfo `protobuf:"bytes,2,opt,name=opUser" json:"opUser,omitempty"` - OperationTime int64 `protobuf:"varint,3,opt,name=operationTime" json:"operationTime,omitempty"` - ChangedUser *GroupMemberFullInfo `protobuf:"bytes,4,opt,name=changedUser" json:"changedUser,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *GroupMemberInfoSetTips) Reset() { *m = GroupMemberInfoSetTips{} } -func (m *GroupMemberInfoSetTips) String() string { return proto.CompactTextString(m) } -func (*GroupMemberInfoSetTips) ProtoMessage() {} -func (*GroupMemberInfoSetTips) Descriptor() ([]byte, []int) { - return fileDescriptor_ws_bc78a4975e7e5f46, []int{40} -} -func (m *GroupMemberInfoSetTips) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_GroupMemberInfoSetTips.Unmarshal(m, b) -} -func (m *GroupMemberInfoSetTips) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_GroupMemberInfoSetTips.Marshal(b, m, deterministic) -} -func (dst *GroupMemberInfoSetTips) XXX_Merge(src proto.Message) { - xxx_messageInfo_GroupMemberInfoSetTips.Merge(dst, src) -} -func (m *GroupMemberInfoSetTips) XXX_Size() int { - return xxx_messageInfo_GroupMemberInfoSetTips.Size(m) -} -func (m *GroupMemberInfoSetTips) XXX_DiscardUnknown() { - xxx_messageInfo_GroupMemberInfoSetTips.DiscardUnknown(m) -} - -var xxx_messageInfo_GroupMemberInfoSetTips proto.InternalMessageInfo - -func (m *GroupMemberInfoSetTips) GetGroup() *GroupInfo { - if m != nil { - return m.Group - } - return nil -} - -func (m *GroupMemberInfoSetTips) GetOpUser() *GroupMemberFullInfo { - if m != nil { - return m.OpUser - } - return nil -} - -func (m *GroupMemberInfoSetTips) GetOperationTime() int64 { - if m != nil { - return m.OperationTime - } - return 0 -} - -func (m *GroupMemberInfoSetTips) GetChangedUser() *GroupMemberFullInfo { - if m != nil { - return m.ChangedUser - } - return nil -} - -type OrganizationChangedTips struct { - OpUser *UserInfo `protobuf:"bytes,2,opt,name=opUser" json:"opUser,omitempty"` - OperationTime int64 `protobuf:"varint,3,opt,name=operationTime" json:"operationTime,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *OrganizationChangedTips) Reset() { *m = OrganizationChangedTips{} } -func (m *OrganizationChangedTips) String() string { return proto.CompactTextString(m) } -func (*OrganizationChangedTips) ProtoMessage() {} -func (*OrganizationChangedTips) Descriptor() ([]byte, []int) { - return fileDescriptor_ws_bc78a4975e7e5f46, []int{41} -} -func (m *OrganizationChangedTips) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_OrganizationChangedTips.Unmarshal(m, b) -} -func (m *OrganizationChangedTips) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_OrganizationChangedTips.Marshal(b, m, deterministic) -} -func (dst *OrganizationChangedTips) XXX_Merge(src proto.Message) { - xxx_messageInfo_OrganizationChangedTips.Merge(dst, src) -} -func (m *OrganizationChangedTips) XXX_Size() int { - return xxx_messageInfo_OrganizationChangedTips.Size(m) -} -func (m *OrganizationChangedTips) XXX_DiscardUnknown() { - xxx_messageInfo_OrganizationChangedTips.DiscardUnknown(m) -} - -var xxx_messageInfo_OrganizationChangedTips proto.InternalMessageInfo - -func (m *OrganizationChangedTips) GetOpUser() *UserInfo { - if m != nil { - return m.OpUser - } - return nil -} - -func (m *OrganizationChangedTips) GetOperationTime() int64 { - if m != nil { - return m.OperationTime - } - return 0 -} - -type FriendApplication struct { - AddTime int64 `protobuf:"varint,1,opt,name=addTime" json:"addTime,omitempty"` - AddSource string `protobuf:"bytes,2,opt,name=addSource" json:"addSource,omitempty"` - AddWording string `protobuf:"bytes,3,opt,name=addWording" json:"addWording,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *FriendApplication) Reset() { *m = FriendApplication{} } -func (m *FriendApplication) String() string { return proto.CompactTextString(m) } -func (*FriendApplication) ProtoMessage() {} -func (*FriendApplication) Descriptor() ([]byte, []int) { - return fileDescriptor_ws_bc78a4975e7e5f46, []int{42} -} -func (m *FriendApplication) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_FriendApplication.Unmarshal(m, b) -} -func (m *FriendApplication) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_FriendApplication.Marshal(b, m, deterministic) -} -func (dst *FriendApplication) XXX_Merge(src proto.Message) { - xxx_messageInfo_FriendApplication.Merge(dst, src) -} -func (m *FriendApplication) XXX_Size() int { - return xxx_messageInfo_FriendApplication.Size(m) -} -func (m *FriendApplication) XXX_DiscardUnknown() { - xxx_messageInfo_FriendApplication.DiscardUnknown(m) -} - -var xxx_messageInfo_FriendApplication proto.InternalMessageInfo - -func (m *FriendApplication) GetAddTime() int64 { - if m != nil { - return m.AddTime - } - return 0 -} - -func (m *FriendApplication) GetAddSource() string { - if m != nil { - return m.AddSource - } - return "" -} - -func (m *FriendApplication) GetAddWording() string { - if m != nil { - return m.AddWording - } - return "" -} - -type FromToUserID struct { - FromUserID string `protobuf:"bytes,1,opt,name=fromUserID" json:"fromUserID,omitempty"` - ToUserID string `protobuf:"bytes,2,opt,name=toUserID" json:"toUserID,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *FromToUserID) Reset() { *m = FromToUserID{} } -func (m *FromToUserID) String() string { return proto.CompactTextString(m) } -func (*FromToUserID) ProtoMessage() {} -func (*FromToUserID) Descriptor() ([]byte, []int) { - return fileDescriptor_ws_bc78a4975e7e5f46, []int{43} -} -func (m *FromToUserID) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_FromToUserID.Unmarshal(m, b) -} -func (m *FromToUserID) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_FromToUserID.Marshal(b, m, deterministic) -} -func (dst *FromToUserID) XXX_Merge(src proto.Message) { - xxx_messageInfo_FromToUserID.Merge(dst, src) -} -func (m *FromToUserID) XXX_Size() int { - return xxx_messageInfo_FromToUserID.Size(m) -} -func (m *FromToUserID) XXX_DiscardUnknown() { - xxx_messageInfo_FromToUserID.DiscardUnknown(m) -} - -var xxx_messageInfo_FromToUserID proto.InternalMessageInfo - -func (m *FromToUserID) GetFromUserID() string { - if m != nil { - return m.FromUserID - } - return "" -} - -func (m *FromToUserID) GetToUserID() string { - if m != nil { - return m.ToUserID - } - return "" -} - -// FromUserID apply to add ToUserID -type FriendApplicationTips struct { - FromToUserID *FromToUserID `protobuf:"bytes,1,opt,name=fromToUserID" json:"fromToUserID,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *FriendApplicationTips) Reset() { *m = FriendApplicationTips{} } -func (m *FriendApplicationTips) String() string { return proto.CompactTextString(m) } -func (*FriendApplicationTips) ProtoMessage() {} -func (*FriendApplicationTips) Descriptor() ([]byte, []int) { - return fileDescriptor_ws_bc78a4975e7e5f46, []int{44} -} -func (m *FriendApplicationTips) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_FriendApplicationTips.Unmarshal(m, b) -} -func (m *FriendApplicationTips) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_FriendApplicationTips.Marshal(b, m, deterministic) -} -func (dst *FriendApplicationTips) XXX_Merge(src proto.Message) { - xxx_messageInfo_FriendApplicationTips.Merge(dst, src) -} -func (m *FriendApplicationTips) XXX_Size() int { - return xxx_messageInfo_FriendApplicationTips.Size(m) -} -func (m *FriendApplicationTips) XXX_DiscardUnknown() { - xxx_messageInfo_FriendApplicationTips.DiscardUnknown(m) -} - -var xxx_messageInfo_FriendApplicationTips proto.InternalMessageInfo - -func (m *FriendApplicationTips) GetFromToUserID() *FromToUserID { - if m != nil { - return m.FromToUserID - } - return nil -} - -// FromUserID accept or reject ToUserID -type FriendApplicationApprovedTips struct { - FromToUserID *FromToUserID `protobuf:"bytes,1,opt,name=fromToUserID" json:"fromToUserID,omitempty"` - HandleMsg string `protobuf:"bytes,2,opt,name=handleMsg" json:"handleMsg,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *FriendApplicationApprovedTips) Reset() { *m = FriendApplicationApprovedTips{} } -func (m *FriendApplicationApprovedTips) String() string { return proto.CompactTextString(m) } -func (*FriendApplicationApprovedTips) ProtoMessage() {} -func (*FriendApplicationApprovedTips) Descriptor() ([]byte, []int) { - return fileDescriptor_ws_bc78a4975e7e5f46, []int{45} -} -func (m *FriendApplicationApprovedTips) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_FriendApplicationApprovedTips.Unmarshal(m, b) -} -func (m *FriendApplicationApprovedTips) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_FriendApplicationApprovedTips.Marshal(b, m, deterministic) -} -func (dst *FriendApplicationApprovedTips) XXX_Merge(src proto.Message) { - xxx_messageInfo_FriendApplicationApprovedTips.Merge(dst, src) -} -func (m *FriendApplicationApprovedTips) XXX_Size() int { - return xxx_messageInfo_FriendApplicationApprovedTips.Size(m) -} -func (m *FriendApplicationApprovedTips) XXX_DiscardUnknown() { - xxx_messageInfo_FriendApplicationApprovedTips.DiscardUnknown(m) -} - -var xxx_messageInfo_FriendApplicationApprovedTips proto.InternalMessageInfo - -func (m *FriendApplicationApprovedTips) GetFromToUserID() *FromToUserID { - if m != nil { - return m.FromToUserID - } - return nil -} - -func (m *FriendApplicationApprovedTips) GetHandleMsg() string { - if m != nil { - return m.HandleMsg - } - return "" -} - -// FromUserID accept or reject ToUserID -type FriendApplicationRejectedTips struct { - FromToUserID *FromToUserID `protobuf:"bytes,1,opt,name=fromToUserID" json:"fromToUserID,omitempty"` - HandleMsg string `protobuf:"bytes,2,opt,name=handleMsg" json:"handleMsg,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *FriendApplicationRejectedTips) Reset() { *m = FriendApplicationRejectedTips{} } -func (m *FriendApplicationRejectedTips) String() string { return proto.CompactTextString(m) } -func (*FriendApplicationRejectedTips) ProtoMessage() {} -func (*FriendApplicationRejectedTips) Descriptor() ([]byte, []int) { - return fileDescriptor_ws_bc78a4975e7e5f46, []int{46} -} -func (m *FriendApplicationRejectedTips) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_FriendApplicationRejectedTips.Unmarshal(m, b) -} -func (m *FriendApplicationRejectedTips) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_FriendApplicationRejectedTips.Marshal(b, m, deterministic) -} -func (dst *FriendApplicationRejectedTips) XXX_Merge(src proto.Message) { - xxx_messageInfo_FriendApplicationRejectedTips.Merge(dst, src) -} -func (m *FriendApplicationRejectedTips) XXX_Size() int { - return xxx_messageInfo_FriendApplicationRejectedTips.Size(m) -} -func (m *FriendApplicationRejectedTips) XXX_DiscardUnknown() { - xxx_messageInfo_FriendApplicationRejectedTips.DiscardUnknown(m) -} - -var xxx_messageInfo_FriendApplicationRejectedTips proto.InternalMessageInfo - -func (m *FriendApplicationRejectedTips) GetFromToUserID() *FromToUserID { - if m != nil { - return m.FromToUserID - } - return nil -} - -func (m *FriendApplicationRejectedTips) GetHandleMsg() string { - if m != nil { - return m.HandleMsg - } - return "" -} - -// FromUserID Added a friend ToUserID -type FriendAddedTips struct { - Friend *FriendInfo `protobuf:"bytes,1,opt,name=friend" json:"friend,omitempty"` - OperationTime int64 `protobuf:"varint,2,opt,name=operationTime" json:"operationTime,omitempty"` - OpUser *PublicUserInfo `protobuf:"bytes,3,opt,name=opUser" json:"opUser,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *FriendAddedTips) Reset() { *m = FriendAddedTips{} } -func (m *FriendAddedTips) String() string { return proto.CompactTextString(m) } -func (*FriendAddedTips) ProtoMessage() {} -func (*FriendAddedTips) Descriptor() ([]byte, []int) { - return fileDescriptor_ws_bc78a4975e7e5f46, []int{47} -} -func (m *FriendAddedTips) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_FriendAddedTips.Unmarshal(m, b) -} -func (m *FriendAddedTips) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_FriendAddedTips.Marshal(b, m, deterministic) -} -func (dst *FriendAddedTips) XXX_Merge(src proto.Message) { - xxx_messageInfo_FriendAddedTips.Merge(dst, src) -} -func (m *FriendAddedTips) XXX_Size() int { - return xxx_messageInfo_FriendAddedTips.Size(m) -} -func (m *FriendAddedTips) XXX_DiscardUnknown() { - xxx_messageInfo_FriendAddedTips.DiscardUnknown(m) -} - -var xxx_messageInfo_FriendAddedTips proto.InternalMessageInfo - -func (m *FriendAddedTips) GetFriend() *FriendInfo { - if m != nil { - return m.Friend - } - return nil -} - -func (m *FriendAddedTips) GetOperationTime() int64 { - if m != nil { - return m.OperationTime - } - return 0 -} - -func (m *FriendAddedTips) GetOpUser() *PublicUserInfo { - if m != nil { - return m.OpUser - } - return nil -} - -// FromUserID deleted a friend ToUserID -type FriendDeletedTips struct { - FromToUserID *FromToUserID `protobuf:"bytes,1,opt,name=fromToUserID" json:"fromToUserID,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *FriendDeletedTips) Reset() { *m = FriendDeletedTips{} } -func (m *FriendDeletedTips) String() string { return proto.CompactTextString(m) } -func (*FriendDeletedTips) ProtoMessage() {} -func (*FriendDeletedTips) Descriptor() ([]byte, []int) { - return fileDescriptor_ws_bc78a4975e7e5f46, []int{48} -} -func (m *FriendDeletedTips) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_FriendDeletedTips.Unmarshal(m, b) -} -func (m *FriendDeletedTips) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_FriendDeletedTips.Marshal(b, m, deterministic) -} -func (dst *FriendDeletedTips) XXX_Merge(src proto.Message) { - xxx_messageInfo_FriendDeletedTips.Merge(dst, src) -} -func (m *FriendDeletedTips) XXX_Size() int { - return xxx_messageInfo_FriendDeletedTips.Size(m) -} -func (m *FriendDeletedTips) XXX_DiscardUnknown() { - xxx_messageInfo_FriendDeletedTips.DiscardUnknown(m) -} - -var xxx_messageInfo_FriendDeletedTips proto.InternalMessageInfo - -func (m *FriendDeletedTips) GetFromToUserID() *FromToUserID { - if m != nil { - return m.FromToUserID - } - return nil -} - -type BlackAddedTips struct { - FromToUserID *FromToUserID `protobuf:"bytes,1,opt,name=fromToUserID" json:"fromToUserID,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *BlackAddedTips) Reset() { *m = BlackAddedTips{} } -func (m *BlackAddedTips) String() string { return proto.CompactTextString(m) } -func (*BlackAddedTips) ProtoMessage() {} -func (*BlackAddedTips) Descriptor() ([]byte, []int) { - return fileDescriptor_ws_bc78a4975e7e5f46, []int{49} -} -func (m *BlackAddedTips) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_BlackAddedTips.Unmarshal(m, b) -} -func (m *BlackAddedTips) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_BlackAddedTips.Marshal(b, m, deterministic) -} -func (dst *BlackAddedTips) XXX_Merge(src proto.Message) { - xxx_messageInfo_BlackAddedTips.Merge(dst, src) -} -func (m *BlackAddedTips) XXX_Size() int { - return xxx_messageInfo_BlackAddedTips.Size(m) -} -func (m *BlackAddedTips) XXX_DiscardUnknown() { - xxx_messageInfo_BlackAddedTips.DiscardUnknown(m) -} - -var xxx_messageInfo_BlackAddedTips proto.InternalMessageInfo - -func (m *BlackAddedTips) GetFromToUserID() *FromToUserID { - if m != nil { - return m.FromToUserID - } - return nil -} - -type BlackDeletedTips struct { - FromToUserID *FromToUserID `protobuf:"bytes,1,opt,name=fromToUserID" json:"fromToUserID,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *BlackDeletedTips) Reset() { *m = BlackDeletedTips{} } -func (m *BlackDeletedTips) String() string { return proto.CompactTextString(m) } -func (*BlackDeletedTips) ProtoMessage() {} -func (*BlackDeletedTips) Descriptor() ([]byte, []int) { - return fileDescriptor_ws_bc78a4975e7e5f46, []int{50} -} -func (m *BlackDeletedTips) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_BlackDeletedTips.Unmarshal(m, b) -} -func (m *BlackDeletedTips) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_BlackDeletedTips.Marshal(b, m, deterministic) -} -func (dst *BlackDeletedTips) XXX_Merge(src proto.Message) { - xxx_messageInfo_BlackDeletedTips.Merge(dst, src) -} -func (m *BlackDeletedTips) XXX_Size() int { - return xxx_messageInfo_BlackDeletedTips.Size(m) -} -func (m *BlackDeletedTips) XXX_DiscardUnknown() { - xxx_messageInfo_BlackDeletedTips.DiscardUnknown(m) -} - -var xxx_messageInfo_BlackDeletedTips proto.InternalMessageInfo - -func (m *BlackDeletedTips) GetFromToUserID() *FromToUserID { - if m != nil { - return m.FromToUserID - } - return nil -} - -type FriendInfoChangedTips struct { - FromToUserID *FromToUserID `protobuf:"bytes,1,opt,name=fromToUserID" json:"fromToUserID,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *FriendInfoChangedTips) Reset() { *m = FriendInfoChangedTips{} } -func (m *FriendInfoChangedTips) String() string { return proto.CompactTextString(m) } -func (*FriendInfoChangedTips) ProtoMessage() {} -func (*FriendInfoChangedTips) Descriptor() ([]byte, []int) { - return fileDescriptor_ws_bc78a4975e7e5f46, []int{51} -} -func (m *FriendInfoChangedTips) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_FriendInfoChangedTips.Unmarshal(m, b) -} -func (m *FriendInfoChangedTips) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_FriendInfoChangedTips.Marshal(b, m, deterministic) -} -func (dst *FriendInfoChangedTips) XXX_Merge(src proto.Message) { - xxx_messageInfo_FriendInfoChangedTips.Merge(dst, src) -} -func (m *FriendInfoChangedTips) XXX_Size() int { - return xxx_messageInfo_FriendInfoChangedTips.Size(m) -} -func (m *FriendInfoChangedTips) XXX_DiscardUnknown() { - xxx_messageInfo_FriendInfoChangedTips.DiscardUnknown(m) -} - -var xxx_messageInfo_FriendInfoChangedTips proto.InternalMessageInfo - -func (m *FriendInfoChangedTips) GetFromToUserID() *FromToUserID { - if m != nil { - return m.FromToUserID - } - return nil -} - -// ////////////////////user///////////////////// -type UserInfoUpdatedTips struct { - UserID string `protobuf:"bytes,1,opt,name=userID" json:"userID,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *UserInfoUpdatedTips) Reset() { *m = UserInfoUpdatedTips{} } -func (m *UserInfoUpdatedTips) String() string { return proto.CompactTextString(m) } -func (*UserInfoUpdatedTips) ProtoMessage() {} -func (*UserInfoUpdatedTips) Descriptor() ([]byte, []int) { - return fileDescriptor_ws_bc78a4975e7e5f46, []int{52} -} -func (m *UserInfoUpdatedTips) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_UserInfoUpdatedTips.Unmarshal(m, b) -} -func (m *UserInfoUpdatedTips) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_UserInfoUpdatedTips.Marshal(b, m, deterministic) -} -func (dst *UserInfoUpdatedTips) XXX_Merge(src proto.Message) { - xxx_messageInfo_UserInfoUpdatedTips.Merge(dst, src) -} -func (m *UserInfoUpdatedTips) XXX_Size() int { - return xxx_messageInfo_UserInfoUpdatedTips.Size(m) -} -func (m *UserInfoUpdatedTips) XXX_DiscardUnknown() { - xxx_messageInfo_UserInfoUpdatedTips.DiscardUnknown(m) -} - -var xxx_messageInfo_UserInfoUpdatedTips proto.InternalMessageInfo - -func (m *UserInfoUpdatedTips) GetUserID() string { - if m != nil { - return m.UserID - } - return "" -} - -// ////////////////////conversation///////////////////// -type ConversationUpdateTips struct { - UserID string `protobuf:"bytes,1,opt,name=UserID" json:"UserID,omitempty"` - ConversationIDList []string `protobuf:"bytes,2,rep,name=conversationIDList" json:"conversationIDList,omitempty"` - UpdateUnreadCountTime int64 `protobuf:"varint,3,opt,name=updateUnreadCountTime" json:"updateUnreadCountTime,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *ConversationUpdateTips) Reset() { *m = ConversationUpdateTips{} } -func (m *ConversationUpdateTips) String() string { return proto.CompactTextString(m) } -func (*ConversationUpdateTips) ProtoMessage() {} -func (*ConversationUpdateTips) Descriptor() ([]byte, []int) { - return fileDescriptor_ws_bc78a4975e7e5f46, []int{53} -} -func (m *ConversationUpdateTips) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_ConversationUpdateTips.Unmarshal(m, b) -} -func (m *ConversationUpdateTips) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_ConversationUpdateTips.Marshal(b, m, deterministic) -} -func (dst *ConversationUpdateTips) XXX_Merge(src proto.Message) { - xxx_messageInfo_ConversationUpdateTips.Merge(dst, src) -} -func (m *ConversationUpdateTips) XXX_Size() int { - return xxx_messageInfo_ConversationUpdateTips.Size(m) -} -func (m *ConversationUpdateTips) XXX_DiscardUnknown() { - xxx_messageInfo_ConversationUpdateTips.DiscardUnknown(m) -} - -var xxx_messageInfo_ConversationUpdateTips proto.InternalMessageInfo - -func (m *ConversationUpdateTips) GetUserID() string { - if m != nil { - return m.UserID - } - return "" -} - -func (m *ConversationUpdateTips) GetConversationIDList() []string { - if m != nil { - return m.ConversationIDList - } - return nil -} - -func (m *ConversationUpdateTips) GetUpdateUnreadCountTime() int64 { - if m != nil { - return m.UpdateUnreadCountTime - } - return 0 -} - -type ConversationSetPrivateTips struct { - RecvID string `protobuf:"bytes,1,opt,name=recvID" json:"recvID,omitempty"` - SendID string `protobuf:"bytes,2,opt,name=sendID" json:"sendID,omitempty"` - IsPrivate bool `protobuf:"varint,3,opt,name=isPrivate" json:"isPrivate,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *ConversationSetPrivateTips) Reset() { *m = ConversationSetPrivateTips{} } -func (m *ConversationSetPrivateTips) String() string { return proto.CompactTextString(m) } -func (*ConversationSetPrivateTips) ProtoMessage() {} -func (*ConversationSetPrivateTips) Descriptor() ([]byte, []int) { - return fileDescriptor_ws_bc78a4975e7e5f46, []int{54} -} -func (m *ConversationSetPrivateTips) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_ConversationSetPrivateTips.Unmarshal(m, b) -} -func (m *ConversationSetPrivateTips) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_ConversationSetPrivateTips.Marshal(b, m, deterministic) -} -func (dst *ConversationSetPrivateTips) XXX_Merge(src proto.Message) { - xxx_messageInfo_ConversationSetPrivateTips.Merge(dst, src) -} -func (m *ConversationSetPrivateTips) XXX_Size() int { - return xxx_messageInfo_ConversationSetPrivateTips.Size(m) -} -func (m *ConversationSetPrivateTips) XXX_DiscardUnknown() { - xxx_messageInfo_ConversationSetPrivateTips.DiscardUnknown(m) -} - -var xxx_messageInfo_ConversationSetPrivateTips proto.InternalMessageInfo - -func (m *ConversationSetPrivateTips) GetRecvID() string { - if m != nil { - return m.RecvID - } - return "" -} - -func (m *ConversationSetPrivateTips) GetSendID() string { - if m != nil { - return m.SendID - } - return "" -} - -func (m *ConversationSetPrivateTips) GetIsPrivate() bool { - if m != nil { - return m.IsPrivate - } - return false -} - -// //////////////////message/////////////////////// -type DeleteMessageTips struct { - OpUserID string `protobuf:"bytes,1,opt,name=opUserID" json:"opUserID,omitempty"` - UserID string `protobuf:"bytes,2,opt,name=userID" json:"userID,omitempty"` - SeqList []uint32 `protobuf:"varint,3,rep,packed,name=seqList" json:"seqList,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *DeleteMessageTips) Reset() { *m = DeleteMessageTips{} } -func (m *DeleteMessageTips) String() string { return proto.CompactTextString(m) } -func (*DeleteMessageTips) ProtoMessage() {} -func (*DeleteMessageTips) Descriptor() ([]byte, []int) { - return fileDescriptor_ws_bc78a4975e7e5f46, []int{55} -} -func (m *DeleteMessageTips) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_DeleteMessageTips.Unmarshal(m, b) -} -func (m *DeleteMessageTips) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_DeleteMessageTips.Marshal(b, m, deterministic) -} -func (dst *DeleteMessageTips) XXX_Merge(src proto.Message) { - xxx_messageInfo_DeleteMessageTips.Merge(dst, src) -} -func (m *DeleteMessageTips) XXX_Size() int { - return xxx_messageInfo_DeleteMessageTips.Size(m) -} -func (m *DeleteMessageTips) XXX_DiscardUnknown() { - xxx_messageInfo_DeleteMessageTips.DiscardUnknown(m) -} - -var xxx_messageInfo_DeleteMessageTips proto.InternalMessageInfo - -func (m *DeleteMessageTips) GetOpUserID() string { - if m != nil { - return m.OpUserID - } - return "" -} - -func (m *DeleteMessageTips) GetUserID() string { - if m != nil { - return m.UserID - } - return "" -} - -func (m *DeleteMessageTips) GetSeqList() []uint32 { - if m != nil { - return m.SeqList - } - return nil -} - -// /cms -type RequestPagination struct { - PageNumber int32 `protobuf:"varint,1,opt,name=pageNumber" json:"pageNumber,omitempty"` - ShowNumber int32 `protobuf:"varint,2,opt,name=showNumber" json:"showNumber,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *RequestPagination) Reset() { *m = RequestPagination{} } -func (m *RequestPagination) String() string { return proto.CompactTextString(m) } -func (*RequestPagination) ProtoMessage() {} -func (*RequestPagination) Descriptor() ([]byte, []int) { - return fileDescriptor_ws_bc78a4975e7e5f46, []int{56} -} -func (m *RequestPagination) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_RequestPagination.Unmarshal(m, b) -} -func (m *RequestPagination) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_RequestPagination.Marshal(b, m, deterministic) -} -func (dst *RequestPagination) XXX_Merge(src proto.Message) { - xxx_messageInfo_RequestPagination.Merge(dst, src) -} -func (m *RequestPagination) XXX_Size() int { - return xxx_messageInfo_RequestPagination.Size(m) -} -func (m *RequestPagination) XXX_DiscardUnknown() { - xxx_messageInfo_RequestPagination.DiscardUnknown(m) -} - -var xxx_messageInfo_RequestPagination proto.InternalMessageInfo - -func (m *RequestPagination) GetPageNumber() int32 { - if m != nil { - return m.PageNumber - } - return 0 -} - -func (m *RequestPagination) GetShowNumber() int32 { - if m != nil { - return m.ShowNumber - } - return 0 -} - -type ResponsePagination struct { - CurrentPage int32 `protobuf:"varint,5,opt,name=CurrentPage" json:"CurrentPage,omitempty"` - ShowNumber int32 `protobuf:"varint,6,opt,name=ShowNumber" json:"ShowNumber,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *ResponsePagination) Reset() { *m = ResponsePagination{} } -func (m *ResponsePagination) String() string { return proto.CompactTextString(m) } -func (*ResponsePagination) ProtoMessage() {} -func (*ResponsePagination) Descriptor() ([]byte, []int) { - return fileDescriptor_ws_bc78a4975e7e5f46, []int{57} -} -func (m *ResponsePagination) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_ResponsePagination.Unmarshal(m, b) -} -func (m *ResponsePagination) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_ResponsePagination.Marshal(b, m, deterministic) -} -func (dst *ResponsePagination) XXX_Merge(src proto.Message) { - xxx_messageInfo_ResponsePagination.Merge(dst, src) -} -func (m *ResponsePagination) XXX_Size() int { - return xxx_messageInfo_ResponsePagination.Size(m) -} -func (m *ResponsePagination) XXX_DiscardUnknown() { - xxx_messageInfo_ResponsePagination.DiscardUnknown(m) -} - -var xxx_messageInfo_ResponsePagination proto.InternalMessageInfo - -func (m *ResponsePagination) GetCurrentPage() int32 { - if m != nil { - return m.CurrentPage - } - return 0 -} - -func (m *ResponsePagination) GetShowNumber() int32 { - if m != nil { - return m.ShowNumber - } - return 0 -} - -// /////////////////signal////////////// -type SignalReq struct { - // Types that are valid to be assigned to Payload: - // *SignalReq_Invite - // *SignalReq_InviteInGroup - // *SignalReq_Cancel - // *SignalReq_Accept - // *SignalReq_HungUp - // *SignalReq_Reject - // *SignalReq_GetRoomByGroupID - // *SignalReq_OnRoomParticipantConnectedReq - // *SignalReq_OnRoomParticipantDisconnectedReq - // *SignalReq_GetTokenByRoomID - Payload isSignalReq_Payload `protobuf_oneof:"payload"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *SignalReq) Reset() { *m = SignalReq{} } -func (m *SignalReq) String() string { return proto.CompactTextString(m) } -func (*SignalReq) ProtoMessage() {} -func (*SignalReq) Descriptor() ([]byte, []int) { - return fileDescriptor_ws_bc78a4975e7e5f46, []int{58} -} -func (m *SignalReq) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_SignalReq.Unmarshal(m, b) -} -func (m *SignalReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_SignalReq.Marshal(b, m, deterministic) -} -func (dst *SignalReq) XXX_Merge(src proto.Message) { - xxx_messageInfo_SignalReq.Merge(dst, src) -} -func (m *SignalReq) XXX_Size() int { - return xxx_messageInfo_SignalReq.Size(m) -} -func (m *SignalReq) XXX_DiscardUnknown() { - xxx_messageInfo_SignalReq.DiscardUnknown(m) -} - -var xxx_messageInfo_SignalReq proto.InternalMessageInfo - -type isSignalReq_Payload interface { - isSignalReq_Payload() -} - -type SignalReq_Invite struct { - Invite *SignalInviteReq `protobuf:"bytes,1,opt,name=invite,oneof"` -} -type SignalReq_InviteInGroup struct { - InviteInGroup *SignalInviteInGroupReq `protobuf:"bytes,2,opt,name=inviteInGroup,oneof"` -} -type SignalReq_Cancel struct { - Cancel *SignalCancelReq `protobuf:"bytes,3,opt,name=cancel,oneof"` -} -type SignalReq_Accept struct { - Accept *SignalAcceptReq `protobuf:"bytes,4,opt,name=accept,oneof"` -} -type SignalReq_HungUp struct { - HungUp *SignalHungUpReq `protobuf:"bytes,5,opt,name=hungUp,oneof"` -} -type SignalReq_Reject struct { - Reject *SignalRejectReq `protobuf:"bytes,6,opt,name=reject,oneof"` -} -type SignalReq_GetRoomByGroupID struct { - GetRoomByGroupID *SignalGetRoomByGroupIDReq `protobuf:"bytes,7,opt,name=getRoomByGroupID,oneof"` -} -type SignalReq_OnRoomParticipantConnectedReq struct { - OnRoomParticipantConnectedReq *SignalOnRoomParticipantConnectedReq `protobuf:"bytes,8,opt,name=onRoomParticipantConnectedReq,oneof"` -} -type SignalReq_OnRoomParticipantDisconnectedReq struct { - OnRoomParticipantDisconnectedReq *SignalOnRoomParticipantDisconnectedReq `protobuf:"bytes,9,opt,name=onRoomParticipantDisconnectedReq,oneof"` -} -type SignalReq_GetTokenByRoomID struct { - GetTokenByRoomID *SignalGetTokenByRoomIDReq `protobuf:"bytes,10,opt,name=getTokenByRoomID,oneof"` -} - -func (*SignalReq_Invite) isSignalReq_Payload() {} -func (*SignalReq_InviteInGroup) isSignalReq_Payload() {} -func (*SignalReq_Cancel) isSignalReq_Payload() {} -func (*SignalReq_Accept) isSignalReq_Payload() {} -func (*SignalReq_HungUp) isSignalReq_Payload() {} -func (*SignalReq_Reject) isSignalReq_Payload() {} -func (*SignalReq_GetRoomByGroupID) isSignalReq_Payload() {} -func (*SignalReq_OnRoomParticipantConnectedReq) isSignalReq_Payload() {} -func (*SignalReq_OnRoomParticipantDisconnectedReq) isSignalReq_Payload() {} -func (*SignalReq_GetTokenByRoomID) isSignalReq_Payload() {} - -func (m *SignalReq) GetPayload() isSignalReq_Payload { - if m != nil { - return m.Payload - } - return nil -} - -func (m *SignalReq) GetInvite() *SignalInviteReq { - if x, ok := m.GetPayload().(*SignalReq_Invite); ok { - return x.Invite - } - return nil -} - -func (m *SignalReq) GetInviteInGroup() *SignalInviteInGroupReq { - if x, ok := m.GetPayload().(*SignalReq_InviteInGroup); ok { - return x.InviteInGroup - } - return nil -} - -func (m *SignalReq) GetCancel() *SignalCancelReq { - if x, ok := m.GetPayload().(*SignalReq_Cancel); ok { - return x.Cancel - } - return nil -} - -func (m *SignalReq) GetAccept() *SignalAcceptReq { - if x, ok := m.GetPayload().(*SignalReq_Accept); ok { - return x.Accept - } - return nil -} - -func (m *SignalReq) GetHungUp() *SignalHungUpReq { - if x, ok := m.GetPayload().(*SignalReq_HungUp); ok { - return x.HungUp - } - return nil -} - -func (m *SignalReq) GetReject() *SignalRejectReq { - if x, ok := m.GetPayload().(*SignalReq_Reject); ok { - return x.Reject - } - return nil -} - -func (m *SignalReq) GetGetRoomByGroupID() *SignalGetRoomByGroupIDReq { - if x, ok := m.GetPayload().(*SignalReq_GetRoomByGroupID); ok { - return x.GetRoomByGroupID - } - return nil -} - -func (m *SignalReq) GetOnRoomParticipantConnectedReq() *SignalOnRoomParticipantConnectedReq { - if x, ok := m.GetPayload().(*SignalReq_OnRoomParticipantConnectedReq); ok { - return x.OnRoomParticipantConnectedReq - } - return nil -} - -func (m *SignalReq) GetOnRoomParticipantDisconnectedReq() *SignalOnRoomParticipantDisconnectedReq { - if x, ok := m.GetPayload().(*SignalReq_OnRoomParticipantDisconnectedReq); ok { - return x.OnRoomParticipantDisconnectedReq - } - return nil -} - -func (m *SignalReq) GetGetTokenByRoomID() *SignalGetTokenByRoomIDReq { - if x, ok := m.GetPayload().(*SignalReq_GetTokenByRoomID); ok { - return x.GetTokenByRoomID - } - return nil -} - -// XXX_OneofFuncs is for the internal use of the proto package. -func (*SignalReq) XXX_OneofFuncs() (func(msg proto.Message, b *proto.Buffer) error, func(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error), func(msg proto.Message) (n int), []any) { - return _SignalReq_OneofMarshaler, _SignalReq_OneofUnmarshaler, _SignalReq_OneofSizer, []any{ - (*SignalReq_Invite)(nil), - (*SignalReq_InviteInGroup)(nil), - (*SignalReq_Cancel)(nil), - (*SignalReq_Accept)(nil), - (*SignalReq_HungUp)(nil), - (*SignalReq_Reject)(nil), - (*SignalReq_GetRoomByGroupID)(nil), - (*SignalReq_OnRoomParticipantConnectedReq)(nil), - (*SignalReq_OnRoomParticipantDisconnectedReq)(nil), - (*SignalReq_GetTokenByRoomID)(nil), - } -} - -func _SignalReq_OneofMarshaler(msg proto.Message, b *proto.Buffer) error { - m := msg.(*SignalReq) - // payload - switch x := m.Payload.(type) { - case *SignalReq_Invite: - b.EncodeVarint(1<<3 | proto.WireBytes) - if err := b.EncodeMessage(x.Invite); err != nil { - return err - } - case *SignalReq_InviteInGroup: - b.EncodeVarint(2<<3 | proto.WireBytes) - if err := b.EncodeMessage(x.InviteInGroup); err != nil { - return err - } - case *SignalReq_Cancel: - b.EncodeVarint(3<<3 | proto.WireBytes) - if err := b.EncodeMessage(x.Cancel); err != nil { - return err - } - case *SignalReq_Accept: - b.EncodeVarint(4<<3 | proto.WireBytes) - if err := b.EncodeMessage(x.Accept); err != nil { - return err - } - case *SignalReq_HungUp: - b.EncodeVarint(5<<3 | proto.WireBytes) - if err := b.EncodeMessage(x.HungUp); err != nil { - return err - } - case *SignalReq_Reject: - b.EncodeVarint(6<<3 | proto.WireBytes) - if err := b.EncodeMessage(x.Reject); err != nil { - return err - } - case *SignalReq_GetRoomByGroupID: - b.EncodeVarint(7<<3 | proto.WireBytes) - if err := b.EncodeMessage(x.GetRoomByGroupID); err != nil { - return err - } - case *SignalReq_OnRoomParticipantConnectedReq: - b.EncodeVarint(8<<3 | proto.WireBytes) - if err := b.EncodeMessage(x.OnRoomParticipantConnectedReq); err != nil { - return err - } - case *SignalReq_OnRoomParticipantDisconnectedReq: - b.EncodeVarint(9<<3 | proto.WireBytes) - if err := b.EncodeMessage(x.OnRoomParticipantDisconnectedReq); err != nil { - return err - } - case *SignalReq_GetTokenByRoomID: - b.EncodeVarint(10<<3 | proto.WireBytes) - if err := b.EncodeMessage(x.GetTokenByRoomID); err != nil { - return err - } - case nil: - default: - return fmt.Errorf("SignalReq.Payload has unexpected type %T", x) - } - return nil -} - -func _SignalReq_OneofUnmarshaler(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error) { - m := msg.(*SignalReq) - switch tag { - case 1: // payload.invite - if wire != proto.WireBytes { - return true, proto.ErrInternalBadWireType - } - msg := new(SignalInviteReq) - err := b.DecodeMessage(msg) - m.Payload = &SignalReq_Invite{msg} - return true, err - case 2: // payload.inviteInGroup - if wire != proto.WireBytes { - return true, proto.ErrInternalBadWireType - } - msg := new(SignalInviteInGroupReq) - err := b.DecodeMessage(msg) - m.Payload = &SignalReq_InviteInGroup{msg} - return true, err - case 3: // payload.cancel - if wire != proto.WireBytes { - return true, proto.ErrInternalBadWireType - } - msg := new(SignalCancelReq) - err := b.DecodeMessage(msg) - m.Payload = &SignalReq_Cancel{msg} - return true, err - case 4: // payload.accept - if wire != proto.WireBytes { - return true, proto.ErrInternalBadWireType - } - msg := new(SignalAcceptReq) - err := b.DecodeMessage(msg) - m.Payload = &SignalReq_Accept{msg} - return true, err - case 5: // payload.hungUp - if wire != proto.WireBytes { - return true, proto.ErrInternalBadWireType - } - msg := new(SignalHungUpReq) - err := b.DecodeMessage(msg) - m.Payload = &SignalReq_HungUp{msg} - return true, err - case 6: // payload.reject - if wire != proto.WireBytes { - return true, proto.ErrInternalBadWireType - } - msg := new(SignalRejectReq) - err := b.DecodeMessage(msg) - m.Payload = &SignalReq_Reject{msg} - return true, err - case 7: // payload.getRoomByGroupID - if wire != proto.WireBytes { - return true, proto.ErrInternalBadWireType - } - msg := new(SignalGetRoomByGroupIDReq) - err := b.DecodeMessage(msg) - m.Payload = &SignalReq_GetRoomByGroupID{msg} - return true, err - case 8: // payload.onRoomParticipantConnectedReq - if wire != proto.WireBytes { - return true, proto.ErrInternalBadWireType - } - msg := new(SignalOnRoomParticipantConnectedReq) - err := b.DecodeMessage(msg) - m.Payload = &SignalReq_OnRoomParticipantConnectedReq{msg} - return true, err - case 9: // payload.onRoomParticipantDisconnectedReq - if wire != proto.WireBytes { - return true, proto.ErrInternalBadWireType - } - msg := new(SignalOnRoomParticipantDisconnectedReq) - err := b.DecodeMessage(msg) - m.Payload = &SignalReq_OnRoomParticipantDisconnectedReq{msg} - return true, err - case 10: // payload.getTokenByRoomID - if wire != proto.WireBytes { - return true, proto.ErrInternalBadWireType - } - msg := new(SignalGetTokenByRoomIDReq) - err := b.DecodeMessage(msg) - m.Payload = &SignalReq_GetTokenByRoomID{msg} - return true, err - default: - return false, nil - } -} - -func _SignalReq_OneofSizer(msg proto.Message) (n int) { - m := msg.(*SignalReq) - // payload - switch x := m.Payload.(type) { - case *SignalReq_Invite: - s := proto.Size(x.Invite) - n += 1 // tag and wire - n += proto.SizeVarint(uint64(s)) - n += s - case *SignalReq_InviteInGroup: - s := proto.Size(x.InviteInGroup) - n += 1 // tag and wire - n += proto.SizeVarint(uint64(s)) - n += s - case *SignalReq_Cancel: - s := proto.Size(x.Cancel) - n += 1 // tag and wire - n += proto.SizeVarint(uint64(s)) - n += s - case *SignalReq_Accept: - s := proto.Size(x.Accept) - n += 1 // tag and wire - n += proto.SizeVarint(uint64(s)) - n += s - case *SignalReq_HungUp: - s := proto.Size(x.HungUp) - n += 1 // tag and wire - n += proto.SizeVarint(uint64(s)) - n += s - case *SignalReq_Reject: - s := proto.Size(x.Reject) - n += 1 // tag and wire - n += proto.SizeVarint(uint64(s)) - n += s - case *SignalReq_GetRoomByGroupID: - s := proto.Size(x.GetRoomByGroupID) - n += 1 // tag and wire - n += proto.SizeVarint(uint64(s)) - n += s - case *SignalReq_OnRoomParticipantConnectedReq: - s := proto.Size(x.OnRoomParticipantConnectedReq) - n += 1 // tag and wire - n += proto.SizeVarint(uint64(s)) - n += s - case *SignalReq_OnRoomParticipantDisconnectedReq: - s := proto.Size(x.OnRoomParticipantDisconnectedReq) - n += 1 // tag and wire - n += proto.SizeVarint(uint64(s)) - n += s - case *SignalReq_GetTokenByRoomID: - s := proto.Size(x.GetTokenByRoomID) - n += 1 // tag and wire - n += proto.SizeVarint(uint64(s)) - n += s - case nil: - default: - panic(fmt.Sprintf("proto: unexpected type %T in oneof", x)) - } - return n -} - -type SignalResp struct { - // Types that are valid to be assigned to Payload: - // *SignalResp_Invite - // *SignalResp_InviteInGroup - // *SignalResp_Cancel - // *SignalResp_Accept - // *SignalResp_HungUp - // *SignalResp_Reject - // *SignalResp_GetRoomByGroupID - // *SignalResp_GetTokenByRoomID - Payload isSignalResp_Payload `protobuf_oneof:"payload"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *SignalResp) Reset() { *m = SignalResp{} } -func (m *SignalResp) String() string { return proto.CompactTextString(m) } -func (*SignalResp) ProtoMessage() {} -func (*SignalResp) Descriptor() ([]byte, []int) { - return fileDescriptor_ws_bc78a4975e7e5f46, []int{59} -} -func (m *SignalResp) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_SignalResp.Unmarshal(m, b) -} -func (m *SignalResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_SignalResp.Marshal(b, m, deterministic) -} -func (dst *SignalResp) XXX_Merge(src proto.Message) { - xxx_messageInfo_SignalResp.Merge(dst, src) -} -func (m *SignalResp) XXX_Size() int { - return xxx_messageInfo_SignalResp.Size(m) -} -func (m *SignalResp) XXX_DiscardUnknown() { - xxx_messageInfo_SignalResp.DiscardUnknown(m) -} - -var xxx_messageInfo_SignalResp proto.InternalMessageInfo - -type isSignalResp_Payload interface { - isSignalResp_Payload() -} - -type SignalResp_Invite struct { - Invite *SignalInviteReply `protobuf:"bytes,1,opt,name=invite,oneof"` -} -type SignalResp_InviteInGroup struct { - InviteInGroup *SignalInviteInGroupReply `protobuf:"bytes,2,opt,name=inviteInGroup,oneof"` -} -type SignalResp_Cancel struct { - Cancel *SignalCancelReply `protobuf:"bytes,3,opt,name=cancel,oneof"` -} -type SignalResp_Accept struct { - Accept *SignalAcceptReply `protobuf:"bytes,4,opt,name=accept,oneof"` -} -type SignalResp_HungUp struct { - HungUp *SignalHungUpReply `protobuf:"bytes,5,opt,name=hungUp,oneof"` -} -type SignalResp_Reject struct { - Reject *SignalRejectReply `protobuf:"bytes,6,opt,name=reject,oneof"` -} -type SignalResp_GetRoomByGroupID struct { - GetRoomByGroupID *SignalGetRoomByGroupIDReply `protobuf:"bytes,7,opt,name=getRoomByGroupID,oneof"` -} -type SignalResp_GetTokenByRoomID struct { - GetTokenByRoomID *SignalGetTokenByRoomIDReply `protobuf:"bytes,8,opt,name=getTokenByRoomID,oneof"` -} - -func (*SignalResp_Invite) isSignalResp_Payload() {} -func (*SignalResp_InviteInGroup) isSignalResp_Payload() {} -func (*SignalResp_Cancel) isSignalResp_Payload() {} -func (*SignalResp_Accept) isSignalResp_Payload() {} -func (*SignalResp_HungUp) isSignalResp_Payload() {} -func (*SignalResp_Reject) isSignalResp_Payload() {} -func (*SignalResp_GetRoomByGroupID) isSignalResp_Payload() {} -func (*SignalResp_GetTokenByRoomID) isSignalResp_Payload() {} - -func (m *SignalResp) GetPayload() isSignalResp_Payload { - if m != nil { - return m.Payload - } - return nil -} - -func (m *SignalResp) GetInvite() *SignalInviteReply { - if x, ok := m.GetPayload().(*SignalResp_Invite); ok { - return x.Invite - } - return nil -} - -func (m *SignalResp) GetInviteInGroup() *SignalInviteInGroupReply { - if x, ok := m.GetPayload().(*SignalResp_InviteInGroup); ok { - return x.InviteInGroup - } - return nil -} - -func (m *SignalResp) GetCancel() *SignalCancelReply { - if x, ok := m.GetPayload().(*SignalResp_Cancel); ok { - return x.Cancel - } - return nil -} - -func (m *SignalResp) GetAccept() *SignalAcceptReply { - if x, ok := m.GetPayload().(*SignalResp_Accept); ok { - return x.Accept - } - return nil -} - -func (m *SignalResp) GetHungUp() *SignalHungUpReply { - if x, ok := m.GetPayload().(*SignalResp_HungUp); ok { - return x.HungUp - } - return nil -} - -func (m *SignalResp) GetReject() *SignalRejectReply { - if x, ok := m.GetPayload().(*SignalResp_Reject); ok { - return x.Reject - } - return nil -} - -func (m *SignalResp) GetGetRoomByGroupID() *SignalGetRoomByGroupIDReply { - if x, ok := m.GetPayload().(*SignalResp_GetRoomByGroupID); ok { - return x.GetRoomByGroupID - } - return nil -} - -func (m *SignalResp) GetGetTokenByRoomID() *SignalGetTokenByRoomIDReply { - if x, ok := m.GetPayload().(*SignalResp_GetTokenByRoomID); ok { - return x.GetTokenByRoomID - } - return nil -} - -// XXX_OneofFuncs is for the internal use of the proto package. -func (*SignalResp) XXX_OneofFuncs() (func(msg proto.Message, b *proto.Buffer) error, func(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error), func(msg proto.Message) (n int), []any) { - return _SignalResp_OneofMarshaler, _SignalResp_OneofUnmarshaler, _SignalResp_OneofSizer, []any{ - (*SignalResp_Invite)(nil), - (*SignalResp_InviteInGroup)(nil), - (*SignalResp_Cancel)(nil), - (*SignalResp_Accept)(nil), - (*SignalResp_HungUp)(nil), - (*SignalResp_Reject)(nil), - (*SignalResp_GetRoomByGroupID)(nil), - (*SignalResp_GetTokenByRoomID)(nil), - } -} - -func _SignalResp_OneofMarshaler(msg proto.Message, b *proto.Buffer) error { - m := msg.(*SignalResp) - // payload - switch x := m.Payload.(type) { - case *SignalResp_Invite: - b.EncodeVarint(1<<3 | proto.WireBytes) - if err := b.EncodeMessage(x.Invite); err != nil { - return err - } - case *SignalResp_InviteInGroup: - b.EncodeVarint(2<<3 | proto.WireBytes) - if err := b.EncodeMessage(x.InviteInGroup); err != nil { - return err - } - case *SignalResp_Cancel: - b.EncodeVarint(3<<3 | proto.WireBytes) - if err := b.EncodeMessage(x.Cancel); err != nil { - return err - } - case *SignalResp_Accept: - b.EncodeVarint(4<<3 | proto.WireBytes) - if err := b.EncodeMessage(x.Accept); err != nil { - return err - } - case *SignalResp_HungUp: - b.EncodeVarint(5<<3 | proto.WireBytes) - if err := b.EncodeMessage(x.HungUp); err != nil { - return err - } - case *SignalResp_Reject: - b.EncodeVarint(6<<3 | proto.WireBytes) - if err := b.EncodeMessage(x.Reject); err != nil { - return err - } - case *SignalResp_GetRoomByGroupID: - b.EncodeVarint(7<<3 | proto.WireBytes) - if err := b.EncodeMessage(x.GetRoomByGroupID); err != nil { - return err - } - case *SignalResp_GetTokenByRoomID: - b.EncodeVarint(8<<3 | proto.WireBytes) - if err := b.EncodeMessage(x.GetTokenByRoomID); err != nil { - return err - } - case nil: - default: - return fmt.Errorf("SignalResp.Payload has unexpected type %T", x) - } - return nil -} - -func _SignalResp_OneofUnmarshaler(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error) { - m := msg.(*SignalResp) - switch tag { - case 1: // payload.invite - if wire != proto.WireBytes { - return true, proto.ErrInternalBadWireType - } - msg := new(SignalInviteReply) - err := b.DecodeMessage(msg) - m.Payload = &SignalResp_Invite{msg} - return true, err - case 2: // payload.inviteInGroup - if wire != proto.WireBytes { - return true, proto.ErrInternalBadWireType - } - msg := new(SignalInviteInGroupReply) - err := b.DecodeMessage(msg) - m.Payload = &SignalResp_InviteInGroup{msg} - return true, err - case 3: // payload.cancel - if wire != proto.WireBytes { - return true, proto.ErrInternalBadWireType - } - msg := new(SignalCancelReply) - err := b.DecodeMessage(msg) - m.Payload = &SignalResp_Cancel{msg} - return true, err - case 4: // payload.accept - if wire != proto.WireBytes { - return true, proto.ErrInternalBadWireType - } - msg := new(SignalAcceptReply) - err := b.DecodeMessage(msg) - m.Payload = &SignalResp_Accept{msg} - return true, err - case 5: // payload.hungUp - if wire != proto.WireBytes { - return true, proto.ErrInternalBadWireType - } - msg := new(SignalHungUpReply) - err := b.DecodeMessage(msg) - m.Payload = &SignalResp_HungUp{msg} - return true, err - case 6: // payload.reject - if wire != proto.WireBytes { - return true, proto.ErrInternalBadWireType - } - msg := new(SignalRejectReply) - err := b.DecodeMessage(msg) - m.Payload = &SignalResp_Reject{msg} - return true, err - case 7: // payload.getRoomByGroupID - if wire != proto.WireBytes { - return true, proto.ErrInternalBadWireType - } - msg := new(SignalGetRoomByGroupIDReply) - err := b.DecodeMessage(msg) - m.Payload = &SignalResp_GetRoomByGroupID{msg} - return true, err - case 8: // payload.getTokenByRoomID - if wire != proto.WireBytes { - return true, proto.ErrInternalBadWireType - } - msg := new(SignalGetTokenByRoomIDReply) - err := b.DecodeMessage(msg) - m.Payload = &SignalResp_GetTokenByRoomID{msg} - return true, err - default: - return false, nil - } -} - -func _SignalResp_OneofSizer(msg proto.Message) (n int) { - m := msg.(*SignalResp) - // payload - switch x := m.Payload.(type) { - case *SignalResp_Invite: - s := proto.Size(x.Invite) - n += 1 // tag and wire - n += proto.SizeVarint(uint64(s)) - n += s - case *SignalResp_InviteInGroup: - s := proto.Size(x.InviteInGroup) - n += 1 // tag and wire - n += proto.SizeVarint(uint64(s)) - n += s - case *SignalResp_Cancel: - s := proto.Size(x.Cancel) - n += 1 // tag and wire - n += proto.SizeVarint(uint64(s)) - n += s - case *SignalResp_Accept: - s := proto.Size(x.Accept) - n += 1 // tag and wire - n += proto.SizeVarint(uint64(s)) - n += s - case *SignalResp_HungUp: - s := proto.Size(x.HungUp) - n += 1 // tag and wire - n += proto.SizeVarint(uint64(s)) - n += s - case *SignalResp_Reject: - s := proto.Size(x.Reject) - n += 1 // tag and wire - n += proto.SizeVarint(uint64(s)) - n += s - case *SignalResp_GetRoomByGroupID: - s := proto.Size(x.GetRoomByGroupID) - n += 1 // tag and wire - n += proto.SizeVarint(uint64(s)) - n += s - case *SignalResp_GetTokenByRoomID: - s := proto.Size(x.GetTokenByRoomID) - n += 1 // tag and wire - n += proto.SizeVarint(uint64(s)) - n += s - case nil: - default: - panic(fmt.Sprintf("proto: unexpected type %T in oneof", x)) - } - return n -} - -type InvitationInfo struct { - InviterUserID string `protobuf:"bytes,1,opt,name=inviterUserID" json:"inviterUserID,omitempty"` - InviteeUserIDList []string `protobuf:"bytes,2,rep,name=inviteeUserIDList" json:"inviteeUserIDList,omitempty"` - CustomData string `protobuf:"bytes,3,opt,name=customData" json:"customData,omitempty"` - GroupID string `protobuf:"bytes,4,opt,name=groupID" json:"groupID,omitempty"` - RoomID string `protobuf:"bytes,5,opt,name=roomID" json:"roomID,omitempty"` - Timeout int32 `protobuf:"varint,6,opt,name=timeout" json:"timeout,omitempty"` - MediaType string `protobuf:"bytes,7,opt,name=mediaType" json:"mediaType,omitempty"` - PlatformID int32 `protobuf:"varint,8,opt,name=platformID" json:"platformID,omitempty"` - SessionType int32 `protobuf:"varint,9,opt,name=sessionType" json:"sessionType,omitempty"` - InitiateTime int32 `protobuf:"varint,10,opt,name=initiateTime" json:"initiateTime,omitempty"` - BusyLineUserIDList []string `protobuf:"bytes,11,rep,name=busyLineUserIDList" json:"busyLineUserIDList,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *InvitationInfo) Reset() { *m = InvitationInfo{} } -func (m *InvitationInfo) String() string { return proto.CompactTextString(m) } -func (*InvitationInfo) ProtoMessage() {} -func (*InvitationInfo) Descriptor() ([]byte, []int) { - return fileDescriptor_ws_bc78a4975e7e5f46, []int{60} -} -func (m *InvitationInfo) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_InvitationInfo.Unmarshal(m, b) -} -func (m *InvitationInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_InvitationInfo.Marshal(b, m, deterministic) -} -func (dst *InvitationInfo) XXX_Merge(src proto.Message) { - xxx_messageInfo_InvitationInfo.Merge(dst, src) -} -func (m *InvitationInfo) XXX_Size() int { - return xxx_messageInfo_InvitationInfo.Size(m) -} -func (m *InvitationInfo) XXX_DiscardUnknown() { - xxx_messageInfo_InvitationInfo.DiscardUnknown(m) -} - -var xxx_messageInfo_InvitationInfo proto.InternalMessageInfo - -func (m *InvitationInfo) GetInviterUserID() string { - if m != nil { - return m.InviterUserID - } - return "" -} - -func (m *InvitationInfo) GetInviteeUserIDList() []string { - if m != nil { - return m.InviteeUserIDList - } - return nil -} - -func (m *InvitationInfo) GetCustomData() string { - if m != nil { - return m.CustomData - } - return "" -} - -func (m *InvitationInfo) GetGroupID() string { - if m != nil { - return m.GroupID - } - return "" -} - -func (m *InvitationInfo) GetRoomID() string { - if m != nil { - return m.RoomID - } - return "" -} - -func (m *InvitationInfo) GetTimeout() int32 { - if m != nil { - return m.Timeout - } - return 0 -} - -func (m *InvitationInfo) GetMediaType() string { - if m != nil { - return m.MediaType - } - return "" -} - -func (m *InvitationInfo) GetPlatformID() int32 { - if m != nil { - return m.PlatformID - } - return 0 -} - -func (m *InvitationInfo) GetSessionType() int32 { - if m != nil { - return m.SessionType - } - return 0 -} - -func (m *InvitationInfo) GetInitiateTime() int32 { - if m != nil { - return m.InitiateTime - } - return 0 -} - -func (m *InvitationInfo) GetBusyLineUserIDList() []string { - if m != nil { - return m.BusyLineUserIDList - } - return nil -} - -type ParticipantMetaData struct { - GroupInfo *GroupInfo `protobuf:"bytes,1,opt,name=groupInfo" json:"groupInfo,omitempty"` - GroupMemberInfo *GroupMemberFullInfo `protobuf:"bytes,2,opt,name=groupMemberInfo" json:"groupMemberInfo,omitempty"` - UserInfo *PublicUserInfo `protobuf:"bytes,3,opt,name=userInfo" json:"userInfo,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *ParticipantMetaData) Reset() { *m = ParticipantMetaData{} } -func (m *ParticipantMetaData) String() string { return proto.CompactTextString(m) } -func (*ParticipantMetaData) ProtoMessage() {} -func (*ParticipantMetaData) Descriptor() ([]byte, []int) { - return fileDescriptor_ws_bc78a4975e7e5f46, []int{61} -} -func (m *ParticipantMetaData) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_ParticipantMetaData.Unmarshal(m, b) -} -func (m *ParticipantMetaData) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_ParticipantMetaData.Marshal(b, m, deterministic) -} -func (dst *ParticipantMetaData) XXX_Merge(src proto.Message) { - xxx_messageInfo_ParticipantMetaData.Merge(dst, src) -} -func (m *ParticipantMetaData) XXX_Size() int { - return xxx_messageInfo_ParticipantMetaData.Size(m) -} -func (m *ParticipantMetaData) XXX_DiscardUnknown() { - xxx_messageInfo_ParticipantMetaData.DiscardUnknown(m) -} - -var xxx_messageInfo_ParticipantMetaData proto.InternalMessageInfo - -func (m *ParticipantMetaData) GetGroupInfo() *GroupInfo { - if m != nil { - return m.GroupInfo - } - return nil -} - -func (m *ParticipantMetaData) GetGroupMemberInfo() *GroupMemberFullInfo { - if m != nil { - return m.GroupMemberInfo - } - return nil -} - -func (m *ParticipantMetaData) GetUserInfo() *PublicUserInfo { - if m != nil { - return m.UserInfo - } - return nil -} - -type SignalInviteReq struct { - OpUserID string `protobuf:"bytes,1,opt,name=opUserID" json:"opUserID,omitempty"` - Invitation *InvitationInfo `protobuf:"bytes,2,opt,name=invitation" json:"invitation,omitempty"` - OfflinePushInfo *OfflinePushInfo `protobuf:"bytes,3,opt,name=offlinePushInfo" json:"offlinePushInfo,omitempty"` - Participant *ParticipantMetaData `protobuf:"bytes,4,opt,name=participant" json:"participant,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *SignalInviteReq) Reset() { *m = SignalInviteReq{} } -func (m *SignalInviteReq) String() string { return proto.CompactTextString(m) } -func (*SignalInviteReq) ProtoMessage() {} -func (*SignalInviteReq) Descriptor() ([]byte, []int) { - return fileDescriptor_ws_bc78a4975e7e5f46, []int{62} -} -func (m *SignalInviteReq) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_SignalInviteReq.Unmarshal(m, b) -} -func (m *SignalInviteReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_SignalInviteReq.Marshal(b, m, deterministic) -} -func (dst *SignalInviteReq) XXX_Merge(src proto.Message) { - xxx_messageInfo_SignalInviteReq.Merge(dst, src) -} -func (m *SignalInviteReq) XXX_Size() int { - return xxx_messageInfo_SignalInviteReq.Size(m) -} -func (m *SignalInviteReq) XXX_DiscardUnknown() { - xxx_messageInfo_SignalInviteReq.DiscardUnknown(m) -} - -var xxx_messageInfo_SignalInviteReq proto.InternalMessageInfo - -func (m *SignalInviteReq) GetOpUserID() string { - if m != nil { - return m.OpUserID - } - return "" -} - -func (m *SignalInviteReq) GetInvitation() *InvitationInfo { - if m != nil { - return m.Invitation - } - return nil -} - -func (m *SignalInviteReq) GetOfflinePushInfo() *OfflinePushInfo { - if m != nil { - return m.OfflinePushInfo - } - return nil -} - -func (m *SignalInviteReq) GetParticipant() *ParticipantMetaData { - if m != nil { - return m.Participant - } - return nil -} - -type SignalInviteReply struct { - Token string `protobuf:"bytes,1,opt,name=token" json:"token,omitempty"` - RoomID string `protobuf:"bytes,2,opt,name=roomID" json:"roomID,omitempty"` - LiveURL string `protobuf:"bytes,3,opt,name=liveURL" json:"liveURL,omitempty"` - BusyLineUserIDList []string `protobuf:"bytes,4,rep,name=busyLineUserIDList" json:"busyLineUserIDList,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *SignalInviteReply) Reset() { *m = SignalInviteReply{} } -func (m *SignalInviteReply) String() string { return proto.CompactTextString(m) } -func (*SignalInviteReply) ProtoMessage() {} -func (*SignalInviteReply) Descriptor() ([]byte, []int) { - return fileDescriptor_ws_bc78a4975e7e5f46, []int{63} -} -func (m *SignalInviteReply) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_SignalInviteReply.Unmarshal(m, b) -} -func (m *SignalInviteReply) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_SignalInviteReply.Marshal(b, m, deterministic) -} -func (dst *SignalInviteReply) XXX_Merge(src proto.Message) { - xxx_messageInfo_SignalInviteReply.Merge(dst, src) -} -func (m *SignalInviteReply) XXX_Size() int { - return xxx_messageInfo_SignalInviteReply.Size(m) -} -func (m *SignalInviteReply) XXX_DiscardUnknown() { - xxx_messageInfo_SignalInviteReply.DiscardUnknown(m) -} - -var xxx_messageInfo_SignalInviteReply proto.InternalMessageInfo - -func (m *SignalInviteReply) GetToken() string { - if m != nil { - return m.Token - } - return "" -} - -func (m *SignalInviteReply) GetRoomID() string { - if m != nil { - return m.RoomID - } - return "" -} - -func (m *SignalInviteReply) GetLiveURL() string { - if m != nil { - return m.LiveURL - } - return "" -} - -func (m *SignalInviteReply) GetBusyLineUserIDList() []string { - if m != nil { - return m.BusyLineUserIDList - } - return nil -} - -type SignalInviteInGroupReq struct { - OpUserID string `protobuf:"bytes,1,opt,name=opUserID" json:"opUserID,omitempty"` - Invitation *InvitationInfo `protobuf:"bytes,2,opt,name=invitation" json:"invitation,omitempty"` - OfflinePushInfo *OfflinePushInfo `protobuf:"bytes,3,opt,name=offlinePushInfo" json:"offlinePushInfo,omitempty"` - Participant *ParticipantMetaData `protobuf:"bytes,4,opt,name=participant" json:"participant,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *SignalInviteInGroupReq) Reset() { *m = SignalInviteInGroupReq{} } -func (m *SignalInviteInGroupReq) String() string { return proto.CompactTextString(m) } -func (*SignalInviteInGroupReq) ProtoMessage() {} -func (*SignalInviteInGroupReq) Descriptor() ([]byte, []int) { - return fileDescriptor_ws_bc78a4975e7e5f46, []int{64} -} -func (m *SignalInviteInGroupReq) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_SignalInviteInGroupReq.Unmarshal(m, b) -} -func (m *SignalInviteInGroupReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_SignalInviteInGroupReq.Marshal(b, m, deterministic) -} -func (dst *SignalInviteInGroupReq) XXX_Merge(src proto.Message) { - xxx_messageInfo_SignalInviteInGroupReq.Merge(dst, src) -} -func (m *SignalInviteInGroupReq) XXX_Size() int { - return xxx_messageInfo_SignalInviteInGroupReq.Size(m) -} -func (m *SignalInviteInGroupReq) XXX_DiscardUnknown() { - xxx_messageInfo_SignalInviteInGroupReq.DiscardUnknown(m) -} - -var xxx_messageInfo_SignalInviteInGroupReq proto.InternalMessageInfo - -func (m *SignalInviteInGroupReq) GetOpUserID() string { - if m != nil { - return m.OpUserID - } - return "" -} - -func (m *SignalInviteInGroupReq) GetInvitation() *InvitationInfo { - if m != nil { - return m.Invitation - } - return nil -} - -func (m *SignalInviteInGroupReq) GetOfflinePushInfo() *OfflinePushInfo { - if m != nil { - return m.OfflinePushInfo - } - return nil -} - -func (m *SignalInviteInGroupReq) GetParticipant() *ParticipantMetaData { - if m != nil { - return m.Participant - } - return nil -} - -type SignalInviteInGroupReply struct { - Token string `protobuf:"bytes,1,opt,name=token" json:"token,omitempty"` - RoomID string `protobuf:"bytes,2,opt,name=roomID" json:"roomID,omitempty"` - LiveURL string `protobuf:"bytes,3,opt,name=liveURL" json:"liveURL,omitempty"` - BusyLineUserIDList []string `protobuf:"bytes,4,rep,name=busyLineUserIDList" json:"busyLineUserIDList,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *SignalInviteInGroupReply) Reset() { *m = SignalInviteInGroupReply{} } -func (m *SignalInviteInGroupReply) String() string { return proto.CompactTextString(m) } -func (*SignalInviteInGroupReply) ProtoMessage() {} -func (*SignalInviteInGroupReply) Descriptor() ([]byte, []int) { - return fileDescriptor_ws_bc78a4975e7e5f46, []int{65} -} -func (m *SignalInviteInGroupReply) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_SignalInviteInGroupReply.Unmarshal(m, b) -} -func (m *SignalInviteInGroupReply) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_SignalInviteInGroupReply.Marshal(b, m, deterministic) -} -func (dst *SignalInviteInGroupReply) XXX_Merge(src proto.Message) { - xxx_messageInfo_SignalInviteInGroupReply.Merge(dst, src) -} -func (m *SignalInviteInGroupReply) XXX_Size() int { - return xxx_messageInfo_SignalInviteInGroupReply.Size(m) -} -func (m *SignalInviteInGroupReply) XXX_DiscardUnknown() { - xxx_messageInfo_SignalInviteInGroupReply.DiscardUnknown(m) -} - -var xxx_messageInfo_SignalInviteInGroupReply proto.InternalMessageInfo - -func (m *SignalInviteInGroupReply) GetToken() string { - if m != nil { - return m.Token - } - return "" -} - -func (m *SignalInviteInGroupReply) GetRoomID() string { - if m != nil { - return m.RoomID - } - return "" -} - -func (m *SignalInviteInGroupReply) GetLiveURL() string { - if m != nil { - return m.LiveURL - } - return "" -} - -func (m *SignalInviteInGroupReply) GetBusyLineUserIDList() []string { - if m != nil { - return m.BusyLineUserIDList - } - return nil -} - -type SignalCancelReq struct { - OpUserID string `protobuf:"bytes,1,opt,name=opUserID" json:"opUserID,omitempty"` - Invitation *InvitationInfo `protobuf:"bytes,2,opt,name=invitation" json:"invitation,omitempty"` - OfflinePushInfo *OfflinePushInfo `protobuf:"bytes,3,opt,name=offlinePushInfo" json:"offlinePushInfo,omitempty"` - Participant *ParticipantMetaData `protobuf:"bytes,4,opt,name=participant" json:"participant,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *SignalCancelReq) Reset() { *m = SignalCancelReq{} } -func (m *SignalCancelReq) String() string { return proto.CompactTextString(m) } -func (*SignalCancelReq) ProtoMessage() {} -func (*SignalCancelReq) Descriptor() ([]byte, []int) { - return fileDescriptor_ws_bc78a4975e7e5f46, []int{66} -} -func (m *SignalCancelReq) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_SignalCancelReq.Unmarshal(m, b) -} -func (m *SignalCancelReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_SignalCancelReq.Marshal(b, m, deterministic) -} -func (dst *SignalCancelReq) XXX_Merge(src proto.Message) { - xxx_messageInfo_SignalCancelReq.Merge(dst, src) -} -func (m *SignalCancelReq) XXX_Size() int { - return xxx_messageInfo_SignalCancelReq.Size(m) -} -func (m *SignalCancelReq) XXX_DiscardUnknown() { - xxx_messageInfo_SignalCancelReq.DiscardUnknown(m) -} - -var xxx_messageInfo_SignalCancelReq proto.InternalMessageInfo - -func (m *SignalCancelReq) GetOpUserID() string { - if m != nil { - return m.OpUserID - } - return "" -} - -func (m *SignalCancelReq) GetInvitation() *InvitationInfo { - if m != nil { - return m.Invitation - } - return nil -} - -func (m *SignalCancelReq) GetOfflinePushInfo() *OfflinePushInfo { - if m != nil { - return m.OfflinePushInfo - } - return nil -} - -func (m *SignalCancelReq) GetParticipant() *ParticipantMetaData { - if m != nil { - return m.Participant - } - return nil -} - -type SignalCancelReply struct { - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *SignalCancelReply) Reset() { *m = SignalCancelReply{} } -func (m *SignalCancelReply) String() string { return proto.CompactTextString(m) } -func (*SignalCancelReply) ProtoMessage() {} -func (*SignalCancelReply) Descriptor() ([]byte, []int) { - return fileDescriptor_ws_bc78a4975e7e5f46, []int{67} -} -func (m *SignalCancelReply) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_SignalCancelReply.Unmarshal(m, b) -} -func (m *SignalCancelReply) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_SignalCancelReply.Marshal(b, m, deterministic) -} -func (dst *SignalCancelReply) XXX_Merge(src proto.Message) { - xxx_messageInfo_SignalCancelReply.Merge(dst, src) -} -func (m *SignalCancelReply) XXX_Size() int { - return xxx_messageInfo_SignalCancelReply.Size(m) -} -func (m *SignalCancelReply) XXX_DiscardUnknown() { - xxx_messageInfo_SignalCancelReply.DiscardUnknown(m) -} - -var xxx_messageInfo_SignalCancelReply proto.InternalMessageInfo - -type SignalAcceptReq struct { - OpUserID string `protobuf:"bytes,1,opt,name=opUserID" json:"opUserID,omitempty"` - Invitation *InvitationInfo `protobuf:"bytes,2,opt,name=invitation" json:"invitation,omitempty"` - OfflinePushInfo *OfflinePushInfo `protobuf:"bytes,3,opt,name=offlinePushInfo" json:"offlinePushInfo,omitempty"` - Participant *ParticipantMetaData `protobuf:"bytes,4,opt,name=participant" json:"participant,omitempty"` - OpUserPlatformID int32 `protobuf:"varint,5,opt,name=opUserPlatformID" json:"opUserPlatformID,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *SignalAcceptReq) Reset() { *m = SignalAcceptReq{} } -func (m *SignalAcceptReq) String() string { return proto.CompactTextString(m) } -func (*SignalAcceptReq) ProtoMessage() {} -func (*SignalAcceptReq) Descriptor() ([]byte, []int) { - return fileDescriptor_ws_bc78a4975e7e5f46, []int{68} -} -func (m *SignalAcceptReq) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_SignalAcceptReq.Unmarshal(m, b) -} -func (m *SignalAcceptReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_SignalAcceptReq.Marshal(b, m, deterministic) -} -func (dst *SignalAcceptReq) XXX_Merge(src proto.Message) { - xxx_messageInfo_SignalAcceptReq.Merge(dst, src) -} -func (m *SignalAcceptReq) XXX_Size() int { - return xxx_messageInfo_SignalAcceptReq.Size(m) -} -func (m *SignalAcceptReq) XXX_DiscardUnknown() { - xxx_messageInfo_SignalAcceptReq.DiscardUnknown(m) -} - -var xxx_messageInfo_SignalAcceptReq proto.InternalMessageInfo - -func (m *SignalAcceptReq) GetOpUserID() string { - if m != nil { - return m.OpUserID - } - return "" -} - -func (m *SignalAcceptReq) GetInvitation() *InvitationInfo { - if m != nil { - return m.Invitation - } - return nil -} - -func (m *SignalAcceptReq) GetOfflinePushInfo() *OfflinePushInfo { - if m != nil { - return m.OfflinePushInfo - } - return nil -} - -func (m *SignalAcceptReq) GetParticipant() *ParticipantMetaData { - if m != nil { - return m.Participant - } - return nil -} - -func (m *SignalAcceptReq) GetOpUserPlatformID() int32 { - if m != nil { - return m.OpUserPlatformID - } - return 0 -} - -type SignalAcceptReply struct { - Token string `protobuf:"bytes,1,opt,name=token" json:"token,omitempty"` - RoomID string `protobuf:"bytes,2,opt,name=roomID" json:"roomID,omitempty"` - LiveURL string `protobuf:"bytes,3,opt,name=liveURL" json:"liveURL,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *SignalAcceptReply) Reset() { *m = SignalAcceptReply{} } -func (m *SignalAcceptReply) String() string { return proto.CompactTextString(m) } -func (*SignalAcceptReply) ProtoMessage() {} -func (*SignalAcceptReply) Descriptor() ([]byte, []int) { - return fileDescriptor_ws_bc78a4975e7e5f46, []int{69} -} -func (m *SignalAcceptReply) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_SignalAcceptReply.Unmarshal(m, b) -} -func (m *SignalAcceptReply) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_SignalAcceptReply.Marshal(b, m, deterministic) -} -func (dst *SignalAcceptReply) XXX_Merge(src proto.Message) { - xxx_messageInfo_SignalAcceptReply.Merge(dst, src) -} -func (m *SignalAcceptReply) XXX_Size() int { - return xxx_messageInfo_SignalAcceptReply.Size(m) -} -func (m *SignalAcceptReply) XXX_DiscardUnknown() { - xxx_messageInfo_SignalAcceptReply.DiscardUnknown(m) -} - -var xxx_messageInfo_SignalAcceptReply proto.InternalMessageInfo - -func (m *SignalAcceptReply) GetToken() string { - if m != nil { - return m.Token - } - return "" -} - -func (m *SignalAcceptReply) GetRoomID() string { - if m != nil { - return m.RoomID - } - return "" -} - -func (m *SignalAcceptReply) GetLiveURL() string { - if m != nil { - return m.LiveURL - } - return "" -} - -type SignalHungUpReq struct { - OpUserID string `protobuf:"bytes,1,opt,name=opUserID" json:"opUserID,omitempty"` - Invitation *InvitationInfo `protobuf:"bytes,2,opt,name=invitation" json:"invitation,omitempty"` - OfflinePushInfo *OfflinePushInfo `protobuf:"bytes,3,opt,name=offlinePushInfo" json:"offlinePushInfo,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *SignalHungUpReq) Reset() { *m = SignalHungUpReq{} } -func (m *SignalHungUpReq) String() string { return proto.CompactTextString(m) } -func (*SignalHungUpReq) ProtoMessage() {} -func (*SignalHungUpReq) Descriptor() ([]byte, []int) { - return fileDescriptor_ws_bc78a4975e7e5f46, []int{70} -} -func (m *SignalHungUpReq) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_SignalHungUpReq.Unmarshal(m, b) -} -func (m *SignalHungUpReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_SignalHungUpReq.Marshal(b, m, deterministic) -} -func (dst *SignalHungUpReq) XXX_Merge(src proto.Message) { - xxx_messageInfo_SignalHungUpReq.Merge(dst, src) -} -func (m *SignalHungUpReq) XXX_Size() int { - return xxx_messageInfo_SignalHungUpReq.Size(m) -} -func (m *SignalHungUpReq) XXX_DiscardUnknown() { - xxx_messageInfo_SignalHungUpReq.DiscardUnknown(m) -} - -var xxx_messageInfo_SignalHungUpReq proto.InternalMessageInfo - -func (m *SignalHungUpReq) GetOpUserID() string { - if m != nil { - return m.OpUserID - } - return "" -} - -func (m *SignalHungUpReq) GetInvitation() *InvitationInfo { - if m != nil { - return m.Invitation - } - return nil -} - -func (m *SignalHungUpReq) GetOfflinePushInfo() *OfflinePushInfo { - if m != nil { - return m.OfflinePushInfo - } - return nil -} - -type SignalHungUpReply struct { - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *SignalHungUpReply) Reset() { *m = SignalHungUpReply{} } -func (m *SignalHungUpReply) String() string { return proto.CompactTextString(m) } -func (*SignalHungUpReply) ProtoMessage() {} -func (*SignalHungUpReply) Descriptor() ([]byte, []int) { - return fileDescriptor_ws_bc78a4975e7e5f46, []int{71} -} -func (m *SignalHungUpReply) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_SignalHungUpReply.Unmarshal(m, b) -} -func (m *SignalHungUpReply) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_SignalHungUpReply.Marshal(b, m, deterministic) -} -func (dst *SignalHungUpReply) XXX_Merge(src proto.Message) { - xxx_messageInfo_SignalHungUpReply.Merge(dst, src) -} -func (m *SignalHungUpReply) XXX_Size() int { - return xxx_messageInfo_SignalHungUpReply.Size(m) -} -func (m *SignalHungUpReply) XXX_DiscardUnknown() { - xxx_messageInfo_SignalHungUpReply.DiscardUnknown(m) -} - -var xxx_messageInfo_SignalHungUpReply proto.InternalMessageInfo - -type SignalRejectReq struct { - OpUserID string `protobuf:"bytes,1,opt,name=opUserID" json:"opUserID,omitempty"` - Invitation *InvitationInfo `protobuf:"bytes,2,opt,name=invitation" json:"invitation,omitempty"` - OfflinePushInfo *OfflinePushInfo `protobuf:"bytes,3,opt,name=offlinePushInfo" json:"offlinePushInfo,omitempty"` - Participant *ParticipantMetaData `protobuf:"bytes,4,opt,name=participant" json:"participant,omitempty"` - OpUserPlatformID int32 `protobuf:"varint,5,opt,name=opUserPlatformID" json:"opUserPlatformID,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *SignalRejectReq) Reset() { *m = SignalRejectReq{} } -func (m *SignalRejectReq) String() string { return proto.CompactTextString(m) } -func (*SignalRejectReq) ProtoMessage() {} -func (*SignalRejectReq) Descriptor() ([]byte, []int) { - return fileDescriptor_ws_bc78a4975e7e5f46, []int{72} -} -func (m *SignalRejectReq) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_SignalRejectReq.Unmarshal(m, b) -} -func (m *SignalRejectReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_SignalRejectReq.Marshal(b, m, deterministic) -} -func (dst *SignalRejectReq) XXX_Merge(src proto.Message) { - xxx_messageInfo_SignalRejectReq.Merge(dst, src) -} -func (m *SignalRejectReq) XXX_Size() int { - return xxx_messageInfo_SignalRejectReq.Size(m) -} -func (m *SignalRejectReq) XXX_DiscardUnknown() { - xxx_messageInfo_SignalRejectReq.DiscardUnknown(m) -} - -var xxx_messageInfo_SignalRejectReq proto.InternalMessageInfo - -func (m *SignalRejectReq) GetOpUserID() string { - if m != nil { - return m.OpUserID - } - return "" -} - -func (m *SignalRejectReq) GetInvitation() *InvitationInfo { - if m != nil { - return m.Invitation - } - return nil -} - -func (m *SignalRejectReq) GetOfflinePushInfo() *OfflinePushInfo { - if m != nil { - return m.OfflinePushInfo - } - return nil -} - -func (m *SignalRejectReq) GetParticipant() *ParticipantMetaData { - if m != nil { - return m.Participant - } - return nil -} - -func (m *SignalRejectReq) GetOpUserPlatformID() int32 { - if m != nil { - return m.OpUserPlatformID - } - return 0 -} - -type SignalRejectReply struct { - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *SignalRejectReply) Reset() { *m = SignalRejectReply{} } -func (m *SignalRejectReply) String() string { return proto.CompactTextString(m) } -func (*SignalRejectReply) ProtoMessage() {} -func (*SignalRejectReply) Descriptor() ([]byte, []int) { - return fileDescriptor_ws_bc78a4975e7e5f46, []int{73} -} -func (m *SignalRejectReply) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_SignalRejectReply.Unmarshal(m, b) -} -func (m *SignalRejectReply) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_SignalRejectReply.Marshal(b, m, deterministic) -} -func (dst *SignalRejectReply) XXX_Merge(src proto.Message) { - xxx_messageInfo_SignalRejectReply.Merge(dst, src) -} -func (m *SignalRejectReply) XXX_Size() int { - return xxx_messageInfo_SignalRejectReply.Size(m) -} -func (m *SignalRejectReply) XXX_DiscardUnknown() { - xxx_messageInfo_SignalRejectReply.DiscardUnknown(m) -} - -var xxx_messageInfo_SignalRejectReply proto.InternalMessageInfo - -type SignalGetRoomByGroupIDReq struct { - OpUserID string `protobuf:"bytes,1,opt,name=opUserID" json:"opUserID,omitempty"` - GroupID string `protobuf:"bytes,2,opt,name=groupID" json:"groupID,omitempty"` - Participant *ParticipantMetaData `protobuf:"bytes,3,opt,name=participant" json:"participant,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *SignalGetRoomByGroupIDReq) Reset() { *m = SignalGetRoomByGroupIDReq{} } -func (m *SignalGetRoomByGroupIDReq) String() string { return proto.CompactTextString(m) } -func (*SignalGetRoomByGroupIDReq) ProtoMessage() {} -func (*SignalGetRoomByGroupIDReq) Descriptor() ([]byte, []int) { - return fileDescriptor_ws_bc78a4975e7e5f46, []int{74} -} -func (m *SignalGetRoomByGroupIDReq) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_SignalGetRoomByGroupIDReq.Unmarshal(m, b) -} -func (m *SignalGetRoomByGroupIDReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_SignalGetRoomByGroupIDReq.Marshal(b, m, deterministic) -} -func (dst *SignalGetRoomByGroupIDReq) XXX_Merge(src proto.Message) { - xxx_messageInfo_SignalGetRoomByGroupIDReq.Merge(dst, src) -} -func (m *SignalGetRoomByGroupIDReq) XXX_Size() int { - return xxx_messageInfo_SignalGetRoomByGroupIDReq.Size(m) -} -func (m *SignalGetRoomByGroupIDReq) XXX_DiscardUnknown() { - xxx_messageInfo_SignalGetRoomByGroupIDReq.DiscardUnknown(m) -} - -var xxx_messageInfo_SignalGetRoomByGroupIDReq proto.InternalMessageInfo - -func (m *SignalGetRoomByGroupIDReq) GetOpUserID() string { - if m != nil { - return m.OpUserID - } - return "" -} - -func (m *SignalGetRoomByGroupIDReq) GetGroupID() string { - if m != nil { - return m.GroupID - } - return "" -} - -func (m *SignalGetRoomByGroupIDReq) GetParticipant() *ParticipantMetaData { - if m != nil { - return m.Participant - } - return nil -} - -type SignalGetRoomByGroupIDReply struct { - Invitation *InvitationInfo `protobuf:"bytes,1,opt,name=invitation" json:"invitation,omitempty"` - Participant []*ParticipantMetaData `protobuf:"bytes,2,rep,name=participant" json:"participant,omitempty"` - RoomID string `protobuf:"bytes,3,opt,name=roomID" json:"roomID,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *SignalGetRoomByGroupIDReply) Reset() { *m = SignalGetRoomByGroupIDReply{} } -func (m *SignalGetRoomByGroupIDReply) String() string { return proto.CompactTextString(m) } -func (*SignalGetRoomByGroupIDReply) ProtoMessage() {} -func (*SignalGetRoomByGroupIDReply) Descriptor() ([]byte, []int) { - return fileDescriptor_ws_bc78a4975e7e5f46, []int{75} -} -func (m *SignalGetRoomByGroupIDReply) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_SignalGetRoomByGroupIDReply.Unmarshal(m, b) -} -func (m *SignalGetRoomByGroupIDReply) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_SignalGetRoomByGroupIDReply.Marshal(b, m, deterministic) -} -func (dst *SignalGetRoomByGroupIDReply) XXX_Merge(src proto.Message) { - xxx_messageInfo_SignalGetRoomByGroupIDReply.Merge(dst, src) -} -func (m *SignalGetRoomByGroupIDReply) XXX_Size() int { - return xxx_messageInfo_SignalGetRoomByGroupIDReply.Size(m) -} -func (m *SignalGetRoomByGroupIDReply) XXX_DiscardUnknown() { - xxx_messageInfo_SignalGetRoomByGroupIDReply.DiscardUnknown(m) -} - -var xxx_messageInfo_SignalGetRoomByGroupIDReply proto.InternalMessageInfo - -func (m *SignalGetRoomByGroupIDReply) GetInvitation() *InvitationInfo { - if m != nil { - return m.Invitation - } - return nil -} - -func (m *SignalGetRoomByGroupIDReply) GetParticipant() []*ParticipantMetaData { - if m != nil { - return m.Participant - } - return nil -} - -func (m *SignalGetRoomByGroupIDReply) GetRoomID() string { - if m != nil { - return m.RoomID - } - return "" -} - -type SignalOnRoomParticipantConnectedReq struct { - Invitation *InvitationInfo `protobuf:"bytes,1,opt,name=invitation" json:"invitation,omitempty"` - Participant []*ParticipantMetaData `protobuf:"bytes,2,rep,name=participant" json:"participant,omitempty"` - GroupID string `protobuf:"bytes,3,opt,name=groupID" json:"groupID,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *SignalOnRoomParticipantConnectedReq) Reset() { *m = SignalOnRoomParticipantConnectedReq{} } -func (m *SignalOnRoomParticipantConnectedReq) String() string { return proto.CompactTextString(m) } -func (*SignalOnRoomParticipantConnectedReq) ProtoMessage() {} -func (*SignalOnRoomParticipantConnectedReq) Descriptor() ([]byte, []int) { - return fileDescriptor_ws_bc78a4975e7e5f46, []int{76} -} -func (m *SignalOnRoomParticipantConnectedReq) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_SignalOnRoomParticipantConnectedReq.Unmarshal(m, b) -} -func (m *SignalOnRoomParticipantConnectedReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_SignalOnRoomParticipantConnectedReq.Marshal(b, m, deterministic) -} -func (dst *SignalOnRoomParticipantConnectedReq) XXX_Merge(src proto.Message) { - xxx_messageInfo_SignalOnRoomParticipantConnectedReq.Merge(dst, src) -} -func (m *SignalOnRoomParticipantConnectedReq) XXX_Size() int { - return xxx_messageInfo_SignalOnRoomParticipantConnectedReq.Size(m) -} -func (m *SignalOnRoomParticipantConnectedReq) XXX_DiscardUnknown() { - xxx_messageInfo_SignalOnRoomParticipantConnectedReq.DiscardUnknown(m) -} - -var xxx_messageInfo_SignalOnRoomParticipantConnectedReq proto.InternalMessageInfo - -func (m *SignalOnRoomParticipantConnectedReq) GetInvitation() *InvitationInfo { - if m != nil { - return m.Invitation - } - return nil -} - -func (m *SignalOnRoomParticipantConnectedReq) GetParticipant() []*ParticipantMetaData { - if m != nil { - return m.Participant - } - return nil -} - -func (m *SignalOnRoomParticipantConnectedReq) GetGroupID() string { - if m != nil { - return m.GroupID - } - return "" -} - -type SignalOnRoomParticipantDisconnectedReq struct { - Invitation *InvitationInfo `protobuf:"bytes,1,opt,name=invitation" json:"invitation,omitempty"` - Participant []*ParticipantMetaData `protobuf:"bytes,2,rep,name=participant" json:"participant,omitempty"` - GroupID string `protobuf:"bytes,3,opt,name=groupID" json:"groupID,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *SignalOnRoomParticipantDisconnectedReq) Reset() { - *m = SignalOnRoomParticipantDisconnectedReq{} -} -func (m *SignalOnRoomParticipantDisconnectedReq) String() string { return proto.CompactTextString(m) } -func (*SignalOnRoomParticipantDisconnectedReq) ProtoMessage() {} -func (*SignalOnRoomParticipantDisconnectedReq) Descriptor() ([]byte, []int) { - return fileDescriptor_ws_bc78a4975e7e5f46, []int{77} -} -func (m *SignalOnRoomParticipantDisconnectedReq) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_SignalOnRoomParticipantDisconnectedReq.Unmarshal(m, b) -} -func (m *SignalOnRoomParticipantDisconnectedReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_SignalOnRoomParticipantDisconnectedReq.Marshal(b, m, deterministic) -} -func (dst *SignalOnRoomParticipantDisconnectedReq) XXX_Merge(src proto.Message) { - xxx_messageInfo_SignalOnRoomParticipantDisconnectedReq.Merge(dst, src) -} -func (m *SignalOnRoomParticipantDisconnectedReq) XXX_Size() int { - return xxx_messageInfo_SignalOnRoomParticipantDisconnectedReq.Size(m) -} -func (m *SignalOnRoomParticipantDisconnectedReq) XXX_DiscardUnknown() { - xxx_messageInfo_SignalOnRoomParticipantDisconnectedReq.DiscardUnknown(m) -} - -var xxx_messageInfo_SignalOnRoomParticipantDisconnectedReq proto.InternalMessageInfo - -func (m *SignalOnRoomParticipantDisconnectedReq) GetInvitation() *InvitationInfo { - if m != nil { - return m.Invitation - } - return nil -} - -func (m *SignalOnRoomParticipantDisconnectedReq) GetParticipant() []*ParticipantMetaData { - if m != nil { - return m.Participant - } - return nil -} - -func (m *SignalOnRoomParticipantDisconnectedReq) GetGroupID() string { - if m != nil { - return m.GroupID - } - return "" -} - -type SignalGetTokenByRoomIDReq struct { - RoomID string `protobuf:"bytes,1,opt,name=roomID" json:"roomID,omitempty"` - OpUserID string `protobuf:"bytes,2,opt,name=opUserID" json:"opUserID,omitempty"` - Participant *ParticipantMetaData `protobuf:"bytes,3,opt,name=participant" json:"participant,omitempty"` - OperationID string `protobuf:"bytes,4,opt,name=operationID" json:"operationID,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *SignalGetTokenByRoomIDReq) Reset() { *m = SignalGetTokenByRoomIDReq{} } -func (m *SignalGetTokenByRoomIDReq) String() string { return proto.CompactTextString(m) } -func (*SignalGetTokenByRoomIDReq) ProtoMessage() {} -func (*SignalGetTokenByRoomIDReq) Descriptor() ([]byte, []int) { - return fileDescriptor_ws_bc78a4975e7e5f46, []int{78} -} -func (m *SignalGetTokenByRoomIDReq) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_SignalGetTokenByRoomIDReq.Unmarshal(m, b) -} -func (m *SignalGetTokenByRoomIDReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_SignalGetTokenByRoomIDReq.Marshal(b, m, deterministic) -} -func (dst *SignalGetTokenByRoomIDReq) XXX_Merge(src proto.Message) { - xxx_messageInfo_SignalGetTokenByRoomIDReq.Merge(dst, src) -} -func (m *SignalGetTokenByRoomIDReq) XXX_Size() int { - return xxx_messageInfo_SignalGetTokenByRoomIDReq.Size(m) -} -func (m *SignalGetTokenByRoomIDReq) XXX_DiscardUnknown() { - xxx_messageInfo_SignalGetTokenByRoomIDReq.DiscardUnknown(m) -} - -var xxx_messageInfo_SignalGetTokenByRoomIDReq proto.InternalMessageInfo - -func (m *SignalGetTokenByRoomIDReq) GetRoomID() string { - if m != nil { - return m.RoomID - } - return "" -} - -func (m *SignalGetTokenByRoomIDReq) GetOpUserID() string { - if m != nil { - return m.OpUserID - } - return "" -} - -func (m *SignalGetTokenByRoomIDReq) GetParticipant() *ParticipantMetaData { - if m != nil { - return m.Participant - } - return nil -} - -func (m *SignalGetTokenByRoomIDReq) GetOperationID() string { - if m != nil { - return m.OperationID - } - return "" -} - -type SignalGetTokenByRoomIDReply struct { - Token string `protobuf:"bytes,1,opt,name=token" json:"token,omitempty"` - LiveURL string `protobuf:"bytes,2,opt,name=liveURL" json:"liveURL,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *SignalGetTokenByRoomIDReply) Reset() { *m = SignalGetTokenByRoomIDReply{} } -func (m *SignalGetTokenByRoomIDReply) String() string { return proto.CompactTextString(m) } -func (*SignalGetTokenByRoomIDReply) ProtoMessage() {} -func (*SignalGetTokenByRoomIDReply) Descriptor() ([]byte, []int) { - return fileDescriptor_ws_bc78a4975e7e5f46, []int{79} -} -func (m *SignalGetTokenByRoomIDReply) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_SignalGetTokenByRoomIDReply.Unmarshal(m, b) -} -func (m *SignalGetTokenByRoomIDReply) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_SignalGetTokenByRoomIDReply.Marshal(b, m, deterministic) -} -func (dst *SignalGetTokenByRoomIDReply) XXX_Merge(src proto.Message) { - xxx_messageInfo_SignalGetTokenByRoomIDReply.Merge(dst, src) -} -func (m *SignalGetTokenByRoomIDReply) XXX_Size() int { - return xxx_messageInfo_SignalGetTokenByRoomIDReply.Size(m) -} -func (m *SignalGetTokenByRoomIDReply) XXX_DiscardUnknown() { - xxx_messageInfo_SignalGetTokenByRoomIDReply.DiscardUnknown(m) -} - -var xxx_messageInfo_SignalGetTokenByRoomIDReply proto.InternalMessageInfo - -func (m *SignalGetTokenByRoomIDReply) GetToken() string { - if m != nil { - return m.Token - } - return "" -} - -func (m *SignalGetTokenByRoomIDReply) GetLiveURL() string { - if m != nil { - return m.LiveURL - } - return "" -} - -type DelMsgListReq struct { - OpUserID string `protobuf:"bytes,1,opt,name=opUserID" json:"opUserID,omitempty"` - UserID string `protobuf:"bytes,2,opt,name=userID" json:"userID,omitempty"` - SeqList []uint32 `protobuf:"varint,3,rep,packed,name=seqList" json:"seqList,omitempty"` - OperationID string `protobuf:"bytes,4,opt,name=operationID" json:"operationID,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *DelMsgListReq) Reset() { *m = DelMsgListReq{} } -func (m *DelMsgListReq) String() string { return proto.CompactTextString(m) } -func (*DelMsgListReq) ProtoMessage() {} -func (*DelMsgListReq) Descriptor() ([]byte, []int) { - return fileDescriptor_ws_bc78a4975e7e5f46, []int{80} -} -func (m *DelMsgListReq) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_DelMsgListReq.Unmarshal(m, b) -} -func (m *DelMsgListReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_DelMsgListReq.Marshal(b, m, deterministic) -} -func (dst *DelMsgListReq) XXX_Merge(src proto.Message) { - xxx_messageInfo_DelMsgListReq.Merge(dst, src) -} -func (m *DelMsgListReq) XXX_Size() int { - return xxx_messageInfo_DelMsgListReq.Size(m) -} -func (m *DelMsgListReq) XXX_DiscardUnknown() { - xxx_messageInfo_DelMsgListReq.DiscardUnknown(m) -} - -var xxx_messageInfo_DelMsgListReq proto.InternalMessageInfo - -func (m *DelMsgListReq) GetOpUserID() string { - if m != nil { - return m.OpUserID - } - return "" -} - -func (m *DelMsgListReq) GetUserID() string { - if m != nil { - return m.UserID - } - return "" -} - -func (m *DelMsgListReq) GetSeqList() []uint32 { - if m != nil { - return m.SeqList - } - return nil -} - -func (m *DelMsgListReq) GetOperationID() string { - if m != nil { - return m.OperationID - } - return "" -} - -type DelMsgListResp struct { - ErrCode int32 `protobuf:"varint,1,opt,name=errCode" json:"errCode,omitempty"` - ErrMsg string `protobuf:"bytes,2,opt,name=errMsg" json:"errMsg,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *DelMsgListResp) Reset() { *m = DelMsgListResp{} } -func (m *DelMsgListResp) String() string { return proto.CompactTextString(m) } -func (*DelMsgListResp) ProtoMessage() {} -func (*DelMsgListResp) Descriptor() ([]byte, []int) { - return fileDescriptor_ws_bc78a4975e7e5f46, []int{81} -} -func (m *DelMsgListResp) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_DelMsgListResp.Unmarshal(m, b) -} -func (m *DelMsgListResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_DelMsgListResp.Marshal(b, m, deterministic) -} -func (dst *DelMsgListResp) XXX_Merge(src proto.Message) { - xxx_messageInfo_DelMsgListResp.Merge(dst, src) -} -func (m *DelMsgListResp) XXX_Size() int { - return xxx_messageInfo_DelMsgListResp.Size(m) -} -func (m *DelMsgListResp) XXX_DiscardUnknown() { - xxx_messageInfo_DelMsgListResp.DiscardUnknown(m) -} - -var xxx_messageInfo_DelMsgListResp proto.InternalMessageInfo - -func (m *DelMsgListResp) GetErrCode() int32 { - if m != nil { - return m.ErrCode - } - return 0 -} - -func (m *DelMsgListResp) GetErrMsg() string { - if m != nil { - return m.ErrMsg - } - return "" -} - -type SetAppBackgroundStatusReq struct { - UserID string `protobuf:"bytes,1,opt,name=userID" json:"userID,omitempty"` - IsBackground bool `protobuf:"varint,2,opt,name=isBackground" json:"isBackground,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *SetAppBackgroundStatusReq) Reset() { *m = SetAppBackgroundStatusReq{} } -func (m *SetAppBackgroundStatusReq) String() string { return proto.CompactTextString(m) } -func (*SetAppBackgroundStatusReq) ProtoMessage() {} -func (*SetAppBackgroundStatusReq) Descriptor() ([]byte, []int) { - return fileDescriptor_ws_bc78a4975e7e5f46, []int{82} -} -func (m *SetAppBackgroundStatusReq) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_SetAppBackgroundStatusReq.Unmarshal(m, b) -} -func (m *SetAppBackgroundStatusReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_SetAppBackgroundStatusReq.Marshal(b, m, deterministic) -} -func (dst *SetAppBackgroundStatusReq) XXX_Merge(src proto.Message) { - xxx_messageInfo_SetAppBackgroundStatusReq.Merge(dst, src) -} -func (m *SetAppBackgroundStatusReq) XXX_Size() int { - return xxx_messageInfo_SetAppBackgroundStatusReq.Size(m) -} -func (m *SetAppBackgroundStatusReq) XXX_DiscardUnknown() { - xxx_messageInfo_SetAppBackgroundStatusReq.DiscardUnknown(m) -} - -var xxx_messageInfo_SetAppBackgroundStatusReq proto.InternalMessageInfo - -func (m *SetAppBackgroundStatusReq) GetUserID() string { - if m != nil { - return m.UserID - } - return "" -} - -func (m *SetAppBackgroundStatusReq) GetIsBackground() bool { - if m != nil { - return m.IsBackground - } - return false -} - -type SetAppBackgroundStatusResp struct { - ErrCode int32 `protobuf:"varint,1,opt,name=errCode" json:"errCode,omitempty"` - ErrMsg string `protobuf:"bytes,2,opt,name=errMsg" json:"errMsg,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *SetAppBackgroundStatusResp) Reset() { *m = SetAppBackgroundStatusResp{} } -func (m *SetAppBackgroundStatusResp) String() string { return proto.CompactTextString(m) } -func (*SetAppBackgroundStatusResp) ProtoMessage() {} -func (*SetAppBackgroundStatusResp) Descriptor() ([]byte, []int) { - return fileDescriptor_ws_bc78a4975e7e5f46, []int{83} -} -func (m *SetAppBackgroundStatusResp) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_SetAppBackgroundStatusResp.Unmarshal(m, b) -} -func (m *SetAppBackgroundStatusResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_SetAppBackgroundStatusResp.Marshal(b, m, deterministic) -} -func (dst *SetAppBackgroundStatusResp) XXX_Merge(src proto.Message) { - xxx_messageInfo_SetAppBackgroundStatusResp.Merge(dst, src) -} -func (m *SetAppBackgroundStatusResp) XXX_Size() int { - return xxx_messageInfo_SetAppBackgroundStatusResp.Size(m) -} -func (m *SetAppBackgroundStatusResp) XXX_DiscardUnknown() { - xxx_messageInfo_SetAppBackgroundStatusResp.DiscardUnknown(m) -} - -var xxx_messageInfo_SetAppBackgroundStatusResp proto.InternalMessageInfo - -func (m *SetAppBackgroundStatusResp) GetErrCode() int32 { - if m != nil { - return m.ErrCode - } - return 0 -} - -func (m *SetAppBackgroundStatusResp) GetErrMsg() string { - if m != nil { - return m.ErrMsg - } - return "" -} - -type ExtendMsgSet struct { - SourceID string `protobuf:"bytes,1,opt,name=sourceID" json:"sourceID,omitempty"` - SessionType int32 `protobuf:"varint,2,opt,name=sessionType" json:"sessionType,omitempty"` - ExtendMsgs map[string]*ExtendMsg `protobuf:"bytes,3,rep,name=extendMsgs" json:"extendMsgs,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` - MaxMsgUpdateTime int64 `protobuf:"varint,4,opt,name=MaxMsgUpdateTime" json:"MaxMsgUpdateTime,omitempty"` - ExtendMsgNum int32 `protobuf:"varint,5,opt,name=extendMsgNum" json:"extendMsgNum,omitempty"` - CreateTime int64 `protobuf:"varint,6,opt,name=createTime" json:"createTime,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *ExtendMsgSet) Reset() { *m = ExtendMsgSet{} } -func (m *ExtendMsgSet) String() string { return proto.CompactTextString(m) } -func (*ExtendMsgSet) ProtoMessage() {} -func (*ExtendMsgSet) Descriptor() ([]byte, []int) { - return fileDescriptor_ws_bc78a4975e7e5f46, []int{84} -} -func (m *ExtendMsgSet) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_ExtendMsgSet.Unmarshal(m, b) -} -func (m *ExtendMsgSet) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_ExtendMsgSet.Marshal(b, m, deterministic) -} -func (dst *ExtendMsgSet) XXX_Merge(src proto.Message) { - xxx_messageInfo_ExtendMsgSet.Merge(dst, src) -} -func (m *ExtendMsgSet) XXX_Size() int { - return xxx_messageInfo_ExtendMsgSet.Size(m) -} -func (m *ExtendMsgSet) XXX_DiscardUnknown() { - xxx_messageInfo_ExtendMsgSet.DiscardUnknown(m) -} - -var xxx_messageInfo_ExtendMsgSet proto.InternalMessageInfo - -func (m *ExtendMsgSet) GetSourceID() string { - if m != nil { - return m.SourceID - } - return "" -} - -func (m *ExtendMsgSet) GetSessionType() int32 { - if m != nil { - return m.SessionType - } - return 0 -} - -func (m *ExtendMsgSet) GetExtendMsgs() map[string]*ExtendMsg { - if m != nil { - return m.ExtendMsgs - } - return nil -} - -func (m *ExtendMsgSet) GetMaxMsgUpdateTime() int64 { - if m != nil { - return m.MaxMsgUpdateTime - } - return 0 -} - -func (m *ExtendMsgSet) GetExtendMsgNum() int32 { - if m != nil { - return m.ExtendMsgNum - } - return 0 -} - -func (m *ExtendMsgSet) GetCreateTime() int64 { - if m != nil { - return m.CreateTime - } - return 0 -} - -type ExtendMsg struct { - ReactionExtensionList map[string]*KeyValue `protobuf:"bytes,1,rep,name=reactionExtensionList" json:"reactionExtensionList,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` - ClientMsgID string `protobuf:"bytes,2,opt,name=clientMsgID" json:"clientMsgID,omitempty"` - MsgFirstModifyTime int64 `protobuf:"varint,3,opt,name=msgFirstModifyTime" json:"msgFirstModifyTime,omitempty"` - AttachedInfo string `protobuf:"bytes,4,opt,name=attachedInfo" json:"attachedInfo,omitempty"` - Ex string `protobuf:"bytes,5,opt,name=ex" json:"ex,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *ExtendMsg) Reset() { *m = ExtendMsg{} } -func (m *ExtendMsg) String() string { return proto.CompactTextString(m) } -func (*ExtendMsg) ProtoMessage() {} -func (*ExtendMsg) Descriptor() ([]byte, []int) { - return fileDescriptor_ws_bc78a4975e7e5f46, []int{85} -} -func (m *ExtendMsg) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_ExtendMsg.Unmarshal(m, b) -} -func (m *ExtendMsg) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_ExtendMsg.Marshal(b, m, deterministic) -} -func (dst *ExtendMsg) XXX_Merge(src proto.Message) { - xxx_messageInfo_ExtendMsg.Merge(dst, src) -} -func (m *ExtendMsg) XXX_Size() int { - return xxx_messageInfo_ExtendMsg.Size(m) -} -func (m *ExtendMsg) XXX_DiscardUnknown() { - xxx_messageInfo_ExtendMsg.DiscardUnknown(m) -} - -var xxx_messageInfo_ExtendMsg proto.InternalMessageInfo - -func (m *ExtendMsg) GetReactionExtensionList() map[string]*KeyValue { - if m != nil { - return m.ReactionExtensionList - } - return nil -} - -func (m *ExtendMsg) GetClientMsgID() string { - if m != nil { - return m.ClientMsgID - } - return "" -} - -func (m *ExtendMsg) GetMsgFirstModifyTime() int64 { - if m != nil { - return m.MsgFirstModifyTime - } - return 0 -} - -func (m *ExtendMsg) GetAttachedInfo() string { - if m != nil { - return m.AttachedInfo - } - return "" -} - -func (m *ExtendMsg) GetEx() string { - if m != nil { - return m.Ex - } - return "" -} - -type KeyValue struct { - TypeKey string `protobuf:"bytes,1,opt,name=typeKey" json:"typeKey,omitempty"` - Value string `protobuf:"bytes,2,opt,name=value" json:"value,omitempty"` - LatestUpdateTime int64 `protobuf:"varint,3,opt,name=latestUpdateTime" json:"latestUpdateTime,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *KeyValue) Reset() { *m = KeyValue{} } -func (m *KeyValue) String() string { return proto.CompactTextString(m) } -func (*KeyValue) ProtoMessage() {} -func (*KeyValue) Descriptor() ([]byte, []int) { - return fileDescriptor_ws_bc78a4975e7e5f46, []int{86} -} -func (m *KeyValue) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_KeyValue.Unmarshal(m, b) -} -func (m *KeyValue) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_KeyValue.Marshal(b, m, deterministic) -} -func (dst *KeyValue) XXX_Merge(src proto.Message) { - xxx_messageInfo_KeyValue.Merge(dst, src) -} -func (m *KeyValue) XXX_Size() int { - return xxx_messageInfo_KeyValue.Size(m) -} -func (m *KeyValue) XXX_DiscardUnknown() { - xxx_messageInfo_KeyValue.DiscardUnknown(m) -} - -var xxx_messageInfo_KeyValue proto.InternalMessageInfo - -func (m *KeyValue) GetTypeKey() string { - if m != nil { - return m.TypeKey - } - return "" -} - -func (m *KeyValue) GetValue() string { - if m != nil { - return m.Value - } - return "" -} - -func (m *KeyValue) GetLatestUpdateTime() int64 { - if m != nil { - return m.LatestUpdateTime - } - return 0 -} - -func init() { - proto.RegisterType((*GroupInfo)(nil), "server_api_params.GroupInfo") - proto.RegisterType((*GroupInfoForSet)(nil), "server_api_params.GroupInfoForSet") - proto.RegisterType((*GroupMemberFullInfo)(nil), "server_api_params.GroupMemberFullInfo") - proto.RegisterType((*PublicUserInfo)(nil), "server_api_params.PublicUserInfo") - proto.RegisterType((*UserInfo)(nil), "server_api_params.UserInfo") - proto.RegisterType((*FriendInfo)(nil), "server_api_params.FriendInfo") - proto.RegisterType((*BlackInfo)(nil), "server_api_params.BlackInfo") - proto.RegisterType((*GroupRequest)(nil), "server_api_params.GroupRequest") - proto.RegisterType((*FriendRequest)(nil), "server_api_params.FriendRequest") - proto.RegisterType((*Department)(nil), "server_api_params.Department") - proto.RegisterType((*OrganizationUser)(nil), "server_api_params.OrganizationUser") - proto.RegisterType((*DepartmentMember)(nil), "server_api_params.DepartmentMember") - proto.RegisterType((*UserDepartmentMember)(nil), "server_api_params.UserDepartmentMember") - proto.RegisterType((*UserInDepartment)(nil), "server_api_params.UserInDepartment") - proto.RegisterType((*PullMessageBySeqListReq)(nil), "server_api_params.PullMessageBySeqListReq") - proto.RegisterMapType((map[string]*SeqList)(nil), "server_api_params.PullMessageBySeqListReq.GroupSeqListEntry") - proto.RegisterType((*SeqList)(nil), "server_api_params.seqList") - proto.RegisterType((*MsgDataList)(nil), "server_api_params.MsgDataList") - proto.RegisterType((*PullMessageBySeqListResp)(nil), "server_api_params.PullMessageBySeqListResp") - proto.RegisterMapType((map[string]*MsgDataList)(nil), "server_api_params.PullMessageBySeqListResp.GroupMsgDataListEntry") - proto.RegisterType((*GetMaxAndMinSeqReq)(nil), "server_api_params.GetMaxAndMinSeqReq") - proto.RegisterType((*MaxAndMinSeq)(nil), "server_api_params.MaxAndMinSeq") - proto.RegisterType((*GetMaxAndMinSeqResp)(nil), "server_api_params.GetMaxAndMinSeqResp") - proto.RegisterMapType((map[string]*MaxAndMinSeq)(nil), "server_api_params.GetMaxAndMinSeqResp.GroupMaxAndMinSeqEntry") - proto.RegisterType((*UserSendMsgResp)(nil), "server_api_params.UserSendMsgResp") - proto.RegisterType((*MsgData)(nil), "server_api_params.MsgData") - proto.RegisterMapType((map[string]bool)(nil), "server_api_params.MsgData.OptionsEntry") - proto.RegisterType((*OfflinePushInfo)(nil), "server_api_params.OfflinePushInfo") - proto.RegisterType((*TipsComm)(nil), "server_api_params.TipsComm") - proto.RegisterType((*GroupCreatedTips)(nil), "server_api_params.GroupCreatedTips") - proto.RegisterType((*GroupInfoSetTips)(nil), "server_api_params.GroupInfoSetTips") - proto.RegisterType((*JoinGroupApplicationTips)(nil), "server_api_params.JoinGroupApplicationTips") - proto.RegisterType((*MemberQuitTips)(nil), "server_api_params.MemberQuitTips") - proto.RegisterType((*GroupApplicationAcceptedTips)(nil), "server_api_params.GroupApplicationAcceptedTips") - proto.RegisterType((*GroupApplicationRejectedTips)(nil), "server_api_params.GroupApplicationRejectedTips") - proto.RegisterType((*GroupOwnerTransferredTips)(nil), "server_api_params.GroupOwnerTransferredTips") - proto.RegisterType((*MemberKickedTips)(nil), "server_api_params.MemberKickedTips") - proto.RegisterType((*MemberInvitedTips)(nil), "server_api_params.MemberInvitedTips") - proto.RegisterType((*MemberEnterTips)(nil), "server_api_params.MemberEnterTips") - proto.RegisterType((*GroupDismissedTips)(nil), "server_api_params.GroupDismissedTips") - proto.RegisterType((*GroupMemberMutedTips)(nil), "server_api_params.GroupMemberMutedTips") - proto.RegisterType((*GroupMemberCancelMutedTips)(nil), "server_api_params.GroupMemberCancelMutedTips") - proto.RegisterType((*GroupMutedTips)(nil), "server_api_params.GroupMutedTips") - proto.RegisterType((*GroupCancelMutedTips)(nil), "server_api_params.GroupCancelMutedTips") - proto.RegisterType((*GroupMemberInfoSetTips)(nil), "server_api_params.GroupMemberInfoSetTips") - proto.RegisterType((*OrganizationChangedTips)(nil), "server_api_params.OrganizationChangedTips") - proto.RegisterType((*FriendApplication)(nil), "server_api_params.FriendApplication") - proto.RegisterType((*FromToUserID)(nil), "server_api_params.FromToUserID") - proto.RegisterType((*FriendApplicationTips)(nil), "server_api_params.FriendApplicationTips") - proto.RegisterType((*FriendApplicationApprovedTips)(nil), "server_api_params.FriendApplicationApprovedTips") - proto.RegisterType((*FriendApplicationRejectedTips)(nil), "server_api_params.FriendApplicationRejectedTips") - proto.RegisterType((*FriendAddedTips)(nil), "server_api_params.FriendAddedTips") - proto.RegisterType((*FriendDeletedTips)(nil), "server_api_params.FriendDeletedTips") - proto.RegisterType((*BlackAddedTips)(nil), "server_api_params.BlackAddedTips") - proto.RegisterType((*BlackDeletedTips)(nil), "server_api_params.BlackDeletedTips") - proto.RegisterType((*FriendInfoChangedTips)(nil), "server_api_params.FriendInfoChangedTips") - proto.RegisterType((*UserInfoUpdatedTips)(nil), "server_api_params.UserInfoUpdatedTips") - proto.RegisterType((*ConversationUpdateTips)(nil), "server_api_params.ConversationUpdateTips") - proto.RegisterType((*ConversationSetPrivateTips)(nil), "server_api_params.ConversationSetPrivateTips") - proto.RegisterType((*DeleteMessageTips)(nil), "server_api_params.DeleteMessageTips") - proto.RegisterType((*RequestPagination)(nil), "server_api_params.RequestPagination") - proto.RegisterType((*ResponsePagination)(nil), "server_api_params.ResponsePagination") - proto.RegisterType((*SignalReq)(nil), "server_api_params.SignalReq") - proto.RegisterType((*SignalResp)(nil), "server_api_params.SignalResp") - proto.RegisterType((*InvitationInfo)(nil), "server_api_params.InvitationInfo") - proto.RegisterType((*ParticipantMetaData)(nil), "server_api_params.ParticipantMetaData") - proto.RegisterType((*SignalInviteReq)(nil), "server_api_params.SignalInviteReq") - proto.RegisterType((*SignalInviteReply)(nil), "server_api_params.SignalInviteReply") - proto.RegisterType((*SignalInviteInGroupReq)(nil), "server_api_params.SignalInviteInGroupReq") - proto.RegisterType((*SignalInviteInGroupReply)(nil), "server_api_params.SignalInviteInGroupReply") - proto.RegisterType((*SignalCancelReq)(nil), "server_api_params.SignalCancelReq") - proto.RegisterType((*SignalCancelReply)(nil), "server_api_params.SignalCancelReply") - proto.RegisterType((*SignalAcceptReq)(nil), "server_api_params.SignalAcceptReq") - proto.RegisterType((*SignalAcceptReply)(nil), "server_api_params.SignalAcceptReply") - proto.RegisterType((*SignalHungUpReq)(nil), "server_api_params.SignalHungUpReq") - proto.RegisterType((*SignalHungUpReply)(nil), "server_api_params.SignalHungUpReply") - proto.RegisterType((*SignalRejectReq)(nil), "server_api_params.SignalRejectReq") - proto.RegisterType((*SignalRejectReply)(nil), "server_api_params.SignalRejectReply") - proto.RegisterType((*SignalGetRoomByGroupIDReq)(nil), "server_api_params.SignalGetRoomByGroupIDReq") - proto.RegisterType((*SignalGetRoomByGroupIDReply)(nil), "server_api_params.SignalGetRoomByGroupIDReply") - proto.RegisterType((*SignalOnRoomParticipantConnectedReq)(nil), "server_api_params.SignalOnRoomParticipantConnectedReq") - proto.RegisterType((*SignalOnRoomParticipantDisconnectedReq)(nil), "server_api_params.SignalOnRoomParticipantDisconnectedReq") - proto.RegisterType((*SignalGetTokenByRoomIDReq)(nil), "server_api_params.SignalGetTokenByRoomIDReq") - proto.RegisterType((*SignalGetTokenByRoomIDReply)(nil), "server_api_params.SignalGetTokenByRoomIDReply") - proto.RegisterType((*DelMsgListReq)(nil), "server_api_params.DelMsgListReq") - proto.RegisterType((*DelMsgListResp)(nil), "server_api_params.DelMsgListResp") - proto.RegisterType((*SetAppBackgroundStatusReq)(nil), "server_api_params.SetAppBackgroundStatusReq") - proto.RegisterType((*SetAppBackgroundStatusResp)(nil), "server_api_params.SetAppBackgroundStatusResp") - proto.RegisterType((*ExtendMsgSet)(nil), "server_api_params.ExtendMsgSet") - proto.RegisterMapType((map[string]*ExtendMsg)(nil), "server_api_params.ExtendMsgSet.ExtendMsgsEntry") - proto.RegisterType((*ExtendMsg)(nil), "server_api_params.ExtendMsg") - proto.RegisterMapType((map[string]*KeyValue)(nil), "server_api_params.ExtendMsg.ReactionExtensionListEntry") - proto.RegisterType((*KeyValue)(nil), "server_api_params.KeyValue") -} - -func init() { proto.RegisterFile("sdk_ws/ws.proto", fileDescriptor_ws_bc78a4975e7e5f46) } - -var fileDescriptor_ws_bc78a4975e7e5f46 = []byte{ - // 4162 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x3c, 0x59, 0x8f, 0x1c, 0x57, - 0xb9, 0xa9, 0xea, 0x65, 0xba, 0xbf, 0x9e, 0xa5, 0xa7, 0x6c, 0x4f, 0x3a, 0x13, 0xc7, 0x77, 0x6e, - 0xc5, 0xf2, 0x75, 0x7c, 0x9d, 0xf1, 0xbd, 0xce, 0x72, 0x6f, 0x36, 0xa3, 0x59, 0xec, 0xf1, 0xc4, - 0xee, 0x99, 0x49, 0xb5, 0x1d, 0xa3, 0x24, 0x92, 0xa9, 0xe9, 0x3a, 0xd3, 0x53, 0x99, 0xea, 0xaa, - 0x9a, 0x5a, 0xc6, 0x1e, 0x1e, 0x40, 0x2c, 0x02, 0x24, 0x1e, 0x90, 0x10, 0x8b, 0x04, 0x6f, 0xbc, - 0x20, 0x10, 0x8a, 0x10, 0x0a, 0x12, 0x12, 0x08, 0x21, 0xc4, 0x03, 0x12, 0x48, 0xe4, 0x1d, 0x09, - 0x04, 0x2f, 0x20, 0xc4, 0x1f, 0x40, 0x42, 0x0a, 0x3a, 0x4b, 0x55, 0x9d, 0x53, 0x4b, 0x77, 0xbb, - 0x35, 0x8a, 0x6d, 0x99, 0x27, 0xfb, 0xfb, 0xea, 0x7c, 0xdf, 0xf9, 0xf6, 0xf3, 0x9d, 0xa5, 0x07, - 0x66, 0x7c, 0x63, 0xef, 0xf6, 0x1d, 0xff, 0xc2, 0x1d, 0x7f, 0xd1, 0xf5, 0x9c, 0xc0, 0x51, 0x66, - 0x7d, 0xe4, 0x1d, 0x20, 0xef, 0xb6, 0xee, 0x9a, 0xb7, 0x5d, 0xdd, 0xd3, 0xfb, 0xfe, 0xfc, 0xe2, - 0xa6, 0x8b, 0xec, 0x67, 0xd7, 0xdb, 0xcf, 0x76, 0xc8, 0xa7, 0x0b, 0xee, 0x5e, 0xef, 0x02, 0x19, - 0x7c, 0x21, 0x22, 0xf6, 0x74, 0xd7, 0x45, 0x1e, 0x63, 0xa1, 0xfe, 0xb1, 0x0c, 0xf5, 0x35, 0xcf, - 0x09, 0xdd, 0x75, 0x7b, 0xc7, 0x51, 0x5a, 0x30, 0xd1, 0x23, 0xc0, 0x6a, 0x4b, 0x5a, 0x90, 0xce, - 0xd6, 0xb5, 0x08, 0x54, 0x4e, 0x42, 0x9d, 0xfc, 0x77, 0x43, 0xef, 0xa3, 0x96, 0x4c, 0xbe, 0x25, - 0x08, 0x45, 0x85, 0x49, 0xdb, 0x09, 0xcc, 0x1d, 0xb3, 0xab, 0x07, 0xa6, 0x63, 0xb7, 0x4a, 0x64, - 0x80, 0x80, 0xc3, 0x63, 0x4c, 0x3b, 0xf0, 0x1c, 0x23, 0xec, 0x92, 0x31, 0x65, 0x3a, 0x86, 0xc7, - 0xe1, 0xf9, 0x77, 0xf4, 0x2e, 0xba, 0xa9, 0x5d, 0x6f, 0x55, 0xe8, 0xfc, 0x0c, 0x54, 0x16, 0xa0, - 0xe1, 0xdc, 0xb1, 0x91, 0x77, 0xd3, 0x47, 0xde, 0xfa, 0x6a, 0xab, 0x4a, 0xbe, 0xf2, 0x28, 0xe5, - 0x14, 0x40, 0xd7, 0x43, 0x7a, 0x80, 0x6e, 0x98, 0x7d, 0xd4, 0x9a, 0x58, 0x90, 0xce, 0x4e, 0x69, - 0x1c, 0x06, 0x73, 0xe8, 0xa3, 0xfe, 0x36, 0xf2, 0x56, 0x9c, 0xd0, 0x0e, 0x5a, 0x35, 0x32, 0x80, - 0x47, 0x29, 0xd3, 0x20, 0xa3, 0xbb, 0xad, 0x3a, 0x61, 0x2d, 0xa3, 0xbb, 0xca, 0x1c, 0x54, 0xfd, - 0x40, 0x0f, 0x42, 0xbf, 0x05, 0x0b, 0xd2, 0xd9, 0x8a, 0xc6, 0x20, 0xe5, 0x34, 0x4c, 0x11, 0xbe, - 0x4e, 0x24, 0x4d, 0x83, 0x90, 0x88, 0xc8, 0xd8, 0x62, 0x37, 0x0e, 0x5d, 0xd4, 0x9a, 0x24, 0x0c, - 0x12, 0x84, 0x72, 0x0e, 0x9a, 0x36, 0x42, 0xc6, 0x9b, 0xc8, 0x4b, 0xac, 0x36, 0x45, 0x06, 0x65, - 0xf0, 0xca, 0x19, 0x98, 0xb6, 0x1c, 0x67, 0xaf, 0x4d, 0x44, 0xc5, 0x7e, 0x6a, 0x4d, 0x93, 0x91, - 0x29, 0xac, 0x72, 0x1e, 0x66, 0x75, 0xd7, 0xb5, 0x0e, 0x29, 0xea, 0x8a, 0x67, 0x22, 0xdb, 0x68, - 0xcd, 0x90, 0xa1, 0xd9, 0x0f, 0xca, 0x8b, 0x30, 0xc7, 0xfb, 0xe7, 0xa6, 0x6b, 0x44, 0xb6, 0x6b, - 0x12, 0xd3, 0x14, 0x7c, 0x55, 0x16, 0x41, 0x11, 0xbe, 0x50, 0x13, 0xcc, 0x12, 0x13, 0xe4, 0x7c, - 0x51, 0xbf, 0x56, 0x82, 0x99, 0x38, 0xc2, 0xae, 0x38, 0x5e, 0x07, 0x05, 0x0f, 0x70, 0x9c, 0xd1, - 0x18, 0xa8, 0xc6, 0x31, 0xb0, 0x96, 0xe3, 0x27, 0x1c, 0x5b, 0x8d, 0x8b, 0x4f, 0x2e, 0xf6, 0x1c, - 0xa7, 0x67, 0x21, 0x9a, 0x48, 0xdb, 0xe1, 0xce, 0xe2, 0xba, 0x1d, 0x3c, 0x77, 0xf1, 0x4d, 0xdd, - 0x0a, 0x51, 0x8e, 0x13, 0x57, 0x32, 0x4e, 0xac, 0x0d, 0x67, 0x93, 0xf6, 0xf0, 0x7a, 0x9e, 0x87, - 0xeb, 0xc3, 0xf9, 0x64, 0xa9, 0xd4, 0x0f, 0x65, 0x38, 0x46, 0xdc, 0xc2, 0xb0, 0xa1, 0x65, 0x0d, - 0x29, 0x01, 0x73, 0x50, 0x0d, 0xa9, 0xb3, 0xa9, 0x5f, 0x18, 0x84, 0x5d, 0xe6, 0x39, 0x16, 0xba, - 0x8e, 0x0e, 0x90, 0x45, 0x3c, 0x52, 0xd1, 0x12, 0x84, 0x32, 0x0f, 0xb5, 0x77, 0x1d, 0xd3, 0x26, - 0x81, 0x55, 0x26, 0x1f, 0x63, 0x18, 0x7f, 0xb3, 0xcd, 0xee, 0x9e, 0x8d, 0x7d, 0x4d, 0xfd, 0x10, - 0xc3, 0xbc, 0x8b, 0xaa, 0xa2, 0x8b, 0xce, 0xc0, 0xb4, 0xee, 0xba, 0x6d, 0xdd, 0xee, 0x21, 0x8f, - 0x4e, 0x3a, 0x41, 0xd3, 0x41, 0xc4, 0xe2, 0x82, 0x80, 0x67, 0xea, 0x38, 0xa1, 0xd7, 0x45, 0xc4, - 0xda, 0x15, 0x8d, 0xc3, 0x60, 0x3e, 0x8e, 0x8b, 0x3c, 0x2e, 0x8f, 0x69, 0xea, 0xa7, 0xb0, 0x2c, - 0x24, 0x20, 0x0e, 0x09, 0x5c, 0x48, 0xc2, 0x00, 0x5d, 0xb6, 0x0d, 0xa2, 0x54, 0x83, 0x15, 0x92, - 0x04, 0x85, 0x0b, 0x84, 0x69, 0x1f, 0x98, 0x41, 0x5c, 0xae, 0x26, 0x69, 0x81, 0x10, 0x90, 0xea, - 0x17, 0x24, 0x98, 0xde, 0x0a, 0xb7, 0x2d, 0xb3, 0x4b, 0x10, 0xd8, 0xf8, 0x89, 0x89, 0x25, 0xc1, - 0xc4, 0xbc, 0xa1, 0xe4, 0x62, 0x43, 0x95, 0x44, 0x43, 0xcd, 0x41, 0xb5, 0x87, 0x6c, 0x03, 0x79, - 0xcc, 0xf0, 0x0c, 0x62, 0x0a, 0x55, 0x22, 0x85, 0xd4, 0x3f, 0xc8, 0x50, 0xfb, 0x88, 0x45, 0x58, - 0x80, 0x86, 0xbb, 0xeb, 0xd8, 0x68, 0x23, 0xc4, 0xc1, 0xc7, 0x64, 0xe1, 0x51, 0xca, 0x71, 0xa8, - 0x6c, 0x9b, 0x5e, 0xb0, 0x4b, 0xbc, 0x3f, 0xa5, 0x51, 0x00, 0x63, 0x51, 0x5f, 0x37, 0xa9, 0xcb, - 0xeb, 0x1a, 0x05, 0x98, 0x42, 0xb5, 0xd8, 0x43, 0xe2, 0x52, 0x50, 0xcf, 0x2c, 0x05, 0xd9, 0x08, - 0x82, 0xdc, 0x08, 0x3a, 0x07, 0xcd, 0x9e, 0xe5, 0x6c, 0xeb, 0x96, 0x86, 0xba, 0x07, 0x6d, 0xbf, - 0xb7, 0xe9, 0x06, 0xc4, 0xdd, 0x15, 0x2d, 0x83, 0xc7, 0xf6, 0x21, 0x22, 0x76, 0x02, 0x8f, 0xb9, - 0x3b, 0x86, 0xd5, 0x7f, 0x48, 0x00, 0x34, 0xed, 0x88, 0x89, 0x53, 0x6b, 0x99, 0x94, 0x5d, 0xcb, - 0xe6, 0xa0, 0xea, 0xa1, 0xbe, 0xee, 0xed, 0x45, 0xa9, 0x46, 0xa1, 0x94, 0x62, 0xa5, 0x8c, 0x62, - 0xaf, 0x00, 0xec, 0x90, 0x79, 0x30, 0x1f, 0x62, 0x72, 0x5c, 0x18, 0x32, 0x5d, 0xc2, 0x62, 0xe4, - 0x6d, 0x8d, 0x1b, 0x8e, 0xf3, 0x58, 0x37, 0x0c, 0x96, 0x2e, 0x15, 0x9a, 0xc7, 0x31, 0x22, 0x27, - 0x5b, 0xaa, 0x03, 0xb2, 0x65, 0x22, 0x0e, 0xae, 0xbf, 0x4b, 0x50, 0x5f, 0xb6, 0xf4, 0xee, 0xde, - 0x88, 0xaa, 0x8b, 0x2a, 0xca, 0x19, 0x15, 0xd7, 0x60, 0x6a, 0x1b, 0xb3, 0x8b, 0x54, 0x20, 0x56, - 0x68, 0x5c, 0xfc, 0xcf, 0x1c, 0x2d, 0xc5, 0xe4, 0xd2, 0x44, 0x3a, 0x51, 0xdd, 0xf2, 0x70, 0x75, - 0x2b, 0x03, 0xd4, 0x8d, 0xd7, 0x0b, 0xf5, 0x9b, 0x25, 0x98, 0x24, 0x65, 0x55, 0x43, 0xfb, 0x21, - 0xf2, 0x03, 0xe5, 0x35, 0xa8, 0x85, 0x91, 0xa8, 0xd2, 0xa8, 0xa2, 0xc6, 0x24, 0xca, 0xcb, 0x6c, - 0x3d, 0x24, 0xf4, 0x32, 0xa1, 0x3f, 0x99, 0x43, 0x1f, 0x2f, 0xb0, 0x5a, 0x32, 0x1c, 0xaf, 0x84, - 0xbb, 0xba, 0x6d, 0x58, 0x48, 0x43, 0x7e, 0x68, 0x05, 0xac, 0x36, 0x0b, 0x38, 0x1a, 0x69, 0xfb, - 0x6d, 0xbf, 0xc7, 0xd6, 0x49, 0x06, 0x61, 0xeb, 0xd0, 0x71, 0xf8, 0x13, 0x55, 0x3d, 0x41, 0xe0, - 0x84, 0xf7, 0xd0, 0x3e, 0xf1, 0x10, 0x4d, 0xcf, 0x08, 0x4c, 0xe6, 0x64, 0x56, 0xa3, 0x81, 0x20, - 0xe0, 0xb0, 0x8b, 0x29, 0x4c, 0x18, 0xd0, 0x46, 0x8c, 0xc3, 0x64, 0xfa, 0x30, 0xb1, 0x90, 0x43, - 0xa6, 0x90, 0x67, 0xca, 0x6d, 0x23, 0xaf, 0xdc, 0xfe, 0xbe, 0x04, 0x53, 0x34, 0x09, 0x23, 0xd7, - 0x9c, 0xc2, 0xd9, 0xe2, 0xf4, 0x85, 0x58, 0xe4, 0x30, 0x58, 0x17, 0x0c, 0x6d, 0x88, 0x65, 0x4f, - 0xc0, 0xe1, 0x80, 0xc6, 0xf0, 0x15, 0xa1, 0xfc, 0xf1, 0xa8, 0x68, 0x96, 0x35, 0xbe, 0x0c, 0x72, - 0x18, 0x5c, 0x38, 0x02, 0x47, 0x88, 0xb1, 0x18, 0xc6, 0xb4, 0x81, 0x13, 0xcf, 0x4f, 0xa3, 0x8c, - 0xc3, 0x60, 0x2f, 0x05, 0x4e, 0x34, 0x37, 0x35, 0x75, 0x82, 0xa0, 0x9c, 0xd9, 0xbc, 0x74, 0xf9, - 0x8b, 0xe1, 0x4c, 0x6c, 0xd4, 0x07, 0xc6, 0x06, 0x08, 0xb1, 0x21, 0xa6, 0x68, 0x23, 0x93, 0xa2, - 0xa7, 0x61, 0x8a, 0xf2, 0x49, 0x2d, 0x7f, 0x02, 0x52, 0x8c, 0xb0, 0xa9, 0x74, 0x84, 0x89, 0x31, - 0x32, 0x5d, 0x10, 0x23, 0x33, 0x71, 0xde, 0xfd, 0x48, 0x06, 0x58, 0x45, 0xae, 0xee, 0x05, 0x7d, - 0x64, 0x07, 0x58, 0x3d, 0x23, 0x86, 0x62, 0xe7, 0x0a, 0x38, 0x7e, 0xd5, 0x92, 0xc5, 0x55, 0x4b, - 0x81, 0x32, 0x31, 0x38, 0xf5, 0x26, 0xf9, 0x3f, 0x36, 0xa6, 0xab, 0x7b, 0x94, 0x1b, 0x4d, 0x95, - 0x18, 0xc6, 0xab, 0x92, 0xe3, 0x19, 0x6c, 0x1d, 0xab, 0x68, 0x14, 0xc0, 0x25, 0x24, 0x99, 0x8f, - 0xec, 0x02, 0xaa, 0x74, 0x95, 0x11, 0xb1, 0x43, 0x37, 0x2e, 0xe7, 0xa0, 0xe9, 0x87, 0xdb, 0x89, - 0x72, 0x1b, 0x61, 0x9f, 0x25, 0x4d, 0x06, 0x8f, 0x8d, 0x4a, 0x77, 0x34, 0x78, 0x10, 0x5d, 0xf8, - 0x12, 0x44, 0xba, 0x93, 0x51, 0x7f, 0x2d, 0x43, 0x73, 0xd3, 0xeb, 0xe9, 0xb6, 0xf9, 0xc9, 0xb8, - 0x63, 0x1f, 0xab, 0x01, 0x58, 0x80, 0x06, 0xb2, 0x7b, 0x96, 0xe9, 0xef, 0x6e, 0x24, 0x76, 0xe3, - 0x51, 0xbc, 0xb1, 0xcb, 0x45, 0x2d, 0x42, 0x45, 0x68, 0x11, 0xe6, 0xa0, 0xda, 0x77, 0xb6, 0x4d, - 0x2b, 0x8a, 0x7b, 0x06, 0x91, 0x98, 0x47, 0x16, 0x22, 0xbd, 0x42, 0x1c, 0xf3, 0x11, 0x22, 0x69, - 0x1b, 0x6a, 0xb9, 0x6d, 0x43, 0x9d, 0x6f, 0x1b, 0x44, 0xc3, 0x43, 0xc6, 0xf0, 0xd4, 0x5c, 0x8d, - 0xb8, 0x0e, 0x0d, 0x5a, 0xe2, 0x7f, 0x21, 0x41, 0x33, 0x71, 0x05, 0xed, 0xa9, 0x0b, 0x4d, 0x99, - 0x8e, 0x4e, 0x39, 0x27, 0x3a, 0xe3, 0x98, 0x2a, 0xf1, 0x31, 0x85, 0xa3, 0xd0, 0xf1, 0x4d, 0x6e, - 0x63, 0x13, 0xc3, 0x78, 0x36, 0x0b, 0xe9, 0x9c, 0x21, 0x29, 0xc4, 0x6d, 0x63, 0xab, 0xc2, 0x36, - 0x36, 0xbd, 0x52, 0xff, 0x44, 0x82, 0xe3, 0x38, 0x02, 0x32, 0x6a, 0x6c, 0x42, 0xd3, 0x49, 0x45, - 0x09, 0x5b, 0xca, 0x9e, 0xce, 0x59, 0x8a, 0xd2, 0x01, 0xa5, 0x65, 0x88, 0x31, 0x43, 0x23, 0x35, - 0x09, 0x5b, 0xdb, 0xf2, 0x18, 0xa6, 0xe5, 0xd1, 0x32, 0xc4, 0xea, 0xcf, 0x24, 0x68, 0xd2, 0xc5, - 0x93, 0xab, 0x01, 0x47, 0x2e, 0xf6, 0x2d, 0x38, 0x9e, 0x9e, 0xf9, 0xba, 0xe9, 0x07, 0x2d, 0x79, - 0xa1, 0x34, 0xaa, 0xe8, 0xb9, 0x0c, 0xd4, 0x1f, 0xc8, 0xf0, 0xf8, 0x56, 0x68, 0x59, 0x6d, 0xe4, - 0xfb, 0x7a, 0x0f, 0x2d, 0x1f, 0x76, 0xd0, 0x3e, 0xfe, 0xa0, 0xa1, 0xfd, 0xc2, 0x18, 0xc2, 0x9d, - 0x14, 0x69, 0x45, 0x4c, 0xc7, 0x8e, 0x43, 0x88, 0x47, 0xe1, 0x94, 0xf3, 0x29, 0x9f, 0x56, 0x69, - 0xa1, 0x84, 0x17, 0x69, 0x06, 0x2a, 0x9f, 0x80, 0x49, 0xd2, 0x25, 0xb0, 0x69, 0x5a, 0x65, 0xa2, - 0xc0, 0xab, 0xb9, 0x7d, 0x49, 0xae, 0x54, 0xb4, 0xdf, 0x60, 0xf0, 0x65, 0x3b, 0xf0, 0x0e, 0x35, - 0x81, 0xe3, 0xfc, 0xdb, 0x30, 0x9b, 0x19, 0xa2, 0x34, 0xa1, 0xb4, 0x87, 0x0e, 0x99, 0x1e, 0xf8, - 0xbf, 0xca, 0xff, 0x40, 0xe5, 0x00, 0x6f, 0x50, 0x99, 0xf7, 0xe7, 0x73, 0x24, 0x60, 0x32, 0x6b, - 0x74, 0xe0, 0xcb, 0xf2, 0xff, 0x4b, 0xea, 0xd3, 0xb1, 0x62, 0xbc, 0x8e, 0x92, 0xa0, 0xa3, 0x7a, - 0x0d, 0x1a, 0x6d, 0xbf, 0xb7, 0xaa, 0x07, 0x3a, 0x19, 0xf8, 0x2a, 0x34, 0xfa, 0x09, 0x48, 0x06, - 0xe7, 0xcf, 0xc7, 0x88, 0x34, 0x7e, 0xb8, 0xfa, 0x81, 0x0c, 0xad, 0x7c, 0x53, 0xf8, 0x2e, 0x96, - 0x01, 0x79, 0xde, 0x8a, 0x63, 0x20, 0xa2, 0x5a, 0x45, 0x8b, 0x40, 0xec, 0x3b, 0xe4, 0x79, 0x78, - 0x7d, 0x63, 0x6d, 0x3c, 0x85, 0x94, 0x45, 0x28, 0x5b, 0x91, 0x5b, 0x06, 0x4b, 0x41, 0xc6, 0x29, - 0x7d, 0x68, 0x12, 0xeb, 0x72, 0x0a, 0x31, 0x9f, 0x2d, 0x8d, 0xec, 0x33, 0xdf, 0xa5, 0x4e, 0xe3, - 0x78, 0x50, 0xc7, 0x65, 0x58, 0xcf, 0x77, 0xe1, 0x44, 0xee, 0xd0, 0x1c, 0x07, 0x3e, 0x2f, 0x3a, - 0xf0, 0x54, 0xb1, 0x2a, 0x69, 0x27, 0xba, 0xa0, 0xac, 0xa1, 0xa0, 0xad, 0xdf, 0x5d, 0xb2, 0x8d, - 0xb6, 0x69, 0x77, 0xd0, 0x3e, 0x8e, 0xf6, 0x05, 0x68, 0xb0, 0xe3, 0x86, 0xd8, 0x4d, 0x75, 0x8d, - 0x47, 0x15, 0x9e, 0x42, 0xa4, 0xf2, 0xa1, 0x94, 0xc9, 0x07, 0xf5, 0x12, 0x4c, 0xf2, 0xd3, 0x91, - 0x05, 0x46, 0xbf, 0xdb, 0x41, 0xfb, 0x44, 0xa1, 0x29, 0x8d, 0x41, 0x04, 0x4f, 0x46, 0xb0, 0xdd, - 0x07, 0x83, 0xd4, 0xdf, 0xc8, 0x70, 0x2c, 0x23, 0xb2, 0xef, 0xde, 0x2b, 0x1f, 0x3e, 0x5e, 0x4a, - 0x45, 0xf1, 0x52, 0x16, 0xe2, 0x65, 0x0f, 0x66, 0xa9, 0x93, 0xb8, 0xa9, 0x5b, 0x15, 0x12, 0x00, - 0xaf, 0xe5, 0x6d, 0x06, 0xb2, 0x42, 0x32, 0xdf, 0x73, 0x58, 0xea, 0xfc, 0x2c, 0xdf, 0x79, 0x04, - 0x73, 0xf9, 0x83, 0x73, 0xdc, 0xff, 0x82, 0xe8, 0xfe, 0xff, 0xc8, 0x73, 0x3f, 0x2f, 0x09, 0xe7, - 0xff, 0xcf, 0x48, 0x30, 0x83, 0xab, 0x6a, 0x07, 0xd9, 0x46, 0xdb, 0xef, 0x11, 0x4b, 0x2e, 0x40, - 0x83, 0x32, 0x68, 0xfb, 0xbd, 0x64, 0x77, 0xc8, 0xa1, 0xf0, 0x88, 0xae, 0x65, 0xe2, 0xea, 0x49, - 0x46, 0xb0, 0xaa, 0xc7, 0xa1, 0xf0, 0x0a, 0xe9, 0x23, 0x76, 0x34, 0x83, 0xcd, 0x5b, 0xd2, 0x62, - 0x98, 0xad, 0x78, 0xe5, 0x78, 0xc5, 0x7b, 0x7f, 0x02, 0x26, 0x58, 0x78, 0x92, 0x55, 0x12, 0x6f, - 0xd0, 0xe3, 0x3a, 0x4b, 0x21, 0xda, 0x04, 0x77, 0x0f, 0x92, 0x78, 0xa3, 0x10, 0x7f, 0x4e, 0x56, - 0x12, 0xcf, 0xc9, 0x52, 0x32, 0x96, 0xb3, 0x32, 0xa6, 0xf4, 0xac, 0x64, 0xf5, 0xc4, 0x3d, 0x1f, - 0x69, 0x83, 0xb6, 0x2c, 0x3d, 0xd8, 0x71, 0xbc, 0x3e, 0xdb, 0x6f, 0x57, 0xb4, 0x0c, 0x1e, 0xf7, - 0x99, 0x14, 0x17, 0x6f, 0x14, 0xe8, 0x9a, 0x9e, 0xc2, 0xe2, 0xb6, 0x9c, 0x62, 0xa2, 0x0d, 0x03, - 0x3d, 0x30, 0x11, 0x91, 0x54, 0x36, 0xdf, 0x37, 0x1d, 0x9b, 0xb4, 0xac, 0x74, 0x5f, 0xc0, 0xa3, - 0xb0, 0xe6, 0x7d, 0xbf, 0x77, 0xc5, 0x73, 0xfa, 0x6c, 0x2f, 0x16, 0x81, 0x44, 0x73, 0xc7, 0x0e, - 0xa2, 0x76, 0x97, 0x1e, 0x95, 0xf0, 0x28, 0x4c, 0xcb, 0x40, 0xd2, 0x41, 0x4d, 0x6a, 0x11, 0x88, - 0x83, 0xcb, 0x47, 0xfb, 0xac, 0xd3, 0xc7, 0xff, 0x15, 0x3c, 0x39, 0x93, 0xf2, 0xa4, 0xd8, 0xba, - 0x35, 0xc9, 0x57, 0xbe, 0x75, 0x4b, 0x7a, 0x9e, 0x59, 0xa1, 0xe7, 0x59, 0x82, 0x09, 0xc7, 0xc5, - 0xf5, 0xc0, 0x6f, 0x29, 0x24, 0x7f, 0xfe, 0xab, 0xb8, 0x62, 0x2d, 0x6e, 0xd2, 0x91, 0x34, 0x53, - 0x22, 0x3a, 0xe5, 0x3a, 0xcc, 0x38, 0x3b, 0x3b, 0x96, 0x69, 0xa3, 0xad, 0xd0, 0xdf, 0x25, 0xfb, - 0xf2, 0x63, 0x24, 0xfa, 0xd5, 0xbc, 0xae, 0x42, 0x1c, 0xa9, 0xa5, 0x49, 0x71, 0x2b, 0xa8, 0x07, - 0x74, 0x47, 0x44, 0x2a, 0xde, 0x71, 0x52, 0xf1, 0x04, 0x1c, 0x39, 0x70, 0xe4, 0x2a, 0xff, 0x09, - 0x62, 0x38, 0x1e, 0x45, 0xb9, 0x04, 0x7a, 0x77, 0x17, 0x91, 0x13, 0xa6, 0xd6, 0x1c, 0x6d, 0x28, - 0x79, 0x1c, 0x0b, 0xfe, 0xc7, 0xe3, 0x6e, 0xb6, 0x05, 0x13, 0xa6, 0xaf, 0x21, 0xbd, 0x1b, 0xb4, - 0xce, 0x2e, 0x48, 0x67, 0x6b, 0x5a, 0x04, 0x2a, 0x17, 0xe1, 0xb8, 0xe9, 0x5f, 0xbe, 0x1b, 0x20, - 0xcf, 0xd6, 0x2d, 0xfc, 0xaf, 0xed, 0x13, 0x8b, 0x3d, 0x43, 0x86, 0xe5, 0x7e, 0x53, 0x16, 0x41, - 0xc1, 0x51, 0x60, 0x7a, 0x7e, 0xd0, 0x76, 0x0c, 0x73, 0xe7, 0x90, 0x38, 0xe6, 0x1c, 0x71, 0x4c, - 0xce, 0x97, 0xf9, 0x97, 0x61, 0x92, 0x37, 0x6f, 0x4e, 0x6d, 0x39, 0xce, 0xd7, 0x96, 0x1a, 0x5f, - 0x3a, 0xbe, 0x2e, 0xc1, 0x4c, 0xca, 0xb0, 0x78, 0x74, 0x60, 0x06, 0x16, 0x62, 0x1c, 0x28, 0x80, - 0x37, 0x72, 0x06, 0xf2, 0xbb, 0x2c, 0x75, 0xc9, 0xff, 0x99, 0x1d, 0x4a, 0xb1, 0x1d, 0x54, 0x98, - 0x34, 0x37, 0x3b, 0x98, 0x51, 0xc7, 0x09, 0x6d, 0x23, 0xbe, 0x2f, 0xe0, 0x70, 0xe4, 0x84, 0x61, - 0xb3, 0xb3, 0xac, 0x1b, 0x3d, 0x44, 0x6f, 0x8f, 0x2a, 0x44, 0x26, 0x11, 0xa9, 0x1a, 0x50, 0xbb, - 0x61, 0xba, 0xfe, 0x8a, 0xd3, 0xef, 0xe3, 0x00, 0x34, 0x50, 0x80, 0xb7, 0x1c, 0x12, 0x71, 0x17, - 0x83, 0xb0, 0x2f, 0x0d, 0xb4, 0xa3, 0x87, 0x56, 0x80, 0x87, 0x46, 0x05, 0x8c, 0x43, 0x91, 0xd3, - 0x0e, 0xdf, 0xb1, 0x57, 0x29, 0x35, 0x95, 0x93, 0xc3, 0xa8, 0xbf, 0x92, 0xa1, 0x49, 0x0a, 0xf4, - 0x0a, 0x09, 0x77, 0x83, 0x10, 0x5d, 0x84, 0x0a, 0x29, 0x3f, 0xac, 0xc1, 0x1d, 0x7c, 0x44, 0x44, - 0x87, 0x2a, 0x97, 0xa0, 0xea, 0xb8, 0xa4, 0x2b, 0xa6, 0xd5, 0xfb, 0x4c, 0x11, 0x91, 0x78, 0x43, - 0xa0, 0x31, 0x2a, 0xe5, 0x0a, 0x40, 0x3f, 0x69, 0x82, 0x69, 0x2f, 0x33, 0x2a, 0x0f, 0x8e, 0x12, - 0x1b, 0x37, 0x5e, 0xa6, 0xe3, 0x6b, 0x82, 0x92, 0x26, 0x22, 0x95, 0x0d, 0x98, 0x26, 0x62, 0x6f, - 0x46, 0x67, 0x85, 0xc4, 0x07, 0xa3, 0xcf, 0x98, 0xa2, 0x56, 0xbf, 0x23, 0x31, 0x33, 0xe2, 0xaf, - 0x1d, 0x44, 0x6d, 0x9f, 0x98, 0x44, 0x1a, 0xcb, 0x24, 0xf3, 0x50, 0xeb, 0x87, 0xdc, 0xd1, 0x65, - 0x49, 0x8b, 0xe1, 0xc4, 0x45, 0xa5, 0x91, 0x5d, 0xa4, 0x7e, 0x57, 0x82, 0xd6, 0xeb, 0x8e, 0x69, - 0x93, 0x0f, 0x4b, 0xae, 0x6b, 0xb1, 0xdb, 0xa4, 0xb1, 0x7d, 0xfe, 0x31, 0xa8, 0xeb, 0x94, 0x8d, - 0x1d, 0x30, 0xb7, 0x8f, 0x70, 0x1c, 0x99, 0xd0, 0x70, 0x67, 0x42, 0x25, 0xfe, 0x4c, 0x48, 0x7d, - 0x4f, 0x82, 0x69, 0x6a, 0x94, 0x37, 0x42, 0x33, 0x18, 0x5b, 0xbe, 0x65, 0xa8, 0xed, 0x87, 0x66, - 0x30, 0x46, 0x54, 0xc6, 0x74, 0xd9, 0x78, 0x2a, 0xe5, 0xc4, 0x93, 0xfa, 0x81, 0x04, 0x27, 0xd3, - 0x66, 0x5d, 0xea, 0x76, 0x91, 0x7b, 0x3f, 0x53, 0x4a, 0x38, 0x13, 0x2b, 0xe7, 0x9c, 0x89, 0x79, - 0xa8, 0x8b, 0xcc, 0x03, 0xe4, 0x2d, 0xf9, 0x6c, 0x93, 0xcf, 0x61, 0x72, 0x55, 0xd2, 0xd0, 0xbb, - 0xa8, 0xfb, 0xf0, 0xaa, 0xf4, 0x39, 0x19, 0x9e, 0x58, 0x8b, 0x13, 0xf7, 0x86, 0xa7, 0xdb, 0xfe, - 0x0e, 0xf2, 0xbc, 0xfb, 0xa8, 0xcf, 0x75, 0x98, 0xb2, 0xd1, 0x9d, 0x44, 0x26, 0x96, 0xce, 0xa3, - 0xb2, 0x11, 0x89, 0x47, 0xab, 0x7d, 0xea, 0x3f, 0x25, 0x68, 0x52, 0x3e, 0xd7, 0xcc, 0xee, 0xde, - 0x7d, 0x54, 0x7e, 0x03, 0xa6, 0xf7, 0x88, 0x04, 0x18, 0x1a, 0xa3, 0xec, 0xa7, 0xa8, 0x47, 0x54, - 0xff, 0x43, 0x09, 0x66, 0xa3, 0x4b, 0xf0, 0x03, 0xf3, 0x7e, 0x06, 0xf3, 0x16, 0xcc, 0xd0, 0x4b, - 0x85, 0x71, 0x0d, 0x90, 0x26, 0x1f, 0xd1, 0x02, 0x3f, 0x96, 0x60, 0x86, 0x72, 0xba, 0x6c, 0x07, - 0xc8, 0x1b, 0x5b, 0xff, 0xab, 0xd0, 0x40, 0x76, 0xe0, 0xe9, 0xf6, 0x38, 0x15, 0x96, 0x27, 0x1d, - 0xb1, 0xc8, 0xbe, 0x27, 0x81, 0x42, 0x58, 0xad, 0x9a, 0x7e, 0xdf, 0xf4, 0xfd, 0xfb, 0xe8, 0xba, - 0xd1, 0x04, 0xfe, 0x96, 0x0c, 0xc7, 0x39, 0x2e, 0xed, 0x30, 0x78, 0xd0, 0x45, 0x56, 0x56, 0xa1, - 0x8e, 0x7b, 0x0c, 0xfe, 0xca, 0x77, 0xd4, 0x89, 0x12, 0x42, 0xdc, 0x05, 0x13, 0xa0, 0x83, 0xba, - 0x8e, 0x6d, 0xd0, 0x52, 0x3c, 0xa5, 0x09, 0x38, 0x5c, 0x86, 0xe6, 0x39, 0x36, 0x2b, 0xba, 0xdd, - 0x45, 0xd6, 0x23, 0x63, 0x22, 0xf5, 0xfb, 0x12, 0x4c, 0xd3, 0x21, 0x0f, 0xbe, 0xca, 0xea, 0x0f, - 0x25, 0x16, 0xc8, 0x0f, 0x8d, 0x97, 0x70, 0x78, 0xcd, 0x71, 0x5c, 0xf8, 0xbe, 0xfc, 0xc1, 0x0d, - 0xad, 0xab, 0xd0, 0xe8, 0xee, 0xea, 0x76, 0x6f, 0xac, 0xe0, 0xe2, 0x49, 0xd5, 0x00, 0x1e, 0xe7, - 0xef, 0x20, 0x56, 0xe8, 0x27, 0xa2, 0xfe, 0x73, 0x29, 0x55, 0x06, 0x3e, 0xe9, 0xb8, 0x37, 0xa3, - 0xef, 0xc1, 0x2c, 0xbd, 0x14, 0xe7, 0x7a, 0x46, 0xa5, 0x05, 0x13, 0xba, 0x41, 0x0f, 0x5e, 0x24, - 0x42, 0x14, 0x81, 0xe2, 0xa3, 0x09, 0xf6, 0x3c, 0x2f, 0x79, 0x34, 0x71, 0x0a, 0x40, 0x37, 0x8c, - 0x5b, 0x8e, 0x67, 0x98, 0x76, 0xb4, 0x41, 0xe0, 0x30, 0xea, 0xeb, 0x30, 0x79, 0xc5, 0x73, 0xfa, - 0x37, 0xb8, 0xeb, 0xed, 0x81, 0x17, 0xf0, 0xfc, 0xd5, 0xb8, 0x2c, 0x5e, 0x8d, 0xab, 0xef, 0xc0, - 0x89, 0x8c, 0xe0, 0xc4, 0x58, 0x2b, 0xf4, 0xd6, 0x3e, 0x9a, 0x84, 0x85, 0x4c, 0xde, 0xd1, 0x24, - 0x2f, 0x8b, 0x26, 0x10, 0xa9, 0x9f, 0x95, 0xe0, 0xa9, 0x0c, 0xfb, 0x25, 0xd7, 0xf5, 0x9c, 0x03, - 0xe6, 0x93, 0xa3, 0x98, 0x46, 0x6c, 0x8e, 0xe5, 0x54, 0x73, 0x9c, 0x2f, 0x84, 0xd0, 0xd0, 0x7f, - 0x04, 0x42, 0x7c, 0x4f, 0x82, 0x19, 0x26, 0x84, 0x61, 0xb0, 0x69, 0x5f, 0x80, 0x2a, 0x7d, 0x37, - 0xc4, 0x26, 0x7c, 0x2a, 0x77, 0xc2, 0xe8, 0xbd, 0x93, 0xc6, 0x06, 0x67, 0x23, 0x52, 0xce, 0xcb, - 0xa8, 0x97, 0xe2, 0x60, 0x1f, 0xf9, 0x65, 0x0f, 0x23, 0x50, 0x3f, 0x1e, 0x05, 0xf3, 0x2a, 0xb2, - 0xd0, 0x51, 0xda, 0x48, 0xbd, 0x09, 0xd3, 0xe4, 0x11, 0x53, 0x62, 0x83, 0x23, 0x61, 0x7b, 0x0b, - 0x9a, 0x84, 0xed, 0x91, 0xcb, 0x1b, 0x67, 0x07, 0xb6, 0x0f, 0x5f, 0x4a, 0x8e, 0x84, 0xfb, 0xb3, - 0x70, 0x2c, 0xb2, 0x3d, 0x7d, 0x18, 0x4c, 0x79, 0x17, 0x5c, 0x55, 0xaa, 0xdf, 0x90, 0x60, 0x6e, - 0xc5, 0xb1, 0x0f, 0x90, 0xe7, 0x0b, 0x8f, 0x89, 0x29, 0x89, 0x90, 0xfd, 0x0c, 0x52, 0x16, 0x41, - 0xe9, 0x72, 0x14, 0xec, 0x70, 0x54, 0x26, 0x87, 0xa3, 0x39, 0x5f, 0x94, 0xe7, 0xe1, 0x44, 0x48, - 0xb8, 0xde, 0xb4, 0x3d, 0xa4, 0x1b, 0xe4, 0x3c, 0x8e, 0x2b, 0x7a, 0xf9, 0x1f, 0xd5, 0x77, 0x61, - 0x9e, 0x97, 0xab, 0x83, 0x82, 0x2d, 0xcf, 0x3c, 0xe0, 0x64, 0x63, 0x27, 0xff, 0x92, 0x70, 0xf2, - 0x9f, 0xdc, 0x14, 0xc8, 0xc2, 0x4d, 0xc1, 0x49, 0xa8, 0x9b, 0x3e, 0x63, 0x40, 0xe6, 0xad, 0x69, - 0x09, 0x42, 0xd5, 0x61, 0x96, 0x7a, 0x99, 0x5d, 0xcd, 0x91, 0x29, 0xe6, 0xa1, 0x46, 0x43, 0x37, - 0x9e, 0x24, 0x86, 0x0b, 0x2f, 0xba, 0x0a, 0xaf, 0x75, 0xd5, 0x0e, 0xcc, 0xb2, 0xa7, 0x4d, 0x5b, - 0x7a, 0xcf, 0xb4, 0x69, 0x2d, 0x3f, 0x05, 0xe0, 0xea, 0xbd, 0xe8, 0xa1, 0x25, 0xbd, 0xa0, 0xe4, - 0x30, 0xf8, 0xbb, 0xbf, 0xeb, 0xdc, 0x61, 0xdf, 0x65, 0xfa, 0x3d, 0xc1, 0xa8, 0x6f, 0x82, 0xa2, - 0x21, 0xdf, 0x75, 0x6c, 0x1f, 0x71, 0x5c, 0x17, 0xa0, 0xb1, 0x12, 0x7a, 0x1e, 0xb2, 0xf1, 0x54, - 0xd1, 0x6b, 0x41, 0x1e, 0x85, 0xf9, 0x76, 0x12, 0xbe, 0xf4, 0xee, 0x82, 0xc3, 0xa8, 0x7f, 0xaa, - 0x42, 0xbd, 0x63, 0xf6, 0x6c, 0xdd, 0xd2, 0xd0, 0xbe, 0xf2, 0x2a, 0x54, 0xe9, 0xce, 0x88, 0x05, - 0x64, 0xde, 0x59, 0x3a, 0x1d, 0x4d, 0xb7, 0x80, 0x1a, 0xda, 0xbf, 0xfa, 0x98, 0xc6, 0x68, 0x94, - 0x37, 0xa2, 0x07, 0x60, 0xeb, 0xf4, 0xa4, 0x8c, 0x2d, 0x93, 0xcf, 0x0c, 0x61, 0xc2, 0x46, 0x53, - 0x5e, 0x22, 0x07, 0x2c, 0x50, 0x97, 0x74, 0x4e, 0xac, 0x0a, 0x15, 0x0b, 0x44, 0x1b, 0x2c, 0x26, - 0x10, 0xa5, 0xc1, 0xd4, 0x3a, 0x39, 0x4b, 0x62, 0x0d, 0x41, 0x31, 0x35, 0x3d, 0x72, 0x62, 0xd4, - 0x94, 0x06, 0x53, 0xef, 0x86, 0x76, 0xef, 0xa6, 0xcb, 0x8e, 0x38, 0x8b, 0xa9, 0xaf, 0x92, 0x61, - 0x8c, 0x9a, 0xd2, 0x60, 0x6a, 0x8f, 0xac, 0x11, 0xc4, 0xe8, 0x83, 0xa8, 0xe9, 0x52, 0xc2, 0xa8, - 0x29, 0x8d, 0xf2, 0x16, 0x34, 0x7b, 0x28, 0xd0, 0x1c, 0xa7, 0xbf, 0x7c, 0xb8, 0xc6, 0xee, 0xb7, - 0xe8, 0x7b, 0xf7, 0xf3, 0x85, 0x7c, 0xd6, 0x52, 0x04, 0x94, 0x63, 0x86, 0x8f, 0xf2, 0x29, 0x78, - 0xca, 0xb1, 0x31, 0x6a, 0x4b, 0xf7, 0x02, 0xb3, 0x6b, 0xba, 0xba, 0x1d, 0xac, 0x38, 0xb6, 0x4d, - 0xd6, 0x33, 0x0d, 0xed, 0xb3, 0x17, 0xf1, 0x2f, 0x16, 0x4e, 0xb4, 0x39, 0x88, 0xfa, 0xea, 0x63, - 0xda, 0x60, 0xf6, 0xca, 0x17, 0x25, 0x58, 0xc8, 0x8c, 0x58, 0x35, 0xfd, 0x2e, 0x2f, 0x03, 0x7d, - 0x4d, 0xff, 0xd2, 0xe8, 0x32, 0xa4, 0x18, 0x5c, 0x7d, 0x4c, 0x1b, 0x3a, 0x09, 0xb3, 0xf2, 0x0d, - 0x67, 0x0f, 0xd9, 0xcb, 0x87, 0x78, 0xec, 0xfa, 0x2a, 0xb9, 0x4b, 0x1b, 0x62, 0x65, 0x81, 0x20, - 0xb1, 0xb2, 0x80, 0x5e, 0xae, 0xc3, 0x84, 0xab, 0x1f, 0x5a, 0x8e, 0x6e, 0xa8, 0x7f, 0x2d, 0x03, - 0x44, 0xae, 0xf6, 0x49, 0x47, 0x2c, 0x24, 0xd9, 0xe9, 0xa1, 0x49, 0xe6, 0x5a, 0x87, 0x5c, 0x9a, - 0x75, 0xf2, 0xd3, 0xec, 0xbf, 0x47, 0x4d, 0x33, 0xca, 0x2d, 0x95, 0x68, 0x97, 0x52, 0x89, 0x76, - 0x7a, 0x68, 0xa2, 0x31, 0xa1, 0x58, 0xaa, 0x5d, 0x4a, 0xa5, 0xda, 0xe9, 0xa1, 0xa9, 0xc6, 0xe8, - 0x59, 0xb2, 0x5d, 0x4a, 0x25, 0xdb, 0xe9, 0xa1, 0xc9, 0xc6, 0xe8, 0x59, 0xba, 0x5d, 0x4a, 0xa5, - 0xdb, 0xe9, 0xa1, 0xe9, 0xc6, 0xe8, 0x59, 0xc2, 0xbd, 0x53, 0x98, 0x70, 0x8b, 0xf7, 0x90, 0x70, - 0x94, 0x67, 0x36, 0xe5, 0xde, 0xc9, 0x09, 0xb4, 0xda, 0x70, 0xee, 0xa9, 0x40, 0x4b, 0xb8, 0x17, - 0x86, 0xda, 0xe7, 0x4b, 0x30, 0x4d, 0xdc, 0x4d, 0x57, 0x65, 0x7b, 0xc7, 0xc9, 0x3e, 0xcb, 0x95, - 0x72, 0x9e, 0xe5, 0x2a, 0xe7, 0x61, 0x96, 0x22, 0x10, 0x77, 0x0b, 0x4a, 0x17, 0xfa, 0xec, 0x07, - 0x72, 0xef, 0x1b, 0xfa, 0x81, 0xd3, 0x5f, 0xd5, 0x03, 0x3d, 0xda, 0x61, 0x24, 0x18, 0xfe, 0x56, - 0xbe, 0x9c, 0xf9, 0xf5, 0x8a, 0x47, 0xf5, 0xaf, 0xb0, 0xd5, 0x9c, 0x40, 0x98, 0x22, 0x30, 0xfb, - 0xc8, 0x09, 0x03, 0xb6, 0x48, 0x45, 0x20, 0x7d, 0x4b, 0x69, 0x98, 0x3a, 0xb9, 0xcb, 0x66, 0x0f, - 0x0d, 0x63, 0x04, 0x59, 0x57, 0x93, 0xbb, 0x79, 0xf6, 0xeb, 0x92, 0x04, 0x33, 0xc2, 0x3d, 0x3a, - 0xf9, 0xa1, 0x92, 0x19, 0x98, 0xfc, 0x03, 0xc4, 0x8a, 0x26, 0xe0, 0x70, 0x1f, 0xb4, 0x1d, 0xfa, - 0x87, 0xd7, 0x4d, 0x9b, 0x37, 0x4f, 0x83, 0xf6, 0x41, 0xd9, 0x2f, 0xea, 0x9f, 0x25, 0x38, 0xc6, - 0xd5, 0x9d, 0x36, 0x0a, 0x74, 0x62, 0x17, 0xe1, 0x19, 0xb9, 0x74, 0x6f, 0xcf, 0xc8, 0xb7, 0x60, - 0xa6, 0x27, 0x6e, 0xcb, 0xef, 0x71, 0x47, 0x9d, 0x26, 0x17, 0xde, 0xc4, 0x97, 0xee, 0xf9, 0x4d, - 0xbc, 0xfa, 0x25, 0x19, 0x66, 0x52, 0xcd, 0xc0, 0xc0, 0x4e, 0x6a, 0x09, 0xc0, 0x8c, 0x43, 0x73, - 0xc0, 0xad, 0x97, 0x18, 0xbf, 0x1a, 0x47, 0x94, 0x77, 0xe9, 0x5f, 0x1a, 0xff, 0xd2, 0xff, 0x2a, - 0x34, 0xdc, 0xc4, 0x49, 0x03, 0x0e, 0x0d, 0x72, 0x5c, 0xa9, 0xf1, 0xa4, 0xea, 0x97, 0x25, 0x98, - 0xcd, 0x94, 0x6c, 0x72, 0x19, 0x8e, 0x13, 0x35, 0xbe, 0x0c, 0xc7, 0x00, 0x97, 0x01, 0x72, 0x3a, - 0x03, 0x2c, 0xf3, 0x80, 0xff, 0xf5, 0x0e, 0x03, 0x0b, 0xa2, 0xaf, 0x5c, 0x18, 0x7d, 0x5f, 0x91, - 0x61, 0x2e, 0xbf, 0xc1, 0x7a, 0x54, 0xfd, 0xf3, 0x55, 0x09, 0x5a, 0x45, 0x6b, 0xe1, 0x7d, 0x73, - 0x53, 0x92, 0x3f, 0x71, 0xef, 0xfa, 0xa8, 0xfa, 0xe7, 0x58, 0x94, 0x3e, 0x5c, 0x73, 0xa1, 0xbe, - 0x1f, 0xdb, 0x27, 0xee, 0xce, 0x1f, 0x51, 0xfb, 0x28, 0xe7, 0xa0, 0x49, 0xd5, 0xe4, 0xde, 0xa1, - 0xd1, 0xcd, 0x5e, 0x06, 0xaf, 0xbe, 0x1d, 0xd9, 0x92, 0x6b, 0xb4, 0x8e, 0x2a, 0xc6, 0xd5, 0x9f, - 0x4b, 0x91, 0x4f, 0xe2, 0x3d, 0xcf, 0x43, 0xe5, 0x93, 0x24, 0xd2, 0xb8, 0x36, 0x92, 0x8b, 0xb4, - 0x78, 0x2f, 0xf6, 0xef, 0x48, 0x1b, 0x1e, 0x69, 0xb1, 0x2d, 0xb9, 0x96, 0x5a, 0xfd, 0xb6, 0x04, - 0x4f, 0x14, 0xee, 0x47, 0x07, 0x5a, 0x95, 0x6b, 0x1a, 0x65, 0xb1, 0x69, 0x4c, 0xa9, 0x57, 0x1a, - 0xbf, 0xd0, 0xfc, 0x52, 0x82, 0x27, 0x07, 0x34, 0xef, 0x29, 0xcf, 0x4a, 0xe3, 0x78, 0x36, 0x25, - 0xac, 0x5c, 0x78, 0x31, 0x3d, 0xd4, 0x17, 0x49, 0x7a, 0x96, 0xf8, 0xf4, 0x54, 0x7f, 0x2b, 0xc1, - 0xd3, 0x23, 0xec, 0xc4, 0x1f, 0x2c, 0x65, 0x0a, 0x1f, 0xea, 0xaa, 0xbf, 0x93, 0xe0, 0xcc, 0x68, - 0x9b, 0xfa, 0x87, 0x45, 0xa3, 0x9f, 0xf2, 0x39, 0x90, 0x3e, 0x2d, 0xe0, 0xdc, 0x2a, 0x09, 0x55, - 0x97, 0xcf, 0x0d, 0x39, 0x95, 0x1b, 0x47, 0x96, 0x01, 0xe9, 0x07, 0xfa, 0xe5, 0xec, 0x03, 0xfd, - 0x36, 0x97, 0x22, 0xd9, 0x1d, 0x68, 0xc1, 0x52, 0xc2, 0x2d, 0x19, 0xb2, 0xb8, 0x64, 0x7c, 0x1a, - 0xa6, 0x56, 0x91, 0xd5, 0xf6, 0x7b, 0xd1, 0x4f, 0x69, 0x8e, 0xf4, 0xb4, 0x75, 0x04, 0x7d, 0x96, - 0x61, 0x9a, 0x17, 0x60, 0x9c, 0x9f, 0x8a, 0xa8, 0xb7, 0xe0, 0x89, 0x0e, 0x0a, 0x96, 0x5c, 0x77, - 0x59, 0xef, 0xee, 0x61, 0x37, 0xdb, 0x46, 0x87, 0x3c, 0x65, 0x1e, 0xf4, 0xdb, 0x20, 0xbc, 0xb3, - 0xf4, 0x13, 0x02, 0xf6, 0x82, 0x56, 0xc0, 0xa9, 0x1b, 0x30, 0x5f, 0xc4, 0x78, 0x2c, 0x41, 0xff, - 0x26, 0xc3, 0x24, 0x79, 0x0f, 0x6c, 0xb4, 0xfd, 0x5e, 0x07, 0x91, 0x1f, 0xc4, 0xfb, 0xe4, 0x5a, - 0x30, 0xb1, 0x76, 0x04, 0xa7, 0x37, 0xc7, 0x72, 0x76, 0x73, 0xbc, 0x09, 0x80, 0x22, 0x6e, 0x3e, - 0x7b, 0x64, 0x73, 0x21, 0x27, 0xec, 0xf8, 0x29, 0x13, 0x80, 0xbd, 0xd9, 0xe6, 0x58, 0xe0, 0xf5, - 0xa5, 0xad, 0xdf, 0x6d, 0xfb, 0x3d, 0xee, 0x0f, 0x9d, 0xd0, 0xb7, 0x36, 0x19, 0x3c, 0xb6, 0x5f, - 0x4c, 0xb9, 0x11, 0xf6, 0xd9, 0x3a, 0x24, 0xe0, 0x52, 0x2f, 0xd0, 0xab, 0xe9, 0x17, 0xe8, 0xf3, - 0x6f, 0xc3, 0x4c, 0x4a, 0x9c, 0x9c, 0x37, 0xce, 0x17, 0xc5, 0xdf, 0x4f, 0x9c, 0x1c, 0xa4, 0x20, - 0xff, 0x02, 0xfa, 0x2f, 0x32, 0xd4, 0xe3, 0x0f, 0x4a, 0x1f, 0x4e, 0x78, 0x48, 0x27, 0x7f, 0xd9, - 0x24, 0x7e, 0x91, 0xcd, 0xfd, 0xca, 0xe9, 0xff, 0x06, 0x71, 0x5d, 0xd4, 0xf2, 0x28, 0xa9, 0xf9, - 0xf2, 0xb9, 0x8e, 0xf0, 0x1b, 0x8c, 0xfc, 0xc7, 0xe0, 0xa5, 0xa2, 0xc7, 0xe0, 0x99, 0xe7, 0xeb, - 0xe5, 0xc2, 0xe7, 0xeb, 0xf1, 0x1f, 0xad, 0x98, 0x47, 0x30, 0x5f, 0x2c, 0x7a, 0x8e, 0xa9, 0xff, - 0x57, 0x34, 0x75, 0xde, 0x15, 0xfa, 0x35, 0x74, 0x48, 0xff, 0x5c, 0x0a, 0x67, 0xe9, 0x1d, 0xa8, - 0x45, 0x68, 0x72, 0x54, 0x74, 0xe8, 0xa2, 0x6b, 0x31, 0xe3, 0x08, 0x14, 0xdf, 0xaa, 0xd7, 0x19, - 0x3d, 0x0e, 0x39, 0x4b, 0x0f, 0x90, 0x1f, 0x70, 0x21, 0x47, 0x8d, 0x90, 0xc1, 0x2f, 0x9f, 0x7f, - 0xeb, 0xdc, 0xa6, 0x8b, 0xec, 0xdb, 0xeb, 0xed, 0xcc, 0x9f, 0x6c, 0x7a, 0x25, 0x23, 0xe9, 0x76, - 0x95, 0x7c, 0x7f, 0xee, 0x5f, 0x01, 0x00, 0x00, 0xff, 0xff, 0x71, 0x3a, 0xae, 0x9b, 0x12, 0x4a, - 0x00, 0x00, -} diff --git a/tools/data-conversion/openim/proto/sdk_ws/ws.proto b/tools/data-conversion/openim/proto/sdk_ws/ws.proto deleted file mode 100644 index 95b956b0e6..0000000000 --- a/tools/data-conversion/openim/proto/sdk_ws/ws.proto +++ /dev/null @@ -1,754 +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. - -syntax = "proto3"; -import "Open-IM-Server/pkg/proto/sdk_ws/wrappers.proto"; -option go_package = "Open_IM/pkg/proto/sdk_ws;server_api_params"; -package server_api_params; - - -////////////////////////////////base/////////////////////////////// - - -message GroupInfo{ - string groupID = 1; - string groupName = 2; - string notification = 3; - string introduction = 4; - string faceURL = 5; - string ownerUserID = 6; - uint32 createTime = 7; - uint32 memberCount = 8; - string ex = 9; - int32 status = 10; - string creatorUserID = 11; - int32 groupType = 12; - int32 needVerification = 13; - int32 lookMemberInfo = 14; - int32 applyMemberFriend = 15; - uint32 notificationUpdateTime = 16; - string notificationUserID = 17; -} - -message GroupInfoForSet{ - string groupID = 1; - string groupName = 2; - string notification = 3; - string introduction = 4; - string faceURL = 5; - string ex = 6; - google.protobuf.Int32Value needVerification = 7; - google.protobuf.Int32Value lookMemberInfo = 8; - google.protobuf.Int32Value applyMemberFriend = 9; -} - - -message GroupMemberFullInfo { - string groupID = 1 ; - string userID = 2 ; - int32 roleLevel = 3; - int32 joinTime = 4; - string nickname = 5; - string faceURL = 6; - int32 appMangerLevel = 7; //if >0 - int32 joinSource = 8; - string operatorUserID = 9; - string ex = 10; - uint32 muteEndTime = 11; - string inviterUserID = 12; -} - -message PublicUserInfo{ - string userID = 1; - string nickname = 2; - string faceURL = 3; - int32 gender = 4; - string ex = 5; -} - -message UserInfo{ - string userID = 1; - string nickname = 2; - string faceURL = 3; - int32 gender = 4; - string phoneNumber = 5; - uint32 birth = 6; - string email = 7; - string ex = 8; - uint32 createTime = 9; - int32 appMangerLevel = 10; - int32 globalRecvMsgOpt = 11; - string birthStr = 12; -} - -message FriendInfo{ - string ownerUserID = 1; - string remark = 2; - uint32 createTime = 3; - UserInfo friendUser = 4; - int32 addSource = 5; - string operatorUserID = 6; - string ex = 7; -} - -message BlackInfo{ - string ownerUserID = 1; - uint32 createTime = 2; - PublicUserInfo blackUserInfo = 3; - int32 addSource = 4; - string operatorUserID = 5; - string ex = 6; -} - -message GroupRequest{ - PublicUserInfo userInfo = 1; - GroupInfo groupInfo = 2; - int32 handleResult = 3; - string reqMsg = 4; - string handleMsg = 5; - uint32 reqTime = 6; - string handleUserID = 7; - uint32 handleTime = 8; - string ex = 9; - int32 joinSource = 10; - string inviterUserID = 11; -} - -message FriendRequest{ - string fromUserID = 1; - string fromNickname = 2; - string fromFaceURL = 3; - int32 fromGender = 4; - string toUserID = 5; - string toNickname = 6; - string toFaceURL = 7; - int32 toGender = 8; - int32 handleResult = 9; - string reqMsg = 10; - uint32 createTime = 11; - string handlerUserID = 12; - string handleMsg = 13; - uint32 handleTime = 14; - string ex = 15; -} - -///////////////////////////////////organization///////////////////////////////////// - -message Department { - string departmentID = 1; - string faceURL = 2; - string name = 3; - string parentID = 4; - int32 order = 5; - int32 departmentType = 6; - uint32 createTime = 7; - uint32 subDepartmentNum = 8; - uint32 memberNum = 9; - string ex = 10; -} - - - -message OrganizationUser { - string userID = 1; - string nickname = 2; - string englishName = 3; - string faceURL = 4; - int32 gender = 5; - string mobile = 6; - string telephone = 7; - uint32 birth = 8; - string email = 9; - uint32 createTime = 10; - string ex = 11; - string birthStr = 12; -} - -message DepartmentMember { - string userID = 1; - string departmentID = 2; - int32 order = 3; - string position = 4; - int32 leader = 5; - int32 status = 6; - string ex = 7; -} - - -message UserDepartmentMember { - OrganizationUser organizationUser = 1; - DepartmentMember departmentMember = 2; -} - - -message UserInDepartment { - OrganizationUser organizationUser = 1; - repeated DepartmentMember departmentMemberList = 2; -} - - - - - -///////////////////////////////////organization end////////////////////////////////// - - - - - - -///////////////////////////////////base end///////////////////////////////////// -message PullMessageBySeqListReq{ - string userID = 1; - string operationID = 2; - repeated uint32 seqList = 3; - map groupSeqList = 4; -} - -message seqList { - repeated uint32 seqList = 1; -} - - -message MsgDataList { - repeated MsgData msgDataList = 1; -} - -message PullMessageBySeqListResp { - int32 errCode = 1; - string errMsg = 2; - repeated MsgData list = 3; - map groupMsgDataList = 4; -} - - - -message GetMaxAndMinSeqReq { - repeated string groupIDList = 1; - string userID = 2; - string operationID = 3; -} -message MaxAndMinSeq{ - uint32 maxSeq = 1; - uint32 minSeq = 2; -} -message GetMaxAndMinSeqResp { - uint32 maxSeq = 1; - uint32 minSeq = 2; - int32 errCode = 3; - string errMsg = 4; - map groupMaxAndMinSeq = 5; -} - -message UserSendMsgResp { - string serverMsgID = 1; - string clientMsgID = 2; - int64 sendTime = 3; - string ex = 4; -} - -message MsgData { - 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; - int32 msgFrom = 10; - int32 contentType = 11; - bytes content = 12; - uint32 seq = 14; - int64 sendTime = 15; - int64 createTime = 16; - int32 status = 17; - map options = 18; - OfflinePushInfo offlinePushInfo = 19; - repeated string atUserIDList = 20; - bytes msgDataList = 21; - string attachedInfo = 22; - string ex = 23; - - bool isReact = 40; - bool isExternalExtensions = 41; - int64 msgFirstModifyTime = 42; - -} -message OfflinePushInfo{ - string title = 1; - string desc = 2; - string ex = 3; - string iOSPushSound = 4; - bool iOSBadgeCount = 5; -} - - - - - - - - - -message TipsComm{ - bytes detail = 1; - string defaultTips = 2; - string jsonDetail = 3; -} - -//////////////////////group///////////////////// - - -// OnGroupCreated() -message GroupCreatedTips{ - GroupInfo group = 1; - GroupMemberFullInfo opUser = 2; - repeated GroupMemberFullInfo memberList = 3; - int64 operationTime = 4; - GroupMemberFullInfo groupOwnerUser = 5; -} - -// OnGroupInfoSet() -message GroupInfoSetTips{ - GroupMemberFullInfo opUser = 1; //who do this - int64 muteTime = 2; - GroupInfo group = 3; -} - -// OnJoinGroupApplication() -message JoinGroupApplicationTips{ - GroupInfo group = 1; - PublicUserInfo applicant = 2; - string reqMsg = 3; -} - -// OnQuitGroup() -//Actively leave the group -message MemberQuitTips{ - GroupInfo group = 1; - GroupMemberFullInfo quitUser = 2; - int64 operationTime = 3; -} - - -// OnApplicationGroupAccepted() -message GroupApplicationAcceptedTips{ - GroupInfo group = 1; - GroupMemberFullInfo opUser = 2; - string handleMsg = 4; - int32 receiverAs = 5; // admin(==1) or applicant(==0) -} - -// OnApplicationGroupRejected() -message GroupApplicationRejectedTips{ - GroupInfo group = 1; - GroupMemberFullInfo opUser = 2; - string handleMsg = 4; - int32 receiverAs = 5; // admin(==1) or applicant(==0) -} - -// OnTransferGroupOwner() -message GroupOwnerTransferredTips{ - GroupInfo group = 1; - GroupMemberFullInfo opUser = 2; - GroupMemberFullInfo newGroupOwner = 3; - int64 operationTime = 4; -} - - -// OnMemberKicked() -message MemberKickedTips{ - GroupInfo group = 1; - GroupMemberFullInfo opUser = 2; - repeated GroupMemberFullInfo kickedUserList = 3; - int64 operationTime = 4; -} - -// OnMemberInvited() -message MemberInvitedTips{ - GroupInfo group = 1; - GroupMemberFullInfo opUser = 2; - repeated GroupMemberFullInfo invitedUserList = 3; - int64 operationTime = 4; -} - -//Actively join the group -message MemberEnterTips{ - GroupInfo group = 1; - GroupMemberFullInfo entrantUser = 2; - int64 operationTime = 3; -} - -message GroupDismissedTips{ - GroupInfo group = 1; - GroupMemberFullInfo opUser = 2; - int64 operationTime = 3; -} - -message GroupMemberMutedTips{ - GroupInfo group = 1; - GroupMemberFullInfo opUser = 2; - int64 operationTime = 3; - GroupMemberFullInfo mutedUser = 4; - uint32 mutedSeconds = 5; -} - -message GroupMemberCancelMutedTips{ - GroupInfo group = 1; - GroupMemberFullInfo opUser = 2; - int64 operationTime = 3; - GroupMemberFullInfo mutedUser = 4; -} - -message GroupMutedTips{ - GroupInfo group = 1; - GroupMemberFullInfo opUser = 2; - int64 operationTime = 3; -} - -message GroupCancelMutedTips{ - GroupInfo group = 1; - GroupMemberFullInfo opUser = 2; - int64 operationTime = 3; -} - -message GroupMemberInfoSetTips{ - GroupInfo group = 1; - GroupMemberFullInfo opUser = 2; - int64 operationTime = 3; - GroupMemberFullInfo changedUser = 4; -} - - -message OrganizationChangedTips{ - UserInfo opUser = 2; - int64 operationTime = 3; -} - - -//////////////////////friend///////////////////// -//message FriendInfo{ -// UserInfo OwnerUser = 1; -// string Remark = 2; -// uint64 CreateTime = 3; -// UserInfo FriendUser = 4; -//} - -message FriendApplication{ - int64 addTime = 1; - string addSource = 2; - string addWording = 3; -} - -message FromToUserID{ - string fromUserID = 1; - string toUserID = 2; -} - -//FromUserID apply to add ToUserID -message FriendApplicationTips{ - FromToUserID fromToUserID = 1; -} - -//FromUserID accept or reject ToUserID -message FriendApplicationApprovedTips{ - FromToUserID fromToUserID = 1; - string handleMsg = 2; -} - -//FromUserID accept or reject ToUserID -message FriendApplicationRejectedTips{ - FromToUserID fromToUserID = 1; - string handleMsg = 2; -} - - -// FromUserID Added a friend ToUserID -message FriendAddedTips{ - FriendInfo friend = 1; - int64 operationTime = 2; - PublicUserInfo opUser = 3; //who do this - -} - -// FromUserID deleted a friend ToUserID -message FriendDeletedTips{ - FromToUserID fromToUserID = 1; -} - - - -message BlackAddedTips{ - FromToUserID fromToUserID = 1; -} - -message BlackDeletedTips{ - FromToUserID fromToUserID = 1; -} - -message FriendInfoChangedTips{ - FromToUserID fromToUserID = 1; -} -//////////////////////user///////////////////// -message UserInfoUpdatedTips{ - string userID = 1; -} - -//////////////////////conversation///////////////////// -message ConversationUpdateTips{ - string UserID = 1; - repeated string conversationIDList = 2; - int64 updateUnreadCountTime = 3; - - -} - -message ConversationSetPrivateTips{ - string recvID = 1; - string sendID = 2; - bool isPrivate = 3; -} - -////////////////////message/////////////////////// -message DeleteMessageTips{ - string opUserID = 1; - string userID = 2; - repeated uint32 seqList = 3; -} -///cms -message RequestPagination { - int32 pageNumber = 1; - int32 showNumber = 2; -} - -message ResponsePagination { - int32 CurrentPage = 5; - int32 ShowNumber = 6; -} - - -///////////////////signal////////////// -message SignalReq { - oneof payload { - SignalInviteReq invite = 1; - SignalInviteInGroupReq inviteInGroup = 2; - SignalCancelReq cancel = 3; - SignalAcceptReq accept = 4; - SignalHungUpReq hungUp = 5; - SignalRejectReq reject = 6; - SignalGetRoomByGroupIDReq getRoomByGroupID = 7; - - SignalOnRoomParticipantConnectedReq onRoomParticipantConnectedReq = 8; - SignalOnRoomParticipantDisconnectedReq onRoomParticipantDisconnectedReq = 9; - SignalGetTokenByRoomIDReq getTokenByRoomID = 10; - } -} - -message SignalResp { - oneof payload { - SignalInviteReply invite = 1; - SignalInviteInGroupReply inviteInGroup = 2; - SignalCancelReply cancel = 3; - SignalAcceptReply accept = 4; - SignalHungUpReply hungUp = 5; - SignalRejectReply reject = 6; - SignalGetRoomByGroupIDReply getRoomByGroupID = 7; - SignalGetTokenByRoomIDReply getTokenByRoomID = 8; - } -} - - -message InvitationInfo { - string inviterUserID = 1; - repeated string inviteeUserIDList = 2; - string customData = 3; - string groupID = 4; - string roomID = 5; - int32 timeout = 6; - string mediaType = 7; - int32 platformID = 8; - int32 sessionType = 9; - int32 initiateTime = 10; - repeated string busyLineUserIDList = 11; -} - -message ParticipantMetaData{ - GroupInfo groupInfo = 1; - GroupMemberFullInfo groupMemberInfo = 2; - PublicUserInfo userInfo = 3; -} - -message SignalInviteReq { - string opUserID = 1; - InvitationInfo invitation = 2; - OfflinePushInfo offlinePushInfo = 3; - ParticipantMetaData participant = 4; - -} - -message SignalInviteReply { - string token = 1; - string roomID = 2; - string liveURL = 3; - repeated string busyLineUserIDList = 4; -} - -message SignalInviteInGroupReq { - string opUserID = 1; - InvitationInfo invitation = 2; - OfflinePushInfo offlinePushInfo = 3; - ParticipantMetaData participant = 4; -} - -message SignalInviteInGroupReply { - string token = 1; - string roomID = 2; - string liveURL = 3; - repeated string busyLineUserIDList = 4; -} - -message SignalCancelReq { - string opUserID = 1; - InvitationInfo invitation = 2; - OfflinePushInfo offlinePushInfo = 3; - ParticipantMetaData participant = 4; -} - -message SignalCancelReply { - -} - -message SignalAcceptReq { - string opUserID = 1; - InvitationInfo invitation = 2; - OfflinePushInfo offlinePushInfo = 3; - ParticipantMetaData participant = 4; - int32 opUserPlatformID = 5; -} - -message SignalAcceptReply { - string token = 1; - string roomID = 2; - string liveURL = 3; -} - -message SignalHungUpReq { - string opUserID = 1; - InvitationInfo invitation = 2; - OfflinePushInfo offlinePushInfo = 3; -} - -message SignalHungUpReply { - -} - - -message SignalRejectReq { - string opUserID = 1; - InvitationInfo invitation = 2; - OfflinePushInfo offlinePushInfo = 3; - ParticipantMetaData participant = 4; - int32 opUserPlatformID = 5; -} - -message SignalRejectReply { - -} - -message SignalGetRoomByGroupIDReq { - string opUserID = 1; - string groupID = 2; - ParticipantMetaData participant = 3; -} - -message SignalGetRoomByGroupIDReply { - InvitationInfo invitation = 1; - repeated ParticipantMetaData participant = 2; - string roomID = 3; -} - -message SignalOnRoomParticipantConnectedReq { - InvitationInfo invitation = 1; - repeated ParticipantMetaData participant = 2; - string groupID = 3; -} - -message SignalOnRoomParticipantDisconnectedReq { - InvitationInfo invitation = 1; - repeated ParticipantMetaData participant = 2; - string groupID = 3; -} - -message SignalGetTokenByRoomIDReq { - string roomID = 1; - string opUserID = 2; - ParticipantMetaData participant = 3; - string operationID = 4; -} - -message SignalGetTokenByRoomIDReply { - string token = 1; - string liveURL = 2; -} - - -message DelMsgListReq{ - string opUserID = 1; - string userID = 2; - repeated uint32 seqList = 3; - string operationID = 4; -} - -message DelMsgListResp{ - int32 errCode = 1; - string errMsg = 2; -} - -message SetAppBackgroundStatusReq { - string userID = 1; - bool isBackground = 2; -} - -message SetAppBackgroundStatusResp { - int32 errCode = 1; - string errMsg = 2; -} - -message ExtendMsgSet { - string sourceID = 1; - int32 sessionType = 2; - map extendMsgs = 3; - int64 MaxMsgUpdateTime = 4; - int32 extendMsgNum = 5; - int64 createTime = 6; -} - -message ExtendMsg { - map reactionExtensionList = 1; - string clientMsgID = 2; - int64 msgFirstModifyTime = 3; - string attachedInfo = 4; - string ex = 5; -} - -message KeyValue { - string typeKey = 1; - string value = 2; - int64 latestUpdateTime = 3; -} - - - diff --git a/tools/data-conversion/utils/find_insert.go b/tools/data-conversion/utils/find_insert.go deleted file mode 100644 index 150820fce8..0000000000 --- a/tools/data-conversion/utils/find_insert.go +++ /dev/null @@ -1,119 +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 utils - -import ( - "fmt" - "log" - "sync" - "sync/atomic" - - "gorm.io/gorm" - "gorm.io/gorm/schema" -) - -func FindAndInsert[V2 any, V3 schema.Tabler](v2db *gorm.DB, v3db *gorm.DB, fn func(V2) (V3, bool)) (string, error) { - const batchSize = 100 - var t V3 - name := t.TableName() - if err := v3db.AutoMigrate(&t); err != nil { - return name, fmt.Errorf("auto migrate v3 %s failed %w", name, err) - } - for i := 0; ; i++ { - var v2s []V2 - if err := v2db.Offset(i * batchSize).Limit(batchSize).Find(&v2s).Error; err != nil { - return name, fmt.Errorf("find v2 %s failed %w", name, err) - } - if len(v2s) == 0 { - return name, nil - } - v3s := make([]V3, 0, len(v2s)) - for _, v := range v2s { - res, ok := fn(v) - if ok { - v3s = append(v3s, res) - } - } - if len(v3s) == 0 { - continue - } - if err := v3db.Create(&v3s).Error; err != nil { - return name, fmt.Errorf("insert v3 %s failed %w", name, err) - } - } -} - -type TakeList []Task - -func (l *TakeList) Append(fn ...Task) { - *l = append(*l, fn...) -} - -type Task func() (string, error) - -func RunTask(concurrency int, tasks TakeList) []string { - if len(tasks) == 0 { - return []string{} - } - if concurrency < 1 { - concurrency = 1 - } - if concurrency > len(tasks) { - concurrency = len(tasks) - } - - taskCh := make(chan func() (string, error), 4) - go func() { - defer close(taskCh) - for i := range tasks { - taskCh <- tasks[i] - } - }() - - var lock sync.Mutex - var failedTables []string - - var wg sync.WaitGroup - wg.Add(concurrency) - var count int64 - - for i := 0; i < concurrency; i++ { - go func() { - defer wg.Done() - for task := range taskCh { - name, err := task() - index := atomic.AddInt64(&count, 1) - if err == nil { - log.Printf("[%d/%d] %s success\n", index, len(tasks), name) - } else { - lock.Lock() - failedTables = append(failedTables, name) - lock.Unlock() - log.Printf("[%d/%d] %s failed %s\n", index, len(tasks), name, err) - return - } - } - }() - } - - wg.Wait() - if len(failedTables) == 0 { - log.Println("all tables success") - } else { - log.Printf("failed tables %d: %+v\n", len(failedTables), failedTables) - } - - return failedTables -} diff --git a/tools/data-conversion/utils/time.go b/tools/data-conversion/utils/time.go deleted file mode 100644 index 9077a3d88d..0000000000 --- a/tools/data-conversion/utils/time.go +++ /dev/null @@ -1,28 +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 utils - -import "time" - -func InitTime(ts ...*time.Time) { - for i := range ts { - if ts[i] == nil { - continue - } - if ts[i].IsZero() || ts[i].UnixMicro() < 0 { - *ts[i] = time.UnixMicro(0) - } - } -} diff --git a/tools/up35/README.md b/tools/up35/README.md deleted file mode 100644 index c5bdcd3b62..0000000000 --- a/tools/up35/README.md +++ /dev/null @@ -1,67 +0,0 @@ -# README for OpenIM Server Data Conversion Tool - -## Overview - -This tool is part of the OpenIM Server suite, specifically designed for data conversion between MySQL and MongoDB databases. It handles the migration of various data types, including user information, friendships, group memberships, and more from a MySQL database to MongoDB, ensuring data consistency and integrity during the transition. - -## Features - -+ **Configurable Database Connections:** Supports connections to both MySQL and MongoDB, configurable through a YAML file. -+ **Data Conversion Tasks:** Converts a range of data models, including user profiles, friend requests, group memberships, and logs. -+ **Version Control:** Maintains data versioning, ensuring only necessary migrations are performed. -+ **Error Handling:** Robust error handling for database connectivity and query execution. - -## Requirements - -+ Go programming environment -+ MySQL and MongoDB servers -+ OpenIM Server dependencies installed - -## Installation - -1. Ensure Go is installed and set up on your system. -2. Clone the OpenIM Server repository. -3. Navigate to the directory containing this tool. -4. Install required dependencies. - -## Configuration - -+ Configuration is managed through a YAML file specified at runtime. -+ Set up the MySQL and MongoDB connection parameters in the config file. - -## Usage - -To run the tool, use the following command from the terminal: - -```go -make build BINS="up35" -``` - -Where `path/to/config.yaml` is the path to your configuration file. - -## Functionality - -The main functions of the script include: - -+ `InitConfig(path string)`: Reads and parses the YAML configuration file. -+ `GetMysql()`: Establishes a connection to the MySQL database. -+ `GetMongo()`: Establishes a connection to the MongoDB database. -+ `Main(path string)`: Orchestrates the data migration process. -+ `SetMongoDataVersion(db *mongo.Database, curver string)`: Updates the data version in MongoDB after migration. -+ `NewTask(...)`: Generic function to handle the migration of different data types. -+ `insertMany(coll *mongo.Collection, objs []any)`: Inserts multiple records into a MongoDB collection. -+ `getColl(obj any)`: Retrieves the MongoDB collection associated with a given object. -+ `convert struct`: Contains methods for converting MySQL models to MongoDB models. - -## Notes - -+ Ensure that the MySQL and MongoDB instances are accessible and that the credentials provided in the config file are correct. -+ It is advisable to backup databases before running the migration to prevent data loss. - -## Contributing - -Contributions to improve the tool or address issues are welcome. Please follow the project's contribution guidelines. - -## License - -Refer to the project's license document for usage and distribution rights. \ No newline at end of file diff --git a/tools/up35/go.mod b/tools/up35/go.mod deleted file mode 100644 index 23163a4dcd..0000000000 --- a/tools/up35/go.mod +++ /dev/null @@ -1,3 +0,0 @@ -module github.com/openimsdk/open-im-server/v3/tools/up35 - -go 1.19 diff --git a/tools/up35/go.sum b/tools/up35/go.sum deleted file mode 100644 index 1a81e5b338..0000000000 --- a/tools/up35/go.sum +++ /dev/null @@ -1,125 +0,0 @@ -github.com/OpenIMSDK/protocol v0.0.31 h1:ax43x9aqA6EKNXNukS5MT5BSTqkUmwO4uTvbJLtzCgE= -github.com/OpenIMSDK/protocol v0.0.31/go.mod h1:F25dFrwrIx3lkNoiuf6FkCfxuwf8L4Z8UIsdTHP/r0Y= -github.com/OpenIMSDK/tools v0.0.18 h1:h3CvKB90DNd2aIJcOQ99cqgeW6C0na0PzR1TNsfxwL0= -github.com/OpenIMSDK/tools v0.0.18/go.mod h1:eg+q4A34Qmu73xkY0mt37FHGMCMfC6CtmOnm0kFEGFI= -github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= -github.com/bwmarrin/snowflake v0.3.0 h1:xm67bEhkKh6ij1790JB83OujPR5CzNe8QuQqAgISZN0= -github.com/bwmarrin/snowflake v0.3.0/go.mod h1:NdZxfVWX+oR6y2K0o6qAYv6gIOP9rjG0/E9WsDpxqwE= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= -github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI= -github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= -github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= -github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= -github.com/jinzhu/copier v0.4.0 h1:w3ciUoD19shMCRargcpm0cm91ytaBhDvuRpz1ODO/U8= -github.com/jinzhu/copier v0.4.0/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg= -github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= -github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= -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/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= -github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I= -github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= -github.com/lestrrat-go/envload v0.0.0-20180220234015-a3eb8ddeffcc h1:RKf14vYWi2ttpEmkA4aQ3j4u9dStX2t4M8UM6qqNsG8= -github.com/lestrrat-go/envload v0.0.0-20180220234015-a3eb8ddeffcc/go.mod h1:kopuH9ugFRkIXf3YoqHKyrJ9YfUFsckUU9S7B+XP+is= -github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible h1:Y6sqxHMyB1D2YSzWkLibYKgg+SwmyFU9dF2hn6MdTj4= -github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible/go.mod h1:ZQnN8lSECaebrkQytbHj4xNgtg8CR7RYXnPok8e0EHA= -github.com/lestrrat-go/strftime v1.0.6 h1:CFGsDEt1pOpFNU+TJB0nhz9jl+K0hZSLE205AhTIGQQ= -github.com/lestrrat-go/strftime v1.0.6/go.mod h1:f7jQKgV5nnJpYgdEasS+/y7EsTb8ykN2z68n3TtcTaw= -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/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ= -github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8= -github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= -github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= -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= -github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4= -github.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6c8= -github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM= -github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d h1:splanxYIlg+5LfHAM6xpdFEAYOk8iySO56hMFq6uLyA= -github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= -github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -go.mongodb.org/mongo-driver v1.12.1 h1:nLkghSU8fQNaK7oUmDhQFsnrtcoNy7Z6LVFKsEecqgE= -go.mongodb.org/mongo-driver v1.12.1/go.mod h1:/rGBTebI3XYboVmgz+Wv3Bcbl3aD0QF9zl6kDDw18rQ= -go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= -go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= -go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= -go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= -go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60= -go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= -golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= -golang.org/x/image v0.13.0 h1:3cge/F/QTkNLauhf2QoE9zp+7sr+ZcL4HnoZmdwg9sg= -golang.org/x/image v0.13.0/go.mod h1:6mmbMOeV28HuMTgA6OSRkdXKYw/t5W9Uwn2Yv1r3Yxk= -golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= -golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/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.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ= -golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= -golang.org/x/sys v0.14.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/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= -golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= -golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231012201019-e917dd12ba7a h1:a2MQQVoTo96JC9PMGtGBymLp7+/RzpFc2yX/9WfFg1c= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231012201019-e917dd12ba7a/go.mod h1:4cYg8o5yUbm77w8ZX00LhMVNl/YVBFJRYWDc0uYWMs0= -google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk= -google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= -google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -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/driver/mysql v1.5.1 h1:WUEH5VF9obL/lTtzjmML/5e6VfFR/788coz2uaVCAZw= -gorm.io/driver/mysql v1.5.1/go.mod h1:Jo3Xu7mMhCyj8dlrb3WoCaRd1FhsVh+yMXb1jUInf5o= -gorm.io/gorm v1.25.1/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k= -gorm.io/gorm v1.25.4 h1:iyNd8fNAe8W9dvtlgeRI5zSVZPsq3OpcTu37cYcpCmw= -gorm.io/gorm v1.25.4/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k= diff --git a/tools/up35/pkg/convert.go b/tools/up35/pkg/convert.go deleted file mode 100644 index 53ada0e047..0000000000 --- a/tools/up35/pkg/convert.go +++ /dev/null @@ -1,242 +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 pkg - -import ( - "time" - - mongomodel "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" - mysqlmodel "github.com/openimsdk/open-im-server/v3/tools/data-conversion/openim/mysql/v3" - mongomodelrtc "github.com/openimsdk/open-im-server/v3/tools/up35/pkg/internal/rtc/mongo/table" - mysqlmodelrtc "github.com/openimsdk/open-im-server/v3/tools/up35/pkg/internal/rtc/mysql" -) - -type convert struct{} - -func (convert) User(v mysqlmodel.UserModel) mongomodel.UserModel { - return mongomodel.UserModel{ - UserID: v.UserID, - Nickname: v.Nickname, - FaceURL: v.FaceURL, - Ex: v.Ex, - AppMangerLevel: v.AppMangerLevel, - GlobalRecvMsgOpt: v.GlobalRecvMsgOpt, - CreateTime: v.CreateTime, - } -} - -func (convert) Friend(v mysqlmodel.FriendModel) mongomodel.FriendModel { - return mongomodel.FriendModel{ - OwnerUserID: v.OwnerUserID, - FriendUserID: v.FriendUserID, - Remark: v.Remark, - CreateTime: v.CreateTime, - AddSource: v.AddSource, - OperatorUserID: v.OperatorUserID, - Ex: v.Ex, - } -} - -func (convert) FriendRequest(v mysqlmodel.FriendRequestModel) mongomodel.FriendRequestModel { - return mongomodel.FriendRequestModel{ - FromUserID: v.FromUserID, - ToUserID: v.ToUserID, - HandleResult: v.HandleResult, - ReqMsg: v.ReqMsg, - CreateTime: v.CreateTime, - HandlerUserID: v.HandlerUserID, - HandleMsg: v.HandleMsg, - HandleTime: v.HandleTime, - Ex: v.Ex, - } -} - -func (convert) Black(v mysqlmodel.BlackModel) mongomodel.BlackModel { - return mongomodel.BlackModel{ - OwnerUserID: v.OwnerUserID, - BlockUserID: v.BlockUserID, - CreateTime: v.CreateTime, - AddSource: v.AddSource, - OperatorUserID: v.OperatorUserID, - Ex: v.Ex, - } -} - -func (convert) Group(v mysqlmodel.GroupModel) mongomodel.GroupModel { - return mongomodel.GroupModel{ - GroupID: v.GroupID, - GroupName: v.GroupName, - Notification: v.Notification, - Introduction: v.Introduction, - FaceURL: v.FaceURL, - CreateTime: v.CreateTime, - Ex: v.Ex, - Status: v.Status, - CreatorUserID: v.CreatorUserID, - GroupType: v.GroupType, - NeedVerification: v.NeedVerification, - LookMemberInfo: v.LookMemberInfo, - ApplyMemberFriend: v.ApplyMemberFriend, - NotificationUpdateTime: v.NotificationUpdateTime, - NotificationUserID: v.NotificationUserID, - } -} - -func (convert) GroupMember(v mysqlmodel.GroupMemberModel) mongomodel.GroupMemberModel { - return mongomodel.GroupMemberModel{ - GroupID: v.GroupID, - UserID: v.UserID, - Nickname: v.Nickname, - FaceURL: v.FaceURL, - RoleLevel: v.RoleLevel, - JoinTime: v.JoinTime, - JoinSource: v.JoinSource, - InviterUserID: v.InviterUserID, - OperatorUserID: v.OperatorUserID, - MuteEndTime: v.MuteEndTime, - Ex: v.Ex, - } -} - -func (convert) GroupRequest(v mysqlmodel.GroupRequestModel) mongomodel.GroupRequestModel { - return mongomodel.GroupRequestModel{ - UserID: v.UserID, - GroupID: v.GroupID, - HandleResult: v.HandleResult, - ReqMsg: v.ReqMsg, - HandledMsg: v.HandledMsg, - ReqTime: v.ReqTime, - HandleUserID: v.HandleUserID, - HandledTime: v.HandledTime, - JoinSource: v.JoinSource, - InviterUserID: v.InviterUserID, - Ex: v.Ex, - } -} - -func (convert) Conversation(v mysqlmodel.ConversationModel) mongomodel.ConversationModel { - return mongomodel.ConversationModel{ - OwnerUserID: v.OwnerUserID, - ConversationID: v.ConversationID, - ConversationType: v.ConversationType, - UserID: v.UserID, - GroupID: v.GroupID, - RecvMsgOpt: v.RecvMsgOpt, - IsPinned: v.IsPinned, - IsPrivateChat: v.IsPrivateChat, - BurnDuration: v.BurnDuration, - GroupAtType: v.GroupAtType, - AttachedInfo: v.AttachedInfo, - Ex: v.Ex, - MaxSeq: v.MaxSeq, - MinSeq: v.MinSeq, - CreateTime: v.CreateTime, - IsMsgDestruct: v.IsMsgDestruct, - MsgDestructTime: v.MsgDestructTime, - LatestMsgDestructTime: v.LatestMsgDestructTime, - } -} - -func (convert) Object(engine string) func(v mysqlmodel.ObjectModel) mongomodel.ObjectModel { - return func(v mysqlmodel.ObjectModel) mongomodel.ObjectModel { - return mongomodel.ObjectModel{ - Name: v.Name, - UserID: v.UserID, - Hash: v.Hash, - Engine: engine, - Key: v.Key, - Size: v.Size, - ContentType: v.ContentType, - Group: v.Cause, - CreateTime: v.CreateTime, - } - } -} - -func (convert) Log(v mysqlmodel.Log) mongomodel.LogModel { - return mongomodel.LogModel{ - LogID: v.LogID, - Platform: v.Platform, - UserID: v.UserID, - CreateTime: v.CreateTime, - Url: v.Url, - FileName: v.FileName, - SystemType: v.SystemType, - Version: v.Version, - Ex: v.Ex, - } -} - -func (convert) SignalModel(v mysqlmodelrtc.SignalModel) mongomodelrtc.SignalModel { - return mongomodelrtc.SignalModel{ - SID: v.SID, - InviterUserID: v.InviterUserID, - CustomData: v.CustomData, - GroupID: v.GroupID, - RoomID: v.RoomID, - Timeout: v.Timeout, - MediaType: v.MediaType, - PlatformID: v.PlatformID, - SessionType: v.SessionType, - InitiateTime: v.InitiateTime, - EndTime: v.EndTime, - FileURL: v.FileURL, - Title: v.Title, - Desc: v.Desc, - Ex: v.Ex, - IOSPushSound: v.IOSPushSound, - IOSBadgeCount: v.IOSBadgeCount, - SignalInfo: v.SignalInfo, - } -} - -func (convert) SignalInvitationModel(v mysqlmodelrtc.SignalInvitationModel) mongomodelrtc.SignalInvitationModel { - return mongomodelrtc.SignalInvitationModel{ - SID: v.SID, - UserID: v.UserID, - Status: v.Status, - InitiateTime: v.InitiateTime, - HandleTime: v.HandleTime, - } -} - -func (convert) Meeting(v mysqlmodelrtc.MeetingInfo) mongomodelrtc.MeetingInfo { - return mongomodelrtc.MeetingInfo{ - RoomID: v.RoomID, - MeetingName: v.MeetingName, - HostUserID: v.HostUserID, - Status: v.Status, - StartTime: time.Unix(v.StartTime, 0), - EndTime: time.Unix(v.EndTime, 0), - CreateTime: v.CreateTime, - Ex: v.Ex, - } -} - -func (convert) MeetingInvitationInfo(v mysqlmodelrtc.MeetingInvitationInfo) mongomodelrtc.MeetingInvitationInfo { - return mongomodelrtc.MeetingInvitationInfo{ - RoomID: v.RoomID, - UserID: v.UserID, - CreateTime: v.CreateTime, - } -} - -func (convert) MeetingVideoRecord(v mysqlmodelrtc.MeetingVideoRecord) mongomodelrtc.MeetingVideoRecord { - return mongomodelrtc.MeetingVideoRecord{ - RoomID: v.RoomID, - FileURL: v.FileURL, - CreateTime: v.CreateTime, - } -} diff --git a/tools/up35/pkg/internal/rtc/mongo/mgo/meeting.go b/tools/up35/pkg/internal/rtc/mongo/mgo/meeting.go deleted file mode 100644 index fd0f2818b2..0000000000 --- a/tools/up35/pkg/internal/rtc/mongo/mgo/meeting.go +++ /dev/null @@ -1,102 +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 mgo - -import ( - "context" - "time" - - "github.com/OpenIMSDK/tools/mgoutil" - "github.com/OpenIMSDK/tools/pagination" - "go.mongodb.org/mongo-driver/bson" - "go.mongodb.org/mongo-driver/mongo" - "go.mongodb.org/mongo-driver/mongo/options" - - "github.com/openimsdk/open-im-server/v3/tools/up35/pkg/internal/rtc/mongo/table" -) - -func NewMeeting(db *mongo.Database) (table.MeetingInterface, error) { - coll := db.Collection("meeting") - _, err := coll.Indexes().CreateMany(context.Background(), []mongo.IndexModel{ - { - Keys: bson.D{ - {Key: "room_id", Value: 1}, - }, - Options: options.Index().SetUnique(true), - }, - { - Keys: bson.D{ - {Key: "host_user_id", Value: 1}, - }, - }, - { - Keys: bson.D{ - {Key: "create_time", Value: -1}, - }, - }, - }) - if err != nil { - return nil, err - } - return &meeting{coll: coll}, nil -} - -type meeting struct { - coll *mongo.Collection -} - -func (x *meeting) Find(ctx context.Context, roomIDs []string) ([]*table.MeetingInfo, error) { - return mgoutil.Find[*table.MeetingInfo](ctx, x.coll, bson.M{"room_id": bson.M{"$in": roomIDs}}) -} - -func (x *meeting) CreateMeetingInfo(ctx context.Context, meetingInfo *table.MeetingInfo) error { - return mgoutil.InsertMany(ctx, x.coll, []*table.MeetingInfo{meetingInfo}) -} - -func (x *meeting) UpdateMeetingInfo(ctx context.Context, roomID string, update map[string]any) error { - if len(update) == 0 { - return nil - } - return mgoutil.UpdateOne(ctx, x.coll, bson.M{"room_id": roomID}, bson.M{"$set": update}, false) -} - -func (x *meeting) GetUnCompleteMeetingIDList(ctx context.Context, roomIDs []string) ([]string, error) { - if len(roomIDs) == 0 { - return nil, nil - } - return mgoutil.Find[string](ctx, x.coll, bson.M{"room_id": bson.M{"$in": roomIDs}, "status": 0}, options.Find().SetProjection(bson.M{"_id": 0, "room_id": 1})) -} - -func (x *meeting) Delete(ctx context.Context, roomIDs []string) error { - return mgoutil.DeleteMany(ctx, x.coll, bson.M{"room_id": bson.M{"$in": roomIDs}}) -} - -func (x *meeting) GetMeetingRecords(ctx context.Context, hostUserID string, startTime, endTime time.Time, pagination pagination.Pagination) (int64, []*table.MeetingInfo, error) { - var and []bson.M - if hostUserID != "" { - and = append(and, bson.M{"host_user_id": hostUserID}) - } - if !startTime.IsZero() { - and = append(and, bson.M{"create_time": bson.M{"$gte": startTime}}) - } - if !endTime.IsZero() { - and = append(and, bson.M{"create_time": bson.M{"$lte": endTime}}) - } - filter := bson.M{} - if len(and) > 0 { - filter["$and"] = and - } - return mgoutil.FindPage[*table.MeetingInfo](ctx, x.coll, filter, pagination, options.Find().SetSort(bson.M{"create_time": -1})) -} diff --git a/tools/up35/pkg/internal/rtc/mongo/mgo/meeting_invitation.go b/tools/up35/pkg/internal/rtc/mongo/mgo/meeting_invitation.go deleted file mode 100644 index 9926748bfa..0000000000 --- a/tools/up35/pkg/internal/rtc/mongo/mgo/meeting_invitation.go +++ /dev/null @@ -1,97 +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 mgo - -import ( - "context" - "time" - - "github.com/OpenIMSDK/tools/mgoutil" - "github.com/OpenIMSDK/tools/pagination" - "github.com/OpenIMSDK/tools/utils" - "go.mongodb.org/mongo-driver/bson" - "go.mongodb.org/mongo-driver/mongo" - "go.mongodb.org/mongo-driver/mongo/options" - - "github.com/openimsdk/open-im-server/v3/tools/up35/pkg/internal/rtc/mongo/table" -) - -func NewMeetingInvitation(db *mongo.Database) (table.MeetingInvitationInterface, error) { - coll := db.Collection("meeting_invitation") - _, err := coll.Indexes().CreateMany(context.Background(), []mongo.IndexModel{ - { - Keys: bson.D{ - {Key: "room_id", Value: 1}, - {Key: "user_id", Value: 1}, - }, - Options: options.Index().SetUnique(true), - }, - { - Keys: bson.D{ - {Key: "create_time", Value: -1}, - }, - }, - }) - if err != nil { - return nil, err - } - return &meetingInvitation{coll: coll}, nil -} - -type meetingInvitation struct { - coll *mongo.Collection -} - -func (x *meetingInvitation) FindUserIDs(ctx context.Context, roomID string) ([]string, error) { - return mgoutil.Find[string](ctx, x.coll, bson.M{"room_id": roomID}, options.Find().SetProjection(bson.M{"_id": 0, "user_id": 1})) -} - -func (x *meetingInvitation) CreateMeetingInvitationInfo(ctx context.Context, roomID string, inviteeUserIDs []string) error { - now := time.Now() - return mgoutil.InsertMany(ctx, x.coll, utils.Slice(inviteeUserIDs, func(userID string) *table.MeetingInvitationInfo { - return &table.MeetingInvitationInfo{ - RoomID: roomID, - UserID: userID, - CreateTime: now, - } - })) -} - -func (x *meetingInvitation) GetUserInvitedMeetingIDs(ctx context.Context, userID string) (meetingIDs []string, err error) { - fiveDaysAgo := time.Now().AddDate(0, 0, -5) - return mgoutil.Find[string]( - ctx, - x.coll, - bson.M{"user_id": userID, "create_time": bson.M{"$gte": fiveDaysAgo}}, - options.Find().SetSort(bson.M{"create_time": -1}).SetProjection(bson.M{"_id": 0, "room_id": 1}), - ) -} - -func (x *meetingInvitation) Delete(ctx context.Context, roomIDs []string) error { - return mgoutil.DeleteMany(ctx, x.coll, bson.M{"room_id": bson.M{"$in": roomIDs}}) -} - -func (x *meetingInvitation) GetMeetingRecords(ctx context.Context, joinedUserID string, startTime, endTime time.Time, pagination pagination.Pagination) (int64, []string, error) { - var and []bson.M - and = append(and, bson.M{"user_id": joinedUserID}) - if !startTime.IsZero() { - and = append(and, bson.M{"create_time": bson.M{"$gte": startTime}}) - } - if !endTime.IsZero() { - and = append(and, bson.M{"create_time": bson.M{"$lte": endTime}}) - } - opt := options.Find().SetSort(bson.M{"create_time": -1}).SetProjection(bson.M{"_id": 0, "room_id": 1}) - return mgoutil.FindPage[string](ctx, x.coll, bson.M{"$and": and}, pagination, opt) -} diff --git a/tools/up35/pkg/internal/rtc/mongo/mgo/meeting_record.go b/tools/up35/pkg/internal/rtc/mongo/mgo/meeting_record.go deleted file mode 100644 index 4e9dc5e0f1..0000000000 --- a/tools/up35/pkg/internal/rtc/mongo/mgo/meeting_record.go +++ /dev/null @@ -1,48 +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 mgo - -import ( - "context" - - "github.com/OpenIMSDK/tools/mgoutil" - "go.mongodb.org/mongo-driver/bson" - "go.mongodb.org/mongo-driver/mongo" - - "github.com/openimsdk/open-im-server/v3/tools/up35/pkg/internal/rtc/mongo/table" -) - -func NewMeetingRecord(db *mongo.Database) (table.MeetingRecordInterface, error) { - coll := db.Collection("meeting_record") - _, err := coll.Indexes().CreateMany(context.Background(), []mongo.IndexModel{ - { - Keys: bson.D{ - {Key: "room_id", Value: 1}, - }, - }, - }) - if err != nil { - return nil, err - } - return &meetingRecord{coll: coll}, nil -} - -type meetingRecord struct { - coll *mongo.Collection -} - -func (x *meetingRecord) CreateMeetingVideoRecord(ctx context.Context, meetingVideoRecord *table.MeetingVideoRecord) error { - return mgoutil.InsertMany(ctx, x.coll, []*table.MeetingVideoRecord{meetingVideoRecord}) -} diff --git a/tools/up35/pkg/internal/rtc/mongo/mgo/signal.go b/tools/up35/pkg/internal/rtc/mongo/mgo/signal.go deleted file mode 100644 index 47fd3fb025..0000000000 --- a/tools/up35/pkg/internal/rtc/mongo/mgo/signal.go +++ /dev/null @@ -1,105 +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 mgo - -import ( - "context" - "time" - - "github.com/OpenIMSDK/tools/mgoutil" - "github.com/OpenIMSDK/tools/pagination" - "go.mongodb.org/mongo-driver/bson" - "go.mongodb.org/mongo-driver/mongo" - "go.mongodb.org/mongo-driver/mongo/options" - - "github.com/openimsdk/open-im-server/v3/tools/up35/pkg/internal/rtc/mongo/table" -) - -func NewSignal(db *mongo.Database) (table.SignalInterface, error) { - coll := db.Collection("signal") - _, err := coll.Indexes().CreateMany(context.Background(), []mongo.IndexModel{ - { - Keys: bson.D{ - {Key: "sid", Value: 1}, - }, - Options: options.Index().SetUnique(true), - }, - { - Keys: bson.D{ - {Key: "inviter_user_id", Value: 1}, - }, - }, - { - Keys: bson.D{ - {Key: "initiate_time", Value: -1}, - }, - }, - }) - if err != nil { - return nil, err - } - return &signal{coll: coll}, nil -} - -type signal struct { - coll *mongo.Collection -} - -func (x *signal) Find(ctx context.Context, sids []string) ([]*table.SignalModel, error) { - return mgoutil.Find[*table.SignalModel](ctx, x.coll, bson.M{"sid": bson.M{"$in": sids}}) -} - -func (x *signal) CreateSignal(ctx context.Context, signalModel *table.SignalModel) error { - return mgoutil.InsertMany(ctx, x.coll, []*table.SignalModel{signalModel}) -} - -func (x *signal) Update(ctx context.Context, sid string, update map[string]any) error { - if len(update) == 0 { - return nil - } - return mgoutil.UpdateOne(ctx, x.coll, bson.M{"sid": sid}, bson.M{"$set": update}, false) -} - -func (x *signal) UpdateSignalFileURL(ctx context.Context, sID, fileURL string) error { - return x.Update(ctx, sID, map[string]any{"file_url": fileURL}) -} - -func (x *signal) UpdateSignalEndTime(ctx context.Context, sID string, endTime time.Time) error { - return x.Update(ctx, sID, map[string]any{"end_time": endTime}) -} - -func (x *signal) Delete(ctx context.Context, sids []string) error { - if len(sids) == 0 { - return nil - } - return mgoutil.DeleteMany(ctx, x.coll, bson.M{"sid": bson.M{"$in": sids}}) -} - -func (x *signal) PageSignal(ctx context.Context, sesstionType int32, sendID string, startTime, endTime time.Time, pagination pagination.Pagination) (int64, []*table.SignalModel, error) { - var and []bson.M - if !startTime.IsZero() { - and = append(and, bson.M{"initiate_time": bson.M{"$gte": startTime}}) - } - if !endTime.IsZero() { - and = append(and, bson.M{"initiate_time": bson.M{"$lte": endTime}}) - } - if sesstionType != 0 { - and = append(and, bson.M{"sesstion_type": sesstionType}) - } - if sendID != "" { - and = append(and, bson.M{"inviter_user_id": sendID}) - } - return mgoutil.FindPage[*table.SignalModel](ctx, x.coll, bson.M{"$and": and}, pagination, options.Find().SetSort(bson.M{"initiate_time": -1})) -} diff --git a/tools/up35/pkg/internal/rtc/mongo/mgo/signal_invitation.go b/tools/up35/pkg/internal/rtc/mongo/mgo/signal_invitation.go deleted file mode 100644 index 1f76381e9e..0000000000 --- a/tools/up35/pkg/internal/rtc/mongo/mgo/signal_invitation.go +++ /dev/null @@ -1,94 +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 mgo - -import ( - "context" - "time" - - "github.com/OpenIMSDK/tools/mgoutil" - "github.com/OpenIMSDK/tools/pagination" - "github.com/OpenIMSDK/tools/utils" - "go.mongodb.org/mongo-driver/bson" - "go.mongodb.org/mongo-driver/mongo" - "go.mongodb.org/mongo-driver/mongo/options" - - "github.com/openimsdk/open-im-server/v3/tools/up35/pkg/internal/rtc/mongo/table" -) - -func NewSignalInvitation(db *mongo.Database) (table.SignalInvitationInterface, error) { - coll := db.Collection("signal_invitation") - _, err := coll.Indexes().CreateMany(context.Background(), []mongo.IndexModel{ - { - Keys: bson.D{ - {Key: "sid", Value: 1}, - {Key: "user_id", Value: 1}, - }, - Options: options.Index().SetUnique(true), - }, - { - Keys: bson.D{ - {Key: "initiate_time", Value: -1}, - }, - }, - }) - if err != nil { - return nil, err - } - return &signalInvitation{coll: coll}, nil -} - -type signalInvitation struct { - coll *mongo.Collection -} - -func (x *signalInvitation) Find(ctx context.Context, sid string) ([]*table.SignalInvitationModel, error) { - return mgoutil.Find[*table.SignalInvitationModel](ctx, x.coll, bson.M{"sid": sid}) -} - -func (x *signalInvitation) CreateSignalInvitation(ctx context.Context, sid string, inviteeUserIDs []string) error { - now := time.Now() - return mgoutil.InsertMany(ctx, x.coll, utils.Slice(inviteeUserIDs, func(userID string) *table.SignalInvitationModel { - return &table.SignalInvitationModel{ - UserID: userID, - SID: sid, - InitiateTime: now, - HandleTime: time.Unix(0, 0), - } - })) -} - -func (x *signalInvitation) HandleSignalInvitation(ctx context.Context, sID, InviteeUserID string, status int32) error { - return mgoutil.UpdateOne(ctx, x.coll, bson.M{"sid": sID, "user_id": InviteeUserID}, bson.M{"$set": bson.M{"status": status, "handle_time": time.Now()}}, true) -} - -func (x *signalInvitation) PageSID(ctx context.Context, recvID string, startTime, endTime time.Time, pagination pagination.Pagination) (int64, []string, error) { - var and []bson.M - and = append(and, bson.M{"user_id": recvID}) - if !startTime.IsZero() { - and = append(and, bson.M{"initiate_time": bson.M{"$gte": startTime}}) - } - if !endTime.IsZero() { - and = append(and, bson.M{"initiate_time": bson.M{"$lte": endTime}}) - } - return mgoutil.FindPage[string](ctx, x.coll, bson.M{"$and": and}, pagination, options.Find().SetProjection(bson.M{"_id": 0, "sid": 1}).SetSort(bson.M{"initiate_time": -1})) -} - -func (x *signalInvitation) Delete(ctx context.Context, sids []string) error { - if len(sids) == 0 { - return nil - } - return mgoutil.DeleteMany(ctx, x.coll, bson.M{"sid": bson.M{"$in": sids}}) -} diff --git a/tools/up35/pkg/internal/rtc/mongo/table/meeting.go b/tools/up35/pkg/internal/rtc/mongo/table/meeting.go deleted file mode 100644 index 6ff387bbbf..0000000000 --- a/tools/up35/pkg/internal/rtc/mongo/table/meeting.go +++ /dev/null @@ -1,66 +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 table - -import ( - "context" - "time" - - "github.com/OpenIMSDK/tools/pagination" -) - -type MeetingInfo struct { - RoomID string `bson:"room_id"` - MeetingName string `bson:"meeting_name"` - HostUserID string `bson:"host_user_id"` - Status int64 `bson:"status"` - StartTime time.Time `bson:"start_time"` - EndTime time.Time `bson:"end_time"` - CreateTime time.Time `bson:"create_time"` - Ex string `bson:"ex"` -} - -type MeetingInterface interface { - Find(ctx context.Context, roomIDs []string) ([]*MeetingInfo, error) - CreateMeetingInfo(ctx context.Context, meetingInfo *MeetingInfo) error - UpdateMeetingInfo(ctx context.Context, roomID string, update map[string]any) error - GetUnCompleteMeetingIDList(ctx context.Context, roomIDs []string) ([]string, error) - Delete(ctx context.Context, roomIDs []string) error - GetMeetingRecords(ctx context.Context, hostUserID string, startTime, endTime time.Time, pagination pagination.Pagination) (int64, []*MeetingInfo, error) -} - -type MeetingInvitationInfo struct { - RoomID string `bson:"room_id"` - UserID string `bson:"user_id"` - CreateTime time.Time `bson:"create_time"` -} - -type MeetingInvitationInterface interface { - FindUserIDs(ctx context.Context, roomID string) ([]string, error) - CreateMeetingInvitationInfo(ctx context.Context, roomID string, inviteeUserIDs []string) error - GetUserInvitedMeetingIDs(ctx context.Context, userID string) (meetingIDs []string, err error) - Delete(ctx context.Context, roomIDs []string) error - GetMeetingRecords(ctx context.Context, joinedUserID string, startTime, endTime time.Time, pagination pagination.Pagination) (int64, []string, error) -} - -type MeetingVideoRecord struct { - RoomID string `bson:"room_id"` - FileURL string `bson:"file_url"` - CreateTime time.Time `bson:"create_time"` -} - -type MeetingRecordInterface interface { - CreateMeetingVideoRecord(ctx context.Context, meetingVideoRecord *MeetingVideoRecord) error -} diff --git a/tools/up35/pkg/internal/rtc/mongo/table/signal.go b/tools/up35/pkg/internal/rtc/mongo/table/signal.go deleted file mode 100644 index 8d8aa96edc..0000000000 --- a/tools/up35/pkg/internal/rtc/mongo/table/signal.go +++ /dev/null @@ -1,88 +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 table - -import ( - "context" - "time" - - "github.com/OpenIMSDK/tools/errs" - "github.com/OpenIMSDK/tools/pagination" - "github.com/redis/go-redis/v9" - "go.mongodb.org/mongo-driver/mongo" -) - -type SignalModel struct { - SID string `bson:"sid"` - InviterUserID string `bson:"inviter_user_id"` - CustomData string `bson:"custom_data"` - GroupID string `bson:"group_id"` - RoomID string `bson:"room_id"` - Timeout int32 `bson:"timeout"` - MediaType string `bson:"media_type"` - PlatformID int32 `bson:"platform_id"` - SessionType int32 `bson:"session_type"` - InitiateTime time.Time `bson:"initiate_time"` - EndTime time.Time `bson:"end_time"` - FileURL string `bson:"file_url"` - - Title string `bson:"title"` - Desc string `bson:"desc"` - Ex string `bson:"ex"` - IOSPushSound string `bson:"ios_push_sound"` - IOSBadgeCount bool `bson:"ios_badge_count"` - SignalInfo string `bson:"signal_info"` -} - -type SignalInterface interface { - Find(ctx context.Context, sids []string) ([]*SignalModel, error) - CreateSignal(ctx context.Context, signalModel *SignalModel) error - Update(ctx context.Context, sid string, update map[string]any) error - UpdateSignalFileURL(ctx context.Context, sID, fileURL string) error - UpdateSignalEndTime(ctx context.Context, sID string, endTime time.Time) error - Delete(ctx context.Context, sids []string) error - PageSignal(ctx context.Context, sesstionType int32, sendID string, startTime, endTime time.Time, pagination pagination.Pagination) (int64, []*SignalModel, error) -} - -type SignalInvitationModel struct { - SID string `bson:"sid"` - UserID string `bson:"user_id"` - Status int32 `bson:"status"` - InitiateTime time.Time `bson:"initiate_time"` - HandleTime time.Time `bson:"handle_time"` -} - -type SignalInvitationInterface interface { - Find(ctx context.Context, sid string) ([]*SignalInvitationModel, error) - CreateSignalInvitation(ctx context.Context, sid string, inviteeUserIDs []string) error - HandleSignalInvitation(ctx context.Context, sID, InviteeUserID string, status int32) error - PageSID(ctx context.Context, recvID string, startTime, endTime time.Time, pagination pagination.Pagination) (int64, []string, error) - Delete(ctx context.Context, sids []string) error -} - -func IsNotFound(err error) bool { - if err == nil { - return false - } - err = errs.Unwrap(err) - return err == mongo.ErrNoDocuments || err == redis.Nil -} - -func IsDuplicate(err error) bool { - if err == nil { - return false - } - return mongo.IsDuplicateKeyError(errs.Unwrap(err)) -} diff --git a/tools/up35/pkg/internal/rtc/mysql/meeting.go b/tools/up35/pkg/internal/rtc/mysql/meeting.go deleted file mode 100644 index 71515c3b77..0000000000 --- a/tools/up35/pkg/internal/rtc/mysql/meeting.go +++ /dev/null @@ -1,54 +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 relation - -import ( - "time" -) - -type MeetingInfo struct { - RoomID string `gorm:"column:room_id;primary_key;size:128;index:room_id;index:status,priority:1"` - MeetingName string `gorm:"column:meeting_name;size:64"` - HostUserID string `gorm:"column:host_user_id;size:64;index:host_user_id"` - Status int64 `gorm:"column:status;index:status,priority:2"` - StartTime int64 `gorm:"column:start_time"` - EndTime int64 `gorm:"column:end_time"` - CreateTime time.Time `gorm:"column:create_time"` - Ex string `gorm:"column:ex;size:1024"` -} - -func (MeetingInfo) TableName() string { - return "meeting" -} - -type MeetingInvitationInfo struct { - RoomID string `gorm:"column:room_id;primary_key;size:128"` - UserID string `gorm:"column:user_id;primary_key;size:64;index:user_id"` - CreateTime time.Time `gorm:"column:create_time"` -} - -func (MeetingInvitationInfo) TableName() string { - return "meeting_invitation" -} - -type MeetingVideoRecord struct { - RoomID string `gorm:"column:room_id;size:128"` - FileURL string `gorm:"column:file_url"` - CreateTime time.Time `gorm:"column:create_time"` -} - -func (MeetingVideoRecord) TableName() string { - return "meeting_video_record" -} diff --git a/tools/up35/pkg/internal/rtc/mysql/signal.go b/tools/up35/pkg/internal/rtc/mysql/signal.go deleted file mode 100644 index c546360a4a..0000000000 --- a/tools/up35/pkg/internal/rtc/mysql/signal.go +++ /dev/null @@ -1,57 +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 relation - -import ( - "time" -) - -type SignalModel struct { - SID string `gorm:"column:sid;type:char(128);primary_key"` - InviterUserID string `gorm:"column:inviter_user_id;type:char(64);index:inviter_user_id_index"` - CustomData string `gorm:"column:custom_data;type:text"` - GroupID string `gorm:"column:group_id;type:char(64)"` - RoomID string `gorm:"column:room_id;primary_key;type:char(128)"` - Timeout int32 `gorm:"column:timeout"` - MediaType string `gorm:"column:media_type;type:char(64)"` - PlatformID int32 `gorm:"column:platform_id"` - SessionType int32 `gorm:"column:sesstion_type"` - InitiateTime time.Time `gorm:"column:initiate_time"` - EndTime time.Time `gorm:"column:end_time"` - FileURL string `gorm:"column:file_url" json:"-"` - - Title string `gorm:"column:title;size:128"` - Desc string `gorm:"column:desc;size:1024"` - Ex string `gorm:"column:ex;size:1024"` - IOSPushSound string `gorm:"column:ios_push_sound"` - IOSBadgeCount bool `gorm:"column:ios_badge_count"` - SignalInfo string `gorm:"column:signal_info;size:1024"` -} - -func (SignalModel) TableName() string { - return "signal" -} - -type SignalInvitationModel struct { - UserID string `gorm:"column:user_id;primary_key"` - SID string `gorm:"column:sid;type:char(128);primary_key"` - Status int32 `gorm:"column:status"` - InitiateTime time.Time `gorm:"column:initiate_time;primary_key"` - HandleTime time.Time `gorm:"column:handle_time"` -} - -func (SignalInvitationModel) TableName() string { - return "signal_invitation" -} diff --git a/tools/up35/pkg/pkg.go b/tools/up35/pkg/pkg.go deleted file mode 100644 index 54aef1ce96..0000000000 --- a/tools/up35/pkg/pkg.go +++ /dev/null @@ -1,230 +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 pkg - -import ( - "context" - "errors" - "fmt" - "log" - "os" - "reflect" - "strconv" - - "github.com/OpenIMSDK/tools/errs" - - "gopkg.in/yaml.v3" - - "github.com/go-sql-driver/mysql" - "go.mongodb.org/mongo-driver/bson" - "go.mongodb.org/mongo-driver/mongo" - "go.mongodb.org/mongo-driver/mongo/options" - gormmysql "gorm.io/driver/mysql" - "gorm.io/gorm" - "gorm.io/gorm/logger" - - "github.com/openimsdk/open-im-server/v3/pkg/common/config" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/mgo" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/unrelation" - rtcmgo "github.com/openimsdk/open-im-server/v3/tools/up35/pkg/internal/rtc/mongo/mgo" -) - -const ( - versionTable = "dataver" - versionKey = "data_version" - versionValue = 35 -) - -func InitConfig(path string) (*config.GlobalConfig, error) { - data, err := os.ReadFile(path) - if err != nil { - return nil, errs.Wrap(err, "ReadFile unmarshal failed") - } - - conf := config.NewGlobalConfig() - err = yaml.Unmarshal(data, &conf) - if err != nil { - return nil, errs.Wrap(err, "InitConfig unmarshal failed") - } - return conf, nil -} - -func GetMysql(config *config.GlobalConfig) (*gorm.DB, error) { - conf := config.Mysql - mysqlDSN := fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=utf8mb4&parseTime=True&loc=Local", conf.Username, conf.Password, conf.Address[0], conf.Database) - return gorm.Open(gormmysql.Open(mysqlDSN), &gorm.Config{Logger: logger.Discard}) -} - -func GetMongo(config *config.GlobalConfig) (*mongo.Database, error) { - mgo, err := unrelation.NewMongo(config) - if err != nil { - return nil, err - } - return mgo.GetDatabase(config.Mongo.Database), nil -} - -func Main(path string) error { - conf, err := InitConfig(path) - if err != nil { - return err - } - if conf.Mysql == nil { - return nil - } - mongoDB, err := GetMongo(conf) - if err != nil { - return err - } - var version struct { - Key string `bson:"key"` - Value string `bson:"value"` - } - switch mongoDB.Collection(versionTable).FindOne(context.Background(), bson.M{"key": versionKey}).Decode(&version) { - case nil: - if ver, _ := strconv.Atoi(version.Value); ver >= versionValue { - return nil - } - case mongo.ErrNoDocuments: - default: - return err - } - mysqlDB, err := GetMysql(conf) - if err != nil { - if mysqlErr, ok := err.(*mysql.MySQLError); ok && mysqlErr.Number == 1049 { - if err := SetMongoDataVersion(mongoDB, version.Value); err != nil { - return err - } - return nil // database not exist - } - return err - } - - var c convert - var tasks []func() error - tasks = append(tasks, - func() error { return NewTask(mysqlDB, mongoDB, mgo.NewUserMongo, c.User) }, - func() error { return NewTask(mysqlDB, mongoDB, mgo.NewFriendMongo, c.Friend) }, - func() error { return NewTask(mysqlDB, mongoDB, mgo.NewFriendRequestMongo, c.FriendRequest) }, - func() error { return NewTask(mysqlDB, mongoDB, mgo.NewBlackMongo, c.Black) }, - func() error { return NewTask(mysqlDB, mongoDB, mgo.NewGroupMongo, c.Group) }, - func() error { return NewTask(mysqlDB, mongoDB, mgo.NewGroupMember, c.GroupMember) }, - func() error { return NewTask(mysqlDB, mongoDB, mgo.NewGroupRequestMgo, c.GroupRequest) }, - func() error { return NewTask(mysqlDB, mongoDB, mgo.NewConversationMongo, c.Conversation) }, - func() error { return NewTask(mysqlDB, mongoDB, mgo.NewS3Mongo, c.Object(conf.Object.Enable)) }, - func() error { return NewTask(mysqlDB, mongoDB, mgo.NewLogMongo, c.Log) }, - - func() error { return NewTask(mysqlDB, mongoDB, rtcmgo.NewSignal, c.SignalModel) }, - func() error { return NewTask(mysqlDB, mongoDB, rtcmgo.NewSignalInvitation, c.SignalInvitationModel) }, - func() error { return NewTask(mysqlDB, mongoDB, rtcmgo.NewMeeting, c.Meeting) }, - func() error { return NewTask(mysqlDB, mongoDB, rtcmgo.NewMeetingInvitation, c.MeetingInvitationInfo) }, - func() error { return NewTask(mysqlDB, mongoDB, rtcmgo.NewMeetingRecord, c.MeetingVideoRecord) }, - ) - - for _, task := range tasks { - if err := task(); err != nil { - return err - } - } - - if err := SetMongoDataVersion(mongoDB, version.Value); err != nil { - return err - } - return nil -} - -func SetMongoDataVersion(db *mongo.Database, curver string) error { - filter := bson.M{"key": versionKey, "value": curver} - update := bson.M{"$set": bson.M{"key": versionKey, "value": strconv.Itoa(versionValue)}} - _, err := db.Collection(versionTable).UpdateOne(context.Background(), filter, update, options.Update().SetUpsert(true)) - return err -} - -// NewTask A mysql table B mongodb model C mongodb table -func NewTask[A interface{ TableName() string }, B any, C any](gormDB *gorm.DB, mongoDB *mongo.Database, mongoDBInit func(db *mongo.Database) (B, error), convert func(v A) C) error { - obj, err := mongoDBInit(mongoDB) - if err != nil { - return err - } - var zero A - tableName := zero.TableName() - coll, err := getColl(obj) - if err != nil { - return errs.Wrap(fmt.Errorf("get mongo collection %s failed, err: %w", tableName, err)) - } - var count int - defer func() { - log.Printf("completed convert %s total %d\n", tableName, count) - }() - const batch = 100 - for page := 0; ; page++ { - res := make([]A, 0, batch) - if err := gormDB.Limit(batch).Offset(page * batch).Find(&res).Error; err != nil { - if mysqlErr, ok := err.(*mysql.MySQLError); ok && mysqlErr.Number == 1146 { - return nil // table not exist - } - return errs.Wrap(fmt.Errorf("find mysql table %s failed, err: %w", tableName, err)) - } - if len(res) == 0 { - return nil - } - temp := make([]any, len(res)) - for i := range res { - temp[i] = convert(res[i]) - } - if err := insertMany(coll, temp); err != nil { - return errs.Wrap(fmt.Errorf("insert mongo table %s failed, err: %w", tableName, err)) - } - count += len(res) - if len(res) < batch { - return nil - } - log.Printf("current convert %s completed %d\n", tableName, count) - } -} - -func insertMany(coll *mongo.Collection, objs []any) error { - if _, err := coll.InsertMany(context.Background(), objs); err != nil { - if !mongo.IsDuplicateKeyError(err) { - return errs.Wrap(err) - } - } - for i := range objs { - _, err := coll.InsertOne(context.Background(), objs[i]) - switch { - case err == nil: - case mongo.IsDuplicateKeyError(err): - default: - return err - } - } - return nil -} - -func getColl(obj any) (_ *mongo.Collection, err error) { - defer func() { - if e := recover(); e != nil { - err = fmt.Errorf("not found %+v", e) - } - }() - stu := reflect.ValueOf(obj).Elem() - typ := reflect.TypeOf(&mongo.Collection{}).String() - for i := 0; i < stu.NumField(); i++ { - field := stu.Field(i) - if field.Type().String() == typ { - return (*mongo.Collection)(field.UnsafePointer()), nil - } - } - return nil, errors.New("not found") -} diff --git a/tools/up35/up35.go b/tools/up35/up35.go deleted file mode 100644 index 63b6ec2c20..0000000000 --- a/tools/up35/up35.go +++ /dev/null @@ -1,34 +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 main - -import ( - "flag" - "log" - "os" - - "github.com/openimsdk/open-im-server/v3/tools/up35/pkg" -) - -func main() { - var path string - flag.StringVar(&path, "c", "", "path config file") - flag.Parse() - if err := pkg.Main(path); err != nil { - log.Fatal(err) - return - } - os.Exit(0) -} From 148a2493bb3102a1f0ce446f22801cde4b6d55ff Mon Sep 17 00:00:00 2001 From: skiffer-git <72860476+skiffer-git@users.noreply.github.com> Date: Sat, 9 Mar 2024 13:52:07 +0800 Subject: [PATCH 105/188] Fix bug redis address (#2063) * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * fix: mongo * fix: mongo * fix: mongo * openim.yaml * localcache * localcache * localcache * localcache * localcache * localcache * localcache * localcache * localcache * local cache * local cache * local cache * local cache * fix: GroupApplicationAcceptedNotification * fix: GroupApplicationAcceptedNotification * fix: NotificationUserInfoUpdate * feat: cache add single-flight and timing-wheel. * feat: local cache * feat: local cache * feat: local cache * feat: cache add single-flight and timing-wheel. * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * refactor: refactor the code of push and optimization. * cicd: robot automated Change * refactor: rename cache. * merge * fix: refactor project dir avoid import cycle. * update tools * merge * feat: conversation FindRecvMsgNotNotifyUserIDs * feat: conversation FindRecvMsgNotNotifyUserIDs * feat: conversation FindRecvMsgNotNotifyUserIDs * merge * merge the latest main * Exit with code 1 when the check script fails (#2023) * Optimize script logs * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Exit with code 1 when the check script fails * Execute after the component check succeeds && minio.Enable is not configured to use MinIO (#2027) * Exit with code 1 when the check script fails (#2022) * Optimize script logs * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Exit with code 1 when the check script fails * Exit with code 1 when the check script fails * Exit with code 1 when the check script fails * Exit with code 1 when the check script fails * Exit with code 1 when the check script fails * Handle the return value of pre-start * Handle the return value of pre-start * Handle the return value of pre-start * minio.Enable is not configured to use MinIO, therefore the image server is not checked * minio.Enable is not configured to use MinIO, therefore the image server is not checked * minio.Enable is not configured to use MinIO, therefore the image server is not checked * minio.Enable is not configured to use MinIO, therefore the image server is not checked * Log redirection causes incorrect program exit status. (#2031) * Exit with code 1 when the check script fails (#2022) * Optimize script logs * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Exit with code 1 when the check script fails * cicd: bump League Patch (#2025) * Execute after the component check succeeds && minio.Enable is not configured to use MinIO (#2026) * Exit with code 1 when the check script fails * Exit with code 1 when the check script fails * Exit with code 1 when the check script fails * Exit with code 1 when the check script fails * Handle the return value of pre-start * Handle the return value of pre-start * Handle the return value of pre-start * minio.Enable is not configured to use MinIO, therefore the image server is not checked * minio.Enable is not configured to use MinIO, therefore the image server is not checked * minio.Enable is not configured to use MinIO, therefore the image server is not checked * minio.Enable is not configured to use MinIO, therefore the image server is not checked * Log redirection causes incorrect program exit status. --------- Co-authored-by: OpenIM Bot <124379614+kubbot@users.noreply.github.com> * delete * add context deadline exceeded * Error not handled * Error not handled * Error not handled * Error not handled * Fix bug Remove duplicate function definitions (#2034) * Exit with code 1 when the check script fails (#2022) * Optimize script logs * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Exit with code 1 when the check script fails * delete * delete log * configGetEnv failed,err:string to int failed: strconv.Atoi: parsing "openim_v3": invalid syntaxr * Fix bug configGetEnv failed,err:string to int failed: strconv.Atoi: parsing "openim_v3": invalid syntaxr (#2045) * Error not handled (#2040) * delete * add context deadline exceeded * Error not handled * Error not handled * Error not handled * Error not handled * feat: add local cache for high frequency reads (#2036) * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * fix: mongo * fix: mongo * fix: mongo * openim.yaml * localcache * localcache * localcache * localcache * localcache * localcache * localcache * localcache * localcache * local cache * local cache * local cache * local cache * fix: GroupApplicationAcceptedNotification * fix: GroupApplicationAcceptedNotification * fix: NotificationUserInfoUpdate * feat: cache add single-flight and timing-wheel. * feat: local cache * feat: local cache * feat: local cache * feat: cache add single-flight and timing-wheel. * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * refactor: refactor the code of push and optimization. * cicd: robot automated Change * refactor: rename cache. * merge * fix: refactor project dir avoid import cycle. * update tools * merge * feat: conversation FindRecvMsgNotNotifyUserIDs * feat: conversation FindRecvMsgNotNotifyUserIDs * feat: conversation FindRecvMsgNotNotifyUserIDs * merge * merge the latest main --------- Co-authored-by: Gordon <46924906+FGadvancer@users.noreply.github.com> Co-authored-by: withchao * configGetEnv failed,err:string to int failed: strconv.Atoi: parsing "openim_v3": invalid syntaxr --------- Co-authored-by: chao <48119764+withchao@users.noreply.github.com> Co-authored-by: Gordon <46924906+FGadvancer@users.noreply.github.com> Co-authored-by: withchao * Feature: delete log for update images (#2050) * Error not handled (#2040) * delete * add context deadline exceeded * Error not handled * Error not handled * Error not handled * Error not handled * feat: add local cache for high frequency reads (#2036) * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * fix: mongo * fix: mongo * fix: mongo * openim.yaml * localcache * localcache * localcache * localcache * localcache * localcache * localcache * localcache * localcache * local cache * local cache * local cache * local cache * fix: GroupApplicationAcceptedNotification * fix: GroupApplicationAcceptedNotification * fix: NotificationUserInfoUpdate * feat: cache add single-flight and timing-wheel. * feat: local cache * feat: local cache * feat: local cache * feat: cache add single-flight and timing-wheel. * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * refactor: refactor the code of push and optimization. * cicd: robot automated Change * refactor: rename cache. * merge * fix: refactor project dir avoid import cycle. * update tools * merge * feat: conversation FindRecvMsgNotNotifyUserIDs * feat: conversation FindRecvMsgNotNotifyUserIDs * feat: conversation FindRecvMsgNotNotifyUserIDs * merge * merge the latest main --------- Co-authored-by: Gordon <46924906+FGadvancer@users.noreply.github.com> Co-authored-by: withchao * Fix bug Remove duplicate function definitions (#2033) * delete * delete log * Fix bug configGetEnv failed,err:string to int failed: strconv.Atoi: parsing "openim_v3": invalid syntaxr (#2044) * delete * add context deadline exceeded * Error not handled * Error not handled * Error not handled * Error not handled * configGetEnv failed,err:string to int failed: strconv.Atoi: parsing "openim_v3": invalid syntaxr * delete log (#2047) * delete log --------- Co-authored-by: chao <48119764+withchao@users.noreply.github.com> Co-authored-by: Gordon <46924906+FGadvancer@users.noreply.github.com> Co-authored-by: withchao * test Signed-off-by: unknown <44203734@qq.com> * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * redis address port error * change go proxy --------- Signed-off-by: unknown <44203734@qq.com> Co-authored-by: withchao <993506633@qq.com> Co-authored-by: chao <48119764+withchao@users.noreply.github.com> Co-authored-by: Gordon <46924906+FGadvancer@users.noreply.github.com> Co-authored-by: withchao Co-authored-by: OpenIM Bot <124379614+kubbot@users.noreply.github.com> --- Dockerfile | 3 ++- tools/component/component.go | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index b07ff520e8..71b785629b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,7 +3,8 @@ FROM golang:1.20 AS builder # Set go mod installation source and proxy ARG GO111MODULE=on -ARG GOPROXY=https://goproxy.cn,direct +ARG GOPROXY=https://goproxy.io,direct + ENV GO111MODULE=$GO111MODULE ENV GOPROXY=$GOPROXY diff --git a/tools/component/component.go b/tools/component/component.go index e0d753c3fe..f926f5e400 100644 --- a/tools/component/component.go +++ b/tools/component/component.go @@ -314,7 +314,7 @@ func configGetEnv(config *config.GlobalConfig) error { config.Redis.Username = getEnv("REDIS_USERNAME", config.Redis.Username) config.Redis.Password = getEnv("REDIS_PASSWORD", config.Redis.Password) - config.Redis.Address = getArrEnv("REDIS_ADDRESS", "REDIS_PASSWORD", config.Redis.Address) + config.Redis.Address = getArrEnv("REDIS_ADDRESS", "REDIS_PORT", config.Redis.Address) config.Object.ApiURL = getEnv("OBJECT_APIURL", config.Object.ApiURL) config.Object.Minio.Endpoint = getEnv("MINIO_ENDPOINT", config.Object.Minio.Endpoint) From 572b5acc263dbe1f6b7d3008ea97d699e426211a Mon Sep 17 00:00:00 2001 From: skiffer-git <72860476+skiffer-git@users.noreply.github.com> Date: Sat, 9 Mar 2024 15:25:31 +0800 Subject: [PATCH 106/188] Run in the background (#2065) --- scripts/docker-start-all.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/docker-start-all.sh b/scripts/docker-start-all.sh index 4c9b7308f8..4f8747a2a2 100755 --- a/scripts/docker-start-all.sh +++ b/scripts/docker-start-all.sh @@ -25,5 +25,5 @@ OPENIM_ROOT=$(dirname "${BASH_SOURCE[0]}")/.. source "${OPENIM_ROOT}/scripts/install/common.sh" openim::log::info "\n# Use Docker to start all openim service" trap 'openim::util::onCtrlC' INT -"${OPENIM_ROOT}"/scripts/start-all.sh +"${OPENIM_ROOT}"/scripts/start-all.sh 2>&1 & tail -f ${DOCKER_LOG_FILE} From c12f9dca7cffdb505b39127f76f9b4e568a91773 Mon Sep 17 00:00:00 2001 From: OpenIM Bot <124379614+kubbot@users.noreply.github.com> Date: Sun, 10 Mar 2024 10:24:20 +0800 Subject: [PATCH 107/188] cicd: bump League Patch (#2057) --- internal/push/push_rpc_server.go | 2 +- internal/push/push_to_client.go | 2 +- internal/rpc/conversation/conversaion.go | 5 ++++- internal/rpc/friend/friend.go | 19 +++++++------------ internal/rpc/msg/server.go | 3 +-- internal/rpc/msg/verify.go | 2 +- pkg/common/cachekey/black.go | 14 ++++++++++++++ pkg/common/cachekey/conversation.go | 14 ++++++++++++++ pkg/common/cachekey/friend.go | 14 ++++++++++++++ pkg/common/cachekey/group.go | 14 ++++++++++++++ pkg/common/cachekey/user.go | 14 ++++++++++++++ pkg/common/config/parse_test.go | 3 ++- pkg/common/db/cache/black.go | 6 +++--- pkg/common/db/cache/config.go | 19 +++++++++++++++++-- pkg/common/db/cache/conversation.go | 8 ++++---- pkg/common/db/cache/friend.go | 8 ++++---- pkg/common/db/cache/group.go | 6 +++--- pkg/common/db/cache/meta_cache.go | 2 +- pkg/common/db/cache/msg.go | 4 ++-- pkg/common/db/cache/user.go | 6 +++--- pkg/common/redispubsub/redispubliser.go | 14 ++++++++++++++ pkg/common/redispubsub/redissubscriber.go | 15 +++++++++++++++ pkg/localcache/cache.go | 19 +++++++++++++++++-- pkg/localcache/cache_test.go | 14 ++++++++++++++ pkg/localcache/link/link.go | 14 ++++++++++++++ pkg/localcache/link/link_test.go | 14 ++++++++++++++ pkg/localcache/lru/lru.go | 14 ++++++++++++++ pkg/localcache/lru/lru_expiration.go | 17 ++++++++++++++++- pkg/localcache/lru/lru_lazy.go | 17 ++++++++++++++++- pkg/localcache/lru/lru_lazy_test.go | 14 ++++++++++++++ pkg/localcache/lru/lru_slot.go | 14 ++++++++++++++ pkg/localcache/option.go | 17 ++++++++++++++++- pkg/localcache/tool.go | 14 ++++++++++++++ pkg/rpccache/common.go | 14 ++++++++++++++ pkg/rpccache/conversation.go | 15 +++++++++++++++ pkg/rpccache/friend.go | 17 ++++++++++++++++- pkg/rpccache/group.go | 15 +++++++++++++++ pkg/rpccache/subscriber.go | 15 +++++++++++++++ pkg/rpccache/user.go | 15 +++++++++++++++ tools/component/component.go | 3 ++- 40 files changed, 408 insertions(+), 48 deletions(-) diff --git a/internal/push/push_rpc_server.go b/internal/push/push_rpc_server.go index d5d4c92425..a8bb189749 100644 --- a/internal/push/push_rpc_server.go +++ b/internal/push/push_rpc_server.go @@ -16,7 +16,6 @@ package push import ( "context" - "github.com/openimsdk/open-im-server/v3/pkg/rpccache" "github.com/OpenIMSDK/protocol/constant" pbpush "github.com/OpenIMSDK/protocol/push" @@ -26,6 +25,7 @@ import ( "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" + "github.com/openimsdk/open-im-server/v3/pkg/rpccache" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" "google.golang.org/grpc" ) diff --git a/internal/push/push_to_client.go b/internal/push/push_to_client.go index 2bf17eaf94..d7f30ebce0 100644 --- a/internal/push/push_to_client.go +++ b/internal/push/push_to_client.go @@ -18,7 +18,6 @@ import ( "context" "encoding/json" "errors" - "github.com/openimsdk/open-im-server/v3/pkg/rpccache" "sync" "github.com/OpenIMSDK/protocol/constant" @@ -39,6 +38,7 @@ import ( "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" "github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics" "github.com/openimsdk/open-im-server/v3/pkg/msgprocessor" + "github.com/openimsdk/open-im-server/v3/pkg/rpccache" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" "golang.org/x/sync/errgroup" "google.golang.org/grpc" diff --git a/internal/rpc/conversation/conversaion.go b/internal/rpc/conversation/conversaion.go index 81b4d9d45d..91eec079bd 100644 --- a/internal/rpc/conversation/conversaion.go +++ b/internal/rpc/conversation/conversaion.go @@ -528,7 +528,10 @@ func (c *conversationServer) getConversationInfo( return conversationMsg, nil } -func (c *conversationServer) GetConversationNotReceiveMessageUserIDs(ctx context.Context, req *pbconversation.GetConversationNotReceiveMessageUserIDsReq) (*pbconversation.GetConversationNotReceiveMessageUserIDsResp, error) { +func (c *conversationServer) GetConversationNotReceiveMessageUserIDs( + ctx context.Context, + req *pbconversation.GetConversationNotReceiveMessageUserIDsReq, +) (*pbconversation.GetConversationNotReceiveMessageUserIDsResp, error) { userIDs, err := c.conversationDatabase.GetConversationNotReceiveMessageUserIDs(ctx, req.ConversationID) if err != nil { return nil, err diff --git a/internal/rpc/friend/friend.go b/internal/rpc/friend/friend.go index 9466c52245..6403a4159d 100644 --- a/internal/rpc/friend/friend.go +++ b/internal/rpc/friend/friend.go @@ -16,31 +16,26 @@ package friend import ( "context" - "github.com/OpenIMSDK/tools/tx" - - "github.com/OpenIMSDK/protocol/sdkws" - - "github.com/openimsdk/open-im-server/v3/pkg/authverify" - - "github.com/OpenIMSDK/tools/log" - - "github.com/openimsdk/open-im-server/v3/pkg/common/convert" - "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" - - "google.golang.org/grpc" "github.com/OpenIMSDK/protocol/constant" pbfriend "github.com/OpenIMSDK/protocol/friend" + "github.com/OpenIMSDK/protocol/sdkws" registry "github.com/OpenIMSDK/tools/discoveryregistry" "github.com/OpenIMSDK/tools/errs" + "github.com/OpenIMSDK/tools/log" + "github.com/OpenIMSDK/tools/tx" "github.com/OpenIMSDK/tools/utils" + "github.com/openimsdk/open-im-server/v3/pkg/authverify" "github.com/openimsdk/open-im-server/v3/pkg/common/config" + "github.com/openimsdk/open-im-server/v3/pkg/common/convert" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" "github.com/openimsdk/open-im-server/v3/pkg/common/db/mgo" tablerelation "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" "github.com/openimsdk/open-im-server/v3/pkg/common/db/unrelation" + "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient/notification" + "google.golang.org/grpc" ) type friendServer struct { diff --git a/internal/rpc/msg/server.go b/internal/rpc/msg/server.go index 6212dea032..f2d735a70c 100644 --- a/internal/rpc/msg/server.go +++ b/internal/rpc/msg/server.go @@ -15,8 +15,6 @@ package msg import ( - "github.com/openimsdk/open-im-server/v3/pkg/rpccache" - "github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/protocol/conversation" "github.com/OpenIMSDK/protocol/msg" @@ -25,6 +23,7 @@ import ( "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" "github.com/openimsdk/open-im-server/v3/pkg/common/db/unrelation" + "github.com/openimsdk/open-im-server/v3/pkg/rpccache" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" "google.golang.org/grpc" ) diff --git a/internal/rpc/msg/verify.go b/internal/rpc/msg/verify.go index 318464cf82..bdaa7fd87f 100644 --- a/internal/rpc/msg/verify.go +++ b/internal/rpc/msg/verify.go @@ -16,7 +16,6 @@ package msg import ( "context" - "github.com/OpenIMSDK/tools/log" "math/rand" "strconv" "time" @@ -25,6 +24,7 @@ import ( "github.com/OpenIMSDK/protocol/msg" "github.com/OpenIMSDK/protocol/sdkws" "github.com/OpenIMSDK/tools/errs" + "github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/utils" ) diff --git a/pkg/common/cachekey/black.go b/pkg/common/cachekey/black.go index 527ad14dc2..7d2ee2771f 100644 --- a/pkg/common/cachekey/black.go +++ b/pkg/common/cachekey/black.go @@ -1,3 +1,17 @@ +// 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 cachekey const ( diff --git a/pkg/common/cachekey/conversation.go b/pkg/common/cachekey/conversation.go index 665ca11c6c..aea4ceec68 100644 --- a/pkg/common/cachekey/conversation.go +++ b/pkg/common/cachekey/conversation.go @@ -1,3 +1,17 @@ +// 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 cachekey const ( diff --git a/pkg/common/cachekey/friend.go b/pkg/common/cachekey/friend.go index f37c9da37d..9691b1f5c9 100644 --- a/pkg/common/cachekey/friend.go +++ b/pkg/common/cachekey/friend.go @@ -1,3 +1,17 @@ +// 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 cachekey const ( diff --git a/pkg/common/cachekey/group.go b/pkg/common/cachekey/group.go index 1dcf0ffcef..681121ecba 100644 --- a/pkg/common/cachekey/group.go +++ b/pkg/common/cachekey/group.go @@ -1,3 +1,17 @@ +// 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 cachekey import ( diff --git a/pkg/common/cachekey/user.go b/pkg/common/cachekey/user.go index 3fb877e222..473ca1b12f 100644 --- a/pkg/common/cachekey/user.go +++ b/pkg/common/cachekey/user.go @@ -1,3 +1,17 @@ +// 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 cachekey const ( diff --git a/pkg/common/config/parse_test.go b/pkg/common/config/parse_test.go index 9b964a2777..35b019b837 100644 --- a/pkg/common/config/parse_test.go +++ b/pkg/common/config/parse_test.go @@ -17,10 +17,11 @@ package config import ( _ "embed" "fmt" - "gopkg.in/yaml.v3" "reflect" "testing" + "gopkg.in/yaml.v3" + "github.com/openimsdk/open-im-server/v3/pkg/msgprocessor" ) diff --git a/pkg/common/db/cache/black.go b/pkg/common/db/cache/black.go index fd743e9179..a5304b4b0d 100644 --- a/pkg/common/db/cache/black.go +++ b/pkg/common/db/cache/black.go @@ -16,12 +16,12 @@ package cache import ( "context" - "github.com/OpenIMSDK/tools/log" - "github.com/openimsdk/open-im-server/v3/pkg/common/cachekey" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" "time" + "github.com/OpenIMSDK/tools/log" "github.com/dtm-labs/rockscache" + "github.com/openimsdk/open-im-server/v3/pkg/common/cachekey" + "github.com/openimsdk/open-im-server/v3/pkg/common/config" relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" "github.com/redis/go-redis/v9" ) diff --git a/pkg/common/db/cache/config.go b/pkg/common/db/cache/config.go index 7599d8a115..c760e0c033 100644 --- a/pkg/common/db/cache/config.go +++ b/pkg/common/db/cache/config.go @@ -1,10 +1,25 @@ +// 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 cache import ( - "github.com/openimsdk/open-im-server/v3/pkg/common/cachekey" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" "strings" "sync" + + "github.com/openimsdk/open-im-server/v3/pkg/common/cachekey" + "github.com/openimsdk/open-im-server/v3/pkg/common/config" ) var ( diff --git a/pkg/common/db/cache/conversation.go b/pkg/common/db/cache/conversation.go index ef725642c7..c8f752cd39 100644 --- a/pkg/common/db/cache/conversation.go +++ b/pkg/common/db/cache/conversation.go @@ -16,15 +16,15 @@ package cache import ( "context" - "github.com/OpenIMSDK/tools/log" - "github.com/openimsdk/open-im-server/v3/pkg/common/cachekey" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" "math/big" "strings" "time" + "github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/utils" "github.com/dtm-labs/rockscache" + "github.com/openimsdk/open-im-server/v3/pkg/common/cachekey" + "github.com/openimsdk/open-im-server/v3/pkg/common/config" relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" "github.com/redis/go-redis/v9" ) @@ -37,7 +37,7 @@ const ( //recvMsgOptKey = "RECV_MSG_OPT:" //superGroupRecvMsgNotNotifyUserIDsKey = "SUPER_GROUP_RECV_MSG_NOT_NOTIFY_USER_IDS:" //superGroupRecvMsgNotNotifyUserIDsHashKey = "SUPER_GROUP_RECV_MSG_NOT_NOTIFY_USER_IDS_HASH:" - //conversationNotReceiveMessageUserIDsKey = "CONVERSATION_NOT_RECEIVE_MESSAGE_USER_IDS:" + //conversationNotReceiveMessageUserIDsKey = "CONVERSATION_NOT_RECEIVE_MESSAGE_USER_IDS:". conversationExpireTime = time.Second * 60 * 60 * 12 ) diff --git a/pkg/common/db/cache/friend.go b/pkg/common/db/cache/friend.go index 30b8bf7eaf..2d20705ef8 100644 --- a/pkg/common/db/cache/friend.go +++ b/pkg/common/db/cache/friend.go @@ -16,13 +16,13 @@ package cache import ( "context" - "github.com/OpenIMSDK/tools/log" - "github.com/openimsdk/open-im-server/v3/pkg/common/cachekey" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" "time" + "github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/utils" "github.com/dtm-labs/rockscache" + "github.com/openimsdk/open-im-server/v3/pkg/common/cachekey" + "github.com/openimsdk/open-im-server/v3/pkg/common/config" relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" "github.com/redis/go-redis/v9" ) @@ -31,7 +31,7 @@ const ( friendExpireTime = time.Second * 60 * 60 * 12 //friendIDsKey = "FRIEND_IDS:" //TwoWayFriendsIDsKey = "COMMON_FRIENDS_IDS:" - //friendKey = "FRIEND_INFO:" + //friendKey = "FRIEND_INFO:". ) // FriendCache is an interface for caching friend-related data. diff --git a/pkg/common/db/cache/group.go b/pkg/common/db/cache/group.go index 37b21ae902..7022461cbb 100644 --- a/pkg/common/db/cache/group.go +++ b/pkg/common/db/cache/group.go @@ -17,8 +17,6 @@ package cache import ( "context" "fmt" - "github.com/openimsdk/open-im-server/v3/pkg/common/cachekey" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" "time" "github.com/OpenIMSDK/protocol/constant" @@ -26,6 +24,8 @@ import ( "github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/utils" "github.com/dtm-labs/rockscache" + "github.com/openimsdk/open-im-server/v3/pkg/common/cachekey" + "github.com/openimsdk/open-im-server/v3/pkg/common/config" relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" "github.com/redis/go-redis/v9" ) @@ -38,7 +38,7 @@ const ( //groupMemberInfoKey = "GROUP_MEMBER_INFO:" //joinedGroupsKey = "JOIN_GROUPS_KEY:" //groupMemberNumKey = "GROUP_MEMBER_NUM_CACHE:" - //groupRoleLevelMemberIDsKey = "GROUP_ROLE_LEVEL_MEMBER_IDS:" + //groupRoleLevelMemberIDsKey = "GROUP_ROLE_LEVEL_MEMBER_IDS:". ) type GroupHash interface { diff --git a/pkg/common/db/cache/meta_cache.go b/pkg/common/db/cache/meta_cache.go index b148513814..431b7c867e 100644 --- a/pkg/common/db/cache/meta_cache.go +++ b/pkg/common/db/cache/meta_cache.go @@ -18,7 +18,6 @@ import ( "context" "encoding/json" "errors" - "github.com/redis/go-redis/v9" "fmt" "time" @@ -27,6 +26,7 @@ import ( "github.com/OpenIMSDK/tools/mw/specialerror" "github.com/OpenIMSDK/tools/utils" "github.com/dtm-labs/rockscache" + "github.com/redis/go-redis/v9" ) const ( diff --git a/pkg/common/db/cache/msg.go b/pkg/common/db/cache/msg.go index eb79fdb704..b8e9dbc774 100644 --- a/pkg/common/db/cache/msg.go +++ b/pkg/common/db/cache/msg.go @@ -38,11 +38,11 @@ const ( conversationUserMinSeq = "CON_USER_MIN_SEQ:" hasReadSeq = "HAS_READ_SEQ:" - //appleDeviceToken = "DEVICE_TOKEN" + //appleDeviceToken = "DEVICE_TOKEN". getuiToken = "GETUI_TOKEN" getuiTaskID = "GETUI_TASK_ID" //signalCache = "SIGNAL_CACHE:" - //signalListCache = "SIGNAL_LIST_CACHE:" + //signalListCache = "SIGNAL_LIST_CACHE:". FCM_TOKEN = "FCM_TOKEN:" messageCache = "MESSAGE_CACHE:" diff --git a/pkg/common/db/cache/user.go b/pkg/common/db/cache/user.go index c081731ce4..a60f558361 100644 --- a/pkg/common/db/cache/user.go +++ b/pkg/common/db/cache/user.go @@ -18,8 +18,6 @@ import ( "context" "encoding/json" "errors" - "github.com/openimsdk/open-im-server/v3/pkg/common/cachekey" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" "hash/crc32" "strconv" "time" @@ -29,13 +27,15 @@ import ( "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/log" "github.com/dtm-labs/rockscache" + "github.com/openimsdk/open-im-server/v3/pkg/common/cachekey" + "github.com/openimsdk/open-im-server/v3/pkg/common/config" relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" "github.com/redis/go-redis/v9" ) const ( userExpireTime = time.Second * 60 * 60 * 12 - //userInfoKey = "USER_INFO:" + //userInfoKey = "USER_INFO:". userGlobalRecvMsgOptKey = "USER_GLOBAL_RECV_MSG_OPT_KEY:" olineStatusKey = "ONLINE_STATUS:" userOlineStatusExpireTime = time.Second * 60 * 60 * 24 diff --git a/pkg/common/redispubsub/redispubliser.go b/pkg/common/redispubsub/redispubliser.go index 822b25bf9d..6e41af73a0 100644 --- a/pkg/common/redispubsub/redispubliser.go +++ b/pkg/common/redispubsub/redispubliser.go @@ -1,3 +1,17 @@ +// 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 redispubsub import "github.com/redis/go-redis/v9" diff --git a/pkg/common/redispubsub/redissubscriber.go b/pkg/common/redispubsub/redissubscriber.go index a7029a9932..aea99b3182 100644 --- a/pkg/common/redispubsub/redissubscriber.go +++ b/pkg/common/redispubsub/redissubscriber.go @@ -1,7 +1,22 @@ +// 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 redispubsub import ( "context" + "github.com/redis/go-redis/v9" ) diff --git a/pkg/localcache/cache.go b/pkg/localcache/cache.go index 4b405b46ac..91c490922f 100644 --- a/pkg/localcache/cache.go +++ b/pkg/localcache/cache.go @@ -1,11 +1,26 @@ +// 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 localcache import ( "context" - "github.com/openimsdk/localcache/link" - "github.com/openimsdk/localcache/lru" "hash/fnv" "unsafe" + + "github.com/openimsdk/localcache/link" + "github.com/openimsdk/localcache/lru" ) type Cache[V any] interface { diff --git a/pkg/localcache/cache_test.go b/pkg/localcache/cache_test.go index c497b7b4ab..c206e67992 100644 --- a/pkg/localcache/cache_test.go +++ b/pkg/localcache/cache_test.go @@ -1,3 +1,17 @@ +// 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 localcache import ( diff --git a/pkg/localcache/link/link.go b/pkg/localcache/link/link.go index 4f238907b9..8c7701506e 100644 --- a/pkg/localcache/link/link.go +++ b/pkg/localcache/link/link.go @@ -1,3 +1,17 @@ +// 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 link import ( diff --git a/pkg/localcache/link/link_test.go b/pkg/localcache/link/link_test.go index ed684e6939..bb9fee6a0b 100644 --- a/pkg/localcache/link/link_test.go +++ b/pkg/localcache/link/link_test.go @@ -1,3 +1,17 @@ +// 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 link import ( diff --git a/pkg/localcache/lru/lru.go b/pkg/localcache/lru/lru.go index 2995ec028d..64280f238f 100644 --- a/pkg/localcache/lru/lru.go +++ b/pkg/localcache/lru/lru.go @@ -1,3 +1,17 @@ +// 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 lru import "github.com/hashicorp/golang-lru/v2/simplelru" diff --git a/pkg/localcache/lru/lru_expiration.go b/pkg/localcache/lru/lru_expiration.go index 3cf61f0616..970ac083e3 100644 --- a/pkg/localcache/lru/lru_expiration.go +++ b/pkg/localcache/lru/lru_expiration.go @@ -1,9 +1,24 @@ +// 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 lru import ( - "github.com/hashicorp/golang-lru/v2/expirable" "sync" "time" + + "github.com/hashicorp/golang-lru/v2/expirable" ) func NewExpirationLRU[K comparable, V any](size int, successTTL, failedTTL time.Duration, target Target, onEvict EvictCallback[K, V]) LRU[K, V] { diff --git a/pkg/localcache/lru/lru_lazy.go b/pkg/localcache/lru/lru_lazy.go index a9270ea4a8..d6e64aae43 100644 --- a/pkg/localcache/lru/lru_lazy.go +++ b/pkg/localcache/lru/lru_lazy.go @@ -1,9 +1,24 @@ +// 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 lru import ( - "github.com/hashicorp/golang-lru/v2/simplelru" "sync" "time" + + "github.com/hashicorp/golang-lru/v2/simplelru" ) type layLruItem[V any] struct { diff --git a/pkg/localcache/lru/lru_lazy_test.go b/pkg/localcache/lru/lru_lazy_test.go index 09fd04cd3b..167dd2135b 100644 --- a/pkg/localcache/lru/lru_lazy_test.go +++ b/pkg/localcache/lru/lru_lazy_test.go @@ -1,3 +1,17 @@ +// 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 lru import ( diff --git a/pkg/localcache/lru/lru_slot.go b/pkg/localcache/lru/lru_slot.go index c1b8b94d07..d034e94d32 100644 --- a/pkg/localcache/lru/lru_slot.go +++ b/pkg/localcache/lru/lru_slot.go @@ -1,3 +1,17 @@ +// 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 lru func NewSlotLRU[K comparable, V any](slotNum int, hash func(K) uint64, create func() LRU[K, V]) LRU[K, V] { diff --git a/pkg/localcache/option.go b/pkg/localcache/option.go index ecb5da0e63..e60d5aa07b 100644 --- a/pkg/localcache/option.go +++ b/pkg/localcache/option.go @@ -1,9 +1,24 @@ +// 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 localcache import ( "context" - "github.com/openimsdk/localcache/lru" "time" + + "github.com/openimsdk/localcache/lru" ) func defaultOption() *option { diff --git a/pkg/localcache/tool.go b/pkg/localcache/tool.go index ea35908233..ec04ea990a 100644 --- a/pkg/localcache/tool.go +++ b/pkg/localcache/tool.go @@ -1,3 +1,17 @@ +// 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 localcache func AnyValue[V any](v any, err error) (V, error) { diff --git a/pkg/rpccache/common.go b/pkg/rpccache/common.go index 6dc826e305..5ed007edc4 100644 --- a/pkg/rpccache/common.go +++ b/pkg/rpccache/common.go @@ -1,3 +1,17 @@ +// 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 rpccache func newListMap[V comparable](values []V, err error) (*listMap[V], error) { diff --git a/pkg/rpccache/conversation.go b/pkg/rpccache/conversation.go index ae77b29b70..027ef42fa6 100644 --- a/pkg/rpccache/conversation.go +++ b/pkg/rpccache/conversation.go @@ -1,7 +1,22 @@ +// 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 rpccache import ( "context" + pbconversation "github.com/OpenIMSDK/protocol/conversation" "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/log" diff --git a/pkg/rpccache/friend.go b/pkg/rpccache/friend.go index 66694f6181..35122fff5a 100644 --- a/pkg/rpccache/friend.go +++ b/pkg/rpccache/friend.go @@ -1,7 +1,22 @@ +// 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 rpccache import ( "context" + "github.com/OpenIMSDK/tools/log" "github.com/openimsdk/localcache" "github.com/openimsdk/open-im-server/v3/pkg/common/cachekey" @@ -49,7 +64,7 @@ func (f *FriendLocalCache) IsFriend(ctx context.Context, possibleFriendUserID, u }, cachekey.GetFriendIDsKey(possibleFriendUserID))) } -// IsBlack possibleBlackUserID selfUserID +// IsBlack possibleBlackUserID selfUserID. func (f *FriendLocalCache) IsBlack(ctx context.Context, possibleBlackUserID, userID string) (val bool, err error) { log.ZDebug(ctx, "FriendLocalCache IsBlack req", "possibleBlackUserID", possibleBlackUserID, "userID", userID) defer func() { diff --git a/pkg/rpccache/group.go b/pkg/rpccache/group.go index b3c666da4a..402f63185e 100644 --- a/pkg/rpccache/group.go +++ b/pkg/rpccache/group.go @@ -1,7 +1,22 @@ +// 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 rpccache import ( "context" + "github.com/OpenIMSDK/protocol/sdkws" "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/log" diff --git a/pkg/rpccache/subscriber.go b/pkg/rpccache/subscriber.go index 571ff6d2db..cd65094e2b 100644 --- a/pkg/rpccache/subscriber.go +++ b/pkg/rpccache/subscriber.go @@ -1,8 +1,23 @@ +// 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 rpccache import ( "context" "encoding/json" + "github.com/OpenIMSDK/tools/log" "github.com/redis/go-redis/v9" ) diff --git a/pkg/rpccache/user.go b/pkg/rpccache/user.go index 7d6cd5c7e3..c48b058214 100644 --- a/pkg/rpccache/user.go +++ b/pkg/rpccache/user.go @@ -1,7 +1,22 @@ +// 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 rpccache import ( "context" + "github.com/OpenIMSDK/protocol/sdkws" "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/log" diff --git a/tools/component/component.go b/tools/component/component.go index f926f5e400..3220f36f73 100644 --- a/tools/component/component.go +++ b/tools/component/component.go @@ -30,8 +30,9 @@ import ( "github.com/OpenIMSDK/tools/component" "github.com/OpenIMSDK/tools/errs" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" "gopkg.in/yaml.v3" + + "github.com/openimsdk/open-im-server/v3/pkg/common/config" ) const ( From 3a1615795e973b1ce4a61ea6eda97def9af9dcf2 Mon Sep 17 00:00:00 2001 From: Xinwei Xiong <3293172751NSS@gmail.com> Date: Sun, 10 Mar 2024 13:03:27 +0800 Subject: [PATCH 108/188] feat: add scripts verify shell check (#2068) --- scripts/verify-shellcheck.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/verify-shellcheck.sh b/scripts/verify-shellcheck.sh index c7e713d093..0c4f165bf3 100755 --- a/scripts/verify-shellcheck.sh +++ b/scripts/verify-shellcheck.sh @@ -87,6 +87,7 @@ disabled=( 2178 2064 2260 + 2261 2043 2178 2044 From 5454c512e00d355e88f359cf6d693d577088b367 Mon Sep 17 00:00:00 2001 From: Xinwei Xiong <3293172751NSS@gmail.com> Date: Sun, 10 Mar 2024 13:34:08 +0800 Subject: [PATCH 109/188] fix: fix docker file images proxy (#2069) * fix: fix docker file images proxy * fix: fix docker file images proxy --- Dockerfile | 2 -- build/images/openim-api/Dockerfile | 2 +- build/images/openim-cmdutils/Dockerfile | 2 +- build/images/openim-crontask/Dockerfile | 2 +- build/images/openim-msggateway/Dockerfile | 2 +- build/images/openim-msgtransfer/Dockerfile | 2 +- build/images/openim-push/Dockerfile | 2 +- build/images/openim-rpc-auth/Dockerfile | 2 +- build/images/openim-rpc-conversation/Dockerfile | 2 +- build/images/openim-rpc-friend/Dockerfile | 2 +- build/images/openim-rpc-group/Dockerfile | 2 +- build/images/openim-rpc-msg/Dockerfile | 2 +- build/images/openim-rpc-third/Dockerfile | 2 +- build/images/openim-rpc-user/Dockerfile | 2 +- build/images/openim-tools/component/Dockerfile | 2 +- build/images/openim-tools/openim-web/Dockerfile | 2 +- 16 files changed, 15 insertions(+), 17 deletions(-) diff --git a/Dockerfile b/Dockerfile index 71b785629b..514a63db4f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -11,8 +11,6 @@ ENV GOPROXY=$GOPROXY # Set up the working directory WORKDIR /openim/openim-server - - # Copy all files to the container ADD . . diff --git a/build/images/openim-api/Dockerfile b/build/images/openim-api/Dockerfile index 8c3d710f13..5832c31a61 100644 --- a/build/images/openim-api/Dockerfile +++ b/build/images/openim-api/Dockerfile @@ -19,7 +19,7 @@ FROM golang:1.20 AS builder ARG GO111MODULE=on -ARG GOPROXY=https://goproxy.cn,direct +ARG GOPROXY=https://goproxy.io,direct WORKDIR /openim/openim-server diff --git a/build/images/openim-cmdutils/Dockerfile b/build/images/openim-cmdutils/Dockerfile index 413016f24f..5afbe6ecec 100644 --- a/build/images/openim-cmdutils/Dockerfile +++ b/build/images/openim-cmdutils/Dockerfile @@ -19,7 +19,7 @@ FROM golang:1.20 AS builder ARG GO111MODULE=on -ARG GOPROXY=https://goproxy.cn,direct +ARG GOPROXY=https://goproxy.io,direct WORKDIR /openim/openim-server diff --git a/build/images/openim-crontask/Dockerfile b/build/images/openim-crontask/Dockerfile index 35ba757848..4019e16c12 100644 --- a/build/images/openim-crontask/Dockerfile +++ b/build/images/openim-crontask/Dockerfile @@ -19,7 +19,7 @@ FROM golang:1.20 AS builder ARG GO111MODULE=on -ARG GOPROXY=https://goproxy.cn,direct +ARG GOPROXY=https://goproxy.io,direct WORKDIR /openim/openim-server diff --git a/build/images/openim-msggateway/Dockerfile b/build/images/openim-msggateway/Dockerfile index fe9db8f324..c9d1ce949c 100644 --- a/build/images/openim-msggateway/Dockerfile +++ b/build/images/openim-msggateway/Dockerfile @@ -19,7 +19,7 @@ FROM golang:1.20 AS builder ARG GO111MODULE=on -ARG GOPROXY=https://goproxy.cn,direct +ARG GOPROXY=https://goproxy.io,direct WORKDIR /openim/openim-server diff --git a/build/images/openim-msgtransfer/Dockerfile b/build/images/openim-msgtransfer/Dockerfile index c04425f94a..08a026c350 100644 --- a/build/images/openim-msgtransfer/Dockerfile +++ b/build/images/openim-msgtransfer/Dockerfile @@ -19,7 +19,7 @@ FROM golang:1.20 AS builder ARG GO111MODULE=on -ARG GOPROXY=https://goproxy.cn,direct +ARG GOPROXY=https://goproxy.io,direct WORKDIR /openim/openim-server diff --git a/build/images/openim-push/Dockerfile b/build/images/openim-push/Dockerfile index e51b7a44c5..43a3833c2a 100644 --- a/build/images/openim-push/Dockerfile +++ b/build/images/openim-push/Dockerfile @@ -19,7 +19,7 @@ FROM golang:1.20 AS builder ARG GO111MODULE=on -ARG GOPROXY=https://goproxy.cn,direct +ARG GOPROXY=https://goproxy.io,direct WORKDIR /openim/openim-server diff --git a/build/images/openim-rpc-auth/Dockerfile b/build/images/openim-rpc-auth/Dockerfile index 8054935bd8..6a64c3e79e 100644 --- a/build/images/openim-rpc-auth/Dockerfile +++ b/build/images/openim-rpc-auth/Dockerfile @@ -19,7 +19,7 @@ FROM golang:1.20 AS builder ARG GO111MODULE=on -ARG GOPROXY=https://goproxy.cn,direct +ARG GOPROXY=https://goproxy.io,direct WORKDIR /openim/openim-server diff --git a/build/images/openim-rpc-conversation/Dockerfile b/build/images/openim-rpc-conversation/Dockerfile index 0cfb681a2d..421755094b 100644 --- a/build/images/openim-rpc-conversation/Dockerfile +++ b/build/images/openim-rpc-conversation/Dockerfile @@ -19,7 +19,7 @@ FROM golang:1.20 AS builder ARG GO111MODULE=on -ARG GOPROXY=https://goproxy.cn,direct +ARG GOPROXY=https://goproxy.io,direct WORKDIR /openim/openim-server diff --git a/build/images/openim-rpc-friend/Dockerfile b/build/images/openim-rpc-friend/Dockerfile index 36870bc7e9..ba3a381162 100644 --- a/build/images/openim-rpc-friend/Dockerfile +++ b/build/images/openim-rpc-friend/Dockerfile @@ -19,7 +19,7 @@ FROM golang:1.20 AS builder ARG GO111MODULE=on -ARG GOPROXY=https://goproxy.cn,direct +ARG GOPROXY=https://goproxy.io,direct WORKDIR /openim/openim-server diff --git a/build/images/openim-rpc-group/Dockerfile b/build/images/openim-rpc-group/Dockerfile index 85ba3b74dc..916c8e848c 100644 --- a/build/images/openim-rpc-group/Dockerfile +++ b/build/images/openim-rpc-group/Dockerfile @@ -19,7 +19,7 @@ FROM golang:1.20 AS builder ARG GO111MODULE=on -ARG GOPROXY=https://goproxy.cn,direct +ARG GOPROXY=https://goproxy.io,direct WORKDIR /openim/openim-server diff --git a/build/images/openim-rpc-msg/Dockerfile b/build/images/openim-rpc-msg/Dockerfile index 7e1aaf50b4..a0ac98c472 100644 --- a/build/images/openim-rpc-msg/Dockerfile +++ b/build/images/openim-rpc-msg/Dockerfile @@ -19,7 +19,7 @@ FROM golang:1.20 AS builder ARG GO111MODULE=on -ARG GOPROXY=https://goproxy.cn,direct +ARG GOPROXY=https://goproxy.io,direct WORKDIR /openim/openim-server diff --git a/build/images/openim-rpc-third/Dockerfile b/build/images/openim-rpc-third/Dockerfile index ab3e6c949b..9fe17dd408 100644 --- a/build/images/openim-rpc-third/Dockerfile +++ b/build/images/openim-rpc-third/Dockerfile @@ -19,7 +19,7 @@ FROM golang:1.20 AS builder ARG GO111MODULE=on -ARG GOPROXY=https://goproxy.cn,direct +ARG GOPROXY=https://goproxy.io,direct WORKDIR /openim/openim-server diff --git a/build/images/openim-rpc-user/Dockerfile b/build/images/openim-rpc-user/Dockerfile index cd0121b7d8..bdd0a42eee 100644 --- a/build/images/openim-rpc-user/Dockerfile +++ b/build/images/openim-rpc-user/Dockerfile @@ -19,7 +19,7 @@ FROM golang:1.20 AS builder ARG GO111MODULE=on -ARG GOPROXY=https://goproxy.cn,direct +ARG GOPROXY=https://goproxy.io,direct WORKDIR /openim/openim-server diff --git a/build/images/openim-tools/component/Dockerfile b/build/images/openim-tools/component/Dockerfile index 1be6e776fd..1f7a1a46a5 100644 --- a/build/images/openim-tools/component/Dockerfile +++ b/build/images/openim-tools/component/Dockerfile @@ -19,7 +19,7 @@ FROM golang:1.20 AS builder ARG GO111MODULE=on -ARG GOPROXY=https://goproxy.cn,direct +ARG GOPROXY=https://goproxy.io,direct WORKDIR /openim/openim-server diff --git a/build/images/openim-tools/openim-web/Dockerfile b/build/images/openim-tools/openim-web/Dockerfile index 77ca4cf49d..d145011890 100644 --- a/build/images/openim-tools/openim-web/Dockerfile +++ b/build/images/openim-tools/openim-web/Dockerfile @@ -19,7 +19,7 @@ FROM golang:1.20 AS builder ARG GO111MODULE=on -ARG GOPROXY=https://goproxy.cn,direct +ARG GOPROXY=https://goproxy.io,direct WORKDIR /openim/openim-server From cd7f35452e10f3e3e483c8ecb44ab364575bffc3 Mon Sep 17 00:00:00 2001 From: Xinwei Xiong <3293172751NSS@gmail.com> Date: Mon, 11 Mar 2024 15:54:33 +0800 Subject: [PATCH 110/188] fix: fix docker file images proxy (#2071) * fix: fix docker file images proxy * fix: fix docker file images proxy * docs: optimize openim go code and logging docs --- docs/contrib/bash-log.md | 2 + docs/contrib/go-code.md | 286 ++++++++++++++++++++++++++- docs/contrib/logging.md | 406 +++++++++++++++++++++++++++++++++++++-- scripts/cherry-pick.sh | 4 - 4 files changed, 664 insertions(+), 34 deletions(-) diff --git a/docs/contrib/bash-log.md b/docs/contrib/bash-log.md index 7725d55893..f8b319f6c3 100644 --- a/docs/contrib/bash-log.md +++ b/docs/contrib/bash-log.md @@ -2,6 +2,8 @@ **PATH:** `scripts/lib/logging.sh` + + ### Introduction OpenIM, an intricate project, requires a robust logging mechanism to diagnose issues, maintain system health, and provide insights. A custom-built logging system embedded within OpenIM ensures consistent and structured logs. Let's delve into the design of this logging system and understand its various functions and their usage scenarios. diff --git a/docs/contrib/go-code.md b/docs/contrib/go-code.md index b122917ca7..5c02127251 100644 --- a/docs/contrib/go-code.md +++ b/docs/contrib/go-code.md @@ -266,13 +266,61 @@ errors.New("redis connection failed") - When specifying ranges of numbers, use inclusive ranges whenever possible. - Go 1.13 or above is recommended, and the error generation method is `fmt.Errorf("module xxx: %w", err)`. -### 1.4 panic processing +### 1.4 Panic Processing + +The use of `panic` should be carefully controlled in Go applications to ensure program stability and predictable error handling. Following are revised guidelines emphasizing the restriction on using `panic` and promoting alternative strategies for error handling and program termination. + +- **Prohibited in Business Logic:** Using `panic` within business logic processing is strictly prohibited. Business logic should handle errors gracefully and use error returns to propagate issues up the call stack. + +- **Restricted Use in Main Package:** In the main package, the use of `panic` should be reserved for situations where the program is entirely inoperable, such as failure to open essential files, inability to connect to the database, or other critical startup issues. Even in these scenarios, prefer using structured error handling to terminate the program. + +- **Use `log.Fatal` for Critical Errors:** Instead of panicking, use `log.Fatal` to log critical errors that prevent the program from operating normally. This approach allows the program to terminate while ensuring the error is properly logged for troubleshooting. + +- **Prohibition on Exportable Interfaces:** Exportable interfaces must not invoke `panic`. They should handle errors gracefully and return errors as part of their contract. + +- **Prefer Errors Over Panic:** It is recommended to use error returns instead of panic to convey errors within a package. This approach promotes error handling that integrates smoothly with Go's error handling idioms. + +#### Alternative to Panic: Structured Program Termination + +To enforce these guidelines, consider implementing structured functions to terminate the program gracefully in the face of unrecoverable errors, while providing clear error messages. Here are two recommended functions: + +```go +// ExitWithError logs an error message and exits the program with a non-zero status. +func ExitWithError(err error) { + progName := filepath.Base(os.Args[0]) + fmt.Fprintf(os.Stderr, "%s exit -1: %+v\n", progName, err) + os.Exit(-1) +} + +// SIGTERMExit logs a warning message when the program receives a SIGTERM signal and exits with status 0. +func SIGTERMExit() { + progName := filepath.Base(os.Args[0]) + fmt.Fprintf(os.Stderr, "Warning %s receive process terminal SIGTERM exit 0\n", progName) +} +``` + +#### Example Usage: + +```go +import ( + _ "net/http/pprof" + + "github.com/openimsdk/open-im-server/v3/pkg/common/cmd" + util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" +) + +func main() { + apiCmd := cmd.NewApiCmd() + apiCmd.AddPortFlag() + apiCmd.AddPrometheusPortFlag() + if err := apiCmd.Execute(); err != nil { + util.ExitWithError(err) + } +} +``` + +In this example, `ExitWithError` is used to terminate the program when an unrecoverable error occurs, providing a clear error message to stderr and exiting with a non-zero status. This approach ensures that critical errors are logged and the program exits in a controlled manner, facilitating troubleshooting and maintaining the stability of the application. -- Panic is prohibited in business logic processing. -- In the main package, panic is only used when the program is completely inoperable, for example, the file cannot be opened, the database cannot be connected, and the program cannot run normally. -- In the main package, use `log.Fatal` to record errors, so that the program can be terminated by the log, or the exception thrown by the panic can be recorded in the log file, which is convenient for troubleshooting. -- An exportable interface must not panic. -- It is recommended to use error instead of panic to convey errors in the package. ### 1.5 Unit Tests @@ -439,10 +487,15 @@ var allowGitHook bool - Local variables should be as short as possible, for example, use buf to refer to buffer, and use i to refer to index. - The code automatically generated by the code generation tool can exclude this rule (such as the Id in `xxx.pb.go`) -### 2.7 Constant naming +### 2.7 Constant Naming + +In Go, constants play a critical role in defining values that do not change throughout the execution of a program. Adhering to best practices in naming constants can significantly improve the readability and maintainability of your code. Here are some guidelines for constant naming: -- The constant name must follow the camel case, and the initial letter is uppercase or lowercase according to the access control decision. -- If it is a constant of enumeration type, you need to create the corresponding type first: +- **Camel Case Naming:** The name of a constant must follow the camel case notation. The initial letter should be uppercase or lowercase based on the access control requirements. Uppercase indicates that the constant is exported (visible outside the package), while lowercase indicates package-private visibility (visible only within its own package). + +- **Enumeration Type Constants:** For constants that represent a set of enumerated values, it's recommended to define a corresponding type first. This approach not only enhances type safety but also improves code readability by clearly indicating the purpose of the enumeration. + +**Example:** ```go // Code defines an error code type. @@ -452,11 +505,40 @@ type Code int const ( // ErrUnknown - 0: An unknown error occurred. ErrUnknown Code = iota - // ErrFatal - 1: An fatal error occurred. + // ErrFatal - 1: A fatal error occurred. ErrFatal ) ``` +In the example above, `Code` is defined as a new type based on `int`. The enumerated constants `ErrUnknown` and `ErrFatal` are then defined with explicit comments to indicate their purpose and values. This pattern is particularly useful for grouping related constants and providing additional context. + +### Global Variables and Constants Across Packages + +- **Use Constants for Global Variables:** When defining variables that are intended to be accessed across packages, prefer using constants to ensure immutability. This practice avoids unintended modifications to the value, which can lead to unpredictable behavior or hard-to-track bugs. + +- **Lowercase for Package-Private Usage:** If a global variable or constant is intended for use only within its own package, it should start with a lowercase letter. This clearly signals its limited scope of visibility, adhering to Go's access control mechanism based on naming conventions. + +**Guideline:** + +- For global constants that need to be accessed across packages, declare them with an uppercase initial letter. This makes them exported, adhering to Go's visibility rules. +- For constants used within the same package, start their names with a lowercase letter to limit their scope to the package. + +**Example:** + +```go +package config + +// MaxConnections - the maximum number of allowed connections. Visible across packages. +const MaxConnections int = 100 + +// minIdleTime - the minimum idle time before a connection is considered stale. Only visible within the config package. +const minIdleTime int = 30 +``` + +In this example, `MaxConnections` is a global constant meant to be accessed across packages, hence it starts with an uppercase letter. On the other hand, `minIdleTime` is intended for use only within the `config` package, so it starts with a lowercase letter. + +Following these guidelines ensures that your Go code is more readable, maintainable, and consistent with Go's design philosophy and access control mechanisms. + ### 2.8 Error naming - The Error type should be written in the form of FooError. @@ -473,6 +555,190 @@ type ExitError struct { var ErrFormat = errors. New("unknown format") ``` +For non-standard Err naming, CICD will report an error + + +### 2.9 Handling Errors Properly + +In Go, proper error handling is crucial for creating reliable and maintainable applications. It's important to ensure that errors are not ignored or discarded, as this can lead to unpredictable behavior and difficult-to-debug issues. Here are the guidelines and examples regarding the proper handling of errors. + +#### Guideline: Do Not Discard Errors + +- **Mandatory Error Propagation:** When calling a function that returns an error, the calling function must handle or propagate the error, instead of ignoring it. This approach ensures that errors are not silently ignored, allowing higher-level logic to make informed decisions about error handling. + +#### Incorrect Example: Discarding an Error + +```go +package main + +import ( + "io/ioutil" + "log" +) + +func ReadFileContent(filename string) string { + content, _ := ioutil.ReadFile(filename) // Incorrect: Error is ignored + return string(content) +} + +func main() { + content := ReadFileContent("example.txt") + log.Println(content) +} +``` + +In this incorrect example, the error returned by `ioutil.ReadFile` is ignored. This can lead to situations where the program continues execution even if the file doesn't exist or cannot be accessed, potentially causing more cryptic errors downstream. + +#### Correct Example: Propagating an Error + +```go +package main + +import ( + "io/ioutil" + "log" +) + +// ReadFileContent attempts to read and return the content of the specified file. +// It returns an error if reading fails. +func ReadFileContent(filename string) (string, error) { + content, err := ioutil.ReadFile(filename) + if err != nil { + // Correct: Propagate the error + return "", err + } + return string(content), nil +} + +func main() { + content, err := ReadFileContent("example.txt") + if err != nil { + log.Fatalf("Failed to read file: %v", err) + } + log.Println(content) +} +``` + +In the correct example, the error returned by `ioutil.ReadFile` is propagated back to the caller. The `main` function then checks the error and terminates the program with an appropriate error message if an error occurred. This approach ensures that errors are handled appropriately, and the program does not proceed with invalid state. + +### Best Practices for Error Handling + +1. **Always check the error returned by a function.** Do not ignore it. +2. **Propagate errors up the call stack unless they can be handled gracefully at the current level.** +3. **Provide context for errors when propagating them, making it easier to trace the source of the error.** This can be achieved using `fmt.Errorf` with the `%w` verb or dedicated wrapping functions provided by some error handling packages. +4. **Log the error at the point where it is handled or makes the program to terminate, to provide insight into the failure.** + +By following these guidelines, you ensure that your Go applications handle errors in a consistent and effective manner, improving their reliability and maintainability. + + +### 2.10 Using Context with IO or Inter-Process Communication (IPC) + +In Go, `context.Context` is a powerful construct for managing deadlines, cancellation signals, and other request-scoped values across API boundaries and between processes. It is particularly important in I/O operations or inter-process communication (IPC), where operations might need to be cancelled or timed out. + +#### Guideline: Use Context for IO and IPC + +- **Mandatory Use of Context:** When performing I/O operations or inter-process communication, it's crucial to use `context.Context` to manage the lifecycle of these operations. This includes setting deadlines, handling cancellation signals, and passing request-scoped values. + +#### Incorrect Example: Ignoring Context in an HTTP Call + +```go +package main + +import ( + "io/ioutil" + "net/http" + "log" +) + +// FetchData makes an HTTP GET request to the specified URL and returns the response body. +// This function does not use context, making it impossible to cancel the request or set a deadline. +func FetchData(url string) (string, error) { + resp, err := http.Get(url) // Incorrect: Ignoring context + if err != nil { + return "", err + } + defer resp.Body.Close() + + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return "", err + } + + return string(body), nil +} + +func main() { + data, err := FetchData("http://example.com") + if err != nil { + log.Fatalf("Failed to fetch data: %v", err) + } + log.Println(data) +} +``` + +In this incorrect example, the `FetchData` function makes an HTTP GET request without using a `context`. This approach does not allow the request to be cancelled or a timeout to be set, potentially leading to resources being wasted if the server takes too long to respond or if the operation needs to be aborted for any reason. + +#### Correct Example: Using Context in an HTTP Call + +```go +package main + +import ( + "context" + "io/ioutil" + "net/http" + "log" + "time" +) + +// FetchDataWithContext makes an HTTP GET request to the specified URL using the provided context. +// This allows the request to be cancelled or timed out according to the context's deadline. +func FetchDataWithContext(ctx context.Context, url string) (string, error) { + req, err := http.NewRequestWithContext(ctx, "GET", url, nil) + if err != nil { + return "", err + } + + resp, err := http.DefaultClient.Do(req) + if err != nil { + return "", err + } + defer resp.Body.Close() + + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return "", err + } + + return string(body), nil +} + +func main() { + // Create a context with a 5-second timeout + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + + data, err := FetchDataWithContext(ctx, "http://example.com") + if err != nil { + log.Fatalf("Failed to fetch data: %v", err) + } + log.Println(data) +} +``` + +In the correct example, `FetchDataWithContext` uses a context to make the HTTP GET request. This allows the operation to be cancelled or subjected to a timeout, as dictated by the context passed to it. The `context.WithTimeout` function is used in `main` to create a context that cancels the request if it takes longer than 5 seconds, demonstrating a practical use of context to manage operation lifecycle. + +### Best Practices for Using Context + +1. **Pass context as the first parameter of a function**, following the convention `func(ctx context.Context, ...)`. +2. **Never ignore the context** provided to you in functions that support it. Always use it in your I/O or IPC operations. +3. **Avoid storing context in a struct**. Contexts are meant to be passed around within the call stack, not stored. +4. **Use context's cancellation and deadline features** to control the lifecycle of blocking operations, especially in network I/O and IPC scenarios. +5. **Propagate context down the call stack** to any function that supports it, ensuring that your application can respond to cancellation signals and deadlines effectively. + +By adhering to these guidelines and examples, you can ensure that your Go applications handle I/O and IPC operations more reliably and efficiently, with proper support for cancellation, timeouts, and request-scoped values. + + ## 3. Comment specification - Each exportable name must have a comment, which briefly introduces the exported variables, functions, structures, interfaces, etc. diff --git a/docs/contrib/logging.md b/docs/contrib/logging.md index fd9e883efc..e4774929c4 100644 --- a/docs/contrib/logging.md +++ b/docs/contrib/logging.md @@ -1,20 +1,386 @@ -## Log Standards - -### Log Standards - -- The unified log package `github.com/openimsdk/open-im-server/internal/pkg/log` should be used for all logging; -- Use structured logging formats: `log.Infow`, `log.Warnw`, `log.Errorw`, etc. For example: `log.Infow("Update post function called")`; -- All logs should start with an uppercase letter and should not end with a `.`. For example: `log.Infow("Update post function called")`; -- Use past tense. For example, use `Could not delete B` instead of `Cannot delete B`; -- Adhere to log level standards: - - Debug level logs use `log.Debugw`; - - Info level logs use `log.Infow`; - - Warning level logs use `log.Warnw`; - - Error level logs use `log.Errorw`; - - Panic level logs use `log.Panicw`; - - Fatal level logs use `log.Fatalw`. -- Log settings: - - Development and test environments: The log level is set to `debug`, the log format can be set to `console` / `json` as needed, and caller is enabled; - - Production environment: The log level is set to `info`, the log format is set to `json`, and caller is enabled. (**Note**: In the early stages of going online, to facilitate troubleshooting, the log level can be set to `debug`) -- When logging, avoid outputting sensitive information, such as passwords, keys, etc. -- If you are calling a logging function in a function/method with a `context.Context` parameter, it is recommended to use `log.L(ctx).Infow()` for logging. \ No newline at end of file +# OpenIM Logging and Error Handling Documentation + +## Script Logging Documentation Link + +If you wish to view the script's logging documentation, you can click on this link: [Logging Documentation](https://github.com/OpenIMSDK/Open-IM-Server/blob/main/docs/contrib/bash-log.md). + +Below is the documentation for logging and error handling in the OpenIM Go project. + +To create a standard set of documentation that is quick to read and easy to understand, we will highlight key information about the `Logger` interface and the `CodeError` interface. This includes the purpose of each interface, key methods, and their use cases. This will help developers quickly grasp how to effectively use logging and error handling within the project. + +## Logging (`Logger` Interface) + +### Purpose +The `Logger` interface aims to provide the OpenIM project with a unified and flexible logging mechanism, supporting structured logging formats for efficient log management and analysis. + +### Key Methods + +- **Debug, Info, Warn, Error** + Log messages of different levels to suit various logging needs and scenarios. These methods accept a context (`context.Context`), a message (`string`), and key-value pairs (`...interface{}`), allowing the log to carry rich context information. + +- **WithValues** + Append key-value pair information to log messages, returning a new `Logger` instance. This helps in adding consistent context information. + +- **WithName** + Set the name of the logger, which helps in identifying the source of the logs. + +- **WithCallDepth** + Adjust the call stack depth to accurately identify the source of the log message. + +### Use Cases + +- Developers should choose the appropriate logging level (such as `Debug`, `Info`, `Warn`, `Error`) based on the importance of the information when logging. +- Use `WithValues` and `WithName` to add richer context information to logs, facilitating subsequent tracking and analysis. + +## Error Handling (`CodeError` Interface) + +### Purpose +The `CodeError` interface is designed to provide a unified mechanism for error handling and wrapping, making error information more detailed and manageable. + +### Key Methods + +- **Code** + Return the error code to distinguish between different types of errors. + +- **Msg** + Return the error message description to display to the user. + +- **Detail** + Return detailed information about the error for further debugging by developers. + +- **WithDetail** + Add detailed information to the error, returning a new `CodeError` instance. + +- **Is** + Determine whether the current error matches a specified error, supporting a flexible error comparison mechanism. + +- **Wrap** + Wrap another error with additional message description, facilitating the tracing of the error's cause. + +### Use Cases + +- When defining errors with specific codes and messages, use error types that implement the `CodeError` interface. +- Use `WithDetail` to add additional context information to errors for more accurate problem localization. +- Use the `Is` method to judge the type of error for conditional branching. +- Use the `Wrap` method to wrap underlying errors while adding more contextual descriptions. + +## Logging Standards and Code Examples + +In the OpenIM project, we use the unified logging package `github.com/OpenIMSDK/tools/log` for logging to achieve efficient log management and analysis. This logging package supports structured logging formats, making it easier for developers to handle log information. + +### Logger Interface and Implementation + +The logger interface is defined as follows: + +```go +type Logger interface { + Debug(ctx context.Context, msg string, keysAndValues ...interface{}) + Info(ctx context.Context, msg string, keysAndValues ...interface{}) + Warn(ctx context.Context, msg string, err error, keysAndValues ...interface{}) + Error(ctx context.Context, msg string, err error, keysAndValues ...interface{}) + WithValues(keysAndValues ...interface{}) Logger + WithName(name string) Logger + WithCallDepth(depth int) Logger +} +``` + +Example code: Using the `Logger` interface to log at the info level. + +```go +func main() { + logger := log.NewLogger().WithName("MyService") + ctx := context.Background() + logger.Info(ctx, "Service started", "port", "8080") +} +``` + +## Error Handling and Code Examples + +We use the `github.com/OpenIMSDK/tools/errs` package for unified error handling and wrapping. + +### CodeError Interface and Implementation + +The error interface is defined as follows: + +```go +type CodeError interface { + Code() int + Msg() string + Detail() string + WithDetail(detail string) CodeError + Is(err error, loose ...bool) bool + Wrap(msg ...string) error + error +} +``` + +Example code: Creating and using the `CodeError` interface to handle errors. + +```go +package main + +import ( + "fmt" + "github.com/OpenIMSDK/tools/errs" +) + +func main() { + err := errs.New(404, "Resource not found") + err = err.WithDetail(" + +More details") + if e, ok := err.(errs.CodeError); ok { + fmt.Println(e.Code(), e.Msg(), e.Detail()) + } +} +``` + +### Detailed Logging Standards and Code Examples + +1. **Print key information at startup** + It is crucial to print entry parameters and key process information at program startup. This helps understand the startup state and configuration of the program. + + **Code Example**: + ```go + package main + + import ( + "fmt" + "os" + ) + + func main() { + fmt.Println("Program startup, version: 1.0.0") + fmt.Printf("Connecting to database: %s\n", os.Getenv("DATABASE_URL")) + } + ``` + +2. **Use `tools/log` and `fmt` for logging** + Logging should be done using a specialized logging library for unified management and formatted log output. + + **Code Example**: Logging an info level message with `tools/log`. + ```go + package main + + import ( + "context" + "github.com/OpenIMSDK/tools/log" + ) + + func main() { + ctx := context.Background() + log.Info(ctx, "Application started successfully") + } + ``` + +3. **Use standard error output for startup failures or critical information** + Critical error messages or program startup failures should be indicated to the user through standard error output. + + **Code Example**: + ```go + package main + + import ( + "fmt" + "os" + ) + + func checkEnvironment() bool { + return os.Getenv("REQUIRED_ENV") != "" + } + + func main() { + if !checkEnvironment() { + fmt.Fprintln(os.Stderr, "Missing required environment variable") + os.Exit(1) + } + } + ``` + + We encapsulate it into separate tools, which can output error information through the `tools/log` package. + + ```go + package main + + import ( + util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" + ) + + func main() { + if err := apiCmd.Execute(); err != nil { + util.ExitWithError(err) + } + } + ``` + +4. **Use `tools/log` package for runtime logging** + This ensures consistency and control over logging. + + **Code Example**: Same as the above example using `tools/log`. When `tools/log` is not initialized, consider using `fmt` for standard output. + +5. **Error logs should be printed by the top-level caller** + This is to avoid duplicate logging of errors, typically errors are caught and logged at the application's outermost level. + + **Code Example**: + ```go + package main + + import ( + "github.com/OpenIMSDK/tools/log" + "context" + ) + + func doSomething() error { + // An error occurs here + return errs.Wrap(errors.New("An error occurred")) + } + + func controller() error { + err := doSomething() + if err != nil { + return err + } + return nil + } + + func main() { + err := controller() + if err != nil { + log.Error(context.Background(), "Operation failed", err) + } + } + ``` + +6. **Handling logs for API RPC calls and non-RPC applications** + + For API RPC calls using gRPC, logs at the information level are printed by middleware on the gRPC server side, reducing the need to manually log in each RPC method. For non-RPC applications, it's recommended to manually log key execution paths to track the application's execution flow. + + **gRPC Server-Side Logging Middleware:** + + In gRPC, `UnaryInterceptor` and `StreamInterceptor` can intercept Unary and Stream type RPC calls, respectively. Here's an example of how to implement a simple Unary RPC logging middleware: + + ```go + package main + + import ( + "context" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + "log" + "time" + ) + + // unaryServerInterceptor returns a new unary server interceptor that logs each request. + func unaryServerInterceptor() grpc.UnaryServerInterceptor { + return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) { + // Record the start time of the request + start := time.Now() + // Call the actual RPC method + resp, err = handler(ctx, req) + // After the request ends, log the duration and other information + log.Printf("Request method: %s, duration: %s, error status: %v", info.FullMethod, time.Since(start), status.Code(err)) + return resp, err + } + } + + func main() { + // Create a gRPC server and add the middleware + s := grpc.NewServer + +(grpc.UnaryInterceptor(unaryServerInterceptor())) + // Register your service + + // Start the gRPC server + log.Println("Starting gRPC server...") + // ... + } + ``` + + **Logging for Non-RPC Applications:** + + For non-RPC applications, the key is to log at appropriate places in the code to maintain an execution trace. Here's a simple example showing how to log when handling a task: + + ```go + package main + + import ( + "log" + ) + + func processTask(taskID string) { + // Log the start of task processing + log.Printf("Starting task processing: %s", taskID) + // Suppose this is where the task is processed + + // Log after the task is completed + log.Printf("Task processing completed: %s", taskID) + } + + func main() { + // Example task ID + taskID := "task123" + processTask(taskID) + } + ``` + + In both scenarios, appropriate logging can help developers and operators monitor the health of the system, trace the source of issues, and quickly locate and resolve problems. For gRPC logging, using middleware can effectively centralize log management and control. For non-RPC applications, ensuring logs are placed at critical execution points can help understand the program's operational flow and state changes. + +### When to Wrap Errors? + +1. **Wrap errors generated within the function** + When an error occurs within a function, use `errs.Wrap` to add context information to the original error. + + **Code Example**: + ```go + func doSomething() error { + // Suppose an error occurs here + err, _ := someFunc() + if err != nil { + return errs.Wrap(err, "doSomething failed") + } + } + ``` + +2. **Wrap errors from system calls or other packages** + When calling external libraries or system functions that return errors, also add context information to wrap the error. + + **Code Example**: + ```go + func readConfig(file string) error { + _, err := os.ReadFile(file) + if err != nil { + return errs.Wrap(err, "Failed to read config file") + } + return nil + } + ``` + +3. **No need to re-wrap errors for internal module calls** + + If an error has been appropriately wrapped with sufficient context information in an internal module call, there's no need to wrap it again. + + **Code Example**: + ```go + func doSomething() error { + err := doAnotherThing() + if err != nil { + return err + } + return nil + } + ``` + +4. **Ensure comprehensive wrapping of errors with detailed messages** + When wrapping errors, ensure to provide ample context information to make the error more understandable and easier to debug. + + **Code Example**: + ```go + func connectDatabase() error { + err := db.Connect(config.DatabaseURL) + if err != nil { + return errs.Wrap(err, fmt.Sprintf("Failed to connect to database, URL: %s", config.DatabaseURL)) + } + return nil + } + ``` \ No newline at end of file diff --git a/scripts/cherry-pick.sh b/scripts/cherry-pick.sh index f8d7912f81..ff303269d8 100755 --- a/scripts/cherry-pick.sh +++ b/scripts/cherry-pick.sh @@ -21,10 +21,6 @@ # checks them out to a branch named: # automated-cherry-pick-of--- - - - - OPENIM_ROOT=$(dirname "${BASH_SOURCE[0]}")/.. source "${OPENIM_ROOT}/scripts/lib/init.sh" From 8501c66d14b6774157886ae5b6538139ca5e7f94 Mon Sep 17 00:00:00 2001 From: Brabem <69128477+luhaoling@users.noreply.github.com> Date: Wed, 13 Mar 2024 10:13:15 +0800 Subject: [PATCH 111/188] fix: fix the protocol version (#2074) --- go.mod | 2 +- go.sum | 4 ++-- internal/api/route.go | 1 - internal/rpc/group/group.go | 13 +++---------- internal/rpc/msg/sync_msg.go | 4 ++-- internal/rpc/third/log.go | 7 +++++++ pkg/common/db/mgo/group.go | 4 +++- pkg/common/db/unrelation/msg.go | 4 ++-- scripts/install/test.sh | 2 +- 9 files changed, 21 insertions(+), 20 deletions(-) diff --git a/go.mod b/go.mod index 10f08fa533..da28155712 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.19 require ( firebase.google.com/go v3.13.0+incompatible - github.com/OpenIMSDK/protocol v0.0.55 + github.com/OpenIMSDK/protocol v0.0.56 github.com/OpenIMSDK/tools v0.0.37 github.com/bwmarrin/snowflake v0.3.0 // indirect github.com/dtm-labs/rockscache v0.1.1 diff --git a/go.sum b/go.sum index 230c142c6c..c3803ef581 100644 --- a/go.sum +++ b/go.sum @@ -18,8 +18,8 @@ firebase.google.com/go v3.13.0+incompatible/go.mod h1:xlah6XbEyW6tbfSklcfe5FHJIw github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/IBM/sarama v1.42.2 h1:VoY4hVIZ+WQJ8G9KNY/SQlWguBQXQ9uvFPOnrcu8hEw= github.com/IBM/sarama v1.42.2/go.mod h1:FLPGUGwYqEs62hq2bVG6Io2+5n+pS6s/WOXVKWSLFtE= -github.com/OpenIMSDK/protocol v0.0.55 h1:eBjg8DyuhxGmuCUjpoZjg6MJJJXU/xJ3xJwFhrn34yA= -github.com/OpenIMSDK/protocol v0.0.55/go.mod h1:F25dFrwrIx3lkNoiuf6FkCfxuwf8L4Z8UIsdTHP/r0Y= +github.com/OpenIMSDK/protocol v0.0.56 h1:mbVFyDBachEsmJLfYW5AU1z2KL8AUEpoHG8RPCIxjgg= +github.com/OpenIMSDK/protocol v0.0.56/go.mod h1:F25dFrwrIx3lkNoiuf6FkCfxuwf8L4Z8UIsdTHP/r0Y= github.com/OpenIMSDK/tools v0.0.37 h1:qvDqmA4RbEJtPjZouWCkVuf/pjm6Y8nUrG5iH2gcnOg= github.com/OpenIMSDK/tools v0.0.37/go.mod h1:wBfR5CYmEyvxl03QJbTkhz1CluK6J4/lX0lviu8JAjE= github.com/QcloudApi/qcloud_sign_golang v0.0.0-20141224014652-e4130a326409/go.mod h1:1pk82RBxDY/JZnPQrtqHlUFfCctgdorsd9M06fMynOM= diff --git a/internal/api/route.go b/internal/api/route.go index 92fa83fb0e..ca0b6829ef 100644 --- a/internal/api/route.go +++ b/internal/api/route.go @@ -50,7 +50,6 @@ import ( ) func Start(config *config.GlobalConfig, port int, proPort int) error { - log.ZDebug(context.Background(), "configAPI1111111111111111111", config, "port", port, "javafdasfs") if port == 0 || proPort == 0 { err := "port or proPort is empty:" + strconv.Itoa(port) + "," + strconv.Itoa(proPort) return errs.Wrap(fmt.Errorf(err)) diff --git a/internal/rpc/group/group.go b/internal/rpc/group/group.go index 4be8fab0cb..d966bfad8e 100644 --- a/internal/rpc/group/group.go +++ b/internal/rpc/group/group.go @@ -1068,6 +1068,7 @@ func (s *groupServer) GetGroups(ctx context.Context, req *pbgroup.GetGroupsReq) group []*relationtb.GroupModel err error ) + if req.GroupID != "" { group, err = s.db.FindGroup(ctx, []string{req.GroupID}) resp.Total = uint32(len(group)) @@ -1080,15 +1081,7 @@ func (s *groupServer) GetGroups(ctx context.Context, req *pbgroup.GetGroupsReq) return nil, err } - var groups []*relationtb.GroupModel - for _, v := range group { - if v.Status == constant.GroupStatusDismissed { - resp.Total-- - continue - } - groups = append(groups, v) - } - groupIDs := utils.Slice(groups, func(e *relationtb.GroupModel) string { + groupIDs := utils.Slice(group, func(e *relationtb.GroupModel) string { return e.GroupID }) ownerMembers, err := s.db.FindGroupsOwner(ctx, groupIDs) @@ -1102,7 +1095,7 @@ func (s *groupServer) GetGroups(ctx context.Context, req *pbgroup.GetGroupsReq) if err != nil { return nil, err } - resp.Groups = utils.Slice(groups, func(group *relationtb.GroupModel) *pbgroup.CMSGroup { + resp.Groups = utils.Slice(group, func(group *relationtb.GroupModel) *pbgroup.CMSGroup { var ( userID string username string diff --git a/internal/rpc/msg/sync_msg.go b/internal/rpc/msg/sync_msg.go index 6fa4a0c9d1..379302e983 100644 --- a/internal/rpc/msg/sync_msg.go +++ b/internal/rpc/msg/sync_msg.go @@ -131,7 +131,7 @@ func (m *msgServer) SearchMessage(ctx context.Context, req *msg.SearchMessageReq sendIDs = append(sendIDs, chatLog.SendID) } switch chatLog.SessionType { - case constant.SingleChatType: + case constant.SingleChatType, constant.NotificationChatType: recvIDs = append(recvIDs, chatLog.RecvID) case constant.GroupChatType, constant.SuperGroupChatType: groupIDs = append(groupIDs, chatLog.GroupID) @@ -173,7 +173,7 @@ func (m *msgServer) SearchMessage(ctx context.Context, req *msg.SearchMessageReq pbchatLog.SenderNickname = sendMap[chatLog.SendID] } switch chatLog.SessionType { - case constant.SingleChatType: + case constant.SingleChatType, constant.NotificationChatType: pbchatLog.RecvNickname = recvMap[chatLog.RecvID] case constant.GroupChatType, constant.SuperGroupChatType: diff --git a/internal/rpc/third/log.go b/internal/rpc/third/log.go index b425dd819e..97428254c7 100644 --- a/internal/rpc/third/log.go +++ b/internal/rpc/third/log.go @@ -133,6 +133,13 @@ func (t *thirdServer) SearchLogs(ctx context.Context, req *third.SearchLogsReq) if req.StartTime > req.EndTime { return nil, errs.ErrArgs.Wrap("startTime>endTime") } + if req.StartTime == 0 && req.EndTime == 0 { + t := time.Date(2019, time.January, 1, 0, 0, 0, 0, time.UTC) + timestampMills := t.UnixNano() / int64(time.Millisecond) + req.StartTime = timestampMills + req.EndTime = time.Now().UnixNano() / int64(time.Millisecond) + } + total, logs, err := t.thirdDatabase.SearchLogs(ctx, req.Keyword, time.UnixMilli(req.StartTime), time.UnixMilli(req.EndTime), req.Pagination) if err != nil { return nil, err diff --git a/pkg/common/db/mgo/group.go b/pkg/common/db/mgo/group.go index 1bef90ebeb..a3d777f59c 100644 --- a/pkg/common/db/mgo/group.go +++ b/pkg/common/db/mgo/group.go @@ -16,6 +16,7 @@ package mgo import ( "context" + "github.com/OpenIMSDK/protocol/constant" "time" "github.com/OpenIMSDK/tools/errs" @@ -69,7 +70,8 @@ func (g *GroupMgo) Take(ctx context.Context, groupID string) (group *relation.Gr } func (g *GroupMgo) Search(ctx context.Context, keyword string, pagination pagination.Pagination) (total int64, groups []*relation.GroupModel, err error) { - return mgoutil.FindPage[*relation.GroupModel](ctx, g.coll, bson.M{"group_name": bson.M{"$regex": keyword}}, pagination) + return mgoutil.FindPage[*relation.GroupModel](ctx, g.coll, bson.M{"group_name": bson.M{"$regex": keyword}, + "status": bson.M{"$ne": constant.GroupStatusDismissed}}, pagination) } func (g *GroupMgo) CountTotal(ctx context.Context, before *time.Time) (count int64, err error) { diff --git a/pkg/common/db/unrelation/msg.go b/pkg/common/db/unrelation/msg.go index 4deca56f80..a129f3e996 100644 --- a/pkg/common/db/unrelation/msg.go +++ b/pkg/common/db/unrelation/msg.go @@ -1063,8 +1063,8 @@ func (m *MsgMongoDriver) searchMessage(ctx context.Context, req *msg.SearchMessa // Changed to keyed fields for bson.M to avoid govet errors condition = append(condition, bson.M{"$eq": bson.A{bson.M{"$dateToString": bson.M{"format": "%Y-%m-%d", "date": bson.M{"$toDate": "$$item.msg.send_time"}}}, req.SendTime}}) } - if req.MsgType != 0 { - condition = append(condition, bson.M{"$eq": bson.A{"$$item.msg.content_type", req.MsgType}}) + if req.ContentType != 0 { + condition = append(condition, bson.M{"$eq": bson.A{"$$item.msg.content_type", req.ContentType}}) } if req.SessionType != 0 { condition = append(condition, bson.M{"$eq": bson.A{"$$item.msg.session_type", req.SessionType}}) diff --git a/scripts/install/test.sh b/scripts/install/test.sh index 4ea3f16caf..3263075703 100755 --- a/scripts/install/test.sh +++ b/scripts/install/test.sh @@ -1272,7 +1272,7 @@ openim::test::search_msg() { { "sendID": "${sendID}", "recvID": "${recvID}", - "msgType": ${msgType}, + "contentType": ${msgType}, "sendTime": "${sendTime}", "sessionType": ${sessionType}, "pagination": { From e86d1cd7427c36407e21bced1ad562c637c82a07 Mon Sep 17 00:00:00 2001 From: OpenIM-Gordon <46924906+FGadvancer@users.noreply.github.com> Date: Wed, 13 Mar 2024 13:42:00 +0800 Subject: [PATCH 112/188] optimization: message remove options. (#2082) * fix: remove unnecessary error handling to avoid sending failed notifications. * fix: remove unnecessary error handling to avoid sending nil resp. * optimization: message remove options. --- internal/rpc/msg/verify.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/internal/rpc/msg/verify.go b/internal/rpc/msg/verify.go index bdaa7fd87f..5bfd7013ea 100644 --- a/internal/rpc/msg/verify.go +++ b/internal/rpc/msg/verify.go @@ -158,9 +158,6 @@ func (m *msgServer) encapsulateMsgData(msg *sdkws.MsgData) { case constant.Custom: fallthrough case constant.Quote: - utils.SetSwitchFromOptions(msg.Options, constant.IsConversationUpdate, true) - utils.SetSwitchFromOptions(msg.Options, constant.IsUnreadCount, true) - utils.SetSwitchFromOptions(msg.Options, constant.IsSenderSync, true) case constant.Revoke: utils.SetSwitchFromOptions(msg.Options, constant.IsUnreadCount, false) utils.SetSwitchFromOptions(msg.Options, constant.IsOfflinePush, false) From 2d2fa99d2ce310818480932db37d03737ab1ec6e Mon Sep 17 00:00:00 2001 From: OpenIM Bot <124379614+kubbot@users.noreply.github.com> Date: Thu, 14 Mar 2024 10:17:22 +0800 Subject: [PATCH 113/188] cicd: bump League Patch (#2105) --- pkg/common/db/mgo/group.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/common/db/mgo/group.go b/pkg/common/db/mgo/group.go index a3d777f59c..07c5394e26 100644 --- a/pkg/common/db/mgo/group.go +++ b/pkg/common/db/mgo/group.go @@ -16,9 +16,9 @@ package mgo import ( "context" - "github.com/OpenIMSDK/protocol/constant" "time" + "github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/mgoutil" "github.com/OpenIMSDK/tools/pagination" From e795dce6966871f46ac0915d347933eca9d2e698 Mon Sep 17 00:00:00 2001 From: Xinwei Xiong <3293172751NSS@gmail.com> Date: Mon, 18 Mar 2024 10:17:21 +0800 Subject: [PATCH 114/188] cicd: update e2e-test fix e2e and api test ci (#2101) --- .github/workflows/e2e-test.yml | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/.github/workflows/e2e-test.yml b/.github/workflows/e2e-test.yml index b5f901d250..f98221e41b 100644 --- a/.github/workflows/e2e-test.yml +++ b/.github/workflows/e2e-test.yml @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -name: OpenIM Linux System E2E Test +name: OpenIM E2E And API Test on: workflow_dispatch: @@ -82,7 +82,7 @@ jobs: sudo make tidy sudo make tools.verify.go-gitlint - - name: Build, Start + - name: Build, Start(make build && make start) run: | sudo ./scripts/install/install.sh -i @@ -90,9 +90,8 @@ jobs: run: | sudo ./scripts/install/install.sh -s - - name: Exec OpenIM API test + - name: Exec OpenIM API test (make test-api) run: | - sudo make test-api mkdir -p ./tmp touch ./tmp/test.md echo "# OpenIM Test" >> ./tmp/test.md @@ -103,9 +102,10 @@ jobs: echo "" >> ./tmp/test.md echo "
" >> ./tmp/test.md - - name: Exec OpenIM E2E Test + sudo make test-api + + - name: Exec OpenIM E2E Test (make test-e2e) run: | - sudo make test-e2e echo "" >> ./tmp/test.md echo "## OpenIM E2E Test" >> ./tmp/test.md echo "
Command Output for OpenIM E2E Test" >> ./tmp/test.md @@ -114,6 +114,8 @@ jobs: echo "" >> ./tmp/test.md echo "
" >> ./tmp/test.md + sudo make test-e2e + - name: Comment PR with file uses: thollander/actions-comment-pull-request@v2 with: @@ -143,4 +145,4 @@ jobs: PUBLISH_BRANCH: gh-pages env: GITHUB_TOKEN: ${{ secrets.BOT_GITHUB_TOKEN }} - continue-on-error: true \ No newline at end of file + continue-on-error: true From 1c2eafce2567a242f6d34cfb7b1f155d54db5a54 Mon Sep 17 00:00:00 2001 From: Xinwei Xiong <3293172751NSS@gmail.com> Date: Mon, 18 Mar 2024 10:33:29 +0800 Subject: [PATCH 115/188] add github actions is create code-language-detector.yml (#2113) * feat: remove tools/codescan catalog * feat: add code language detector github actions --- .github/code-language-detector.yml | 7 ++ .github/workflows/code-language-detector.yml | 13 +++ go.work | 1 - scripts/verify-annotation-language.sh | 46 -------- tools/codescan/checker/checker.go | 104 ------------------- tools/codescan/codescan.go | 34 ------ tools/codescan/config.yaml | 21 ---- tools/codescan/config/config.go | 49 --------- tools/codescan/go.mod | 3 - 9 files changed, 20 insertions(+), 258 deletions(-) create mode 100644 .github/code-language-detector.yml create mode 100644 .github/workflows/code-language-detector.yml delete mode 100755 scripts/verify-annotation-language.sh delete mode 100644 tools/codescan/checker/checker.go delete mode 100644 tools/codescan/codescan.go delete mode 100644 tools/codescan/config.yaml delete mode 100644 tools/codescan/config/config.go delete mode 100644 tools/codescan/go.mod diff --git a/.github/code-language-detector.yml b/.github/code-language-detector.yml new file mode 100644 index 0000000000..9a81236b8a --- /dev/null +++ b/.github/code-language-detector.yml @@ -0,0 +1,7 @@ +directory: ./ +file_types: + - .go + - .yaml + - .yml +languages: + - Chinese \ No newline at end of file diff --git a/.github/workflows/code-language-detector.yml b/.github/workflows/code-language-detector.yml new file mode 100644 index 0000000000..22307576a4 --- /dev/null +++ b/.github/workflows/code-language-detector.yml @@ -0,0 +1,13 @@ +name: Language Check Workflow Test + +on: [pull_request] + +jobs: + comment-language-detector: + runs-on: ubuntu-latest + steps: + - name: Checkout Repository + uses: actions/checkout@v4 + + - name: Code Language Detector + uses: kubecub/comment-lang-detector@v1.0.0 \ No newline at end of file diff --git a/go.work b/go.work index 8dc91a6319..56eb874d4a 100644 --- a/go.work +++ b/go.work @@ -3,7 +3,6 @@ go 1.19 use ( . ./test/typecheck - ./tools/codescan ./tools/changelog ./tools/component ./tools/formitychecker diff --git a/scripts/verify-annotation-language.sh b/scripts/verify-annotation-language.sh deleted file mode 100755 index 6b863776c9..0000000000 --- a/scripts/verify-annotation-language.sh +++ /dev/null @@ -1,46 +0,0 @@ -#!/usr/bin/env bash -# 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. - - -# This script verifies whether codes follow golang convention. -# Usage: `scripts/verify-pkg-names.sh`. - -set -o errexit - -OPENIM_ROOT=$(dirname "${BASH_SOURCE[0]}")/.. -source "${OPENIM_ROOT}/scripts/lib/init.sh" - -openim::golang::verify_go_version - -openim::golang::verify_go_version - -OPENIM_OUTPUT_HOSTBIN_TOOLS="${OPENIM_ROOT}/_output/bin/tools/linux/amd64" -CODESCAN_BINARY="${OPENIM_OUTPUT_HOSTBIN_TOOLS}/codescan" - -if [[ ! -f "${CODESCAN_BINARY}" ]]; then - echo "codescan binary not found, building..." - pushd "${OPENIM_ROOT}" >/dev/null - make build BINS="codescan" - popd >/dev/null -fi - -if [[ ! -f "${CODESCAN_BINARY}" ]]; then - echo "Failed to build codescan binary." - exit 1 -fi - -CONFIG_PATH="${OPENIM_ROOT}/tools/codescan/config.yaml" - -"${CODESCAN_BINARY}" -config "${CONFIG_PATH}" \ No newline at end of file diff --git a/tools/codescan/checker/checker.go b/tools/codescan/checker/checker.go deleted file mode 100644 index ad724dd5bb..0000000000 --- a/tools/codescan/checker/checker.go +++ /dev/null @@ -1,104 +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 checker - -import ( - "bufio" - "fmt" - "os" - "path/filepath" - "regexp" - "strings" - - "github.com/openimsdk/open-im-server/tools/codescan/config" -) - -type CheckResult struct { - FilePath string - Lines []int -} - -func checkFileForChineseComments(filePath string) ([]CheckResult, error) { - file, err := os.Open(filePath) - if err != nil { - return nil, err - } - defer file.Close() - - var results []CheckResult - scanner := bufio.NewScanner(file) - reg := regexp.MustCompile(`[\p{Han}]+`) - lineNumber := 0 - - var linesWithChinese []int - for scanner.Scan() { - lineNumber++ - if reg.FindString(scanner.Text()) != "" { - linesWithChinese = append(linesWithChinese, lineNumber) - } - } - - if len(linesWithChinese) > 0 { - results = append(results, CheckResult{ - FilePath: filePath, - Lines: linesWithChinese, - }) - } - - if err := scanner.Err(); err != nil { - return nil, err - } - - return results, nil -} - -func WalkDirAndCheckComments(cfg config.Config) error { - var allResults []CheckResult - err := filepath.Walk(cfg.Directory, func(path string, info os.FileInfo, err error) error { - if err != nil { - return err - } - if info.IsDir() { - return nil - } - for _, fileType := range cfg.FileTypes { - if filepath.Ext(path) == fileType { - results, err := checkFileForChineseComments(path) - if err != nil { - return err - } - if len(results) > 0 { - allResults = append(allResults, results...) - } - } - } - return nil - }) - - if err != nil { - return err - } - - if len(allResults) > 0 { - var errMsg strings.Builder - errMsg.WriteString("Files containing Chinese comments:\n") - for _, result := range allResults { - errMsg.WriteString(fmt.Sprintf("%s: Lines %v\n", result.FilePath, result.Lines)) - } - return fmt.Errorf(errMsg.String()) - } - - return nil -} diff --git a/tools/codescan/codescan.go b/tools/codescan/codescan.go deleted file mode 100644 index a83e895fcb..0000000000 --- a/tools/codescan/codescan.go +++ /dev/null @@ -1,34 +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 main - -import ( - "log" - - "github.com/openimsdk/open-im-server/tools/codescan/checker" - "github.com/openimsdk/open-im-server/tools/codescan/config" -) - -func main() { - cfg, err := config.ParseConfig() - if err != nil { - log.Fatalf("Error parsing config: %v", err) - } - - err = checker.WalkDirAndCheckComments(cfg) - if err != nil { - panic(err) - } -} diff --git a/tools/codescan/config.yaml b/tools/codescan/config.yaml deleted file mode 100644 index 32a8c1f54b..0000000000 --- a/tools/codescan/config.yaml +++ /dev/null @@ -1,21 +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. - -directory: ./ -file_types: - - .go - - .yaml - - .yml -languages: - - Chinese \ No newline at end of file diff --git a/tools/codescan/config/config.go b/tools/codescan/config/config.go deleted file mode 100644 index aebf0d4f75..0000000000 --- a/tools/codescan/config/config.go +++ /dev/null @@ -1,49 +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 config - -import ( - "flag" - "log" - "os" - - "gopkg.in/yaml.v2" -) - -type Config struct { - Directory string `yaml:"directory"` - FileTypes []string `yaml:"file_types"` - Languages []string `yaml:"languages"` -} - -func ParseConfig() (Config, error) { - var configPath string - flag.StringVar(&configPath, "config", "./", "Path to config file") - flag.Parse() - - var config Config - if configPath != "" { - configFile, err := os.ReadFile(configPath) - if err != nil { - return Config{}, err - } - if err := yaml.Unmarshal(configFile, &config); err != nil { - return Config{}, err - } - } else { - log.Fatal("Config file must be provided") - } - return config, nil -} diff --git a/tools/codescan/go.mod b/tools/codescan/go.mod deleted file mode 100644 index 2ad1321018..0000000000 --- a/tools/codescan/go.mod +++ /dev/null @@ -1,3 +0,0 @@ -module github.com/openimsdk/open-im-server/tools/codescan - -go 1.19 From b67c6bacd0ea66b5569149660b00715da104e824 Mon Sep 17 00:00:00 2001 From: Xinwei Xiong <3293172751NSS@gmail.com> Date: Mon, 18 Mar 2024 10:34:19 +0800 Subject: [PATCH 116/188] docs: Update openim version management strategy, detailed design (#2076) * Update version.md * Update version.md --- docs/contrib/version.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/contrib/version.md b/docs/contrib/version.md index 574badf598..337aa4f7d1 100644 --- a/docs/contrib/version.md +++ b/docs/contrib/version.md @@ -96,7 +96,6 @@ We reinforce our approach to branch management and versioning with stringent tes This document describes the maximum version skew supported between various openim components. Specific cluster deployment tools may place additional restrictions on version skew. - ### Supported version skew In highly-available (HA) clusters, the newest and oldest `openim-api` instances must be within one minor version. @@ -210,6 +209,7 @@ git merge release-v3.1 # Push the updates to the main branch git push origin main ``` + ## Release Process ``` @@ -232,5 +232,7 @@ For more details on managing Docker image versions, visit [OpenIM Docker Images More on multi-branch version management design and version management design at helm charts: -+ https://github.com/openimsdk/open-im-server/issues/1695 -+ https://github.com/openimsdk/open-im-server/issues/1662 \ No newline at end of file +About Helm's version management strategy for Multiple Apps and multiple Services: + ++ [中文版本管理文档](https://github.com/openimsdk/helm-charts/blob/main/docs/contrib/version-zh.md) ++ [English version management documents](https://github.com/openimsdk/helm-charts/blob/main/docs/contrib/version.md) From 7c25c91e9bc7718e60600342d58247d22e7f7d54 Mon Sep 17 00:00:00 2001 From: Xinwei Xiong <3293172751NSS@gmail.com> Date: Mon, 18 Mar 2024 10:34:48 +0800 Subject: [PATCH 117/188] feat: golang fix apt test design (#2084) * feat: make lint format * feat: make lint format * feat: make lint format * fix: fix make lint * feat: add scripts verify shell check * feat: add scripts verify shell check --- .golangci.yml | 2 +- docker-compose.yml | 17 ---- internal/api/msg.go | 7 +- internal/msggateway/context.go | 3 +- internal/msggateway/user_map.go | 86 +++++++++++-------- .../msgtransfer/online_history_msg_handler.go | 9 +- internal/push/offlinepush/getui/push.go | 3 +- internal/push/push_rpc_server.go | 3 +- internal/push/tools.go | 3 +- internal/rpc/friend/black.go | 7 +- internal/rpc/friend/friend.go | 16 +++- internal/rpc/group/group.go | 1 + pkg/rpcclient/notification/friend.go | 5 +- scripts/install/test.sh | 3 +- 14 files changed, 86 insertions(+), 79 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index 9c79606426..c262cfa2f0 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -745,7 +745,7 @@ linters: - misspell # Spelling mistakes - staticcheck # Static analysis - unused # Checks for unused code - - goimports # Checks if imports are correctly sorted and formatted + # - goimports # Checks if imports are correctly sorted and formatted - godot # Checks for comment punctuation - bodyclose # Ensures HTTP response body is closed - stylecheck # Style checker for Go code diff --git a/docker-compose.yml b/docker-compose.yml index 8538eec832..ef0714329a 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -186,23 +186,6 @@ services: # server: # ipv4_address: ${OPENIM_SERVER_NETWORK_ADDRESS:-172.28.0.8} -### TODO: mysql is required to deploy the openim-chat component - # mysql: - # image: mysql:${MYSQL_IMAGE_VERSION:-5.7} - # platform: linux/amd64 - # ports: - # - "${MYSQL_PORT:-13306}:3306" - # container_name: mysql - # volumes: - # - "${DATA_DIR:-./}/components/mysql/data:/var/lib/mysql" - # - "/etc/localtime:/etc/localtime" - # environment: - # MYSQL_ROOT_PASSWORD: "${MYSQL_PASSWORD:-openIM123}" - # restart: always - # networks: - # server: - # ipv4_address: ${MYSQL_NETWORK_ADDRESS:-172.28.0.15} - # openim-chat: # image: ${IMAGE_REGISTRY:-ghcr.io/openimsdk}/openim-chat:${CHAT_IMAGE_VERSION:-main} # container_name: openim-chat diff --git a/internal/api/msg.go b/internal/api/msg.go index d38c14d4e5..ad5001459e 100644 --- a/internal/api/msg.go +++ b/internal/api/msg.go @@ -215,25 +215,22 @@ func (m *MessageApi) SendMessage(c *gin.Context) { // Set the receiver ID in the message data. sendMsgReq.MsgData.RecvID = req.RecvID - // Declare a variable to store the message sending status. - var status int - // Attempt to send the message using the client. respPb, err := m.Client.SendMsg(c, sendMsgReq) if err != nil { // Set the status to failed and respond with an error if sending fails. - status = constant.MsgSendFailed apiresp.GinError(c, err) return } // Set the status to successful if the message is sent. - status = constant.MsgSendSuccessed + var status int = constant.MsgSendSuccessed // Attempt to update the message sending status in the system. _, err = m.Client.SetSendMsgStatus(c, &msg.SetSendMsgStatusReq{ Status: int32(status), }) + if err != nil { // Log the error if updating the status fails. apiresp.GinError(c, err) diff --git a/internal/msggateway/context.go b/internal/msggateway/context.go index 85fe5c734d..ad679c1a14 100644 --- a/internal/msggateway/context.go +++ b/internal/msggateway/context.go @@ -141,7 +141,6 @@ func (c *UserConnContext) GetBackground() bool { b, err := strconv.ParseBool(c.Req.URL.Query().Get(BackgroundStatus)) if err != nil { return false - } else { - return b } + return b } diff --git a/internal/msggateway/user_map.go b/internal/msggateway/user_map.go index b4cec59fa9..89eb20de6c 100644 --- a/internal/msggateway/user_map.go +++ b/internal/msggateway/user_map.go @@ -19,7 +19,6 @@ import ( "sync" "github.com/OpenIMSDK/tools/log" - "github.com/OpenIMSDK/tools/utils" ) type UserMap struct { @@ -71,48 +70,65 @@ func (u *UserMap) Set(key string, v *Client) { } func (u *UserMap) delete(key string, connRemoteAddr string) (isDeleteUser bool) { + // Attempt to load the clients associated with the key. allClients, existed := u.m.Load(key) - if existed { - oldClients := allClients.([]*Client) - var a []*Client - for _, client := range oldClients { - if client.ctx.GetRemoteAddr() != connRemoteAddr { - a = append(a, client) - } - } - if len(a) == 0 { - u.m.Delete(key) - return true - } else { - u.m.Store(key, a) - return false + if !existed { + // Return false immediately if the key does not exist. + return false + } + + // Convert allClients to a slice of *Client. + oldClients := allClients.([]*Client) + var remainingClients []*Client + for _, client := range oldClients { + // Keep clients that do not match the connRemoteAddr. + if client.ctx.GetRemoteAddr() != connRemoteAddr { + remainingClients = append(remainingClients, client) } } - return existed + + // If no clients remain after filtering, delete the key from the map. + if len(remainingClients) == 0 { + u.m.Delete(key) + return true + } + + // Otherwise, update the key with the remaining clients. + u.m.Store(key, remainingClients) + return false } -func (u *UserMap) deleteClients(key string, clients []*Client) (isDeleteUser bool) { - m := utils.SliceToMapAny(clients, func(c *Client) (string, struct{}) { - return c.ctx.GetRemoteAddr(), struct{}{} - }) +func (u *UserMap) deleteClients(key string, clientsToDelete []*Client) (isDeleteUser bool) { + // Convert the slice of clients to delete into a map for efficient lookup. + deleteMap := make(map[string]struct{}) + for _, client := range clientsToDelete { + deleteMap[client.ctx.GetRemoteAddr()] = struct{}{} + } + + // Load the current clients associated with the key. allClients, existed := u.m.Load(key) - if existed { - oldClients := allClients.([]*Client) - var a []*Client - for _, client := range oldClients { - if _, ok := m[client.ctx.GetRemoteAddr()]; !ok { - a = append(a, client) - } - } - if len(a) == 0 { - u.m.Delete(key) - return true - } else { - u.m.Store(key, a) - return false + if !existed { + // If the key doesn't exist, return false. + return false + } + + // Filter out clients that are in the deleteMap. + oldClients := allClients.([]*Client) + var remainingClients []*Client + for _, client := range oldClients { + if _, shouldBeDeleted := deleteMap[client.ctx.GetRemoteAddr()]; !shouldBeDeleted { + remainingClients = append(remainingClients, client) } } - return existed + + // Update or delete the key based on the remaining clients. + if len(remainingClients) == 0 { + u.m.Delete(key) + return true + } + + u.m.Store(key, remainingClients) + return false } func (u *UserMap) DeleteAll(key string) { diff --git a/internal/msgtransfer/online_history_msg_handler.go b/internal/msgtransfer/online_history_msg_handler.go index b81bd12b8c..50fc933690 100644 --- a/internal/msgtransfer/online_history_msg_handler.go +++ b/internal/msgtransfer/online_history_msg_handler.go @@ -184,12 +184,11 @@ func (och *OnlineHistoryRedisConsumerHandler) getPushStorageMsgList( options2 := msgprocessor.Options(msg.Options) if options2.IsHistory() { return true - } else { - // if !(!options2.IsSenderSync() && conversationID == msg.MsgData.SendID) { - // return false - // } - return false } + // if !(!options2.IsSenderSync() && conversationID == msg.MsgData.SendID) { + // return false + // } + return false } for _, v := range totalMsgs { options := msgprocessor.Options(v.message.Options) diff --git a/internal/push/offlinepush/getui/push.go b/internal/push/offlinepush/getui/push.go index 67f6292db3..1a95727e5c 100644 --- a/internal/push/offlinepush/getui/push.go +++ b/internal/push/offlinepush/getui/push.go @@ -90,9 +90,8 @@ func (g *Client) Push(ctx context.Context, userIDs []string, title, content stri for i, v := range s.GetSplitResult() { go func(index int, userIDs []string) { defer wg.Done() - if err := g.batchPush(ctx, token, userIDs, pushReq); err != nil { + if err = g.batchPush(ctx, token, userIDs, pushReq); err != nil { log.ZError(ctx, "batchPush failed", err, "index", index, "token", token, "req", pushReq) - err = err } }(i, v.Item) } diff --git a/internal/push/push_rpc_server.go b/internal/push/push_rpc_server.go index a8bb189749..b68b06666e 100644 --- a/internal/push/push_rpc_server.go +++ b/internal/push/push_rpc_server.go @@ -90,9 +90,8 @@ func (r *pushServer) PushMsg(ctx context.Context, pbData *pbpush.PushMsgReq) (re if err != nil { if err != errNoOfflinePusher { return nil, err - } else { - log.ZWarn(ctx, "offline push failed", err, "msg", pbData.String()) } + log.ZWarn(ctx, "offline push failed", err, "msg", pbData.String()) } return &pbpush.PushMsgResp{}, nil } diff --git a/internal/push/tools.go b/internal/push/tools.go index 3242767b16..760c8c95bb 100644 --- a/internal/push/tools.go +++ b/internal/push/tools.go @@ -26,7 +26,6 @@ func GetContent(msg *sdkws.MsgData) string { _ = proto.Unmarshal(msg.Content, &tips) content := tips.JsonDetail return content - } else { - return string(msg.Content) } + return string(msg.Content) } diff --git a/internal/rpc/friend/black.go b/internal/rpc/friend/black.go index 64c63eb734..4bb0d9f58f 100644 --- a/internal/rpc/friend/black.go +++ b/internal/rpc/friend/black.go @@ -79,9 +79,14 @@ func (s *friendServer) AddBlack(ctx context.Context, req *pbfriend.AddBlackReq) CreateTime: time.Now(), Ex: req.Ex, } + if err := s.blackDatabase.Create(ctx, []*relation.BlackModel{&black}); err != nil { return nil, err } - s.notificationSender.BlackAddedNotification(ctx, req) + + if err := s.notificationSender.BlackAddedNotification(ctx, req); err != nil { + return nil, err + } + return &pbfriend.AddBlackResp{}, nil } diff --git a/internal/rpc/friend/friend.go b/internal/rpc/friend/friend.go index 6403a4159d..4df4085a9c 100644 --- a/internal/rpc/friend/friend.go +++ b/internal/rpc/friend/friend.go @@ -114,26 +114,36 @@ func (s *friendServer) ApplyToAddFriend(ctx context.Context, req *pbfriend.Apply if err := authverify.CheckAccessV3(ctx, req.FromUserID, s.config); err != nil { return nil, err } + if req.ToUserID == req.FromUserID { return nil, errs.ErrCanNotAddYourself.Wrap("req.ToUserID", req.ToUserID) } + if err = CallbackBeforeAddFriend(ctx, s.config, req); err != nil && err != errs.ErrCallbackContinue { return nil, err } + if _, err := s.userRpcClient.GetUsersInfoMap(ctx, []string{req.ToUserID, req.FromUserID}); err != nil { return nil, err } + in1, in2, err := s.friendDatabase.CheckIn(ctx, req.FromUserID, req.ToUserID) if err != nil { return nil, err } + if in1 && in2 { return nil, errs.ErrRelationshipAlready.Wrap() } + if err = s.friendDatabase.AddFriendRequest(ctx, req.FromUserID, req.ToUserID, req.ReqMsg, req.Ex); err != nil { return nil, err } - s.notificationSender.FriendApplicationAddNotification(ctx, req) + + if err = s.notificationSender.FriendApplicationAddNotification(ctx, req); err != nil { + return nil, err + } + if err = CallbackAfterAddFriend(ctx, s.config, req); err != nil && err != errs.ErrCallbackContinue { return nil, err } @@ -197,7 +207,9 @@ func (s *friendServer) RespondFriendApply(ctx context.Context, req *pbfriend.Res if err != nil { return nil, err } - s.notificationSender.FriendApplicationAgreedNotification(ctx, req) + if err := s.notificationSender.FriendApplicationAgreedNotification(ctx, req); err != nil { + return nil, err + } return resp, nil } if req.HandleResult == constant.FriendResponseRefuse { diff --git a/internal/rpc/group/group.go b/internal/rpc/group/group.go index d966bfad8e..7ebd237b52 100644 --- a/internal/rpc/group/group.go +++ b/internal/rpc/group/group.go @@ -637,6 +637,7 @@ func (s *groupServer) GetGroupMembersInfo(ctx context.Context, req *pbgroup.GetG return resp, nil } +// GetGroupApplicationList handles functions that get a list of group requests func (s *groupServer) GetGroupApplicationList(ctx context.Context, req *pbgroup.GetGroupApplicationListReq) (*pbgroup.GetGroupApplicationListResp, error) { groupIDs, err := s.db.FindUserManagedGroupID(ctx, req.FromUserID) if err != nil { diff --git a/pkg/rpcclient/notification/friend.go b/pkg/rpcclient/notification/friend.go index dafca055a1..751bdf4757 100644 --- a/pkg/rpcclient/notification/friend.go +++ b/pkg/rpcclient/notification/friend.go @@ -126,10 +126,7 @@ func (f *FriendNotificationSender) UserInfoUpdatedNotification(ctx context.Conte return f.Notification(ctx, mcontext.GetOpUserID(ctx), changedUserID, constant.UserInfoUpdatedNotification, &tips) } -func (f *FriendNotificationSender) FriendApplicationAddNotification( - ctx context.Context, - req *pbfriend.ApplyToAddFriendReq, -) error { +func (f *FriendNotificationSender) FriendApplicationAddNotification(ctx context.Context, req *pbfriend.ApplyToAddFriendReq) error { tips := sdkws.FriendApplicationTips{FromToUserID: &sdkws.FromToUserID{ FromUserID: req.FromUserID, ToUserID: req.ToUserID, diff --git a/scripts/install/test.sh b/scripts/install/test.sh index 3263075703..51d541ecea 100755 --- a/scripts/install/test.sh +++ b/scripts/install/test.sh @@ -932,7 +932,7 @@ openim::test::set_group_info() { { "groupInfoForSet": { "groupID": "${1}", - "groupName": "new-name", + "groupName": "new group name", "notification": "new notification", "introduction": "new introduction", "faceURL": "www.newfaceURL.com", @@ -1076,6 +1076,7 @@ function openim::test::group() { local GROUP_ID=$RANDOM local GROUP_ID2=$RANDOM + # Assumes that TEST_GROUP_ID, USER_ID, and other necessary IDs are set as environment variables before running this suite. # 0. Register a friend user. openim::test::user_register "${USER_ID}" "group00" "new_face_url" From 4cd42d7e19cf17914936967071175a8227424b78 Mon Sep 17 00:00:00 2001 From: Xinwei Xiong <3293172751NSS@gmail.com> Date: Mon, 18 Mar 2024 10:35:00 +0800 Subject: [PATCH 118/188] fix: create time sort (#2090) --- pkg/common/db/mgo/group.go | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/pkg/common/db/mgo/group.go b/pkg/common/db/mgo/group.go index 07c5394e26..01bb64cdec 100644 --- a/pkg/common/db/mgo/group.go +++ b/pkg/common/db/mgo/group.go @@ -19,7 +19,8 @@ import ( "time" "github.com/OpenIMSDK/protocol/constant" - "github.com/OpenIMSDK/tools/errs" + + "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/mgoutil" "github.com/OpenIMSDK/tools/pagination" "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" @@ -70,8 +71,12 @@ func (g *GroupMgo) Take(ctx context.Context, groupID string) (group *relation.Gr } func (g *GroupMgo) Search(ctx context.Context, keyword string, pagination pagination.Pagination) (total int64, groups []*relation.GroupModel, err error) { - return mgoutil.FindPage[*relation.GroupModel](ctx, g.coll, bson.M{"group_name": bson.M{"$regex": keyword}, - "status": bson.M{"$ne": constant.GroupStatusDismissed}}, pagination) + opts := options.Find().SetSort(bson.D{{Key: "created_at", Value: -1}}) + + return mgoutil.FindPage[*relation.GroupModel](ctx, g.coll, bson.M{ + "group_name": bson.M{"$regex": keyword}, + "status": bson.M{"$ne": constant.GroupStatusDismissed}, + }, pagination, opts) } func (g *GroupMgo) CountTotal(ctx context.Context, before *time.Time) (count int64, err error) { From 4ed575a53c5566b35ee5ac3ac1caa7f16985cf11 Mon Sep 17 00:00:00 2001 From: Xinwei Xiong <3293172751NSS@gmail.com> Date: Mon, 18 Mar 2024 10:35:19 +0800 Subject: [PATCH 119/188] fix: fix group getGroupMemberIDs is 0 err (#2108) --- internal/rpc/group/cache.go | 5 +---- internal/rpc/group/group.go | 4 ++++ internal/rpc/msg/sync_msg.go | 23 ++++++++++++++++------- pkg/authverify/token.go | 1 + pkg/rpcclient/group.go | 12 ++---------- 5 files changed, 24 insertions(+), 21 deletions(-) diff --git a/internal/rpc/group/cache.go b/internal/rpc/group/cache.go index 54b60c5543..35c631effe 100644 --- a/internal/rpc/group/cache.go +++ b/internal/rpc/group/cache.go @@ -33,10 +33,7 @@ func (s *groupServer) GetGroupInfoCache( return resp, nil } -func (s *groupServer) GetGroupMemberCache( - ctx context.Context, - req *pbgroup.GetGroupMemberCacheReq, -) (resp *pbgroup.GetGroupMemberCacheResp, err error) { +func (s *groupServer) GetGroupMemberCache(ctx context.Context, req *pbgroup.GetGroupMemberCacheReq) (resp *pbgroup.GetGroupMemberCacheResp, err error) { members, err := s.db.TakeGroupMember(ctx, req.GroupID, req.GroupMemberID) if err != nil { return nil, err diff --git a/internal/rpc/group/group.go b/internal/rpc/group/group.go index 7ebd237b52..e1e0dfed71 100644 --- a/internal/rpc/group/group.go +++ b/internal/rpc/group/group.go @@ -952,6 +952,7 @@ func (s *groupServer) SetGroupInfo(ctx context.Context, req *pbgroup.SetGroupInf return nil, errs.Wrap(errs.ErrDismissedAlready) } resp := &pbgroup.SetGroupInfoResp{} + count, err := s.db.FindGroupMemberNum(ctx, group.GroupID) if err != nil { return nil, err @@ -1078,6 +1079,7 @@ func (s *groupServer) GetGroups(ctx context.Context, req *pbgroup.GetGroupsReq) total, group, err = s.db.SearchGroup(ctx, req.GroupName, req.Pagination) resp.Total = uint32(total) } + if err != nil { return nil, err } @@ -1085,10 +1087,12 @@ func (s *groupServer) GetGroups(ctx context.Context, req *pbgroup.GetGroupsReq) groupIDs := utils.Slice(group, func(e *relationtb.GroupModel) string { return e.GroupID }) + ownerMembers, err := s.db.FindGroupsOwner(ctx, groupIDs) if err != nil { return nil, err } + ownerMemberMap := utils.SliceToMap(ownerMembers, func(e *relationtb.GroupMemberModel) string { return e.GroupID }) diff --git a/internal/rpc/msg/sync_msg.go b/internal/rpc/msg/sync_msg.go index 379302e983..0a8b3f89e7 100644 --- a/internal/rpc/msg/sync_msg.go +++ b/internal/rpc/msg/sync_msg.go @@ -137,6 +137,7 @@ func (m *msgServer) SearchMessage(ctx context.Context, req *msg.SearchMessageReq groupIDs = append(groupIDs, chatLog.GroupID) } } + // Retrieve sender and receiver information if len(sendIDs) != 0 { sendInfos, err := m.UserLocalCache.GetUsersInfo(ctx, sendIDs) if err != nil { @@ -155,6 +156,8 @@ func (m *msgServer) SearchMessage(ctx context.Context, req *msg.SearchMessageReq recvMap[recvInfo.UserID] = recvInfo.Nickname } } + + // Retrieve group information including member counts if len(groupIDs) != 0 { groupInfos, err := m.GroupLocalCache.GetGroupInfos(ctx, groupIDs) if err != nil { @@ -162,8 +165,14 @@ func (m *msgServer) SearchMessage(ctx context.Context, req *msg.SearchMessageReq } for _, groupInfo := range groupInfos { groupMap[groupInfo.GroupID] = groupInfo + // Get actual member count + memberIDs, err := m.GroupLocalCache.GetGroupMemberIDs(ctx, groupInfo.GroupID) + if err == nil { + groupInfo.MemberCount = uint32(len(memberIDs)) // Update the member count with actual number + } } } + // Construct response with updated information for _, chatLog := range chatLogs { pbchatLog := &msg.ChatLog{} utils.CopyStructFields(pbchatLog, chatLog) @@ -175,14 +184,14 @@ func (m *msgServer) SearchMessage(ctx context.Context, req *msg.SearchMessageReq switch chatLog.SessionType { case constant.SingleChatType, constant.NotificationChatType: pbchatLog.RecvNickname = recvMap[chatLog.RecvID] - case constant.GroupChatType, constant.SuperGroupChatType: - pbchatLog.SenderFaceURL = groupMap[chatLog.GroupID].FaceURL - pbchatLog.GroupMemberCount = groupMap[chatLog.GroupID].MemberCount - pbchatLog.RecvID = groupMap[chatLog.GroupID].GroupID - pbchatLog.GroupName = groupMap[chatLog.GroupID].GroupName - pbchatLog.GroupOwner = groupMap[chatLog.GroupID].OwnerUserID - pbchatLog.GroupType = groupMap[chatLog.GroupID].GroupType + groupInfo := groupMap[chatLog.GroupID] + pbchatLog.SenderFaceURL = groupInfo.FaceURL + pbchatLog.GroupMemberCount = groupInfo.MemberCount // Reflects actual member count + pbchatLog.RecvID = groupInfo.GroupID + pbchatLog.GroupName = groupInfo.GroupName + pbchatLog.GroupOwner = groupInfo.OwnerUserID + pbchatLog.GroupType = groupInfo.GroupType } resp.ChatLogs = append(resp.ChatLogs, pbchatLog) } diff --git a/pkg/authverify/token.go b/pkg/authverify/token.go index 26c43532d1..8127e08dfd 100644 --- a/pkg/authverify/token.go +++ b/pkg/authverify/token.go @@ -60,6 +60,7 @@ func CheckAdmin(ctx context.Context, config *config.GlobalConfig) error { } return errs.ErrNoPermission.Wrap(fmt.Sprintf("user %s is not admin userID", mcontext.GetOpUserID(ctx))) } + func CheckIMAdmin(ctx context.Context, config *config.GlobalConfig) error { if utils.IsContain(mcontext.GetOpUserID(ctx), config.IMAdmin.UserID) { return nil diff --git a/pkg/rpcclient/group.go b/pkg/rpcclient/group.go index ec7aab6957..3e9c93e7a4 100644 --- a/pkg/rpcclient/group.go +++ b/pkg/rpcclient/group.go @@ -49,11 +49,7 @@ func NewGroupRpcClient(discov discoveryregistry.SvcDiscoveryRegistry, config *co return GroupRpcClient(*NewGroup(discov, config)) } -func (g *GroupRpcClient) GetGroupInfos( - ctx context.Context, - groupIDs []string, - complete bool, -) ([]*sdkws.GroupInfo, error) { +func (g *GroupRpcClient) GetGroupInfos(ctx context.Context, groupIDs []string, complete bool) ([]*sdkws.GroupInfo, error) { resp, err := g.Client.GetGroupsInfo(ctx, &group.GetGroupsInfoReq{ GroupIDs: groupIDs, }) @@ -184,11 +180,7 @@ func (g *GroupRpcClient) GetGroupInfoCache(ctx context.Context, groupID string) return resp.GroupInfo, nil } -func (g *GroupRpcClient) GetGroupMemberCache( - ctx context.Context, - groupID string, - groupMemberID string, -) (*sdkws.GroupMemberFullInfo, error) { +func (g *GroupRpcClient) GetGroupMemberCache(ctx context.Context, groupID string, groupMemberID string) (*sdkws.GroupMemberFullInfo, error) { resp, err := g.Client.GetGroupMemberCache(ctx, &group.GetGroupMemberCacheReq{ GroupID: groupID, GroupMemberID: groupMemberID, From 8f218057e455541f5cc5a3709da0694e631c2435 Mon Sep 17 00:00:00 2001 From: chao <48119764+withchao@users.noreply.github.com> Date: Mon, 18 Mar 2024 10:49:36 +0800 Subject: [PATCH 120/188] fix: conversation crash caused by non-existence (#2087) * fix: GroupApplicationAcceptedNotification * fix: GroupApplicationAcceptedNotification * fix: NotificationUserInfoUpdate * cicd: robot automated Change * fix: component * fix: getConversationInfo --------- Co-authored-by: withchao --- internal/rpc/conversation/conversaion.go | 26 ++++++++++++++++-------- tools/component/component.go | 5 +++-- 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/internal/rpc/conversation/conversaion.go b/internal/rpc/conversation/conversaion.go index 91eec079bd..e78e4a18f0 100644 --- a/internal/rpc/conversation/conversaion.go +++ b/internal/rpc/conversation/conversaion.go @@ -506,19 +506,27 @@ func (c *conversationServer) getConversationInfo( switch chatLog.SessionType { case constant.SingleChatType: if chatLog.SendID == userID { - msgInfo.FaceURL = sendMap[chatLog.RecvID].FaceURL - msgInfo.SenderName = sendMap[chatLog.RecvID].Nickname + if recv, ok := sendMap[chatLog.RecvID]; ok { + msgInfo.FaceURL = recv.FaceURL + msgInfo.SenderName = recv.Nickname + } break } - msgInfo.FaceURL = sendMap[chatLog.SendID].FaceURL - msgInfo.SenderName = sendMap[chatLog.SendID].Nickname + if send, ok := sendMap[chatLog.SendID]; ok { + msgInfo.FaceURL = send.FaceURL + msgInfo.SenderName = send.Nickname + } case constant.GroupChatType, constant.SuperGroupChatType: - msgInfo.GroupName = groupMap[chatLog.GroupID].GroupName - msgInfo.GroupFaceURL = groupMap[chatLog.GroupID].FaceURL - msgInfo.GroupMemberCount = groupMap[chatLog.GroupID].MemberCount msgInfo.GroupID = chatLog.GroupID - msgInfo.GroupType = groupMap[chatLog.GroupID].GroupType - msgInfo.SenderName = sendMap[chatLog.SendID].Nickname + if group, ok := groupMap[chatLog.GroupID]; ok { + msgInfo.GroupName = group.GroupName + msgInfo.GroupFaceURL = group.FaceURL + msgInfo.GroupMemberCount = group.MemberCount + msgInfo.GroupType = group.GroupType + } + if send, ok := sendMap[chatLog.SendID]; ok { + msgInfo.SenderName = send.Nickname + } } pbchatLog.ConversationID = conversationID msgInfo.LatestMsgRecvTime = chatLog.SendTime diff --git a/tools/component/component.go b/tools/component/component.go index 3220f36f73..e1f86e1207 100644 --- a/tools/component/component.go +++ b/tools/component/component.go @@ -99,13 +99,14 @@ func main() { } checks := []checkFunc{ - //{name: "Mysql", function: checkMysql}, {name: "Mongo", function: checkMongo, config: conf}, {name: "Redis", function: checkRedis, config: conf}, - {name: "Minio", function: checkMinio, config: conf}, {name: "Zookeeper", function: checkZookeeper, config: conf}, {name: "Kafka", function: checkKafka, config: conf}, } + if conf.Object.Enable == "minio" { + checks = append(checks, checkFunc{name: "Minio", function: checkMinio, config: conf}) + } for i := 0; i < maxRetry; i++ { if i != 0 { From c69522b878550fc5386643c87572b7223559fa20 Mon Sep 17 00:00:00 2001 From: OpenIM Bot <124379614+kubbot@users.noreply.github.com> Date: Tue, 19 Mar 2024 14:23:50 +0800 Subject: [PATCH 121/188] cicd: bump League Patch (#2117) --- .github/code-language-detector.yml | 14 ++++++++++++++ .github/workflows/code-language-detector.yml | 14 ++++++++++++++ internal/rpc/friend/black.go | 2 +- internal/rpc/group/group.go | 2 +- pkg/common/db/mgo/group.go | 3 +-- 5 files changed, 31 insertions(+), 4 deletions(-) diff --git a/.github/code-language-detector.yml b/.github/code-language-detector.yml index 9a81236b8a..32a8c1f54b 100644 --- a/.github/code-language-detector.yml +++ b/.github/code-language-detector.yml @@ -1,3 +1,17 @@ +# 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. + directory: ./ file_types: - .go diff --git a/.github/workflows/code-language-detector.yml b/.github/workflows/code-language-detector.yml index 22307576a4..80ec947338 100644 --- a/.github/workflows/code-language-detector.yml +++ b/.github/workflows/code-language-detector.yml @@ -1,3 +1,17 @@ +# 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. + name: Language Check Workflow Test on: [pull_request] diff --git a/internal/rpc/friend/black.go b/internal/rpc/friend/black.go index 4bb0d9f58f..4e130360cd 100644 --- a/internal/rpc/friend/black.go +++ b/internal/rpc/friend/black.go @@ -79,7 +79,7 @@ func (s *friendServer) AddBlack(ctx context.Context, req *pbfriend.AddBlackReq) CreateTime: time.Now(), Ex: req.Ex, } - + if err := s.blackDatabase.Create(ctx, []*relation.BlackModel{&black}); err != nil { return nil, err } diff --git a/internal/rpc/group/group.go b/internal/rpc/group/group.go index e1e0dfed71..92d9e27d6a 100644 --- a/internal/rpc/group/group.go +++ b/internal/rpc/group/group.go @@ -637,7 +637,7 @@ func (s *groupServer) GetGroupMembersInfo(ctx context.Context, req *pbgroup.GetG return resp, nil } -// GetGroupApplicationList handles functions that get a list of group requests +// GetGroupApplicationList handles functions that get a list of group requests. func (s *groupServer) GetGroupApplicationList(ctx context.Context, req *pbgroup.GetGroupApplicationListReq) (*pbgroup.GetGroupApplicationListResp, error) { groupIDs, err := s.db.FindUserManagedGroupID(ctx, req.FromUserID) if err != nil { diff --git a/pkg/common/db/mgo/group.go b/pkg/common/db/mgo/group.go index 01bb64cdec..c63e3c3761 100644 --- a/pkg/common/db/mgo/group.go +++ b/pkg/common/db/mgo/group.go @@ -19,8 +19,7 @@ import ( "time" "github.com/OpenIMSDK/protocol/constant" - - "github.com/OpenIMSDK/tools/errs" + "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/mgoutil" "github.com/OpenIMSDK/tools/pagination" "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" From 6d1062bef8f800169e0ced8851372666631e007a Mon Sep 17 00:00:00 2001 From: Yibiao He Date: Tue, 19 Mar 2024 17:40:30 +0800 Subject: [PATCH 122/188] fix: Fix the callback after reading the group message (#2114) --- internal/rpc/msg/callback.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/internal/rpc/msg/callback.go b/internal/rpc/msg/callback.go index 536402bf99..927bbe0c22 100644 --- a/internal/rpc/msg/callback.go +++ b/internal/rpc/msg/callback.go @@ -156,27 +156,27 @@ func callbackMsgModify(ctx context.Context, globalConfig *config.GlobalConfig, m return nil } func CallbackGroupMsgRead(ctx context.Context, globalConfig *config.GlobalConfig, req *cbapi.CallbackGroupMsgReadReq) error { - if !globalConfig.Callback.CallbackGroupMsgRead.Enable || req.ContentType != constant.Text { + if !globalConfig.Callback.CallbackGroupMsgRead.Enable { return nil } req.CallbackCommand = cbapi.CallbackGroupMsgReadCommand resp := &cbapi.CallbackGroupMsgReadResp{} - if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, req, resp, globalConfig.Callback.CallbackMsgModify); err != nil { + if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, req, resp, globalConfig.Callback.CallbackGroupMsgRead); err != nil { return err } return nil } func CallbackSingleMsgRead(ctx context.Context, globalConfig *config.GlobalConfig, req *cbapi.CallbackSingleMsgReadReq) error { - if !globalConfig.Callback.CallbackSingleMsgRead.Enable || req.ContentType != constant.Text { + if !globalConfig.Callback.CallbackSingleMsgRead.Enable { return nil } req.CallbackCommand = cbapi.CallbackSingleMsgRead resp := &cbapi.CallbackSingleMsgReadResp{} - if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, req, resp, globalConfig.Callback.CallbackMsgModify); err != nil { + if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, req, resp, globalConfig.Callback.CallbackSingleMsgRead); err != nil { return err } return nil From 0274d516e0aa82682cb4e92d251509813c5793ca Mon Sep 17 00:00:00 2001 From: skiffer-git <72860476+skiffer-git@users.noreply.github.com> Date: Tue, 19 Mar 2024 19:46:10 +0800 Subject: [PATCH 123/188] The check script is not compatible with Mac. (#2119) * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * fix: mongo * fix: mongo * fix: mongo * openim.yaml * localcache * localcache * localcache * localcache * localcache * localcache * localcache * localcache * localcache * local cache * local cache * local cache * local cache * fix: GroupApplicationAcceptedNotification * fix: GroupApplicationAcceptedNotification * fix: NotificationUserInfoUpdate * feat: cache add single-flight and timing-wheel. * feat: local cache * feat: local cache * feat: local cache * feat: cache add single-flight and timing-wheel. * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * refactor: refactor the code of push and optimization. * cicd: robot automated Change * refactor: rename cache. * merge * fix: refactor project dir avoid import cycle. * update tools * merge * feat: conversation FindRecvMsgNotNotifyUserIDs * feat: conversation FindRecvMsgNotNotifyUserIDs * feat: conversation FindRecvMsgNotNotifyUserIDs * merge * merge the latest main * Exit with code 1 when the check script fails (#2023) * Optimize script logs * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Exit with code 1 when the check script fails * Execute after the component check succeeds && minio.Enable is not configured to use MinIO (#2027) * Exit with code 1 when the check script fails (#2022) * Optimize script logs * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Exit with code 1 when the check script fails * Exit with code 1 when the check script fails * Exit with code 1 when the check script fails * Exit with code 1 when the check script fails * Exit with code 1 when the check script fails * Handle the return value of pre-start * Handle the return value of pre-start * Handle the return value of pre-start * minio.Enable is not configured to use MinIO, therefore the image server is not checked * minio.Enable is not configured to use MinIO, therefore the image server is not checked * minio.Enable is not configured to use MinIO, therefore the image server is not checked * minio.Enable is not configured to use MinIO, therefore the image server is not checked * Log redirection causes incorrect program exit status. (#2031) * Exit with code 1 when the check script fails (#2022) * Optimize script logs * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Exit with code 1 when the check script fails * cicd: bump League Patch (#2025) * Execute after the component check succeeds && minio.Enable is not configured to use MinIO (#2026) * Exit with code 1 when the check script fails * Exit with code 1 when the check script fails * Exit with code 1 when the check script fails * Exit with code 1 when the check script fails * Handle the return value of pre-start * Handle the return value of pre-start * Handle the return value of pre-start * minio.Enable is not configured to use MinIO, therefore the image server is not checked * minio.Enable is not configured to use MinIO, therefore the image server is not checked * minio.Enable is not configured to use MinIO, therefore the image server is not checked * minio.Enable is not configured to use MinIO, therefore the image server is not checked * Log redirection causes incorrect program exit status. --------- Co-authored-by: OpenIM Bot <124379614+kubbot@users.noreply.github.com> * delete * add context deadline exceeded * Error not handled * Error not handled * Error not handled * Error not handled * Fix bug Remove duplicate function definitions (#2034) * Exit with code 1 when the check script fails (#2022) * Optimize script logs * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Exit with code 1 when the check script fails * delete * delete log * configGetEnv failed,err:string to int failed: strconv.Atoi: parsing "openim_v3": invalid syntaxr * Fix bug configGetEnv failed,err:string to int failed: strconv.Atoi: parsing "openim_v3": invalid syntaxr (#2045) * Error not handled (#2040) * delete * add context deadline exceeded * Error not handled * Error not handled * Error not handled * Error not handled * feat: add local cache for high frequency reads (#2036) * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * fix: mongo * fix: mongo * fix: mongo * openim.yaml * localcache * localcache * localcache * localcache * localcache * localcache * localcache * localcache * localcache * local cache * local cache * local cache * local cache * fix: GroupApplicationAcceptedNotification * fix: GroupApplicationAcceptedNotification * fix: NotificationUserInfoUpdate * feat: cache add single-flight and timing-wheel. * feat: local cache * feat: local cache * feat: local cache * feat: cache add single-flight and timing-wheel. * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * refactor: refactor the code of push and optimization. * cicd: robot automated Change * refactor: rename cache. * merge * fix: refactor project dir avoid import cycle. * update tools * merge * feat: conversation FindRecvMsgNotNotifyUserIDs * feat: conversation FindRecvMsgNotNotifyUserIDs * feat: conversation FindRecvMsgNotNotifyUserIDs * merge * merge the latest main --------- Co-authored-by: Gordon <46924906+FGadvancer@users.noreply.github.com> Co-authored-by: withchao * configGetEnv failed,err:string to int failed: strconv.Atoi: parsing "openim_v3": invalid syntaxr --------- Co-authored-by: chao <48119764+withchao@users.noreply.github.com> Co-authored-by: Gordon <46924906+FGadvancer@users.noreply.github.com> Co-authored-by: withchao * Feature: delete log for update images (#2050) * Error not handled (#2040) * delete * add context deadline exceeded * Error not handled * Error not handled * Error not handled * Error not handled * feat: add local cache for high frequency reads (#2036) * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * fix: mongo * fix: mongo * fix: mongo * openim.yaml * localcache * localcache * localcache * localcache * localcache * localcache * localcache * localcache * localcache * local cache * local cache * local cache * local cache * fix: GroupApplicationAcceptedNotification * fix: GroupApplicationAcceptedNotification * fix: NotificationUserInfoUpdate * feat: cache add single-flight and timing-wheel. * feat: local cache * feat: local cache * feat: local cache * feat: cache add single-flight and timing-wheel. * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * refactor: refactor the code of push and optimization. * cicd: robot automated Change * refactor: rename cache. * merge * fix: refactor project dir avoid import cycle. * update tools * merge * feat: conversation FindRecvMsgNotNotifyUserIDs * feat: conversation FindRecvMsgNotNotifyUserIDs * feat: conversation FindRecvMsgNotNotifyUserIDs * merge * merge the latest main --------- Co-authored-by: Gordon <46924906+FGadvancer@users.noreply.github.com> Co-authored-by: withchao * Fix bug Remove duplicate function definitions (#2033) * delete * delete log * Fix bug configGetEnv failed,err:string to int failed: strconv.Atoi: parsing "openim_v3": invalid syntaxr (#2044) * delete * add context deadline exceeded * Error not handled * Error not handled * Error not handled * Error not handled * configGetEnv failed,err:string to int failed: strconv.Atoi: parsing "openim_v3": invalid syntaxr * delete log (#2047) * delete log --------- Co-authored-by: chao <48119764+withchao@users.noreply.github.com> Co-authored-by: Gordon <46924906+FGadvancer@users.noreply.github.com> Co-authored-by: withchao * test Signed-off-by: unknown <44203734@qq.com> * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * Bug: component check (#2054) * Error not handled (#2040) * delete * add context deadline exceeded * Error not handled * Error not handled * Error not handled * Error not handled * feat: add local cache for high frequency reads (#2036) * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * fix: mongo * fix: mongo * fix: mongo * openim.yaml * localcache * localcache * localcache * localcache * localcache * localcache * localcache * localcache * localcache * local cache * local cache * local cache * local cache * fix: GroupApplicationAcceptedNotification * fix: GroupApplicationAcceptedNotification * fix: NotificationUserInfoUpdate * feat: cache add single-flight and timing-wheel. * feat: local cache * feat: local cache * feat: local cache * feat: cache add single-flight and timing-wheel. * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * refactor: refactor the code of push and optimization. * cicd: robot automated Change * refactor: rename cache. * merge * fix: refactor project dir avoid import cycle. * update tools * merge * feat: conversation FindRecvMsgNotNotifyUserIDs * feat: conversation FindRecvMsgNotNotifyUserIDs * feat: conversation FindRecvMsgNotNotifyUserIDs * merge * merge the latest main --------- Co-authored-by: Gordon <46924906+FGadvancer@users.noreply.github.com> Co-authored-by: withchao * configGetEnv failed,err:string to int failed: strconv.Atoi: parsing "openim_v3": invalid syntaxr * Fix bug Remove duplicate function definitions (#2033) * delete * delete log * Fix bug configGetEnv failed,err:string to int failed: strconv.Atoi: parsing "openim_v3": invalid syntaxr (#2044) * delete * add context deadline exceeded * Error not handled * Error not handled * Error not handled * Error not handled * configGetEnv failed,err:string to int failed: strconv.Atoi: parsing "openim_v3": invalid syntaxr * delete log (#2047) * test Signed-off-by: unknown <44203734@qq.com> * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check --------- Signed-off-by: unknown <44203734@qq.com> Co-authored-by: chao <48119764+withchao@users.noreply.github.com> Co-authored-by: Gordon <46924906+FGadvancer@users.noreply.github.com> Co-authored-by: withchao * Fix bug delete data conversion (#2060) * Error not handled (#2040) * delete * add context deadline exceeded * Error not handled * Error not handled * Error not handled * Error not handled * feat: add local cache for high frequency reads (#2036) * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * fix: mongo * fix: mongo * fix: mongo * openim.yaml * localcache * localcache * localcache * localcache * localcache * localcache * localcache * localcache * localcache * local cache * local cache * local cache * local cache * fix: GroupApplicationAcceptedNotification * fix: GroupApplicationAcceptedNotification * fix: NotificationUserInfoUpdate * feat: cache add single-flight and timing-wheel. * feat: local cache * feat: local cache * feat: local cache * feat: cache add single-flight and timing-wheel. * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * refactor: refactor the code of push and optimization. * cicd: robot automated Change * refactor: rename cache. * merge * fix: refactor project dir avoid import cycle. * update tools * merge * feat: conversation FindRecvMsgNotNotifyUserIDs * feat: conversation FindRecvMsgNotNotifyUserIDs * feat: conversation FindRecvMsgNotNotifyUserIDs * merge * merge the latest main --------- Co-authored-by: Gordon <46924906+FGadvancer@users.noreply.github.com> Co-authored-by: withchao * configGetEnv failed,err:string to int failed: strconv.Atoi: parsing "openim_v3": invalid syntaxr * Fix bug Remove duplicate function definitions (#2033) * delete * delete log * Fix bug configGetEnv failed,err:string to int failed: strconv.Atoi: parsing "openim_v3": invalid syntaxr (#2044) * delete * add context deadline exceeded * Error not handled * Error not handled * Error not handled * Error not handled * configGetEnv failed,err:string to int failed: strconv.Atoi: parsing "openim_v3": invalid syntaxr * delete log (#2047) * test Signed-off-by: unknown <44203734@qq.com> * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * Bug: component check (#2053) * delete * add context deadline exceeded * Error not handled * Error not handled * Error not handled * Error not handled * configGetEnv failed,err:string to int failed: strconv.Atoi: parsing "openim_v3": invalid syntaxr * test Signed-off-by: unknown <44203734@qq.com> * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check --------- Signed-off-by: unknown <44203734@qq.com> * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * Bug: component check (#2056) * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * fix: mongo * fix: mongo * fix: mongo * openim.yaml * localcache * localcache * localcache * localcache * localcache * localcache * localcache * localcache * localcache * local cache * local cache * local cache * local cache * fix: GroupApplicationAcceptedNotification * fix: GroupApplicationAcceptedNotification * fix: NotificationUserInfoUpdate * feat: cache add single-flight and timing-wheel. * feat: local cache * feat: local cache * feat: local cache * feat: cache add single-flight and timing-wheel. * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * refactor: refactor the code of push and optimization. * cicd: robot automated Change * refactor: rename cache. * merge * fix: refactor project dir avoid import cycle. * update tools * merge * feat: conversation FindRecvMsgNotNotifyUserIDs * feat: conversation FindRecvMsgNotNotifyUserIDs * feat: conversation FindRecvMsgNotNotifyUserIDs * merge * merge the latest main * Exit with code 1 when the check script fails (#2023) * Optimize script logs * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Exit with code 1 when the check script fails * Execute after the component check succeeds && minio.Enable is not configured to use MinIO (#2027) * Exit with code 1 when the check script fails (#2022) * Optimize script logs * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Exit with code 1 when the check script fails * Exit with code 1 when the check script fails * Exit with code 1 when the check script fails * Exit with code 1 when the check script fails * Exit with code 1 when the check script fails * Handle the return value of pre-start * Handle the return value of pre-start * Handle the return value of pre-start * minio.Enable is not configured to use MinIO, therefore the image server is not checked * minio.Enable is not configured to use MinIO, therefore the image server is not checked * minio.Enable is not configured to use MinIO, therefore the image server is not checked * minio.Enable is not configured to use MinIO, therefore the image server is not checked * Log redirection causes incorrect program exit status. (#2031) * Exit with code 1 when the check script fails (#2022) * Optimize script logs * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Exit with code 1 when the check script fails * cicd: bump League Patch (#2025) * Execute after the component check succeeds && minio.Enable is not configured to use MinIO (#2026) * Exit with code 1 when the check script fails * Exit with code 1 when the check script fails * Exit with code 1 when the check script fails * Exit with code 1 when the check script fails * Handle the return value of pre-start * Handle the return value of pre-start * Handle the return value of pre-start * minio.Enable is not configured to use MinIO, therefore the image server is not checked * minio.Enable is not configured to use MinIO, therefore the image server is not checked * minio.Enable is not configured to use MinIO, therefore the image server is not checked * minio.Enable is not configured to use MinIO, therefore the image server is not checked * Log redirection causes incorrect program exit status. --------- Co-authored-by: OpenIM Bot <124379614+kubbot@users.noreply.github.com> * delete * add context deadline exceeded * Error not handled * Error not handled * Error not handled * Error not handled * Fix bug Remove duplicate function definitions (#2034) * Exit with code 1 when the check script fails (#2022) * Optimize script logs * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Exit with code 1 when the check script fails * delete * delete log * configGetEnv failed,err:string to int failed: strconv.Atoi: parsing "openim_v3": invalid syntaxr * Fix bug configGetEnv failed,err:string to int failed: strconv.Atoi: parsing "openim_v3": invalid syntaxr (#2045) * Error not handled (#2040) * delete * add context deadline exceeded * Error not handled * Error not handled * Error not handled * Error not handled * feat: add local cache for high frequency reads (#2036) * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * fix: mongo * fix: mongo * fix: mongo * openim.yaml * localcache * localcache * localcache * localcache * localcache * localcache * localcache * localcache * localcache * local cache * local cache * local cache * local cache * fix: GroupApplicationAcceptedNotification * fix: GroupApplicationAcceptedNotification * fix: NotificationUserInfoUpdate * feat: cache add single-flight and timing-wheel. * feat: local cache * feat: local cache * feat: local cache * feat: cache add single-flight and timing-wheel. * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * refactor: refactor the code of push and optimization. * cicd: robot automated Change * refactor: rename cache. * merge * fix: refactor project dir avoid import cycle. * update tools * merge * feat: conversation FindRecvMsgNotNotifyUserIDs * feat: conversation FindRecvMsgNotNotifyUserIDs * feat: conversation FindRecvMsgNotNotifyUserIDs * merge * merge the latest main --------- Co-authored-by: Gordon <46924906+FGadvancer@users.noreply.github.com> Co-authored-by: withchao * configGetEnv failed,err:string to int failed: strconv.Atoi: parsing "openim_v3": invalid syntaxr --------- Co-authored-by: chao <48119764+withchao@users.noreply.github.com> Co-authored-by: Gordon <46924906+FGadvancer@users.noreply.github.com> Co-authored-by: withchao * Feature: delete log for update images (#2050) * Error not handled (#2040) * delete * add context deadline exceeded * Error not handled * Error not handled * Error not handled * Error not handled * feat: add local cache for high frequency reads (#2036) * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * fix: mongo * fix: mongo * fix: mongo * openim.yaml * localcache * localcache * localcache * localcache * localcache * localcache * localcache * localcache * localcache * local cache * local cache * local cache * local cache * fix: GroupApplicationAcceptedNotification * fix: GroupApplicationAcceptedNotification * fix: NotificationUserInfoUpdate * feat: cache add single-flight and timing-wheel. * feat: local cache * feat: local cache * feat: local cache * feat: cache add single-flight and timing-wheel. * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * refactor: refactor the code of push and optimization. * cicd: robot automated Change * refactor: rename cache. * merge * fix: refactor project dir avoid import cycle. * update tools * merge * feat: conversation FindRecvMsgNotNotifyUserIDs * feat: conversation FindRecvMsgNotNotifyUserIDs * feat: conversation FindRecvMsgNotNotifyUserIDs * merge * merge the latest main --------- Co-authored-by: Gordon <46924906+FGadvancer@users.noreply.github.com> Co-authored-by: withchao * Fix bug Remove duplicate function definitions (#2033) * delete * delete log * Fix bug configGetEnv failed,err:string to int failed: strconv.Atoi: parsing "openim_v3": invalid syntaxr (#2044) * delete * add context deadline exceeded * Error not handled * Error not handled * Error not handled * Error not handled * configGetEnv failed,err:string to int failed: strconv.Atoi: parsing "openim_v3": invalid syntaxr * delete log (#2047) * delete log --------- Co-authored-by: chao <48119764+withchao@users.noreply.github.com> Co-authored-by: Gordon <46924906+FGadvancer@users.noreply.github.com> Co-authored-by: withchao * test Signed-off-by: unknown <44203734@qq.com> * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check --------- Signed-off-by: unknown <44203734@qq.com> Co-authored-by: withchao <993506633@qq.com> Co-authored-by: chao <48119764+withchao@users.noreply.github.com> Co-authored-by: Gordon <46924906+FGadvancer@users.noreply.github.com> Co-authored-by: withchao Co-authored-by: OpenIM Bot <124379614+kubbot@users.noreply.github.com> * Delete Data Conversion Tool * Delete Data Conversion Tool * Delete Data Conversion Tool * Delete Data Conversion Tool * Delete Data Conversion Tool * Delete Data Conversion Tool * Delete Data Conversion Tool * Delete Data Conversion Tool * Delete Data Conversion Tool * delete data conversion tool * delete data conversion tool * delete data conversion tool --------- Signed-off-by: unknown <44203734@qq.com> Co-authored-by: chao <48119764+withchao@users.noreply.github.com> Co-authored-by: Gordon <46924906+FGadvancer@users.noreply.github.com> Co-authored-by: withchao Co-authored-by: withchao <993506633@qq.com> Co-authored-by: OpenIM Bot <124379614+kubbot@users.noreply.github.com> * Fix bug redis address (#2062) * Error not handled (#2040) * delete * add context deadline exceeded * Error not handled * Error not handled * Error not handled * Error not handled * feat: add local cache for high frequency reads (#2036) * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * fix: mongo * fix: mongo * fix: mongo * openim.yaml * localcache * localcache * localcache * localcache * localcache * localcache * localcache * localcache * localcache * local cache * local cache * local cache * local cache * fix: GroupApplicationAcceptedNotification * fix: GroupApplicationAcceptedNotification * fix: NotificationUserInfoUpdate * feat: cache add single-flight and timing-wheel. * feat: local cache * feat: local cache * feat: local cache * feat: cache add single-flight and timing-wheel. * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * refactor: refactor the code of push and optimization. * cicd: robot automated Change * refactor: rename cache. * merge * fix: refactor project dir avoid import cycle. * update tools * merge * feat: conversation FindRecvMsgNotNotifyUserIDs * feat: conversation FindRecvMsgNotNotifyUserIDs * feat: conversation FindRecvMsgNotNotifyUserIDs * merge * merge the latest main --------- Co-authored-by: Gordon <46924906+FGadvancer@users.noreply.github.com> Co-authored-by: withchao * configGetEnv failed,err:string to int failed: strconv.Atoi: parsing "openim_v3": invalid syntaxr * Fix bug Remove duplicate function definitions (#2033) * delete * delete log * Fix bug configGetEnv failed,err:string to int failed: strconv.Atoi: parsing "openim_v3": invalid syntaxr (#2044) * delete * add context deadline exceeded * Error not handled * Error not handled * Error not handled * Error not handled * configGetEnv failed,err:string to int failed: strconv.Atoi: parsing "openim_v3": invalid syntaxr * delete log (#2047) * test Signed-off-by: unknown <44203734@qq.com> * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * Bug: component check (#2053) * delete * add context deadline exceeded * Error not handled * Error not handled * Error not handled * Error not handled * configGetEnv failed,err:string to int failed: strconv.Atoi: parsing "openim_v3": invalid syntaxr * test Signed-off-by: unknown <44203734@qq.com> * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check --------- Signed-off-by: unknown <44203734@qq.com> * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * Bug: component check (#2056) * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * fix: mongo * fix: mongo * fix: mongo * openim.yaml * localcache * localcache * localcache * localcache * localcache * localcache * localcache * localcache * localcache * local cache * local cache * local cache * local cache * fix: GroupApplicationAcceptedNotification * fix: GroupApplicationAcceptedNotification * fix: NotificationUserInfoUpdate * feat: cache add single-flight and timing-wheel. * feat: local cache * feat: local cache * feat: local cache * feat: cache add single-flight and timing-wheel. * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * refactor: refactor the code of push and optimization. * cicd: robot automated Change * refactor: rename cache. * merge * fix: refactor project dir avoid import cycle. * update tools * merge * feat: conversation FindRecvMsgNotNotifyUserIDs * feat: conversation FindRecvMsgNotNotifyUserIDs * feat: conversation FindRecvMsgNotNotifyUserIDs * merge * merge the latest main * Exit with code 1 when the check script fails (#2023) * Optimize script logs * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Exit with code 1 when the check script fails * Execute after the component check succeeds && minio.Enable is not configured to use MinIO (#2027) * Exit with code 1 when the check script fails (#2022) * Optimize script logs * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Exit with code 1 when the check script fails * Exit with code 1 when the check script fails * Exit with code 1 when the check script fails * Exit with code 1 when the check script fails * Exit with code 1 when the check script fails * Handle the return value of pre-start * Handle the return value of pre-start * Handle the return value of pre-start * minio.Enable is not configured to use MinIO, therefore the image server is not checked * minio.Enable is not configured to use MinIO, therefore the image server is not checked * minio.Enable is not configured to use MinIO, therefore the image server is not checked * minio.Enable is not configured to use MinIO, therefore the image server is not checked * Log redirection causes incorrect program exit status. (#2031) * Exit with code 1 when the check script fails (#2022) * Optimize script logs * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Exit with code 1 when the check script fails * cicd: bump League Patch (#2025) * Execute after the component check succeeds && minio.Enable is not configured to use MinIO (#2026) * Exit with code 1 when the check script fails * Exit with code 1 when the check script fails * Exit with code 1 when the check script fails * Exit with code 1 when the check script fails * Handle the return value of pre-start * Handle the return value of pre-start * Handle the return value of pre-start * minio.Enable is not configured to use MinIO, therefore the image server is not checked * minio.Enable is not configured to use MinIO, therefore the image server is not checked * minio.Enable is not configured to use MinIO, therefore the image server is not checked * minio.Enable is not configured to use MinIO, therefore the image server is not checked * Log redirection causes incorrect program exit status. --------- Co-authored-by: OpenIM Bot <124379614+kubbot@users.noreply.github.com> * delete * add context deadline exceeded * Error not handled * Error not handled * Error not handled * Error not handled * Fix bug Remove duplicate function definitions (#2034) * Exit with code 1 when the check script fails (#2022) * Optimize script logs * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Exit with code 1 when the check script fails * delete * delete log * configGetEnv failed,err:string to int failed: strconv.Atoi: parsing "openim_v3": invalid syntaxr * Fix bug configGetEnv failed,err:string to int failed: strconv.Atoi: parsing "openim_v3": invalid syntaxr (#2045) * Error not handled (#2040) * delete * add context deadline exceeded * Error not handled * Error not handled * Error not handled * Error not handled * feat: add local cache for high frequency reads (#2036) * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * fix: mongo * fix: mongo * fix: mongo * openim.yaml * localcache * localcache * localcache * localcache * localcache * localcache * localcache * localcache * localcache * local cache * local cache * local cache * local cache * fix: GroupApplicationAcceptedNotification * fix: GroupApplicationAcceptedNotification * fix: NotificationUserInfoUpdate * feat: cache add single-flight and timing-wheel. * feat: local cache * feat: local cache * feat: local cache * feat: cache add single-flight and timing-wheel. * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * refactor: refactor the code of push and optimization. * cicd: robot automated Change * refactor: rename cache. * merge * fix: refactor project dir avoid import cycle. * update tools * merge * feat: conversation FindRecvMsgNotNotifyUserIDs * feat: conversation FindRecvMsgNotNotifyUserIDs * feat: conversation FindRecvMsgNotNotifyUserIDs * merge * merge the latest main --------- Co-authored-by: Gordon <46924906+FGadvancer@users.noreply.github.com> Co-authored-by: withchao * configGetEnv failed,err:string to int failed: strconv.Atoi: parsing "openim_v3": invalid syntaxr --------- Co-authored-by: chao <48119764+withchao@users.noreply.github.com> Co-authored-by: Gordon <46924906+FGadvancer@users.noreply.github.com> Co-authored-by: withchao * Feature: delete log for update images (#2050) * Error not handled (#2040) * delete * add context deadline exceeded * Error not handled * Error not handled * Error not handled * Error not handled * feat: add local cache for high frequency reads (#2036) * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * fix: mongo * fix: mongo * fix: mongo * openim.yaml * localcache * localcache * localcache * localcache * localcache * localcache * localcache * localcache * localcache * local cache * local cache * local cache * local cache * fix: GroupApplicationAcceptedNotification * fix: GroupApplicationAcceptedNotification * fix: NotificationUserInfoUpdate * feat: cache add single-flight and timing-wheel. * feat: local cache * feat: local cache * feat: local cache * feat: cache add single-flight and timing-wheel. * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * refactor: refactor the code of push and optimization. * cicd: robot automated Change * refactor: rename cache. * merge * fix: refactor project dir avoid import cycle. * update tools * merge * feat: conversation FindRecvMsgNotNotifyUserIDs * feat: conversation FindRecvMsgNotNotifyUserIDs * feat: conversation FindRecvMsgNotNotifyUserIDs * merge * merge the latest main --------- Co-authored-by: Gordon <46924906+FGadvancer@users.noreply.github.com> Co-authored-by: withchao * Fix bug Remove duplicate function definitions (#2033) * delete * delete log * Fix bug configGetEnv failed,err:string to int failed: strconv.Atoi: parsing "openim_v3": invalid syntaxr (#2044) * delete * add context deadline exceeded * Error not handled * Error not handled * Error not handled * Error not handled * configGetEnv failed,err:string to int failed: strconv.Atoi: parsing "openim_v3": invalid syntaxr * delete log (#2047) * delete log --------- Co-authored-by: chao <48119764+withchao@users.noreply.github.com> Co-authored-by: Gordon <46924906+FGadvancer@users.noreply.github.com> Co-authored-by: withchao * test Signed-off-by: unknown <44203734@qq.com> * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check --------- Signed-off-by: unknown <44203734@qq.com> Co-authored-by: withchao <993506633@qq.com> Co-authored-by: chao <48119764+withchao@users.noreply.github.com> Co-authored-by: Gordon <46924906+FGadvancer@users.noreply.github.com> Co-authored-by: withchao Co-authored-by: OpenIM Bot <124379614+kubbot@users.noreply.github.com> * Fix bug delete data conversion (#2059) * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * fix: mongo * fix: mongo * fix: mongo * openim.yaml * localcache * localcache * localcache * localcache * localcache * localcache * localcache * localcache * localcache * local cache * local cache * local cache * local cache * fix: GroupApplicationAcceptedNotification * fix: GroupApplicationAcceptedNotification * fix: NotificationUserInfoUpdate * feat: cache add single-flight and timing-wheel. * feat: local cache * feat: local cache * feat: local cache * feat: cache add single-flight and timing-wheel. * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * refactor: refactor the code of push and optimization. * cicd: robot automated Change * refactor: rename cache. * merge * fix: refactor project dir avoid import cycle. * update tools * merge * feat: conversation FindRecvMsgNotNotifyUserIDs * feat: conversation FindRecvMsgNotNotifyUserIDs * feat: conversation FindRecvMsgNotNotifyUserIDs * merge * merge the latest main * Exit with code 1 when the check script fails (#2023) * Optimize script logs * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Exit with code 1 when the check script fails * Execute after the component check succeeds && minio.Enable is not configured to use MinIO (#2027) * Exit with code 1 when the check script fails (#2022) * Optimize script logs * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Exit with code 1 when the check script fails * Exit with code 1 when the check script fails * Exit with code 1 when the check script fails * Exit with code 1 when the check script fails * Exit with code 1 when the check script fails * Handle the return value of pre-start * Handle the return value of pre-start * Handle the return value of pre-start * minio.Enable is not configured to use MinIO, therefore the image server is not checked * minio.Enable is not configured to use MinIO, therefore the image server is not checked * minio.Enable is not configured to use MinIO, therefore the image server is not checked * minio.Enable is not configured to use MinIO, therefore the image server is not checked * Log redirection causes incorrect program exit status. (#2031) * Exit with code 1 when the check script fails (#2022) * Optimize script logs * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Exit with code 1 when the check script fails * cicd: bump League Patch (#2025) * Execute after the component check succeeds && minio.Enable is not configured to use MinIO (#2026) * Exit with code 1 when the check script fails * Exit with code 1 when the check script fails * Exit with code 1 when the check script fails * Exit with code 1 when the check script fails * Handle the return value of pre-start * Handle the return value of pre-start * Handle the return value of pre-start * minio.Enable is not configured to use MinIO, therefore the image server is not checked * minio.Enable is not configured to use MinIO, therefore the image server is not checked * minio.Enable is not configured to use MinIO, therefore the image server is not checked * minio.Enable is not configured to use MinIO, therefore the image server is not checked * Log redirection causes incorrect program exit status. --------- Co-authored-by: OpenIM Bot <124379614+kubbot@users.noreply.github.com> * delete * add context deadline exceeded * Error not handled * Error not handled * Error not handled * Error not handled * Fix bug Remove duplicate function definitions (#2034) * Exit with code 1 when the check script fails (#2022) * Optimize script logs * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Exit with code 1 when the check script fails * delete * delete log * configGetEnv failed,err:string to int failed: strconv.Atoi: parsing "openim_v3": invalid syntaxr * Fix bug configGetEnv failed,err:string to int failed: strconv.Atoi: parsing "openim_v3": invalid syntaxr (#2045) * Error not handled (#2040) * delete * add context deadline exceeded * Error not handled * Error not handled * Error not handled * Error not handled * feat: add local cache for high frequency reads (#2036) * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * fix: mongo * fix: mongo * fix: mongo * openim.yaml * localcache * localcache * localcache * localcache * localcache * localcache * localcache * localcache * localcache * local cache * local cache * local cache * local cache * fix: GroupApplicationAcceptedNotification * fix: GroupApplicationAcceptedNotification * fix: NotificationUserInfoUpdate * feat: cache add single-flight and timing-wheel. * feat: local cache * feat: local cache * feat: local cache * feat: cache add single-flight and timing-wheel. * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * refactor: refactor the code of push and optimization. * cicd: robot automated Change * refactor: rename cache. * merge * fix: refactor project dir avoid import cycle. * update tools * merge * feat: conversation FindRecvMsgNotNotifyUserIDs * feat: conversation FindRecvMsgNotNotifyUserIDs * feat: conversation FindRecvMsgNotNotifyUserIDs * merge * merge the latest main --------- Co-authored-by: Gordon <46924906+FGadvancer@users.noreply.github.com> Co-authored-by: withchao * configGetEnv failed,err:string to int failed: strconv.Atoi: parsing "openim_v3": invalid syntaxr --------- Co-authored-by: chao <48119764+withchao@users.noreply.github.com> Co-authored-by: Gordon <46924906+FGadvancer@users.noreply.github.com> Co-authored-by: withchao * Feature: delete log for update images (#2050) * Error not handled (#2040) * delete * add context deadline exceeded * Error not handled * Error not handled * Error not handled * Error not handled * feat: add local cache for high frequency reads (#2036) * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * fix: mongo * fix: mongo * fix: mongo * openim.yaml * localcache * localcache * localcache * localcache * localcache * localcache * localcache * localcache * localcache * local cache * local cache * local cache * local cache * fix: GroupApplicationAcceptedNotification * fix: GroupApplicationAcceptedNotification * fix: NotificationUserInfoUpdate * feat: cache add single-flight and timing-wheel. * feat: local cache * feat: local cache * feat: local cache * feat: cache add single-flight and timing-wheel. * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * refactor: refactor the code of push and optimization. * cicd: robot automated Change * refactor: rename cache. * merge * fix: refactor project dir avoid import cycle. * update tools * merge * feat: conversation FindRecvMsgNotNotifyUserIDs * feat: conversation FindRecvMsgNotNotifyUserIDs * feat: conversation FindRecvMsgNotNotifyUserIDs * merge * merge the latest main --------- Co-authored-by: Gordon <46924906+FGadvancer@users.noreply.github.com> Co-authored-by: withchao * Fix bug Remove duplicate function definitions (#2033) * delete * delete log * Fix bug configGetEnv failed,err:string to int failed: strconv.Atoi: parsing "openim_v3": invalid syntaxr (#2044) * delete * add context deadline exceeded * Error not handled * Error not handled * Error not handled * Error not handled * configGetEnv failed,err:string to int failed: strconv.Atoi: parsing "openim_v3": invalid syntaxr * delete log (#2047) * delete log --------- Co-authored-by: chao <48119764+withchao@users.noreply.github.com> Co-authored-by: Gordon <46924906+FGadvancer@users.noreply.github.com> Co-authored-by: withchao * test Signed-off-by: unknown <44203734@qq.com> * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * Bug: component check (#2054) * Error not handled (#2040) * delete * add context deadline exceeded * Error not handled * Error not handled * Error not handled * Error not handled * feat: add local cache for high frequency reads (#2036) * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * fix: mongo * fix: mongo * fix: mongo * openim.yaml * localcache * localcache * localcache * localcache * localcache * localcache * localcache * localcache * localcache * local cache * local cache * local cache * local cache * fix: GroupApplicationAcceptedNotification * fix: GroupApplicationAcceptedNotification * fix: NotificationUserInfoUpdate * feat: cache add single-flight and timing-wheel. * feat: local cache * feat: local cache * feat: local cache * feat: cache add single-flight and timing-wheel. * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * refactor: refactor the code of push and optimization. * cicd: robot automated Change * refactor: rename cache. * merge * fix: refactor project dir avoid import cycle. * update tools * merge * feat: conversation FindRecvMsgNotNotifyUserIDs * feat: conversation FindRecvMsgNotNotifyUserIDs * feat: conversation FindRecvMsgNotNotifyUserIDs * merge * merge the latest main --------- Co-authored-by: Gordon <46924906+FGadvancer@users.noreply.github.com> Co-authored-by: withchao * configGetEnv failed,err:string to int failed: strconv.Atoi: parsing "openim_v3": invalid syntaxr * Fix bug Remove duplicate function definitions (#2033) * delete * delete log * Fix bug configGetEnv failed,err:string to int failed: strconv.Atoi: parsing "openim_v3": invalid syntaxr (#2044) * delete * add context deadline exceeded * Error not handled * Error not handled * Error not handled * Error not handled * configGetEnv failed,err:string to int failed: strconv.Atoi: parsing "openim_v3": invalid syntaxr * delete log (#2047) * test Signed-off-by: unknown <44203734@qq.com> * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check --------- Signed-off-by: unknown <44203734@qq.com> Co-authored-by: chao <48119764+withchao@users.noreply.github.com> Co-authored-by: Gordon <46924906+FGadvancer@users.noreply.github.com> Co-authored-by: withchao * Delete Data Conversion Tool * Delete Data Conversion Tool * Delete Data Conversion Tool * Delete Data Conversion Tool * Delete Data Conversion Tool * Delete Data Conversion Tool * Delete Data Conversion Tool * Delete Data Conversion Tool * Delete Data Conversion Tool * delete data conversion tool * delete data conversion tool * delete data conversion tool --------- Signed-off-by: unknown <44203734@qq.com> Co-authored-by: withchao <993506633@qq.com> Co-authored-by: chao <48119764+withchao@users.noreply.github.com> Co-authored-by: Gordon <46924906+FGadvancer@users.noreply.github.com> Co-authored-by: withchao Co-authored-by: OpenIM Bot <124379614+kubbot@users.noreply.github.com> * redis address port error * change go proxy --------- Signed-off-by: unknown <44203734@qq.com> Co-authored-by: chao <48119764+withchao@users.noreply.github.com> Co-authored-by: Gordon <46924906+FGadvancer@users.noreply.github.com> Co-authored-by: withchao Co-authored-by: withchao <993506633@qq.com> Co-authored-by: OpenIM Bot <124379614+kubbot@users.noreply.github.com> * Fix bug docker start log (#2066) * Error not handled (#2040) * delete * add context deadline exceeded * Error not handled * Error not handled * Error not handled * Error not handled * feat: add local cache for high frequency reads (#2036) * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * fix: mongo * fix: mongo * fix: mongo * openim.yaml * localcache * localcache * localcache * localcache * localcache * localcache * localcache * localcache * localcache * local cache * local cache * local cache * local cache * fix: GroupApplicationAcceptedNotification * fix: GroupApplicationAcceptedNotification * fix: NotificationUserInfoUpdate * feat: cache add single-flight and timing-wheel. * feat: local cache * feat: local cache * feat: local cache * feat: cache add single-flight and timing-wheel. * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * refactor: refactor the code of push and optimization. * cicd: robot automated Change * refactor: rename cache. * merge * fix: refactor project dir avoid import cycle. * update tools * merge * feat: conversation FindRecvMsgNotNotifyUserIDs * feat: conversation FindRecvMsgNotNotifyUserIDs * feat: conversation FindRecvMsgNotNotifyUserIDs * merge * merge the latest main --------- Co-authored-by: Gordon <46924906+FGadvancer@users.noreply.github.com> Co-authored-by: withchao * Fix bug Remove duplicate function definitions (#2033) * delete * delete log * Fix bug configGetEnv failed,err:string to int failed: strconv.Atoi: parsing "openim_v3": invalid syntaxr (#2044) * delete * add context deadline exceeded * Error not handled * Error not handled * Error not handled * Error not handled * configGetEnv failed,err:string to int failed: strconv.Atoi: parsing "openim_v3": invalid syntaxr * delete log (#2047) * Bug: component check (#2053) * delete * add context deadline exceeded * Error not handled * Error not handled * Error not handled * Error not handled * configGetEnv failed,err:string to int failed: strconv.Atoi: parsing "openim_v3": invalid syntaxr * test Signed-off-by: unknown <44203734@qq.com> * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check --------- Signed-off-by: unknown <44203734@qq.com> * Bug: component check (#2056) * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * fix: mongo * fix: mongo * fix: mongo * openim.yaml * localcache * localcache * localcache * localcache * localcache * localcache * localcache * localcache * localcache * local cache * local cache * local cache * local cache * fix: GroupApplicationAcceptedNotification * fix: GroupApplicationAcceptedNotification * fix: NotificationUserInfoUpdate * feat: cache add single-flight and timing-wheel. * feat: local cache * feat: local cache * feat: local cache * feat: cache add single-flight and timing-wheel. * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * refactor: refactor the code of push and optimization. * cicd: robot automated Change * refactor: rename cache. * merge * fix: refactor project dir avoid import cycle. * update tools * merge * feat: conversation FindRecvMsgNotNotifyUserIDs * feat: conversation FindRecvMsgNotNotifyUserIDs * feat: conversation FindRecvMsgNotNotifyUserIDs * merge * merge the latest main * Exit with code 1 when the check script fails (#2023) * Optimize script logs * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Exit with code 1 when the check script fails * Execute after the component check succeeds && minio.Enable is not configured to use MinIO (#2027) * Exit with code 1 when the check script fails (#2022) * Optimize script logs * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Exit with code 1 when the check script fails * Exit with code 1 when the check script fails * Exit with code 1 when the check script fails * Exit with code 1 when the check script fails * Exit with code 1 when the check script fails * Handle the return value of pre-start * Handle the return value of pre-start * Handle the return value of pre-start * minio.Enable is not configured to use MinIO, therefore the image server is not checked * minio.Enable is not configured to use MinIO, therefore the image server is not checked * minio.Enable is not configured to use MinIO, therefore the image server is not checked * minio.Enable is not configured to use MinIO, therefore the image server is not checked * Log redirection causes incorrect program exit status. (#2031) * Exit with code 1 when the check script fails (#2022) * Optimize script logs * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Exit with code 1 when the check script fails * cicd: bump League Patch (#2025) * Execute after the component check succeeds && minio.Enable is not configured to use MinIO (#2026) * Exit with code 1 when the check script fails * Exit with code 1 when the check script fails * Exit with code 1 when the check script fails * Exit with code 1 when the check script fails * Handle the return value of pre-start * Handle the return value of pre-start * Handle the return value of pre-start * minio.Enable is not configured to use MinIO, therefore the image server is not checked * minio.Enable is not configured to use MinIO, therefore the image server is not checked * minio.Enable is not configured to use MinIO, therefore the image server is not checked * minio.Enable is not configured to use MinIO, therefore the image server is not checked * Log redirection causes incorrect program exit status. --------- Co-authored-by: OpenIM Bot <124379614+kubbot@users.noreply.github.com> * delete * add context deadline exceeded * Error not handled * Error not handled * Error not handled * Error not handled * Fix bug Remove duplicate function definitions (#2034) * Exit with code 1 when the check script fails (#2022) * Optimize script logs * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Exit with code 1 when the check script fails * delete * delete log * configGetEnv failed,err:string to int failed: strconv.Atoi: parsing "openim_v3": invalid syntaxr * Fix bug configGetEnv failed,err:string to int failed: strconv.Atoi: parsing "openim_v3": invalid syntaxr (#2045) * Error not handled (#2040) * delete * add context deadline exceeded * Error not handled * Error not handled * Error not handled * Error not handled * feat: add local cache for high frequency reads (#2036) * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * fix: mongo * fix: mongo * fix: mongo * openim.yaml * localcache * localcache * localcache * localcache * localcache * localcache * localcache * localcache * localcache * local cache * local cache * local cache * local cache * fix: GroupApplicationAcceptedNotification * fix: GroupApplicationAcceptedNotification * fix: NotificationUserInfoUpdate * feat: cache add single-flight and timing-wheel. * feat: local cache * feat: local cache * feat: local cache * feat: cache add single-flight and timing-wheel. * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * refactor: refactor the code of push and optimization. * cicd: robot automated Change * refactor: rename cache. * merge * fix: refactor project dir avoid import cycle. * update tools * merge * feat: conversation FindRecvMsgNotNotifyUserIDs * feat: conversation FindRecvMsgNotNotifyUserIDs * feat: conversation FindRecvMsgNotNotifyUserIDs * merge * merge the latest main --------- Co-authored-by: Gordon <46924906+FGadvancer@users.noreply.github.com> Co-authored-by: withchao * configGetEnv failed,err:string to int failed: strconv.Atoi: parsing "openim_v3": invalid syntaxr --------- Co-authored-by: chao <48119764+withchao@users.noreply.github.com> Co-authored-by: Gordon <46924906+FGadvancer@users.noreply.github.com> Co-authored-by: withchao * Feature: delete log for update images (#2050) * Error not handled (#2040) * delete * add context deadline exceeded * Error not handled * Error not handled * Error not handled * Error not handled * feat: add local cache for high frequency reads (#2036) * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * fix: mongo * fix: mongo * fix: mongo * openim.yaml * localcache * localcache * localcache * localcache * localcache * localcache * localcache * localcache * localcache * local cache * local cache * local cache * local cache * fix: GroupApplicationAcceptedNotification * fix: GroupApplicationAcceptedNotification * fix: NotificationUserInfoUpdate * feat: cache add single-flight and timing-wheel. * feat: local cache * feat: local cache * feat: local cache * feat: cache add single-flight and timing-wheel. * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * refactor: refactor the code of push and optimization. * cicd: robot automated Change * refactor: rename cache. * merge * fix: refactor project dir avoid import cycle. * update tools * merge * feat: conversation FindRecvMsgNotNotifyUserIDs * feat: conversation FindRecvMsgNotNotifyUserIDs * feat: conversation FindRecvMsgNotNotifyUserIDs * merge * merge the latest main --------- Co-authored-by: Gordon <46924906+FGadvancer@users.noreply.github.com> Co-authored-by: withchao * Fix bug Remove duplicate function definitions (#2033) * delete * delete log * Fix bug configGetEnv failed,err:string to int failed: strconv.Atoi: parsing "openim_v3": invalid syntaxr (#2044) * delete * add context deadline exceeded * Error not handled * Error not handled * Error not handled * Error not handled * configGetEnv failed,err:string to int failed: strconv.Atoi: parsing "openim_v3": invalid syntaxr * delete log (#2047) * delete log --------- Co-authored-by: chao <48119764+withchao@users.noreply.github.com> Co-authored-by: Gordon <46924906+FGadvancer@users.noreply.github.com> Co-authored-by: withchao * test Signed-off-by: unknown <44203734@qq.com> * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check --------- Signed-off-by: unknown <44203734@qq.com> Co-authored-by: withchao <993506633@qq.com> Co-authored-by: chao <48119764+withchao@users.noreply.github.com> Co-authored-by: Gordon <46924906+FGadvancer@users.noreply.github.com> Co-authored-by: withchao Co-authored-by: OpenIM Bot <124379614+kubbot@users.noreply.github.com> * Fix bug delete data conversion (#2059) * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * fix: mongo * fix: mongo * fix: mongo * openim.yaml * localcache * localcache * localcache * localcache * localcache * localcache * localcache * localcache * localcache * local cache * local cache * local cache * local cache * fix: GroupApplicationAcceptedNotification * fix: GroupApplicationAcceptedNotification * fix: NotificationUserInfoUpdate * feat: cache add single-flight and timing-wheel. * feat: local cache * feat: local cache * feat: local cache * feat: cache add single-flight and timing-wheel. * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * refactor: refactor the code of push and optimization. * cicd: robot automated Change * refactor: rename cache. * merge * fix: refactor project dir avoid import cycle. * update tools * merge * feat: conversation FindRecvMsgNotNotifyUserIDs * feat: conversation FindRecvMsgNotNotifyUserIDs * feat: conversation FindRecvMsgNotNotifyUserIDs * merge * merge the latest main * Exit with code 1 when the check script fails (#2023) * Optimize script logs * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Exit with code 1 when the check script fails * Execute after the component check succeeds && minio.Enable is not configured to use MinIO (#2027) * Exit with code 1 when the check script fails (#2022) * Optimize script logs * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Exit with code 1 when the check script fails * Exit with code 1 when the check script fails * Exit with code 1 when the check script fails * Exit with code 1 when the check script fails * Exit with code 1 when the check script fails * Handle the return value of pre-start * Handle the return value of pre-start * Handle the return value of pre-start * minio.Enable is not configured to use MinIO, therefore the image server is not checked * minio.Enable is not configured to use MinIO, therefore the image server is not checked * minio.Enable is not configured to use MinIO, therefore the image server is not checked * minio.Enable is not configured to use MinIO, therefore the image server is not checked * Log redirection causes incorrect program exit status. (#2031) * Exit with code 1 when the check script fails (#2022) * Optimize script logs * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Exit with code 1 when the check script fails * cicd: bump League Patch (#2025) * Execute after the component check succeeds && minio.Enable is not configured to use MinIO (#2026) * Exit with code 1 when the check script fails * Exit with code 1 when the check script fails * Exit with code 1 when the check script fails * Exit with code 1 when the check script fails * Handle the return value of pre-start * Handle the return value of pre-start * Handle the return value of pre-start * minio.Enable is not configured to use MinIO, therefore the image server is not checked * minio.Enable is not configured to use MinIO, therefore the image server is not checked * minio.Enable is not configured to use MinIO, therefore the image server is not checked * minio.Enable is not configured to use MinIO, therefore the image server is not checked * Log redirection causes incorrect program exit status. --------- Co-authored-by: OpenIM Bot <124379614+kubbot@users.noreply.github.com> * delete * add context deadline exceeded * Error not handled * Error not handled * Error not handled * Error not handled * Fix bug Remove duplicate function definitions (#2034) * Exit with code 1 when the check script fails (#2022) * Optimize script logs * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Exit with code 1 when the check script fails * delete * delete log * configGetEnv failed,err:string to int failed: strconv.Atoi: parsing "openim_v3": invalid syntaxr * Fix bug configGetEnv failed,err:string to int failed: strconv.Atoi: parsing "openim_v3": invalid syntaxr (#2045) * Error not handled (#2040) * delete * add context deadline exceeded * Error not handled * Error not handled * Error not handled * Error not handled * feat: add local cache for high frequency reads (#2036) * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * fix: mongo * fix: mongo * fix: mongo * openim.yaml * localcache * localcache * localcache * localcache * localcache * localcache * localcache * localcache * localcache * local cache * local cache * local cache * local cache * fix: GroupApplicationAcceptedNotification * fix: GroupApplicationAcceptedNotification * fix: NotificationUserInfoUpdate * feat: cache add single-flight and timing-wheel. * feat: local cache * feat: local cache * feat: local cache * feat: cache add single-flight and timing-wheel. * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * refactor: refactor the code of push and optimization. * cicd: robot automated Change * refactor: rename cache. * merge * fix: refactor project dir avoid import cycle. * update tools * merge * feat: conversation FindRecvMsgNotNotifyUserIDs * feat: conversation FindRecvMsgNotNotifyUserIDs * feat: conversation FindRecvMsgNotNotifyUserIDs * merge * merge the latest main --------- Co-authored-by: Gordon <46924906+FGadvancer@users.noreply.github.com> Co-authored-by: withchao * configGetEnv failed,err:string to int failed: strconv.Atoi: parsing "openim_v3": invalid syntaxr --------- Co-authored-by: chao <48119764+withchao@users.noreply.github.com> Co-authored-by: Gordon <46924906+FGadvancer@users.noreply.github.com> Co-authored-by: withchao * Feature: delete log for update images (#2050) * Error not handled (#2040) * delete * add context deadline exceeded * Error not handled * Error not handled * Error not handled * Error not handled * feat: add local cache for high frequency reads (#2036) * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * fix: mongo * fix: mongo * fix: mongo * openim.yaml * localcache * localcache * localcache * localcache * localcache * localcache * localcache * localcache * localcache * local cache * local cache * local cache * local cache * fix: GroupApplicationAcceptedNotification * fix: GroupApplicationAcceptedNotification * fix: NotificationUserInfoUpdate * feat: cache add single-flight and timing-wheel. * feat: local cache * feat: local cache * feat: local cache * feat: cache add single-flight and timing-wheel. * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * refactor: refactor the code of push and optimization. * cicd: robot automated Change * refactor: rename cache. * merge * fix: refactor project dir avoid import cycle. * update tools * merge * feat: conversation FindRecvMsgNotNotifyUserIDs * feat: conversation FindRecvMsgNotNotifyUserIDs * feat: conversation FindRecvMsgNotNotifyUserIDs * merge * merge the latest main --------- Co-authored-by: Gordon <46924906+FGadvancer@users.noreply.github.com> Co-authored-by: withchao * Fix bug Remove duplicate function definitions (#2033) * delete * delete log * Fix bug configGetEnv failed,err:string to int failed: strconv.Atoi: parsing "openim_v3": invalid syntaxr (#2044) * delete * add context deadline exceeded * Error not handled * Error not handled * Error not handled * Error not handled * configGetEnv failed,err:string to int failed: strconv.Atoi: parsing "openim_v3": invalid syntaxr * delete log (#2047) * delete log --------- Co-authored-by: chao <48119764+withchao@users.noreply.github.com> Co-authored-by: Gordon <46924906+FGadvancer@users.noreply.github.com> Co-authored-by: withchao * test Signed-off-by: unknown <44203734@qq.com> * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * Bug: component check (#2054) * Error not handled (#2040) * delete * add context deadline exceeded * Error not handled * Error not handled * Error not handled * Error not handled * feat: add local cache for high frequency reads (#2036) * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * fix: mongo * fix: mongo * fix: mongo * openim.yaml * localcache * localcache * localcache * localcache * localcache * localcache * localcache * localcache * localcache * local cache * local cache * local cache * local cache * fix: GroupApplicationAcceptedNotification * fix: GroupApplicationAcceptedNotification * fix: NotificationUserInfoUpdate * feat: cache add single-flight and timing-wheel. * feat: local cache * feat: local cache * feat: local cache * feat: cache add single-flight and timing-wheel. * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * refactor: refactor the code of push and optimization. * cicd: robot automated Change * refactor: rename cache. * merge * fix: refactor project dir avoid import cycle. * update tools * merge * feat: conversation FindRecvMsgNotNotifyUserIDs * feat: conversation FindRecvMsgNotNotifyUserIDs * feat: conversation FindRecvMsgNotNotifyUserIDs * merge * merge the latest main --------- Co-authored-by: Gordon <46924906+FGadvancer@users.noreply.github.com> Co-authored-by: withchao * configGetEnv failed,err:string to int failed: strconv.Atoi: parsing "openim_v3": invalid syntaxr * Fix bug Remove duplicate function definitions (#2033) * delete * delete log * Fix bug configGetEnv failed,err:string to int failed: strconv.Atoi: parsing "openim_v3": invalid syntaxr (#2044) * delete * add context deadline exceeded * Error not handled * Error not handled * Error not handled * Error not handled * configGetEnv failed,err:string to int failed: strconv.Atoi: parsing "openim_v3": invalid syntaxr * delete log (#2047) * test Signed-off-by: unknown <44203734@qq.com> * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check --------- Signed-off-by: unknown <44203734@qq.com> Co-authored-by: chao <48119764+withchao@users.noreply.github.com> Co-authored-by: Gordon <46924906+FGadvancer@users.noreply.github.com> Co-authored-by: withchao * Delete Data Conversion Tool * Delete Data Conversion Tool * Delete Data Conversion Tool * Delete Data Conversion Tool * Delete Data Conversion Tool * Delete Data Conversion Tool * Delete Data Conversion Tool * Delete Data Conversion Tool * Delete Data Conversion Tool * delete data conversion tool * delete data conversion tool * delete data conversion tool --------- Signed-off-by: unknown <44203734@qq.com> Co-authored-by: withchao <993506633@qq.com> Co-authored-by: chao <48119764+withchao@users.noreply.github.com> Co-authored-by: Gordon <46924906+FGadvancer@users.noreply.github.com> Co-authored-by: withchao Co-authored-by: OpenIM Bot <124379614+kubbot@users.noreply.github.com> * Fix bug redis address (#2063) * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * fix: mongo * fix: mongo * fix: mongo * openim.yaml * localcache * localcache * localcache * localcache * localcache * localcache * localcache * localcache * localcache * local cache * local cache * local cache * local cache * fix: GroupApplicationAcceptedNotification * fix: GroupApplicationAcceptedNotification * fix: NotificationUserInfoUpdate * feat: cache add single-flight and timing-wheel. * feat: local cache * feat: local cache * feat: local cache * feat: cache add single-flight and timing-wheel. * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * refactor: refactor the code of push and optimization. * cicd: robot automated Change * refactor: rename cache. * merge * fix: refactor project dir avoid import cycle. * update tools * merge * feat: conversation FindRecvMsgNotNotifyUserIDs * feat: conversation FindRecvMsgNotNotifyUserIDs * feat: conversation FindRecvMsgNotNotifyUserIDs * merge * merge the latest main * Exit with code 1 when the check script fails (#2023) * Optimize script logs * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Exit with code 1 when the check script fails * Execute after the component check succeeds && minio.Enable is not configured to use MinIO (#2027) * Exit with code 1 when the check script fails (#2022) * Optimize script logs * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Exit with code 1 when the check script fails * Exit with code 1 when the check script fails * Exit with code 1 when the check script fails * Exit with code 1 when the check script fails * Exit with code 1 when the check script fails * Handle the return value of pre-start * Handle the return value of pre-start * Handle the return value of pre-start * minio.Enable is not configured to use MinIO, therefore the image server is not checked * minio.Enable is not configured to use MinIO, therefore the image server is not checked * minio.Enable is not configured to use MinIO, therefore the image server is not checked * minio.Enable is not configured to use MinIO, therefore the image server is not checked * Log redirection causes incorrect program exit status. (#2031) * Exit with code 1 when the check script fails (#2022) * Optimize script logs * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Exit with code 1 when the check script fails * cicd: bump League Patch (#2025) * Execute after the component check succeeds && minio.Enable is not configured to use MinIO (#2026) * Exit with code 1 when the check script fails * Exit with code 1 when the check script fails * Exit with code 1 when the check script fails * Exit with code 1 when the check script fails * Handle the return value of pre-start * Handle the return value of pre-start * Handle the return value of pre-start * minio.Enable is not configured to use MinIO, therefore the image server is not checked * minio.Enable is not configured to use MinIO, therefore the image server is not checked * minio.Enable is not configured to use MinIO, therefore the image server is not checked * minio.Enable is not configured to use MinIO, therefore the image server is not checked * Log redirection causes incorrect program exit status. --------- Co-authored-by: OpenIM Bot <124379614+kubbot@users.noreply.github.com> * delete * add context deadline exceeded * Error not handled * Error not handled * Error not handled * Error not handled * Fix bug Remove duplicate function definitions (#2034) * Exit with code 1 when the check script fails (#2022) * Optimize script logs * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Optimizing Docker Log Output Detection * Exit with code 1 when the check script fails * delete * delete log * configGetEnv failed,err:string to int failed: strconv.Atoi: parsing "openim_v3": invalid syntaxr * Fix bug configGetEnv failed,err:string to int failed: strconv.Atoi: parsing "openim_v3": invalid syntaxr (#2045) * Error not handled (#2040) * delete * add context deadline exceeded * Error not handled * Error not handled * Error not handled * Error not handled * feat: add local cache for high frequency reads (#2036) * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * fix: mongo * fix: mongo * fix: mongo * openim.yaml * localcache * localcache * localcache * localcache * localcache * localcache * localcache * localcache * localcache * local cache * local cache * local cache * local cache * fix: GroupApplicationAcceptedNotification * fix: GroupApplicationAcceptedNotification * fix: NotificationUserInfoUpdate * feat: cache add single-flight and timing-wheel. * feat: local cache * feat: local cache * feat: local cache * feat: cache add single-flight and timing-wheel. * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * refactor: refactor the code of push and optimization. * cicd: robot automated Change * refactor: rename cache. * merge * fix: refactor project dir avoid import cycle. * update tools * merge * feat: conversation FindRecvMsgNotNotifyUserIDs * feat: conversation FindRecvMsgNotNotifyUserIDs * feat: conversation FindRecvMsgNotNotifyUserIDs * merge * merge the latest main --------- Co-authored-by: Gordon <46924906+FGadvancer@users.noreply.github.com> Co-authored-by: withchao * configGetEnv failed,err:string to int failed: strconv.Atoi: parsing "openim_v3": invalid syntaxr --------- Co-authored-by: chao <48119764+withchao@users.noreply.github.com> Co-authored-by: Gordon <46924906+FGadvancer@users.noreply.github.com> Co-authored-by: withchao * Feature: delete log for update images (#2050) * Error not handled (#2040) * delete * add context deadline exceeded * Error not handled * Error not handled * Error not handled * Error not handled * feat: add local cache for high frequency reads (#2036) * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * feat: msg local cache * fix: mongo * fix: mongo * fix: mongo * openim.yaml * localcache * localcache * localcache * localcache * localcache * localcache * localcache * localcache * localcache * local cache * local cache * local cache * local cache * fix: GroupApplicationAcceptedNotification * fix: GroupApplicationAcceptedNotification * fix: NotificationUserInfoUpdate * feat: cache add single-flight and timing-wheel. * feat: local cache * feat: local cache * feat: local cache * feat: cache add single-flight and timing-wheel. * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * feat: msg rpc local cache * refactor: refactor the code of push and optimization. * cicd: robot automated Change * refactor: rename cache. * merge * fix: refactor project dir avoid import cycle. * update tools * merge * feat: conversation FindRecvMsgNotNotifyUserIDs * feat: conversation FindRecvMsgNotNotifyUserIDs * feat: conversation FindRecvMsgNotNotifyUserIDs * merge * merge the latest main --------- Co-authored-by: Gordon <46924906+FGadvancer@users.noreply.github.com> Co-authored-by: withchao * Fix bug Remove duplicate function definitions (#2033) * delete * delete log * Fix bug configGetEnv failed,err:string to int failed: strconv.Atoi: parsing "openim_v3": invalid syntaxr (#2044) * delete * add context deadline exceeded * Error not handled * Error not handled * Error not handled * Error not handled * configGetEnv failed,err:string to int failed: strconv.Atoi: parsing "openim_v3": invalid syntaxr * delete log (#2047) * delete log --------- Co-authored-by: chao <48119764+withchao@users.noreply.github.com> Co-authored-by: Gordon <46924906+FGadvancer@users.noreply.github.com> Co-authored-by: withchao * test Signed-off-by: unknown <44203734@qq.com> * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * fix bug: component check * redis address port error * change go proxy --------- Signed-off-by: unknown <44203734@qq.com> Co-authored-by: withchao <993506633@qq.com> Co-authored-by: chao <48119764+withchao@users.noreply.github.com> Co-authored-by: Gordon <46924906+FGadvancer@users.noreply.github.com> Co-authored-by: withchao Co-authored-by: OpenIM Bot <124379614+kubbot@users.noreply.github.com> * Run in the background --------- Signed-off-by: unknown <44203734@qq.com> Co-authored-by: chao <48119764+withchao@users.noreply.github.com> Co-authored-by: Gordon <46924906+FGadvancer@users.noreply.github.com> Co-authored-by: withchao Co-authored-by: withchao <993506633@qq.com> Co-authored-by: OpenIM Bot <124379614+kubbot@users.noreply.github.com> * optimization: message remove options. * fix: getConversationInfo * scripts for Mac * scripts for Mac * scripts for Mac * scripts for Mac * scripts for Mac * scripts for Mac * scripts for Mac * scripts for Mac * scripts for Mac --------- Signed-off-by: unknown <44203734@qq.com> Co-authored-by: withchao <993506633@qq.com> Co-authored-by: chao <48119764+withchao@users.noreply.github.com> Co-authored-by: Gordon <46924906+FGadvancer@users.noreply.github.com> Co-authored-by: withchao Co-authored-by: OpenIM Bot <124379614+kubbot@users.noreply.github.com> Co-authored-by: Gordon <1432970085@qq.com> Co-authored-by: Xinwei Xiong <3293172751NSS@gmail.com> --- Dockerfile | 1 + scripts/lib/util.sh | 4 ++-- tools/component/component.go | 1 + 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 514a63db4f..d4c2e26024 100644 --- a/Dockerfile +++ b/Dockerfile @@ -11,6 +11,7 @@ ENV GOPROXY=$GOPROXY # Set up the working directory WORKDIR /openim/openim-server + # Copy all files to the container ADD . . diff --git a/scripts/lib/util.sh b/scripts/lib/util.sh index 7bcfbad970..dcce56c12f 100755 --- a/scripts/lib/util.sh +++ b/scripts/lib/util.sh @@ -413,7 +413,7 @@ openim::util::check_process_names() { else # If there are PIDs, loop through each one for pid in "${pids[@]}"; do - local command=$(ps -p $pid -o cmd=) + local command=$(ps -p $pid -o comm=) local start_time=$(ps -p $pid -o lstart=) local port=$(get_port $pid) @@ -489,7 +489,7 @@ openim::util::check_process_names_for_stop() { else # If there are PIDs, loop through each one for pid in "${pids[@]}"; do - local command=$(ps -p $pid -o cmd=) + local command=$(ps -p $pid -o comm=) local start_time=$(ps -p $pid -o lstart=) local port=$(get_port $pid) diff --git a/tools/component/component.go b/tools/component/component.go index e1f86e1207..9f36d93294 100644 --- a/tools/component/component.go +++ b/tools/component/component.go @@ -30,6 +30,7 @@ import ( "github.com/OpenIMSDK/tools/component" "github.com/OpenIMSDK/tools/errs" + "gopkg.in/yaml.v3" "github.com/openimsdk/open-im-server/v3/pkg/common/config" From c50b787c5822bf658b437de0576c73ab8cb0d81f Mon Sep 17 00:00:00 2001 From: Xinwei Xiong <3293172751NSS@gmail.com> Date: Wed, 20 Mar 2024 09:25:11 +0800 Subject: [PATCH 124/188] Update env-template.yaml (#2128) --- deployments/templates/env-template.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deployments/templates/env-template.yaml b/deployments/templates/env-template.yaml index 85619b4220..b1fb8b78be 100644 --- a/deployments/templates/env-template.yaml +++ b/deployments/templates/env-template.yaml @@ -143,7 +143,7 @@ KAFKA_LATESTMSG_REDIS_TOPIC=${KAFKA_LATESTMSG_REDIS_TOPIC} # MINIO_PORT # ---------- # MINIO_PORT sets the port for the MinIO object storage service. -# Upon changing this port, the MinIO endpoint URLs in the `config/config.yaml` file must be updated +# Upon changing this port, the MinIO endpoint URLs in the config/config.yaml file must be updated # to reflect this change. The endpoints include both the 'endpoint' and 'signEndpoint' # under the MinIO configuration. # From f52a4fe7e5e64716f580f8f02a42e191dff542d4 Mon Sep 17 00:00:00 2001 From: Xinwei Xiong <3293172751NSS@gmail.com> Date: Wed, 20 Mar 2024 10:20:23 +0800 Subject: [PATCH 125/188] feat: set git cherry pick and Milestone (#2131) --- .github/workflows/bot-auto-cherry-pick.yml | 4 ++-- .github/workflows/milestone.yml | 6 ++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/.github/workflows/bot-auto-cherry-pick.yml b/.github/workflows/bot-auto-cherry-pick.yml index baafecad72..cdd7241e2c 100644 --- a/.github/workflows/bot-auto-cherry-pick.yml +++ b/.github/workflows/bot-auto-cherry-pick.yml @@ -25,6 +25,7 @@ jobs: - name: Comment cherry-pick command uses: actions/github-script@v7 with: + github-token: ${{ secrets.BOT_GITHUB_TOKEN }} script: | const pr = context.payload.pull_request; if (!pr.merged) { @@ -63,5 +64,4 @@ jobs: repo: context.repo.repo, issue_number: pr.number, body: cherryPickCmd - }); - github-token: ${{ secrets.BOT_GITHUB_TOKEN }} \ No newline at end of file + }); \ No newline at end of file diff --git a/.github/workflows/milestone.yml b/.github/workflows/milestone.yml index ecd64656af..c74e7074a7 100644 --- a/.github/workflows/milestone.yml +++ b/.github/workflows/milestone.yml @@ -41,6 +41,7 @@ jobs: steps: - uses: actions/github-script@v7 # v6 with: + github-token: ${{ secrets.BOT_GITHUB_TOKEN }} script: | if (!context.payload.pull_request.merged) { console.log('PR was not merged, skipping.'); @@ -56,9 +57,10 @@ jobs: owner: context.repo.owner, repo: context.repo.repo, state: 'open', - sort: 'due_on', - direction: 'asc' + sort: 'title', + direction: 'desc' }) + if (milestones.data.length === 0) { console.log('There are no milestones, skipping.'); return; From 8788515576232184710c710124c9d0d046342932 Mon Sep 17 00:00:00 2001 From: OpenIM Bot <124379614+kubbot@users.noreply.github.com> Date: Wed, 20 Mar 2024 10:32:00 +0800 Subject: [PATCH 126/188] cicd: bump League Patch (#2130) --- tools/component/component.go | 1 - 1 file changed, 1 deletion(-) diff --git a/tools/component/component.go b/tools/component/component.go index 9f36d93294..e1f86e1207 100644 --- a/tools/component/component.go +++ b/tools/component/component.go @@ -30,7 +30,6 @@ import ( "github.com/OpenIMSDK/tools/component" "github.com/OpenIMSDK/tools/errs" - "gopkg.in/yaml.v3" "github.com/openimsdk/open-im-server/v3/pkg/common/config" From f6ab243d2f0eea5927ebbe77bd5fb0405fa50569 Mon Sep 17 00:00:00 2001 From: Xinwei Xiong <3293172751NSS@gmail.com> Date: Wed, 20 Mar 2024 10:32:41 +0800 Subject: [PATCH 127/188] Update bot-cherry-pick.yml (#2132) --- .github/workflows/bot-cherry-pick.yml | 42 ++++++++++++++++++++++++--- 1 file changed, 38 insertions(+), 4 deletions(-) diff --git a/.github/workflows/bot-cherry-pick.yml b/.github/workflows/bot-cherry-pick.yml index e488e97de4..71597189c6 100644 --- a/.github/workflows/bot-cherry-pick.yml +++ b/.github/workflows/bot-cherry-pick.yml @@ -12,23 +12,57 @@ # See the License for the specific language governing permissions and # limitations under the License. -name: Github Rebot for Cherry Pick On Comment +name: Github Robot for Cherry Pick On Comment + on: issue_comment: types: [created] + jobs: cherry-pick: name: Cherry Pick - # && github.event.comment.user.login=='kubbot' if: github.event.issue.pull_request != '' && contains(github.event.comment.body, '/cherry-pick') runs-on: ubuntu-latest + steps: - name: Checkout the latest code uses: actions/checkout@v4 with: token: ${{ secrets.BOT_GITHUB_TOKEN }} - fetch-depth: 0 # otherwise, you will fail to push refs to dest repo + fetch-depth: 0 # To ensure all history is available for cherry-picking + - name: Automatic Cherry Pick uses: vendoo/gha-cherry-pick@v1 + with: + # Assuming the cherry-pick commit SHA is passed in the comment like '/cherry-pick sha' + commit-sha: ${{ github.event.comment.body }} + env: + GITHUB_TOKEN: ${{ secrets.BOT_GITHUB_TOKEN }} + + - name: Create a new branch for PR + run: | + PR_BRANCH="cherry-pick-${GITHUB_SHA}-to-${{ github.base_ref }}" + git checkout -b $PR_BRANCH + git push origin $PR_BRANCH + env: + GITHUB_TOKEN: ${{ secrets.BOT_GITHUB_TOKEN }} + + - name: Create Pull Request + uses: actions/github-script@v5 + with: + script: | + const prTitle = "Cherry-pick to ${{ github.base_ref }}" + const prBody = "Automated cherry-pick of ${{ github.event.comment.body }}\n\n/cc @kubbot" + const base = "${{ github.base_ref }}" + const head = "cherry-pick-${{ github.sha }}-to-${{ github.base_ref }}" + const createPr = await github.rest.pulls.create({ + owner: context.repo.owner, + repo: context.repo.repo, + title: prTitle, + body: prBody, + head: head, + base: base, + maintainer_can_modify: true, // Allows maintainers to edit the PR + }) env: - GITHUB_TOKEN: ${{ secrets.BOT_GITHUB_TOKEN }} \ No newline at end of file + GITHUB_TOKEN: ${{ secrets.BOT_GITHUB_TOKEN }} From 71f62080f3086eb2834e06f47301254f0e37fd9b Mon Sep 17 00:00:00 2001 From: Xinwei Xiong <3293172751NSS@gmail.com> Date: Mon, 25 Mar 2024 12:27:40 +0800 Subject: [PATCH 128/188] feat: Remove Go Typecheck Tools Implement GitHub Actions Based Typecheck for OpenIM (#2140) * feat: remove go typecheck tools * feat: add actions go typecheck tools * Update verify-typecheck.sh --- .github/workflows/openimci.yml | 5 +- go.work | 1 - scripts/make-rules/tools.mk | 11 ++ scripts/run-in-gopath.sh | 4 - scripts/update-generated-docs.sh | 6 +- scripts/update-yamlfmt.sh | 5 - scripts/verify-shellcheck.sh | 4 - scripts/verify-spelling.sh | 4 - scripts/verify-typecheck.sh | 13 +- scripts/verify-yamlfmt.sh | 4 - test/typecheck/README.md | 52 ----- test/typecheck/go.mod | 10 - test/typecheck/go.sum | 7 - test/typecheck/typecheck.go | 319 ------------------------------- test/typecheck/typecheck_test.go | 121 ------------ 15 files changed, 19 insertions(+), 547 deletions(-) delete mode 100644 test/typecheck/README.md delete mode 100644 test/typecheck/go.mod delete mode 100644 test/typecheck/go.sum delete mode 100644 test/typecheck/typecheck.go delete mode 100644 test/typecheck/typecheck_test.go diff --git a/.github/workflows/openimci.yml b/.github/workflows/openimci.yml index d10033a1c4..5aeddd09ae 100644 --- a/.github/workflows/openimci.yml +++ b/.github/workflows/openimci.yml @@ -57,7 +57,7 @@ jobs: steps: - name: Setup uses: actions/checkout@v4 - + - name: Set up Go ${{ matrix.go_version }} uses: actions/setup-go@v5 with: @@ -70,6 +70,9 @@ jobs: version: '3.x' # If available, use the latest major version that's compatible repo-token: ${{ secrets.GITHUB_TOKEN }} + - name: Code Typecheck Detector + uses: kubecub/typecheck@main + - name: Module Operations run: | sudo make tidy diff --git a/go.work b/go.work index 56eb874d4a..02e4154d37 100644 --- a/go.work +++ b/go.work @@ -2,7 +2,6 @@ go 1.19 use ( . - ./test/typecheck ./tools/changelog ./tools/component ./tools/formitychecker diff --git a/scripts/make-rules/tools.mk b/scripts/make-rules/tools.mk index 5d39258eae..917c18cfea 100644 --- a/scripts/make-rules/tools.mk +++ b/scripts/make-rules/tools.mk @@ -237,6 +237,17 @@ install.richgo: install.rts: @$(GO) install github.com/galeone/rts/cmd/rts@latest +# ================= kubecub openim tools ========================================= +## install.typecheck: install kubecub typecheck check for go code +.PHONY: install.typecheck +install.typecheck: + @$(GO) install github.com/kubecub/typecheck@latest + +## install.comment-lang-detector: install kubecub comment-lang-detector check for go code comment language +.PHONY: install.comment-lang-detector +install.comment-lang-detector: + @$(GO) install github.com/kubecub/comment-lang-detector/cmd/cld@latest + ## tools.help: Display help information about the tools package .PHONY: tools.help tools.help: scripts/make-rules/tools.mk diff --git a/scripts/run-in-gopath.sh b/scripts/run-in-gopath.sh index 6af9869757..6d8b7943be 100755 --- a/scripts/run-in-gopath.sh +++ b/scripts/run-in-gopath.sh @@ -20,10 +20,6 @@ # the project. # Usage: `scripts/run-in-gopath.sh `. - - - - OPENIM_ROOT=$(dirname "${BASH_SOURCE[0]}")/.. source "${OPENIM_ROOT}/scripts/lib/init.sh" diff --git a/scripts/update-generated-docs.sh b/scripts/update-generated-docs.sh index d48a4067be..4c1fbfccc6 100755 --- a/scripts/update-generated-docs.sh +++ b/scripts/update-generated-docs.sh @@ -18,10 +18,6 @@ # immediately before exporting docs. We do not want to check these documents in # by default. - - - - OPENIM_ROOT=$(dirname "${BASH_SOURCE[0]}")/.. source "${OPENIM_ROOT}/scripts/lib/init.sh" @@ -33,7 +29,7 @@ BINS=( genman genyaml ) -make -C "${OPENIM_ROOT}" WHAT="${BINS[*]}" +make -C "${OPENIM_ROOT}" BINS="${BINS[*]}" openim::util::ensure-temp-dir diff --git a/scripts/update-yamlfmt.sh b/scripts/update-yamlfmt.sh index 24ec60de91..8de0cc84c0 100755 --- a/scripts/update-yamlfmt.sh +++ b/scripts/update-yamlfmt.sh @@ -13,11 +13,6 @@ # See the License for the specific language governing permissions and # limitations under the License. - - - - - OPENIM_ROOT=$(dirname "${BASH_SOURCE[0]}")/.. source "${OPENIM_ROOT}/scripts/lib/init.sh" diff --git a/scripts/verify-shellcheck.sh b/scripts/verify-shellcheck.sh index 0c4f165bf3..3e56038dde 100755 --- a/scripts/verify-shellcheck.sh +++ b/scripts/verify-shellcheck.sh @@ -17,10 +17,6 @@ # This script lints each shell script by `shellcheck`. # Usage: `scripts/verify-shellcheck.sh`. - - - - OPENIM_ROOT=$(dirname "${BASH_SOURCE[0]}")/.. source "${OPENIM_ROOT}/scripts/lib/init.sh" diff --git a/scripts/verify-spelling.sh b/scripts/verify-spelling.sh index fa0852866d..c718c1ad15 100755 --- a/scripts/verify-spelling.sh +++ b/scripts/verify-spelling.sh @@ -17,10 +17,6 @@ # working directory by client9/misspell package. # Usage: `scripts/verify-spelling.sh`. - - - - OPENIM_ROOT=$(dirname "${BASH_SOURCE[0]}")/.. export OPENIM_ROOT source "${OPENIM_ROOT}/scripts/lib/init.sh" diff --git a/scripts/verify-typecheck.sh b/scripts/verify-typecheck.sh index c9b2aaf309..f6c14844fc 100755 --- a/scripts/verify-typecheck.sh +++ b/scripts/verify-typecheck.sh @@ -16,26 +16,19 @@ # This script does a fast type check of script srnetes code for all platforms. # Usage: `scripts/verify-typecheck.sh`. - - - - OPENIM_ROOT=$(dirname "${BASH_SOURCE[0]}")/.. source "${OPENIM_ROOT}/scripts/lib/init.sh" openim::golang::verify_go_version cd "${OPENIM_ROOT}" - -# As of June, 2020 the typecheck tool is written in terms of go/packages, but -# that library doesn't work well with multiple modules. Until that is done, -# force this tooling to run in a fake GOPATH. ret=0 TYPECHECK_SERIAL="${TYPECHECK_SERIAL:-false}" scripts/run-in-gopath.sh \ -go run test/typecheck/typecheck.go "$@" "--serial=$TYPECHECK_SERIAL" || ret=$? +make tools.verify.typecheck +${OPENIM_ROOT}/_output/tools/typecheck "$@" "--serial=$TYPECHECK_SERIAL" || ret=$? if [[ $ret -ne 0 ]]; then openim::log::error "Type Check has failed. This may cause cross platform build failures." >&2 - openim::log::error "Please see https://github.com/openimsdk/open-im-server/tree/main/test/typecheck for more information." >&2 + openim::log::error "Please see https://github.com/kubecub/typecheck for more information." >&2 exit 1 fi diff --git a/scripts/verify-yamlfmt.sh b/scripts/verify-yamlfmt.sh index 3acbf457c9..a0aa583a80 100755 --- a/scripts/verify-yamlfmt.sh +++ b/scripts/verify-yamlfmt.sh @@ -19,10 +19,6 @@ # # Usage: `scripts/verify-yamlfmt.sh`. - - - - OPENIM_ROOT=$(dirname "${BASH_SOURCE[0]}")/.. source "${OPENIM_ROOT}/scripts/lib/init.sh" diff --git a/test/typecheck/README.md b/test/typecheck/README.md deleted file mode 100644 index e5b76d4c69..0000000000 --- a/test/typecheck/README.md +++ /dev/null @@ -1,52 +0,0 @@ -# OpenIM Typecheck: Cross-Platform Source Code Type Checking for Go - -## Introduction - -OpenIM Typecheck is a robust tool designed for cross-platform source code type checking across all Go build platforms. This utility leverages Go’s built-in parsing and type-check libraries (`go/parser` and `go/types`) to deliver efficient and reliable code analysis. - -## Advantages - -- **Speed**: A complete compilation with OpenIM can take approximately 3 minutes. In contrast, OpenIM Typecheck achieves this in mere seconds, significantly enhancing productivity. -- **Resource Efficiency**: Unlike the typical requirement of over 40GB of RAM for standard processes, Typecheck operates effectively with less than 8GB of RAM. This reduction in resource consumption makes it highly suitable for a variety of systems, reducing overheads and facilitating smoother operations. - -## Implementation - -OpenIM Typecheck employs Go's native parsing and type-checking libraries (`go/parser` and `go/types`). However, it's important to note that these libraries aren't identical to those used by the Go compiler. While occasional mismatches may occur, these libraries generally provide close approximations to the compiler's functionality, offering a reliable basis for type checking. - -## Error Handling - -Typecheck's approach to error handling is pragmatic, focusing on practicality and build continuity. - -**Errors reported by `go/types` but not by `go build`**: -- **Actual Errors** (as per the specification): - - These should ideally be rectified. If rectification is not feasible, such as in cases of ongoing work or external dependencies in the code, these errors can be overlooked. - - Example: Unused variables within a closure. -- **False Positives**: - - These errors should be ignored and, where appropriate, reported upstream for resolution. - - Example: Type mismatches between staging and generated types. - -**Errors reported by `go build` but not by us**: -- CGo-related errors, including both syntax and linker issues, are outside our scope. - -## Usage - -### Locally - -To run Typecheck locally, simply use the following command: - -```bash -make verify -``` - -### Continuous Integration (CI) - -In CI environments, Typecheck can be integrated into the workflow as follows: - -```yaml -- name: Typecheck - run: make verify -``` - -This streamlined process facilitates efficient error detection and resolution, ensuring a robust and reliable build pipeline. - -More to learn about typecheck [share blog](https://nsddd.top/posts/concurrent-type-checking-and-cross-platform-development-in-go/) \ No newline at end of file diff --git a/test/typecheck/go.mod b/test/typecheck/go.mod deleted file mode 100644 index 9ef1b1da77..0000000000 --- a/test/typecheck/go.mod +++ /dev/null @@ -1,10 +0,0 @@ -module github.com/openimsdk/open-im-server/test/typecheck - -go 1.19 - -require golang.org/x/tools v0.12.0 - -require ( - golang.org/x/mod v0.12.0 // indirect - golang.org/x/sys v0.11.0 // indirect -) diff --git a/test/typecheck/go.sum b/test/typecheck/go.sum deleted file mode 100644 index 14a66101bc..0000000000 --- a/test/typecheck/go.sum +++ /dev/null @@ -1,7 +0,0 @@ -golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= -golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= -golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM= -golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/tools v0.12.0 h1:YW6HUoUmYBpwSgyaGaZq1fHjrBjX1rlpZ54T6mu2kss= -golang.org/x/tools v0.12.0/go.mod h1:Sc0INKfu04TlqNoRA1hgpFZbhYXHPr4V5DzpSBTPqQM= diff --git a/test/typecheck/typecheck.go b/test/typecheck/typecheck.go deleted file mode 100644 index 975ce988da..0000000000 --- a/test/typecheck/typecheck.go +++ /dev/null @@ -1,319 +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. - -// do a fast type check of openim code, for all platforms. -package main - -import ( - "flag" - "fmt" - "io" - "log" - "os" - "path/filepath" - "sort" - "strings" - "sync" - "time" - - "golang.org/x/tools/go/packages" -) - -var ( - verbose = flag.Bool("verbose", false, "print more information") - cross = flag.Bool("cross", true, "build for all platforms") - platforms = flag.String("platform", "", "comma-separated list of platforms to typecheck") - timings = flag.Bool("time", false, "output times taken for each phase") - defuses = flag.Bool("defuse", false, "output defs/uses") - serial = flag.Bool("serial", false, "don't type check platforms in parallel (equivalent to --parallel=1)") - parallel = flag.Int("parallel", 2, "limits how many platforms can be checked in parallel. 0 means no limit.") - skipTest = flag.Bool("skip-test", false, "don't type check test code") - tags = flag.String("tags", "", "comma-separated list of build tags to apply in addition to go's defaults") - ignoreDirs = flag.String("ignore-dirs", "", "comma-separated list of directories to ignore in addition to the default hardcoded list including staging, vendor, and hidden dirs") - - // When processed in order, windows and darwin are early to make - // interesting OS-based errors happen earlier. - crossPlatforms = []string{ - "linux/amd64", "windows/386", - "darwin/amd64", "darwin/arm64", - "linux/386", "linux/arm", - "windows/amd64", "linux/arm64", - "linux/ppc64le", "linux/s390x", - "windows/arm64", - } - - // directories we always ignore - standardIgnoreDirs = []string{ - // Staging code is symlinked from vendor/k8s.io, and uses import - // paths as if it were inside of vendor/. It fails typechecking - // inside of staging/, but works when typechecked as part of vendor/. - "staging", - "components", - "logs", - // OS-specific vendor code tends to be imported by OS-specific - // packages. We recursively typecheck imported vendored packages for - // each OS, but don't typecheck everything for every OS. - "vendor", - "test", - "_output", - "*/mw/rpc_server_interceptor.go", - // Tools we use for maintaining the code base but not necessarily - // ship as part of the release - "sopenim::golang::setup_env:tools/yamlfmt/yamlfmt.go:tools", - } -) - -func newConfig(platform string) *packages.Config { - platSplit := strings.Split(platform, "/") - goos, goarch := platSplit[0], platSplit[1] - mode := packages.NeedName | packages.NeedFiles | packages.NeedTypes | packages.NeedSyntax | packages.NeedDeps | packages.NeedImports | packages.NeedModule - if *defuses { - mode = mode | packages.NeedTypesInfo - } - env := append(os.Environ(), - "CGO_ENABLED=1", - fmt.Sprintf("GOOS=%s", goos), - fmt.Sprintf("GOARCH=%s", goarch)) - tagstr := "selinux" - if *tags != "" { - tagstr = tagstr + "," + *tags - } - flags := []string{"-tags", tagstr} - - return &packages.Config{ - Mode: mode, - Env: env, - BuildFlags: flags, - Tests: !(*skipTest), - } -} - -type collector struct { - dirs []string - ignoreDirs []string -} - -func newCollector(ignoreDirs string) collector { - c := collector{ - ignoreDirs: append([]string(nil), standardIgnoreDirs...), - } - if ignoreDirs != "" { - c.ignoreDirs = append(c.ignoreDirs, strings.Split(ignoreDirs, ",")...) - } - return c -} - -func (c *collector) walk(roots []string) error { - for _, root := range roots { - err := filepath.Walk(root, c.handlePath) - if err != nil { - return err - } - } - sort.Strings(c.dirs) - return nil -} - -// handlePath walks the filesystem recursively, collecting directories, -// ignoring some unneeded directories (hidden/vendored) that are handled -// specially later. -func (c *collector) handlePath(path string, info os.FileInfo, err error) error { - if err != nil { - return err - } - if info.IsDir() { - name := info.Name() - // Ignore hidden directories (.git, .cache, etc) - if (len(name) > 1 && (name[0] == '.' || name[0] == '_')) || name == "testdata" { - if *verbose { - fmt.Printf("DBG: skipping dir %s\n", path) - } - return filepath.SkipDir - } - for _, dir := range c.ignoreDirs { - if path == dir { - if *verbose { - fmt.Printf("DBG: ignoring dir %s\n", path) - } - return filepath.SkipDir - } - } - // Make dirs into relative pkg names. - // NOTE: can't use filepath.Join because it elides the leading "./" - pkg := path - if !strings.HasPrefix(pkg, "./") { - pkg = "./" + pkg - } - c.dirs = append(c.dirs, pkg) - if *verbose { - fmt.Printf("DBG: added dir %s\n", path) - } - } - return nil -} - -func (c *collector) verify(plat string) ([]string, error) { - errors := []packages.Error{} - start := time.Now() - config := newConfig(plat) - - rootPkgs, err := packages.Load(config, c.dirs...) - if err != nil { - return nil, err - } - - // Recursively import all deps and flatten to one list. - allMap := map[string]*packages.Package{} - for _, pkg := range rootPkgs { - if *verbose { - serialFprintf(os.Stdout, "pkg %q has %d GoFiles\n", pkg.PkgPath, len(pkg.GoFiles)) - } - allMap[pkg.PkgPath] = pkg - if len(pkg.Imports) > 0 { - for _, imp := range pkg.Imports { - if *verbose { - serialFprintf(os.Stdout, "pkg %q imports %q\n", pkg.PkgPath, imp.PkgPath) - } - allMap[imp.PkgPath] = imp - } - } - } - keys := make([]string, 0, len(allMap)) - for k := range allMap { - keys = append(keys, k) - } - sort.Strings(keys) - allList := make([]*packages.Package, 0, len(keys)) - for _, k := range keys { - allList = append(allList, allMap[k]) - } - - for _, pkg := range allList { - if len(pkg.GoFiles) > 0 { - if len(pkg.Errors) > 0 && (pkg.PkgPath == "main" || strings.Contains(pkg.PkgPath, ".")) { - errors = append(errors, pkg.Errors...) - } - } - if *defuses { - for id, obj := range pkg.TypesInfo.Defs { - serialFprintf(os.Stdout, "%s: %q defines %v\n", - pkg.Fset.Position(id.Pos()), id.Name, obj) - } - for id, obj := range pkg.TypesInfo.Uses { - serialFprintf(os.Stdout, "%s: %q uses %v\n", - pkg.Fset.Position(id.Pos()), id.Name, obj) - } - } - } - if *timings { - serialFprintf(os.Stdout, "%s took %.1fs\n", plat, time.Since(start).Seconds()) - } - return dedup(errors), nil -} - -func dedup(errors []packages.Error) []string { - ret := []string{} - - m := map[string]bool{} - for _, e := range errors { - es := e.Error() - if !m[es] { - ret = append(ret, es) - m[es] = true - } - } - return ret -} - -var outMu sync.Mutex - -func serialFprintf(w io.Writer, format string, a ...any) (n int, err error) { - outMu.Lock() - defer outMu.Unlock() - return fmt.Fprintf(w, format, a...) -} - -func main() { - flag.Parse() - args := flag.Args() - - if *verbose { - *serial = true // to avoid confusing interleaved logs - } - - if len(args) == 0 { - args = append(args, ".") - } - - c := newCollector(*ignoreDirs) - - if err := c.walk(args); err != nil { - log.Fatalf("Error walking: %v", err) - } - - plats := crossPlatforms[:] - if *platforms != "" { - plats = strings.Split(*platforms, ",") - } else if !*cross { - plats = plats[:1] - } - - var wg sync.WaitGroup - var failMu sync.Mutex - failed := false - - if *serial { - *parallel = 1 - } else if *parallel == 0 { - *parallel = len(plats) - } - throttle := make(chan int, *parallel) - - for _, plat := range plats { - wg.Add(1) - go func(plat string) { - // block until there's room for this task - throttle <- 1 - defer func() { - // indicate this task is done - <-throttle - }() - - f := false - serialFprintf(os.Stdout, "type-checking %s\n", plat) - errors, err := c.verify(plat) - if err != nil { - serialFprintf(os.Stderr, "ERROR(%s): failed to verify: %v\n", plat, err) - f = true - } else if len(errors) > 0 { - for _, e := range errors { - // Special case CGo errors which may depend on headers we - // don't have. - if !strings.HasSuffix(e, "could not import C (no metadata for C)") { - f = true - serialFprintf(os.Stderr, "ERROR(%s): %s\n", plat, e) - } - } - } - failMu.Lock() - failed = failed || f - failMu.Unlock() - wg.Done() - }(plat) - } - wg.Wait() - if failed { - os.Exit(1) - } -} diff --git a/test/typecheck/typecheck_test.go b/test/typecheck/typecheck_test.go deleted file mode 100644 index 3f6924cbdf..0000000000 --- a/test/typecheck/typecheck_test.go +++ /dev/null @@ -1,121 +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 main - -import ( - "errors" - "flag" - "os" - "path/filepath" - "testing" - - "golang.org/x/tools/go/packages" -) - -// This exists because `go` is not always in the PATH when running CI. -var goBinary = flag.String("go", "", "path to a `go` binary") - -func TestVerify(t *testing.T) { - // x/tools/packages is going to literally exec `go`, so it needs some - // setup. - setEnvVars(t) - - tcs := []struct { - path string - expect int - }{ - // {"./testdata/good", 0}, - // {"./testdata/bad", 18}, - } - - for _, tc := range tcs { - c := newCollector("") - if err := c.walk([]string{tc.path}); err != nil { - t.Fatalf("error walking %s: %v", tc.path, err) - } - - errs, err := c.verify("linux/amd64") - if err != nil { - t.Errorf("unexpected error: %v", err) - } else if len(errs) != tc.expect { - t.Errorf("Expected %d errors, got %d: %v", tc.expect, len(errs), errs) - } - } -} - -func setEnvVars(t testing.TB) { - t.Helper() - if *goBinary != "" { - newPath := filepath.Dir(*goBinary) - curPath := os.Getenv("PATH") - if curPath != "" { - newPath = newPath + ":" + curPath - } - t.Setenv("PATH", newPath) - } - if os.Getenv("HOME") == "" { - t.Setenv("HOME", "/tmp") - } -} - -func TestHandlePath(t *testing.T) { - c := collector{ - ignoreDirs: standardIgnoreDirs, - } - e := errors.New("ex") - i, _ := os.Stat(".") // i.IsDir() == true - if c.handlePath("foo", nil, e) != e { - t.Error("handlePath not returning errors") - } - if c.handlePath("vendor", i, nil) != filepath.SkipDir { - t.Error("should skip vendor") - } -} - -func TestDedup(t *testing.T) { - testcases := []struct { - input []packages.Error - expected int - }{{ - input: nil, - expected: 0, - }, { - input: []packages.Error{ - {Pos: "file:7", Msg: "message", Kind: packages.ParseError}, - }, - expected: 1, - }, { - input: []packages.Error{ - {Pos: "file:7", Msg: "message1", Kind: packages.ParseError}, - {Pos: "file:8", Msg: "message2", Kind: packages.ParseError}, - }, - expected: 2, - }, { - input: []packages.Error{ - {Pos: "file:7", Msg: "message1", Kind: packages.ParseError}, - {Pos: "file:8", Msg: "message2", Kind: packages.ParseError}, - {Pos: "file:7", Msg: "message1", Kind: packages.ParseError}, - }, - expected: 2, - }} - - for i, tc := range testcases { - out := dedup(tc.input) - if len(out) != tc.expected { - t.Errorf("[%d] dedup(%v) = '%v', expected %d", - i, tc.input, out, tc.expected) - } - } -} From 48df76fb8bc10841d4f3c9e85b830fcd46c3cd53 Mon Sep 17 00:00:00 2001 From: Xinwei Xiong <3293172751NSS@gmail.com> Date: Sun, 31 Mar 2024 12:40:35 +0800 Subject: [PATCH 129/188] docs: update openim images docs deployment aliyun (#2154) --- docs/contrib/images.md | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/docs/contrib/images.md b/docs/contrib/images.md index d1a83d6392..396ffb2e38 100644 --- a/docs/contrib/images.md +++ b/docs/contrib/images.md @@ -96,4 +96,21 @@ When pulling OpenIM's Docker images, you can choose the most suitable source bas 3. Run the `docker images` command to confirm that the image has been successfully pulled. -This concludes OpenIM's image management strategy and the steps for pulling images. If you have any questions, please feel free to ask. +### Accelerating Deployment for Users in China with Aliyun Mirror or Alternative Image Addresses + +For users in China looking to speed up the deployment process of OpenIM, leveraging a mirror image address is a highly recommended practice. After executing the `make init` command, a `.env` file is generated, which you'll need to edit to configure the image registry source. This configuration is crucial for optimizing download speeds and ensuring a smoother setup process. + +Within the generated `.env` file, you'll find a section dedicated to choosing the image address. It includes options for GitHub (`ghcr.io/openimsdk`), Docker Hub (`openim`), and Ali Cloud (`registry.cn-hangzhou.aliyuncs.com/openimsdk`). To achieve the best performance within China, it is advised to use the Aliyun image address. + +To do this, you need to comment out the current `IMAGE_REGISTRY` setting and uncomment the Aliyun option. Here is how you can adjust it for Aliyun: + +```bash +# Choose the image address: GitHub (ghcr.io/openimsdk), Docker Hub (openim), +# or Ali Cloud (registry.cn-hangzhou.aliyuncs.com/openimsdk). +# Uncomment one of the following three options. Aliyun is recommended for users in China. +# IMAGE_REGISTRY="ghcr.io/openimsdk" +# IMAGE_REGISTRY="openim" +IMAGE_REGISTRY="registry.cn-hangzhou.aliyuncs.com/openimsdk" +``` + +This change directs the deployment process to fetch the required images from the Aliyun registry, significantly improving download and installation speeds due to the geographical and network advantages within China. If, for any reason, you prefer not to use Aliyun or encounter issues, consider switching to another mirror address listed in the `.env` file by following the same uncommenting process. This flexibility ensures that users can select the most suitable image source for their specific situation, leading to a more efficient deployment of OpenIM. From 4f40022105bc6d671bb04c4831ceb961c6f02bee Mon Sep 17 00:00:00 2001 From: Xinwei Xiong <3293172751NSS@gmail.com> Date: Tue, 2 Apr 2024 11:31:25 +0800 Subject: [PATCH 130/188] feat: Enhancements to OpenIM Engineering Practices with Standardizer and Tool Versioning (#2159) * feat: add standardizer optimize makefile * feat: add standardizer optimize makefile * feat: add openim test docs * feat: add openim kafka docs * feat: add openim kafka docs * feat: add openim kafka docs --- .github/code-language-detector.yml | 1 + .github/release-drafter.yml | 2 +- .github/standardizer.yml | 50 ++++++ .github/workflows/openimci.yml | 3 + Makefile | 1 + README_zh_CN.md | 2 +- docker-compose-1.yml | 2 +- docker-compose.yml | 2 +- docs/contrib/kafka.md | 162 ++++++++++++++++++ docs/contrib/logging.md | 2 +- docs/contrib/test.md | 86 +++++++++- docs/images/Open-IM.png | Bin 17614 -> 0 bytes .../{Architecture.jpg => architecture.jpg} | Bin docs/images/{Wechat.jpg => wechat.jpg} | Bin go.work | 1 - .../{directResolver.go => direct_resolver.go} | 0 scripts/lib/golang.sh | 3 - scripts/lib/release.sh | 2 +- scripts/make-rules/common-versions.mk | 58 +++++++ scripts/make-rules/common.mk | 7 + scripts/make-rules/tools.mk | 110 +++++++----- scripts/verify-standardizer.sh | 33 ++++ .../{sendMessage.json => send-message.json} | 0 tools/formitychecker/README.md | 102 ----------- tools/formitychecker/checker/checker.go | 113 ------------ tools/formitychecker/config/config.go | 41 ----- tools/formitychecker/formitychecker.go | 41 ----- tools/formitychecker/go.mod | 3 - 28 files changed, 472 insertions(+), 355 deletions(-) create mode 100644 .github/standardizer.yml create mode 100644 docs/contrib/kafka.md delete mode 100644 docs/images/Open-IM.png rename docs/images/{Architecture.jpg => architecture.jpg} (100%) rename docs/images/{Wechat.jpg => wechat.jpg} (100%) rename pkg/common/discoveryregister/direct/{directResolver.go => direct_resolver.go} (100%) create mode 100644 scripts/make-rules/common-versions.mk create mode 100755 scripts/verify-standardizer.sh rename test/testdata/requests/{sendMessage.json => send-message.json} (100%) delete mode 100644 tools/formitychecker/README.md delete mode 100644 tools/formitychecker/checker/checker.go delete mode 100644 tools/formitychecker/config/config.go delete mode 100644 tools/formitychecker/formitychecker.go delete mode 100644 tools/formitychecker/go.mod diff --git a/.github/code-language-detector.yml b/.github/code-language-detector.yml index 32a8c1f54b..194c2474ad 100644 --- a/.github/code-language-detector.yml +++ b/.github/code-language-detector.yml @@ -12,6 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. +# https://github.com/marketplace/actions/code-language-detector directory: ./ file_types: - .go diff --git a/.github/release-drafter.yml b/.github/release-drafter.yml index 154386ff51..55ee241d7b 100644 --- a/.github/release-drafter.yml +++ b/.github/release-drafter.yml @@ -48,4 +48,4 @@ template: | ## Contributors to this $REPOSITORY release - $CONTRIBUTORS \ No newline at end of file + $CONTRIBUTORS diff --git a/.github/standardizer.yml b/.github/standardizer.yml new file mode 100644 index 0000000000..fceb69df10 --- /dev/null +++ b/.github/standardizer.yml @@ -0,0 +1,50 @@ +# https://github.com/marketplace/actions/conformity-checker-for-project +baseConfig: + searchDirectory: "./" + ignoreCase: false + +directoryNaming: + allowHyphens: true + allowUnderscores: false + mustBeLowercase: true + +fileNaming: + allowHyphens: true + allowUnderscores: true + mustBeLowercase: true + +ignoreFormats: + - "\\.log$" + - "\\.env$" + - "README\\.md$" + - "_test\\.go$" + - "\\.md$" + - _test\\.txt$ + - LICENSE + - Dockerfile + - CODEOWNERS + - Makefile + +ignoreDirectories: + - "vendor" + - ".git" + - "deployments" + - "node_modules" + - "logs" + - "CHANGELOG" + - "components" + - "_output" + - "tools/openim-web" + - "CHANGELOG" + - "examples/Test_directory" + - test/testdata + +fileTypeSpecificNaming: + ".yaml": + allowHyphens: true + allowUnderscores: false + mustBeLowercase: true + ".go": + allowHyphens: false + allowUnderscores: true + mustBeLowercase: true \ No newline at end of file diff --git a/.github/workflows/openimci.yml b/.github/workflows/openimci.yml index 5aeddd09ae..f47283997d 100644 --- a/.github/workflows/openimci.yml +++ b/.github/workflows/openimci.yml @@ -73,6 +73,9 @@ jobs: - name: Code Typecheck Detector uses: kubecub/typecheck@main + - name: Conformity Checker for Project + uses: kubecub/standardizer@main + - name: Module Operations run: | sudo make tidy diff --git a/Makefile b/Makefile index 89b9e41522..818372fb8f 100644 --- a/Makefile +++ b/Makefile @@ -19,6 +19,7 @@ VERSION_PACKAGE=github.com/openimsdk/open-im-server/v3/pkg/version # Includes include scripts/make-rules/common.mk # make sure include common.mk at the first include line +include scripts/make-rules/common-versions.mk include scripts/make-rules/golang.mk include scripts/make-rules/image.mk include scripts/make-rules/copyright.mk diff --git a/README_zh_CN.md b/README_zh_CN.md index 7eabfa509b..f42031165f 100644 --- a/README_zh_CN.md +++ b/README_zh_CN.md @@ -52,7 +52,7 @@

## 🟢 扫描微信进群交流 - + ## Ⓜ️ 关于 OpenIM diff --git a/docker-compose-1.yml b/docker-compose-1.yml index 39fc944ce2..ed852fd299 100644 --- a/docker-compose-1.yml +++ b/docker-compose-1.yml @@ -1,4 +1,4 @@ -#fixme Clone openIM Server project before using docker-compose,project address:https://github.com/OpenIMSDK/Open-IM-Server.git +#fixme Clone openIM Server project before using docker-compose,project address:https://github.com/openimsdk/open-im-server.git # The command that triggers this file to pull the image is "docker compose up -f" version: '3' diff --git a/docker-compose.yml b/docker-compose.yml index ef0714329a..a983acbaf1 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,4 +1,4 @@ -#fixme Clone openIM Server project before using docker-compose,project address:https://github.com/OpenIMSDK/Open-IM-Server.git +#fixme Clone openIM Server project before using docker-compose,project address:https://github.com/openimsdk/open-im-server.git # The command that triggers this file to pull the image is "docker compose up -d". version: '3' diff --git a/docs/contrib/kafka.md b/docs/contrib/kafka.md new file mode 100644 index 0000000000..4547c9480b --- /dev/null +++ b/docs/contrib/kafka.md @@ -0,0 +1,162 @@ +# OpenIM Kafka Guide + +This document aims to provide a set of concise guidelines to help you quickly install and use Kafka through Docker Compose. + +## Installing Kafka + +With the Docker Compose script provided by OpenIM, you can easily install Kafka. Use the following command to start Kafka: + +```bash +docker compose up -d +``` + +After executing this command, Kafka will be installed and started. You can confirm the Kafka container is running with the following command: + +```bash +docker ps | grep kafka +``` + +The output of this command, as shown below, displays the status information of the Kafka container: + +``` +be416b5a0851 bitnami/kafka:3.5.1 "/opt/bitnami/script…" 3 days ago Up 2 days 9092/tcp, 0.0.0.0:19094->9094/tcp, :::19094->9094/tcp kafka +``` + +### References + +- Official Docker installation documentation: [Click here](http://events.jianshu.io/p/b60afa35303a) +- Detailed installation guide: [Tutorial on Towards Data Science](https://towardsdatascience.com/how-to-install-apache-kafka-using-docker-the-easy-way-4ceb00817d8b) + +## Using Kafka + +### Entering the Kafka Container + +To execute Kafka commands, you first need to enter the Kafka container. Use the following command: + +```bash +docker exec -it kafka bash +``` + +### Kafka Command Tools + +Inside the Kafka container, you can use various command-line tools to manage Kafka. These tools include but are not limited to: + +- `kafka-topics.sh`: For creating, deleting, listing, or altering topics. +- `kafka-console-producer.sh`: Allows sending messages to a specified topic from the command line. +- `kafka-console-consumer.sh`: Allows reading messages from the command line, with the ability to specify topics. +- `kafka-consumer-groups.sh`: For managing consumer group information. + +### Kafka Client Tool Installation + +For easier Kafka management, you can install Kafka client tools. If you installed Kafka through OpenIM's Docker Compose, you can install the Kafka client tools with the following command: + +```bash +make install.kafkactl +``` + +### Automatic Topic Creation + +When installing Kafka through OpenIM's Docker Compose method, OpenIM automatically creates the following topics: + +- `latestMsgToRedis` +- `msgToPush` +- `offlineMsgToMongoMysql` + +These topics are created using the `scripts/create-topic.sh` script. The script waits for Kafka to be ready before executing the commands to create topics: + +```bash +# Wait for Kafka to be ready +until /opt/bitnami/kafka/bin/kafka-topics.sh --list --bootstrap-server localhost:9092; do + echo "Waiting for Kafka to be ready..." + sleep 2 +done + +# Create topics +/opt/bitnami/kafka/bin/kafka-topics.sh --create --bootstrap-server localhost:9092 --replication-factor 1 --partitions 8 --topic latestMsgToRedis +/opt/bitnami/kafka/bin/kafka-topics.sh --create --bootstrap-server localhost:9092 --replication-factor 1 --partitions 8 --topic msgToPush +/opt/bitnami/kafka/bin/kafka-topics.sh --create --bootstrap-server localhost:9092 --replication-factor 1 --partitions 8 --topic offlineMsgToMongoMysql + +echo "Topics created." +``` + +The optimized and expanded documentation further details some basic commands for operations inside the Kafka container, as well as basic commands for managing Kafka using `kafkactl`. Here is a more detailed guide. + + +## Basic Commands in the Kafka Container + +### Listing Topics + +To list all existing topics, you can use the following command: + +```bash +kafka-topics.sh --list --bootstrap-server localhost:9092 +``` + +### Creating a New Topic + +When creating a new topic, you can specify the number of partitions and the replication factor. Here is the command to create a new topic: + +```bash +kafka-topics.sh --create --bootstrap-server localhost:9092 --replication-factor 1 --partitions 1 --topic your_topic_name +``` + +### Producing Messages + +To send messages to a specific topic, you can use the producer command. The following command prompts you to enter messages, which are sent to the specified topic with each press of the Enter key: + +```bash +kafka-console-producer.sh --broker-list localhost:9092 --topic your_topic_name +``` + +### Consuming Messages + +To read messages from a specific topic, you can use the consumer command. The following command reads new messages from the specified topic and outputs them on the console: + +```bash +kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic your_topic_name --from-beginning +``` + +The ` + +--from-beginning` parameter reads messages from the beginning of the topic. If this parameter is omitted, only new messages will be read. + + +## Basic Commands Using `kafkactl` + +`kafkactl` is a command-line tool for managing and operating Kafka clusters. It offers a more modern way to interact with Kafka. + +### Listing Topics + +To list all topics, you can use: + +```bash +kafkactl get topics +``` + +### Creating a New Topic + +To create a new topic with `kafkactl`, use: + +```bash +kafkactl create topic your_topic_name --partitions 1 --replication-factor 1 +``` + +### Producing Messages + +To send messages to a topic, you can use: + +```bash +kafkactl produce your_topic_name --value "your message" +``` + +Here, `"your message"` is the content of the message you want to send. + +### Consuming Messages + +To consume messages from a topic, use: + +```bash +kafkactl consume your_topic_name --from-beginning +``` + +Again, the `--from-beginning` parameter will start consuming messages from the beginning of the topic. If you do not wish to start from the beginning, you can omit this parameter. \ No newline at end of file diff --git a/docs/contrib/logging.md b/docs/contrib/logging.md index e4774929c4..c44f6f3c74 100644 --- a/docs/contrib/logging.md +++ b/docs/contrib/logging.md @@ -2,7 +2,7 @@ ## Script Logging Documentation Link -If you wish to view the script's logging documentation, you can click on this link: [Logging Documentation](https://github.com/OpenIMSDK/Open-IM-Server/blob/main/docs/contrib/bash-log.md). +If you wish to view the script's logging documentation, you can click on this link: [Logging Documentation](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/bash-log.md). Below is the documentation for logging and error handling in the OpenIM Go project. diff --git a/docs/contrib/test.md b/docs/contrib/test.md index 37c1792cf2..2470a05373 100644 --- a/docs/contrib/test.md +++ b/docs/contrib/test.md @@ -2,14 +2,94 @@ This document serves as a comprehensive guide to understanding and utilizing the `test.sh` script for testing OpenIM RPC services. The `test.sh` script is a collection of bash functions designed to test various aspects of the OpenIM RPC services, ensuring that each part of the API is functioning as expected. -+ Scripts:https://github.com/OpenIMSDK/Open-IM-Server/tree/main/scripts/install/test.sh ++ Scripts:https://github.com/openimsdk/open-im-server/tree/main/scripts/install/test.sh -For some complex, bulky functional tests, performance tests, and various e2e tests, We are all in the current warehouse to https://github.com/OpenIMSDK/Open-IM-Server/tree/main/test or https://github.com/openim-sigs/test-infra directory In the. +For some complex, bulky functional tests, performance tests, and various e2e tests, We are all in the current warehouse to https://github.com/openimsdk/open-im-server/tree/main/test or https://github.com/openim-sigs/test-infra directory In the. + About OpenIM Feature [Test Docs](https://docs.google.com/spreadsheets/d/1zELWkwxgOOZ7u5pmYCqqaFnvZy2SVajv/edit?usp=sharing&ouid=103266350914914783293&rtpof=true&sd=true) +## Util Test -## Usage +Let's restructure and enhance the document under a unified second-level heading, adding clarity and details for better comprehension and visual appeal. + +--- + +## Development Guide + +### Comprehensive Testing Instructions + +#### Running Unit Tests + +- **Command**: To execute unit tests, input the following in your terminal: + ``` + make test + ``` + +#### Evaluating Test Coverage + +- **Overview**: It's crucial to assess how much of your code is covered by tests. +- **Command**: + ```bash + make cover + ``` + This command generates a report detailing the percentage of your code tested, ensuring adherence to quality standards. + +#### Conducting API Tests + +- **Purpose**: API tests validate the interaction and functionality of your application's interfaces. +- **How to Run**: + ``` + make test-api + ``` + Use this to check the integrity and reliability of your API endpoints. + +#### End-to-End (E2E) Testing + +- **Scope**: E2E tests simulate real-user scenarios from start to finish. +- **Execution**: + ``` + make test-e2e + ``` + This comprehensive testing ensures your application performs as expected in real-world situations. + +### Crafting Unit Test Cases + +#### Setup for Test Case Generation + +- **Installation**: Install the `gotests` tool to generate test cases automatically. + ```bash + make install.gotests + ``` + This command installs the `gotests` tool for test case generation. + +- **Environment Preparation**: Define your test template environment variable and generate test cases as shown below: + ```bash + export GOTESTS_TEMPLATE=testify + gotests -i -w -only keyFunc . + ``` + This prepares your environment for test case generation using the `testify` template. + +#### Isolating Function Tests + +- **Single Function Testing**: When you need to focus on testing a single function for detailed examination. +- **Method**: + ```bash + go test -v -run TestKeyFunc + ``` + This command specifically runs tests for `TestKeyFunc`, allowing targeted debugging and validation. + +### Important Note + +- **Quality Assurance**: Throughout your development process, it is imperative to ensure that the unit test coverage meets or surpasses the standards set by OpenIM. +- **Maintaining Standards**: Regularly running your tests with + ```make test``` + supports maintaining high code quality and adherence to OpenIM's rigorous testing benchmarks. + +## E2E Test + +TODO + +## Api Test The `test.sh` script is located within the `./scripts/install/` directory of the OpenIM service's codebase. To use the script, navigate to this directory from your terminal: diff --git a/docs/images/Open-IM.png b/docs/images/Open-IM.png deleted file mode 100644 index b617065505626ea5df9467ca5e945f851258aee6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17614 zcmZU*2RNJU8#Z3r(we3AtWs)Io1nF+)vAas6t!zhtkRa+_1d+HqLmpsu(y6z`JUss)+go)(FjT_{e8Y(Yu+#rPG|Nd}? z2>)rA3sJ)VBJg~vu5_bhfMo;!<(B<3oo6?0l*N(az_;<=@4nSA_PlX}qV3NQL8sgI z*Eepc*l4Oed*x@b6L^sT?1Zdc5yT(*<2!AGR8jR`}UXCH$s|7d79+L>gQxs zYAvx;*00l5$8AByK1!`R_3tw8d?uHC()!>jk@ad?dF>k;!ej=@GVZWj%Vpq9QSS4% z`olABmIE6X8yNF2#-j$q!Ys&|*J*7)U|lvQtET?CckjxTzW(y0p5fk|TZAD`AKa5x z@T2ei!8YtOyhFG8LnC1B>u1LJx+O8HEA}aB??~! z(}q@&vH|~X(4wDBSa{W)yZWJquI2aM{#W(~Jd~!L^|p3u7JjJk-yIhkmq>EkNBq~K zPIgZK{3TqgrRWJgv-JN;&iwR%3(`?K%<%5`kN@jxR!@2Olh`CuU|Q{~rp5o2%+;Q@ zqTfYpHJ)XBs!ki=b^(Ha$LUx4yIMBjBapXUW61meif^(LvS`+9=v)rU2J|%HH^1}W zY)nGn8{qs~iM4^Ecd@vu3wChu<-~&ZUV~@s-l$aX6OmqAB&Jz4V{n$&h{jI!OWm4SKeo1Sa@=_R^E9agY884`jGT^VQss9fwikH zR`$%l*;h)=bB$;7PXE+tbMV6pzrVX$%`OIjo0}mH`y;?rq+7SHdyK9kFAr0$^}N%n z<8R~#F5uR-whgjPfU7)12%nt=L^f{K{N(E5I_Kq#+WeGGdK1U*w{l4O01x-W$>0^{ z1#t7#vD>TuF0mqCW+~VESR2$r@O5YV#5=p5t5u%n#iR)m%ktIc3YZZF`94eVJaTB} zLg~O`VgN(%x3!caS&@z$Ci&rp9SEk-F@bLeXYp};Hi~C0*D=sn3;ug`XMK8Ed9P%i zrzrFXom2z^Yn}7THAjPv@}lyvA?#$hR{AU(8yh3TevKJq@YVB^vbaD=m|5%Y?xU)P zl2^i(fyYmMureB`_N@HRnX<>R$4`j=EULx+PBKau#of=LhIX!&+M)gIkX29T*Q=qM zvVol7gHeNPvHFJky)2#vRnd#F(hkQY;vlEP`#e_`W1lKn0e<4CitUta0S2f6F%omg zeu$n*FRYC{VE?|Vbbl~T{VeLeL-XZMa|ONS?C8^Qm}mral^5Q(JR-5COH`3 zevQjau?Kpp`TBzV#3=Z9VhUCGxhLoFF&XzU*_%B3rLxYZM016|ZFS{+Q+N^pRuG=_ z!I1-R-9KD;4gCFleNA5d6}}!LHSb&(aL5#Y`q*x@*1USVwxE|ddp6_4nfCo&8uWJM1tNBio=fSesyD({*|Az-oiqxUT*T?n@$ zC4WRqo_d^ZdxAy%iQ9Gr&v|)I90#hfm`%!yTT~} zEL<=|Vlt%I7rS4N+w`@b%#<^qvS(x)OB>=b)jMApAGJ! zlG9tsnX9=|ydI4xar_zFkd+N^amC@NBCZWN$&MpvgrnGz0@*~S8`o|BwJ-n87(*;L zv!I~rWm;rvC^t6ziJS}d-OI~#{@z}cxHmA?H|j%cxFVpi9I$Wtej*Bdj4AxN0X7%- zy=cBYWj_uKYyI3!VBnO1syFk0t7;L%(x|x5)`Jv%q42k#K0EW=Fc!21$&l<7(G{

(=B5HMGYis7g@9X2O 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 diff --git a/docs/images/Architecture.jpg b/docs/images/architecture.jpg similarity index 100% rename from docs/images/Architecture.jpg rename to docs/images/architecture.jpg diff --git a/docs/images/Wechat.jpg b/docs/images/wechat.jpg similarity index 100% rename from docs/images/Wechat.jpg rename to docs/images/wechat.jpg diff --git a/go.work b/go.work index 02e4154d37..7cc1b80a11 100644 --- a/go.work +++ b/go.work @@ -4,7 +4,6 @@ use ( . ./tools/changelog ./tools/component - ./tools/formitychecker ./tools/imctl ./tools/infra ./tools/ncpu diff --git a/pkg/common/discoveryregister/direct/directResolver.go b/pkg/common/discoveryregister/direct/direct_resolver.go similarity index 100% rename from pkg/common/discoveryregister/direct/directResolver.go rename to pkg/common/discoveryregister/direct/direct_resolver.go diff --git a/scripts/lib/golang.sh b/scripts/lib/golang.sh index 7b9d7e60c0..f9648cbdba 100755 --- a/scripts/lib/golang.sh +++ b/scripts/lib/golang.sh @@ -314,9 +314,6 @@ openim::golang::setup_platforms readonly OPENIM_CLIENT_TARGETS=( changelog component - conversion-msg - conversion-mysql - formitychecker imctl infra ncpu diff --git a/scripts/lib/release.sh b/scripts/lib/release.sh index c1fbd00a1b..05e92377d5 100755 --- a/scripts/lib/release.sh +++ b/scripts/lib/release.sh @@ -243,7 +243,7 @@ function openim::release::package_client_tarballs() { local client_bins=("${OPENIM_CLIENT_BINARIES[@]}") - # client_bins: changelog component conversion-msg conversion-mysql formitychecker imctl infra ncpu openim-web up35 versionchecker yamlfmt + # client_bins: changelog component imctl infra ncpu openim-web up35 versionchecker yamlfmt # Copy client binclient_bins:aries openim::log::info " Copy client binaries: ${client_bins[@]/#/${LOCAL_OUTPUT_BINTOOLSPATH}/${platform}/}" openim::log::info " Copy client binaries to: ${release_stage}/client/bin" diff --git a/scripts/make-rules/common-versions.mk b/scripts/make-rules/common-versions.mk new file mode 100644 index 0000000000..572585fcee --- /dev/null +++ b/scripts/make-rules/common-versions.mk @@ -0,0 +1,58 @@ +# Copyright © 2023 OpenIMSDK. +# +# 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 Makefile Versions used +# +# Define the latest version for each tool to ensure consistent versioning across installations +GOLANGCI_LINT_VERSION ?= latest +GOIMPORTS_VERSION ?= latest +ADDLICENSE_VERSION ?= latest +DEEPCOPY_GEN_VERSION ?= latest +CONVERSION_GEN_VERSION ?= latest +GINKGO_VERSION ?= v1.16.2 +GO_GITLINT_VERSION ?= latest +GO_JUNIT_REPORT_VERSION ?= latest +GOTESTS_VERSION ?= latest +SWAGGER_VERSION ?= latest +KUBE_SCORE_VERSION ?= latest +KUBECONFORM_VERSION ?= latest +GSEMVER_VERSION ?= latest +GIT_CHGLOG_VERSION ?= latest +KO_VERSION ?= latest +GITHUB_RELEASE_VERSION ?= latest +COSCLI_VERSION ?= v0.19.0-beta +MINIO_VERSION ?= latest +DELVE_VERSION ?= latest +AIR_VERSION ?= latest +GOLINES_VERSION ?= latest +GO_MOD_OUTDATED_VERSION ?= latest +CFSSL_VERSION ?= latest +DEPTH_VERSION ?= latest +GO_CALLVIS_VERSION ?= latest +MISSPELL_VERSION ?= latest +GOTHANKS_VERSION ?= latest +RICHGO_VERSION ?= latest +RTS_VERSION ?= latest +TYPECHECK_VERSION ?= latest +COMMENT_LANG_DETECTOR_VERSION ?= latest +STANDARDIZER_VERSION ?= latest +GO_TESTS_VERSION ?= v1.6.0 +GO_APIDIFF_VERSION ?= v0.8.2 +KAFKACTL_VERSION ?= latest +GOTESTSUM_VERSION ?= latest + +WIRE_VERSION ?= latest +# WIRE_VERSION ?= $(call get_go_version,github.com/google/wire) +MOCKGEN_VERSION ?= $(call get_go_version,github.com/golang/mock) +PROTOC_GEN_GO_VERSION ?= $(call get_go_version,github.com/golang/protobuf/protoc-gen-go) \ No newline at end of file diff --git a/scripts/make-rules/common.mk b/scripts/make-rules/common.mk index f8537b6cab..ffbb69a55d 100644 --- a/scripts/make-rules/common.mk +++ b/scripts/make-rules/common.mk @@ -78,6 +78,13 @@ VERSION := $(shell git describe --tags --always --match='v*') # v2.3.3: git tag endif +# Helper function to get dependency version from go.mod +get_gomod_version = $(shell go list -m $1 | awk '{print $$2}') +define go_install +$(info ===========> Installing $(1)@$(2)) +$(GO) install $(1)@$(2) +endef + # Check if the tree is dirty. default to dirty(maybe u should commit?) GIT_TREE_STATE:="dirty" ifeq (, $(shell git status --porcelain 2>/dev/null)) diff --git a/scripts/make-rules/tools.mk b/scripts/make-rules/tools.mk index 917c18cfea..5335d094d9 100644 --- a/scripts/make-rules/tools.mk +++ b/scripts/make-rules/tools.mk @@ -64,81 +64,101 @@ tools.verify.%: ## install.golangci-lint: Install golangci-lint .PHONY: install.golangci-lint install.golangci-lint: - @$(GO) install github.com/golangci/golangci-lint/cmd/golangci-lint@latest + @$(GO) install github.com/golangci/golangci-lint/cmd/golangci-lint@$(GOLANGCI_LINT_VERSION) ## install.goimports: Install goimports, used to format go source files .PHONY: install.goimports install.goimports: - @$(GO) install golang.org/x/tools/cmd/goimports@latest + @$(GO) install golang.org/x/tools/cmd/goimports@$(GOIMPORTS_VERSION) ## install.addlicense: Install addlicense, used to add license header to source files .PHONY: install.addlicense install.addlicense: - @$(GO) install github.com/google/addlicense@latest + @$(GO) install github.com/google/addlicense@$(ADDLICENSE_VERSION) ## install.deepcopy-gen: Install deepcopy-gen, used to generate deep copy functions .PHONY: install.deepcopy-gen install.deepcopy-gen: - @$(GO) install k8s.io/code-generator/cmd/deepcopy-gen@latest + @$(GO) install k8s.io/code-generator/cmd/deepcopy-gen@$(DEEPCOPY_GEN_VERSION) ## install.conversion-gen: Install conversion-gen, used to generate conversion functions .PHONY: install.conversion-gen install.conversion-gen: - @$(GO) install k8s.io/code-generator/cmd/conversion-gen@latest + @$(GO) install k8s.io/code-generator/cmd/conversion-gen@$(CONVERSION_GEN_VERSION) ## install.ginkgo: Install ginkgo to run a single test or set of tests .PHONY: install.ginkgo install.ginkgo: - @$(GO) install github.com/onsi/ginkgo/ginkgo@v1.16.2 + @$(GO) install github.com/onsi/ginkgo/ginkgo@$(GINKGO_VERSION) -## Install go-gitlint: Install go-gitlint, used to check git commit message +## install.go-gitlint: Install go-gitlint, used to check git commit message .PHONY: install.go-gitlint install.go-gitlint: - @$(GO) install github.com/marmotedu/go-gitlint/cmd/go-gitlint@latest + @$(GO) install github.com/marmotedu/go-gitlint/cmd/go-gitlint@$(GO_GITLINT_VERSION) ## install.go-junit-report: Install go-junit-report, used to convert go test output to junit xml .PHONY: install.go-junit-report install.go-junit-report: - @$(GO) install github.com/jstemmer/go-junit-report@latest + @$(GO) install github.com/jstemmer/go-junit-report@$(GO_JUNIT_REPORT_VERSION) ## install.gotests: Install gotests, used to generate go tests +.PHONY: install.gotests +install.gotests: + @$(GO) install github.com/cweill/gotests/gotests@$(GO_TESTS_VERSION) + +## install.kafkactl: Install kafkactl command line tool. +.PHONY: install.kafkactl +install.kafkactl: + @$(GO) install github.com/deviceinsight/kafkactl@$(KAFKACTL_VERSION) + +## install.go-apidiff: Install go-apidiff, used to check api changes +.PHONY: install.go-apidiff +install.go-apidiff: + @$(GO) install github.com/joelanford/go-apidiff@$(GO_APIDIFF_VERSION) + +## install.swagger: Install swagger, used to generate swagger documentation .PHONY: install.swagger install.swagger: - @$(GO) install github.com/go-swagger/go-swagger/cmd/swagger@latest + @$(GO) install github.com/go-swagger/go-swagger/cmd/swagger@$(SWAGGER_VERSION) # ============================================================================== # Tools that might be used include go gvm # +## install.gotestsum: Install gotestsum, used to run go tests +.PHONY: install.gotestsum +install.gotestsum: + @$(GO) install gotest.tools/gotestsum@$(GOTESTSUM_VERSION) + ## install.kube-score: Install kube-score, used to check kubernetes yaml files .PHONY: install.kube-score install.kube-score: - @$(GO) install github.com/zegl/kube-score/cmd/kube-score@latest + @$(GO) install github.com/zegl/kube-score/cmd/kube-score@$(KUBE_SCORE_VERSION) ## install.kubeconform: Install kubeconform, used to check kubernetes yaml files .PHONY: install.kubeconform install.kubeconform: - @$(GO) install github.com/yannh/kubeconform/cmd/kubeconform@latest + @$(GO) install github.com/yannh/kubeconform/cmd/kubeconform@$(KUBECONFORM_VERSION) ## install.gsemver: Install gsemver, used to generate semver .PHONY: install.gsemver install.gsemver: - @$(GO) install github.com/arnaud-deprez/gsemver@latest + @$(GO) install github.com/arnaud-deprez/gsemver@$(GSEMVER_VERSION) ## install.git-chglog: Install git-chglog, used to generate changelog .PHONY: install.git-chglog install.git-chglog: - @$(GO) install github.com/git-chglog/git-chglog/cmd/git-chglog@latest + @$(GO) install github.com/git-chglog/git-chglog/cmd/git-chglog@$(GIT_CHGLOG_VERSION) ## install.ko: Install ko, used to build go program into container images .PHONY: install.ko install.ko: - @$(GO) install github.com/google/ko@latest + @$(GO) install github.com/google/ko@$(KO_VERSION) ## install.github-release: Install github-release, used to create github release .PHONY: install.github-release install.github-release: - @$(GO) install github.com/github-release/github-release@latest + @$(GO) install github.com/github-release/github-release@$(GITHUB_RELEASE_VERSION) ## install.coscli: Install coscli, used to upload files to cos # example: ./coscli cp/sync -r /home/off-line/docker-off-line/ cos://openim-1306374445/openim/image/amd/off-line/off-line/ -e cos.ap-guangzhou.myqcloud.com @@ -146,7 +166,7 @@ install.github-release: # amd64 .PHONY: install.coscli install.coscli: - @wget -q https://github.com/tencentyun/coscli/releases/download/v0.19.0-beta/coscli-linux -O ${TOOLS_DIR}/coscli + @wget -q https://github.com/tencentyun/coscli/releases/download/$(COSCLI_VERSION)/coscli-linux -O ${TOOLS_DIR}/coscli @chmod +x ${TOOLS_DIR}/coscli ## install.coscmd: Install coscmd, used to upload files to cos @@ -157,50 +177,50 @@ install.coscmd: ## install.minio: Install minio, used to upload files to minio .PHONY: install.minio install.minio: - @$(GO) install github.com/minio/minio@latest + @$(GO) install github.com/minio/minio@$(MINIO_VERSION) ## install.delve: Install delve, used to debug go program .PHONY: install.delve install.delve: - @$(GO) install github.com/go-delve/delve/cmd/dlv@latest + @$(GO) install github.com/go-delve/delve/cmd/dlv@$(DELVE_VERSION) ## install.air: Install air, used to hot reload go program .PHONY: install.air install.air: - @$(GO) install github.com/cosmtrek/air@latest + @$(GO) install github.com/cosmtrek/air@$(AIR_VERSION) ## install.gvm: Install gvm, gvm is a Go version manager, built on top of the official go tool. -# github: https://github.com/moovweb/gvm .PHONY: install.gvm install.gvm: - @echo "===========> Installing gvm,The default installation path is ~/.gvm/scripts/gvm" + @echo "===========> Installing gvm, The default installation path is ~/.gvm/scripts/gvm" @bash < <(curl -s -S -L https://raw.githubusercontent.com/moovweb/gvm/master/binscripts/gvm-installer) - @$(shell source /root/.gvm/scripts/gvm) + @source /root/.gvm/scripts/gvm ## install.golines: Install golines, used to format long lines .PHONY: install.golines install.golines: - @$(GO) install github.com/segmentio/golines@latest + @$(GO) install github.com/segmentio/golines@$(GOLINES_VERSION) ## install.go-mod-outdated: Install go-mod-outdated, used to check outdated dependencies .PHONY: install.go-mod-outdated install.go-mod-outdated: - @$(GO) install github.com/psampaz/go-mod-outdated@latest + @$(GO) install github.com/psampaz/go-mod-outdated@$(GO_MOD_OUTDATED_VERSION) ## install.mockgen: Install mockgen, used to generate mock functions .PHONY: install.mockgen install.mockgen: - @$(GO) install github.com/golang/mock/mockgen@latest + @$(GO) install github.com/golang/mock/mockgen@$(MOCKGEN_VERSION) + +## install.wire: Install wire, used to generate wire files +.PHONY: install.wire +install.wire: + @$(GO) install github.com/google/wire/cmd/wire@$(WIRE_VERSION) -## install.gotests: Install gotests, used to generate test functions -.PHONY: install.gotests -install.gotests: - @$(GO) install github.com/cweill/gotests/gotests@latest ## install.protoc-gen-go: Install protoc-gen-go, used to generate go source files from protobuf files .PHONY: install.protoc-gen-go install.protoc-gen-go: - @$(GO) install github.com/golang/protobuf/protoc-gen-go@latest + @$(GO) install github.com/golang/protobuf/protoc-gen-go@$(PROTOC_GEN_GO_VERSION) ## install.cfssl: Install cfssl, used to generate certificates .PHONY: install.cfssl @@ -210,43 +230,49 @@ install.cfssl: ## install.depth: Install depth, used to check dependency tree .PHONY: install.depth install.depth: - @$(GO) install github.com/KyleBanks/depth/cmd/depth@latest + @$(GO) install github.com/KyleBanks/depth/cmd/depth@$(DEPTH_VERSION) ## install.go-callvis: Install go-callvis, used to visualize call graph .PHONY: install.go-callvis install.go-callvis: - @$(GO) install github.com/ofabry/go-callvis@latest + @$(GO) install github.com/ofabry/go-callvis@$(GO_CALLVIS_VERSION) -## install.misspell +## install.misspell: Install misspell .PHONY: install.misspell install.misspell: - @$(GO) install github.com/client9/misspell/cmd/misspell@latest + @$(GO) install github.com/client9/misspell/cmd/misspell@$(MISSPELL_VERSION) ## install.gothanks: Install gothanks, used to thank go dependencies .PHONY: install.gothanks install.gothanks: - @$(GO) install github.com/psampaz/gothanks@latest + @$(GO) install github.com/psampaz/gothanks@$(GOTHANKS_VERSION) ## install.richgo: Install richgo .PHONY: install.richgo install.richgo: - @$(GO) install github.com/kyoh86/richgo@latest + @$(GO) install github.com/kyoh86/richgo@$(RICHGO_VERSION) ## install.rts: Install rts .PHONY: install.rts install.rts: - @$(GO) install github.com/galeone/rts/cmd/rts@latest + @$(GO) install github.com/galeone/rts/cmd/rts@$(RTS_VERSION) # ================= kubecub openim tools ========================================= -## install.typecheck: install kubecub typecheck check for go code +# https://github.com/kubecub +## install.typecheck: Install kubecub typecheck, checks for go code .PHONY: install.typecheck install.typecheck: - @$(GO) install github.com/kubecub/typecheck@latest + @$(GO) install github.com/kubecub/typecheck@$(TYPECHECK_VERSION) -## install.comment-lang-detector: install kubecub comment-lang-detector check for go code comment language +## install.comment-lang-detector: Install kubecub comment-lang-detector, checks for go code comment language .PHONY: install.comment-lang-detector install.comment-lang-detector: - @$(GO) install github.com/kubecub/comment-lang-detector/cmd/cld@latest + @$(GO) install github.com/kubecub/comment-lang-detector/cmd/cld@$(COMMENT_LANG_DETECTOR_VERSION) + +## install.standardizer: Install kubecub standardizer, checks for go code standardization +.PHONY: install.standardizer +install.standardizer: + @$(GO) install github.com/kubecub/standardizer@$(STANDARDIZER_VERSION) ## tools.help: Display help information about the tools package .PHONY: tools.help diff --git a/scripts/verify-standardizer.sh b/scripts/verify-standardizer.sh new file mode 100755 index 0000000000..08a13b9a26 --- /dev/null +++ b/scripts/verify-standardizer.sh @@ -0,0 +1,33 @@ +#!/usr/bin/env bash +# 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. + +# This script does a fast type check of script srnetes code for all platforms. +# Usage: `scripts/verify-standardizer.sh`. + +OPENIM_ROOT=$(dirname "${BASH_SOURCE[0]}")/.. +source "${OPENIM_ROOT}/scripts/lib/init.sh" + +openim::golang::verify_go_version + +cd "${OPENIM_ROOT}" +ret=0 +scripts/run-in-gopath.sh \ +make tools.verify.standardizer +${OPENIM_ROOT}/_output/tools/standardizer || ret=$? +if [[ $ret -ne 0 ]]; then + openim::log::error "Failed to check the directory name or file name. Your name may not meet the specification. Please check the configuration file and the directory or file name." >&2 + openim::log::error "Please see https://github.com/kubecub/standardizer for more information." >&2 + exit 1 +fi diff --git a/test/testdata/requests/sendMessage.json b/test/testdata/requests/send-message.json similarity index 100% rename from test/testdata/requests/sendMessage.json rename to test/testdata/requests/send-message.json diff --git a/tools/formitychecker/README.md b/tools/formitychecker/README.md deleted file mode 100644 index 7cabf8a66d..0000000000 --- a/tools/formitychecker/README.md +++ /dev/null @@ -1,102 +0,0 @@ -# Development of a Go-Based Conformity Checker for Project File and Directory Naming Standards - -### 1. Project Overview - -#### Project Name - -- `GoConformityChecker` - -#### Functionality Description - -- Checks if the file and subdirectory names in a specified directory adhere to specific naming conventions. -- Supports specific file types (e.g., `.go`, `.yml`, `.yaml`, `.md`, `.sh`, etc.). -- Allows users to specify directories to be checked and directories to be ignored. -- More read https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/code-conventions.md - -#### Naming Conventions - -- Go files: Only underscores are allowed. -- YAML, YML, and Markdown files: Only hyphens are allowed. -- Directories: Only underscores are allowed. - -### 2. File Structure - -- `main.go`: Entry point of the program, handles command-line arguments. -- `checker/checker.go`: Contains the core logic. -- `config/config.go`: Parses and stores configuration information. - -### 3. Core Code Design - -#### main.go - -- Parses command-line arguments, including the directory to be checked and directories to be ignored. -- Calls the `checker` module for checking. - -#### config.go - -- Defines a configuration structure, such as directories to check and ignore. - -#### checker.go - -- Iterates through the specified directory. -- Applies different naming rules based on file types and directory names. -- Records files or directories that do not conform to the standards. - -### 4. Pseudocode Example - -#### main.go - -```go -package main - -import ( - "flag" - "fmt" - "GoConformityChecker/checker" -) - -func main() { - // Parse command-line arguments - var targetDir string - var ignoreDirs string - flag.StringVar(&targetDir, "target", ".", "Directory to check") - flag.StringVar(&ignoreDirs, "ignore", "", "Directories to ignore") - flag.Parse() - - // Call the checker - err := checker.CheckDirectory(targetDir, ignoreDirs) - if err != nil { - fmt.Println("Error:", err) - } -} -``` - -#### checker.go - -```go -package checker - -import ( - // Import necessary packages -) - -func CheckDirectory(targetDir, ignoreDirs string) error { - // Iterate through the directory, applying rules to check file and directory names - // Return any found errors or non-conformities - return nil -} -``` - -### 5. Implementation Details - -- **File and Directory Traversal**: Use Go's `path/filepath` package to traverse directories and subdirectories. -- **Naming Rules Checking**: Apply different regex expressions for naming checks based on file extensions. -- **Error Handling and Reporting**: Record files or directories that do not conform and report to the user. - -### 6. Future Development and Extensions - -- Support more file types and naming rules. -- Provide more detailed error reports, such as showing line numbers and specific naming mistakes. -- Add a graphical or web interface for non-command-line users. - -The above is an overview of the entire project's design. Following this design, specific coding implementation can begin. Note that the actual implementation may need adjustments based on real-world conditions. \ No newline at end of file diff --git a/tools/formitychecker/checker/checker.go b/tools/formitychecker/checker/checker.go deleted file mode 100644 index b17cc5427c..0000000000 --- a/tools/formitychecker/checker/checker.go +++ /dev/null @@ -1,113 +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 checker - -import ( - "fmt" - "os" - "path/filepath" - "regexp" - "strings" - - "github.com/OpenIMSDK/tools/errs" - - "github.com/openimsdk/open-im-server/tools/formitychecker/config" -) - -var ( - underscoreRegex = regexp.MustCompile(`^[a-zA-Z0-9_]+\.[a-zA-Z0-9]+$`) - hyphenRegex = regexp.MustCompile(`^[a-zA-Z0-9\-]+\.[a-zA-Z0-9]+$`) -) - -// CheckDirectory initiates the checking process for the specified directories using configuration from config.Config. -func CheckDirectory(cfg *config.Config) error { - ignoreMap := make(map[string]struct{}) - for _, dir := range cfg.IgnoreDirs { - ignoreMap[dir] = struct{}{} - } - - for _, targetDir := range cfg.TargetDirs { - err := filepath.Walk(targetDir, func(path string, info os.FileInfo, err error) error { - if err != nil { - return errs.Wrap(err, fmt.Sprintf("error walking directory '%s'", targetDir)) - } - - // Skip if the directory is in the ignore list - dirName := filepath.Base(filepath.Dir(path)) - if _, ok := ignoreMap[dirName]; ok && info.IsDir() { - return filepath.SkipDir - } - - // Check the naming convention - if err := checkNamingConvention(path, info); err != nil { - fmt.Println(err) - } - - return nil - }) - - if err != nil { - return fmt.Errorf("error checking directory '%s': %w", targetDir, err) - } - } - - return nil -} - -// checkNamingConvention checks if the file or directory name conforms to the standard naming conventions. -func checkNamingConvention(path string, info os.FileInfo) error { - fileName := info.Name() - - // Handle special cases for directories like .git - if info.IsDir() && strings.HasPrefix(fileName, ".") { - return nil // Skip special directories - } - - // Extract the main part of the name (without extension for files) - mainName := fileName - if !info.IsDir() { - mainName = strings.TrimSuffix(fileName, filepath.Ext(fileName)) - } - - // Determine the type of file and apply corresponding naming rule - switch { - case info.IsDir(): - if !isValidName(mainName, "_") { // Directory names must only contain underscores - return fmt.Errorf("!!! invalid directory name: %s", path) - } - case strings.HasSuffix(fileName, ".go"): - if !isValidName(mainName, "_") { // Go files must only contain underscores - return fmt.Errorf("!!! invalid Go file name: %s", path) - } - case strings.HasSuffix(fileName, ".yml"), strings.HasSuffix(fileName, ".yaml"), strings.HasSuffix(fileName, ".md"): - if !isValidName(mainName, "-") { // YML, YAML, and Markdown files must only contain hyphens - return fmt.Errorf("!!! invalid file name: %s", path) - } - } - - return nil -} - -// isValidName checks if the file name conforms to the specified rule (underscore or hyphen). -func isValidName(name, charType string) bool { - switch charType { - case "_": - return underscoreRegex.MatchString(name) - case "-": - return hyphenRegex.MatchString(name) - default: - return false - } -} diff --git a/tools/formitychecker/config/config.go b/tools/formitychecker/config/config.go deleted file mode 100644 index 0c4f6a16b8..0000000000 --- a/tools/formitychecker/config/config.go +++ /dev/null @@ -1,41 +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 config - -import ( - "strings" -) - -// Config holds all the configuration parameters for the checker. -type Config struct { - TargetDirs []string // Directories to check - IgnoreDirs []string // Directories to ignore -} - -// NewConfig creates and returns a new Config instance. -func NewConfig(targetDirs, ignoreDirs string) *Config { - return &Config{ - TargetDirs: parseDirs(targetDirs), - IgnoreDirs: parseDirs(ignoreDirs), - } -} - -// parseDirs splits a comma-separated string into a slice of directory names. -func parseDirs(dirs string) []string { - if dirs == "" { - return nil - } - return strings.Split(dirs, ",") -} diff --git a/tools/formitychecker/formitychecker.go b/tools/formitychecker/formitychecker.go deleted file mode 100644 index 2bedbfb32d..0000000000 --- a/tools/formitychecker/formitychecker.go +++ /dev/null @@ -1,41 +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 main - -import ( - "flag" - "fmt" - - "github.com/openimsdk/open-im-server/tools/formitychecker/checker" - "github.com/openimsdk/open-im-server/tools/formitychecker/config" -) - -func main() { - defaultTargetDirs := "." - defaultIgnoreDirs := "components,.git" - - var targetDirs string - var ignoreDirs string - flag.StringVar(&targetDirs, "target", defaultTargetDirs, "Directories to check (default: current directory)") - flag.StringVar(&ignoreDirs, "ignore", defaultIgnoreDirs, "Directories to ignore (default: A/, B/)") - flag.Parse() - - conf := config.NewConfig(targetDirs, ignoreDirs) - - err := checker.CheckDirectory(conf) - if err != nil { - fmt.Println("Error:", err) - } -} diff --git a/tools/formitychecker/go.mod b/tools/formitychecker/go.mod deleted file mode 100644 index 698b776475..0000000000 --- a/tools/formitychecker/go.mod +++ /dev/null @@ -1,3 +0,0 @@ -module github.com/openimsdk/open-im-server/tools/formitychecker - -go 1.19 From cca5336a8a78698f7c75df3b8e42349f38e15564 Mon Sep 17 00:00:00 2001 From: Xinwei Xiong <3293172751NSS@gmail.com> Date: Tue, 16 Apr 2024 00:05:30 +0800 Subject: [PATCH 131/188] feat: optimize go version auto set (#2182) --- scripts/make-rules/golang.mk | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/make-rules/golang.mk b/scripts/make-rules/golang.mk index 5a5d1a7885..d6de8e3465 100644 --- a/scripts/make-rules/golang.mk +++ b/scripts/make-rules/golang.mk @@ -17,7 +17,7 @@ # GO := go -GO_SUPPORTED_VERSIONS ?= 1.19|1.20|1.21|1.22|1.23 +GO_MINIMUM_VERSION ?= 1.19 GO_LDFLAGS += -X $(VERSION_PACKAGE).gitVersion=$(GIT_TAG) \ -X $(VERSION_PACKAGE).gitCommit=$(GIT_COMMIT) \ @@ -132,8 +132,8 @@ go.versionchecker: ## go.build.verify: Verify that a suitable version of Go exists .PHONY: go.build.verify go.build.verify: -ifneq ($(shell $(GO) version | grep -q -E '\bgo($(GO_SUPPORTED_VERSIONS))\b' && echo 0 || echo 1), 0) - $(error unsupported go version. Please make install one of the following supported version: '$(GO_SUPPORTED_VERSIONS)') +ifneq ($(shell $(GO) version|awk -v min=$(GO_MINIMUM_VERSION) '{gsub(/go/,"",$$3);if($$3 >= min){print 0}else{print 1}}'), 0) + $(error unsupported go version. Please install a go version which is greater than or equal to '$(GO_MINIMUM_VERSION)') endif ## go.build.%: Build binaries for a specific platform From b76816bc142d0a43eaf2525725f9b72959d6e0a4 Mon Sep 17 00:00:00 2001 From: OpenIM-Gordon <46924906+FGadvancer@users.noreply.github.com> Date: Fri, 19 Apr 2024 22:23:08 +0800 Subject: [PATCH 132/188] refactor: 3.7.0 code conventions. (#2148) * Script Refactoring * Script Refactoring * Script Refactoring * Script Refactoring * Script Refactoring * Script Refactoring * Script Refactoring * Script Refactoring * Script Refactoring * Script Refactoring * Script Refactoring * Script Refactoring * feat: add code lint * feat: add code lint * Script Refactoring * Script Refactoring * Script Refactoring * Script Refactoring * Script Refactoring * Script Refactoring * Script Refactoring * Script Refactoring * Script Refactoring * Script Refactoring * Script Refactoring * Script Refactoring * Script Refactoring * Script Refactoring * Script Refactoring * Script Refactoring * Script Refactoring * feat: code format * Script Refactoring * Script Refactoring * Script Refactoring * Adjust MinIO configuration settings * Adjust configuration settings * Adjust configuration settings * refactor: config change. * refactor: webhooks update. * Adjust configuration settings * refactor: webhooks update. * Adjust configuration settings * Adjust configuration settings * Adjust configuration settings * feat: s3 api addr * refactor: webhooks update. * Adjust configuration settings * Adjust configuration settings * Adjust configuration settings * Adjust configuration settings * Adjust configuration settings * Adjust configuration settings * Adjust configuration settings * refactor: webhooks update. * refactor: kafka update. * Simplify the Docker Compose configuration, remove unnecessary environment variables, and eliminate the gateway service. * refactor: kafka update. * refactor: kafka update. * Simplify the Docker Compose configuration, remove unnecessary environment variables, and eliminate the gateway service. * Simplify the Docker Compose configuration, remove unnecessary environment variables, and eliminate the gateway service. * Windows can compile and run. * Windows can compile and run. * refactor: kafka update. * feat: msg cache split * refactor: webhooks update * refactor: webhooks update * refactor: friends update * refactor: group update * refactor: third update * refactor: api update * refactor: crontab update * refactor: msggateway update * mage * mage * refactor: all module update. * check * refactor: all module update. * load config * load config * load config * load config * refactor: all module update. * refactor: all module update. * refactor: all module update. * refactor: all module update. * refactor: all module update. * Optimize Docker configuration and script. * refactor: all module update. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * refactor: all module update. * Optimize Docker configuration and script. * refactor: all module update. * refactor: all module update. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * update tools * update tools * Optimize Docker configuration and script. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * update protocol * Optimize Docker configuration and script. * Optimize Docker configuration and script. * refactor: all module update. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * refactor: api remove token auth by redis directly. * Code Refactoring * refactor: websocket auth change to call rpc of auth. * refactor: kick online user and remove token change to call auth rpc. * refactor: kick online user and remove token change to call auth rpc. * refactor: remove msggateway redis. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor webhook * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor webhook * refactor: cmd update. * refactor: cmd update. * fix: runtime: goroutine stack exceeds * refactor: cmd update. * refactor notification * refactor notification * refactor * refactor: cmd update. * refactor: cmd update. * refactor * refactor * refactor * protojson * protojson * protojson * go mod * wrapperspb * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: context update. * refactor: websocket update info. * refactor: websocket update info. * refactor: websocket update info. * refactor: websocket update info. * refactor: api name change. * refactor: debug info. * refactor: debug info. * refactor: debug info. * fix: update file * refactor * refactor * refactor: debug info. * refactor: debug info. * refactor: debug info. * refactor: debug info. * refactor: debug info. * refactor: debug info. * fix: callback update. * fix: callback update. * refactor * fix: update message. * fix: msg cache timeout. * refactor * refactor * fix: push update. * fix: push update. * fix: push update. * fix: push update. * fix: push update. * fix: push update. * fix: push update. * fix: websocket handle error remove when upgrade error. --------- Co-authored-by: skiffer-git <44203734@qq.com> Co-authored-by: Xinwei Xiong (cubxxw) <3293172751nss@gmail.com> Co-authored-by: withchao <993506633@qq.com> --- .env | 13 + .github/workflows/pull-request.yml | 7 +- .gitignore | 1 - .golangci.yml | 242 +-- Dockerfile | 1 - Makefile | 256 --- bootstrap.bat | 31 + bootstrap.sh | 23 + build/images/openim-api/Dockerfile | 1 - build/images/openim-cmdutils/Dockerfile | 1 - build/images/openim-crontask/Dockerfile | 1 - build/images/openim-msggateway/Dockerfile | 1 - build/images/openim-msgtransfer/Dockerfile | 1 - build/images/openim-push/Dockerfile | 1 - build/images/openim-rpc-auth/Dockerfile | 1 - .../images/openim-rpc-conversation/Dockerfile | 1 - build/images/openim-rpc-friend/Dockerfile | 1 - build/images/openim-rpc-group/Dockerfile | 1 - build/images/openim-rpc-msg/Dockerfile | 1 - build/images/openim-rpc-third/Dockerfile | 1 - build/images/openim-rpc-user/Dockerfile | 1 - .../images/openim-tools/component/Dockerfile | 1 - .../images/openim-tools/openim-web/Dockerfile | 57 - cmd/openim-api/main.go | 10 +- cmd/openim-cmdutils/main.go | 10 +- cmd/openim-crontask/main.go | 7 +- cmd/openim-msggateway/main.go | 10 +- cmd/openim-msgtransfer/main.go | 9 +- cmd/openim-push/main.go | 10 +- cmd/openim-rpc/openim-rpc-auth/main.go | 10 +- .../openim-rpc-conversation/main.go | 10 +- cmd/openim-rpc/openim-rpc-friend/main.go | 10 +- cmd/openim-rpc/openim-rpc-group/main.go | 10 +- cmd/openim-rpc/openim-rpc-msg/main.go | 10 +- cmd/openim-rpc/openim-rpc-third/main.go | 10 +- cmd/openim-rpc/openim-rpc-user/main.go | 10 +- config/README_zh_CN.md | 65 + config/Readme.md | 243 --- config/kafka.yml | 18 + config/local-cache.yml | 27 + config/log.yml | 13 + config/minio.yml | 9 + config/mongodb.yml | 7 + config/notification.yml | 354 ++++ config/openim-api.yml | 13 + config/openim-crontask.yml | 4 + config/openim-msggateway.yml | 19 + config/openim-msgtransfer.yml | 3 + config/openim-push.yml | 37 + config/openim-rpc-auth.yml | 13 + config/openim-rpc-conversation.yml | 11 + config/openim-rpc-friend.yml | 8 + config/openim-rpc-group.yml | 9 + config/openim-rpc-msg.yml | 14 + config/openim-rpc-third.yml | 40 + config/openim-rpc-user.yml | 17 + config/redis.yml | 7 + config/share.yml | 15 + config/templates/config.yaml.template | 76 +- config/templates/env.template | 8 +- config/templates/open-im-ng-example.conf | 1 + config/templates/prometheus-dashboard.yaml | 2 +- config/webhooks.yml | 156 ++ config/zookeeper.yml | 6 + .../openim-api/templates/deployment.yaml | 6 +- .../charts/openim-api/templates/service.yaml | 4 +- .../templates/deployment.yaml | 6 +- .../openim-msggateway/templates/service.yaml | 4 +- .../templates/deployment.yaml | 6 +- .../openim-msgtransfer/templates/service.yaml | 4 +- .../openim-push/templates/deployment.yaml | 6 +- .../charts/openim-push/templates/service.yaml | 4 +- .../openim-rpc-auth/templates/deployment.yaml | 6 +- .../openim-rpc-auth/templates/service.yaml | 4 +- .../templates/deployment.yaml | 6 +- .../templates/service.yaml | 4 +- .../templates/deployment.yaml | 6 +- .../openim-rpc-friend/templates/service.yaml | 4 +- .../templates/deployment.yaml | 6 +- .../openim-rpc-group/templates/service.yaml | 4 +- .../openim-rpc-msg/templates/deployment.yaml | 6 +- .../openim-rpc-msg/templates/service.yaml | 4 +- .../templates/deployment.yaml | 6 +- .../openim-rpc-third/templates/service.yaml | 4 +- .../openim-rpc-user/templates/deployment.yaml | 6 +- .../openim-rpc-user/templates/service.yaml | 4 +- deployments/templates/config.yaml | 2 +- docker-compose-1.yml | 298 ---- docker-compose.yml | 276 +-- docs/contrib/go-code.md | 113 +- docs/contrib/go-code1.md | 1554 +++++++++++++++++ docs/contrib/go-doc.md | 50 + docs/contrib/logging.md | 135 +- go.mod | 95 +- go.sum | 205 ++- go.work | 14 - internal/api/auth.go | 4 +- internal/api/conversation.go | 4 +- internal/api/custom_validator.go | 4 +- internal/api/friend.go | 4 +- internal/api/group.go | 16 +- internal/api/init.go | 118 ++ internal/api/msg.go | 79 +- internal/api/{route.go => router.go} | 210 +-- internal/api/statistics.go | 4 +- internal/api/third.go | 58 +- internal/api/user.go | 18 +- internal/msggateway/callback.go | 128 +- internal/msggateway/client.go | 50 +- internal/msggateway/compressor.go | 23 +- internal/msggateway/constant.go | 2 +- internal/msggateway/context.go | 57 +- internal/msggateway/encoder.go | 12 +- internal/msggateway/http_error.go | 6 +- internal/msggateway/hub_server.go | 63 +- internal/msggateway/init.go | 41 +- internal/msggateway/long_conn.go | 55 +- internal/msggateway/message_handler.go | 78 +- internal/msggateway/n_ws_server.go | 299 ++-- internal/msggateway/user_map.go | 19 +- internal/msgtransfer/init.go | 92 +- .../msgtransfer/online_history_msg_handler.go | 83 +- .../online_msg_to_mongo_handler.go | 39 +- internal/push/callback.go | 207 ++- internal/push/consumer_init.go | 41 - internal/push/offlinepush/dummy/push.go | 5 +- internal/push/offlinepush/fcm/push.go | 24 +- internal/push/offlinepush/getui/body.go | 6 +- internal/push/offlinepush/getui/push.go | 43 +- .../push/offlinepush/jpush/body/audience.go | 4 +- .../offlinepush/jpush/body/notification.go | 4 +- .../push/offlinepush/jpush/body/platform.go | 10 +- internal/push/offlinepush/jpush/push.go | 25 +- .../push/offlinepush/offlinepush_interface.go | 37 - internal/push/offlinepush/offlinepusher.go | 52 + internal/push/offlinepush/options/options.go | 14 + internal/push/onlinepusher.go | 204 +++ internal/push/push.go | 71 + internal/push/push_handler.go | 342 +++- internal/push/push_rpc_server.go | 107 -- internal/push/push_to_client.go | 522 ------ internal/push/tools.go | 31 - internal/rpc/auth/auth.go | 98 +- internal/rpc/conversation/conversaion.go | 128 +- .../rpc/conversation/notification.go | 22 +- internal/rpc/friend/black.go | 15 +- internal/rpc/friend/callback.go | 234 ++- internal/rpc/friend/friend.go | 173 +- .../rpc/friend/notification.go | 73 +- internal/rpc/group/cache.go | 20 +- internal/rpc/group/callback.go | 517 +++--- internal/rpc/group/convert.go | 7 +- internal/rpc/group/db_map.go | 6 +- internal/rpc/group/fill.go | 2 +- internal/rpc/group/group.go | 678 +++---- .../rpc/group/notification.go | 439 ++--- internal/rpc/group/statistics.go | 6 +- internal/rpc/group/super_group.go | 30 - internal/rpc/msg/as_read.go | 127 +- internal/rpc/msg/callback.go | 197 +-- internal/rpc/msg/delete.go | 76 +- internal/rpc/msg/message_interceptor.go | 43 - internal/rpc/msg/msg_status.go | 16 +- .../rpc/msg/notification.go | 19 +- internal/rpc/msg/revoke.go | 66 +- internal/rpc/msg/send.go | 105 +- internal/rpc/msg/seq.go | 7 +- internal/rpc/msg/server.go | 116 +- internal/rpc/msg/statistics.go | 31 +- internal/rpc/msg/sync_msg.go | 31 +- internal/rpc/msg/utils.go | 25 +- internal/rpc/msg/verify.go | 90 +- internal/rpc/third/log.go | 34 +- internal/rpc/third/s3.go | 50 +- internal/rpc/third/third.go | 81 +- internal/rpc/third/tool.go | 27 +- internal/rpc/user/callback.go | 145 +- .../rpc/user/notification.go | 36 +- internal/rpc/user/statistics.go | 17 +- internal/rpc/user/user.go | 262 ++- internal/tools/conversation.go | 19 +- internal/tools/cron_task.go | 46 +- internal/tools/cron_task_test.go | 153 +- internal/tools/msg.go | 156 +- internal/tools/msg_doc_convert.go | 6 +- magefile.go | 43 + magefile_unix.go | 20 + magefile_windows.go | 8 + pkg/apistruct/doc.go | 2 +- pkg/apistruct/manage.go | 2 +- pkg/apistruct/msg.go | 3 + pkg/authverify/doc.go | 2 +- pkg/authverify/token.go | 62 +- pkg/callbackstruct/common.go | 7 +- pkg/callbackstruct/constant.go | 57 +- pkg/callbackstruct/doc.go | 2 +- pkg/callbackstruct/group.go | 2 +- pkg/callbackstruct/message.go | 2 +- pkg/callbackstruct/push.go | 2 +- pkg/callbackstruct/revoke.go | 1 + pkg/callbackstruct/user.go | 5 +- pkg/common/cachekey/doc.go | 15 + pkg/common/cachekey/token.go | 11 + pkg/common/cmd/api.go | 45 +- pkg/common/cmd/auth.go | 59 + pkg/common/cmd/constant.go | 86 +- pkg/common/cmd/conversation.go | 61 + pkg/common/cmd/cron_task.go | 39 +- pkg/common/cmd/doc.go | 2 +- pkg/common/cmd/friend.go | 62 + pkg/common/cmd/group.go | 62 + pkg/common/cmd/msg.go | 63 + pkg/common/cmd/msg_gateway.go | 60 +- pkg/common/cmd/msg_gateway_test.go | 46 +- pkg/common/cmd/msg_transfer.go | 57 +- pkg/common/cmd/msg_utils.go | 18 +- pkg/common/cmd/push.go | 63 + pkg/common/cmd/root.go | 175 +- pkg/common/cmd/rpc.go | 156 -- pkg/common/cmd/third.go | 62 + pkg/common/cmd/user.go | 63 + pkg/common/config/config.go | 852 +++++---- pkg/common/config/constant.go | 37 + pkg/common/config/doc.go | 2 +- pkg/common/config/load_config.go | 27 + pkg/common/config/load_config_test.go | 36 + pkg/common/config/parse.go | 70 +- pkg/common/config/parse_test.go | 131 -- pkg/common/config/version | 2 +- pkg/common/convert/black.go | 4 +- pkg/common/convert/conversation.go | 12 +- pkg/common/convert/doc.go | 2 +- pkg/common/convert/friend.go | 18 +- pkg/common/convert/group.go | 19 +- pkg/common/convert/msg.go | 14 +- pkg/common/convert/user.go | 2 +- pkg/common/convert/user_test.go | 2 +- pkg/common/db/cache/black.go | 6 +- pkg/common/db/cache/config.go | 21 +- pkg/common/db/cache/conversation.go | 81 +- pkg/common/db/cache/doc.go | 2 +- pkg/common/db/cache/friend.go | 16 +- pkg/common/db/cache/group.go | 30 +- pkg/common/db/cache/init_redis.go | 107 -- pkg/common/db/cache/meta_cache.go | 25 +- pkg/common/db/cache/msg.go | 555 ++---- pkg/common/db/cache/msg_test.go | 2 +- pkg/common/db/cache/s3.go | 32 +- pkg/common/db/cache/seq.go | 182 ++ pkg/common/db/cache/third.go | 85 + pkg/common/db/cache/token.go | 56 + pkg/common/db/cache/user.go | 25 +- pkg/common/db/controller/auth.go | 24 +- pkg/common/db/controller/black.go | 8 +- pkg/common/db/controller/conversation.go | 37 +- pkg/common/db/controller/doc.go | 2 +- pkg/common/db/controller/friend.go | 33 +- pkg/common/db/controller/group.go | 20 +- pkg/common/db/controller/msg.go | 339 ++-- pkg/common/db/controller/msg_test.go | 250 --- pkg/common/db/controller/push.go | 4 +- pkg/common/db/controller/s3.go | 4 +- pkg/common/db/controller/third.go | 6 +- pkg/common/db/controller/user.go | 55 +- pkg/common/db/mgo/black.go | 22 +- pkg/common/db/mgo/conversation.go | 47 +- pkg/common/db/{s3 => mgo}/doc.go | 4 +- pkg/common/db/mgo/friend.go | 26 +- pkg/common/db/mgo/friend_request.go | 20 +- pkg/common/db/mgo/group.go | 26 +- pkg/common/db/mgo/group_member.go | 32 +- pkg/common/db/mgo/group_request.go | 20 +- pkg/common/db/mgo/log.go | 16 +- pkg/common/db/{unrelation => mgo}/msg.go | 788 +++------ pkg/common/db/mgo/object.go | 12 +- .../{unrelation/user.go => mgo/subscribe.go} | 16 +- pkg/common/db/mgo/user.go | 38 +- pkg/common/db/s3/cont/consts.go | 38 - pkg/common/db/s3/cont/controller.go | 282 --- pkg/common/db/s3/cont/error.go | 29 - pkg/common/db/s3/cont/id.go | 49 - pkg/common/db/s3/cont/structs.go | 34 - pkg/common/db/s3/cos/cos.go | 400 ----- pkg/common/db/s3/cos/internal.go | 27 - pkg/common/db/s3/minio/image.go | 120 -- pkg/common/db/s3/minio/internal.go | 25 - pkg/common/db/s3/minio/minio.go | 499 ------ pkg/common/db/s3/minio/thumbnail.go | 150 -- pkg/common/db/s3/oss/internal.go | 39 - pkg/common/db/s3/oss/oss.go | 382 ---- pkg/common/db/s3/s3.go | 166 -- pkg/common/db/table/relation/black.go | 6 +- pkg/common/db/table/relation/conversation.go | 2 +- .../db/{unrelation => table/relation}/doc.go | 4 +- pkg/common/db/table/relation/friend.go | 2 +- .../db/table/relation/friend_request.go | 2 +- pkg/common/db/table/relation/group.go | 2 +- pkg/common/db/table/relation/group_member.go | 12 +- pkg/common/db/table/relation/group_request.go | 2 +- pkg/common/db/table/relation/log.go | 2 +- .../db/table/{unrelation => relation}/msg.go | 32 +- .../user.go => relation/subscribe.go} | 12 +- pkg/common/db/table/relation/user.go | 6 +- pkg/common/db/table/relation/utils.go | 4 +- pkg/common/db/table/unrelation/common.go | 20 - pkg/common/db/table/unrelation/super_group.go | 53 - pkg/common/db/unrelation/mongo.go | 168 -- pkg/common/db/unrelation/msg_convert.go | 81 - pkg/common/db/unrelation/super_group.go | 163 -- .../direct/direct_resolver.go | 2 +- .../discoveryregister/direct/directconn.go | 314 ++-- .../direct}/doc.go | 4 +- .../discoveryregister/discoveryregister.go | 48 +- .../discoveryregister_test.go | 70 +- pkg/common/discoveryregister/doc.go | 15 + .../discoveryregister/kubernetes/doc.go | 15 + .../kubernetes/kubernetes.go | 14 +- pkg/common/discoveryregister/zookeeper/doc.go | 15 + .../discoveryregister/zookeeper/zookeeper.go | 36 - pkg/common/ginprometheus/doc.go | 15 + pkg/common/http/http_client.go | 139 -- pkg/common/http/http_client_test.go | 154 -- pkg/common/kafka/consumer.go | 71 - pkg/common/kafka/consumer_group.go | 87 - pkg/common/kafka/producer.go | 197 --- pkg/common/kafka/util.go | 77 - pkg/common/prommetrics/doc.go | 15 + pkg/common/prommetrics/prommetrics.go | 10 +- pkg/common/prommetrics/prommetrics_test.go | 40 +- pkg/common/redispubsub/doc.go | 15 + pkg/common/servererrs/code.go | 95 + pkg/common/servererrs/doc.go | 1 + pkg/common/servererrs/predefine.go | 68 + pkg/common/servererrs/relation.go | 58 + pkg/common/startrpc/doc.go | 5 +- pkg/common/startrpc/start.go | 74 +- pkg/common/startrpc/start_test.go | 69 - pkg/common/tls/tls.go | 88 - pkg/common/version/base.go | 61 - pkg/common/version/types.go | 44 - pkg/common/version/version.go | 72 - pkg/common/webhook/condition.go | 13 + pkg/common/{db/s3/cont => webhook}/doc.go | 4 +- pkg/common/webhook/http_client.go | 86 + .../common/webhook/http_client_test.go | 2 +- pkg/localcache/doc.go | 15 + pkg/localcache/go.sum | 1 + pkg/localcache/link/doc.go | 15 + pkg/{common/kafka => localcache/lru}/doc.go | 4 +- pkg/localcache/lru/lru_lazy_test.go | 7 +- pkg/msgprocessor/conversation.go | 28 +- pkg/msgprocessor/conversation_test.go | 2 +- pkg/msgprocessor/doc.go | 2 +- pkg/msgprocessor/options.go | 2 +- pkg/rpccache/conversation.go | 10 +- pkg/{common/http => rpccache}/doc.go | 4 +- pkg/rpccache/friend.go | 6 +- pkg/rpccache/group.go | 10 +- pkg/rpccache/subscriber.go | 2 +- pkg/rpccache/user.go | 10 +- pkg/rpcclient/auth.go | 44 +- pkg/rpcclient/conversation.go | 26 +- pkg/rpcclient/doc.go | 2 +- pkg/rpcclient/friend.go | 24 +- pkg/rpcclient/group.go | 42 +- pkg/rpcclient/grouphash/doc.go | 15 + pkg/rpcclient/grouphash/grouphash.go | 10 +- pkg/rpcclient/msg.go | 210 ++- pkg/rpcclient/notification/doc.go | 2 +- pkg/rpcclient/push.go | 19 +- pkg/rpcclient/third.go | 54 +- pkg/rpcclient/user.go | 51 +- pkg/statistics/doc.go | 2 +- pkg/statistics/statistics.go | 2 +- pkg/util/conversationutil/conversationutil.go | 46 + pkg/util/conversationutil/doc.go | 1 + pkg/util/flag/flag.go | 54 - pkg/util/genutil/genutil.go | 54 - pkg/util/genutil/genutil_test.go | 40 - scripts/check-all.sh | 38 +- scripts/cherry-pick.sh | 4 +- scripts/create-topic.sh | 44 +- scripts/demo.sh | 156 -- scripts/docker-check-service.sh | 91 - scripts/docker-start-all.sh | 2 +- scripts/gendoc.sh | 88 +- scripts/init-config.sh | 11 +- scripts/install/openim-api.sh | 2 +- scripts/install/openim-crontask.sh | 2 +- scripts/install/openim-msggateway.sh | 2 +- scripts/install/openim-msgtransfer.sh | 5 +- scripts/install/openim-push.sh | 3 +- scripts/install/openim-rpc.sh | 3 +- scripts/install/openim-tools.sh | 44 +- scripts/lib/golang.sh | 6 +- scripts/lib/logging.sh | 30 +- scripts/lib/release.sh | 2 +- scripts/lib/util.sh | 81 +- scripts/list-feature-tests.sh | 3 - scripts/make-rules/gen.mk | 7 +- scripts/make-rules/golang.mk | 8 +- scripts/mongo-init.sh | 36 +- scripts/start-all.sh | 54 +- test/e2e/framework/helpers/chat/chat.go | 4 +- tools/changelog/go.mod | 3 - tools/changelog/{changelog.go => main.go} | 0 tools/check-component/main.go | 165 ++ tools/check-free-memory/main.go | 26 + tools/component/component.go | 400 ----- tools/component/component_test.go | 65 - tools/component/go.mod | 3 - tools/imctl/go.mod | 18 - tools/imctl/go.sum | 24 - tools/imctl/{imctl.go => main.go} | 0 tools/infra/go.mod | 11 - tools/infra/go.sum | 10 - tools/infra/{infra.go => main.go} | 3 +- tools/ncpu/go.mod | 5 - tools/ncpu/go.sum | 7 - tools/ncpu/{ncpu.go => main.go} | 0 tools/ncpu/{ncpu_test.go => main_test.go} | 0 tools/openim-web/Dockerfile | 47 - tools/openim-web/README.md | 78 - tools/openim-web/go.mod | 7 - tools/openim-web/go.sum | 10 - tools/openim-web/openim-web.go | 63 - tools/openim-web/openim-web_test.go | 71 - tools/url2im/go.mod | 20 - tools/url2im/go.sum | 33 - tools/url2im/pkg/api.go | 10 +- tools/url2im/pkg/manage.go | 10 +- tools/versionchecker/go.mod | 11 - tools/versionchecker/go.sum | 10 - .../{versionchecker.go => main.go} | 23 +- tools/yamlfmt/go.mod | 8 - tools/yamlfmt/go.sum | 6 - tools/yamlfmt/{yamlfmt.go => main.go} | 0 .../yamlfmt/{yamlfmt_test.go => main_test.go} | 0 438 files changed, 11189 insertions(+), 14697 deletions(-) create mode 100644 .env delete mode 100644 Makefile create mode 100644 bootstrap.bat create mode 100644 bootstrap.sh delete mode 100644 build/images/openim-tools/openim-web/Dockerfile create mode 100644 config/README_zh_CN.md delete mode 100644 config/Readme.md create mode 100644 config/kafka.yml create mode 100644 config/local-cache.yml create mode 100644 config/log.yml create mode 100644 config/minio.yml create mode 100644 config/mongodb.yml create mode 100644 config/notification.yml create mode 100644 config/openim-api.yml create mode 100644 config/openim-crontask.yml create mode 100644 config/openim-msggateway.yml create mode 100644 config/openim-msgtransfer.yml create mode 100644 config/openim-push.yml create mode 100644 config/openim-rpc-auth.yml create mode 100644 config/openim-rpc-conversation.yml create mode 100644 config/openim-rpc-friend.yml create mode 100644 config/openim-rpc-group.yml create mode 100644 config/openim-rpc-msg.yml create mode 100644 config/openim-rpc-third.yml create mode 100644 config/openim-rpc-user.yml create mode 100644 config/redis.yml create mode 100644 config/share.yml create mode 100644 config/webhooks.yml create mode 100644 config/zookeeper.yml delete mode 100644 docker-compose-1.yml create mode 100644 docs/contrib/go-code1.md create mode 100644 docs/contrib/go-doc.md delete mode 100644 go.work create mode 100644 internal/api/init.go rename internal/api/{route.go => router.go} (59%) delete mode 100644 internal/push/consumer_init.go delete mode 100644 internal/push/offlinepush/offlinepush_interface.go create mode 100644 internal/push/offlinepush/offlinepusher.go create mode 100644 internal/push/offlinepush/options/options.go create mode 100644 internal/push/onlinepusher.go create mode 100644 internal/push/push.go delete mode 100644 internal/push/push_rpc_server.go delete mode 100644 internal/push/push_to_client.go delete mode 100644 internal/push/tools.go rename pkg/rpcclient/notification/conversation.go => internal/rpc/conversation/notification.go (74%) rename pkg/rpcclient/notification/friend.go => internal/rpc/friend/notification.go (72%) rename pkg/rpcclient/notification/group.go => internal/rpc/group/notification.go (57%) delete mode 100644 internal/rpc/group/super_group.go delete mode 100644 internal/rpc/msg/message_interceptor.go rename pkg/rpcclient/notification/msg.go => internal/rpc/msg/notification.go (61%) rename pkg/rpcclient/notification/user.go => internal/rpc/user/notification.go (72%) create mode 100644 magefile.go create mode 100644 magefile_unix.go create mode 100644 magefile_windows.go create mode 100644 pkg/common/cachekey/doc.go create mode 100644 pkg/common/cachekey/token.go create mode 100644 pkg/common/cmd/auth.go create mode 100644 pkg/common/cmd/conversation.go create mode 100644 pkg/common/cmd/friend.go create mode 100644 pkg/common/cmd/group.go create mode 100644 pkg/common/cmd/msg.go create mode 100644 pkg/common/cmd/push.go delete mode 100644 pkg/common/cmd/rpc.go create mode 100644 pkg/common/cmd/third.go create mode 100644 pkg/common/cmd/user.go create mode 100644 pkg/common/config/constant.go create mode 100644 pkg/common/config/load_config.go create mode 100644 pkg/common/config/load_config_test.go delete mode 100644 pkg/common/config/parse_test.go delete mode 100644 pkg/common/db/cache/init_redis.go create mode 100644 pkg/common/db/cache/seq.go create mode 100644 pkg/common/db/cache/third.go create mode 100644 pkg/common/db/cache/token.go delete mode 100644 pkg/common/db/controller/msg_test.go rename pkg/common/db/{s3 => mgo}/doc.go (81%) rename pkg/common/db/{unrelation => mgo}/msg.go (56%) rename pkg/common/db/{unrelation/user.go => mgo/subscribe.go} (92%) delete mode 100644 pkg/common/db/s3/cont/consts.go delete mode 100644 pkg/common/db/s3/cont/controller.go delete mode 100644 pkg/common/db/s3/cont/error.go delete mode 100644 pkg/common/db/s3/cont/id.go delete mode 100644 pkg/common/db/s3/cont/structs.go delete mode 100644 pkg/common/db/s3/cos/cos.go delete mode 100644 pkg/common/db/s3/cos/internal.go delete mode 100644 pkg/common/db/s3/minio/image.go delete mode 100644 pkg/common/db/s3/minio/internal.go delete mode 100644 pkg/common/db/s3/minio/minio.go delete mode 100644 pkg/common/db/s3/minio/thumbnail.go delete mode 100644 pkg/common/db/s3/oss/internal.go delete mode 100644 pkg/common/db/s3/oss/oss.go delete mode 100644 pkg/common/db/s3/s3.go rename pkg/common/db/{unrelation => table/relation}/doc.go (79%) rename pkg/common/db/table/{unrelation => relation}/msg.go (88%) rename pkg/common/db/table/{unrelation/user.go => relation/subscribe.go} (86%) delete mode 100644 pkg/common/db/table/unrelation/common.go delete mode 100644 pkg/common/db/table/unrelation/super_group.go delete mode 100644 pkg/common/db/unrelation/mongo.go delete mode 100644 pkg/common/db/unrelation/msg_convert.go delete mode 100644 pkg/common/db/unrelation/super_group.go rename pkg/common/{db/table/unrelation => discoveryregister/direct}/doc.go (78%) create mode 100644 pkg/common/discoveryregister/doc.go create mode 100644 pkg/common/discoveryregister/kubernetes/doc.go create mode 100644 pkg/common/discoveryregister/zookeeper/doc.go create mode 100644 pkg/common/ginprometheus/doc.go delete mode 100644 pkg/common/http/http_client.go delete mode 100644 pkg/common/http/http_client_test.go delete mode 100644 pkg/common/kafka/consumer.go delete mode 100644 pkg/common/kafka/consumer_group.go delete mode 100644 pkg/common/kafka/producer.go delete mode 100644 pkg/common/kafka/util.go create mode 100644 pkg/common/prommetrics/doc.go create mode 100644 pkg/common/redispubsub/doc.go create mode 100644 pkg/common/servererrs/code.go create mode 100644 pkg/common/servererrs/doc.go create mode 100644 pkg/common/servererrs/predefine.go create mode 100644 pkg/common/servererrs/relation.go delete mode 100644 pkg/common/startrpc/start_test.go delete mode 100755 pkg/common/tls/tls.go delete mode 100644 pkg/common/version/base.go delete mode 100644 pkg/common/version/types.go delete mode 100644 pkg/common/version/version.go create mode 100644 pkg/common/webhook/condition.go rename pkg/common/{db/s3/cont => webhook}/doc.go (80%) create mode 100644 pkg/common/webhook/http_client.go rename internal/rpc/statistics/statistics.go => pkg/common/webhook/http_client_test.go (96%) create mode 100644 pkg/localcache/doc.go create mode 100644 pkg/localcache/go.sum create mode 100644 pkg/localcache/link/doc.go rename pkg/{common/kafka => localcache/lru}/doc.go (80%) rename pkg/{common/http => rpccache}/doc.go (81%) create mode 100644 pkg/rpcclient/grouphash/doc.go create mode 100644 pkg/util/conversationutil/conversationutil.go create mode 100644 pkg/util/conversationutil/doc.go delete mode 100644 pkg/util/flag/flag.go delete mode 100644 pkg/util/genutil/genutil.go delete mode 100644 pkg/util/genutil/genutil_test.go delete mode 100755 scripts/demo.sh delete mode 100755 scripts/docker-check-service.sh delete mode 100644 tools/changelog/go.mod rename tools/changelog/{changelog.go => main.go} (100%) create mode 100644 tools/check-component/main.go create mode 100644 tools/check-free-memory/main.go delete mode 100644 tools/component/component.go delete mode 100644 tools/component/component_test.go delete mode 100644 tools/component/go.mod delete mode 100644 tools/imctl/go.mod delete mode 100644 tools/imctl/go.sum rename tools/imctl/{imctl.go => main.go} (100%) delete mode 100644 tools/infra/go.mod delete mode 100644 tools/infra/go.sum rename tools/infra/{infra.go => main.go} (90%) delete mode 100644 tools/ncpu/go.mod delete mode 100644 tools/ncpu/go.sum rename tools/ncpu/{ncpu.go => main.go} (100%) rename tools/ncpu/{ncpu_test.go => main_test.go} (100%) delete mode 100644 tools/openim-web/Dockerfile delete mode 100644 tools/openim-web/README.md delete mode 100644 tools/openim-web/go.mod delete mode 100644 tools/openim-web/go.sum delete mode 100644 tools/openim-web/openim-web.go delete mode 100644 tools/openim-web/openim-web_test.go delete mode 100644 tools/url2im/go.mod delete mode 100644 tools/url2im/go.sum delete mode 100644 tools/versionchecker/go.mod delete mode 100644 tools/versionchecker/go.sum rename tools/versionchecker/{versionchecker.go => main.go} (82%) delete mode 100644 tools/yamlfmt/go.mod delete mode 100644 tools/yamlfmt/go.sum rename tools/yamlfmt/{yamlfmt.go => main.go} (100%) rename tools/yamlfmt/{yamlfmt_test.go => main_test.go} (100%) diff --git a/.env b/.env new file mode 100644 index 0000000000..92c4d5c416 --- /dev/null +++ b/.env @@ -0,0 +1,13 @@ + +MONGO_IMAGE=mongo:6.0.2 +REDIS_IMAGE=redis:7.0.0 +ZOOKEEPER_IMAGE=bitnami/zookeeper:3.8 +KAFKA_IMAGE=bitnami/kafka:3.5.1 +MINIO_IMAGE=minio/minio:RELEASE.2024-01-11T07-46-16Z + + +OPENIM_WEB_FRONT_IMAGE=ghcr.io/openimsdk/openim-web:v3.5.0-docker +OPENIM_ADMIN_FRONT_IMAGE=ghcr.io/openimsdk/openim-admin:toc-base-open-docker.35 + +DATA_DIR=./ + diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index c123566f1c..f7c5900ce7 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -56,7 +56,8 @@ jobs: - name: Generate all necessary files, such as error code files run: | - make generate + make gen.docgo.doc + make gen echo "Generate all necessary files successfully" continue-on-error: true @@ -68,9 +69,9 @@ jobs: echo "Generate all necessary files successfully" continue-on-error: true - - name: Generate Vertions + - name: Generate Versions Including Pre-release Identifiers run: | - latest_tag=$(git describe --tags `git rev-list --tags --max-count=1` | grep -oE '[0-9]+\.[0-9]+\.[0-9]+') + latest_tag=$(git describe --tags `git rev-list --tags --max-count=1`) echo $latest_tag > pkg/common/config/version continue-on-error: true diff --git a/.gitignore b/.gitignore index 5142fe5513..fb8d428d24 100644 --- a/.gitignore +++ b/.gitignore @@ -34,7 +34,6 @@ deployments/charts/generated-configs/ ### OpenIM Config ### .env config/config.yaml -config/openim.yaml config/alertmanager.yml config/prometheus.yml config/email.tmpl diff --git a/.golangci.yml b/.golangci.yml index c262cfa2f0..ae8cea6732 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -39,19 +39,19 @@ run: # from this option's value (see skip-dirs-use-default). # "/" will be replaced by current OS file path separator to properly work # on Windows. - skip-dirs: - - components - - docs - - util - - .*~ - - api/swagger/docs - - server/docs - - components/mnt/config/certs - - logs + # skip-dirs: + # - components + # - docs + # - util + # - .*~ + # - api/swagger/docs + # - server/docs + # - components/mnt/config/certs + # - logs # default is true. Enables skipping of directories: # vendor$, third_party$, testdata$, examples$, Godeps$, builtin$ - skip-dirs-use-default: true + # skip-dirs-use-default: true # which files to skip: they will be analyzed, but issues from them # won't be reported. Default value is empty list, but there is @@ -59,15 +59,15 @@ run: # autogenerated files. If it's not please let us know. # "/" will be replaced by current OS file path separator to properly work # on Windows. - skip-files: - - ".*\\.my\\.go$" - - _test.go - - ".*_test.go" - - "mocks/" - - ".github/" - - "logs/" - - "_output/" - - "components/" + # skip-files: + # - ".*\\.my\\.go$" + # - _test.go + # - ".*_test.go" + # - "mocks/" + # - ".github/" + # - "logs/" + # - "_output/" + # - "components/" # by default isn't set. If set we pass it to "go list -mod={option}". From "go help modules": # If invoked with -mod=readonly, the go command is disallowed from the implicit @@ -87,7 +87,7 @@ run: # output configuration options output: # colored-line-number|line-number|json|tab|checkstyle|code-climate, default is "colored-line-number" - format: colored-line-number + # format: colored-line-number # print lines of code with issue, default is true print-issued-lines: true @@ -118,8 +118,7 @@ linters-settings: right-to-left-isolate: true first-strong-isolate: true pop-directional-isolate: true - # checks assignments with too many blank identifiers; default is 2 - max-blank-identifiers: 2 + dupl: # tokens count to trigger issue, 150 by default threshold: 200 @@ -151,6 +150,11 @@ linters-settings: comparison: true exhaustive: + # Program elements to check for exhaustiveness. + # Default: [ switch ] + check: + - switch + - map # check switch statements in generated files also check-generated: false # indicates that switch statements are to be considered exhaustive if a @@ -162,33 +166,34 @@ linters-settings: ignore-enum-members: "" # consider enums only in package scopes, not in inner scopes package-scope-only: false - exhaustivestruct: - struct-patterns: - - '*.Test' - - '*.Test2' - - '*.Embedded' - - '*.External' - - # forbidigo: + + + forbidigo: # # Forbid the following identifiers (identifiers are written using regexp): - # forbid: - # - ^print.*$ - # - 'fmt\.Print.*' - # - fmt.Println.* # too much log noise + forbid: + # - ^print.*$ + - 'fmt\.Print.*' + - fmt.Println.* # too much log noise + - ^unsafe\..*$ + - ^init$ + - ^os.Exit$ + - ^fmt.Print.*$ + - errors.New.*$ + - ^fmt.Println.*$ + - ^panic$ + - painc # - ginkgo\\.F.* # these are used just for local development # # Exclude godoc examples from forbidigo checks. Default is true. # exclude_godoc_examples: false + funlen: - lines: 150 + lines: 220 statements: 80 - gci: - # put imports beginning with prefix after 3rd-party packages; - # only support one prefix - # if not set, use goimports.local-prefixes - prefix: github.com/openimsdk/open-im-server + gocognit: # minimal code complexity to report, 30 by default (but we recommend 10-20) min-complexity: 30 + goconst: # minimal length of string constant, 3 by default min-len: 3 @@ -214,9 +219,6 @@ linters-settings: # By default list of stable checks is used. enabled-checks: #- rangeValCopy - - nestingreduce - - truncatecmp - - unnamedresult - ruleguard # Which checks should be disabled; can't be combined with 'enabled-checks'; default is empty @@ -245,9 +247,6 @@ linters-settings: hugeParam: # size in bytes that makes the warning trigger (default 80) sizeThreshold: 80 - nestingReduce: - # min number of statements inside a branch to trigger a warning (default 5) - bodyWidth: 5 rangeExprCopy: # size in bytes that makes the warning trigger (default 512) sizeThreshold: 512 @@ -261,15 +260,10 @@ linters-settings: ruleguard: # path to a gorules file for the ruleguard checker rules: '' - truncateCmp: - # whether to skip int/uint/uintptr types (default true) - skipArchDependent: true underef: # whether to skip (*x).method() calls where x is a pointer receiver (default true) skipRecvDeref: true - unnamedResult: - # whether to check exported functions - checkExported: true + gocyclo: # minimal code complexity to report, 30 by default (but we recommend 10-20) min-complexity: 30 @@ -286,9 +280,12 @@ linters-settings: # list of regexps for excluding particular comment lines from check exclude: # example: exclude comments which contain numbers - # - '[0-9]+' + - '[0-9]+' + - 'func\s+\w+' + - 'FIXME:' + - '.*func.*' # check that each sentence starts with a capital letter - capital: false + capital: true godox: # report any comments starting with keywords, this is useful for TODO or FIXME comments that # might be left in the code accidentally and should be resolved before merging @@ -311,15 +308,15 @@ linters-settings: # by default extra-rules: false - goheader: - values: - const: + # goheader: + # values: + # const: # define here const type values in format k:v, for example: # COMPANY: MY COMPANY - regexp: + # regexp: # define here regexp type values, for example # AUTHOR: .*@mycompany\.com - template: # |- + # template: # |- # put here copyright header template for source code files, for example: # Note: {{ YEAR }} is a builtin value that returns the year relative to the current machine time. # @@ -337,21 +334,45 @@ linters-settings: # 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. - template-path: + # template-path: # also as alternative of directive 'template' you may put the path to file with the template source + goimports: # put imports beginning with prefix after 3rd-party packages; # it's a comma-separated list of prefixes local-prefixes: github.com/openimsdk/open-im-server gomnd: - settings: - mnd: - # the list of enabled checks, see https://github.com/tommy-muehle/go-mnd/#checks for description. - checks: argument,case,condition,operation,return,assign - # ignored-numbers: 1000 - # ignored-files: magic_.*.go - # ignored-functions: math.* + # List of enabled checks, see https://github.com/tommy-muehle/go-mnd/#checks for description. + # Default: ["argument", "case", "condition", "operation", "return", "assign"] + checks: + - argument + - case + - condition + - operation + - return + - assign + # List of numbers to exclude from analysis. + # The numbers should be written as string. + # Values always ignored: "1", "1.0", "0" and "0.0" + # Default: [] + ignored-numbers: + - '0666' + - '0755' + - '42' + # List of file patterns to exclude from analysis. + # Values always ignored: `.+_test.go` + # Default: [] + ignored-files: + - 'magic1_.+\.go$' + # List of function patterns to exclude from analysis. + # Following functions are always ignored: `time.Date`, + # `strconv.FormatInt`, `strconv.FormatUint`, `strconv.FormatFloat`, + # `strconv.ParseInt`, `strconv.ParseUint`, `strconv.ParseFloat`. + # Default: [] + ignored-functions: + - '^math\.' + - '^webhook\.StatusText$' gomoddirectives: # Allow local `replace` directives. Default is false. replace-local: true @@ -363,6 +384,7 @@ linters-settings: retract-allow-no-explanation: false # Forbid the use of the `exclude` directives. Default is false. exclude-forbidden: false + gomodguard: allowed: modules: @@ -426,9 +448,6 @@ linters-settings: checks: [ "all" ] govet: - # report about shadowed variables - check-shadowing: false - # settings per analyzer settings: printf: # analyzer name, run `go tool vet help` to see all analyzers @@ -445,15 +464,25 @@ linters-settings: disable: - shadow disable-all: false - # depguard: - # list-type: blacklist - # include-go-root: false - # packages: - # - github.com/Sirupsen/logrus - # packages-with-error-message: - # # specify an error message to output when a blacklisted package is used - # - github.com/Sirupsen/logrus: "logging is allowed only by logutils.Log" + depguard: + rules: + prevent_unmaintained_packages: + list-mode: lax # allow unless explicitely denied + files: + - $all + - "!$test" + allow: + - $gostd + deny: + - pkg: io/ioutil + desc: "replaced by io and os packages since Go 1.16: https://tip.golang.org/doc/go1.16#ioutil" + - pkg: github.com/OpenIMSDK + desc: "The OpenIM organization has been replaced with lowercase, please do not use uppercase organization name, you will use openimsdk" + - pkg: log + desc: "We have a wrapped log package at openim, we recommend you to use our wrapped log package, https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/logging.md" + - pkg: errors + desc: "We have a wrapped errors package at openim, we recommend you to use our wrapped errors package, https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/error-code.md" importas: # if set to `true`, force to use alias. @@ -463,6 +492,8 @@ linters-settings: # using `servingv1` alias for `knative.dev/serving/pkg/apis/serving/v1` package - pkg: knative.dev/serving/pkg/apis/serving/v1 alias: servingv1 + - pkg: gopkg.in/yaml.v2 + alias: yaml # using `autoscalingv1alpha1` alias for `knative.dev/serving/pkg/apis/autoscaling/v1alpha1` package - pkg: knative.dev/serving/pkg/apis/autoscaling/v1alpha1 alias: autoscalingv1alpha1 @@ -471,8 +502,6 @@ linters-settings: # see https://github.com/julz/importas#use-regular-expression for details - pkg: knative.dev/serving/pkg/apis/(\w+)/(v[\w\d]+) alias: $1$2 - # using `jwt` alias for `github.com/appleboy/gin-jwt/v2` package - jwt: github.com/appleboy/gin-jwt/v2 ireturn: # ireturn allows using `allow` and `reject` settings at the same time. @@ -503,9 +532,6 @@ linters-settings: line-length: 250 # tab width in spaces. Default to 1. tab-width: 4 - maligned: - # print struct with more effective memory layout or not, false by default - suggest-new: true misspell: # Correct spellings using locale preferences for US or UK. # Default is to use a neutral variety of English. @@ -538,8 +564,6 @@ linters-settings: nolintlint: # Disable to ensure that all nolint directives actually have an effect. Default is true. allow-unused: false - # Disable to ensure that nolint directives don't have a leading space. Default is true. - allow-leading-space: true # Exclude following linters from requiring an explanation. Default is []. allow-no-explanation: [ ] # Enable to require an explanation of nonzero length after each nolint directive. Default is false. @@ -563,14 +587,13 @@ linters-settings: strict: false # Please refer to https://github.com/yeya24/promlinter#usage for detailed usage. disabled-linters: - # - "Help" - # - "MetricUnits" - # - "Counter" - # - "HistogramSummaryReserved" - # - "MetricTypeInName" - # - "ReservedChars" - # - "CamelCase" - # - "lintUnitAbbreviations" + - "Help" + - "MetricUnits" + - "Counter" + - "HistogramSummaryReserved" + - "MetricTypeInName" + - "ReservedChars" + - "CamelCase" predeclared: # comma-separated list of predeclared identifiers to not report on @@ -580,6 +603,7 @@ linters-settings: rowserrcheck: packages: - github.com/jmoiron/sqlx + revive: # see https://github.com/mgechev/revive#available-rules for details. ignore-generated-header: true @@ -587,15 +611,27 @@ linters-settings: rules: - name: indent-error-flow severity: warning + - name: exported + severity: warning + - name: var-naming + arguments: [ [ "OpenIM"] ] + # arguments: [ ["ID", "HTTP", "URL", "URI", "API", "APIKey", "Token", "TokenID", "TokenSecret", "TokenKey", "TokenSecret", "JWT", "JWTToken", "JWTTokenID", "JWTTokenSecret", "JWTTokenKey", "JWTTokenSecret", "OAuth", "OAuthToken", "RPC" ] ] + - name: atomic + - name: line-length-limit + severity: error + arguments: [200] + - name: unhandled-error + arguments : ["fmt.Printf", "myFunction"] + staticcheck: # Select the Go version to target. The default is '1.13'. - go: "1.16" + go: "1.20" # https://staticcheck.io/docs/options#checks checks: [ "all" ] stylecheck: # Select the Go version to target. The default is '1.13'. - go: "1.16" + go: "1.20" # https://staticcheck.io/docs/options#checks checks: [ "all", "-ST1000", "-ST1003", "-ST1016", "-ST1020", "-ST1021", "-ST1022" ] @@ -607,7 +643,6 @@ linters-settings: # https://staticcheck.io/docs/options#http_status_code_whitelist http-status-code-whitelist: [ "200", "400", "404", "500" ] - tagliatelle: # check the struck tag name case case: @@ -653,12 +688,11 @@ linters-settings: # if it's called for subdir of a project it can't find external interfaces. All text editor integrations # with golangci-lint call it on a directory with the changed file. check-exported: false - unused: + # unused: # treat code as a program (not a library) and report unused exported identifiers; default is false. # XXX: if you enable this setting, unused will report a lot of false-positives in text editors: # if it's called for subdir of a project it can't find funcs usages. All text editor integrations # with golangci-lint call it on a directory with the changed file. - check-exported: false whitespace: multi-if: false # Enforces newlines (or comments) after every multi-line if statement multi-func: false # Enforces newlines (or comments) after every multi-line function signature @@ -672,6 +706,7 @@ linters-settings: - errors.New( - errors.Unwrap( - .Wrap( + - .WrapMsg( - .Wrapf( - .WithMessage( - .WithMessagef( @@ -679,6 +714,8 @@ linters-settings: ignorePackageGlobs: - encoding/* - github.com/pkg/* + - github.com/openimsdk/* + - github.com/OpenIMSDK/* wsl: # If true append is only allowed to be cuddled if appending value is @@ -705,7 +742,6 @@ linters-settings: # Allow only slices initialized with a length of zero. Default is false. always: false - # The custom section can be used to define linter plugins to be loaded at runtime. See README doc # for more info. #custom: @@ -731,16 +767,21 @@ linters: - errcheck - decorder - ineffassign + - forbidigo - revive - reassign - tparallel - unconvert + - fieldalignment - dupl - dupword - errname - gci - - goheader + - exhaustive + - gocritic - goprintffuncname + - gomnd + - goconst - gosec - misspell # Spelling mistakes - staticcheck # Static analysis @@ -761,6 +802,7 @@ issues: exclude: - tools/.* - test/.* + - components/* - third_party/.* # Excluding configuration per-path, per-linter, per-text and per-source diff --git a/Dockerfile b/Dockerfile index d4c2e26024..9b10212165 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,7 +3,6 @@ FROM golang:1.20 AS builder # Set go mod installation source and proxy ARG GO111MODULE=on -ARG GOPROXY=https://goproxy.io,direct ENV GO111MODULE=$GO111MODULE ENV GOPROXY=$GOPROXY diff --git a/Makefile b/Makefile deleted file mode 100644 index 818372fb8f..0000000000 --- a/Makefile +++ /dev/null @@ -1,256 +0,0 @@ -# ============================================================================== -# define the default goal -# - -.DEFAULT_GOAL := help - -## all: Run tidy, gen, add-copyright, format, lint, cover, build ✨ -.PHONY: all -all: tidy gen add-copyright verify test-api lint cover restart - -# ============================================================================== -# Build set - -ROOT_PACKAGE=github.com/openimsdk/open-im-server -# TODO: This is version control for the future https://github.com/openimsdk/open-im-server/issues/574 -VERSION_PACKAGE=github.com/openimsdk/open-im-server/v3/pkg/version - -# ============================================================================== -# Includes - -include scripts/make-rules/common.mk # make sure include common.mk at the first include line -include scripts/make-rules/common-versions.mk -include scripts/make-rules/golang.mk -include scripts/make-rules/image.mk -include scripts/make-rules/copyright.mk -include scripts/make-rules/gen.mk -include scripts/make-rules/dependencies.mk -include scripts/make-rules/tools.mk -include scripts/make-rules/release.mk -include scripts/make-rules/swagger.mk - -# ============================================================================== -# Usage - -define USAGE_OPTIONS - -Options: - - DEBUG Whether or not to generate debug symbols. Default is 0. - - BINS Binaries to build. Default is all binaries under cmd. - This option is available when using: make {build}(.multiarch) - Example: make build BINS="openim-api openim-cmdutils". - - PLATFORMS Platform to build for. Default is linux_arm64 and linux_amd64. - This option is available when using: make {build}.multiarch - Example: make multiarch PLATFORMS="linux_s390x linux_mips64 - linux_mips64le darwin_amd64 windows_amd64 linux_amd64 linux_arm64". - - V Set to 1 enable verbose build. Default is 0. -endef -export USAGE_OPTIONS - -# ============================================================================== -# Targets - -## init: Initialize openim server project ✨ -.PHONY: init -init: - @$(MAKE) gen.init - -## init-githooks: Initialize git hooks ✨ -.PHONY: init-githooks -init-githooks: - @$(MAKE) gen.init-githooks - -## gen: Generate all necessary files. ✨ -.PHONY: gen -gen: - @$(MAKE) gen.run - -## demo: Run demo get started with Makefiles quickly ✨ -.PHONY: demo -demo: - @$(MAKE) go.demo - -## version: Check version of openim. ✨ -.PHONY: version -version: - @$(MAKE) go.versionchecker - -## build: Build binaries by default ✨ -.PHONY: build -build: - @$(MAKE) go.build - -## start: Start openim ✨ -.PHONY: start -start: - @$(MAKE) go.start - -## stop: Stop openim ✨ -.PHONY: stop -stop: - @$(MAKE) go.stop - -## restart: Restart openim (make init configuration file is initialized) ✨ -.PHONY: restart -restart: clean stop build start check - -## multiarch: Build binaries for multiple platforms. See option PLATFORMS. ✨ -.PHONY: multiarch -multiarch: - @$(MAKE) go.build.multiarch - -## verify: execute all verity scripts. ✨ -.PHONY: verify -verify: - @$(MAKE) go.verify - -## install: Install deployment openim ✨ -.PHONY: install -install: - @$(MAKE) go.install - -## check: Check OpenIM deployment ✨ -.PHONY: check -check: - @$(MAKE) go.check - -## check-component: Check OpenIM component deployment ✨ -.PHONY: check-component -check-component: - @$(MAKE) go.check-component - -## tidy: tidy go.mod ✨ -.PHONY: tidy -tidy: - @$(GO) mod tidy - -## vendor: vendor go.mod ✨ -.PHONY: vendor -vendor: - @$(GO) mod vendor - -## style: code style -> fmt,vet,lint ✨ -.PHONY: style -style: fmt vet lint - -## fmt: Run go fmt against code. ✨ -.PHONY: fmt -fmt: - @$(GO) fmt ./... - -## vet: Run go vet against code. ✨ -.PHONY: vet -vet: - @$(GO) vet ./... - -## lint: Check syntax and styling of go sources. ✨ -.PHONY: lint -lint: - @$(MAKE) go.lint - -## format: Gofmt (reformat) package sources (exclude vendor dir if existed). ✨ -.PHONY: format -format: - @$(MAKE) go.format - -## test: Run unit test. ✨ -.PHONY: test -test: - @$(MAKE) go.test - -## cover: Run unit test and get test coverage. ✨ -.PHONY: cover -cover: - @$(MAKE) go.test.cover - -## test-api: Run api test. ✨ -.PHONY: test-api -test-api: - @$(MAKE) go.test.api - -## test-e2e: Run e2e test -test-e2e: - @$(MAKE) go.test.e2e - -## updates: Check for updates to go.mod dependencies. ✨ -.PHONY: updates - @$(MAKE) go.updates - -## imports: task to automatically handle import packages in Go files using goimports tool. ✨ -.PHONY: imports -imports: - @$(MAKE) go.imports - -## clean: Delete all files created by the build, as well as all log files. ✨ -.PHONY: clean -clean: - @$(MAKE) go.clean - -## image: Build docker images for host arch. ✨ -.PHONY: image -image: - @$(MAKE) image.build - -## image.multiarch: Build docker images for multiple platforms. See option PLATFORMS. ✨ -.PHONY: image.multiarch -image.multiarch: - @$(MAKE) image.build.multiarch - -## push: Build docker images for host arch and push images to registry. ✨ -.PHONY: push -push: - @$(MAKE) image.push - -## push.multiarch: Build docker images for multiple platforms and push images to registry. ✨ -.PHONY: push.multiarch -push.multiarch: - @$(MAKE) image.push.multiarch - -## tools: Install dependent tools. ✨ -.PHONY: tools -tools: - @$(MAKE) tools.install - -## swagger: Generate swagger document. ✨ -.PHONY: swagger -swagger: - @$(MAKE) swagger.run - -## serve-swagger: Serve swagger spec and docs. ✨ -.PHONY: swagger.serve -serve-swagger: - @$(MAKE) swagger.serve - -## verify-copyright: Verify the license headers for all files. ✨ -.PHONY: verify-copyright -verify-copyright: - @$(MAKE) copyright.verify - -## add-copyright: Add copyright ensure source code files have license headers. ✨ -.PHONY: add-copyright -add-copyright: - @$(MAKE) copyright.add - -## advertise: Project introduction, become a contributor ✨ -.PHONY: advertise -advertise: - @$(MAKE) copyright.advertise - -## release: release the project ✨ -.PHONY: release -release: release.verify release.ensure-tag - @scripts/release.sh - -## help: Show this help info. ✨ -.PHONY: help -help: Makefile - $(call makehelp) - -## help-all: Show all help details info. ✨ -.PHONY: help-all -help-all: go.help copyright.help tools.help image.help dependencies.help gen.help release.help swagger.help help - $(call makeallhelp) diff --git a/bootstrap.bat b/bootstrap.bat new file mode 100644 index 0000000000..819f19c871 --- /dev/null +++ b/bootstrap.bat @@ -0,0 +1,31 @@ +@echo off +SETLOCAL + +mage -version >nul 2>&1 +IF %ERRORLEVEL% EQU 0 ( + echo Mage is already installed. + GOTO DOWNLOAD +) + +go version >nul 2>&1 +IF NOT %ERRORLEVEL% EQU 0 ( + echo Go is not installed. Please install Go and try again. + exit /b 1 +) + +echo Installing Mage... +go install github.com/magefile/mage@latest + +mage -version >nul 2>&1 +IF NOT %ERRORLEVEL% EQU 0 ( + echo Mage installation failed. + echo Please ensure that %GOPATH%/bin is in your PATH. + exit /b 1 +) + +echo Mage installed successfully. + +:DOWNLOAD +go mod download + +ENDLOCAL diff --git a/bootstrap.sh b/bootstrap.sh new file mode 100644 index 0000000000..f79cd1f110 --- /dev/null +++ b/bootstrap.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +if [[ ":$PATH:" == *":$HOME/.local/bin:"* ]]; then + TARGET_DIR="$HOME/.local/bin" +else + TARGET_DIR="/usr/local/bin" + echo "Using /usr/local/bin as the installation directory. Might require sudo permissions." +fi + +if ! command -v mage &> /dev/null; then + echo "Installing Mage to $TARGET_DIR ..." + GOBIN=$TARGET_DIR go install github.com/magefile/mage@latest +fi + +if ! command -v mage &> /dev/null; then + echo "Mage installation failed." + echo "Please ensure that $TARGET_DIR is in your \$PATH." + exit 1 +fi + +echo "Mage installed successfully." + +go mod download diff --git a/build/images/openim-api/Dockerfile b/build/images/openim-api/Dockerfile index 5832c31a61..6622239569 100644 --- a/build/images/openim-api/Dockerfile +++ b/build/images/openim-api/Dockerfile @@ -19,7 +19,6 @@ FROM golang:1.20 AS builder ARG GO111MODULE=on -ARG GOPROXY=https://goproxy.io,direct WORKDIR /openim/openim-server diff --git a/build/images/openim-cmdutils/Dockerfile b/build/images/openim-cmdutils/Dockerfile index 5afbe6ecec..34bcd41f5d 100644 --- a/build/images/openim-cmdutils/Dockerfile +++ b/build/images/openim-cmdutils/Dockerfile @@ -19,7 +19,6 @@ FROM golang:1.20 AS builder ARG GO111MODULE=on -ARG GOPROXY=https://goproxy.io,direct WORKDIR /openim/openim-server diff --git a/build/images/openim-crontask/Dockerfile b/build/images/openim-crontask/Dockerfile index 4019e16c12..90a5629264 100644 --- a/build/images/openim-crontask/Dockerfile +++ b/build/images/openim-crontask/Dockerfile @@ -19,7 +19,6 @@ FROM golang:1.20 AS builder ARG GO111MODULE=on -ARG GOPROXY=https://goproxy.io,direct WORKDIR /openim/openim-server diff --git a/build/images/openim-msggateway/Dockerfile b/build/images/openim-msggateway/Dockerfile index c9d1ce949c..d3a8694eda 100644 --- a/build/images/openim-msggateway/Dockerfile +++ b/build/images/openim-msggateway/Dockerfile @@ -19,7 +19,6 @@ FROM golang:1.20 AS builder ARG GO111MODULE=on -ARG GOPROXY=https://goproxy.io,direct WORKDIR /openim/openim-server diff --git a/build/images/openim-msgtransfer/Dockerfile b/build/images/openim-msgtransfer/Dockerfile index 08a026c350..f949786488 100644 --- a/build/images/openim-msgtransfer/Dockerfile +++ b/build/images/openim-msgtransfer/Dockerfile @@ -19,7 +19,6 @@ FROM golang:1.20 AS builder ARG GO111MODULE=on -ARG GOPROXY=https://goproxy.io,direct WORKDIR /openim/openim-server diff --git a/build/images/openim-push/Dockerfile b/build/images/openim-push/Dockerfile index 43a3833c2a..faebbe9c05 100644 --- a/build/images/openim-push/Dockerfile +++ b/build/images/openim-push/Dockerfile @@ -19,7 +19,6 @@ FROM golang:1.20 AS builder ARG GO111MODULE=on -ARG GOPROXY=https://goproxy.io,direct WORKDIR /openim/openim-server diff --git a/build/images/openim-rpc-auth/Dockerfile b/build/images/openim-rpc-auth/Dockerfile index 6a64c3e79e..1e905d4b2b 100644 --- a/build/images/openim-rpc-auth/Dockerfile +++ b/build/images/openim-rpc-auth/Dockerfile @@ -19,7 +19,6 @@ FROM golang:1.20 AS builder ARG GO111MODULE=on -ARG GOPROXY=https://goproxy.io,direct WORKDIR /openim/openim-server diff --git a/build/images/openim-rpc-conversation/Dockerfile b/build/images/openim-rpc-conversation/Dockerfile index 421755094b..5a69aa89f1 100644 --- a/build/images/openim-rpc-conversation/Dockerfile +++ b/build/images/openim-rpc-conversation/Dockerfile @@ -19,7 +19,6 @@ FROM golang:1.20 AS builder ARG GO111MODULE=on -ARG GOPROXY=https://goproxy.io,direct WORKDIR /openim/openim-server diff --git a/build/images/openim-rpc-friend/Dockerfile b/build/images/openim-rpc-friend/Dockerfile index ba3a381162..fad21a880f 100644 --- a/build/images/openim-rpc-friend/Dockerfile +++ b/build/images/openim-rpc-friend/Dockerfile @@ -19,7 +19,6 @@ FROM golang:1.20 AS builder ARG GO111MODULE=on -ARG GOPROXY=https://goproxy.io,direct WORKDIR /openim/openim-server diff --git a/build/images/openim-rpc-group/Dockerfile b/build/images/openim-rpc-group/Dockerfile index 916c8e848c..d7dede6b9f 100644 --- a/build/images/openim-rpc-group/Dockerfile +++ b/build/images/openim-rpc-group/Dockerfile @@ -19,7 +19,6 @@ FROM golang:1.20 AS builder ARG GO111MODULE=on -ARG GOPROXY=https://goproxy.io,direct WORKDIR /openim/openim-server diff --git a/build/images/openim-rpc-msg/Dockerfile b/build/images/openim-rpc-msg/Dockerfile index a0ac98c472..71ad85f378 100644 --- a/build/images/openim-rpc-msg/Dockerfile +++ b/build/images/openim-rpc-msg/Dockerfile @@ -19,7 +19,6 @@ FROM golang:1.20 AS builder ARG GO111MODULE=on -ARG GOPROXY=https://goproxy.io,direct WORKDIR /openim/openim-server diff --git a/build/images/openim-rpc-third/Dockerfile b/build/images/openim-rpc-third/Dockerfile index 9fe17dd408..3560ad0d75 100644 --- a/build/images/openim-rpc-third/Dockerfile +++ b/build/images/openim-rpc-third/Dockerfile @@ -19,7 +19,6 @@ FROM golang:1.20 AS builder ARG GO111MODULE=on -ARG GOPROXY=https://goproxy.io,direct WORKDIR /openim/openim-server diff --git a/build/images/openim-rpc-user/Dockerfile b/build/images/openim-rpc-user/Dockerfile index bdd0a42eee..a9891ece80 100644 --- a/build/images/openim-rpc-user/Dockerfile +++ b/build/images/openim-rpc-user/Dockerfile @@ -19,7 +19,6 @@ FROM golang:1.20 AS builder ARG GO111MODULE=on -ARG GOPROXY=https://goproxy.io,direct WORKDIR /openim/openim-server diff --git a/build/images/openim-tools/component/Dockerfile b/build/images/openim-tools/component/Dockerfile index 1f7a1a46a5..6bdfa69422 100644 --- a/build/images/openim-tools/component/Dockerfile +++ b/build/images/openim-tools/component/Dockerfile @@ -19,7 +19,6 @@ FROM golang:1.20 AS builder ARG GO111MODULE=on -ARG GOPROXY=https://goproxy.io,direct WORKDIR /openim/openim-server diff --git a/build/images/openim-tools/openim-web/Dockerfile b/build/images/openim-tools/openim-web/Dockerfile deleted file mode 100644 index d145011890..0000000000 --- a/build/images/openim-tools/openim-web/Dockerfile +++ /dev/null @@ -1,57 +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. - -# OpenIM base image: https://github.com/openim-sigs/openim-base-image - -# Set go mod installation source and proxy - -FROM golang:1.20 AS builder - -ARG GO111MODULE=on -ARG GOPROXY=https://goproxy.io,direct - -WORKDIR /openim/openim-server - -ENV GO111MODULE=$GO111MODULE -ENV GOPROXY=$GOPROXY - -RUN apt-get update && apt-get install -y curl unzip - -RUN curl -LO https://app-1302656840.cos.ap-nanjing.myqcloud.com/dist.zip \ - && unzip dist.zip -d ./ \ - && rm dist.zip - -COPY go.mod go.sum ./ -RUN go mod download - -COPY . . - -RUN make clean -RUN make build BINS=openim-web - -FROM ghcr.io/openim-sigs/openim-ubuntu-image:latest - -WORKDIR /openim/openim-server - -COPY --from=builder /openim/openim-server/_output/bin/tools /openim/openim-server/_output/bin/tools/ -COPY --from=builder /openim/openim-server/dist /openim/openim-server/dist - -ENV PORT 11001 -ENV DISTPATH /openim/openim-server/dist - -EXPOSE 11001 - -RUN mv ${OPENIM_SERVER_BINDIR}/tools/$(get_os)/$(get_arch)/openim-web /usr/bin/openim-web - -ENTRYPOINT ["bash", "-c", "openim-web -port $PORT -distPath $DISTPATH"] \ No newline at end of file diff --git a/cmd/openim-api/main.go b/cmd/openim-api/main.go index ee19a5c60d..58e540c05f 100644 --- a/cmd/openim-api/main.go +++ b/cmd/openim-api/main.go @@ -18,14 +18,12 @@ import ( _ "net/http/pprof" "github.com/openimsdk/open-im-server/v3/pkg/common/cmd" - util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" + "github.com/openimsdk/tools/system/program" ) func main() { - apiCmd := cmd.NewApiCmd() - apiCmd.AddPortFlag() - apiCmd.AddPrometheusPortFlag() - if err := apiCmd.Execute(); err != nil { - util.ExitWithError(err) + if err := cmd.NewApiCmd().Exec(); err != nil { + program.ExitWithError(err) } + } diff --git a/cmd/openim-cmdutils/main.go b/cmd/openim-cmdutils/main.go index f6b7889331..433eefb325 100644 --- a/cmd/openim-cmdutils/main.go +++ b/cmd/openim-cmdutils/main.go @@ -16,7 +16,7 @@ package main import ( "github.com/openimsdk/open-im-server/v3/pkg/common/cmd" - util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" + "github.com/openimsdk/tools/system/program" ) func main() { @@ -29,6 +29,8 @@ func main() { getCmd.AddCommand(seqCmd.GetSeqCmd(), msgCmd.GetMsgCmd()) getCmd.AddSuperGroupIDFlag() getCmd.AddUserIDFlag() + getCmd.AddConfigDirFlag() + getCmd.AddIndexFlag() getCmd.AddBeginSeqFlag() getCmd.AddLimitFlag() // openIM get seq --userID=xxx @@ -39,6 +41,8 @@ func main() { fixCmd.AddCommand(seqCmd.FixSeqCmd()) fixCmd.AddSuperGroupIDFlag() fixCmd.AddUserIDFlag() + fixCmd.AddConfigDirFlag() + fixCmd.AddIndexFlag() fixCmd.AddFixAllFlag() // openIM fix seq --userID=xxx // openIM fix seq --superGroupID=xxx @@ -47,6 +51,8 @@ func main() { clearCmd.AddCommand(msgCmd.ClearMsgCmd()) clearCmd.AddSuperGroupIDFlag() clearCmd.AddUserIDFlag() + clearCmd.AddConfigDirFlag() + clearCmd.AddIndexFlag() clearCmd.AddClearAllFlag() clearCmd.AddBeginSeqFlag() clearCmd.AddLimitFlag() @@ -55,6 +61,6 @@ func main() { // openIM clear msg --clearAll msgUtilsCmd.AddCommand(&getCmd.Command, &fixCmd.Command, &clearCmd.Command) if err := msgUtilsCmd.Execute(); err != nil { - util.ExitWithError(err) + program.ExitWithError(err) } } diff --git a/cmd/openim-crontask/main.go b/cmd/openim-crontask/main.go index b52029c64b..6745065187 100644 --- a/cmd/openim-crontask/main.go +++ b/cmd/openim-crontask/main.go @@ -16,12 +16,11 @@ package main import ( "github.com/openimsdk/open-im-server/v3/pkg/common/cmd" - util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" + "github.com/openimsdk/tools/system/program" ) func main() { - cronTaskCmd := cmd.NewCronTaskCmd() - if err := cronTaskCmd.Exec(); err != nil { - util.ExitWithError(err) + if err := cmd.NewCronTaskCmd().Exec(); err != nil { + program.ExitWithError(err) } } diff --git a/cmd/openim-msggateway/main.go b/cmd/openim-msggateway/main.go index 01b13560d3..6e3eda6bf6 100644 --- a/cmd/openim-msggateway/main.go +++ b/cmd/openim-msggateway/main.go @@ -16,15 +16,11 @@ package main import ( "github.com/openimsdk/open-im-server/v3/pkg/common/cmd" - util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" + "github.com/openimsdk/tools/system/program" ) func main() { - msgGatewayCmd := cmd.NewMsgGatewayCmd() - msgGatewayCmd.AddWsPortFlag() - msgGatewayCmd.AddPortFlag() - msgGatewayCmd.AddPrometheusPortFlag() - if err := msgGatewayCmd.Exec(); err != nil { - util.ExitWithError(err) + if err := cmd.NewMsgGatewayCmd().Exec(); err != nil { + program.ExitWithError(err) } } diff --git a/cmd/openim-msgtransfer/main.go b/cmd/openim-msgtransfer/main.go index 84fbbd2ea1..23b629d69a 100644 --- a/cmd/openim-msgtransfer/main.go +++ b/cmd/openim-msgtransfer/main.go @@ -16,14 +16,11 @@ package main import ( "github.com/openimsdk/open-im-server/v3/pkg/common/cmd" - util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" + "github.com/openimsdk/tools/system/program" ) func main() { - msgTransferCmd := cmd.NewMsgTransferCmd() - msgTransferCmd.AddPrometheusPortFlag() - msgTransferCmd.AddTransferProgressFlag() - if err := msgTransferCmd.Exec(); err != nil { - util.ExitWithError(err) + if err := cmd.NewMsgTransferCmd().Exec(); err != nil { + program.ExitWithError(err) } } diff --git a/cmd/openim-push/main.go b/cmd/openim-push/main.go index c7d29fc970..cd5106d173 100644 --- a/cmd/openim-push/main.go +++ b/cmd/openim-push/main.go @@ -15,16 +15,12 @@ package main import ( - "github.com/openimsdk/open-im-server/v3/internal/push" "github.com/openimsdk/open-im-server/v3/pkg/common/cmd" - util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" + "github.com/openimsdk/tools/system/program" ) func main() { - pushCmd := cmd.NewRpcCmd(cmd.RpcPushServer, push.Start) - pushCmd.AddPortFlag() - pushCmd.AddPrometheusPortFlag() - if err := pushCmd.Exec(); err != nil { - util.ExitWithError(err) + if err := cmd.NewPushRpcCmd().Exec(); err != nil { + program.ExitWithError(err) } } diff --git a/cmd/openim-rpc/openim-rpc-auth/main.go b/cmd/openim-rpc/openim-rpc-auth/main.go index da281b70ec..158b1f4647 100644 --- a/cmd/openim-rpc/openim-rpc-auth/main.go +++ b/cmd/openim-rpc/openim-rpc-auth/main.go @@ -15,16 +15,12 @@ package main import ( - "github.com/openimsdk/open-im-server/v3/internal/rpc/auth" "github.com/openimsdk/open-im-server/v3/pkg/common/cmd" - util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" + "github.com/openimsdk/tools/system/program" ) func main() { - authCmd := cmd.NewRpcCmd(cmd.RpcAuthServer, auth.Start) - authCmd.AddPortFlag() - authCmd.AddPrometheusPortFlag() - if err := authCmd.Exec(); err != nil { - util.ExitWithError(err) + if err := cmd.NewAuthRpcCmd().Exec(); err != nil { + program.ExitWithError(err) } } diff --git a/cmd/openim-rpc/openim-rpc-conversation/main.go b/cmd/openim-rpc/openim-rpc-conversation/main.go index 6e74b32517..5b2e66c954 100644 --- a/cmd/openim-rpc/openim-rpc-conversation/main.go +++ b/cmd/openim-rpc/openim-rpc-conversation/main.go @@ -15,16 +15,12 @@ package main import ( - "github.com/openimsdk/open-im-server/v3/internal/rpc/conversation" "github.com/openimsdk/open-im-server/v3/pkg/common/cmd" - util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" + "github.com/openimsdk/tools/system/program" ) func main() { - rpcCmd := cmd.NewRpcCmd(cmd.RpcConversationServer, conversation.Start) - rpcCmd.AddPortFlag() - rpcCmd.AddPrometheusPortFlag() - if err := rpcCmd.Exec(); err != nil { - util.ExitWithError(err) + if err := cmd.NewConversationRpcCmd().Exec(); err != nil { + program.ExitWithError(err) } } diff --git a/cmd/openim-rpc/openim-rpc-friend/main.go b/cmd/openim-rpc/openim-rpc-friend/main.go index a307c01a14..745c405532 100644 --- a/cmd/openim-rpc/openim-rpc-friend/main.go +++ b/cmd/openim-rpc/openim-rpc-friend/main.go @@ -15,16 +15,12 @@ package main import ( - "github.com/openimsdk/open-im-server/v3/internal/rpc/friend" "github.com/openimsdk/open-im-server/v3/pkg/common/cmd" - util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" + "github.com/openimsdk/tools/system/program" ) func main() { - rpcCmd := cmd.NewRpcCmd(cmd.RpcFriendServer, friend.Start) - rpcCmd.AddPortFlag() - rpcCmd.AddPrometheusPortFlag() - if err := rpcCmd.Exec(); err != nil { - util.ExitWithError(err) + if err := cmd.NewFriendRpcCmd().Exec(); err != nil { + program.ExitWithError(err) } } diff --git a/cmd/openim-rpc/openim-rpc-group/main.go b/cmd/openim-rpc/openim-rpc-group/main.go index 2afb7963cc..5badf934e9 100644 --- a/cmd/openim-rpc/openim-rpc-group/main.go +++ b/cmd/openim-rpc/openim-rpc-group/main.go @@ -15,16 +15,12 @@ package main import ( - "github.com/openimsdk/open-im-server/v3/internal/rpc/group" "github.com/openimsdk/open-im-server/v3/pkg/common/cmd" - util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" + "github.com/openimsdk/tools/system/program" ) func main() { - rpcCmd := cmd.NewRpcCmd(cmd.RpcGroupServer, group.Start) - rpcCmd.AddPortFlag() - rpcCmd.AddPrometheusPortFlag() - if err := rpcCmd.Exec(); err != nil { - util.ExitWithError(err) + if err := cmd.NewGroupRpcCmd().Exec(); err != nil { + program.ExitWithError(err) } } diff --git a/cmd/openim-rpc/openim-rpc-msg/main.go b/cmd/openim-rpc/openim-rpc-msg/main.go index bbffbcae7c..37f6cf237a 100644 --- a/cmd/openim-rpc/openim-rpc-msg/main.go +++ b/cmd/openim-rpc/openim-rpc-msg/main.go @@ -15,16 +15,12 @@ package main import ( - "github.com/openimsdk/open-im-server/v3/internal/rpc/msg" "github.com/openimsdk/open-im-server/v3/pkg/common/cmd" - util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" + "github.com/openimsdk/tools/system/program" ) func main() { - rpcCmd := cmd.NewRpcCmd(cmd.RpcMsgServer, msg.Start) - rpcCmd.AddPortFlag() - rpcCmd.AddPrometheusPortFlag() - if err := rpcCmd.Exec(); err != nil { - util.ExitWithError(err) + if err := cmd.NewMsgRpcCmd().Exec(); err != nil { + program.ExitWithError(err) } } diff --git a/cmd/openim-rpc/openim-rpc-third/main.go b/cmd/openim-rpc/openim-rpc-third/main.go index 09a8409e6f..fcead5f897 100644 --- a/cmd/openim-rpc/openim-rpc-third/main.go +++ b/cmd/openim-rpc/openim-rpc-third/main.go @@ -15,16 +15,12 @@ package main import ( - "github.com/openimsdk/open-im-server/v3/internal/rpc/third" "github.com/openimsdk/open-im-server/v3/pkg/common/cmd" - util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" + "github.com/openimsdk/tools/system/program" ) func main() { - rpcCmd := cmd.NewRpcCmd(cmd.RpcThirdServer, third.Start) - rpcCmd.AddPortFlag() - rpcCmd.AddPrometheusPortFlag() - if err := rpcCmd.Exec(); err != nil { - util.ExitWithError(err) + if err := cmd.NewThirdRpcCmd().Exec(); err != nil { + program.ExitWithError(err) } } diff --git a/cmd/openim-rpc/openim-rpc-user/main.go b/cmd/openim-rpc/openim-rpc-user/main.go index 18adbfae57..75ab902914 100644 --- a/cmd/openim-rpc/openim-rpc-user/main.go +++ b/cmd/openim-rpc/openim-rpc-user/main.go @@ -15,16 +15,12 @@ package main import ( - "github.com/openimsdk/open-im-server/v3/internal/rpc/user" "github.com/openimsdk/open-im-server/v3/pkg/common/cmd" - util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" + "github.com/openimsdk/tools/system/program" ) func main() { - rpcCmd := cmd.NewRpcCmd(cmd.RpcUserServer, user.Start) - rpcCmd.AddPortFlag() - rpcCmd.AddPrometheusPortFlag() - if err := rpcCmd.Exec(); err != nil { - util.ExitWithError(err) + if err := cmd.NewUserRpcCmd().Exec(); err != nil { + program.ExitWithError(err) } } diff --git a/config/README_zh_CN.md b/config/README_zh_CN.md new file mode 100644 index 0000000000..6ddab06368 --- /dev/null +++ b/config/README_zh_CN.md @@ -0,0 +1,65 @@ +# OpenIM配置文件说明以及常用配置修改说明 + +## 配置文件说明 + +| Configuration File | Description | +| ------------------------------- | ------------------------------------------------------------ | +| **kafka.yml** | Kafka用户名、密码、地址等配置 | +| **redis.yml** | Redis密码、地址等配置 | +| **minio.yml** | MinIO用户名、密码、地址及外网IP域名等配置;未修改外网IP或域名可能导致图片文件发送失败 | +| **zookeeper.yml** | ZooKeeper用户、密码、地址等配置 | +| **mongodb.yml** | MongoDB用户名、密码、地址等配置 | +| **log.yml** | 日志级别及存储目录等配置 | +| **notification.yml** | 添加好友、创建群组等事件通知配置 | +| **share.yml** | OpenIM各服务所需的公共配置,如secret等 | +| **webhooks.yml** | Webhook中URL等配置 | +| **local-cache.yml** | 本地缓存配置 | +| **openim-rpc-third.yml** | openim-rpc-third服务的监听IP、端口及图片视频对象存储配置 | +| **openim-rpc-user.yml** | openim-rpc-user服务的监听IP、端口配置 | +| **openim-api.yml** | openim-api服务的监听IP、端口等配置项 | +| **openim-crontask.yml** | openim-crontask服务配置 | +| **openim-msggateway.yml** | openim-msggateway服务的监听IP、端口等配置 | +| **openim-msgtransfer.yml** | openim-msgtransfer服务配置 | +| **openim-push.yml** | openim-push服务的监听IP、端口及离线推送配置 | +| **openim-rpc-auth.yml** | openim-rpc-auth服务的监听IP、端口及token有效期等配置 | +| **openim-rpc-conversation.yml** | openim-rpc-conversation服务的监听IP、端口等配置 | +| **openim-rpc-friend.yml** | openim-rpc-friend服务的监听IP、端口等配置 | +| **openim-rpc-group.yml** | openim-rpc-group服务的监听IP、端口等配置 | +| **openim-rpc-msg.yml** | openim-rpc-msg服务的监听IP、端口及消息发送是否验证好友关系等配置 | + +## 常用配置修改 + +| 修改配置项 | 配置文件 | +| ----------------------------------------------- | ----------------------- | +| 使用minio作为图片视频文件对象存储 | `minio.yml` | +| 生产环境日志调整 | `log.yml` | +| 发送消息是否验证好友关系 | `openim-rpc-msg.yml` | +| 修改secret | `share.yml` | +| 使用oss, cos, aws, kodo作为图片视频文件对象存储 | `openim-rpc-third.yml` | +| 设置多端互踢策略 | `openim-msggateway.yml` | +| 设置离线推送 | `openim-push.yml` | + +## 启动某个OpenIM服务的多个实例 + +若要启动某个OpenIM的多个实例,只需增加对应的端口数,并修改项目根目录下的`start-config.yml`文件,重启服务即可生效。例如,启动2个`openim-rpc-user`实例的配置如下: + +```yaml +rpc: + registerIP: '' + listenIP: 0.0.0.0 + ports: [ 10110, 10111 ] + +prometheus: + enable: true + ports: [ 20100, 20101 ] +``` + +修改`start-config.yml`: + +```yaml +serviceBinaries: + openim-rpc-user: 2 +``` + + + diff --git a/config/Readme.md b/config/Readme.md deleted file mode 100644 index 72f4577a54..0000000000 --- a/config/Readme.md +++ /dev/null @@ -1,243 +0,0 @@ -# OpenIM Configuration Guide - - -* 1. [Directory Structure and File Descriptions](#DirectoryStructureandFileDescriptions) - * 1.1. [Directory Structure](#DirectoryStructure) - * 1.2. [Directory Structure Explanation](#DirectoryStructureExplanation) -* 2. [File Descriptions](#FileDescriptions) - * 2.1. [Files in the Root Directory](#FilesintheRootDirectory) - * 2.2. [Files in the `templates/` Directory](#FilesinthetemplatesDirectory) -* 3. [Configuration File Generation](#ConfigurationFileGeneration) - * 3.1. [How to Use `init-config.sh` Script](#HowtoUseinit-config.shScript) - * 3.2. [Examples of Operations](#ExamplesofOperations) - * 3.3. [Points to Note](#PointstoNote) -* 4. [Example Directory](#ExampleDirectory) - * 4.1. [Overview](#Overview) - * 4.2. [Structure](#Structure) - * 4.3. [How to Use These Examples](#HowtoUseTheseExamples) - * 4.4. [Tips for Using Example Files:](#TipsforUsingExampleFiles:) -* 5. [Configuration Item Descriptions](#ConfigurationItemDescriptions) -* 6. [Version Management and Upgrading](#VersionManagementandUpgrading) - * 6.1. [Pulling the Latest Code](#PullingtheLatestCode) - * 6.2. [Generating the Latest Example Configuration Files](#GeneratingtheLatestExampleConfigurationFiles) - * 6.3. [Comparing Configuration File Differences](#ComparingConfigurationFileDifferences) - * 6.4. [Updating Configuration Files](#UpdatingConfigurationFiles) - * 6.5. [Updating Binary Files and Restarting Services](#UpdatingBinaryFilesandRestartingServices) - * 6.6. [Best Practices for Version Management](#BestPracticesforVersionManagement) -* 7. [How to Contribute](#HowtoContribute) - * 7.1. [OpenIM Configuration Item Descriptions](#OpenIMConfigurationItemDescriptions) - * 7.2. [Modifying Template Files](#ModifyingTemplateFiles) - * 7.3. [Updating Configuration Center Scripts](#UpdatingConfigurationCenterScripts) - * 7.4. [Configuration File Generation Process](#ConfigurationFileGenerationProcess) - * 7.5. [Contribution Guidelines](#ContributionGuidelines) - * 7.6. [Submission and Review](#SubmissionandReview) - - - - - -## 1. Directory Structure and File Descriptions - -This document details the structure of the `config` directory, aiding users in understanding and managing configuration files. - -### 1.1. Directory Structure - -```bash -$ tree config -├── alertmanager.yml -├── config.yaml -├── email.tmpl -├── instance-down-rules.yml -├── notification.yaml -├── prometheus.yml -├── Readme.md -└── templates - ├── alertmanager.yml.template - ├── config.yaml.template - ├── email.tmpl.template - ├── env.template - ├── instance-down-rules.yml.template - ├── notification.yaml.template - ├── open-im-ng-example.conf - ├── prometheus-dashboard.yaml - └── prometheus.yml.template -``` - -### 1.2. Directory Structure Explanation - -- **Root Directory (`config/`)**: Contains actual configuration files and the `templates` subdirectory. -- **`templates/` Subdirectory**: Stores configuration templates for generating or updating configuration files in the root directory. - -## 2. File Descriptions - -### 2.1. Files in the Root Directory - -- **`alertmanager.yml`**: Configuration file for AlertManager, managing and setting up the alert system. -- **`config.yaml`**: The main application configuration file, covering service settings. -- **`email.tmpl`**: Template file for email notifications, defining email format and content. -- **`instance-down-rules.yml`**: Instance downtime rules configuration file for the monitoring system. -- **`notification.yaml`**: Configuration file for notification settings, defining different types of notifications. -- **`prometheus.yml`**: Configuration file for the Prometheus monitoring system, setting monitoring metrics and rules. - -### 2.2. Files in the `templates/` Directory - -- **`alertmanager.yml.template`**: Template for AlertManager configuration. -- **`config.yaml.template`**: Main configuration template for the application. -- **`email.tmpl.template`**: Template for email notifications. -- **`env.template`**: Template for environmental variable configurations, setting environment-related configurations. -- **`instance-down-rules.yml.template`**: Template for instance downtime rules. -- **`notification.yaml.template`**: Template for notification settings. -- **`open-im-ng-example.conf`**: Example configuration file for the application. -- **`prometheus-dashboard.yaml`**: Prometheus dashboard configuration file, specific to the OpenIM application. -- **`prometheus.yml.template`**: Template for Prometheus configuration. - -## 3. Configuration File Generation - -Configuration files can be automatically generated using the `make init` command or the `./scripts/init-config.sh` script. These scripts conveniently extract templates from the `templates` directory and generate or update actual configuration files in the root directory. - -### 3.1. How to Use `init-config.sh` Script - -```bash -$ ./scripts/init-config.sh --help -Usage: init-config.sh [options] -Options: - -h, --help Show this help message - --force Overwrite existing files without prompt - --skip Skip generation if file exists - --examples Generate example files - --clean-config Clean all configuration files - --clean-examples Clean all example files -``` - -### 3.2. Examples of Operations - -- Generate all template configuration files: - - ```bash - $ ./scripts/init-config.sh --examples - ``` - -- Force overwrite existing configuration files: - - ```bash - $ ./scripts/init-config.sh --force - ``` - -### 3.3. Points to Note - -- **Template files should not be directly modified**: Files in the `template` directory are templates included in source code management. Direct modification may lead to version conflicts or management issues. -- **Operations for Windows Users**: Windows users can use the `cp` command to copy files from the `template` directory to the `config/` directory and then modify the configuration items as needed. - -## 4. Example Directory - -Welcome to our project's `examples` directory! This directory contains a range of example files, showcasing various configurations and settings of our software. These examples are intended to provide you with templates that can serve as a starting point for your own configurations. - -### 4.1. Overview - -In this directory, you'll find examples suitable for a variety of use cases. Each file is a template with default values and configurations, demonstrating best practices and typical scenarios. Whether you're just getting started or looking to implement complex settings, these examples should help you get on the right track. - -### 4.2. Structure - -Here's a quick overview of the contents in this directory: - -- `env-example.yaml`: Demonstrates how to set up environmental variables. -- `openim-example.yaml`: Example configuration file for the OpenIM application. -- `prometheus-example.yml`: Example configuration for monitoring with Prometheus. -- `alertmanager-example.yml`: Template for setting up Alertmanager configuration. - -### 4.3. How to Use These Examples - -To use these examples, simply copy the relevant files to your working directory and rename them as needed (for example, removing the `-example` suffix). Then, modify the files according to your needs. - -### 4.4. Tips for Using Example Files: - -1. **Read Comments**: Each file contains comments explaining the various sections and settings. Make sure to read these comments for a better understanding of how to customize the file. -2. **Check Required Changes**: Some examples might require mandatory changes before they can be used effectively (such as setting specific environmental variables). -3. **Version Compatibility**: Ensure that the example files are compatible with the version of the software you are using. - -## 5. Configuration Item Descriptions - -## 6. Version Management and Upgrading - -When managing and upgrading the `config` directory's versions, it is crucial to ensure that the configuration files in both the local `config/` and `config/templates/` directories are kept in sync. This process can ensure that your configuration files are consistent with the latest standard templates, while also maintaining custom settings. - -### 6.1. Pulling the Latest Code - -First, ensure that your local repository is in sync with the remote repository. This can be achieved by pulling the latest code: - -```bash -$ git pull -``` - -### 6.2. Generating the Latest Example Configuration Files - -Next, generate the latest example configuration files. This can be done by running the `init-config.sh` script, using the `--examples` option to generate example files, and the `--skip` option to avoid overwriting existing configuration files: - -```bash -$ ./scripts/init-config.sh --examples --skip -``` - -### 6.3. Comparing Configuration File Differences - -Once the latest example configuration files are generated, you need to compare the configuration files in the `config/` and `config/templates/` directories to find any potential differences. This step ensures that you can identify and integrate any important updates or changes. Tools like `diff` can be helpful in completing this step: - -```bash -$ diff -ur config/ config/templates/ -``` - -### 6.4. Updating Configuration Files - -Based on the comparison results, manually update the configuration files in the `config/` directory to reflect the latest configurations in `config/templates/`. During this process, ensure to retain any custom configuration settings. - -### 6.5. Updating Binary Files and Restarting Services - -After updating the configuration files, the next step is to update any related binary files. This typically involves downloading and installing the latest version of the application or service. Depending on the specific application or service, this might involve running specific update scripts or directly downloading the latest version from official sources. - -Once the binary files are updated, the services need to be restarted to apply the new configurations. Make sure to conduct necessary checks before restarting to ensure the correctness of the configurations. - -### 6.6. Best Practices for Version Management - -- **Record Changes**: When committing changes to a version control system, ensure to log detailed change logs. -- **Stay Synced**: Regularly sync with the remote repository to ensure that your local configurations are in line with the latest developments. -- **Backup**: Backup your current configurations before making any significant changes, so that you can revert to a previous state if necessary. - -By following these steps and best practices, you can ensure effective management and smooth upgrading of your `config` directory. - -## 7. How to Contribute - -If you have an understanding of the logic behind OpenIM's configuration generation, then you will clearly know where to make modifications to contribute code. - -### 7.1. OpenIM Configuration Item Descriptions - -First, it is recommended to read the [OpenIM Configuration Items Document](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/environment.md). This will help you understand the roles of various configuration items and how they affect the operation of OpenIM. - -### 7.2. Modifying Template Files - -To contribute to OpenIM, focus on the `./deployments/templates` directory. This contains various configuration template files, which are the basis for generating the final configuration files. - -When making modifications, ensure that your changes align with OpenIM's configuration requirements and logic. This may involve adding new template files or modifying existing files to reflect new configuration options or structural changes. - -### 7.3. Updating Configuration Center Scripts - -In addition to modifying template files, pay attention to the `./scripts/install/environment.sh` script. In this script, you may need to add or modify environment variables. - -This script is responsible for defining environment variables that influence configuration generation. Therefore, any new configuration items or modifications to existing items need to be reflected here. - -### 7.4. Configuration File Generation Process - -The essence of the `make init` command is to use the environment variables defined in `/scripts/install/environment.sh` to render the template files in the `./deployments/templates` directory, thereby generating the final configuration files. - -When contributing code, ensure that your changes work smoothly in this process and do not cause errors during configuration file generation. - -### 7.5. Contribution Guidelines - -- **Code Review**: Ensure your changes have passed code review. This typically means that the code should be clear, easy to understand, and adhere to the project's coding style and best practices. -- **Testing**: Before submitting changes, conduct thorough tests to ensure new or modified configurations work as expected and do not negatively impact existing functionalities. -- **Documentation**: If you have added a new configuration option or made significant changes to an existing one, update the relevant documentation to assist other users and developers in understanding and utilizing these changes. - -### 7.6. Submission and Review - -After completing your changes, submit your code to the OpenIM repository in the form of a Pull Request (PR). The PR will be reviewed by the project maintainers and you may be asked to make further modifications or provide additional information. \ No newline at end of file diff --git a/config/kafka.yml b/config/kafka.yml new file mode 100644 index 0000000000..b1773c80a8 --- /dev/null +++ b/config/kafka.yml @@ -0,0 +1,18 @@ +username: '' +password: '' +producerAck: "" +compressType: "none" +address: [ localhost:19094 ] +toRedisTopic: "toRedis" +toMongoTopic: "toMongo" +toPushTopic: "toPush" +toRedisGroupID: redis +toMongoGroupID: mongo +toPushGroupID: push +tls: + enableTLS: false + caCrt: "" + clientCrt: "" + clientKey: "" + clientKeyPwd: "" + insecureSkipVerify: false diff --git a/config/local-cache.yml b/config/local-cache.yml new file mode 100644 index 0000000000..06e211ebb8 --- /dev/null +++ b/config/local-cache.yml @@ -0,0 +1,27 @@ +user: + topic: DELETE_CACHE_USER + slotNum: 100 + slotSize: 2000 + successExpire: 300 + failedExpire: 5 + +group: + topic: DELETE_CACHE_GROUP + slotNum: 100 + slotSize: 2000 + successExpire: 300 + failedExpire: 5 + +friend: + topic: DELETE_CACHE_FRIEND + slotNum: 100 + slotSize: 2000 + successExpire: 300 + failedExpire: 5 + +conversation: + topic: DELETE_CACHE_CONVERSATION + slotNum: 100 + slotSize: 2000 + successExpire: 300 + failedExpire: 5 diff --git a/config/log.yml b/config/log.yml new file mode 100644 index 0000000000..2194d89174 --- /dev/null +++ b/config/log.yml @@ -0,0 +1,13 @@ +# Log storage path, default is acceptable, change to a full path if modification is needed +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: false +# Whether to log in JSON format, default is acceptable +isJson: false + diff --git a/config/minio.yml b/config/minio.yml new file mode 100644 index 0000000000..0cabb7f36a --- /dev/null +++ b/config/minio.yml @@ -0,0 +1,9 @@ +bucket: "openim" +port: 10005 +accessKeyID: "root" +secretAccessKey: "openIM123" +sessionToken: '' +internalIP: localhost +externalIP: 150.109.93.151 +url: https://image.rentsoft.cn/ +publicRead: false diff --git a/config/mongodb.yml b/config/mongodb.yml new file mode 100644 index 0000000000..12f1f66a55 --- /dev/null +++ b/config/mongodb.yml @@ -0,0 +1,7 @@ +uri: '' +address: [ localhost:37017 ] +database: openim_v3 +username: openIM +password: openIM123 +maxPoolSize: 100 +maxRetry: 10 \ No newline at end of file diff --git a/config/notification.yml b/config/notification.yml new file mode 100644 index 0000000000..1afb44e467 --- /dev/null +++ b/config/notification.yml @@ -0,0 +1,354 @@ +# 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. + +# Determines if a message should be sent. If set to false, it triggers a silent sync without a message. If true, it requires triggering a conversation. +# For rpc notification, send twice: once as a message and once as a notification. +# The options field 'isNotification' indicates if it's a notification. +groupCreated: + isSendMsg: true + +# Reliability level of the message sending. +# Set to 1 to send only when online, 2 for guaranteed delivery. + reliabilityLevel: 1 + +# This setting is effective only when 'isSendMsg' is true. +# It controls whether to count unread messages. + unreadCount: false + +# Configuration for offline push notifications. + offlinePush: + # Enables or disables offline push notifications. + enable: false + + # Title for the notification when a group is created. + title: "create group title" + + # Description for the notification. + desc: "create group desc" + + # Additional information for the notification. + ext: "create group ext" + +# Content type is not added here. +# Content should use a JSON structure conforming to the protobuf format. + +groupInfoSet: + isSendMsg: false + reliabilityLevel: 1 + unreadCount: false + offlinePush: + enable: false + title: "groupInfoSet title" + desc: "groupInfoSet desc" + ext: "groupInfoSet ext" + + +joinGroupApplication: + isSendMsg: false + reliabilityLevel: 1 + unreadCount: false + offlinePush: + enable: false + title: "joinGroupApplication title" + desc: "joinGroupApplication desc" + ext: "joinGroupApplication ext" + +memberQuit: + isSendMsg: true + reliabilityLevel: 1 + unreadCount: false + offlinePush: + enable: false + title: "memberQuit title" + desc: "memberQuit desc" + ext: "memberQuit ext" + +groupApplicationAccepted: + isSendMsg: false + reliabilityLevel: 1 + unreadCount: false + offlinePush: + enable: false + title: "groupApplicationAccepted title" + desc: "groupApplicationAccepted desc" + ext: "groupApplicationAccepted ext" + +groupApplicationRejected: + isSendMsg: false + reliabilityLevel: 1 + unreadCount: false + offlinePush: + enable: false + title: "groupApplicationRejected title" + desc: "groupApplicationRejected desc" + ext: "groupApplicationRejected ext" + + +groupOwnerTransferred: + isSendMsg: true + reliabilityLevel: 1 + unreadCount: false + offlinePush: + enable: false + title: "groupOwnerTransferred title" + desc: "groupOwnerTransferred desc" + ext: "groupOwnerTransferred ext" + +memberKicked: + isSendMsg: true + reliabilityLevel: 1 + unreadCount: false + offlinePush: + enable: false + title: "memberKicked title" + desc: "memberKicked desc" + ext: "memberKicked ext" + +memberInvited: + isSendMsg: true + reliabilityLevel: 1 + unreadCount: false + offlinePush: + enable: false + title: "memberInvited title" + desc: "memberInvited desc" + ext: "memberInvited ext" + +memberEnter: + isSendMsg: true + reliabilityLevel: 1 + unreadCount: false + offlinePush: + enable: false + title: "memberEnter title" + desc: "memberEnter desc" + ext: "memberEnter ext" + +groupDismissed: + isSendMsg: true + reliabilityLevel: 1 + unreadCount: false + offlinePush: + enable: false + title: "groupDismissed title" + desc: "groupDismissed desc" + ext: "groupDismissed ext" + +groupMuted: + isSendMsg: true + reliabilityLevel: 1 + unreadCount: false + offlinePush: + enable: false + title: "groupMuted title" + desc: "groupMuted desc" + ext: "groupMuted ext" + +groupCancelMuted: + isSendMsg: true + reliabilityLevel: 1 + unreadCount: false + offlinePush: + enable: false + title: "groupCancelMuted title" + desc: "groupCancelMuted desc" + ext: "groupCancelMuted ext" + defaultTips: + tips: "group Cancel Muted" + + +groupMemberMuted: + isSendMsg: true + reliabilityLevel: 1 + unreadCount: false + offlinePush: + enable: false + title: "groupMemberMuted title" + desc: "groupMemberMuted desc" + ext: "groupMemberMuted ext" + +groupMemberCancelMuted: + isSendMsg: true + reliabilityLevel: 1 + unreadCount: false + offlinePush: + enable: false + title: "groupMemberCancelMuted title" + desc: "groupMemberCancelMuted desc" + ext: "groupMemberCancelMuted ext" + +groupMemberInfoSet: + isSendMsg: false + reliabilityLevel: 1 + unreadCount: false + offlinePush: + enable: false + title: "groupMemberInfoSet title" + desc: "groupMemberInfoSet desc" + ext: "groupMemberInfoSet ext" + +groupInfoSetAnnouncement: + isSendMsg: true + reliabilityLevel: 1 + unreadCount: false + offlinePush: + enable: false + title: "groupInfoSetAnnouncement title" + desc: "groupInfoSetAnnouncement desc" + ext: "groupInfoSetAnnouncement ext" + + +groupInfoSetName: + isSendMsg: true + reliabilityLevel: 1 + unreadCount: false + offlinePush: + enable: false + title: "groupInfoSetName title" + desc: "groupInfoSetName desc" + ext: "groupInfoSetName ext" + + +#############################friend################################# +friendApplicationAdded: + isSendMsg: false + reliabilityLevel: 1 + unreadCount: false + offlinePush: + enable: false + title: "Somebody applies to add you as a friend" + desc: "Somebody applies to add you as a friend" + ext: "Somebody applies to add you as a friend" + +friendApplicationApproved: + isSendMsg: true + reliabilityLevel: 1 + unreadCount: false + offlinePush: + enable: true + title: "Someone applies to add your friend application" + desc: "Someone applies to add your friend application" + ext: "Someone applies to add your friend application" + +friendApplicationRejected: + isSendMsg: false + reliabilityLevel: 1 + unreadCount: false + offlinePush: + enable: true + title: "Someone rejected your friend application" + desc: "Someone rejected your friend application" + ext: "Someone rejected your friend application" + +friendAdded: + isSendMsg: false + reliabilityLevel: 1 + unreadCount: false + offlinePush: + enable: true + title: "We have become friends" + desc: "We have become friends" + ext: "We have become friends" + +friendDeleted: + isSendMsg: false + reliabilityLevel: 1 + unreadCount: false + offlinePush: + enable: true + title: "deleted a friend" + desc: "deleted a friend" + ext: "deleted a friend" + +friendRemarkSet: + isSendMsg: false + reliabilityLevel: 1 + unreadCount: false + offlinePush: + enable: true + title: "Your friend's profile has been changed" + desc: "Your friend's profile has been changed" + ext: "Your friend's profile has been changed" + +blackAdded: + isSendMsg: false + reliabilityLevel: 1 + unreadCount: false + offlinePush: + enable: true + title: "blocked a user" + desc: "blocked a user" + ext: "blocked a user" + +blackDeleted: + isSendMsg: false + reliabilityLevel: 1 + unreadCount: false + offlinePush: + enable: true + title: "Remove a blocked user" + desc: "Remove a blocked user" + ext: "Remove a blocked user" + +friendInfoUpdated: + isSendMsg: false + reliabilityLevel: 1 + unreadCount: false + offlinePush: + enable: true + title: "friend info updated" + desc: "friend info updated" + ext: "friend info updated" + +#####################user######################### +userInfoUpdated: + isSendMsg: false + reliabilityLevel: 1 + unreadCount: false + offlinePush: + enable: true + title: "Remove a blocked user" + desc: "Remove a blocked user" + ext: "Remove a blocked user" + +userStatusChanged: + isSendMsg: false + reliabilityLevel: 1 + unreadCount: false + offlinePush: + enable: false + title: "user status changed" + desc: "user status changed" + ext: "user status changed" + +#####################conversation######################### +conversationChanged: + isSendMsg: false + reliabilityLevel: 1 + unreadCount: false + offlinePush: + enable: true + title: "conversation changed" + desc: "conversation changed" + ext: "conversation changed" + +conversationSetPrivate: + isSendMsg: true + reliabilityLevel: 1 + unreadCount: false + offlinePush: + enable: true + title: "burn after reading" + desc: "burn after reading" + ext: "burn after reading" diff --git a/config/openim-api.yml b/config/openim-api.yml new file mode 100644 index 0000000000..78a688fcd6 --- /dev/null +++ b/config/openim-api.yml @@ -0,0 +1,13 @@ +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, must be consistent with the number of prometheus.ports + ports: [ 10002 ] + +prometheus: + # Whether to enable prometheus + enable: true + # Prometheus listening ports, must match the number of api.ports + ports: [ 20113 ] + # This address can be accessed via a browser + grafanaURL: http://127.0.0.1:13000/ diff --git a/config/openim-crontask.yml b/config/openim-crontask.yml new file mode 100644 index 0000000000..39f730112a --- /dev/null +++ b/config/openim-crontask.yml @@ -0,0 +1,4 @@ +chatRecordsClearTime: "0 2 * * 3" +msgDestructTime: "0 2 * * *" +retainChatRecords: 365 +enableCronLocker: false diff --git a/config/openim-msggateway.yml b/config/openim-msggateway.yml new file mode 100644 index 0000000000..ad6e180cca --- /dev/null +++ b/config/openim-msggateway.yml @@ -0,0 +1,19 @@ +rpc: + registerIP: '' + ports: [ 10140 ] + +prometheus: + enable: true + ports: [ 20112 ] + +listenIP: 0.0.0.0 + +longConnSvr: + ports: [ 10001 ] + websocketMaxConnNum: 100000 + websocketMaxMsgLen: 4096 + websocketTimeout: 10 + +multiLoginPolicy: 1 + + diff --git a/config/openim-msgtransfer.yml b/config/openim-msgtransfer.yml new file mode 100644 index 0000000000..9cb1598b5b --- /dev/null +++ b/config/openim-msgtransfer.yml @@ -0,0 +1,3 @@ +prometheus: + enable: true + ports: [ 20108, 20109, 20110, 20111 ] diff --git a/config/openim-push.yml b/config/openim-push.yml new file mode 100644 index 0000000000..35e1b2c07d --- /dev/null +++ b/config/openim-push.yml @@ -0,0 +1,37 @@ +rpc: + registerIP: '' + listenIP: 0.0.0.0 + ports: [ 10170 ] + +prometheus: + enable: true + ports: [ 20107 ] + +maxConcurrentWorkers: 3 +enable: getui +geTui: + pushUrl: "https://restapi.getui.com/v2/$appId" + masterSecret: '' + appKey: '' + intent: '' + channelID: '' + channelName: '' +fcm: + serviceAccount: "x.json" +jpns: + appKey: '' + masterSecret: '' + pushURL: '' + pushIntent: '' + +iosPush: + pushSound: "xxx" + badgeCount: true + production: false + + + + + + + diff --git a/config/openim-rpc-auth.yml b/config/openim-rpc-auth.yml new file mode 100644 index 0000000000..a77b5457e8 --- /dev/null +++ b/config/openim-rpc-auth.yml @@ -0,0 +1,13 @@ +rpc: + registerIP: '' + listenIP: 0.0.0.0 + ports: [ 10160 ] + +prometheus: + enable: true + ports: [ 20106 ] + +tokenPolicy: + #token有效期,单位(天) + expire: 90 + diff --git a/config/openim-rpc-conversation.yml b/config/openim-rpc-conversation.yml new file mode 100644 index 0000000000..e2d9b6a536 --- /dev/null +++ b/config/openim-rpc-conversation.yml @@ -0,0 +1,11 @@ +rpc: + registerIP: '' + listenIP: 0.0.0.0 + ports: [ 10180 ] + +prometheus: + enable: true + ports: [ 20105 ] + + + diff --git a/config/openim-rpc-friend.yml b/config/openim-rpc-friend.yml new file mode 100644 index 0000000000..109e3f658f --- /dev/null +++ b/config/openim-rpc-friend.yml @@ -0,0 +1,8 @@ +rpc: + registerIP: '' + listenIP: 0.0.0.0 + ports: [ 10120 ] + +prometheus: + enable: true + ports: [ 20104 ] diff --git a/config/openim-rpc-group.yml b/config/openim-rpc-group.yml new file mode 100644 index 0000000000..a70d6f96e2 --- /dev/null +++ b/config/openim-rpc-group.yml @@ -0,0 +1,9 @@ +rpc: + registerIP: '' + listenIP: 0.0.0.0 + ports: [ 10150 ] + +prometheus: + enable: true + ports: [ 20103 ] + diff --git a/config/openim-rpc-msg.yml b/config/openim-rpc-msg.yml new file mode 100644 index 0000000000..de5e2324df --- /dev/null +++ b/config/openim-rpc-msg.yml @@ -0,0 +1,14 @@ +rpc: + registerIP: '' + listenIP: 0.0.0.0 + ports: [ 10130 ] + +prometheus: + enable: true + ports: [ 20102 ] + +#发消息是否需要好友验证 +friendVerify: false + + + diff --git a/config/openim-rpc-third.yml b/config/openim-rpc-third.yml new file mode 100644 index 0000000000..e3a847bf2c --- /dev/null +++ b/config/openim-rpc-third.yml @@ -0,0 +1,40 @@ +rpc: + registerIP: '' + listenIP: 0.0.0.0 + ports: [ 10190 ] + +prometheus: + enable: true + ports: [ 20101 ] + +object: + enable: "minio" + cos: + bucketURL: https://temp-1252357374.cos.ap-chengdu.myqcloud.com + secretID: '' + secretKey: '' + sessionToken: '' + publicRead: false + oss: + endpoint: "https://oss-cn-chengdu.aliyuncs.com" + bucket: "demo-9999999" + bucketURL: "https://demo-9999999.oss-cn-chengdu.aliyuncs.com" + accessKeyID: '' + accessKeySecret: '' + sessionToken: '' + publicRead: false + kodo: + endpoint: "webhook://s3.cn-east-1.qiniucs.com" + bucket: "demo-9999999" + bucketURL: "webhook://your.domain.com" + accessKeyID: '' + accessKeySecret: '' + sessionToken: '' + publicRead: false + aws: + endpoint: "''" + region: "us-east-1" + bucket: "demo-9999999" + accessKeyID: '' + accessKeySecret: '' + publicRead: false diff --git a/config/openim-rpc-user.yml b/config/openim-rpc-user.yml new file mode 100644 index 0000000000..cbfb55b6c7 --- /dev/null +++ b/config/openim-rpc-user.yml @@ -0,0 +1,17 @@ +rpc: + # API or other RPCs can access this RPC through this IP; if left blank, the internal network IP is obtained by default + registerIP: '' + # Listening IP; 0.0.0.0 means both internal and external IPs are listened to, if blank, the internal network IP is automatically obtained by default + listenIP: 0.0.0.0 + # Listening ports; if multiple are configured, multiple instances will be launched, and must be consistent with the number of prometheus.ports + ports: [ 10110 ] + +prometheus: + # Whether to enable prometheus + enable: true + # Prometheus listening ports, must be consistent with the number of rpc.ports + ports: [ 20100 ] + + + + diff --git a/config/redis.yml b/config/redis.yml new file mode 100644 index 0000000000..26becd887d --- /dev/null +++ b/config/redis.yml @@ -0,0 +1,7 @@ +address: [ localhost:16379 ] +username: '' +password: openIM123 +enablePipeline: false +clusterMode: false +db: 0 +maxRetry: 10 \ No newline at end of file diff --git a/config/share.yml b/config/share.yml new file mode 100644 index 0000000000..2abbb77a0f --- /dev/null +++ b/config/share.yml @@ -0,0 +1,15 @@ +secret: openIM123 +env: zookeeper +rpcRegisterName: + user: user + friend: friend + msg: msg + push: push + messageGateway: messageGateway + group: group + auth: auth + conversation: conversation + third: third + +imAdminUserID: [ "imAdmin" ] + diff --git a/config/templates/config.yaml.template b/config/templates/config.yaml.template index 03413c595c..5c5cfda787 100644 --- a/config/templates/config.yaml.template +++ b/config/templates/config.yaml.template @@ -1,24 +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. - -# ----------------------------------------------------------------- -# TODO: This config file is the template file -# --| source: deployments/templates/config.yaml -# --| env: scripts/install/environment -# --| target: config/config.yaml -# ----------------------------------------------------------------- - envs: discovery: zookeeper @@ -122,14 +101,14 @@ api: # minio.signEndpoint is minio public network address object: enable: "minio" - apiURL: "http://172.28.0.1:10002" + apiURL: "http://127.0.0.1:10002" minio: bucket: "openim" endpoint: "http://172.28.0.1:10005" accessKeyID: "root" secretAccessKey: "openIM123" sessionToken: '' - signEndpoint: "http://172.28.0.1:10005" + signEndpoint: "http://127.0.0.1:10005" publicRead: false cos: bucketURL: https://temp-1252357374.cos.ap-chengdu.myqcloud.com @@ -154,8 +133,8 @@ object: sessionToken: '' publicRead: false aws: - endpoint: "" - region: "" + endpoint: "''" # This might not be necessary unless you're using a custom endpoint + region: "us-east-1" bucket: "demo-9999999" accessKeyID: '' accessKeySecret: '' @@ -200,7 +179,7 @@ rpcRegisterName: # Whether to output in json format # Whether to include stack trace in logs log: - storageLocation: /workspaces/open-im-server/logs/ + storageLocation: /data/workspaces/open-im-server/_output/logs/ rotationTime: 24 remainRotationCount: 2 remainLogLevel: 6 @@ -250,9 +229,10 @@ push: # # Built-in app manager user IDs # Built-in app manager nicknames +# Attention, this configure is discarded. If you have used him before, configure your own manager: - userID: [ "openIM123456", "openIM654321", "openIMAdmin" ] - nickname: [ "system1", "system2", "system3" ] + userID: + nickname: # chatAdmin, use for send notification # @@ -336,7 +316,7 @@ callback: timeout: 5 failedContinue: true afterSendSingleMsg: - enable: true + enable: false timeout: 5 failedContinue: true beforeSendGroupMsg: @@ -521,7 +501,7 @@ callback: # The number of ports needs to be consistent with msg_transfer_service_num in script/path_info.sh prometheus: enable: true - grafanaUrl: http://172.28.0.1:13000/ + grafanaUrl: http://127.0.0.1:13000/ apiPrometheusPort: [20100] userPrometheusPort: [ 20110 ] friendPrometheusPort: [ 20120 ] @@ -534,3 +514,39 @@ prometheus: rtcPrometheusPort: [ 21300 ] thirdPrometheusPort: [ 21301 ] messageTransferPrometheusPort: [ 21400, 21401, 21402, 21403 ] # List of ports + +###################### LocalCache configuration information ###################### +# topic: redis subscriber channel +# slotNum: number of slots, multiple slots can prevent too many keys from competing for a lock +# slotSize: number of slots, the number of cached keys per slot, the overall cache quantity is slotNum * slotSize +# successExpire: successful cache time seconds +# failedExpire: failed cache time seconds +# disable local caching and annotate topic, slotNum, and slotSize +localCache: + user: + topic: DELETE_CACHE_USER + slotNum: 100 + slotSize: 2000 + successExpire: 300 + failedExpire: 5 + + group: + topic: DELETE_CACHE_GROUP + slotNum: 100 + slotSize: 2000 + successExpire: 300 + failedExpire: 5 + + friend: + topic: DELETE_CACHE_FRIEND + slotNum: 100 + slotSize: 2000 + successExpire: 300 + failedExpire: 5 + + conversation: + topic: DELETE_CACHE_CONVERSATION + slotNum: 100 + slotSize: 2000 + successExpire: 300 + failedExpire: 5 diff --git a/config/templates/env.template b/config/templates/env.template index 7a095b2bbd..1178e0f7df 100644 --- a/config/templates/env.template +++ b/config/templates/env.template @@ -25,7 +25,7 @@ # Data storage directory for persistent data. # Example: DATA_DIR=/path/to/data -DATA_DIR=/workspaces/open-im-server +DATA_DIR=/data/workspaces/open-im-server # Docker image registry. Uncomment the preferred one. # Options: ghcr.io/openimsdk, openim, registry.cn-hangzhou.aliyuncs.com/openimsdk @@ -91,7 +91,7 @@ ALERT_MANAGER_NETWORK_ADDRESS=172.28.0.14 # ============================================================================== # Local IP address of the service. Modify if necessary. # Example: OPENIM_IP=172.28.0.1, -OPENIM_IP=172.28.0.1 +OPENIM_IP=127.0.0.1 # ----- ZooKeeper Configuration ----- # Port for ZooKeeper service. @@ -100,7 +100,7 @@ ZOOKEEPER_PORT=12181 # MongoDB service port configuration. # Default: MONGO_PORT=37017 -# MONGO_PORT=37017 +MONGO_PORT=37017 # Password for MongoDB admin user. Used for service authentication. # Default: MONGO_PASSWORD=openIM123 @@ -143,7 +143,7 @@ KAFKA_LATESTMSG_REDIS_TOPIC=latestMsgToRedis # MINIO_PORT # ---------- # MINIO_PORT sets the port for the MinIO object storage service. -# Upon changing this port, the MinIO endpoint URLs in the file must be updated +# Upon changing this port, the MinIO endpoint URLs in the config/config.yaml file must be updated # to reflect this change. The endpoints include both the 'endpoint' and 'signEndpoint' # under the MinIO configuration. # diff --git a/config/templates/open-im-ng-example.conf b/config/templates/open-im-ng-example.conf index 62befa6385..2598347773 100644 --- a/config/templates/open-im-ng-example.conf +++ b/config/templates/open-im-ng-example.conf @@ -66,6 +66,7 @@ server { proxy_set_header Connection "Upgrade"; proxy_set_header X-real-ip $remote_addr; proxy_set_header X-Forwarded-For $remote_addr; + proxy_set_header X-Request-Api $scheme://$host/api; proxy_pass http://im_api/; } location ^~/grafana/ { #10007 prometheus diff --git a/config/templates/prometheus-dashboard.yaml b/config/templates/prometheus-dashboard.yaml index 2e1ae7760c..1dccbd6921 100644 --- a/config/templates/prometheus-dashboard.yaml +++ b/config/templates/prometheus-dashboard.yaml @@ -1213,7 +1213,7 @@ "editorMode": "code", "expr": "sum(rate(app_requests_total{job=~\"^($job)$\"}[$interval])) by (job)", "instant": false, - "legendFormat": "{{job}}-http", + "legendFormat": "{{job}}-webhook", "range": true, "refId": "A" }, diff --git a/config/webhooks.yml b/config/webhooks.yml new file mode 100644 index 0000000000..c7839d4f21 --- /dev/null +++ b/config/webhooks.yml @@ -0,0 +1,156 @@ +url: "webhook://127.0.0.1:10008/callbackExample" +beforeSendSingleMsg: + enable: false + timeout: 5 + failedContinue: true +beforeUpdateUserInfoEx: + enable: false + timeout: 5 + failedContinue: true +afterUpdateUserInfoEx: + enable: false + timeout: 5 +afterSendSingleMsg: + enable: false + timeout: 5 +beforeSendGroupMsg: + enable: false + timeout: 5 + failedContinue: true +beforeMsgModify: + enable: false + timeout: 5 + failedContinue: true +afterSendGroupMsg: + enable: false + timeout: 5 +afterUserOnline: + enable: false + timeout: 5 +afterUserOffline: + enable: false + timeout: 5 +afterUserKickOff: + enable: false + timeout: 5 +beforeOfflinePush: + enable: false + timeout: 5 + failedContinue: true +beforeOnlinePush: + enable: false + timeout: 5 + failedContinue: true +beforeGroupOnlinePush: + enable: false + timeout: 5 + failedContinue: true +beforeAddFriend: + enable: false + timeout: 5 + failedContinue: true +beforeUpdateUserInfo: + enable: false + timeout: 5 + failedContinue: true +afterUpdateUserInfo: + enable: false + timeout: 5 +beforeCreateGroup: + enable: false + timeout: 5 + failedContinue: true +afterCreateGroup: + enable: false + timeout: 5 +beforeMemberJoinGroup: + enable: false + timeout: 5 + failedContinue: true +beforeSetGroupMemberInfo: + enable: false + timeout: 5 + failedContinue: true +afterSetGroupMemberInfo: + enable: false + timeout: 5 +afterQuitGroup: + enable: false + timeout: 5 +afterKickGroupMember: + enable: false + timeout: 5 +afterDismissGroup: + enable: false + timeout: 5 +beforeApplyJoinGroup: + enable: false + timeout: 5 + failedContinue: true +afterGroupMsgRead: + enable: false + timeout: 5 +afterSingleMsgRead: + enable: false + timeout: 5 +beforeUserRegister: + enable: false + timeout: 5 + failedContinue: true +afterUserRegister: + enable: false + timeout: 5 +afterTransferGroupOwner: + enable: false + timeout: 5 +beforeSetFriendRemark: + enable: false + timeout: 5 + failedContinue: true +afterSetFriendRemark: + enable: false + timeout: 5 +afterGroupMsgRevoke: + enable: false + timeout: 5 +afterJoinGroup: + enable: false + timeout: 5 +beforeInviteUserToGroup: + enable: false + timeout: 5 + failedContinue: true +afterSetGroupInfo: + enable: false + timeout: 5 +beforeSetGroupInfo: + enable: false + timeout: 5 + failedContinue: true +afterRevokeMsg: + enable: false + timeout: 5 +beforeAddBlack: + enable: false + timeout: 5 + failedContinue: +afterAddFriend: + enable: false + timeout: 5 +beforeAddFriendAgree: + enable: false + timeout: 5 + failedContinue: true +afterDeleteFriend: + enable: false + timeout: 5 +beforeImportFriends: + enable: false + timeout: 5 + failedContinue: true +afterImportFriends: + enable: false + timeout: 5 +afterRemoveBlack: + enable: false + timeout: 5 diff --git a/config/zookeeper.yml b/config/zookeeper.yml new file mode 100644 index 0000000000..33f52d7ca7 --- /dev/null +++ b/config/zookeeper.yml @@ -0,0 +1,6 @@ + +schema: openim +address: [ localhost:12181 ] +username: '' +password: '' + diff --git a/deployments/charts/openim-api/templates/deployment.yaml b/deployments/charts/openim-api/templates/deployment.yaml index 3b4bf57a24..b0076393f1 100644 --- a/deployments/charts/openim-api/templates/deployment.yaml +++ b/deployments/charts/openim-api/templates/deployment.yaml @@ -48,17 +48,17 @@ spec: image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" imagePullPolicy: {{ .Values.image.pullPolicy }} ports: - - name: http + - name: webhook containerPort: 80 protocol: TCP #livenessProbe: # httpGet: # path: / - # port: http + # port: webhook #readinessProbe: # httpGet: # path: / - # port: http + # port: webhook resources: {{- toYaml .Values.resources | nindent 12 }} volumeMounts: diff --git a/deployments/charts/openim-api/templates/service.yaml b/deployments/charts/openim-api/templates/service.yaml index 3704bf35c8..74f75a25e0 100644 --- a/deployments/charts/openim-api/templates/service.yaml +++ b/deployments/charts/openim-api/templates/service.yaml @@ -22,8 +22,8 @@ spec: type: {{ .Values.service.type }} ports: - port: {{ .Values.service.port }} - targetPort: http + targetPort: webhook protocol: TCP - name: http + name: webhook selector: {{- include "openim-api.selectorLabels" . | nindent 4 }} diff --git a/deployments/charts/openim-msggateway/templates/deployment.yaml b/deployments/charts/openim-msggateway/templates/deployment.yaml index 0f5f9d06fa..e938fa9bf4 100644 --- a/deployments/charts/openim-msggateway/templates/deployment.yaml +++ b/deployments/charts/openim-msggateway/templates/deployment.yaml @@ -48,7 +48,7 @@ spec: image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" imagePullPolicy: {{ .Values.image.pullPolicy }} ports: - - name: http + - name: webhook containerPort: 80 protocol: TCP - name: rpc @@ -57,11 +57,11 @@ spec: #livenessProbe: # httpGet: # path: / - # port: http + # port: webhook #readinessProbe: # httpGet: # path: / - # port: http + # port: webhook resources: {{- toYaml .Values.resources | nindent 12 }} volumeMounts: diff --git a/deployments/charts/openim-msggateway/templates/service.yaml b/deployments/charts/openim-msggateway/templates/service.yaml index e33fce6db7..e914ee1d47 100644 --- a/deployments/charts/openim-msggateway/templates/service.yaml +++ b/deployments/charts/openim-msggateway/templates/service.yaml @@ -22,9 +22,9 @@ spec: type: {{ .Values.service.type }} ports: - port: {{ .Values.service.port }} - targetPort: http + targetPort: webhook protocol: TCP - name: http + name: webhook - port: 88 targetPort: rpc protocol: TCP diff --git a/deployments/charts/openim-msgtransfer/templates/deployment.yaml b/deployments/charts/openim-msgtransfer/templates/deployment.yaml index 2c9e24bddd..019e307d52 100644 --- a/deployments/charts/openim-msgtransfer/templates/deployment.yaml +++ b/deployments/charts/openim-msgtransfer/templates/deployment.yaml @@ -48,17 +48,17 @@ spec: image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" imagePullPolicy: {{ .Values.image.pullPolicy }} ports: - - name: http + - name: webhook containerPort: 80 protocol: TCP #livenessProbe: # httpGet: # path: / - # port: http + # port: webhook #readinessProbe: # httpGet: # path: / - # port: http + # port: webhook resources: {{- toYaml .Values.resources | nindent 12 }} volumeMounts: diff --git a/deployments/charts/openim-msgtransfer/templates/service.yaml b/deployments/charts/openim-msgtransfer/templates/service.yaml index e657f8c18f..467f7d13c5 100644 --- a/deployments/charts/openim-msgtransfer/templates/service.yaml +++ b/deployments/charts/openim-msgtransfer/templates/service.yaml @@ -22,8 +22,8 @@ spec: type: {{ .Values.service.type }} ports: - port: {{ .Values.service.port }} - targetPort: http + targetPort: webhook protocol: TCP - name: http + name: webhook selector: {{- include "openim-msgtransfer.selectorLabels" . | nindent 4 }} diff --git a/deployments/charts/openim-push/templates/deployment.yaml b/deployments/charts/openim-push/templates/deployment.yaml index 34de33e10b..86c27d14c2 100644 --- a/deployments/charts/openim-push/templates/deployment.yaml +++ b/deployments/charts/openim-push/templates/deployment.yaml @@ -48,17 +48,17 @@ spec: image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" imagePullPolicy: {{ .Values.image.pullPolicy }} ports: - - name: http + - name: webhook containerPort: 80 protocol: TCP #livenessProbe: # httpGet: # path: / - # port: http + # port: webhook #readinessProbe: # httpGet: # path: / - # port: http + # port: webhook resources: {{- toYaml .Values.resources | nindent 12 }} volumeMounts: diff --git a/deployments/charts/openim-push/templates/service.yaml b/deployments/charts/openim-push/templates/service.yaml index b38c353753..c2ef8db358 100644 --- a/deployments/charts/openim-push/templates/service.yaml +++ b/deployments/charts/openim-push/templates/service.yaml @@ -22,8 +22,8 @@ spec: type: {{ .Values.service.type }} ports: - port: {{ .Values.service.port }} - targetPort: http + targetPort: webhook protocol: TCP - name: http + name: webhook selector: {{- include "openim-push.selectorLabels" . | nindent 4 }} diff --git a/deployments/charts/openim-rpc-auth/templates/deployment.yaml b/deployments/charts/openim-rpc-auth/templates/deployment.yaml index 2021627754..98c43ecb75 100644 --- a/deployments/charts/openim-rpc-auth/templates/deployment.yaml +++ b/deployments/charts/openim-rpc-auth/templates/deployment.yaml @@ -48,17 +48,17 @@ spec: image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" imagePullPolicy: {{ .Values.image.pullPolicy }} ports: - - name: http + - name: webhook containerPort: 80 protocol: TCP #livenessProbe: # httpGet: # path: / - # port: http + # port: webhook #readinessProbe: # httpGet: # path: / - # port: http + # port: webhook resources: {{- toYaml .Values.resources | nindent 12 }} volumeMounts: diff --git a/deployments/charts/openim-rpc-auth/templates/service.yaml b/deployments/charts/openim-rpc-auth/templates/service.yaml index 3674da014e..7855123470 100644 --- a/deployments/charts/openim-rpc-auth/templates/service.yaml +++ b/deployments/charts/openim-rpc-auth/templates/service.yaml @@ -22,8 +22,8 @@ spec: type: {{ .Values.service.type }} ports: - port: {{ .Values.service.port }} - targetPort: http + targetPort: webhook protocol: TCP - name: http + name: webhook selector: {{- include "openim-rpc-auth.selectorLabels" . | nindent 4 }} diff --git a/deployments/charts/openim-rpc-conversation/templates/deployment.yaml b/deployments/charts/openim-rpc-conversation/templates/deployment.yaml index 01721aa30a..6dcb001f4b 100644 --- a/deployments/charts/openim-rpc-conversation/templates/deployment.yaml +++ b/deployments/charts/openim-rpc-conversation/templates/deployment.yaml @@ -48,17 +48,17 @@ spec: image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" imagePullPolicy: {{ .Values.image.pullPolicy }} ports: - - name: http + - name: webhook containerPort: 80 protocol: TCP #livenessProbe: # httpGet: # path: / - # port: http + # port: webhook #readinessProbe: # httpGet: # path: / - # port: http + # port: webhook resources: {{- toYaml .Values.resources | nindent 12 }} volumeMounts: diff --git a/deployments/charts/openim-rpc-conversation/templates/service.yaml b/deployments/charts/openim-rpc-conversation/templates/service.yaml index f906735846..8559c4d11d 100644 --- a/deployments/charts/openim-rpc-conversation/templates/service.yaml +++ b/deployments/charts/openim-rpc-conversation/templates/service.yaml @@ -22,8 +22,8 @@ spec: type: {{ .Values.service.type }} ports: - port: {{ .Values.service.port }} - targetPort: http + targetPort: webhook protocol: TCP - name: http + name: webhook selector: {{- include "openim-rpc-conversation.selectorLabels" . | nindent 4 }} diff --git a/deployments/charts/openim-rpc-friend/templates/deployment.yaml b/deployments/charts/openim-rpc-friend/templates/deployment.yaml index a571888284..01251cdfac 100644 --- a/deployments/charts/openim-rpc-friend/templates/deployment.yaml +++ b/deployments/charts/openim-rpc-friend/templates/deployment.yaml @@ -48,17 +48,17 @@ spec: image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" imagePullPolicy: {{ .Values.image.pullPolicy }} ports: - - name: http + - name: webhook containerPort: 80 protocol: TCP #livenessProbe: # httpGet: # path: / - # port: http + # port: webhook #readinessProbe: # httpGet: # path: / - # port: http + # port: webhook resources: {{- toYaml .Values.resources | nindent 12 }} volumeMounts: diff --git a/deployments/charts/openim-rpc-friend/templates/service.yaml b/deployments/charts/openim-rpc-friend/templates/service.yaml index e445d561f5..892a007dd7 100644 --- a/deployments/charts/openim-rpc-friend/templates/service.yaml +++ b/deployments/charts/openim-rpc-friend/templates/service.yaml @@ -22,8 +22,8 @@ spec: type: {{ .Values.service.type }} ports: - port: {{ .Values.service.port }} - targetPort: http + targetPort: webhook protocol: TCP - name: http + name: webhook selector: {{- include "openim-rpc-friend.selectorLabels" . | nindent 4 }} diff --git a/deployments/charts/openim-rpc-group/templates/deployment.yaml b/deployments/charts/openim-rpc-group/templates/deployment.yaml index 406d0b3427..e738f33be2 100644 --- a/deployments/charts/openim-rpc-group/templates/deployment.yaml +++ b/deployments/charts/openim-rpc-group/templates/deployment.yaml @@ -48,17 +48,17 @@ spec: image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" imagePullPolicy: {{ .Values.image.pullPolicy }} ports: - - name: http + - name: webhook containerPort: 80 protocol: TCP #livenessProbe: # httpGet: # path: / - # port: http + # port: webhook #readinessProbe: # httpGet: # path: / - # port: http + # port: webhook resources: {{- toYaml .Values.resources | nindent 12 }} volumeMounts: diff --git a/deployments/charts/openim-rpc-group/templates/service.yaml b/deployments/charts/openim-rpc-group/templates/service.yaml index fc6f760603..42e1f78ca5 100644 --- a/deployments/charts/openim-rpc-group/templates/service.yaml +++ b/deployments/charts/openim-rpc-group/templates/service.yaml @@ -22,8 +22,8 @@ spec: type: {{ .Values.service.type }} ports: - port: {{ .Values.service.port }} - targetPort: http + targetPort: webhook protocol: TCP - name: http + name: webhook selector: {{- include "openim-rpc-group.selectorLabels" . | nindent 4 }} diff --git a/deployments/charts/openim-rpc-msg/templates/deployment.yaml b/deployments/charts/openim-rpc-msg/templates/deployment.yaml index d764294ea0..f7267fabbc 100644 --- a/deployments/charts/openim-rpc-msg/templates/deployment.yaml +++ b/deployments/charts/openim-rpc-msg/templates/deployment.yaml @@ -48,17 +48,17 @@ spec: image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" imagePullPolicy: {{ .Values.image.pullPolicy }} ports: - - name: http + - name: webhook containerPort: 80 protocol: TCP #livenessProbe: # httpGet: # path: / - # port: http + # port: webhook #readinessProbe: # httpGet: # path: / - # port: http + # port: webhook resources: {{- toYaml .Values.resources | nindent 12 }} volumeMounts: diff --git a/deployments/charts/openim-rpc-msg/templates/service.yaml b/deployments/charts/openim-rpc-msg/templates/service.yaml index 953b89d5dd..ba403d5abf 100644 --- a/deployments/charts/openim-rpc-msg/templates/service.yaml +++ b/deployments/charts/openim-rpc-msg/templates/service.yaml @@ -22,8 +22,8 @@ spec: type: {{ .Values.service.type }} ports: - port: {{ .Values.service.port }} - targetPort: http + targetPort: webhook protocol: TCP - name: http + name: webhook selector: {{- include "openim-rpc-msg.selectorLabels" . | nindent 4 }} diff --git a/deployments/charts/openim-rpc-third/templates/deployment.yaml b/deployments/charts/openim-rpc-third/templates/deployment.yaml index e4f47de576..7794155359 100644 --- a/deployments/charts/openim-rpc-third/templates/deployment.yaml +++ b/deployments/charts/openim-rpc-third/templates/deployment.yaml @@ -48,17 +48,17 @@ spec: image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" imagePullPolicy: {{ .Values.image.pullPolicy }} ports: - - name: http + - name: webhook containerPort: 80 protocol: TCP #livenessProbe: # httpGet: # path: / - # port: http + # port: webhook #readinessProbe: # httpGet: # path: / - # port: http + # port: webhook resources: {{- toYaml .Values.resources | nindent 12 }} volumeMounts: diff --git a/deployments/charts/openim-rpc-third/templates/service.yaml b/deployments/charts/openim-rpc-third/templates/service.yaml index f467992a21..af112794e8 100644 --- a/deployments/charts/openim-rpc-third/templates/service.yaml +++ b/deployments/charts/openim-rpc-third/templates/service.yaml @@ -22,8 +22,8 @@ spec: type: {{ .Values.service.type }} ports: - port: {{ .Values.service.port }} - targetPort: http + targetPort: webhook protocol: TCP - name: http + name: webhook selector: {{- include "openim-rpc-third.selectorLabels" . | nindent 4 }} diff --git a/deployments/charts/openim-rpc-user/templates/deployment.yaml b/deployments/charts/openim-rpc-user/templates/deployment.yaml index 62106e5a25..26497d837e 100644 --- a/deployments/charts/openim-rpc-user/templates/deployment.yaml +++ b/deployments/charts/openim-rpc-user/templates/deployment.yaml @@ -48,17 +48,17 @@ spec: image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" imagePullPolicy: {{ .Values.image.pullPolicy }} ports: - - name: http + - name: webhook containerPort: 80 protocol: TCP #livenessProbe: # httpGet: # path: / - # port: http + # port: webhook #readinessProbe: # httpGet: # path: / - # port: http + # port: webhook resources: {{- toYaml .Values.resources | nindent 12 }} volumeMounts: diff --git a/deployments/charts/openim-rpc-user/templates/service.yaml b/deployments/charts/openim-rpc-user/templates/service.yaml index f89be1c440..af8a53e195 100644 --- a/deployments/charts/openim-rpc-user/templates/service.yaml +++ b/deployments/charts/openim-rpc-user/templates/service.yaml @@ -22,8 +22,8 @@ spec: type: {{ .Values.service.type }} ports: - port: {{ .Values.service.port }} - targetPort: http + targetPort: webhook protocol: TCP - name: http + name: webhook selector: {{- include "openim-rpc-user.selectorLabels" . | nindent 4 }} diff --git a/deployments/templates/config.yaml b/deployments/templates/config.yaml index 5da6d5d0b1..fee0bf90a4 100644 --- a/deployments/templates/config.yaml +++ b/deployments/templates/config.yaml @@ -323,7 +323,7 @@ iosPush: # Timeout in seconds # Whether to continue execution if callback fails callback: - url: "http://127.0.0.1:10008/callbackExample" + url: "webhook://127.0.0.1:10008/callbackExample" beforeSendSingleMsg: enable: ${CALLBACK_ENABLE} timeout: ${CALLBACK_TIMEOUT} diff --git a/docker-compose-1.yml b/docker-compose-1.yml deleted file mode 100644 index ed852fd299..0000000000 --- a/docker-compose-1.yml +++ /dev/null @@ -1,298 +0,0 @@ -#fixme Clone openIM Server project before using docker-compose,project address:https://github.com/openimsdk/open-im-server.git -# The command that triggers this file to pull the image is "docker compose up -f" -version: '3' - -networks: - server: - driver: bridge - ipam: - driver: default - config: - - subnet: '${DOCKER_BRIDGE_SUBNET:-172.28.0.0/16}' - gateway: '${DOCKER_BRIDGE_GATEWAY:-172.28.0.1}' - -services: - mongodb: - image: mongo:${MONGODB_IMAGE_VERSION-6.0.2} - ports: - - "${MONGO_PORT:-37017}:27017" - container_name: mongo - command: ["/bin/bash", "-c", "/docker-entrypoint-initdb.d/mongo-init.sh || true; docker-entrypoint.sh mongod --wiredTigerCacheSizeGB 1 --auth"] - volumes: - - "${DATA_DIR:-./}/components/mongodb/data/db:/data/db" - - "${DATA_DIR:-./}/components/mongodb/data/logs:/data/logs" - - "${DATA_DIR:-./}/components/mongodb/data/conf:/etc/mongo" - - "./scripts/mongo-init.sh:/docker-entrypoint-initdb.d/mongo-init.sh:ro" - environment: - - TZ=Asia/Shanghai - - wiredTigerCacheSizeGB=1 - - MONGO_INITDB_ROOT_USERNAME=${MONGO_USERNAME:-root} - - MONGO_INITDB_ROOT_PASSWORD=${MONGO_PASSWORD:-openIM123} - - MONGO_INITDB_DATABASE=${MONGO_DATABASE:-openim_v3} - - MONGO_OPENIM_USERNAME=${MONGO_OPENIM_USERNAME:-openIM} # Non-root username - - MONGO_OPENIM_PASSWORD=${MONGO_OPENIM_PASSWORD:-openIM123456} # Non-root password - restart: always - networks: - server: - ipv4_address: ${MONGO_NETWORK_ADDRESS:-172.28.0.2} - - redis: - image: redis:${REDIS_IMAGE_VERSION:-7.0.0} - container_name: redis - ports: - - "${REDIS_PORT:-16379}:6379" - volumes: - - "${DATA_DIR:-./}/components/redis/data:/data" - - "${DATA_DIR:-./}/components/redis/config/redis.conf:/usr/local/redis/config/redis.conf" - environment: - TZ: Asia/Shanghai - restart: always - sysctls: - net.core.somaxconn: 1024 - command: redis-server --requirepass ${REDIS_PASSWORD:-openIM123} --appendonly yes - networks: - server: - ipv4_address: ${REDIS_NETWORK_ADDRESS:-172.28.0.3} - - zookeeper: - image: bitnami/zookeeper:${ZOOKEEPER_IMAGE_VERSION:-3.8} - container_name: zookeeper - ports: - - "${ZOOKEEPER_PORT:-12181}:2181" - volumes: - - "/etc/localtime:/etc/localtime" - environment: - - ALLOW_ANONYMOUS_LOGIN=yes - - TZ="Asia/Shanghai" - restart: always - networks: - server: - ipv4_address: ${ZOOKEEPER_NETWORK_ADDRESS:-172.28.0.5} - - kafka: - image: 'bitnami/kafka:${KAFKA_IMAGE_VERSION:-3.5.1}' - container_name: kafka - restart: always - user: ${KAFKA_USER:-root} - ports: - - "${KAFKA_PORT:-19094}:9094" - volumes: - - ./scripts/create-topic.sh:/opt/bitnami/kafka/create-topic.sh - - "${DATA_DIR:-./}/components/kafka:/bitnami/kafka" - command: > - bash -c "/opt/bitnami/scripts/kafka/run.sh & sleep 5; /opt/bitnami/kafka/create-topic.sh; wait" - environment: - - TZ=Asia/Shanghai - - KAFKA_CFG_NODE_ID=0 - - KAFKA_CFG_PROCESS_ROLES=controller,broker - - KAFKA_CFG_CONTROLLER_QUORUM_VOTERS=0@:9093 - - KAFKA_CFG_LISTENERS=PLAINTEXT://:9092,CONTROLLER://:9093,EXTERNAL://:9094 - - KAFKA_CFG_ADVERTISED_LISTENERS=PLAINTEXT://kafka:9092,EXTERNAL://${DOCKER_BRIDGE_GATEWAY:-172.28.0.1}:${KAFKA_PORT:-19094} - # - KAFKA_CFG_ADVERTISED_LISTENERS=PLAINTEXT://kafka:9092,EXTERNAL://127.0.0.1:${KAFKA_PORT:-19094} # Mac Deployment - - KAFKA_CFG_LISTENER_SECURITY_PROTOCOL_MAP=CONTROLLER:PLAINTEXT,EXTERNAL:PLAINTEXT,PLAINTEXT:PLAINTEXT - - KAFKA_CFG_CONTROLLER_LISTENER_NAMES=CONTROLLER - networks: - server: - ipv4_address: ${KAFKA_NETWORK_ADDRESS:-172.28.0.4} - - minio: - image: minio/minio:${MINIO_IMAGE_VERSION:-RELEASE.2024-01-11T07-46-16Z} - ports: - - "${MINIO_PORT:-10005}:9000" - - "9090:9090" - container_name: minio - volumes: - - "${DATA_DIR:-./}/components/mnt/data:/data" - - "${DATA_DIR:-./}/components/mnt/config:/root/.minio" - environment: - MINIO_ROOT_USER: "${MINIO_ACCESS_KEY:-root}" - MINIO_ROOT_PASSWORD: "${MINIO_SECRET_KEY:-openIM123}" - restart: always - command: minio server /data --console-address ':9090' - networks: - server: - ipv4_address: ${MINIO_NETWORK_ADDRESS:-172.28.0.6} - - openim-web: - image: ${IMAGE_REGISTRY:-ghcr.io/openimsdk}/openim-web:${OPENIM_WEB_IMAGE_VERSION:-v3.5.0-docker} - container_name: openim-web - platform: linux/amd64 - restart: always - ports: - - "${OPENIM_WEB_PORT:-11001}:80" - networks: - server: - ipv4_address: ${OPENIM_WEB_NETWORK_ADDRESS:-172.28.0.7} - - openim-admin: - # https://github.com/openimsdk/open-im-server/issues/1662 - image: ${IMAGE_REGISTRY:-ghcr.io/openimsdk}/openim-admin:${ADMIN_FRONT_VERSION:-toc-base-open-docker.35} - container_name: openim-admin - platform: linux/amd64 - restart: always - ports: - - "${OPENIM_ADMIN_FRONT_PORT:-11002}:80" - networks: - server: - ipv4_address: ${OPENIM_ADMIN_FRONT_NETWORK_ADDRESS:-172.28.0.13} - - prometheus: - image: prom/prometheus - container_name: prometheus - hostname: prometheus - restart: always - volumes: - - "${DATA_DIR:-./}/config/instance-down-rules.yml:/etc/prometheus/instance-down-rules.yml" - - "${DATA_DIR:-./}/config/prometheus.yml:/etc/prometheus/prometheus.yml" - ports: - - "${PROMETHEUS_PORT:-19090}:9090" - networks: - server: - ipv4_address: ${PROMETHEUS_NETWORK_ADDRESS:-172.28.0.10} - - alertmanager: - image: prom/alertmanager - container_name: alertmanager - hostname: alertmanager - restart: always - volumes: - - ${DATA_DIR:-./}/config/alertmanager.yml:/etc/alertmanager/alertmanager.yml - - ${DATA_DIR:-./}/config/email.tmpl:/etc/alertmanager/email.tmpl - ports: - - "${ALERT_MANAGER_PORT:-19093}:9093" - networks: - server: - ipv4_address: ${ALERT_MANAGER_NETWORK_ADDRESS:-172.28.0.14} - - grafana: - image: grafana/grafana - container_name: grafana - hostname: grafana - user: root - restart: always - ports: - - "${GRAFANA_PORT:-13000}:3000" - volumes: - - "${DATA_DIR:-./}/components/grafana:/var/lib/grafana" - networks: - server: - ipv4_address: ${GRAFANA_NETWORK_ADDRESS:-172.28.0.11} - - node-exporter: - image: quay.io/prometheus/node-exporter - container_name: node-exporter - hostname: node-exporter - restart: always - ports: - - "${NODE_EXPORTER_PORT:-19100}:9100" - networks: - server: - ipv4_address: ${NODE_EXPORTER_NETWORK_ADDRESS:-172.28.0.12} - -### Source code deployment does not require pulling the following mirrors - - # openim-server: - # image: ${IMAGE_REGISTRY:-ghcr.io/openimsdk}/openim-server:${SERVER_IMAGE_VERSION:-main} - # container_name: openim-server - # ports: - # - "${OPENIM_WS_PORT:-10001}:${OPENIM_WS_PORT:-10001}" - # - "${API_OPENIM_PORT:-10002}:${API_OPENIM_PORT:-10002}" - # - "${API_PROM_PORT:-20100}:${API_PROM_PORT:-20100}" - # - "${USER_PROM_PORT:-20110}:${USER_PROM_PORT:-20110}" - # - "${FRIEND_PROM_PORT:-20120}:${FRIEND_PROM_PORT:-20120}" - # - "${MESSAGE_PROM_PORT:-20130}:${MESSAGE_PROM_PORT:-20130}" - # - "${MSG_GATEWAY_PROM_PORT:-20140}:${MSG_GATEWAY_PROM_PORT:-20140}" - # - "${GROUP_PROM_PORT:-20150}:${GROUP_PROM_PORT:-20150}" - # - "${AUTH_PROM_PORT:-20160}:${AUTH_PROM_PORT:-20160}" - # - "${PUSH_PROM_PORT:-20170}:${PUSH_PROM_PORT:-20170}" - # - "${CONVERSATION_PROM_PORT:-20230}:${CONVERSATION_PROM_PORT:-20230}" - # - "${RTC_PROM_PORT:-21300}:${RTC_PROM_PORT:-21300}" - # - "${THIRD_PROM_PORT:-21301}:${THIRD_PROM_PORT:-21301}" - # - "21400-21403:21400-21403" - # healthcheck: - # test: ["CMD", "/openim/openim-server/scripts/check-all.sh"] - # interval: 120s - # timeout: 30s - # retries: 5 - # env_file: - # - .env - # environment: - # - OPENIM_IP=${OPENIM_IP:-127.0.0.1} - # volumes: - # - "${DATA_DIR:-./}/openim-server/logs:/openim/openim-server/logs" - # - "${DATA_DIR:-./}/openim-server/_output/logs:/openim/openim-server/_output/logs" - # - "${DATA_DIR:-./}/openim-server/config:/openim/openim-server/config" - # restart: always - # depends_on: - # - kafka - # - mysql - # - mongodb - # - redis - # - minio - # logging: - # driver: json-file - # options: - # max-size: "1g" - # max-file: "2" - # networks: - # server: - # ipv4_address: ${OPENIM_SERVER_NETWORK_ADDRESS:-172.28.0.8} - - ### TODO: mysql is required to deploy the openim-chat component - # mysql: - # image: mysql:${MYSQL_IMAGE_VERSION:-5.7} - # platform: linux/amd64 - # ports: - # - "${MYSQL_PORT:-13306}:3306" - # container_name: mysql - # volumes: - # - "${DATA_DIR:-./}/components/mysql/data:/var/lib/mysql" - # - "/etc/localtime:/etc/localtime" - # environment: - # MYSQL_ROOT_PASSWORD: "${MYSQL_PASSWORD:-openIM123}" - # restart: always - # networks: - # server: - # ipv4_address: ${MYSQL_NETWORK_ADDRESS:-172.28.0.15} - - # openim-chat: - # image: ${IMAGE_REGISTRY:-ghcr.io/openimsdk}/openim-chat:${CHAT_IMAGE_VERSION:-main} - # container_name: openim-chat - # healthcheck: - # test: ["CMD", "/openim/openim-chat/scripts/check_all.sh"] - # interval: 60s - # timeout: 30s - # retries: 5 - # env_file: - # - .env - # environment: - # - ZOOKEEPER_ADDRESS=${DOCKER_BRIDGE_GATEWAY:-172.28.0.1} - # - ZOOKEEPER_PORT=${ZOOKEEPER_PORT:-12181} - # - OPENIM_SERVER_ADDRESS=http://${OPENIM_SERVER_ADDRESS:-172.28.0.1} - # - API_OPENIM_PORT=${API_OPENIM_PORT:-10002} - # - MYSQL_ADDRESS=${DOCKER_BRIDGE_GATEWAY:-172.28.0.1} - # - MYSQL_PORT=${MYSQL_PORT:-13306} - # - REDIS_ADDRESS=${DOCKER_BRIDGE_GATEWAY:-172.28.0.1} - # - REDIS_PORT=${REDIS_PORT:-16379} - # ports: - # - "${OPENIM_CHAT_API_PORT:-10008}:10008" - # - "${OPENIM_ADMIN_API_PORT:-10009}:10009" - # volumes: - # - "${DATA_DIR:-./}/components/openim-chat/logs:/openim/openim-chat/logs" - # - "${DATA_DIR:-./}/components/openim-chat/_output/logs:/openim/openim-chat/_output/logs" - # - "${DATA_DIR:-./}/components/openim-chat/config:/openim/openim-chat/config" - # restart: always - # # user: root:root - # depends_on: - # - mysql - # - kafka - # - redis - # - zookeeper - # logging: - # driver: json-file - # options: - # max-size: "1g" - # max-file: "2" - # networks: - # server: - # ipv4_address: ${OPENIM_CHAT_NETWORK_ADDRESS:-172.28.0.9} diff --git a/docker-compose.yml b/docker-compose.yml index a983acbaf1..11cc7ff132 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,282 +1,120 @@ -#fixme Clone openIM Server project before using docker-compose,project address:https://github.com/openimsdk/open-im-server.git -# The command that triggers this file to pull the image is "docker compose up -d". version: '3' networks: - server: + openim: driver: bridge - ipam: - driver: default - config: - - subnet: '${DOCKER_BRIDGE_SUBNET:-172.28.0.0/16}' - gateway: '${DOCKER_BRIDGE_GATEWAY:-172.28.0.1}' services: mongodb: - image: mongo:${MONGODB_IMAGE_VERSION-6.0.2} + image: "${MONGO_IMAGE}" ports: - - "${MONGO_PORT:-37017}:27017" + - "37017:27017" container_name: mongo - command: ["/bin/bash", "-c", "/docker-entrypoint-initdb.d/mongo-init.sh || true; docker-entrypoint.sh mongod --wiredTigerCacheSizeGB 1 --auth"] + command: ["/bin/bash", "-c", "/docker-entrypoint-initdb.d/mongo-init.sh; docker-entrypoint.sh mongod --wiredTigerCacheSizeGB 1 --auth"] volumes: - - "${DATA_DIR:-./}/components/mongodb/data/db:/data/db" - - "${DATA_DIR:-./}/components/mongodb/data/logs:/data/logs" - - "${DATA_DIR:-./}/components/mongodb/data/conf:/etc/mongo" + - "${DATA_DIR}/components/mongodb/data/db:/data/db" + - "${DATA_DIR}/components/mongodb/data/logs:/data/logs" + - "${DATA_DIR}/components/mongodb/data/conf:/etc/mongo" - "./scripts/mongo-init.sh:/docker-entrypoint-initdb.d/mongo-init.sh:ro" environment: - TZ=Asia/Shanghai - wiredTigerCacheSizeGB=1 - - MONGO_INITDB_ROOT_USERNAME=${MONGO_USERNAME:-root} - - MONGO_INITDB_ROOT_PASSWORD=${MONGO_PASSWORD:-openIM123} - - MONGO_INITDB_DATABASE=${MONGO_DATABASE:-openim_v3} - - MONGO_OPENIM_USERNAME=${MONGO_OPENIM_USERNAME:-openIM} # Non-root username - - MONGO_OPENIM_PASSWORD=${MONGO_OPENIM_PASSWORD:-openIM123456} # Non-root password + - MONGO_INITDB_ROOT_USERNAME=root + - MONGO_INITDB_ROOT_PASSWORD=openIM123 + - MONGO_INITDB_DATABASE=openim_v3 + - MONGO_OPENIM_USERNAME=openIM + - MONGO_OPENIM_PASSWORD=openIM123 restart: always networks: - server: - ipv4_address: ${MONGO_NETWORK_ADDRESS:-172.28.0.2} + - openim redis: - image: redis:${REDIS_IMAGE_VERSION:-7.0.0} + image: "${REDIS_IMAGE}" container_name: redis ports: - - "${REDIS_PORT:-16379}:6379" + - "16379:6379" volumes: - - "${DATA_DIR:-./}/components/redis/data:/data" - - "${DATA_DIR:-./}/components/redis/config/redis.conf:/usr/local/redis/config/redis.conf" + - "${DATA_DIR}/components/redis/data:/data" + - "${DATA_DIR}/components/redis/config/redis.conf:/usr/local/redis/config/redis.conf" environment: TZ: Asia/Shanghai restart: always sysctls: net.core.somaxconn: 1024 - command: redis-server --requirepass ${REDIS_PASSWORD:-openIM123} --appendonly yes + command: redis-server /usr/local/redis/config/redis.conf --requirepass openIM123 --appendonly yes networks: - server: - ipv4_address: ${REDIS_NETWORK_ADDRESS:-172.28.0.3} + - openim zookeeper: - image: bitnami/zookeeper:${ZOOKEEPER_IMAGE_VERSION:-3.8} + image: "${ZOOKEEPER_IMAGE}" container_name: zookeeper ports: - - "${ZOOKEEPER_PORT:-12181}:2181" - volumes: - - "/etc/localtime:/etc/localtime" + - "12181:2181" environment: - - ALLOW_ANONYMOUS_LOGIN=yes - - TZ="Asia/Shanghai" + TZ: "Asia/Shanghai" + ALLOW_ANONYMOUS_LOGIN: "yes" restart: always networks: - server: - ipv4_address: ${ZOOKEEPER_NETWORK_ADDRESS:-172.28.0.5} + - openim kafka: - image: 'bitnami/kafka:${KAFKA_IMAGE_VERSION:-3.5.1}' + image: "${KAFKA_IMAGE}" container_name: kafka restart: always - user: ${KAFKA_USER:-root} ports: - - "${KAFKA_PORT:-19094}:9094" + - "19094:9094" volumes: - ./scripts/create-topic.sh:/opt/bitnami/kafka/create-topic.sh - - "${DATA_DIR:-./}/components/kafka:/bitnami/kafka" + - "${DATA_DIR}/components/kafka:/bitnami/kafka" command: > - bash -c "/opt/bitnami/scripts/kafka/run.sh & sleep 5; /opt/bitnami/kafka/create-topic.sh; wait" + bash -c "/opt/bitnami/scripts/kafka/run.sh & /opt/bitnami/kafka/create-topic.sh; wait" environment: - - TZ=Asia/Shanghai - - KAFKA_CFG_NODE_ID=0 - - KAFKA_CFG_PROCESS_ROLES=controller,broker - - KAFKA_CFG_CONTROLLER_QUORUM_VOTERS=0@:9093 - - KAFKA_CFG_LISTENERS=PLAINTEXT://:9092,CONTROLLER://:9093,EXTERNAL://:9094 - - KAFKA_CFG_ADVERTISED_LISTENERS=PLAINTEXT://kafka:9092,EXTERNAL://${DOCKER_BRIDGE_GATEWAY:-172.28.0.1}:${KAFKA_PORT:-19094} - # - KAFKA_CFG_ADVERTISED_LISTENERS=PLAINTEXT://kafka:9092,EXTERNAL://127.0.0.1:${KAFKA_PORT:-19094} # Mac Deployment - - KAFKA_CFG_LISTENER_SECURITY_PROTOCOL_MAP=CONTROLLER:PLAINTEXT,EXTERNAL:PLAINTEXT,PLAINTEXT:PLAINTEXT - - KAFKA_CFG_CONTROLLER_LISTENER_NAMES=CONTROLLER + TZ: Asia/Shanghai + KAFKA_CFG_NODE_ID: 0 + KAFKA_CFG_PROCESS_ROLES: controller,broker + KAFKA_CFG_CONTROLLER_QUORUM_VOTERS: 0@kafka:9093 + KAFKA_CFG_LISTENERS: PLAINTEXT://:9092,CONTROLLER://:9093,EXTERNAL://:9094 + KAFKA_CFG_ADVERTISED_LISTENERS: PLAINTEXT://kafka:9092,EXTERNAL://localhost:19094 + KAFKA_CFG_LISTENER_SECURITY_PROTOCOL_MAP: CONTROLLER:PLAINTEXT,EXTERNAL:PLAINTEXT,PLAINTEXT:PLAINTEXT + KAFKA_CFG_CONTROLLER_LISTENER_NAMES: CONTROLLER networks: - server: - ipv4_address: ${KAFKA_NETWORK_ADDRESS:-172.28.0.4} + - openim + minio: - image: minio/minio:${MINIO_IMAGE_VERSION:-RELEASE.2024-01-11T07-46-16Z} + image: "${MINIO_IMAGE}" ports: - - "${MINIO_PORT:-10005}:9000" - - "9090:9090" + - "10005:9000" + - "19090:9090" container_name: minio volumes: - - "${DATA_DIR:-./}/components/mnt/data:/data" - - "${DATA_DIR:-./}/components/mnt/config:/root/.minio" + - "${DATA_DIR}/components/mnt/data:/data" + - "${DATA_DIR}/components/mnt/config:/root/.minio" environment: - MINIO_ROOT_USER: "${MINIO_ACCESS_KEY:-root}" - MINIO_ROOT_PASSWORD: "${MINIO_SECRET_KEY:-openIM123}" + TZ: Asia/Shanghai + MINIO_ROOT_USER: root + MINIO_ROOT_PASSWORD: openIM123 restart: always command: minio server /data --console-address ':9090' networks: - server: - ipv4_address: ${MINIO_NETWORK_ADDRESS:-172.28.0.6} + - openim - openim-web: - image: ${IMAGE_REGISTRY:-ghcr.io/openimsdk}/openim-web:${OPENIM_WEB_IMAGE_VERSION:-v3.5.0-docker} - container_name: openim-web - platform: linux/amd64 + openim-web-front: + image: ${OPENIM_WEB_FRONT_IMAGE} + container_name: openim-web-front restart: always ports: - - "${OPENIM_WEB_PORT:-11001}:80" + - "11001:80" networks: - server: - ipv4_address: ${OPENIM_WEB_NETWORK_ADDRESS:-172.28.0.7} + - openim - openim-admin: - # https://github.com/openimsdk/open-im-server/issues/1662 - image: ${IMAGE_REGISTRY:-ghcr.io/openimsdk}/openim-admin:${ADMIN_FRONT_VERSION:-toc-base-open-docker.35} - container_name: openim-admin - platform: linux/amd64 + openim-admin-front: + image: ${OPENIM_ADMIN_FRONT_IMAGE} + container_name: openim-admin-front restart: always ports: - - "${OPENIM_ADMIN_FRONT_PORT:-11002}:80" + - "11002:80" networks: - server: - ipv4_address: ${OPENIM_ADMIN_FRONT_NETWORK_ADDRESS:-172.28.0.13} - -### TODO: Uncomment, or deploy using openim docker: https://github.com/openimsdk/openim-docker -### Uncomment and configure the following services as needed - - # openim-server: - # image: ${IMAGE_REGISTRY:-ghcr.io/openimsdk}/openim-server:${SERVER_IMAGE_VERSION:-main} - # container_name: openim-server - # ports: - # - "${OPENIM_WS_PORT:-10001}:${OPENIM_WS_PORT:-10001}" - # - "${API_OPENIM_PORT:-10002}:${API_OPENIM_PORT:-10002}" - # - "${API_PROM_PORT:-20100}:${API_PROM_PORT:-20100}" - # - "${USER_PROM_PORT:-20110}:${USER_PROM_PORT:-20110}" - # - "${FRIEND_PROM_PORT:-20120}:${FRIEND_PROM_PORT:-20120}" - # - "${MESSAGE_PROM_PORT:-20130}:${MESSAGE_PROM_PORT:-20130}" - # - "${MSG_GATEWAY_PROM_PORT:-20140}:${MSG_GATEWAY_PROM_PORT:-20140}" - # - "${GROUP_PROM_PORT:-20150}:${GROUP_PROM_PORT:-20150}" - # - "${AUTH_PROM_PORT:-20160}:${AUTH_PROM_PORT:-20160}" - # - "${PUSH_PROM_PORT:-20170}:${PUSH_PROM_PORT:-20170}" - # - "${CONVERSATION_PROM_PORT:-20230}:${CONVERSATION_PROM_PORT:-20230}" - # - "${RTC_PROM_PORT:-21300}:${RTC_PROM_PORT:-21300}" - # - "${THIRD_PROM_PORT:-21301}:${THIRD_PROM_PORT:-21301}" - # - "21400-21403:21400-21403" - # healthcheck: - # test: ["CMD", "/openim/openim-server/scripts/check-all.sh"] - # interval: 120s - # timeout: 30s - # retries: 5 - # env_file: - # - .env - # environment: - # - OPENIM_IP=${OPENIM_IP:-127.0.0.1} - # volumes: - # - "${DATA_DIR:-./}/openim-server/logs:/openim/openim-server/logs" - # - "${DATA_DIR:-./}/openim-server/_output/logs:/openim/openim-server/_output/logs" - # - "${DATA_DIR:-./}/openim-server/config:/openim/openim-server/config" - # restart: always - # depends_on: - # - kafka - # - mysql - # - mongodb - # - redis - # - minio - # logging: - # driver: json-file - # options: - # max-size: "1g" - # max-file: "2" - # networks: - # server: - # ipv4_address: ${OPENIM_SERVER_NETWORK_ADDRESS:-172.28.0.8} - - # openim-chat: - # image: ${IMAGE_REGISTRY:-ghcr.io/openimsdk}/openim-chat:${CHAT_IMAGE_VERSION:-main} - # container_name: openim-chat - # healthcheck: - # test: ["CMD", "/openim/openim-chat/scripts/check_all.sh"] - # interval: 60s - # timeout: 30s - # retries: 5 - # env_file: - # - .env - # environment: - # - ZOOKEEPER_ADDRESS=${DOCKER_BRIDGE_GATEWAY:-172.28.0.1} - # - ZOOKEEPER_PORT=${ZOOKEEPER_PORT:-12181} - # - OPENIM_SERVER_ADDRESS=http://${OPENIM_SERVER_ADDRESS:-172.28.0.1} - # - API_OPENIM_PORT=${API_OPENIM_PORT:-10002} - # - MYSQL_ADDRESS=${DOCKER_BRIDGE_GATEWAY:-172.28.0.1} - # - MYSQL_PORT=${MYSQL_PORT:-13306} - # - REDIS_ADDRESS=${DOCKER_BRIDGE_GATEWAY:-172.28.0.1} - # - REDIS_PORT=${REDIS_PORT:-16379} - # ports: - # - "${OPENIM_CHAT_API_PORT:-10008}:10008" - # - "${OPENIM_ADMIN_API_PORT:-10009}:10009" - # volumes: - # - "${DATA_DIR:-./}/components/openim-chat/logs:/openim/openim-chat/logs" - # - "${DATA_DIR:-./}/components/openim-chat/_output/logs:/openim/openim-chat/_output/logs" - # - "${DATA_DIR:-./}/components/openim-chat/config:/openim/openim-chat/config" - # restart: always - # # user: root:root - # depends_on: - # - mysql - # - kafka - # - redis - # - zookeeper - # logging: - # driver: json-file - # options: - # max-size: "1g" - # max-file: "2" - # networks: - # server: - # ipv4_address: ${OPENIM_CHAT_NETWORK_ADDRESS:-172.28.0.9} - - # prometheus: - # image: prom/prometheus - # container_name: prometheus - # hostname: prometheus - # restart: always - # volumes: - # - "${DATA_DIR:-./}/config/instance-down-rules.yml:/etc/prometheus/instance-down-rules.yml" - # - "${DATA_DIR:-./}/config/prometheus.yml:/etc/prometheus/prometheus.yml" - # ports: - # - "${PROMETHEUS_PORT:-19090}:9090" - # networks: - # server: - # ipv4_address: ${PROMETHEUS_NETWORK_ADDRESS:-172.28.0.10} - - # alertmanager: - # image: prom/alertmanager - # container_name: alertmanager - # hostname: alertmanager - # restart: always - # volumes: - # - ${DATA_DIR:-./}/config/alertmanager.yml:/etc/alertmanager/alertmanager.yml - # - ${DATA_DIR:-./}/config/email.tmpl:/etc/alertmanager/email.tmpl - # ports: - # - "${ALERT_MANAGER_PORT:-19093}:9093" - # networks: - # server: - # ipv4_address: ${ALERT_MANAGER_NETWORK_ADDRESS:-172.28.0.14} + - openim - # grafana: - # image: grafana/grafana - # container_name: grafana - # hostname: grafana - # user: root - # restart: always - # ports: - # - "${GRAFANA_PORT:-13000}:3000" - # volumes: - # - "${DATA_DIR:-./}/components/grafana:/var/lib/grafana" - # networks: - # server: - # ipv4_address: ${GRAFANA_NETWORK_ADDRESS:-172.28.0.11} - # node-exporter: - # image: quay.io/prometheus/node-exporter - # container_name: node-exporter - # hostname: node-exporter - # restart: always - # ports: - # - "${NODE_EXPORTER_PORT:-19100}:9100" - # networks: - # server: - # ipv4_address: ${NODE_EXPORTER_NETWORK_ADDRESS:-172.28.0.12} diff --git a/docs/contrib/go-code.md b/docs/contrib/go-code.md index 5c02127251..df74dec1bb 100644 --- a/docs/contrib/go-code.md +++ b/docs/contrib/go-code.md @@ -115,22 +115,83 @@ var s = F() func F() string { return "A" } ``` -- Use `_` as a prefix for unexported top-level constants and variables. +- This example emphasizes using PascalCase for exported constants and camelCase for unexported ones, avoiding all caps and underscores. ```go // bad const ( - defaultHost = "127.0.0.1" - defaultPort = 8080 + MAX_COUNT = 100 + timeout = 30 ) // good const ( - _defaultHost = "127.0.0.1" - _defaultPort = 8080 + MaxCount = 100 // Exported constants should use PascalCase. + defaultTimeout = 30 // Unexported constants should use camelCase. ) ``` +- Grouping related constants enhances organization and readability, especially when there are multiple constants related to a particular feature or configuration. + +```go +// bad +const apiVersion = "v1" +const retryInterval = 5 + +// good +const ( + ApiVersion = "v1" // Group related constants together for better organization. + RetryInterval = 5 +) +``` + +- The "good" practice utilizes iota for a clear, concise, and auto-incrementing way to define enumerations, reducing the potential for errors and improving maintainability. + +```go +// bad +const ( + StatusActive = 0 + StatusInactive = 1 + StatusUnknown = 2 +) + +// good +const ( + StatusActive = iota // Use iota for simple and efficient constant enumerations. + StatusInactive + StatusUnknown +) +``` + +- Specifying types explicitly improves clarity, especially when the purpose or type of a constant might not be immediately obvious. Additionally, adding comments to exported constants or those whose purpose isn't clear from the name alone can greatly aid in understanding the code. + +```go +// bad +const serverAddress = "localhost:8080" +const debugMode = 1 // Is this supposed to be a boolean or an int? + +// good +const ServerAddress string = "localhost:8080" // Specify type for clarity. +// DebugMode indicates if the application should run in debug mode (true for debug mode). +const DebugMode bool = true +``` + +- By defining a contextKey type and making userIDKey of this type, you avoid potential collisions with other context keys. This approach leverages Go's type system to provide compile-time checks against misuse. + +```go +// bad +const userIDKey = "userID" + +// In this example, userIDKey is a string type, which can lead to conflicts or accidental misuse because string keys are prone to typos and collisions in a global namespace. + + +// good +type contextKey string + +const userIDKey contextKey = "userID" +``` + + - Embedded types (such as mutexes) should be at the top of the field list within the struct, and there must be a blank line separating embedded fields from regular fields. ```go @@ -274,8 +335,6 @@ The use of `panic` should be carefully controlled in Go applications to ensure p - **Restricted Use in Main Package:** In the main package, the use of `panic` should be reserved for situations where the program is entirely inoperable, such as failure to open essential files, inability to connect to the database, or other critical startup issues. Even in these scenarios, prefer using structured error handling to terminate the program. -- **Use `log.Fatal` for Critical Errors:** Instead of panicking, use `log.Fatal` to log critical errors that prevent the program from operating normally. This approach allows the program to terminate while ensuring the error is properly logged for troubleshooting. - - **Prohibition on Exportable Interfaces:** Exportable interfaces must not invoke `panic`. They should handle errors gracefully and return errors as part of their contract. - **Prefer Errors Over Panic:** It is recommended to use error returns instead of panic to convey errors within a package. This approach promotes error handling that integrates smoothly with Go's error handling idioms. @@ -303,7 +362,7 @@ func SIGTERMExit() { ```go import ( - _ "net/http/pprof" + _ "net/webhook/pprof" "github.com/openimsdk/open-im-server/v3/pkg/common/cmd" util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" @@ -357,27 +416,31 @@ The naming convention is a very important part of the code specification. A unif - Don't use broad, meaningless package names like common, util, shared or lib. - The package name should be simple and clear, such as net, time, log. -### 2.2 Function Naming -- The function name is in camel case, and the first letter is uppercase or lowercase according to the access control decision,For example: `MixedCaps` or `mixedCaps`. -- Code automatically generated by code generation tools (such as `xxxx.pb.go`) and underscores used to group related test cases (such as `TestMyFunction_WhatIsBeingTested`) exclude this rule. +### 2.2 Function Naming Conventions + +Function names should adhere to the following guidelines, inspired by OpenIM’s standards and Google’s Go Style Guide: + +- Use camel case for function names. Start with an uppercase letter for public functions (`MixedCaps`) and a lowercase letter for private functions (`mixedCaps`). +- Exceptions to this rule include code automatically generated by tools (e.g., `xxxx.pb.go`) and test functions that use underscores for clarity (e.g., `TestMyFunction_WhatIsBeingTested`). + +### 2.3 File and Directory Naming Practices + +To maintain consistency and readability across the OpenIM project, observe the following naming practices: + +**File Names:** +- Use underscores (`_`) as the default separator in filenames, keeping them short and descriptive. +- Both hyphens (`-`) and underscores (`_`) are allowed, but underscores are preferred for general use. -In accordance with the naming conventions adopted by OpenIM and drawing reference from the Google Naming Conventions as per the guidelines available at https://google.github.io/styleguide/go/, the following expectations for naming practices within the project are set forth: +**Script and Markdown Files:** +- Prefer hyphens (`-`) for shell scripts and Markdown (`.md`) files to enhance searchability and web compatibility. -1. **File Names:** - + Both hyphens (`-`) and underscores (`_`) are permitted when naming files. - + A preference is established for the use of underscores (`_`), suggesting it as the best practice in general scenarios. -2. **Script and Markdown Files:** - + For shell scripts (bash files) and Markdown (`.md`) documents, the use of hyphens (`-`) is recommended. - + This recommendation is based on the improved searchability and compatibility in web browsers when hyphens are used in names. -3. **Directories:** - + A consistent approach is mandated for naming directories, exclusively using hyphens (`-`) to separate words within directory names. +**Directories:** +- Name directories with hyphens (`-`) exclusively to separate words, ensuring consistency and readability. +Remember to keep filenames lowercase and use meaningful, concise identifiers to facilitate better organization and navigation within the project. -### 2.3 File Naming -- Keep the filename short and meaningful. -- Filenames should be lowercase and use underscores to separate words. ### 2.4 Structure Naming @@ -478,9 +541,9 @@ var LintGonicMapper = GonicMapper{ - If the variable type is bool, the name should start with Has, Is, Can or Allow, for example: ```go -var has Conflict bool +var hasConflict bool var isExist bool -var can Manage bool +var canManage bool var allowGitHook bool ``` diff --git a/docs/contrib/go-code1.md b/docs/contrib/go-code1.md new file mode 100644 index 0000000000..2206a153e3 --- /dev/null +++ b/docs/contrib/go-code1.md @@ -0,0 +1,1554 @@ +## OpenIM development specification +We have very high standards for code style and specification, and we want our products to be polished and perfect + +## 1. Code style + +### 1.1 Code format + +- Code must be formatted with `gofmt`. +- Leave spaces between operators and operands. +- It is recommended that a line of code does not exceed 120 characters. If the part exceeds, please use an appropriate line break method. But there are also some exception scenarios, such as import lines, code automatically generated by tools, and struct fields with tags. +- The file length cannot exceed 800 lines. +- Function length cannot exceed 80 lines. +- import specification +- All code must be formatted with `goimports` (it is recommended to set the code Go code editor to: run `goimports` on save). +- Do not use relative paths to import packages, such as `import ../util/net`. +- Import aliases must be used when the package name does not match the last directory name of the import path, or when multiple identical package names conflict. + +```go +// bad +"github.com/dgrijalva/jwt-go/v4" + +//good +jwt "github.com/dgrijalva/jwt-go/v4" +``` +- Imported packages are suggested to be grouped, and anonymous package references use a new group, and anonymous package references are explained. + +```go +import ( + // go standard package + "fmt" + + // third party package + "github.com/jinzhu/gorm" + "github.com/spf13/cobra" + "github.com/spf13/viper" + + // Anonymous packages are grouped separately, and anonymous package references are explained + // import mysql driver + _ "github.com/jinzhu/gorm/dialects/mysql" + + // inner package +) +``` + +### 1.2 Declaration, initialization and definition + +When multiple variables need to be used in a function, the `var` declaration can be used at the beginning of the function. Declaration outside the function must use `var`, do not use `:=`, it is easy to step on the scope of the variable. + +```go +var ( + Width int + Height int +) +``` + +- When initializing a structure reference, please use `&T{}` instead of `new(T)` to make it consistent with structure initialization. + +```go + // bad + sptr := new(T) + sptr.Name = "bar" + + // good + sptr := &T{Name: "bar"} +``` + +- The struct declaration and initialization format takes multiple lines and is defined as follows. + +```go + type User struct{ + Username string + Email string + } + + user := User{ + Username: "belm", + Email: "nosbelm@qq.com", +} +``` + +- Similar declarations are grouped together, and the same applies to constant, variable, and type declarations. + +```go +// bad +import "a" +import "b" + +//good +import ( + "a" + "b" +) +``` + +- Specify container capacity where possible to pre-allocate memory for the container, for example: + +```go +v := make(map[int]string, 4) +v := make([]string, 0, 4) +``` + +- At the top level, use the standard var keyword. Do not specify a type unless it is different from the type of the expression. + +```go +// bad +var s string = F() + +func F() string { return "A" } + +// good +var s = F() +// Since F already explicitly returns a string type, we don't need to explicitly specify the type of _s +// still of that type + +func F() string { return "A" } +``` + +- This example emphasizes using PascalCase for exported constants and camelCase for unexported ones, avoiding all caps and underscores. + +```go +// bad +const ( + MAX_COUNT = 100 + timeout = 30 +) + +// good +const ( + MaxCount = 100 // Exported constants should use PascalCase. + defaultTimeout = 30 // Unexported constants should use camelCase. +) +``` + +- Grouping related constants enhances organization and readability, especially when there are multiple constants related to a particular feature or configuration. + +```go +// bad +const apiVersion = "v1" +const retryInterval = 5 + +// good +const ( + ApiVersion = "v1" // Group related constants together for better organization. + RetryInterval = 5 +) +``` + +- The "good" practice utilizes iota for a clear, concise, and auto-incrementing way to define enumerations, reducing the potential for errors and improving maintainability. + +```go +// bad +const ( + StatusActive = 0 + StatusInactive = 1 + StatusUnknown = 2 +) + +// good +const ( + StatusActive = iota // Use iota for simple and efficient constant enumerations. + StatusInactive + StatusUnknown +) +``` + +- Specifying types explicitly improves clarity, especially when the purpose or type of a constant might not be immediately obvious. Additionally, adding comments to exported constants or those whose purpose isn't clear from the name alone can greatly aid in understanding the code. + +```go +// bad +const serverAddress = "localhost:8080" +const debugMode = 1 // Is this supposed to be a boolean or an int? + +// good +const ServerAddress string = "localhost:8080" // Specify type for clarity. +// DebugMode indicates if the application should run in debug mode (true for debug mode). +const DebugMode bool = true +``` + +- By defining a contextKey type and making userIDKey of this type, you avoid potential collisions with other context keys. This approach leverages Go's type system to provide compile-time checks against misuse. + +```go +// bad +const userIDKey = "userID" + +// In this example, userIDKey is a string type, which can lead to conflicts or accidental misuse because string keys are prone to typos and collisions in a global namespace. + + +// good +type contextKey string + +const userIDKey contextKey = "userID" +``` + + +- Embedded types (such as mutexes) should be at the top of the field list within the struct, and there must be a blank line separating embedded fields from regular fields. + +```go +// bad +type Client struct { + version int + http.Client +} + +//good +type Client struct { + http.Client + + version int +} +``` + + +### 1.5 Unit Tests + +- The unit test filename naming convention is `example_test.go`. +- Write a test case for every important exportable function. +- Because the functions in the unit test file are not external, the exportable structures, functions, etc. can be uncommented. +- If `func (b *Bar) Foo` exists, the single test function can be `func TestBar_Foo`. + +## 2. Naming convention + +The naming convention is a very important part of the code specification. A uniform, short, and precise naming convention can greatly improve the readability of the code and avoid unnecessary bugs. + +### 2.1 Package Naming + +- The package name must be consistent with the directory name, try to use a meaningful and short package name, and do not conflict with the standard library. +- Package names are all lowercase, without uppercase or underscores, and use multi-level directories to divide the hierarchy. +- Item names can connect multiple words with dashes. +- Do not use plurals for the package name and the directory name where the package is located, for example, `net/url` instead of `net/urls`. +- Don't use broad, meaningless package names like common, util, shared or lib. +- The package name should be simple and clear, such as net, time, log. + + +### 2.2 Function Naming Conventions + +Function names should adhere to the following guidelines, inspired by OpenIM’s standards and Google’s Go Style Guide: + +- Use camel case for function names. Start with an uppercase letter for public functions (`MixedCaps`) and a lowercase letter for private functions (`mixedCaps`). +- Exceptions to this rule include code automatically generated by tools (e.g., `xxxx.pb.go`) and test functions that use underscores for clarity (e.g., `TestMyFunction_WhatIsBeingTested`). + +### 2.3 File and Directory Naming Practices + +To maintain consistency and readability across the OpenIM project, observe the following naming practices: + +**File Names:** +- Use underscores (`_`) as the default separator in filenames, keeping them short and descriptive. +- Both hyphens (`-`) and underscores (`_`) are allowed, but underscores are preferred for general use. + +**Script and Markdown Files:** +- Prefer hyphens (`-`) for shell scripts and Markdown (`.md`) files to enhance searchability and web compatibility. + +**Directories:** +- Name directories with hyphens (`-`) exclusively to separate words, ensuring consistency and readability. + +Remember to keep filenames lowercase and use meaningful, concise identifiers to facilitate better organization and navigation within the project. + +### 2.4 Structure Naming + +- The camel case is adopted, and the first letter is uppercase or lowercase according to the access control, such as `MixedCaps` or `mixedCaps`. +- Struct names should not be verbs, but should be nouns, such as `Node`, `NodeSpec`. +- Avoid using meaningless structure names such as Data and Info. +- The declaration and initialization of the structure should take multiple lines, for example: + +```go +// User multi-line declaration +type User struct { + name string + Email string +} + +// multi-line initialization +u := User{ + UserName: "belm", + Email: "nosbelm@qq.com", +} +``` + +### 2.5 Interface Naming + +- The interface naming rules are basically consistent with the structure naming rules: +- Interface names of individual functions suffixed with "er"" (e.g. Reader, Writer) can sometimes lead to broken English, but that's okay. +- The interface name of the two functions is named after the two function names, eg ReadWriter. +- An interface name for more than three functions, similar to a structure name. + +For example: + +```go +// Seeking to an offset before the start of the file is an error. +// Seeking to any positive offset is legal, but the behavior of subsequent +// I/O operations on the underlying object are implementation-dependent. +type Seeker interface { + Seek(offset int64, whence int) (int64, error) +} + +// ReadWriter is the interface that groups the basic Read and Write methods. +type ReadWriter interface { + reader + Writer +} +``` + +### 2.6 Variable Naming + +- Variable names must follow camel case, and the initial letter is uppercase or lowercase according to the access control decision. +- In relatively simple (few objects, highly targeted) environments, some names can be abbreviated from full words to single letters, for example: +- user can be abbreviated as u; +- userID can be abbreviated as uid. +- When using proper nouns, the following rules need to be followed: +- If the variable is private and the proper noun is the first word, use lowercase, such as apiClient. +- In other cases, the original wording of the noun should be used, such as APIClient, repoID, UserID. + +Some common nouns are listed below. + +```go +// A GonicMapper that contains a list of common initialisms taken from golang/lint +var LintGonicMapper = GonicMapper{ + "API": true, + "ASCII": true, + "CPU": true, + "CSS": true, + "DNS": true, + "EOF": true, + "GUID": true, + "HTML": true, + "HTTP": true, + "HTTPS": true, + "ID": true, + "IP": true, + "JSON": true, + "LHS": true, + "QPS": true, + "RAM": true, + "RHS": true, + "RPC": true, + "SLA": true, + "SMTP": true, + "SSH": true, + "TLS": true, + "TTL": true, + "UI": true, + "UID": true, + "UUID": true, + "URI": true, + "URL": true, + "UTF8": true, + "VM": true, + "XML": true, + "XSRF": true, + "XSS": true, +} +``` + +- If the variable type is bool, the name should start with Has, Is, Can or Allow, for example: + +```go +var hasConflict bool +var isExist bool +var canManage bool +var allowGitHook bool +``` + +- Local variables should be as short as possible, for example, use buf to refer to buffer, and use i to refer to index. +- The code automatically generated by the code generation tool can exclude this rule (such as the Id in `xxx.pb.go`) + +### 2.7 Constant Naming + +In Go, constants play a critical role in defining values that do not change throughout the execution of a program. Adhering to best practices in naming constants can significantly improve the readability and maintainability of your code. Here are some guidelines for constant naming: + +- **Camel Case Naming:** The name of a constant must follow the camel case notation. The initial letter should be uppercase or lowercase based on the access control requirements. Uppercase indicates that the constant is exported (visible outside the package), while lowercase indicates package-private visibility (visible only within its own package). + +- **Enumeration Type Constants:** For constants that represent a set of enumerated values, it's recommended to define a corresponding type first. This approach not only enhances type safety but also improves code readability by clearly indicating the purpose of the enumeration. + +**Example:** + +```go +// Code defines an error code type. +type Code int + +// Internal errors. +const ( + // ErrUnknown - 0: An unknown error occurred. + ErrUnknown Code = iota + // ErrFatal - 1: A fatal error occurred. + ErrFatal +) +``` + +In the example above, `Code` is defined as a new type based on `int`. The enumerated constants `ErrUnknown` and `ErrFatal` are then defined with explicit comments to indicate their purpose and values. This pattern is particularly useful for grouping related constants and providing additional context. + +### Global Variables and Constants Across Packages + +- **Use Constants for Global Variables:** When defining variables that are intended to be accessed across packages, prefer using constants to ensure immutability. This practice avoids unintended modifications to the value, which can lead to unpredictable behavior or hard-to-track bugs. + +- **Lowercase for Package-Private Usage:** If a global variable or constant is intended for use only within its own package, it should start with a lowercase letter. This clearly signals its limited scope of visibility, adhering to Go's access control mechanism based on naming conventions. + +**Guideline:** + +- For global constants that need to be accessed across packages, declare them with an uppercase initial letter. This makes them exported, adhering to Go's visibility rules. +- For constants used within the same package, start their names with a lowercase letter to limit their scope to the package. + +**Example:** + +```go +package config + +// MaxConnections - the maximum number of allowed connections. Visible across packages. +const MaxConnections int = 100 + +// minIdleTime - the minimum idle time before a connection is considered stale. Only visible within the config package. +const minIdleTime int = 30 +``` + +In this example, `MaxConnections` is a global constant meant to be accessed across packages, hence it starts with an uppercase letter. On the other hand, `minIdleTime` is intended for use only within the `config` package, so it starts with a lowercase letter. + +Following these guidelines ensures that your Go code is more readable, maintainable, and consistent with Go's design philosophy and access control mechanisms. + + + + +### 2.10 Using Context with IO or Inter-Process Communication (IPC) + +In Go, `context.Context` is a powerful construct for managing deadlines, cancellation signals, and other request-scoped values across API boundaries and between processes. It is particularly important in I/O operations or inter-process communication (IPC), where operations might need to be cancelled or timed out. + +#### Guideline: Use Context for IO and IPC + +- **Mandatory Use of Context:** When performing I/O operations or inter-process communication, it's crucial to use `context.Context` to manage the lifecycle of these operations. This includes setting deadlines, handling cancellation signals, and passing request-scoped values. + +#### Incorrect Example: Ignoring Context in an HTTP Call + +```go +package main + +import ( + "io/ioutil" + "net/http" + "log" +) + +// FetchData makes an HTTP GET request to the specified URL and returns the response body. +// This function does not use context, making it impossible to cancel the request or set a deadline. +func FetchData(url string) (string, error) { + resp, err := http.Get(url) // Incorrect: Ignoring context + if err != nil { + return "", err + } + defer resp.Body.Close() + + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return "", err + } + + return string(body), nil +} + +func main() { + data, err := FetchData("http://example.com") + if err != nil { + log.Fatalf("Failed to fetch data: %v", err) + } + log.Println(data) +} +``` + +In this incorrect example, the `FetchData` function makes an HTTP GET request without using a `context`. This approach does not allow the request to be cancelled or a timeout to be set, potentially leading to resources being wasted if the server takes too long to respond or if the operation needs to be aborted for any reason. + +#### Correct Example: Using Context in an HTTP Call + +```go +package main + +import ( + "context" + "io/ioutil" + "net/http" + "log" + "time" +) + +// FetchDataWithContext makes an HTTP GET request to the specified URL using the provided context. +// This allows the request to be cancelled or timed out according to the context's deadline. +func FetchDataWithContext(ctx context.Context, url string) (string, error) { + req, err := http.NewRequestWithContext(ctx, "GET", url, nil) + if err != nil { + return "", err + } + + resp, err := http.DefaultClient.Do(req) + if err != nil { + return "", err + } + defer resp.Body.Close() + + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return "", err + } + + return string(body), nil +} + +func main() { + // Create a context with a 5-second timeout + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + + data, err := FetchDataWithContext(ctx, "http://example.com") + if err != nil { + log.Fatalf("Failed to fetch data: %v", err) + } + log.Println(data) +} +``` + +In the correct example, `FetchDataWithContext` uses a context to make the HTTP GET request. This allows the operation to be cancelled or subjected to a timeout, as dictated by the context passed to it. The `context.WithTimeout` function is used in `main` to create a context that cancels the request if it takes longer than 5 seconds, demonstrating a practical use of context to manage operation lifecycle. + +### Best Practices for Using Context + +1. **Pass context as the first parameter of a function**, following the convention `func(ctx context.Context, ...)`. +2. **Never ignore the context** provided to you in functions that support it. Always use it in your I/O or IPC operations. +3. **Avoid storing context in a struct**. Contexts are meant to be passed around within the call stack, not stored. +4. **Use context's cancellation and deadline features** to control the lifecycle of blocking operations, especially in network I/O and IPC scenarios. +5. **Propagate context down the call stack** to any function that supports it, ensuring that your application can respond to cancellation signals and deadlines effectively. + +By adhering to these guidelines and examples, you can ensure that your Go applications handle I/O and IPC operations more reliably and efficiently, with proper support for cancellation, timeouts, and request-scoped values. + + + +## 3. 日志规范 + +启动时正常日志,打印流程日志,如链接mongo成功,注意不要打印密码等敏感信息。 + +启动时以及运行中异常终止日志,如果需要终止程序,调用ExitWithError + +运行时日志打印,对于错误日志,使用日志库打印,仅在最上层调用打印;对于debug日志,可以随意打印;对于关键日志打印 info; + +## 5.异常及错误处理 + +任何情况禁止使用panic + +错误需要wrap,并带上message和key value,用户排查问题;错误wrap仅一次,及函数本身出现的错误,或者调用项目之外的函数产生的错误。 + +用errs.New()替代errors.New() + + + + + +### 1.4 Panic Processing + +The use of `panic` should be carefully controlled in Go applications to ensure program stability and predictable error handling. Following are revised guidelines emphasizing the restriction on using `panic` and promoting alternative strategies for error handling and program termination. + +- **Prohibited in Business Logic:** Using `panic` within business logic processing is strictly prohibited. Business logic should handle errors gracefully and use error returns to propagate issues up the call stack. + +- **Restricted Use in Main Package:** In the main package, the use of `panic` should be reserved for situations where the program is entirely inoperable, such as failure to open essential files, inability to connect to the database, or other critical startup issues. Even in these scenarios, prefer using structured error handling to terminate the program. + +- **Prohibition on Exportable Interfaces:** Exportable interfaces must not invoke `panic`. They should handle errors gracefully and return errors as part of their contract. + +- **Prefer Errors Over Panic:** It is recommended to use error returns instead of panic to convey errors within a package. This approach promotes error handling that integrates smoothly with Go's error handling idioms. + +#### Alternative to Panic: Structured Program Termination + +To enforce these guidelines, consider implementing structured functions to terminate the program gracefully in the face of unrecoverable errors, while providing clear error messages. Here are two recommended functions: + +```go +// ExitWithError logs an error message and exits the program with a non-zero status. +func ExitWithError(err error) { + progName := filepath.Base(os.Args[0]) + fmt.Fprintf(os.Stderr, "%s exit -1: %+v\n", progName, err) + os.Exit(-1) +} + +// SIGTERMExit logs a warning message when the program receives a SIGTERM signal and exits with status 0. +func SIGTERMExit() { + progName := filepath.Base(os.Args[0]) + fmt.Fprintf(os.Stderr, "Warning %s receive process terminal SIGTERM exit 0\n", progName) +} +``` + +#### Example Usage: + +```go +import ( + _ "net/webhook/pprof" + + "github.com/openimsdk/open-im-server/v3/pkg/common/cmd" + util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" +) + +func main() { + apiCmd := cmd.NewApiCmd() + apiCmd.AddPortFlag() + apiCmd.AddPrometheusPortFlag() + if err := apiCmd.Execute(); err != nil { + util.ExitWithError(err) + } +} +``` + +In this example, `ExitWithError` is used to terminate the program when an unrecoverable error occurs, providing a clear error message to stderr and exiting with a non-zero status. This approach ensures that critical errors are logged and the program exits in a controlled manner, facilitating troubleshooting and maintaining the stability of the application. + + + +### 1.3 Error Handling + +- `error` is returned as the value of the function, `error` must be handled, or the return value assigned to explicitly ignore. For `defer xx.Close()`, there is no need to explicitly handle it. + +```go +func load() error { +// normal code +} + +// bad +load() + +//good + _ = load() +``` + +- When `error` is returned as the value of a function and there are multiple return values, `error` must be the last parameter. + +```go +// bad +func load() (error, int) { +// normal code +} + +//good +func load() (int, error) { +// normal code +} +``` + +- Perform error handling as early as possible and return as early as possible to reduce nesting. + +```go +// bad +if err != nil { +// error code +} else { +// normal code +} + +//good +if err != nil { +// error handling +return err +} +// normal code +``` + +- If you need to use the result of the function call outside if, you should use the following method. + +```go +// bad +if v, err := foo(); err != nil { +// error handling +} + +// good +v, err := foo() +if err != nil { +// error handling +} +``` + +- Errors should be judged independently, not combined with other logic. + +```go +// bad +v, err := foo() +if err != nil || v == nil { + // error handling + return err +} + +//good +v, err := foo() +if err != nil { + // error handling + return err +} + +if v == nil { + // error handling + return errors. New("invalid value v") +} +``` + +- If the return value needs to be initialized, use the following method. + +```go +v, err := f() +if err != nil { + // error handling + return // or continue. +} +``` + +- Bug description suggestions +- Error descriptions start with a lowercase letter and do not end with punctuation, for example: + +```go +// bad +errors.New("Redis connection failed") +errors.New("redis connection failed.") + +// good +errors.New("redis connection failed") +``` + +- Tell users what they can do, not what they can't. +- When declaring a requirement, use must instead of should. For example, `must be greater than 0, must match regex '[a-z]+'`. +- When declaring that a format is incorrect, use must not. For example, `must not contain`. +- Use may not when declaring an action. For example, `may not be specified when otherField is empty, only name may be specified`. +- When quoting a literal string value, indicate the literal in single quotes. For example, `ust not contain '..'`. +- When referencing another field name, specify that name in backticks. For example, must be greater than `request`. +- When specifying unequal, use words instead of symbols. For example, `must be less than 256, must be greater than or equal to 0 (do not use larger than, bigger than, more than, higher than)`. +- When specifying ranges of numbers, use inclusive ranges whenever possible. +- Go 1.13 or above is recommended, and the error generation method is `fmt.Errorf("module xxx: %w", err)`. + +### 1.6 Type assertion failure handling + +- A single return value from a type assertion will panic for an incorrect type. Always use the "comma ok" idiom. + +```go +// bad +t := n.(int) + +//good +t, ok := n.(int) +if !ok { +// error handling +} +``` + + + +### 2.8 Error naming + +- The Error type should be written in the form of FooError. + +```go +type ExitError struct { +// .... +} +``` + +- The Error variable is written in the form of ErrFoo. + +```go +var ErrFormat = errors. New("unknown format") +``` + +For non-standard Err naming, CICD will report an error + + +### 2.9 Handling Errors Properly + +In Go, proper error handling is crucial for creating reliable and maintainable applications. It's important to ensure that errors are not ignored or discarded, as this can lead to unpredictable behavior and difficult-to-debug issues. Here are the guidelines and examples regarding the proper handling of errors. + +#### Guideline: Do Not Discard Errors + +- **Mandatory Error Propagation:** When calling a function that returns an error, the calling function must handle or propagate the error, instead of ignoring it. This approach ensures that errors are not silently ignored, allowing higher-level logic to make informed decisions about error handling. + +#### Incorrect Example: Discarding an Error + +```go +package main + +import ( + "io/ioutil" + "log" +) + +func ReadFileContent(filename string) string { + content, _ := ioutil.ReadFile(filename) // Incorrect: Error is ignored + return string(content) +} + +func main() { + content := ReadFileContent("example.txt") + log.Println(content) +} +``` + +In this incorrect example, the error returned by `ioutil.ReadFile` is ignored. This can lead to situations where the program continues execution even if the file doesn't exist or cannot be accessed, potentially causing more cryptic errors downstream. + +#### Correct Example: Propagating an Error + +```go +package main + +import ( + "io/ioutil" + "log" +) + +// ReadFileContent attempts to read and return the content of the specified file. +// It returns an error if reading fails. +func ReadFileContent(filename string) (string, error) { + content, err := ioutil.ReadFile(filename) + if err != nil { + // Correct: Propagate the error + return "", err + } + return string(content), nil +} + +func main() { + content, err := ReadFileContent("example.txt") + if err != nil { + log.Fatalf("Failed to read file: %v", err) + } + log.Println(content) +} +``` + +In the correct example, the error returned by `ioutil.ReadFile` is propagated back to the caller. The `main` function then checks the error and terminates the program with an appropriate error message if an error occurred. This approach ensures that errors are handled appropriately, and the program does not proceed with invalid state. + +### Best Practices for Error Handling + +1. **Always check the error returned by a function.** Do not ignore it. +2. **Propagate errors up the call stack unless they can be handled gracefully at the current level.** +3. **Provide context for errors when propagating them, making it easier to trace the source of the error.** This can be achieved using `fmt.Errorf` with the `%w` verb or dedicated wrapping functions provided by some error handling packages. +4. **Log the error at the point where it is handled or makes the program to terminate, to provide insight into the failure.** + +By following these guidelines, you ensure that your Go applications handle errors in a consistent and effective manner, improving their reliability and maintainability. + + + + + + + + + + + + + +## Suggestions + + + +## 3. Comment specification + +- Each exportable name must have a comment, which briefly introduces the exported variables, functions, structures, interfaces, etc. +- All single-line comments are used, and multi-line comments are prohibited. +- Same as the code specification, single-line comments should not be too long, and no more than 120 characters are allowed. If it exceeds, please use a new line to display, and try to keep the format elegant. +- A comment must be a complete sentence, starting with the content to be commented and ending with a period, `the format is // name description.`. For example: + +```go +// bad +// logs the flags in the flagset. +func PrintFlags(flags *pflag. FlagSet) { +// normal code +} + +//good +// PrintFlags logs the flags in the flagset. +func PrintFlags(flags *pflag. FlagSet) { +// normal code +} +``` + +- All commented out code should be deleted before submitting code review, otherwise, it should explain why it is not deleted, and give follow-up processing suggestions. + +- Multiple comments can be separated by blank lines, as follows: + +```go +// Package superman implements methods for saving the world. +// +// Experience has shown that a small number of procedures can prove +// helpful when attempting to save the world. +package superman +``` + +### 3.1 Package Notes + +- Each package has one and only one package-level annotation. +- Package comments are uniformly commented with // in the format of `// Package package description`, for example: + +```go +// Package genericclioptions contains flags which can be added to you command, bound, completed, and produce +// useful helper functions. +package genericclioptions +``` + +### 3.2 Variable/Constant Comments + +- Each variable/constant that can be exported must have a comment description, `the format is // variable name variable description`, for example: + +```go +// ErrSigningMethod defines invalid signing method error. +var ErrSigningMethod = errors. New("Invalid signing method") +``` + +- When there is a large block of constant or variable definition, you can comment a general description in front, and then comment the definition of the constant in detail before or at the end of each line of constant, for example: + +```go +// Code must start with 1xxxxx. +const ( + // ErrSuccess - 200: OK. + ErrSuccess int = iota + 100001 + + // ErrUnknown - 500: Internal server error. + ErrUnknown + + // ErrBind - 400: Error occurred while binding the request body to the struct. + ErrBind + + // ErrValidation - 400: Validation failed. + ErrValidation +) +``` + +### 3.3 Structure Annotation + +- Each structure or interface that needs to be exported must have a comment description, the format is `// structure name structure description.`. +- The name of the exportable member variable in the structure, if the meaning is not clear, a comment must be given and placed before the member variable or at the end of the same line. For example: + +```go +// User represents a user restful resource. It is also used as gorm model. +type User struct { + // Standard object's metadata. + metav1.ObjectMeta `json:"metadata,omitempty"` + + Nickname string `json:"nickname" gorm:"column:nickname"` + Password string `json:"password" gorm:"column:password"` + Email string `json:"email" gorm:"column:email"` + Phone string `json:"phone" gorm:"column:phone"` + IsAdmin int `json:"isAdmin,omitempty" gorm:"column:isAdmin"` +} +``` + +### 3.4 Method Notes + +Each function or method that needs to be exported must have a comment, the format is // function name function description., for examplelike: + +```go +// BeforeUpdate run before update database record. +func (p *Policy) BeforeUpdate() (err error) { +// normal code + return nil +} +``` + +### 3.5 Type annotations + +- Each type definition and type alias that needs to be exported must have a comment description, the format is `// type name type description.`, for example: + +```go +// Code defines an error code type. +type Code int +``` + +## 4. Type + +### 4.1 Strings + +- Empty string judgment. + +```go +// bad +if s == "" { + // normal code +} + +//good +if len(s) == 0 { + // normal code +} +``` + +- `[]byte`/`string` equality comparison. + +```go +// bad +var s1 []byte +var s2 []byte +... +bytes.Equal(s1, s2) == 0 +bytes.Equal(s1, s2) != 0 + +//good +var s1 []byte +var s2 []byte +... +bytes. Compare(s1, s2) == 0 +bytes. Compare(s1, s2) != 0 +``` + +- Complex strings use raw strings to avoid character escaping. + +```go +// bad +regexp.MustCompile("\\.") + +//good +regexp.MustCompile(`\.`) +``` + +### 4.2 Slicing + +- Empty slice judgment. + +```go +// bad +if len(slice) = 0 { + // normal code +} + +//good +if slice != nil && len(slice) == 0 { + // normal code +} +``` + +The above judgment also applies to map and channel. + +- Declare a slice. + +```go +// bad +s := []string{} +s := make([]string, 0) + +//good +var s[]string +``` + +- slice copy. + +```go +// bad +var b1, b2 []byte +for i, v := range b1 { + b2[i] = v +} +for i := range b1 { + b2[i] = b1[i] +} + +//good +copy(b2, b1) +``` + +- slice added. + +```go +// bad +var a, b []int +for _, v := range a { + b = append(b, v) +} + +//good +var a, b []int +b = append(b, a...) +``` + +### 4.3 Structure + +- struct initialization. + +The struct is initialized in multi-line format. + +```go +type user struct { +Id int64 +name string +} + +u1 := user{100, "Colin"} + +u2 := user{ + Id: 200, + Name: "Lex", +} +``` + +- + + + +## 5. Control Structure + +### 5.1 if + +- if accepts the initialization statement, the convention is to create local variables in the following way. + +```go +if err := loadConfig(); err != nil { +// error handling +return err +} +``` + +- if For variables of bool type, true and false judgments should be made directly. + +```go +var isAllow bool +if isAllow { +// normal code +} +``` + +### 5.2 for + +- Create local variables using short declarations. + +```go +sum := 0 +for i := 0; i < 10; i++ { + sum += 1 +} +``` + +- Don't use defer in for loop, defer will only be executed when the function exits. + +```go +// bad +for file := range files { + fd, err := os. Open(file) + if err != nil { + return err +} +defer fd. Close() +// normal code +} + +//good +for file := range files { + func() { + fd, err := os. Open(file) + if err != nil { + return err + } + defer fd. Close() + // normal code + }() +} +``` + +### 5.3 range + +- If only the first item (key) is needed, discard the second. + +```go +for keyIndex := range keys { +// normal code +} +``` + +- If only the second item is required, underline the first item. + +```go +sum := 0 +for _, value := range array { + sum += value +} +``` + +### 5.4 switch + +- must have default. + +```go +switch os := runtime.GOOS; os { + case "linux": + fmt.Println("Linux.") + case "darwin": + fmt.Println("OS X.") + default: + fmt.Printf("%s.\n", os) +} +``` + +### 5.5 goto + +- Business code prohibits the use of goto. +- Try not to use frameworks or other low-level source code. + +## 6. Functions + +- Incoming variables and return variables start with a lowercase letter. +- The number of function parameters cannot exceed 5. +- Function grouping and ordering +- Functions should be sorted in rough calling order. +- Functions in the same file should be grouped by receiver. +- Try to use value transfer instead of pointer transfer. +- The incoming parameters are map, slice, chan, interface, do not pass pointers. + +### 6.1 Function parameters + +- If the function returns two or three arguments of the same type, or if the meaning of the result is not clear from the context, use named returns, otherwise it is not recommended to use named returns, for example: + +```go +func coordinate() (x, y float64, err error) { +// normal code +} +``` + +- Both incoming and returned variables start with a lowercase letter. +- Try to pass by value instead of pointer. +- The number of parameters cannot exceed 5. +- Multiple return values can return up to three, and if there are more than three, please use struct. + +### 6.2 defer + +- When resources are created, resources should be released immediately after defer (defer can be used boldly, the performance of defer is greatly improved in Go1.14 version, and the performance loss of defer can be ignored even in performance-sensitive businesses). +- First judge whether there is an error, and then defer to release resources, for example: + +```go +rep, err := http. Get(url) +if err != nil { + return err +} + +defer resp.Body.Close() +``` + +### 6.3 Method Receiver + +- It is recommended to use the lowercase of the first English letter of the class name as the name of the receiver. +- Don't use a single character in the name of the receiver when the function exceeds 20 lines. +- The name of the receiver cannot use confusing names such as me, this, and self. + +### 6.4 Nesting + +- The nesting depth cannot exceed 4 levels. + +### 6.5 Variable Naming + +- The variable declaration should be placed before the first use of the variable as far as possible, following the principle of proximity. +- If the magic number appears more than twice, it is forbidden to use it and use a constant instead, for example: + +```go +// PI... +const Price = 3.14 + +func getAppleCost(n float64) float64 { +return Price * n +} + +func getOrangeCost(n float64) float64 { +return Price * n +} +``` + +## 7. GOPATH setting specification + +- After Go 1.11, the GOPATH rule has been weakened. Existing code (many libraries must have been created before 1.11) must conform to this rule. It is recommended to keep the GOPATH rule to facilitate code maintenance. +- Only one GOPATH is recommended, multiple GOPATHs are not recommended. If multiple GOPATHs are used, the bin directory where compilation takes effect is under the first GOPATH. + + + +## 8. Dependency Management + +- Go 1.11 and above must use Go Modules. +- When using Go Modules as a dependency management project, it is not recommended to submit the vendor directory. +- When using Go Modules as a dependency management project, the go.sum file must be submitted. + +### 9. Best Practices + +- Minimize the use of global variables, but pass parameters, so that each function is "stateless". This reduces coupling and facilitates division of labor and unit testing. +- Verify interface compliance at compile time, for example: + +```go +type LogHandler struct { + h http.Handler + log *zap. Logger +} +var_http.Handler = LogHandler{} +``` + +- When the server processes a request, it should create a context, save the relevant information of the request (such as requestID), and pass it in the function call chain. + +### 9.1 Performance + +- string represents an immutable string variable, modifying string is a relatively heavy operation, and basically needs to re-apply for memory. Therefore, if there is no special need, use []byte more when you need to modify. +- Prefer strconv over fmt. + +### 9.2 Precautions + +- append Be careful about automatically allocating memory, append may return a newly allocated address. +- If you want to directly modify the value of the map, the value can only be a pointer, otherwise the original value must be overwritten. +- map needs to be locked during concurrency. +- The conversion of interface{} cannot be checked during compilation, it can only be checked at runtime, be careful to cause panic. + + + + + +## 10 Golang CI Lint + +- Golang CI Lint is a fast Go linters runner. It runs linters in parallel, uses caching, and works well with all environments, including CI. + +**In local development, you can use the following command to install Golang CI Lint: ** + +```bash +make lint +``` + +**In CI/CD, Check the Github Actions status code below after you submit the code directly** + +[![OpenIM golangci-lint](https://github.com/openimsdk/open-im-server/actions/workflows/golangci-lint.yml/badge.svg)](https://github.com/openimsdk/open-im-server/actions/workflows/golangci-lint.yml) + +golangci lint can select the types of tools, refer to the official documentation: [https://golangci-lint.run/usage/linters/](https://golangci-lint.run/usage/linters/) + +The types of comments we currently use include: [https://github.com/openimsdk/open-im-server/blob/main/.golangci.yml](https://github.com/openimsdk/open-im-server/blob/main/.golangci.yml) the `linters.enable` field in the file. + +e.g: + +```yaml +linters: + # please, do not use `enable-all`: it's deprecated and will be removed soon. + # inverted configuration with `enable-all` and `disable` is not scalable during updates of golangci-lint + # enable-all: true + disable-all: true + enable: + - typecheck # Basic type checking + - gofmt # Format check + - govet # Go's standard linting tool + - gosimple # Suggestions for simplifying code + - misspell # Spelling mistakes + - staticcheck # Static analysis + - unused # Checks for unused code + - goimports # Checks if imports are correctly sorted and formatted + - godot # Checks for comment punctuation + - bodyclose # Ensures HTTP response body is closed + - errcheck # Checks for missed error returns + fast: true +``` + +Add that Chinese comments are not allowed in go code, please write a complete golangci lint specification on the basis of the above. + + +### 10.1 Configuration Document + +This configuration document is designed to configure the operational parameters of OpenIM (a hypothetical or specific code analysis tool), customize output formats, and provide detailed settings for specific code checkers (linters). Below is a summary of the document drafted based on the provided configuration information. + +#### 10.1 Runtime Options + +- **Concurrency** (`concurrency`): Default to use the available CPU count, can be manually set to 4 for parallel analysis. +- **Timeout** (`timeout`): Timeout duration for analysis operations, default is 1 minute, set here to 5 minutes. +- **Issue Exit Code** (`issues-exit-code`): Exit code defaults to 1 if at least one issue is found. +- **Test Files** (`tests`): Whether to include test files, defaults to true. +- **Build Tags** (`build-tags`): Specify build tags used by all linters, defaults to an empty list. Example adds `mytag`. +- **Skip Directories** (`skip-dirs`): Configure which directories' issues are not reported, defaults to empty, but some default directories are independently skipped. +- **Skip Files** (`skip-files`): Specify files where issues should not be reported, supports regular expressions. + +#### 10.2 Output Configuration + +- **Format** (`format`): Set output format, default is "colored-line-number". +- **Print Issued Lines** (`print-issued-lines`): Whether to print the lines where issues occur, defaults to true. +- **Print Linter Name** (`print-linter-name`): Whether to print the linter name at the end of issue text, defaults to true. +- **Uniqueness Filter** (`uniq-by-line`): Whether to make issue outputs unique per line, defaults to true. +- **Path Prefix** (`path-prefix`): Prefix to add to output file references, defaults to no prefix. +- **Sort Results** (`sort-results`): Sort results by file path, line number, and column number. + +#### 10.3 Linters Settings + +In the configuration file, the `linters-settings` section allows detailed configuration of individual linters. Below are examples of specific linters settings and their purposes: + +- **bidichk**: Used to check bidirectional text characters, ensuring correct display direction of text, especially when dealing with mixed left-to-right (LTR) and right-to-left (RTL) text. + +- **dogsled**: Monitors excessive use of blank identifiers (`_`) in assignment operations, which may obscure data processing errors or unclear logic. + +- **dupl**: Identifies duplicate code blocks, helping developers avoid code redundancy. The `threshold` parameter in settings allows adjustment of code similarity threshold triggering warnings. + +- **errcheck**: Checks for unhandled errors. In Go, error handling is achieved by checking function return values. This linter helps ensure all errors are properly handled. + +- **exhaustive**: Checks if `switch` statements include all possible values of an enum type, ensuring exhaustiveness of code. This helps avoid forgetting to handle certain cases. + +#### 10.4 Example: `errcheck` + +**Incorrect Code Example**: + +```go +package main + +import ( + "fmt" + "os" +) + +func main() { + f, _ := os.Open("filename.ext") + defer f.Close() +} +``` + +**Issue**: In the above code, the error return value of `os.Open` function is explicitly ignored. This is a common mistake as it may lead to unhandled errors and hard-to-trace bugs. + +**Correct Form**: + +```go +package main + +import ( + "fmt" + "os" +) + +func main() { + f, err := os.Open("filename.ext") + if err != nil { + fmt.Printf("error opening file: %v\n", err) + return + } + defer f.Close() +} +``` + +In the correct form, by checking the error (`err`) returned by `os.Open`, we gracefully handle error cases rather than simply ignoring them. + +#### 10.5 Example: `gofmt` + +**Incorrect Code Example**: + +```go +package main +import "fmt" +func main() { +fmt.Println("Hello, world!") +} +``` + +**Issue**: This code snippet doesn't follow Go's standard formatting rules, for example, incorrect indentation of `fmt.Println`. + +**Correct Form**: + +```go +package main + +import "fmt" + +func main() { + fmt.Println("Hello, world!") +} +``` + +Using `gofmt` tool can automatically fix such formatting issues, ensuring the code adheres to the coding standards of the Go community. + +#### 10.6 Example: `unused` + +**Incorrect Code Example**: + +```go +package main + +func helper() {} + +func main() {} +``` + +**Issue**: The `helper` function is defined but not called anywhere, indicating potential redundant code or missing functionality implementation. + +**Correct Form**: + +```go +package main + +// If the helper function is indeed needed, ensure it's used properly. +func helper() { + // Implement the function's functionality or ensure it's called elsewhere +} + +func main() { + helper() +} +``` + +To improve the section on Linters settings in the document, we'll expand with more detailed explanations and reinforce understanding through examples. + +#### 10.7 Example: `dogsled` + +**Incorrect Code Example**: + +```go +func getValues() (int, int, int) { + return 1, 2, 3 +} + +func main() { + _, _, val := getValues() + fmt.Println(val) // Only interested in the third return value +} +``` + +**Explanation**: In the above code, we use two blank identifiers to ignore the first two return values. Excessive use of blank identifiers can make code reading difficult. + +**Improved Code**: +Consider refactoring the function or the usage of return values to reduce the need for blank identifiers or explicitly comment why ignoring certain values is safe. + +#### 10.8: `exhaustive` + +**Incorrect Code Example**: + +```go +type Fruit int + +const ( + Apple Fruit = iota + Banana + Orange +) + +func getFruitName(f Fruit) string { + switch f { + case Apple: + return "Apple" + case Banana: + return "Banana" + // Missing handling for Orange + } + return "Unknown" +} +``` + +**Explanation**: In this code, the `switch` statement doesn't cover all possible values of the `Fruit` type; the case for `Orange` is missing. + +**Improved Code**: + +```go +func getFruitName(f Fruit) string { + switch f { + case Apple: + return "Apple" + case Banana: + return "Banana" + case Orange: + return "Orange" + } + return "Unknown" +} +``` + +By adding the missing `case`, we ensure the `switch` statement is exhaustive, handling every possible enum value. + +#### 10.9 Optimization of Configuration Files and Application of Code Analysis Tools + +Through these examples, we demonstrate how to improve code quality by identifying and fixing common coding issues. OpenIM's configuration files allow developers to customize linters' behavior according to project requirements, ensuring code compliance with predefined quality standards and style guidelines. + +By employing these tools and configuration strategies, teams can reduce the number of bugs, enhance code maintainability, and facilitate efficient collaboration during code review processes. + + + + + + + diff --git a/docs/contrib/go-doc.md b/docs/contrib/go-doc.md new file mode 100644 index 0000000000..65b88514e4 --- /dev/null +++ b/docs/contrib/go-doc.md @@ -0,0 +1,50 @@ +# Go Language Documentation for OpenIM + +In the realm of software development, especially within Go language projects, documentation plays a crucial role in ensuring code maintainability and ease of use. Properly written and accurate documentation is not only essential for understanding and utilizing software effectively but also needs to be easy to write and maintain. This principle is at the heart of OpenIM's approach to supporting commands and generating documentation. + +## Supported Commands in OpenIM + +OpenIM leverages Go language's documentation standards to facilitate clear and maintainable code documentation. Below are some of the key commands used in OpenIM for documentation purposes: + +### `go doc` Command + +The `go doc` command is used to print documentation for Go language entities such as variables, constants, functions, structures, and interfaces. This command allows specifying the identifier of the program entity to tailor the output. Examples of `go doc` command usage include: + +- `go doc sync.WaitGroup.Add` prints the documentation for a specific method of a type in a package. +- `go doc -u -all sync.WaitGroup` displays all program entities, including unexported ones, for a specified type. +- `go doc -u sync` outputs all program entities for a specified package, focusing on exported ones without detailed comments. + +### `godoc` Command + +For environments lacking internet access, the `godoc` command serves to view the Go language standard library and project dependency library documentation in a web format. Notably, post-Go 1.12 versions, `godoc` is not part of the Go compiler suite. It can be installed using: + +```shell +go get -u -v golang.org/x/tools/cmd/godoc +``` + +The `godoc` command, once running, hosts a local web server (by default on port 6060) to facilitate documentation browsing at http://127.0.0.1:6060. It generates documentation based on the GOROOT and GOPATH directories, showcasing both the project's own documentation and that of third-party packages installed via `go get`. + +### Custom Documentation Generation Commands in OpenIM + +OpenIM includes a suite of commands aimed at initializing, generating, and maintaining project documentation and associated files. Some notable commands are: + +- `gen.init`: Initializes the OpenIM server project. +- `gen.docgo`: Generates missing `doc.go` files for Go packages, crucial for package-level documentation. +- `gen.errcode.doc`: Generates markdown documentation for OpenIM error codes. +- `gen.ca`: Generates CA files for all certificates, enhancing security documentation. + +These commands underscore the project's commitment to thorough and accessible documentation, supporting both developers and users alike. + +## Writing Your Own Documentation + +When creating documentation for Go projects, including OpenIM, it's important to follow certain practices: + +1. **Commenting**: Use single-line (`//`) and block (`/* */`) comments to provide detailed documentation within the code. Block comments are especially useful for package documentation, which should immediately precede the package statement without any intervening blank lines. + +2. **Overview Section**: To create an overview section in the documentation, place a block comment directly before the package statement. This section should succinctly describe the package's purpose and functionality. + +3. **Detailed Descriptions**: Comments placed before functions, structures, or variables will be used to generate detailed descriptions in the documentation. Follow the same commenting rules as for the overview section. + +4. **Examples**: Include example functions prefixed with `Example` to demonstrate usage. Output from these examples can be documented at the end of the function, starting with `// Output:` followed by the expected result. + +Through adherence to these documentation practices, OpenIM ensures that its codebase remains accessible, maintainable, and easy to use for developers and users alike. \ No newline at end of file diff --git a/docs/contrib/logging.md b/docs/contrib/logging.md index c44f6f3c74..03628f427c 100644 --- a/docs/contrib/logging.md +++ b/docs/contrib/logging.md @@ -66,7 +66,7 @@ The `CodeError` interface is designed to provide a unified mechanism for error h ## Logging Standards and Code Examples -In the OpenIM project, we use the unified logging package `github.com/OpenIMSDK/tools/log` for logging to achieve efficient log management and analysis. This logging package supports structured logging formats, making it easier for developers to handle log information. +In the OpenIM project, we use the unified logging package `github.com/openimsdk/tools/log` for logging to achieve efficient log management and analysis. This logging package supports structured logging formats, making it easier for developers to handle log information. ### Logger Interface and Implementation @@ -96,7 +96,7 @@ func main() { ## Error Handling and Code Examples -We use the `github.com/OpenIMSDK/tools/errs` package for unified error handling and wrapping. +We use the `github.com/openimsdk/tools/errs` package for unified error handling and wrapping. ### CodeError Interface and Implementation @@ -121,7 +121,7 @@ package main import ( "fmt" - "github.com/OpenIMSDK/tools/errs" + "github.com/openimsdk/tools/errs" ) func main() { @@ -164,7 +164,7 @@ More details") import ( "context" - "github.com/OpenIMSDK/tools/log" + "github.com/openimsdk/tools/log" ) func main() { @@ -226,7 +226,7 @@ More details") package main import ( - "github.com/OpenIMSDK/tools/log" + "github.com/openimsdk/tools/log" "context" ) @@ -337,7 +337,19 @@ More details") // Suppose an error occurs here err, _ := someFunc() if err != nil { - return errs.Wrap(err, "doSomething failed") + return errs.WrapMsg(err, "doSomething failed") + } + } + ``` + + It just works if the package is wrong: + + ```go + func doSomething() error { + // Suppose an error occurs here + err, _ := someFunc() + if err != nil { + return errs.Wrap(err) } } ``` @@ -383,4 +395,113 @@ More details") } return nil } - ``` \ No newline at end of file + ``` + + +### About WrapMsg Use + +```go +// "github.com/openimsdk/tools/errs" +func WrapMsg(err error, msg string, kv ...any) error { + if len(kv) == 0 { + if len(msg) == 0 { + return errors.WithStack(err) + } else { + return errors.WithMessage(err, msg) + } + } + var buf bytes.Buffer + if len(msg) > 0 { + buf.WriteString(msg) + buf.WriteString(" ") + } + for i := 0; i < len(kv); i += 2 { + if i > 0 { + buf.WriteString(", ") + } + buf.WriteString(toString(kv[i])) + buf.WriteString("=") + buf.WriteString(toString(kv[i+1])) + } + return errors.WithMessage(err, buf.String()) +} +``` + +1. **Function Signature**: + - `err error`: The original error object. + - `msg string`: The message text to append to the error. + - `kv ...any`: A variable number of parameters used to pass key-value pairs. `any` was introduced in Go 1.18 and is equivalent to `interface{}`, meaning any type. + +2. **Logic**: + - If there are no key-value pairs (`kv` is empty): + - If `msg` is also empty, use `errors.WithStack(err)` to return the original error with the call stack appended. + - If `msg` is not empty, use `errors.WithMessage(err, msg)` to append the message text to the original error. + - If there are key-value pairs, the function constructs a string containing the message text and all key-value pairs. The key-value pairs are added in the format `"key=value"`, separated by commas. If a message text is provided, it is added first, followed by a space. + +3. **Key-Value Pair Formatting**: + - A loop iterates over all the key-value pairs, processing one pair at a time. + - The `toString` function (although not provided in the code, we can assume it converts any type to a string) is used to convert both keys and values to strings, and they are added to a `bytes.Buffer` in the format `"key=value"`. + +4. **Result**: + - Use `errors.WithMessage(err, buf.String())` to append the constructed message text to the original error, and return this new error object. + +Next, let's demonstrate several ways to use the `WrapMsg` function: + +**Example 1: No Additional Information** + +```go +// "github.com/openimsdk/tools/errs" +err := errors.New("original error") +wrappedErr := errs.WrapMsg(err, "") +// wrappedErr will contain the original error and its call stack +``` + +**Example 2: Message Text Only** + +```go +// "github.com/openimsdk/tools/errs" +err := errors.New("original error") +wrappedErr := errs.WrapMsg(err, "additional error information") +// wrappedErr will contain the original error, call stack, and "additional error information" +``` + +**Example 3: Message Text and Key-Value Pairs** + +```go +// "github.com/openimsdk/tools/errs" +err := errors.New("original error") +wrappedErr := errs.WrapMsg(err, "problem occurred", "code", 404, "url", "webhook://example.com") +// wrappedErr will contain the original error, call stack, and "problem occurred code=404, url=http://example.com" +``` + +**Example 4: Key-Value Pairs Only** + +```go +// "github.com/openimsdk/tools/errs" +err := errors.New("original error") +wrappedErr := errs.WrapMsg(err, "", "user", "john_doe", "action", "login") +// wrappedErr will contain the original error, call stack, and "user=john_doe, action=login" +``` + +> [!TIP] WThese examples demonstrate how the `errs.WrapMsg` function can flexibly handle error messages and context data, helping developers to more effectively track and debug their programs. + + +### Example 5: Dynamic Key-Value Pairs from Context +Suppose we have some runtime context variables, such as a user ID and the type of operation being performed, and we want to include these variables in the error message. This can help with later debugging and identifying the specific environment of the issue. + +```go +// Define some context variables +userID := "user123" +operation := "update profile" +errorCode := 500 +requestURL := "webhook://example.com/updateProfile" + +// Create a new error +err := errors.New("original error") + +// Wrap the error, including dynamic key-value pairs from the context +wrappedErr := errs.WrapMsg(err, "operation failed", "user", userID, "action", operation, "code", errorCode, "url", requestURL) +// wrappedErr will contain the original error, call stack, and "operation failed user=user123, action=update profile, code=500, url=http://example.com/updateProfile" +``` + +> [!TIP]In this example, the `WrapMsg` function accepts not just a static error message and additional information, but also dynamic key-value pairs generated from the code's execution context, such as the user ID, operation type, error code, and the URL of the request. Including this contextual information in the error message makes it easier for developers to understand and resolve the issue. \ No newline at end of file diff --git a/go.mod b/go.mod index da28155712..8ada8f2e77 100644 --- a/go.mod +++ b/go.mod @@ -1,12 +1,9 @@ module github.com/openimsdk/open-im-server/v3 -go 1.19 +go 1.20 require ( firebase.google.com/go v3.13.0+incompatible - github.com/OpenIMSDK/protocol v0.0.56 - github.com/OpenIMSDK/tools v0.0.37 - github.com/bwmarrin/snowflake v0.3.0 // indirect github.com/dtm-labs/rockscache v0.1.1 github.com/gin-gonic/gin v1.9.1 github.com/go-playground/validator/v10 v10.18.0 @@ -15,36 +12,36 @@ require ( github.com/gorilla/websocket v1.5.1 github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible // indirect - github.com/minio/minio-go/v7 v7.0.67 github.com/mitchellh/mapstructure v1.5.0 - github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 // indirect github.com/openimsdk/localcache v0.0.1 + github.com/openimsdk/protocol v0.0.64 + github.com/openimsdk/tools v0.0.47-alpha.42 github.com/pkg/errors v0.9.1 // indirect github.com/prometheus/client_golang v1.18.0 - github.com/robfig/cron/v3 v3.0.1 - github.com/sirupsen/logrus v1.9.3 // indirect - github.com/stretchr/testify v1.8.4 + github.com/stretchr/testify v1.9.0 go.mongodb.org/mongo-driver v1.14.0 - golang.org/x/image v0.15.0 google.golang.org/api v0.165.0 - google.golang.org/grpc v1.61.0 - google.golang.org/protobuf v1.32.0 + google.golang.org/grpc v1.62.1 + google.golang.org/protobuf v1.33.0 gopkg.in/yaml.v3 v3.0.1 ) require github.com/google/uuid v1.6.0 require ( - github.com/IBM/sarama v1.42.2 - github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible + github.com/IBM/sarama v1.43.0 + github.com/fatih/color v1.14.1 github.com/go-redis/redis v6.15.9+incompatible + github.com/kelindar/bitmap v1.5.2 + github.com/likexian/gokit v0.25.13 + github.com/openimsdk/gomake v0.0.6 github.com/redis/go-redis/v9 v9.4.0 - github.com/spf13/pflag v1.0.5 + github.com/robfig/cron/v3 v3.0.1 + github.com/shirou/gopsutil v3.21.11+incompatible + github.com/spf13/viper v1.18.2 github.com/stathat/consistent v1.0.0 - github.com/tencentyun/cos-go-sdk-v5 v0.7.46 + go.uber.org/automaxprocs v1.5.3 golang.org/x/sync v0.6.0 - gopkg.in/src-d/go-git.v4 v4.13.1 - gotest.tools v2.2.0+incompatible ) require ( @@ -55,101 +52,113 @@ require ( cloud.google.com/go/iam v1.1.5 // indirect cloud.google.com/go/longrunning v0.5.4 // indirect cloud.google.com/go/storage v1.36.0 // indirect + github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bytedance/sonic v1.9.1 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect github.com/clbanning/mxj v1.8.4 // indirect - github.com/davecgh/go-spew v1.1.1 // 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/dustin/go-humanize v1.0.1 // indirect - github.com/eapache/go-resiliency v1.5.0 // indirect + github.com/eapache/go-resiliency v1.6.0 // indirect github.com/eapache/go-xerial-snappy v0.0.0-20230731223053-c322873962e3 // indirect github.com/eapache/queue v1.1.0 // indirect - github.com/emirpasic/gods v1.12.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect + github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/gabriel-vasile/mimetype v1.4.3 // indirect github.com/gin-contrib/sse v0.1.0 // indirect github.com/go-logr/logr v1.4.1 // indirect github.com/go-logr/stdr v1.2.2 // indirect + github.com/go-ole/go-ole v1.2.6 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-zookeeper/zk v1.0.3 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/golang/snappy v0.0.4 // indirect - github.com/google/go-cmp v0.6.0 // indirect github.com/google/go-querystring v1.1.0 // indirect github.com/google/s2a-go v0.1.7 // indirect github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect github.com/googleapis/gax-go/v2 v2.12.0 // indirect - github.com/hashicorp/errwrap v1.0.0 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/hashicorp/go-uuid v1.0.3 // indirect github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect + github.com/hashicorp/hcl v1.0.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect - github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect github.com/jcmturner/aescts/v2 v2.0.0 // indirect github.com/jcmturner/dnsutils/v2 v2.0.0 // indirect github.com/jcmturner/gofork v1.7.6 // indirect github.com/jcmturner/gokrb5/v8 v8.4.4 // indirect github.com/jcmturner/rpc/v2 v2.0.3 // indirect - github.com/jinzhu/copier v0.3.5 // indirect + github.com/jinzhu/copier v0.4.0 // indirect github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/now v1.1.5 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd // indirect - github.com/klauspost/compress v1.17.4 // indirect + github.com/kelindar/simd v1.1.2 // indirect + github.com/klauspost/compress v1.17.7 // indirect github.com/klauspost/cpuid/v2 v2.2.6 // indirect github.com/leodido/go-urn v1.4.0 // indirect github.com/lithammer/shortuuid v3.0.0+incompatible // indirect + github.com/magefile/mage v1.15.0 // indirect + github.com/magiconair/properties v1.8.7 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect github.com/minio/md5-simd v1.1.2 // indirect + github.com/minio/minio-go/v7 v7.0.69 // indirect github.com/minio/sha256-simd v1.0.1 // indirect - github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe // indirect github.com/mozillazg/go-httpheader v0.4.0 // indirect github.com/onsi/ginkgo v1.16.5 // indirect github.com/onsi/gomega v1.18.1 // indirect - github.com/pelletier/go-toml/v2 v2.0.8 // indirect + github.com/pelletier/go-toml/v2 v2.1.0 // indirect github.com/pierrec/lz4/v4 v4.1.21 // indirect - github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/prometheus/client_model v0.5.0 // indirect github.com/prometheus/common v0.45.0 // indirect github.com/prometheus/procfs v0.12.0 // indirect github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect github.com/rs/xid v1.5.0 // indirect - github.com/sergi/go-diff v1.0.0 // indirect - github.com/src-d/gcfg v1.4.0 // indirect - github.com/stretchr/objx v0.5.0 // indirect + github.com/sagikazarmark/locafero v0.4.0 // indirect + github.com/sagikazarmark/slog-shim v0.1.0 // indirect + github.com/sourcegraph/conc v0.3.0 // indirect + github.com/spf13/afero v1.11.0 // indirect + github.com/spf13/cast v1.6.0 // indirect + github.com/spf13/pflag v1.0.5 // indirect + github.com/stretchr/objx v0.5.2 // indirect + github.com/subosito/gotenv v1.6.0 // indirect + github.com/tencentyun/cos-go-sdk-v5 v0.7.47 // indirect + github.com/tklauser/go-sysconf v0.3.13 // indirect + github.com/tklauser/numcpus v0.7.0 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect - github.com/xanzy/ssh-agent v0.2.1 // 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 github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect + github.com/yusufpapurcu/wmi v1.2.4 // indirect go.opencensus.io v0.24.0 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.47.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.47.0 // indirect go.opentelemetry.io/otel v1.23.0 // indirect go.opentelemetry.io/otel/metric v1.23.0 // indirect go.opentelemetry.io/otel/trace v1.23.0 // indirect - go.uber.org/atomic v1.7.0 // indirect + go.uber.org/atomic v1.9.0 // indirect go.uber.org/multierr v1.11.0 // indirect golang.org/x/arch v0.3.0 // indirect - golang.org/x/net v0.21.0 // indirect + golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect + golang.org/x/image v0.15.0 // indirect + golang.org/x/net v0.22.0 // indirect golang.org/x/oauth2 v0.17.0 // indirect - golang.org/x/sys v0.17.0 // indirect + golang.org/x/sys v0.19.0 // indirect golang.org/x/text v0.14.0 // indirect golang.org/x/time v0.5.0 // indirect google.golang.org/appengine v1.6.8 // indirect google.golang.org/genproto v0.0.0-20240125205218-1f4bbc51befe // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20240116215550-a9fa1716bcac // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240205150955-31a09d347014 // indirect - gopkg.in/src-d/go-billy.v4 v4.3.2 // indirect - gopkg.in/warnings.v0 v0.1.2 // indirect - gorm.io/gorm v1.25.4 // 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 + gorm.io/gorm v1.25.8 // indirect stathat.com/c/consistent v1.0.0 // indirect ) @@ -161,7 +170,7 @@ require ( github.com/spf13/cobra v1.8.0 github.com/ugorji/go/codec v1.2.11 // indirect go.uber.org/zap v1.24.0 // indirect - golang.org/x/crypto v0.19.0 // indirect + golang.org/x/crypto v0.21.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect ) diff --git a/go.sum b/go.sum index c3803ef581..0ef6209fc7 100644 --- a/go.sum +++ b/go.sum @@ -16,28 +16,16 @@ cloud.google.com/go/storage v1.36.0/go.mod h1:M6M/3V/D3KpzMTJyPOR/HU6n2Si5QdaXYE firebase.google.com/go v3.13.0+incompatible h1:3TdYC3DDi6aHn20qoRkxwGqNgdjtblwVAyRLQwGn/+4= firebase.google.com/go v3.13.0+incompatible/go.mod h1:xlah6XbEyW6tbfSklcfe5FHJIwjt8toICdV5Wh9ptHs= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/IBM/sarama v1.42.2 h1:VoY4hVIZ+WQJ8G9KNY/SQlWguBQXQ9uvFPOnrcu8hEw= -github.com/IBM/sarama v1.42.2/go.mod h1:FLPGUGwYqEs62hq2bVG6Io2+5n+pS6s/WOXVKWSLFtE= -github.com/OpenIMSDK/protocol v0.0.56 h1:mbVFyDBachEsmJLfYW5AU1z2KL8AUEpoHG8RPCIxjgg= -github.com/OpenIMSDK/protocol v0.0.56/go.mod h1:F25dFrwrIx3lkNoiuf6FkCfxuwf8L4Z8UIsdTHP/r0Y= -github.com/OpenIMSDK/tools v0.0.37 h1:qvDqmA4RbEJtPjZouWCkVuf/pjm6Y8nUrG5iH2gcnOg= -github.com/OpenIMSDK/tools v0.0.37/go.mod h1:wBfR5CYmEyvxl03QJbTkhz1CluK6J4/lX0lviu8JAjE= +github.com/IBM/sarama v1.43.0 h1:YFFDn8mMI2QL0wOrG0J2sFoVIAFl7hS9JQi2YZsXtJc= +github.com/IBM/sarama v1.43.0/go.mod h1:zlE6HEbC/SMQ9mhEYaF7nNLYOUyrs0obySKCckWP9BM= github.com/QcloudApi/qcloud_sign_golang v0.0.0-20141224014652-e4130a326409/go.mod h1:1pk82RBxDY/JZnPQrtqHlUFfCctgdorsd9M06fMynOM= -github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7 h1:uSoVVbwJiQipAclBbw+8quDsfcvFjOpI5iCf4p/cqCs= -github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs= github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible h1:8psS8a+wKfiLt1iVDX79F7Y6wUM49Lcha2FMXt4UM8g= github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8= -github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA= -github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= -github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= -github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs= github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA= -github.com/bwmarrin/snowflake v0.3.0 h1:xm67bEhkKh6ij1790JB83OujPR5CzNe8QuQqAgISZN0= -github.com/bwmarrin/snowflake v0.3.0/go.mod h1:NdZxfVWX+oR6y2K0o6qAYv6gIOP9rjG0/E9WsDpxqwE= github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s= github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= @@ -54,12 +42,12 @@ github.com/clbanning/mxj v1.8.4 h1:HuhwZtbyvyOw+3Z1AowPkU87JkJUSv751ELWaiTpj8I= github.com/clbanning/mxj v1.8.4/go.mod h1:BVjHeAH+rl9rs6f+QIpeRl0tfu10SXn1pUSa5PVGJng= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= -github.com/cncf/xds/go v0.0.0-20231109132714-523115ebc101 h1:7To3pQ+pZo0i3dsWEbinPNFs5gPSBOsJtx3wTT94VBY= +github.com/cncf/xds/go v0.0.0-20231128003011-0fa0005c9caa h1:jQCWAUqqlij9Pgj2i/PB79y4KOPYVyFYdROxgaCwdTQ= github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= -github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 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= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= @@ -67,39 +55,40 @@ github.com/dtm-labs/rockscache v0.1.1 h1:6S1vgaHvGqrLd8Ka4hRTKeKPV7v+tT0MSkTIX81 github.com/dtm-labs/rockscache v0.1.1/go.mod h1:c76WX0kyIibmQ2ACxUXvDvaLykoPakivMqIxt+UzE7A= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= -github.com/eapache/go-resiliency v1.5.0 h1:dRsaR00whmQD+SgVKlq/vCRFNgtEb5yppyeVos3Yce0= -github.com/eapache/go-resiliency v1.5.0/go.mod h1:5yPzW0MIvSe0JDsv0v+DvcjEv2FyD6iZYSs1ZI+iQho= +github.com/eapache/go-resiliency v1.6.0 h1:CqGDTLtpwuWKn6Nj3uNUdflaq+/kIPsg0gfNzHton30= +github.com/eapache/go-resiliency v1.6.0/go.mod h1:5yPzW0MIvSe0JDsv0v+DvcjEv2FyD6iZYSs1ZI+iQho= github.com/eapache/go-xerial-snappy v0.0.0-20230731223053-c322873962e3 h1:Oy0F4ALJ04o5Qqpdz8XLIpNA3WM/iSIXqxtqo7UGVws= github.com/eapache/go-xerial-snappy v0.0.0-20230731223053-c322873962e3/go.mod h1:YvSRo5mw33fLEx1+DlK6L2VV43tJt5Eyel9n9XBcR+0= github.com/eapache/queue v1.1.0 h1:YOEu7KNc61ntiQlcEeUIoDTJ2o8mQznoNvUhiigpIqc= github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= -github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg= -github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/envoyproxy/protoc-gen-validate v1.0.2 h1:QkIBuU5k+x7/QXPvPPnWXWlCdaBFApVqftFV6k087DA= +github.com/envoyproxy/protoc-gen-validate v1.0.4 h1:gVPz/FMfvh57HdSJQyvBtF00j8JU4zdyUgIUNhlgg0A= +github.com/fatih/color v1.14.1 h1:qfhVLaG5s+nCROl1zJsZRxFeYrHLqWroPOQ8BWiNb4w= +github.com/fatih/color v1.14.1/go.mod h1:2oHN61fhTpgcxD3TSWCgKDiH1+x4OiDVVGH8WlgGZGg= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= -github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= +github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +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/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/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= 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/gliderlabs/ssh v0.2.2 h1:6zsha5zo/TWhRhwqCD3+EarCAgZ2yN28ipRnGPnwkI0= -github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= 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/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +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-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= @@ -148,7 +137,6 @@ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= -github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= @@ -171,8 +159,9 @@ github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/ github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= -github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= @@ -180,12 +169,12 @@ github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/C github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= +github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= -github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= -github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= github.com/jcmturner/aescts/v2 v2.0.0 h1:9YKLH6ey7H4eDBXW8khjYslgyqG2xZikXP0EQFKrle8= github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs= github.com/jcmturner/dnsutils/v2 v2.0.0 h1:lltnkeZGL0wILNvrNiVCR6Ro5PGU/SeBvVO/8c/iPbo= @@ -198,9 +187,8 @@ github.com/jcmturner/gokrb5/v8 v8.4.4 h1:x1Sv4HaTpepFkXbt2IkL29DXRf8sOfZXo8eRKh6 github.com/jcmturner/gokrb5/v8 v8.4.4/go.mod h1:1btQEpgT6k+unzCwX1KdWMEwPPkkgBtP+F6aCACiMrs= github.com/jcmturner/rpc/v2 v2.0.3 h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZY= github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc= -github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= -github.com/jinzhu/copier v0.3.5 h1:GlvfUwHk62RokgqVNvYsku0TATCF7bAHVwEXoBh3iJg= -github.com/jinzhu/copier v0.3.5/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg= +github.com/jinzhu/copier v0.4.0 h1:w3ciUoD19shMCRargcpm0cm91ytaBhDvuRpz1ODO/U8= +github.com/jinzhu/copier v0.4.0/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= @@ -208,21 +196,19 @@ github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/ github.com/jonboulle/clockwork v0.4.0 h1:p4Cf1aMWXnXAUh8lVfewRBx1zaTSYKrKMF2g3ST4RZ4= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= -github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd h1:Coekwdh0v2wtGp9Gmz1Ze3eVRAWJMLokvN3QjdzCHLY= -github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= +github.com/kelindar/bitmap v1.5.2 h1:XwX7CTvJtetQZ64zrOkApoZZHBJRkjE23NfqUALA/HE= +github.com/kelindar/bitmap v1.5.2/go.mod h1:j3qZjxH9s4OtvsnFTP2bmPkjqil9Y2xQlxPYHexasEA= +github.com/kelindar/simd v1.1.2 h1:KduKb+M9cMY2HIH8S/cdJyD+5n5EGgq+Aeeleos55To= +github.com/kelindar/simd v1.1.2/go.mod h1:inq4DFudC7W8L5fhxoeZflLRNpWSs0GNx6MlWFvuvr0= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.17.4 h1:Ej5ixsIri7BrIjBkRZLTo6ghwrEtHFk7ijlczPW4fZ4= -github.com/klauspost/compress v1.17.4/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM= +github.com/klauspost/compress v1.17.7 h1:ehO88t2UGzQK66LMdE8tibEd1ErmzZjNEqWkjLAKQQg= +github.com/klauspost/compress v1.17.7/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.2.6 h1:ndNyv040zDGIDh8thGkXYjnFtiN02M1PVVF+JE/48xc= github.com/klauspost/cpuid/v2 v2.2.6/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= @@ -232,20 +218,27 @@ github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible h1:Y6sqxHMyB1D2YSzWkL github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible/go.mod h1:ZQnN8lSECaebrkQytbHj4xNgtg8CR7RYXnPok8e0EHA= github.com/lestrrat-go/strftime v1.0.6 h1:CFGsDEt1pOpFNU+TJB0nhz9jl+K0hZSLE205AhTIGQQ= github.com/lestrrat-go/strftime v1.0.6/go.mod h1:f7jQKgV5nnJpYgdEasS+/y7EsTb8ykN2z68n3TtcTaw= +github.com/likexian/gokit v0.25.13 h1:p2Uw3+6fGG53CwdU2Dz0T6bOycdb2+bAFAa3ymwWVkM= +github.com/likexian/gokit v0.25.13/go.mod h1:qQhEWFBEfqLCO3/vOEo2EDKd+EycekVtUK4tex+l2H4= github.com/lithammer/shortuuid v3.0.0+incompatible h1:NcD0xWW/MZYXEHa6ITy6kaXN5nwm/V115vj2YXfhS0w= github.com/lithammer/shortuuid v3.0.0+incompatible/go.mod h1:FR74pbAuElzOUuenUHTK2Tciko1/vKuIKS9dSkDrA4w= +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/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= 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/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg= github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k= github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34= github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM= -github.com/minio/minio-go/v7 v7.0.67 h1:BeBvZWAS+kRJm1vGTMJYVjKUNoo0FoEt/wUWdUtfmh8= -github.com/minio/minio-go/v7 v7.0.67/go.mod h1:+UXocnUeZ3wHvVh5s95gcrA4YjMIbccT6ubB+1m054A= +github.com/minio/minio-go/v7 v7.0.69 h1:l8AnsQFyY1xiwa/DaQskY4NXSLA2yrGsW5iD9nRPVS0= +github.com/minio/minio-go/v7 v7.0.69/go.mod h1:XAvOPJQ5Xlzk5o3o/ArO2NMbhSGkimC+bpW/ngRKDmQ= github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dzMM= github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8= -github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= -github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= @@ -259,8 +252,6 @@ github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJ github.com/mozillazg/go-httpheader v0.2.1/go.mod h1:jJ8xECTlalr6ValeXYdOF8fFUISeBAdw6E61aqQma60= github.com/mozillazg/go-httpheader v0.4.0 h1:aBn6aRXtFzyDLZ4VIRLsZbbJloagQfMnCiYgOq6hK4w= github.com/mozillazg/go-httpheader v0.4.0/go.mod h1:PuT8h0pw6efvp8ZeUec1Rs7dwjK08bt6gKSReGMqtdA= -github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ= -github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= @@ -275,16 +266,22 @@ github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1y github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE= github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs= -github.com/pelletier/go-buffruneio v0.2.0/go.mod h1:JkE26KsDizTr40EUHkXVtNPvgGtbSNq5BcowyYOWdKo= -github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ= -github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4= +github.com/openimsdk/gomake v0.0.6 h1:bJmQWDHBj8PQ7oGJ2SL3Gsx0k5CdI/BPfGzlGcV105s= +github.com/openimsdk/gomake v0.0.6/go.mod h1:PndCozNc2IsQIciyn9mvEblYWZwJmAI+06z94EY+csI= +github.com/openimsdk/protocol v0.0.64 h1:OrjSs4CgKN9VLvJvrAsc37O7Ru0E0VllXZQSmG/ab7U= +github.com/openimsdk/protocol v0.0.64/go.mod h1:OZQA9FR55lseYoN2Ql1XAHYKHJGu7OMNkUbuekrKCM8= +github.com/openimsdk/tools v0.0.47-alpha.42 h1:wM6t9otTLhXECq8aQcYaZGvBgo/ZAmbNTqVt3g3NHGg= +github.com/openimsdk/tools v0.0.47-alpha.42/go.mod h1:P4oGP1Pd+d4ctbLD5U/XQTgl8yu8Hd3skx640Fr69ko= +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/pierrec/lz4/v4 v4.1.21 h1:yOVMLb6qSIDP67pl/5F7RepeKYu/VmTyEXvuMI5d9mQ= github.com/pierrec/lz4/v4 v4.1.21/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= -github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g= github.com/prometheus/client_golang v1.18.0 h1:HzFfmkOzH5Q8L8G+kSJKUx5dtG87sewO+FoDDqP5Tbk= github.com/prometheus/client_golang v1.18.0/go.mod h1:T+GXkCk5wSJyOqMIzVgvvjFDlkOQntgjkJWKrN5txjA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= @@ -304,23 +301,31 @@ github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDN github.com/rs/xid v1.5.0 h1:mKX4bl4iPYJtEIxp6CYiUuLQ/8DYMoz0PUdtGgMFRVc= github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ= -github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= -github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= -github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ= +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/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/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= +github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= +github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= +github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY= +github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0= +github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/src-d/gcfg v1.4.0 h1:xXbNR5AlLSA315x2UO+fTSSAXCDf+Ar38/6oyGbDKQ4= -github.com/src-d/gcfg v1.4.0/go.mod h1:p/UMsR43ujA89BJY9duynAwIpvqEujIH/jFlfL7jWoI= +github.com/spf13/viper v1.18.2 h1:LUXCnvUvSM6FXAsj6nnfc8Q2tp1dIgUfY9Kc8GsSOiQ= +github.com/spf13/viper v1.18.2/go.mod h1:EKmWIqdnk5lOcmR72yw6hS+8OPYcwD0jteitLMVB+yk= github.com/stathat/consistent v1.0.0 h1:ZFJ1QTRn8npNBKW065raSZ8xfOqhpb8vLOkfp4CcL/U= github.com/stathat/consistent v1.0.0/go.mod h1:uajTPbgSygZBJ+V+0mY7meZ8i0XAcZs7AQ6V121XSxw= 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.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= @@ -328,19 +333,23 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= +github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.563/go.mod h1:7sCQWVkxcsR38nffDW057DRGk8mUjK1Ing/EFOK8s8Y= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/kms v1.0.563/go.mod h1:uom4Nvi9W+Qkom0exYiJ9VWJjXwyxtPYTkKkaLMlfE0= -github.com/tencentyun/cos-go-sdk-v5 v0.7.46 h1:IeTiMR8qZ7iQWhAGb1niw5vt0T1TfAwPeB8Gn/oTkuk= -github.com/tencentyun/cos-go-sdk-v5 v0.7.46/go.mod h1:DH9US8nB+AJXqwu/AMOrCFN1COv3dpytXuJWHgdg7kE= +github.com/tencentyun/cos-go-sdk-v5 v0.7.47 h1:uoS4Sob16qEYoapkqJq1D1Vnsy9ira9BfNUMtoFYTI4= +github.com/tencentyun/cos-go-sdk-v5 v0.7.47/go.mod h1:DH9US8nB+AJXqwu/AMOrCFN1COv3dpytXuJWHgdg7kE= +github.com/tklauser/go-sysconf v0.3.13 h1:GBUpcahXSpR2xN01jhkNAbTLRk2Yzgggk8IM08lq3r4= +github.com/tklauser/go-sysconf v0.3.13/go.mod h1:zwleP4Q4OehZHGn4CYZDipCgg9usW5IJePewFCGVEa0= +github.com/tklauser/numcpus v0.7.0 h1:yjuerZP127QG9m5Zh/mSO4wqurYil27tHrqwRoRjpr4= +github.com/tklauser/numcpus v0.7.0/go.mod h1:bb6dMVcj8A42tSE7i32fsIUCbQNllK5iDguyOZRUzAY= github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= 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/xanzy/ssh-agent v0.2.1 h1:TCbipTQL2JiiCprBWx9frJ2eJlCYT00NmctrHxVAr70= -github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4= 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= @@ -352,6 +361,8 @@ github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7Jul github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= +github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= go.mongodb.org/mongo-driver v1.14.0 h1:P98w8egYRjYe3XDjxhYJagTokP/H6HzlsnojRgZRd80= go.mongodb.org/mongo-driver v1.14.0/go.mod h1:Vzb0Mk/pa7e6cWw85R4F/endUC3u0U9jGcNU603k65c= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= @@ -367,8 +378,10 @@ go.opentelemetry.io/otel/metric v1.23.0/go.mod h1:MqUW2X2a6Q8RN96E2/nqNoT+z9BSms go.opentelemetry.io/otel/sdk v1.21.0 h1:FTt8qirL1EysG6sTQRZ5TokkU8d0ugCj8htOgThZXQ8= go.opentelemetry.io/otel/trace v1.23.0 h1:37Ik5Ib7xfYVb4V1UtnT97T1jI+AoIYkJyPkuL4iJgI= go.opentelemetry.io/otel/trace v1.23.0/go.mod h1:GSGTbIClEsuZrGIzoEHqsVfxgn5UkggkflQwDScNUsk= -go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= -go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/automaxprocs v1.5.3 h1:kWazyxZUrS3Gs4qUpbwo5kEIMGe/DAvi5Z4tl2NW4j8= +go.uber.org/automaxprocs v1.5.3/go.mod h1:eRbA25aqJrxAbsLO0xy5jVwPt7FQnRgjW+efnwa1WM0= go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= @@ -377,16 +390,16 @@ go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k= golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= -golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= -golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo= -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/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g= +golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k= golang.org/x/image v0.15.0 h1:kOELfmgrmJlw4Cdb7g/QGuB3CvDrXbqEIww/pNtNBm8= golang.org/x/image v0.15.0/go.mod h1:HUYqC05R2ZcZ3ejNQsIHQDQiwWM4JBqmm6MKANTp4LE= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -402,7 +415,6 @@ golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= @@ -413,8 +425,8 @@ golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4= -golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= +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/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.17.0 h1:6m3ZPmLEFdVxKKWnKq4VqZ60gutO35zm+zrAHVmHyDQ= golang.org/x/oauth2 v0.17.0/go.mod h1:OzPDGQiuQMguemayvdylqddI7qcD9lnSDb+1FiwQ5HA= @@ -429,10 +441,9 @@ golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190221075227-b4e8571b14e0/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-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -444,18 +455,16 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y= -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/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= -golang.org/x/term v0.17.0 h1:mkTF7LCd6WGJNL3K1Ad7kwxNfYAW6a8a8QqtMblp/4U= 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= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= @@ -470,7 +479,6 @@ golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGm golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190729092621-ff9f1409240a/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= @@ -492,17 +500,17 @@ google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98 google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20240125205218-1f4bbc51befe h1:USL2DhxfgRchafRvt/wYyyQNzwgL7ZiURcozOE/Pkvo= google.golang.org/genproto v0.0.0-20240125205218-1f4bbc51befe/go.mod h1:cc8bqMqtv9gMOr0zHg2Vzff5ULhhL2IXP4sbcn32Dro= -google.golang.org/genproto/googleapis/api v0.0.0-20240116215550-a9fa1716bcac h1:OZkkudMUu9LVQMCoRUbI/1p5VCo9BOrlvkqMvWtqa6s= -google.golang.org/genproto/googleapis/api v0.0.0-20240116215550-a9fa1716bcac/go.mod h1:B5xPO//w8qmBDjGReYLpR6UJPnkldGkCSMoH/2vxJeg= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240205150955-31a09d347014 h1:FSL3lRCkhaPFxqi0s9o+V4UI2WTzAVOvkgbd4kVV4Wg= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240205150955-31a09d347014/go.mod h1:SaPjaZGWb0lPqs6Ittu0spdfrOArqji4ZdeP5IC/9N4= +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.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= -google.golang.org/grpc v1.61.0 h1:TOvOcuXn30kRao+gfcvsebNEa5iZIiLkisYEkf7R7o0= -google.golang.org/grpc v1.61.0/go.mod h1:VUbo7IFqmF1QtCAstipjG0GIoq49KvMe9+h1jFLBNJs= +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 v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -514,24 +522,15 @@ google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpAD google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I= -google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= +google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/src-d/go-billy.v4 v4.3.2 h1:0SQA1pRztfTFx2miS8sA97XvooFeNOmvUenF4o0EcVg= -gopkg.in/src-d/go-billy.v4 v4.3.2/go.mod h1:nDjArDMp+XMs1aFAESLRjfGSgfvoYN0hDfzEk0GjC98= -gopkg.in/src-d/go-git-fixtures.v3 v3.5.0 h1:ivZFOIltbce2Mo8IjzUHAFoq/IylO9WHhNOAJK+LsJg= -gopkg.in/src-d/go-git-fixtures.v3 v3.5.0/go.mod h1:dLBcvytrw/TYZsNTWCnkNF2DSIlzWYqTe3rJR56Ac7g= -gopkg.in/src-d/go-git.v4 v4.13.1 h1:SRtFyV8Kxc0UP7aCHcijOMQGPxHSmMOPrzulQWolkYE= -gopkg.in/src-d/go-git.v4 v4.13.1/go.mod h1:nx5NYcxdKxq5fpltdHnPa2Exj4Sx0EclMWZQbYDu2z8= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= -gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -540,10 +539,8 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 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.4 h1:iyNd8fNAe8W9dvtlgeRI5zSVZPsq3OpcTu37cYcpCmw= -gorm.io/gorm v1.25.4/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k= -gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= -gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= +gorm.io/gorm v1.25.8 h1:WAGEZ/aEcznN4D03laj8DKnehe1e9gYQAjW8xyPRdeo= +gorm.io/gorm v1.25.8/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= diff --git a/go.work b/go.work deleted file mode 100644 index 7cc1b80a11..0000000000 --- a/go.work +++ /dev/null @@ -1,14 +0,0 @@ -go 1.19 - -use ( - . - ./tools/changelog - ./tools/component - ./tools/imctl - ./tools/infra - ./tools/ncpu - ./tools/openim-web - ./tools/url2im - ./tools/versionchecker - ./tools/yamlfmt -) diff --git a/internal/api/auth.go b/internal/api/auth.go index 0f7a3933b3..f0790ce984 100644 --- a/internal/api/auth.go +++ b/internal/api/auth.go @@ -15,10 +15,10 @@ package api import ( - "github.com/OpenIMSDK/protocol/auth" - "github.com/OpenIMSDK/tools/a2r" "github.com/gin-gonic/gin" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" + "github.com/openimsdk/protocol/auth" + "github.com/openimsdk/tools/a2r" ) type AuthApi rpcclient.Auth diff --git a/internal/api/conversation.go b/internal/api/conversation.go index fe6c67001e..f273eaa4a7 100644 --- a/internal/api/conversation.go +++ b/internal/api/conversation.go @@ -15,10 +15,10 @@ package api import ( - "github.com/OpenIMSDK/protocol/conversation" - "github.com/OpenIMSDK/tools/a2r" "github.com/gin-gonic/gin" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" + "github.com/openimsdk/protocol/conversation" + "github.com/openimsdk/tools/a2r" ) type ConversationApi rpcclient.Conversation diff --git a/internal/api/custom_validator.go b/internal/api/custom_validator.go index d135b0dc47..99c84f0746 100644 --- a/internal/api/custom_validator.go +++ b/internal/api/custom_validator.go @@ -15,8 +15,8 @@ package api import ( - "github.com/OpenIMSDK/protocol/constant" "github.com/go-playground/validator/v10" + "github.com/openimsdk/protocol/constant" ) // RequiredIf validates if the specified field is required based on the session type. @@ -26,7 +26,7 @@ func RequiredIf(fl validator.FieldLevel) bool { switch sessionType { case constant.SingleChatType, constant.NotificationChatType: return fl.FieldName() != "RecvID" || fl.Field().String() != "" - case constant.GroupChatType, constant.SuperGroupChatType: + case constant.WriteGroupChatType, constant.ReadGroupChatType: return fl.FieldName() != "GroupID" || fl.Field().String() != "" default: return true diff --git a/internal/api/friend.go b/internal/api/friend.go index 24bcbf8990..1fea38b313 100644 --- a/internal/api/friend.go +++ b/internal/api/friend.go @@ -15,10 +15,10 @@ package api import ( - "github.com/OpenIMSDK/protocol/friend" - "github.com/OpenIMSDK/tools/a2r" "github.com/gin-gonic/gin" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" + "github.com/openimsdk/protocol/friend" + "github.com/openimsdk/tools/a2r" ) type FriendApi rpcclient.Friend diff --git a/internal/api/group.go b/internal/api/group.go index c18ded64b1..6079c53437 100644 --- a/internal/api/group.go +++ b/internal/api/group.go @@ -15,10 +15,10 @@ package api import ( - "github.com/OpenIMSDK/protocol/group" - "github.com/OpenIMSDK/tools/a2r" "github.com/gin-gonic/gin" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" + "github.com/openimsdk/protocol/group" + "github.com/openimsdk/tools/a2r" ) type GroupApi rpcclient.Group @@ -115,22 +115,14 @@ func (o *GroupApi) GetGroupAbstractInfo(c *gin.Context) { a2r.Call(group.GroupClient.GetGroupAbstractInfo, o.Client, c) } -//func (g *Group) SetGroupMemberNickname(c *gin.Context) { +// func (g *Group) SetGroupMemberNickname(c *gin.Context) { // a2r.Call(group.GroupClient.SetGroupMemberNickname, g.userClient, c) //} // -//func (g *Group) GetGroupAllMemberList(c *gin.Context) { +// func (g *Group) GetGroupAllMemberList(c *gin.Context) { // a2r.Call(group.GroupClient.GetGroupAllMember, g.userClient, c) //} -func (o *GroupApi) GetJoinedSuperGroupList(c *gin.Context) { - a2r.Call(group.GroupClient.GetJoinedSuperGroupList, o.Client, c) -} - -func (o *GroupApi) GetSuperGroupsInfo(c *gin.Context) { - a2r.Call(group.GroupClient.GetSuperGroupsInfo, o.Client, c) -} - func (o *GroupApi) GroupCreateCount(c *gin.Context) { a2r.Call(group.GroupClient.GroupCreateCount, o.Client, c) } diff --git a/internal/api/init.go b/internal/api/init.go new file mode 100644 index 0000000000..dcce69a12f --- /dev/null +++ b/internal/api/init.go @@ -0,0 +1,118 @@ +// 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 api + +import ( + "context" + "fmt" + "github.com/openimsdk/open-im-server/v3/pkg/common/config" + "github.com/openimsdk/tools/utils/datautil" + "github.com/openimsdk/tools/utils/network" + "net" + "net/http" + "os" + "os/signal" + "strconv" + "syscall" + "time" + + kdisc "github.com/openimsdk/open-im-server/v3/pkg/common/discoveryregister" + ginprom "github.com/openimsdk/open-im-server/v3/pkg/common/ginprometheus" + "github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics" + "github.com/openimsdk/tools/discovery" + "github.com/openimsdk/tools/errs" + "github.com/openimsdk/tools/log" + "github.com/openimsdk/tools/system/program" +) + +type Config struct { + RpcConfig config.API + MongodbConfig config.Mongo + ZookeeperConfig config.ZooKeeper + NotificationConfig config.Notification + Share config.Share + MinioConfig config.Minio +} + +func Start(ctx context.Context, index int, config *Config) error { + apiPort, err := datautil.GetElemByIndex(config.RpcConfig.Api.Ports, index) + if err != nil { + return err + } + prometheusPort, err := datautil.GetElemByIndex(config.RpcConfig.Prometheus.Ports, index) + if err != nil { + return err + } + + var client discovery.SvcDiscoveryRegistry + + // Determine whether zk is passed according to whether it is a clustered deployment + client, err = kdisc.NewDiscoveryRegister(&config.ZookeeperConfig, &config.Share) + if err != nil { + return errs.WrapMsg(err, "failed to register discovery service") + } + + if err = client.CreateRpcRootNodes(config.Share.RpcRegisterName.GetServiceNames()); err != nil { + return errs.WrapMsg(err, "failed to create RPC root nodes") + } + + var ( + netDone = make(chan struct{}, 1) + netErr error + ) + + router := newGinRouter(client, config) + if config.RpcConfig.Prometheus.Enable { + go func() { + p := ginprom.NewPrometheus("app", prommetrics.GetGinCusMetrics("Api")) + p.SetListenAddress(fmt.Sprintf(":%d", prometheusPort)) + if err = p.Use(router); err != nil && err != http.ErrServerClosed { + netErr = errs.WrapMsg(err, fmt.Sprintf("prometheus start err: %d", prometheusPort)) + netDone <- struct{}{} + } + }() + + } + address := net.JoinHostPort(network.GetListenIP(config.RpcConfig.Api.ListenIP), strconv.Itoa(apiPort)) + + server := http.Server{Addr: address, Handler: router} + log.CInfo(ctx, "API server is initializing", "address", address, "apiPort", apiPort, "prometheusPort", prometheusPort) + go func() { + err = server.ListenAndServe() + if err != nil && err != http.ErrServerClosed { + netErr = errs.WrapMsg(err, fmt.Sprintf("api start err: %s", server.Addr)) + netDone <- struct{}{} + + } + }() + + sigs := make(chan os.Signal, 1) + signal.Notify(sigs, syscall.SIGTERM) + + ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) + defer cancel() + select { + case <-sigs: + program.SIGTERMExit() + err := server.Shutdown(ctx) + if err != nil { + return errs.WrapMsg(err, "shutdown err") + } + case <-netDone: + close(netDone) + return netErr + } + return nil +} diff --git a/internal/api/msg.go b/internal/api/msg.go index ad5001459e..180342e591 100644 --- a/internal/api/msg.go +++ b/internal/api/msg.go @@ -15,15 +15,6 @@ package api import ( - "github.com/OpenIMSDK/protocol/constant" - "github.com/OpenIMSDK/protocol/msg" - "github.com/OpenIMSDK/protocol/sdkws" - "github.com/OpenIMSDK/tools/a2r" - "github.com/OpenIMSDK/tools/apiresp" - "github.com/OpenIMSDK/tools/errs" - "github.com/OpenIMSDK/tools/log" - "github.com/OpenIMSDK/tools/mcontext" - "github.com/OpenIMSDK/tools/utils" "github.com/gin-gonic/gin" "github.com/go-playground/validator/v10" "github.com/mitchellh/mapstructure" @@ -31,23 +22,38 @@ import ( "github.com/openimsdk/open-im-server/v3/pkg/authverify" "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" + "github.com/openimsdk/protocol/constant" + "github.com/openimsdk/protocol/msg" + "github.com/openimsdk/protocol/sdkws" + "github.com/openimsdk/tools/a2r" + "github.com/openimsdk/tools/apiresp" + "github.com/openimsdk/tools/errs" + "github.com/openimsdk/tools/log" + "github.com/openimsdk/tools/mcontext" + "github.com/openimsdk/tools/utils/datautil" + "github.com/openimsdk/tools/utils/idutil" + "github.com/openimsdk/tools/utils/jsonutil" + "github.com/openimsdk/tools/utils/timeutil" ) type MessageApi struct { *rpcclient.Message validate *validator.Validate userRpcClient *rpcclient.UserRpcClient + imAdminUserID []string } -func NewMessageApi(msgRpcClient *rpcclient.Message, userRpcClient *rpcclient.User) MessageApi { - return MessageApi{Message: msgRpcClient, validate: validator.New(), userRpcClient: rpcclient.NewUserRpcClientByUser(userRpcClient)} +func NewMessageApi(msgRpcClient *rpcclient.Message, userRpcClient *rpcclient.User, + imAdminUserID []string) MessageApi { + return MessageApi{Message: msgRpcClient, validate: validator.New(), + userRpcClient: rpcclient.NewUserRpcClientByUser(userRpcClient), imAdminUserID: imAdminUserID} } func (MessageApi) SetOptions(options map[string]bool, value bool) { - utils.SetSwitchFromOptions(options, constant.IsHistory, value) - utils.SetSwitchFromOptions(options, constant.IsPersistent, value) - utils.SetSwitchFromOptions(options, constant.IsSenderSync, value) - utils.SetSwitchFromOptions(options, constant.IsConversationUpdate, value) + datautil.SetSwitchFromOptions(options, constant.IsHistory, value) + datautil.SetSwitchFromOptions(options, constant.IsPersistent, value) + datautil.SetSwitchFromOptions(options, constant.IsSenderSync, value) + datautil.SetSwitchFromOptions(options, constant.IsConversationUpdate, value) } func (m MessageApi) newUserSendMsgReq(_ *gin.Context, params *apistruct.SendMsg) *msg.SendMsgReq { @@ -56,8 +62,8 @@ func (m MessageApi) newUserSendMsgReq(_ *gin.Context, params *apistruct.SendMsg) switch params.ContentType { case constant.OANotification: notification := sdkws.NotificationElem{} - notification.Detail = utils.StructToJsonString(params.Content) - newContent = utils.StructToJsonString(¬ification) + notification.Detail = jsonutil.StructToJsonString(params.Content) + newContent = jsonutil.StructToJsonString(¬ification) case constant.Text: fallthrough case constant.Picture: @@ -71,19 +77,19 @@ func (m MessageApi) newUserSendMsgReq(_ *gin.Context, params *apistruct.SendMsg) case constant.File: fallthrough default: - newContent = utils.StructToJsonString(params.Content) + newContent = jsonutil.StructToJsonString(params.Content) } if params.IsOnlineOnly { m.SetOptions(options, false) } if params.NotOfflinePush { - utils.SetSwitchFromOptions(options, constant.IsOfflinePush, false) + datautil.SetSwitchFromOptions(options, constant.IsOfflinePush, false) } pbData := msg.SendMsgReq{ MsgData: &sdkws.MsgData{ SendID: params.SendID, GroupID: params.GroupID, - ClientMsgID: utils.GetMsgID(params.SendID), + ClientMsgID: idutil.GetMsgIDByMD5(params.SendID), SenderPlatformID: params.SenderPlatformID, SenderNickname: params.SenderNickname, SenderFaceURL: params.SenderFaceURL, @@ -91,7 +97,7 @@ func (m MessageApi) newUserSendMsgReq(_ *gin.Context, params *apistruct.SendMsg) MsgFrom: constant.SysMsgType, ContentType: params.ContentType, Content: []byte(newContent), - CreateTime: utils.GetCurrentTimestampByMill(), + CreateTime: timeutil.GetCurrentTimestampByMill(), SendTime: params.SendTime, Options: options, OfflinePushInfo: params.OfflinePushInfo, @@ -173,14 +179,14 @@ func (m *MessageApi) getSendMsgReq(c *gin.Context, req apistruct.SendMsg) (sendM return nil, err } default: - return nil, errs.ErrArgs.WithDetail("not support err contentType") + return nil, errs.WrapMsg(errs.ErrArgs, "unsupported content type", "contentType", req.ContentType) } if err := mapstructure.WeakDecode(req.Content, &data); err != nil { - return nil, err + return nil, errs.WrapMsg(err, "failed to decode message content") } - log.ZDebug(c, "getSendMsgReq", "req", req.Content) + log.ZDebug(c, "getSendMsgReq", "decodedContent", data) if err := m.validate.Struct(data); err != nil { - return nil, err + return nil, errs.WrapMsg(err, "validation error") } return m.newUserSendMsgReq(c, &req), nil } @@ -198,9 +204,9 @@ func (m *MessageApi) SendMessage(c *gin.Context) { } // Check if the user has the app manager role. - if !authverify.IsAppManagerUid(c, m.Config) { + if !authverify.IsAppManagerUid(c, m.imAdminUserID) { // Respond with a permission error if the user is not an app manager. - apiresp.GinError(c, errs.ErrNoPermission.Wrap("only app manager can send message")) + apiresp.GinError(c, errs.ErrNoPermission.WrapMsg("only app manager can send message")) return } @@ -253,16 +259,16 @@ func (m *MessageApi) SendBusinessNotification(c *gin.Context) { return } - if !authverify.IsAppManagerUid(c, m.Config) { - apiresp.GinError(c, errs.ErrNoPermission.Wrap("only app manager can send message")) + if !authverify.IsAppManagerUid(c, m.imAdminUserID) { + apiresp.GinError(c, errs.ErrNoPermission.WrapMsg("only app manager can send message")) return } sendMsgReq := msg.SendMsgReq{ MsgData: &sdkws.MsgData{ SendID: req.SendUserID, RecvID: req.RecvUserID, - Content: []byte(utils.StructToJsonString(&sdkws.NotificationElem{ - Detail: utils.StructToJsonString(&struct { + Content: []byte(jsonutil.StructToJsonString(&sdkws.NotificationElem{ + Detail: jsonutil.StructToJsonString(&struct { Key string `json:"key"` Data string `json:"data"` }{Key: req.Key, Data: req.Data}), @@ -270,9 +276,9 @@ func (m *MessageApi) SendBusinessNotification(c *gin.Context) { MsgFrom: constant.SysMsgType, ContentType: constant.BusinessNotification, SessionType: constant.SingleChatType, - CreateTime: utils.GetCurrentTimestampByMill(), - ClientMsgID: utils.GetMsgID(mcontext.GetOpUserID(c)), - Options: config.GetOptionsByNotification(config.NotificationConf{ + CreateTime: timeutil.GetCurrentTimestampByMill(), + ClientMsgID: idutil.GetMsgIDByMD5(mcontext.GetOpUserID(c)), + Options: config.GetOptionsByNotification(config.NotificationConfig{ IsSendMsg: false, ReliabilityLevel: 1, UnreadCount: false, @@ -296,9 +302,8 @@ func (m *MessageApi) BatchSendMsg(c *gin.Context) { apiresp.GinError(c, errs.ErrArgs.WithDetail(err.Error()).Wrap()) return } - log.ZInfo(c, "BatchSendMsg", "req", req) - if err := authverify.CheckAdmin(c, m.Config); err != nil { - apiresp.GinError(c, errs.ErrNoPermission.Wrap("only app manager can send message")) + if err := authverify.CheckAdmin(c, m.imAdminUserID); err != nil { + apiresp.GinError(c, errs.ErrNoPermission.WrapMsg("only app manager can send message")) return } diff --git a/internal/api/route.go b/internal/api/router.go similarity index 59% rename from internal/api/route.go rename to internal/api/router.go index ca0b6829ef..bd2de99db7 100644 --- a/internal/api/route.go +++ b/internal/api/router.go @@ -1,135 +1,25 @@ -// 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 api import ( - "context" "fmt" - "net" - "net/http" - "os" - "os/signal" - "strconv" - "syscall" - "time" - - "github.com/OpenIMSDK/protocol/constant" - "github.com/OpenIMSDK/tools/apiresp" - "github.com/OpenIMSDK/tools/discoveryregistry" - "github.com/OpenIMSDK/tools/errs" - "github.com/OpenIMSDK/tools/log" - "github.com/OpenIMSDK/tools/mw" - "github.com/OpenIMSDK/tools/tokenverify" "github.com/gin-gonic/gin" "github.com/gin-gonic/gin/binding" "github.com/go-playground/validator/v10" - "github.com/openimsdk/open-im-server/v3/pkg/authverify" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" - kdisc "github.com/openimsdk/open-im-server/v3/pkg/common/discoveryregister" - ginprom "github.com/openimsdk/open-im-server/v3/pkg/common/ginprometheus" - "github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics" + "github.com/openimsdk/open-im-server/v3/pkg/common/servererrs" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" - util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" - "github.com/redis/go-redis/v9" + "github.com/openimsdk/protocol/constant" + "github.com/openimsdk/tools/apiresp" + "github.com/openimsdk/tools/discovery" + "github.com/openimsdk/tools/log" + "github.com/openimsdk/tools/mw" "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" + "net/http" ) -func Start(config *config.GlobalConfig, port int, proPort int) error { - if port == 0 || proPort == 0 { - err := "port or proPort is empty:" + strconv.Itoa(port) + "," + strconv.Itoa(proPort) - return errs.Wrap(fmt.Errorf(err)) - } - rdb, err := cache.NewRedis(config) - if err != nil { - return err - } - - var client discoveryregistry.SvcDiscoveryRegistry - - // Determine whether zk is passed according to whether it is a clustered deployment - client, err = kdisc.NewDiscoveryRegister(config) - if err != nil { - return errs.Wrap(err, "register discovery err") - } - - if err = client.CreateRpcRootNodes(config.GetServiceNames()); err != nil { - return errs.Wrap(err, "create rpc root nodes error") - } - - if err = client.RegisterConf2Registry(constant.OpenIMCommonConfigKey, config.EncodeConfig()); err != nil { - return errs.Wrap(err) - } - var ( - netDone = make(chan struct{}, 1) - netErr error - ) - router := newGinRouter(client, rdb, config) - if config.Prometheus.Enable { - go func() { - p := ginprom.NewPrometheus("app", prommetrics.GetGinCusMetrics("Api")) - p.SetListenAddress(fmt.Sprintf(":%d", proPort)) - if err = p.Use(router); err != nil && err != http.ErrServerClosed { - netErr = errs.Wrap(err, fmt.Sprintf("prometheus start err: %d", proPort)) - netDone <- struct{}{} - } - }() - - } - - var address string - if config.Api.ListenIP != "" { - address = net.JoinHostPort(config.Api.ListenIP, strconv.Itoa(port)) - } else { - address = net.JoinHostPort("0.0.0.0", strconv.Itoa(port)) - } - - server := http.Server{Addr: address, Handler: router} - - go func() { - err = server.ListenAndServe() - if err != nil && err != http.ErrServerClosed { - netErr = errs.Wrap(err, fmt.Sprintf("api start err: %s", server.Addr)) - netDone <- struct{}{} - - } - }() - - sigs := make(chan os.Signal, 1) - signal.Notify(sigs, syscall.SIGTERM) - - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) - defer cancel() - select { - case <-sigs: - util.SIGTERMExit() - err := server.Shutdown(ctx) - if err != nil { - return errs.Wrap(err, "shutdown err") - } - case <-netDone: - close(netDone) - return netErr - } - return nil -} - -func newGinRouter(disCov discoveryregistry.SvcDiscoveryRegistry, rdb redis.UniversalClient, config *config.GlobalConfig) *gin.Engine { - disCov.AddOption(mw.GrpcClient(), grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithDefaultServiceConfig(fmt.Sprintf(`{"LoadBalancingPolicy": "%s"}`, "round_robin"))) +func newGinRouter(disCov discovery.SvcDiscoveryRegistry, config *Config) *gin.Engine { + disCov.AddOption(mw.GrpcClient(), grpc.WithTransportCredentials(insecure.NewCredentials()), + grpc.WithDefaultServiceConfig(fmt.Sprintf(`{"LoadBalancingPolicy": "%s"}`, "round_robin"))) gin.SetMode(gin.ReleaseMode) r := gin.New() if v, ok := binding.Validator.Engine().(*validator.Validate); ok { @@ -137,17 +27,18 @@ func newGinRouter(disCov discoveryregistry.SvcDiscoveryRegistry, rdb redis.Unive } r.Use(gin.Recovery(), mw.CorsHandler(), mw.GinParseOperationID()) // init rpc client here - userRpc := rpcclient.NewUser(disCov, config) - groupRpc := rpcclient.NewGroup(disCov, config) - friendRpc := rpcclient.NewFriend(disCov, config) - messageRpc := rpcclient.NewMessage(disCov, config) - conversationRpc := rpcclient.NewConversation(disCov, config) - authRpc := rpcclient.NewAuth(disCov, config) - thirdRpc := rpcclient.NewThird(disCov, config) + userRpc := rpcclient.NewUser(disCov, config.Share.RpcRegisterName.User, config.Share.RpcRegisterName.MessageGateway, + config.Share.IMAdminUserID) + groupRpc := rpcclient.NewGroup(disCov, config.Share.RpcRegisterName.Group) + friendRpc := rpcclient.NewFriend(disCov, config.Share.RpcRegisterName.Friend) + messageRpc := rpcclient.NewMessage(disCov, config.Share.RpcRegisterName.Msg) + conversationRpc := rpcclient.NewConversation(disCov, config.Share.RpcRegisterName.Conversation) + authRpc := rpcclient.NewAuth(disCov, config.Share.RpcRegisterName.Auth) + thirdRpc := rpcclient.NewThird(disCov, config.Share.RpcRegisterName.Third, config.RpcConfig.Prometheus.GrafanaURL) u := NewUserApi(*userRpc) - m := NewMessageApi(messageRpc, userRpc) - ParseToken := GinParseToken(rdb, config) + m := NewMessageApi(messageRpc, userRpc, config.Share.IMAdminUserID) + ParseToken := GinParseToken(authRpc) userRouterGroup := r.Group("/user") { userRouterGroup.POST("/user_register", u.UserRegister) @@ -224,11 +115,6 @@ func newGinRouter(disCov discoveryregistry.SvcDiscoveryRegistry, rdb redis.Unive groupRouterGroup.POST("/get_groups", g.GetGroups) groupRouterGroup.POST("/get_group_member_user_id", g.GetGroupMemberUserIDs) } - superGroupRouterGroup := r.Group("/super_group", ParseToken) - { - superGroupRouterGroup.POST("/get_joined_group_list", g.GetJoinedSuperGroupList) - superGroupRouterGroup.POST("/get_groups_info", g.GetSuperGroupsInfo) - } // certificate authRouterGroup := r.Group("/auth") { @@ -309,68 +195,26 @@ func newGinRouter(disCov discoveryregistry.SvcDiscoveryRegistry, rdb redis.Unive return r } -func GinParseToken(rdb redis.UniversalClient, config *config.GlobalConfig) gin.HandlerFunc { - dataBase := controller.NewAuthDatabase( - cache.NewMsgCacheModel(rdb, config), - config.Secret, - config.TokenPolicy.Expire, - config, - ) +func GinParseToken(authRPC *rpcclient.Auth) gin.HandlerFunc { return func(c *gin.Context) { switch c.Request.Method { case http.MethodPost: token := c.Request.Header.Get(constant.Token) if token == "" { - log.ZWarn(c, "header get token error", errs.ErrArgs.Wrap("header must have token")) - apiresp.GinError(c, errs.ErrArgs.Wrap("header must have token")) - c.Abort() - return - } - claims, err := tokenverify.GetClaimFromToken(token, authverify.Secret(config.Secret)) - if err != nil { - log.ZWarn(c, "jwt get token error", errs.ErrTokenUnknown.Wrap()) - apiresp.GinError(c, errs.ErrTokenUnknown.Wrap()) + log.ZWarn(c, "header get token error", servererrs.ErrArgs.WrapMsg("header must have token")) + apiresp.GinError(c, servererrs.ErrArgs.WrapMsg("header must have token")) c.Abort() return } - m, err := dataBase.GetTokensWithoutError(c, claims.UserID, claims.PlatformID) + resp, err := authRPC.ParseToken(c, token) if err != nil { - apiresp.GinError(c, errs.ErrTokenNotExist.Wrap()) - c.Abort() - return - } - if len(m) == 0 { - apiresp.GinError(c, errs.ErrTokenNotExist.Wrap()) + apiresp.GinError(c, err) c.Abort() return } - if v, ok := m[token]; ok { - switch v { - case constant.NormalToken: - case constant.KickedToken: - apiresp.GinError(c, errs.ErrTokenKicked.Wrap()) - c.Abort() - return - default: - apiresp.GinError(c, errs.ErrTokenUnknown.Wrap()) - c.Abort() - return - } - } else { - apiresp.GinError(c, errs.ErrTokenNotExist.Wrap()) - c.Abort() - return - } - c.Set(constant.OpUserPlatform, constant.PlatformIDToName(claims.PlatformID)) - c.Set(constant.OpUserID, claims.UserID) + c.Set(constant.OpUserPlatform, constant.PlatformIDToName(int(resp.PlatformID))) + c.Set(constant.OpUserID, resp.UserID) c.Next() } } } - -// // handleGinError logs and returns an error response through Gin context. -// func handleGinError(c *gin.Context, logMessage string, errType errs.CodeError, detail string) { -// wrappedErr := errType.Wrap(detail) -// apiresp.GinError(c, wrappedErr) -// c.Abort() -// } diff --git a/internal/api/statistics.go b/internal/api/statistics.go index 2b80a15857..f5ee99f733 100644 --- a/internal/api/statistics.go +++ b/internal/api/statistics.go @@ -15,10 +15,10 @@ package api import ( - "github.com/OpenIMSDK/protocol/user" - "github.com/OpenIMSDK/tools/a2r" "github.com/gin-gonic/gin" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" + "github.com/openimsdk/protocol/user" + "github.com/openimsdk/tools/a2r" ) type StatisticsApi rpcclient.User diff --git a/internal/api/third.go b/internal/api/third.go index 30448ae4dd..6baa70ee5d 100644 --- a/internal/api/third.go +++ b/internal/api/third.go @@ -15,16 +15,20 @@ package api import ( + "context" + "google.golang.org/grpc" "math/rand" "net/http" + "net/url" "strconv" + "strings" - "github.com/OpenIMSDK/protocol/third" - "github.com/OpenIMSDK/tools/a2r" - "github.com/OpenIMSDK/tools/errs" - "github.com/OpenIMSDK/tools/mcontext" "github.com/gin-gonic/gin" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" + "github.com/openimsdk/protocol/third" + "github.com/openimsdk/tools/a2r" + "github.com/openimsdk/tools/errs" + "github.com/openimsdk/tools/mcontext" ) type ThirdApi rpcclient.Third @@ -43,6 +47,35 @@ func (o *ThirdApi) SetAppBadge(c *gin.Context) { // #################### s3 #################### +func setURLPrefixOption[A, B, C any](_ func(client C, ctx context.Context, req *A, options ...grpc.CallOption) (*B, error), fn func(*A) error) *a2r.Option[A, B] { + return &a2r.Option[A, B]{ + BindAfter: fn, + } +} + +func setURLPrefix(c *gin.Context, urlPrefix *string) error { + host := c.GetHeader("X-Request-Api") + if host != "" { + if strings.HasSuffix(host, "/") { + *urlPrefix = host + "object/" + return nil + } else { + *urlPrefix = host + "/object/" + return nil + } + } + u := url.URL{ + Scheme: "http", + Host: c.Request.Host, + Path: "/object/", + } + if c.Request.TLS != nil { + u.Scheme = "https" + } + *urlPrefix = u.String() + return nil +} + func (o *ThirdApi) PartLimit(c *gin.Context) { a2r.Call(third.ThirdClient.PartLimit, o.Client, c) } @@ -52,7 +85,10 @@ func (o *ThirdApi) PartSize(c *gin.Context) { } func (o *ThirdApi) InitiateMultipartUpload(c *gin.Context) { - a2r.Call(third.ThirdClient.InitiateMultipartUpload, o.Client, c) + opt := setURLPrefixOption(third.ThirdClient.InitiateMultipartUpload, func(req *third.InitiateMultipartUploadReq) error { + return setURLPrefix(c, &req.UrlPrefix) + }) + a2r.Call(third.ThirdClient.InitiateMultipartUpload, o.Client, c, opt) } func (o *ThirdApi) AuthSign(c *gin.Context) { @@ -60,7 +96,10 @@ func (o *ThirdApi) AuthSign(c *gin.Context) { } func (o *ThirdApi) CompleteMultipartUpload(c *gin.Context) { - a2r.Call(third.ThirdClient.CompleteMultipartUpload, o.Client, c) + opt := setURLPrefixOption(third.ThirdClient.CompleteMultipartUpload, func(req *third.CompleteMultipartUploadReq) error { + return setURLPrefix(c, &req.UrlPrefix) + }) + a2r.Call(third.ThirdClient.CompleteMultipartUpload, o.Client, c, opt) } func (o *ThirdApi) AccessURL(c *gin.Context) { @@ -72,7 +111,10 @@ func (o *ThirdApi) InitiateFormData(c *gin.Context) { } func (o *ThirdApi) CompleteFormData(c *gin.Context) { - a2r.Call(third.ThirdClient.CompleteFormData, o.Client, c) + opt := setURLPrefixOption(third.ThirdClient.CompleteFormData, func(req *third.CompleteFormDataReq) error { + return setURLPrefix(c, &req.UrlPrefix) + }) + a2r.Call(third.ThirdClient.CompleteFormData, o.Client, c, opt) } func (o *ThirdApi) ObjectRedirect(c *gin.Context) { @@ -126,5 +168,5 @@ func (o *ThirdApi) SearchLogs(c *gin.Context) { } func (o *ThirdApi) GetPrometheus(c *gin.Context) { - c.Redirect(http.StatusFound, o.Config.Prometheus.GrafanaUrl) + c.Redirect(http.StatusFound, o.GrafanaUrl) } diff --git a/internal/api/user.go b/internal/api/user.go index 16b453e467..d48111b9eb 100644 --- a/internal/api/user.go +++ b/internal/api/user.go @@ -15,15 +15,15 @@ package api import ( - "github.com/OpenIMSDK/protocol/constant" - "github.com/OpenIMSDK/protocol/msggateway" - "github.com/OpenIMSDK/protocol/user" - "github.com/OpenIMSDK/tools/a2r" - "github.com/OpenIMSDK/tools/apiresp" - "github.com/OpenIMSDK/tools/errs" - "github.com/OpenIMSDK/tools/log" "github.com/gin-gonic/gin" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" + "github.com/openimsdk/protocol/constant" + "github.com/openimsdk/protocol/msggateway" + "github.com/openimsdk/protocol/user" + "github.com/openimsdk/tools/a2r" + "github.com/openimsdk/tools/apiresp" + "github.com/openimsdk/tools/errs" + "github.com/openimsdk/tools/log" ) type UserApi rpcclient.User @@ -69,7 +69,7 @@ func (u *UserApi) GetUsersOnlineStatus(c *gin.Context) { apiresp.GinError(c, err) return } - conns, err := u.Discov.GetConns(c, u.Config.RpcRegisterName.OpenImMessageGatewayName) + conns, err := u.Discov.GetConns(c, u.MessageGateWayRpcName) if err != nil { apiresp.GinError(c, err) return @@ -133,7 +133,7 @@ func (u *UserApi) GetUsersOnlineTokenDetail(c *gin.Context) { apiresp.GinError(c, errs.ErrArgs.WithDetail(err.Error()).Wrap()) return } - conns, err := u.Discov.GetConns(c, u.Config.RpcRegisterName.OpenImMessageGatewayName) + conns, err := u.Discov.GetConns(c, u.MessageGateWayRpcName) if err != nil { apiresp.GinError(c, err) return diff --git a/internal/msggateway/callback.go b/internal/msggateway/callback.go index afb83bcc48..1750f779bf 100644 --- a/internal/msggateway/callback.go +++ b/internal/msggateway/callback.go @@ -18,21 +18,17 @@ import ( "context" "time" - "github.com/OpenIMSDK/protocol/constant" - "github.com/OpenIMSDK/tools/mcontext" cbapi "github.com/openimsdk/open-im-server/v3/pkg/callbackstruct" "github.com/openimsdk/open-im-server/v3/pkg/common/config" - "github.com/openimsdk/open-im-server/v3/pkg/common/http" + "github.com/openimsdk/protocol/constant" + "github.com/openimsdk/tools/mcontext" ) -func CallbackUserOnline(ctx context.Context, globalConfig *config.GlobalConfig, userID string, platformID int, isAppBackground bool, connID string) error { - if !globalConfig.Callback.CallbackUserOnline.Enable { - return nil - } +func (ws *WsServer) webhookAfterUserOnline(ctx context.Context, after *config.AfterConfig, userID string, platformID int, isAppBackground bool, connID string) { req := cbapi.CallbackUserOnlineReq{ UserStatusCallbackReq: cbapi.UserStatusCallbackReq{ UserStatusBaseCallback: cbapi.UserStatusBaseCallback{ - CallbackCommand: cbapi.CallbackUserOnlineCommand, + CallbackCommand: cbapi.CallbackAfterUserOnlineCommand, OperationID: mcontext.GetOperationID(ctx), PlatformID: platformID, Platform: constant.PlatformIDToName(platformID), @@ -43,21 +39,14 @@ func CallbackUserOnline(ctx context.Context, globalConfig *config.GlobalConfig, IsAppBackground: isAppBackground, ConnID: connID, } - resp := cbapi.CommonCallbackResp{} - if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, &req, &resp, globalConfig.Callback.CallbackUserOnline); err != nil { - return err - } - return nil + ws.webhookClient.AsyncPost(ctx, req.GetCallbackCommand(), req, &cbapi.CommonCallbackResp{}, after) } -func CallbackUserOffline(ctx context.Context, globalConfig *config.GlobalConfig, userID string, platformID int, connID string) error { - if !globalConfig.Callback.CallbackUserOffline.Enable { - return nil - } +func (ws *WsServer) webhookAfterUserOffline(ctx context.Context, after *config.AfterConfig, userID string, platformID int, connID string) { req := &cbapi.CallbackUserOfflineReq{ UserStatusCallbackReq: cbapi.UserStatusCallbackReq{ UserStatusBaseCallback: cbapi.UserStatusBaseCallback{ - CallbackCommand: cbapi.CallbackUserOfflineCommand, + CallbackCommand: cbapi.CallbackAfterUserOfflineCommand, OperationID: mcontext.GetOperationID(ctx), PlatformID: platformID, Platform: constant.PlatformIDToName(platformID), @@ -67,21 +56,14 @@ func CallbackUserOffline(ctx context.Context, globalConfig *config.GlobalConfig, Seq: time.Now().UnixMilli(), ConnID: connID, } - resp := &cbapi.CallbackUserOfflineResp{} - if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, req, resp, globalConfig.Callback.CallbackUserOffline); err != nil { - return err - } - return nil + ws.webhookClient.AsyncPost(ctx, req.GetCallbackCommand(), req, &cbapi.CallbackUserOfflineResp{}, after) } -func CallbackUserKickOff(ctx context.Context, globalConfig *config.GlobalConfig, userID string, platformID int) error { - if !globalConfig.Callback.CallbackUserKickOff.Enable { - return nil - } +func (ws *WsServer) webhookAfterUserKickOff(ctx context.Context, after *config.AfterConfig, userID string, platformID int) { req := &cbapi.CallbackUserKickOffReq{ UserStatusCallbackReq: cbapi.UserStatusCallbackReq{ UserStatusBaseCallback: cbapi.UserStatusBaseCallback{ - CallbackCommand: cbapi.CallbackUserKickOffCommand, + CallbackCommand: cbapi.CallbackAfterUserKickOffCommand, OperationID: mcontext.GetOperationID(ctx), PlatformID: platformID, Platform: constant.PlatformIDToName(platformID), @@ -90,93 +72,5 @@ func CallbackUserKickOff(ctx context.Context, globalConfig *config.GlobalConfig, }, Seq: time.Now().UnixMilli(), } - resp := &cbapi.CommonCallbackResp{} - if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, req, resp, globalConfig.Callback.CallbackUserOffline); err != nil { - return err - } - return nil + ws.webhookClient.AsyncPost(ctx, req.GetCallbackCommand(), req, &cbapi.CommonCallbackResp{}, after) } - -// func callbackUserOnline(operationID, userID string, platformID int, token string, isAppBackground bool, connID -// string) cbApi.CommonCallbackResp { -// callbackResp := cbApi.CommonCallbackResp{OperationID: operationID} -// if !config.Config.Callback.CallbackUserOnline.WithEnable { -// return callbackResp -// } -// callbackUserOnlineReq := cbApi.CallbackUserOnlineReq{ -// Token: token, -// UserStatusCallbackReq: cbApi.UserStatusCallbackReq{ -// UserStatusBaseCallback: cbApi.UserStatusBaseCallback{ -// CallbackCommand: constant.CallbackUserOnlineCommand, -// OperationID: operationID, -// PlatformID: int32(platformID), -// Platform: constant.PlatformIDToName(platformID), -// }, -// UserID: userID, -// }, -// Seq: int(time.Now().UnixNano() / 1e6), -// IsAppBackground: isAppBackground, -// ConnID: connID, -// } -// callbackUserOnlineResp := &cbApi.CallbackUserOnlineResp{CommonCallbackResp: &callbackResp} -// if err := http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, constant.CallbackUserOnlineCommand, -// callbackUserOnlineReq, callbackUserOnlineResp, config.Config.Callback.CallbackUserOnline.CallbackTimeOut); err != nil -// { -// callbackResp.ErrCode = http2.StatusInternalServerError -// callbackResp.ErrMsg = err.Error() -// } -// return callbackResp -//} -//func callbackUserOffline(operationID, userID string, platformID int, connID string) cbApi.CommonCallbackResp { -// callbackResp := cbApi.CommonCallbackResp{OperationID: operationID} -// if !config.Config.Callback.CallbackUserOffline.WithEnable { -// return callbackResp -// } -// callbackOfflineReq := cbApi.CallbackUserOfflineReq{ -// UserStatusCallbackReq: cbApi.UserStatusCallbackReq{ -// UserStatusBaseCallback: cbApi.UserStatusBaseCallback{ -// CallbackCommand: constant.CallbackUserOfflineCommand, -// OperationID: operationID, -// PlatformID: int32(platformID), -// Platform: constant.PlatformIDToName(platformID), -// }, -// UserID: userID, -// }, -// Seq: int(time.Now().UnixNano() / 1e6), -// ConnID: connID, -// } -// callbackUserOfflineResp := &cbApi.CallbackUserOfflineResp{CommonCallbackResp: &callbackResp} -// if err := http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, constant.CallbackUserOfflineCommand, -// callbackOfflineReq, callbackUserOfflineResp, config.Config.Callback.CallbackUserOffline.CallbackTimeOut); err != nil -// { -// callbackResp.ErrCode = http2.StatusInternalServerError -// callbackResp.ErrMsg = err.Error() -// } -// return callbackResp -//} -//func callbackUserKickOff(operationID string, userID string, platformID int) cbApi.CommonCallbackResp { -// callbackResp := cbApi.CommonCallbackResp{OperationID: operationID} -// if !config.Config.Callback.CallbackUserKickOff.WithEnable { -// return callbackResp -// } -// callbackUserKickOffReq := cbApi.CallbackUserKickOffReq{ -// UserStatusCallbackReq: cbApi.UserStatusCallbackReq{ -// UserStatusBaseCallback: cbApi.UserStatusBaseCallback{ -// CallbackCommand: constant.CallbackUserKickOffCommand, -// OperationID: operationID, -// PlatformID: int32(platformID), -// Platform: constant.PlatformIDToName(platformID), -// }, -// UserID: userID, -// }, -// Seq: int(time.Now().UnixNano() / 1e6), -// } -// callbackUserKickOffResp := &cbApi.CallbackUserKickOffResp{CommonCallbackResp: &callbackResp} -// if err := http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, constant.CallbackUserKickOffCommand, -// callbackUserKickOffReq, callbackUserKickOffResp, config.Config.Callback.CallbackUserOffline.CallbackTimeOut); err != -// nil { -// callbackResp.ErrCode = http2.StatusInternalServerError -// callbackResp.ErrMsg = err.Error() -// } -// return callbackResp -//} diff --git a/internal/msggateway/client.go b/internal/msggateway/client.go index 4e843821e2..af869dd850 100644 --- a/internal/msggateway/client.go +++ b/internal/msggateway/client.go @@ -16,28 +16,27 @@ package msggateway import ( "context" - "errors" "fmt" "runtime/debug" "sync" "sync/atomic" - "github.com/OpenIMSDK/protocol/constant" - "github.com/OpenIMSDK/protocol/sdkws" - "github.com/OpenIMSDK/tools/apiresp" - "github.com/OpenIMSDK/tools/errs" - "github.com/OpenIMSDK/tools/log" - "github.com/OpenIMSDK/tools/mcontext" - "github.com/OpenIMSDK/tools/utils" "github.com/openimsdk/open-im-server/v3/pkg/msgprocessor" + "github.com/openimsdk/protocol/constant" + "github.com/openimsdk/protocol/sdkws" + "github.com/openimsdk/tools/apiresp" + "github.com/openimsdk/tools/errs" + "github.com/openimsdk/tools/log" + "github.com/openimsdk/tools/mcontext" + "github.com/openimsdk/tools/utils/stringutil" "google.golang.org/protobuf/proto" ) var ( - ErrConnClosed = errors.New("conn has closed") - ErrNotSupportMessageProtocol = errors.New("not support message protocol") - ErrClientClosed = errors.New("client actively close the connection") - ErrPanic = errors.New("panic error") + ErrConnClosed = errs.New("conn has closed") + ErrNotSupportMessageProtocol = errs.New("not support message protocol") + ErrClientClosed = errs.New("client actively close the connection") + ErrPanic = errs.New("panic error") ) const ( @@ -75,32 +74,20 @@ type Client struct { token string } -// function not used -// func newClient(ctx *UserConnContext, conn LongConn, isCompress bool) *Client { -// return &Client{ -// w: new(sync.Mutex), -// conn: conn, -// PlatformID: utils.StringToInt(ctx.GetPlatformID()), -// IsCompress: isCompress, -// UserID: ctx.GetUserID(), -// ctx: ctx, -// } -// } - // ResetClient updates the client's state with new connection and context information. -func (c *Client) ResetClient(ctx *UserConnContext, conn LongConn, isBackground, isCompress bool, longConnServer LongConnServer, token string) { +func (c *Client) ResetClient(ctx *UserConnContext, conn LongConn, longConnServer LongConnServer) { c.w = new(sync.Mutex) c.conn = conn - c.PlatformID = utils.StringToInt(ctx.GetPlatformID()) - c.IsCompress = isCompress - c.IsBackground = isBackground + c.PlatformID = stringutil.StringToInt(ctx.GetPlatformID()) + c.IsCompress = ctx.GetCompression() + c.IsBackground = ctx.GetBackground() c.UserID = ctx.GetUserID() c.ctx = ctx c.longConnServer = longConnServer c.IsBackground = false c.closed.Store(false) c.closedErr = nil - c.token = token + c.token = ctx.GetToken() } func (c *Client) pingHandler(_ string) error { @@ -126,6 +113,7 @@ func (c *Client) readMessage() { c.conn.SetPingHandler(c.pingHandler) for { + log.ZDebug(c.ctx, "readMessage") messageType, message, returnErr := c.conn.ReadMessage() if returnErr != nil { log.ZWarn(c.ctx, "readMessage", returnErr, "messageType", messageType) @@ -187,7 +175,7 @@ func (c *Client) handleMessage(message []byte) error { } if binaryReq.SendID != c.UserID { - return errs.Wrap(errors.New("exception conn userID not same to req userID"), binaryReq.String()) + return errs.New("exception conn userID not same to req userID", "binaryReq", binaryReq.String()) } ctx := mcontext.WithMustInfoCtx( @@ -267,7 +255,7 @@ func (c *Client) replyMessage(ctx context.Context, binaryReq *Req, err error, re } if binaryReq.ReqIdentifier == WsLogoutMsg { - return errs.Wrap(errors.New("user logout")) + return errs.New("user logout", "operationID", binaryReq.OperationID).Wrap() } return nil } diff --git a/internal/msggateway/compressor.go b/internal/msggateway/compressor.go index 140aac4d86..52d315b79b 100644 --- a/internal/msggateway/compressor.go +++ b/internal/msggateway/compressor.go @@ -20,7 +20,7 @@ import ( "io" "sync" - "github.com/OpenIMSDK/tools/errs" + "github.com/openimsdk/tools/errs" ) var ( @@ -34,6 +34,7 @@ type Compressor interface { DeCompress(compressedData []byte) ([]byte, error) DecompressWithPool(compressedData []byte) ([]byte, error) } + type GzipCompressor struct { compressProtocol string } @@ -47,11 +48,11 @@ func (g *GzipCompressor) Compress(rawData []byte) ([]byte, error) { gz := gzip.NewWriter(&gzipBuffer) if _, err := gz.Write(rawData); err != nil { - return nil, errs.Wrap(err, "GzipCompressor.Compress: writing to gzip writer failed") + return nil, errs.WrapMsg(err, "GzipCompressor.Compress: writing to gzip writer failed") } if err := gz.Close(); err != nil { - return nil, errs.Wrap(err, "GzipCompressor.Compress: closing gzip writer failed") + return nil, errs.WrapMsg(err, "GzipCompressor.Compress: closing gzip writer failed") } return gzipBuffer.Bytes(), nil @@ -65,10 +66,10 @@ func (g *GzipCompressor) CompressWithPool(rawData []byte) ([]byte, error) { gz.Reset(&gzipBuffer) if _, err := gz.Write(rawData); err != nil { - return nil, errs.Wrap(err, "GzipCompressor.CompressWithPool: error writing data") + return nil, errs.WrapMsg(err, "GzipCompressor.CompressWithPool: error writing data") } if err := gz.Close(); err != nil { - return nil, errs.Wrap(err, "GzipCompressor.CompressWithPool: error closing gzip writer") + return nil, errs.WrapMsg(err, "GzipCompressor.CompressWithPool: error closing gzip writer") } return gzipBuffer.Bytes(), nil } @@ -77,16 +78,16 @@ func (g *GzipCompressor) DeCompress(compressedData []byte) ([]byte, error) { buff := bytes.NewBuffer(compressedData) reader, err := gzip.NewReader(buff) if err != nil { - return nil, errs.Wrap(err, "GzipCompressor.DeCompress: NewReader creation failed") + return nil, errs.WrapMsg(err, "GzipCompressor.DeCompress: NewReader creation failed") } decompressedData, err := io.ReadAll(reader) if err != nil { - return nil, errs.Wrap(err, "GzipCompressor.DeCompress: reading from gzip reader failed") + return nil, errs.WrapMsg(err, "GzipCompressor.DeCompress: reading from gzip reader failed") } if err = reader.Close(); err != nil { // Even if closing the reader fails, we've successfully read the data, // so we return the decompressed data and an error indicating the close failure. - return decompressedData, errs.Wrap(err, "GzipCompressor.DeCompress: closing gzip reader failed") + return decompressedData, errs.WrapMsg(err, "GzipCompressor.DeCompress: closing gzip reader failed") } return decompressedData, nil } @@ -97,16 +98,16 @@ func (g *GzipCompressor) DecompressWithPool(compressedData []byte) ([]byte, erro err := reader.Reset(bytes.NewReader(compressedData)) if err != nil { - return nil, errs.Wrap(err, "GzipCompressor.DecompressWithPool: resetting gzip reader failed") + return nil, errs.WrapMsg(err, "GzipCompressor.DecompressWithPool: resetting gzip reader failed") } decompressedData, err := io.ReadAll(reader) if err != nil { - return nil, errs.Wrap(err, "GzipCompressor.DecompressWithPool: reading from pooled gzip reader failed") + return nil, errs.WrapMsg(err, "GzipCompressor.DecompressWithPool: reading from pooled gzip reader failed") } if err = reader.Close(); err != nil { // Similar to DeCompress, return the data and error for close failure. - return decompressedData, errs.Wrap(err, "GzipCompressor.DecompressWithPool: closing pooled gzip reader failed") + return decompressedData, errs.WrapMsg(err, "GzipCompressor.DecompressWithPool: closing pooled gzip reader failed") } return decompressedData, nil } diff --git a/internal/msggateway/constant.go b/internal/msggateway/constant.go index 045629b4ee..64664ac0ab 100644 --- a/internal/msggateway/constant.go +++ b/internal/msggateway/constant.go @@ -26,7 +26,7 @@ const ( Compression = "compression" GzipCompressionProtocol = "gzip" BackgroundStatus = "isBackground" - MsgResp = "isMsgResp" + SendResponse = "isMsgResp" ) const ( diff --git a/internal/msggateway/context.go b/internal/msggateway/context.go index ad679c1a14..6c80ece1ba 100644 --- a/internal/msggateway/context.go +++ b/internal/msggateway/context.go @@ -15,13 +15,16 @@ package msggateway import ( + "github.com/openimsdk/open-im-server/v3/pkg/common/servererrs" "net/http" "net/url" "strconv" "time" - "github.com/OpenIMSDK/protocol/constant" - "github.com/OpenIMSDK/tools/utils" + "github.com/openimsdk/protocol/constant" + "github.com/openimsdk/tools/utils/encrypt" + "github.com/openimsdk/tools/utils/stringutil" + "github.com/openimsdk/tools/utils/timeutil" ) type UserConnContext struct { @@ -54,7 +57,7 @@ func (c *UserConnContext) Value(key any) any { case constant.ConnID: return c.GetConnID() case constant.OpUserPlatform: - return constant.PlatformIDToName(utils.StringToInt(c.GetPlatformID())) + return constant.PlatformIDToName(stringutil.StringToInt(c.GetPlatformID())) case constant.RemoteAddr: return c.RemoteAddr default: @@ -69,7 +72,7 @@ func newContext(respWriter http.ResponseWriter, req *http.Request) *UserConnCont Path: req.URL.Path, Method: req.Method, RemoteAddr: req.RemoteAddr, - ConnID: utils.Md5(req.RemoteAddr + "_" + strconv.Itoa(int(utils.GetCurrentTimestampByMill()))), + ConnID: encrypt.Md5(req.RemoteAddr + "_" + strconv.Itoa(int(timeutil.GetCurrentTimestampByMill()))), } } @@ -133,6 +136,32 @@ func (c *UserConnContext) GetToken() string { return c.Req.URL.Query().Get(Token) } +func (c *UserConnContext) GetCompression() bool { + compression, exists := c.Query(Compression) + if exists && compression == GzipCompressionProtocol { + return true + } else { + compression, exists := c.GetHeader(Compression) + if exists && compression == GzipCompressionProtocol { + return true + } + } + return false +} + +func (c *UserConnContext) ShouldSendResp() bool { + errResp, exists := c.Query(SendResponse) + if exists { + b, err := strconv.ParseBool(errResp) + if err != nil { + return false + } else { + return b + } + } + return false +} + func (c *UserConnContext) SetToken(token string) { c.Req.URL.RawQuery = Token + "=" + token } @@ -144,3 +173,23 @@ func (c *UserConnContext) GetBackground() bool { } return b } +func (c *UserConnContext) ParseEssentialArgs() error { + _, exists := c.Query(Token) + if !exists { + return servererrs.ErrConnArgsErr.WrapMsg("token is empty") + } + _, exists = c.Query(WsUserID) + if !exists { + return servererrs.ErrConnArgsErr.WrapMsg("sendID is empty") + } + platformIDStr, exists := c.Query(PlatformID) + if !exists { + return servererrs.ErrConnArgsErr.WrapMsg("platformID is empty") + } + _, err := strconv.Atoi(platformIDStr) + if err != nil { + return servererrs.ErrConnArgsErr.WrapMsg("platformID is not int") + + } + return nil +} diff --git a/internal/msggateway/encoder.go b/internal/msggateway/encoder.go index cd2c50d964..3af2663748 100644 --- a/internal/msggateway/encoder.go +++ b/internal/msggateway/encoder.go @@ -18,7 +18,7 @@ import ( "bytes" "encoding/gob" - "github.com/OpenIMSDK/tools/errs" + "github.com/openimsdk/tools/errs" ) type Encoder interface { @@ -35,9 +35,8 @@ func NewGobEncoder() *GobEncoder { func (g *GobEncoder) Encode(data any) ([]byte, error) { buff := bytes.Buffer{} enc := gob.NewEncoder(&buff) - err := enc.Encode(data) - if err != nil { - return nil, errs.Wrap(err, "GobEncoder.Encode failed") + if err := enc.Encode(data); err != nil { + return nil, errs.WrapMsg(err, "GobEncoder.Encode failed", "action", "encode") } return buff.Bytes(), nil } @@ -45,9 +44,8 @@ func (g *GobEncoder) Encode(data any) ([]byte, error) { func (g *GobEncoder) Decode(encodeData []byte, decodeData any) error { buff := bytes.NewBuffer(encodeData) dec := gob.NewDecoder(buff) - err := dec.Decode(decodeData) - if err != nil { - return errs.Wrap(err, "GobEncoder.Decode failed") + if err := dec.Decode(decodeData); err != nil { + return errs.WrapMsg(err, "GobEncoder.Decode failed", "action", "decode") } return nil } diff --git a/internal/msggateway/http_error.go b/internal/msggateway/http_error.go index 03881cf270..8d9d035226 100644 --- a/internal/msggateway/http_error.go +++ b/internal/msggateway/http_error.go @@ -14,8 +14,12 @@ package msggateway -import "github.com/OpenIMSDK/tools/apiresp" +import ( + "github.com/openimsdk/tools/apiresp" + "github.com/openimsdk/tools/log" +) func httpError(ctx *UserConnContext, err error) { + log.ZWarn(ctx, "ws connection error", err) apiresp.HttpError(ctx.RespWriter, err) } diff --git a/internal/msggateway/hub_server.go b/internal/msggateway/hub_server.go index 1465655615..bfe81b6024 100644 --- a/internal/msggateway/hub_server.go +++ b/internal/msggateway/hub_server.go @@ -16,38 +16,30 @@ package msggateway import ( "context" - - "github.com/OpenIMSDK/protocol/constant" - "github.com/OpenIMSDK/protocol/msggateway" - "github.com/OpenIMSDK/tools/discoveryregistry" - "github.com/OpenIMSDK/tools/errs" - "github.com/OpenIMSDK/tools/log" - "github.com/OpenIMSDK/tools/mcontext" "github.com/openimsdk/open-im-server/v3/pkg/authverify" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" + "github.com/openimsdk/open-im-server/v3/pkg/common/servererrs" "github.com/openimsdk/open-im-server/v3/pkg/common/startrpc" + "github.com/openimsdk/protocol/constant" + "github.com/openimsdk/protocol/msggateway" + "github.com/openimsdk/tools/discovery" + "github.com/openimsdk/tools/errs" + "github.com/openimsdk/tools/log" + "github.com/openimsdk/tools/mcontext" "google.golang.org/grpc" ) -func (s *Server) InitServer(config *config.GlobalConfig, disCov discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) error { - rdb, err := cache.NewRedis(config) - if err != nil { - return err - } - - msgModel := cache.NewMsgCacheModel(rdb, config) +func (s *Server) InitServer(ctx context.Context, config *Config, disCov discovery.SvcDiscoveryRegistry, server *grpc.Server) error { s.LongConnServer.SetDiscoveryRegistry(disCov, config) - s.LongConnServer.SetCacheHandler(msgModel) msggateway.RegisterMsgGatewayServer(server, s) return nil } -func (s *Server) Start(conf *config.GlobalConfig) error { - return startrpc.Start( - s.rpcPort, - conf.RpcRegisterName.OpenImMessageGatewayName, - s.prometheusPort, +func (s *Server) Start(ctx context.Context, index int, conf *Config) error { + return startrpc.Start(ctx, &conf.ZookeeperConfig, &conf.MsgGateway.Prometheus, conf.MsgGateway.ListenIP, + conf.MsgGateway.RPC.RegisterIP, + conf.MsgGateway.RPC.Ports, index, + conf.Share.RpcRegisterName.MessageGateway, + &conf.Share, conf, s.InitServer, ) @@ -57,7 +49,7 @@ type Server struct { rpcPort int prometheusPort int LongConnServer LongConnServer - config *config.GlobalConfig + config *Config pushTerminal map[int]struct{} } @@ -65,7 +57,7 @@ func (s *Server) SetLongConnServer(LongConnServer LongConnServer) { s.LongConnServer = LongConnServer } -func NewServer(rpcPort int, proPort int, longConnServer LongConnServer, conf *config.GlobalConfig) *Server { +func NewServer(rpcPort int, proPort int, longConnServer LongConnServer, conf *Config) *Server { s := &Server{ rpcPort: rpcPort, prometheusPort: proPort, @@ -89,8 +81,8 @@ func (s *Server) GetUsersOnlineStatus( ctx context.Context, req *msggateway.GetUsersOnlineStatusReq, ) (*msggateway.GetUsersOnlineStatusResp, error) { - if !authverify.IsAppManagerUid(ctx, s.config) { - return nil, errs.ErrNoPermission.Wrap("only app manager") + if !authverify.IsAppManagerUid(ctx, s.config.Share.IMAdminUserID) { + return nil, errs.ErrNoPermission.WrapMsg("only app manager") } var resp msggateway.GetUsersOnlineStatusResp for _, userID := range req.UserIDs { @@ -122,11 +114,9 @@ func (s *Server) GetUsersOnlineStatus( return &resp, nil } -func (s *Server) OnlineBatchPushOneMsg( - ctx context.Context, - req *msggateway.OnlineBatchPushOneMsgReq, -) (*msggateway.OnlineBatchPushOneMsgResp, error) { - panic("implement me") +func (s *Server) OnlineBatchPushOneMsg(ctx context.Context, req *msggateway.OnlineBatchPushOneMsgReq) (*msggateway.OnlineBatchPushOneMsgResp, error) { + // todo implement + return nil, nil } func (s *Server) SuperGroupOnlineBatchPushOneMsg(ctx context.Context, req *msggateway.OnlineBatchPushOneMsgReq, @@ -158,7 +148,7 @@ func (s *Server) SuperGroupOnlineBatchPushOneMsg(ctx context.Context, req *msgga (client.IsBackground && client.PlatformID != constant.IOSPlatformID) { err := client.PushMessage(ctx, req.MsgData) if err != nil { - userPlatform.ResultCode = int64(errs.ErrPushMsgErr.Code()) + userPlatform.ResultCode = int64(servererrs.ErrPushMsgErr.Code()) resp = append(resp, userPlatform) } else { if _, ok := s.pushTerminal[client.PlatformID]; ok { @@ -167,7 +157,7 @@ func (s *Server) SuperGroupOnlineBatchPushOneMsg(ctx context.Context, req *msgga } } } else { - userPlatform.ResultCode = int64(errs.ErrIOSBackgroundPushErr.Code()) + userPlatform.ResultCode = int64(servererrs.ErrIOSBackgroundPushErr.Code()) resp = append(resp, userPlatform) } } @@ -187,7 +177,7 @@ func (s *Server) KickUserOffline( for _, v := range req.KickUserIDList { clients, _, ok := s.LongConnServer.GetUserPlatformCons(v, int(req.PlatformID)) if !ok { - log.ZInfo(ctx, "conn not exist", "userID", v, "platformID", req.PlatformID) + log.ZDebug(ctx, "conn not exist", "userID", v, "platformID", req.PlatformID) continue } @@ -203,10 +193,7 @@ func (s *Server) KickUserOffline( return &msggateway.KickUserOfflineResp{}, nil } -func (s *Server) MultiTerminalLoginCheck( - ctx context.Context, - req *msggateway.MultiTerminalLoginCheckReq, -) (*msggateway.MultiTerminalLoginCheckResp, error) { +func (s *Server) MultiTerminalLoginCheck(ctx context.Context, req *msggateway.MultiTerminalLoginCheckReq) (*msggateway.MultiTerminalLoginCheckResp, error) { if oldClients, userOK, clientOK := s.LongConnServer.GetUserPlatformCons(req.UserID, int(req.PlatformID)); userOK { tempUserCtx := newTempContext() tempUserCtx.SetToken(req.Token) diff --git a/internal/msggateway/init.go b/internal/msggateway/init.go index 4efbb7cdf5..727ade0afd 100644 --- a/internal/msggateway/init.go +++ b/internal/msggateway/init.go @@ -15,22 +15,43 @@ package msggateway import ( - "fmt" + "context" + "github.com/openimsdk/open-im-server/v3/pkg/common/config" + "github.com/openimsdk/tools/utils/datautil" "time" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" + "github.com/openimsdk/tools/log" ) -// RunWsAndServer run ws server. -func RunWsAndServer(conf *config.GlobalConfig, rpcPort, wsPort, prometheusPort int) error { - fmt.Println("start rpc/msg_gateway server, port: ", rpcPort, wsPort, prometheusPort, ", OpenIM version: ", config.Version) +type Config struct { + MsgGateway config.MsgGateway + ZookeeperConfig config.ZooKeeper + Share config.Share + WebhooksConfig config.Webhooks +} + +// Start run ws server. +func Start(ctx context.Context, index int, conf *Config) error { + log.CInfo(ctx, "MSG-GATEWAY server is initializing", "rpcPorts", conf.MsgGateway.RPC.Ports, + "wsPort", conf.MsgGateway.LongConnSvr.Ports, "prometheusPorts", conf.MsgGateway.Prometheus.Ports) + wsPort, err := datautil.GetElemByIndex(conf.MsgGateway.LongConnSvr.Ports, index) + if err != nil { + return err + } + prometheusPort, err := datautil.GetElemByIndex(conf.MsgGateway.Prometheus.Ports, index) + if err != nil { + return err + } + rpcPort, err := datautil.GetElemByIndex(conf.MsgGateway.RPC.Ports, index) + if err != nil { + return err + } longServer, err := NewWsServer( conf, WithPort(wsPort), - WithMaxConnNum(int64(conf.LongConnSvr.WebsocketMaxConnNum)), - WithHandshakeTimeout(time.Duration(conf.LongConnSvr.WebsocketTimeout)*time.Second), - WithMessageMaxMsgLength(conf.LongConnSvr.WebsocketMaxMsgLen), - WithWriteBufferSize(conf.LongConnSvr.WebsocketWriteBufferSize), + WithMaxConnNum(int64(conf.MsgGateway.LongConnSvr.WebsocketMaxConnNum)), + WithHandshakeTimeout(time.Duration(conf.MsgGateway.LongConnSvr.WebsocketTimeout)*time.Second), + WithMessageMaxMsgLength(conf.MsgGateway.LongConnSvr.WebsocketMaxMsgLen), ) if err != nil { return err @@ -39,7 +60,7 @@ func RunWsAndServer(conf *config.GlobalConfig, rpcPort, wsPort, prometheusPort i hubServer := NewServer(rpcPort, prometheusPort, longServer, conf) netDone := make(chan error) go func() { - err = hubServer.Start(conf) + err = hubServer.Start(ctx, index, conf) netDone <- err }() return hubServer.LongConnServer.Run(netDone) diff --git a/internal/msggateway/long_conn.go b/internal/msggateway/long_conn.go index 7dc79c834f..7d5bef4c3a 100644 --- a/internal/msggateway/long_conn.go +++ b/internal/msggateway/long_conn.go @@ -15,12 +15,13 @@ package msggateway import ( - "errors" + "encoding/json" + "github.com/openimsdk/tools/apiresp" "net/http" "time" - "github.com/OpenIMSDK/tools/errs" "github.com/gorilla/websocket" + "github.com/openimsdk/tools/errs" ) type LongConn interface { @@ -75,7 +76,7 @@ func (d *GWebSocket) GenerateLongConn(w http.ResponseWriter, r *http.Request) er conn, err := upgrader.Upgrade(w, r, nil) if err != nil { // The upgrader.Upgrade method usually returns enough error messages to diagnose problems that may occur during the upgrade - return errs.Wrap(err, "GenerateLongConn: WebSocket upgrade failed") + return errs.WrapMsg(err, "GenerateLongConn: WebSocket upgrade failed") } d.conn = conn return nil @@ -86,7 +87,7 @@ func (d *GWebSocket) WriteMessage(messageType int, message []byte) error { return d.conn.WriteMessage(messageType, message) } -//func (d *GWebSocket) setSendConn(sendConn *websocket.Conn) { +// func (d *GWebSocket) setSendConn(sendConn *websocket.Conn) { // d.sendConn = sendConn //} @@ -99,24 +100,24 @@ func (d *GWebSocket) SetReadDeadline(timeout time.Duration) error { } func (d *GWebSocket) SetWriteDeadline(timeout time.Duration) error { - // TODO add error if timeout <= 0 { - return errs.Wrap(errors.New("timeout must be greater than 0")) + return errs.New("timeout must be greater than 0") } // TODO SetWriteDeadline Future add error handling if err := d.conn.SetWriteDeadline(time.Now().Add(timeout)); err != nil { - return errs.Wrap(err, "GWebSocket.SetWriteDeadline failed") + return errs.WrapMsg(err, "GWebSocket.SetWriteDeadline failed") } return nil } func (d *GWebSocket) Dial(urlStr string, requestHeader http.Header) (*http.Response, error) { conn, httpResp, err := websocket.DefaultDialer.Dial(urlStr, requestHeader) - if err == nil { - d.conn = conn + if err != nil { + return httpResp, errs.WrapMsg(err, "GWebSocket.Dial failed", "url", urlStr) } - return httpResp, err + d.conn = conn + return httpResp, nil } func (d *GWebSocket) IsNil() bool { @@ -144,6 +145,34 @@ func (d *GWebSocket) SetPingHandler(handler PingPongHandler) { d.conn.SetPingHandler(handler) } -//func (d *GWebSocket) CheckSendConnDiffNow() bool { -// return d.conn == d.sendConn -//} +func (d *GWebSocket) RespondWithError(err error, w http.ResponseWriter, r *http.Request) error { + if err := d.GenerateLongConn(w, r); err != nil { + return err + } + data, err := json.Marshal(apiresp.ParseError(err)) + if err != nil { + _ = d.Close() + return errs.WrapMsg(err, "json marshal failed") + } + + if err := d.WriteMessage(MessageText, data); err != nil { + _ = d.Close() + return errs.WrapMsg(err, "WriteMessage failed") + } + _ = d.Close() + return nil +} + +func (d *GWebSocket) RespondWithSuccess() error { + data, err := json.Marshal(apiresp.ParseError(nil)) + if err != nil { + _ = d.Close() + return errs.WrapMsg(err, "json marshal failed") + } + + if err := d.WriteMessage(MessageText, data); err != nil { + _ = d.Close() + return errs.WrapMsg(err, "WriteMessage failed") + } + return nil +} diff --git a/internal/msggateway/message_handler.go b/internal/msggateway/message_handler.go index 2fbdd5683e..8a11e6ab3c 100644 --- a/internal/msggateway/message_handler.go +++ b/internal/msggateway/message_handler.go @@ -18,15 +18,15 @@ import ( "context" "sync" - "github.com/OpenIMSDK/protocol/msg" - "github.com/OpenIMSDK/protocol/push" - "github.com/OpenIMSDK/protocol/sdkws" - "github.com/OpenIMSDK/tools/discoveryregistry" - "github.com/OpenIMSDK/tools/errs" - "github.com/OpenIMSDK/tools/utils" "github.com/go-playground/validator/v10" "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" + "github.com/openimsdk/protocol/msg" + "github.com/openimsdk/protocol/push" + "github.com/openimsdk/protocol/sdkws" + "github.com/openimsdk/tools/discovery" + "github.com/openimsdk/tools/errs" + "github.com/openimsdk/tools/utils/jsonutil" "google.golang.org/protobuf/proto" ) @@ -46,7 +46,7 @@ func (r *Req) String() string { tReq.SendID = r.SendID tReq.OperationID = r.OperationID tReq.MsgIncr = r.MsgIncr - return utils.StructToJsonString(tReq) + return jsonutil.StructToJsonString(tReq) } var reqPool = sync.Pool{ @@ -86,7 +86,7 @@ func (r *Resp) String() string { tResp.OperationID = r.OperationID tResp.ErrCode = r.ErrCode tResp.ErrMsg = r.ErrMsg - return utils.StructToJsonString(tResp) + return jsonutil.StructToJsonString(tResp) } type MessageHandler interface { @@ -106,30 +106,30 @@ type GrpcHandler struct { validate *validator.Validate } -func NewGrpcHandler(validate *validator.Validate, client discoveryregistry.SvcDiscoveryRegistry, config *config.GlobalConfig) *GrpcHandler { - msgRpcClient := rpcclient.NewMessageRpcClient(client, config) - pushRpcClient := rpcclient.NewPushRpcClient(client, config) +func NewGrpcHandler(validate *validator.Validate, client discovery.SvcDiscoveryRegistry, rpcRegisterName *config.RpcRegisterName) *GrpcHandler { + msgRpcClient := rpcclient.NewMessageRpcClient(client, rpcRegisterName.Msg) + pushRpcClient := rpcclient.NewPushRpcClient(client, rpcRegisterName.Push) return &GrpcHandler{ msgRpcClient: &msgRpcClient, pushClient: &pushRpcClient, validate: validate, } } -func (g GrpcHandler) GetSeq(context context.Context, data *Req) ([]byte, error) { +func (g GrpcHandler) GetSeq(ctx context.Context, data *Req) ([]byte, error) { req := sdkws.GetMaxSeqReq{} if err := proto.Unmarshal(data.Data, &req); err != nil { - return nil, errs.Wrap(err, "GetSeq: error unmarshaling request") + return nil, errs.WrapMsg(err, "GetSeq: error unmarshaling request", "action", "unmarshal", "dataType", "GetMaxSeqReq") } if err := g.validate.Struct(&req); err != nil { - return nil, errs.Wrap(err, "GetSeq: validation failed") + return nil, errs.WrapMsg(err, "GetSeq: validation failed", "action", "validate", "dataType", "GetMaxSeqReq") } - resp, err := g.msgRpcClient.GetMaxSeq(context, &req) + resp, err := g.msgRpcClient.GetMaxSeq(ctx, &req) if err != nil { return nil, err } c, err := proto.Marshal(resp) if err != nil { - return nil, errs.Wrap(err, "GetSeq: error marshaling response") + return nil, errs.WrapMsg(err, "GetSeq: error marshaling response", "action", "marshal", "dataType", "GetMaxSeqResp") } return c, nil } @@ -137,19 +137,16 @@ func (g GrpcHandler) GetSeq(context context.Context, data *Req) ([]byte, error) // SendMessage handles the sending of messages through gRPC. It unmarshals the request data, // validates the message, and then sends it using the message RPC client. func (g GrpcHandler) SendMessage(ctx context.Context, data *Req) ([]byte, error) { - // Unmarshal the message data from the request. var msgData sdkws.MsgData if err := proto.Unmarshal(data.Data, &msgData); err != nil { - return nil, errs.Wrap(err, "error unmarshalling message data") + return nil, errs.WrapMsg(err, "SendMessage: error unmarshaling message data", "action", "unmarshal", "dataType", "MsgData") } - // Validate the message data structure. if err := g.validate.Struct(&msgData); err != nil { - return nil, errs.Wrap(err, "message data validation failed") + return nil, errs.WrapMsg(err, "SendMessage: message data validation failed", "action", "validate", "dataType", "MsgData") } req := msg.SendMsgReq{MsgData: &msgData} - resp, err := g.msgRpcClient.SendMsg(ctx, &req) if err != nil { return nil, err @@ -157,7 +154,7 @@ func (g GrpcHandler) SendMessage(ctx context.Context, data *Req) ([]byte, error) c, err := proto.Marshal(resp) if err != nil { - return nil, errs.Wrap(err, "error marshaling response") + return nil, errs.WrapMsg(err, "SendMessage: error marshaling response", "action", "marshal", "dataType", "SendMsgResp") } return c, nil @@ -170,7 +167,7 @@ func (g GrpcHandler) SendSignalMessage(context context.Context, data *Req) ([]by } c, err := proto.Marshal(resp) if err != nil { - return nil, errs.Wrap(err, "error marshaling response") + return nil, errs.WrapMsg(err, "error marshaling response", "action", "marshal", "dataType", "SendMsgResp") } return c, nil } @@ -178,10 +175,10 @@ func (g GrpcHandler) SendSignalMessage(context context.Context, data *Req) ([]by func (g GrpcHandler) PullMessageBySeqList(context context.Context, data *Req) ([]byte, error) { req := sdkws.PullMessageBySeqsReq{} if err := proto.Unmarshal(data.Data, &req); err != nil { - return nil, errs.Wrap(err, "error unmarshaling request") + return nil, errs.WrapMsg(err, "error unmarshaling request", "action", "unmarshal", "dataType", "PullMessageBySeqsReq") } if err := g.validate.Struct(data); err != nil { - return nil, errs.Wrap(err, "validation failed") + return nil, errs.WrapMsg(err, "validation failed", "action", "validate", "dataType", "PullMessageBySeqsReq") } resp, err := g.msgRpcClient.PullMessageBySeqList(context, &req) if err != nil { @@ -189,7 +186,7 @@ func (g GrpcHandler) PullMessageBySeqList(context context.Context, data *Req) ([ } c, err := proto.Marshal(resp) if err != nil { - return nil, errs.Wrap(err, "error marshaling response") + return nil, errs.WrapMsg(err, "error marshaling response", "action", "marshal", "dataType", "PullMessageBySeqsResp") } return c, nil } @@ -197,7 +194,7 @@ func (g GrpcHandler) PullMessageBySeqList(context context.Context, data *Req) ([ func (g GrpcHandler) UserLogout(context context.Context, data *Req) ([]byte, error) { req := push.DelUserPushTokenReq{} if err := proto.Unmarshal(data.Data, &req); err != nil { - return nil, errs.Wrap(err, "error unmarshaling request") + return nil, errs.WrapMsg(err, "error unmarshaling request", "action", "unmarshal", "dataType", "DelUserPushTokenReq") } resp, err := g.pushClient.DelUserPushToken(context, &req) if err != nil { @@ -205,7 +202,7 @@ func (g GrpcHandler) UserLogout(context context.Context, data *Req) ([]byte, err } c, err := proto.Marshal(resp) if err != nil { - return nil, errs.Wrap(err, "error marshaling response") + return nil, errs.WrapMsg(err, "error marshaling response", "action", "marshal", "dataType", "DelUserPushTokenResp") } return c, nil } @@ -213,31 +210,10 @@ func (g GrpcHandler) UserLogout(context context.Context, data *Req) ([]byte, err func (g GrpcHandler) SetUserDeviceBackground(_ context.Context, data *Req) ([]byte, bool, error) { req := sdkws.SetAppBackgroundStatusReq{} if err := proto.Unmarshal(data.Data, &req); err != nil { - return nil, false, errs.Wrap(err, "error unmarshaling request") + return nil, false, errs.WrapMsg(err, "error unmarshaling request", "action", "unmarshal", "dataType", "SetAppBackgroundStatusReq") } if err := g.validate.Struct(data); err != nil { - return nil, false, errs.Wrap(err, "validation failed") + return nil, false, errs.WrapMsg(err, "validation failed", "action", "validate", "dataType", "SetAppBackgroundStatusReq") } return nil, req.IsBackground, nil } - -// func (g GrpcHandler) call[T any](ctx context.Context, data Req, m proto.Message, rpc func(ctx context.Context, req -// proto.Message)) ([]byte, error) { -// if err := proto.Unmarshal(data.Data, m); err != nil { -// return nil, err -// } -// if err := g.validate.Struct(m); err != nil { -// return nil, err -// } -// rpc(ctx, m) -// req := msg.SendMsgReq{MsgData: &msgData} -// resp, err := g.notification.Msg.SendMsg(context, &req) -// if err != nil { -// return nil, err -// } -// c, err := proto.Marshal(resp) -// if err != nil { -// return nil, err -// } -// return c, nil -//} diff --git a/internal/msggateway/n_ws_server.go b/internal/msggateway/n_ws_server.go index f5838c7036..cf607d4707 100644 --- a/internal/msggateway/n_ws_server.go +++ b/internal/msggateway/n_ws_server.go @@ -16,29 +16,25 @@ package msggateway import ( "context" - "encoding/json" - "errors" "fmt" + "github.com/openimsdk/open-im-server/v3/pkg/common/webhook" + pbAuth "github.com/openimsdk/protocol/auth" + "github.com/openimsdk/tools/mcontext" "net/http" - "strconv" "sync" "sync/atomic" "time" - "github.com/OpenIMSDK/protocol/constant" - "github.com/OpenIMSDK/protocol/msggateway" - "github.com/OpenIMSDK/tools/apiresp" - "github.com/OpenIMSDK/tools/discoveryregistry" - "github.com/OpenIMSDK/tools/errs" - "github.com/OpenIMSDK/tools/log" - "github.com/OpenIMSDK/tools/utils" "github.com/go-playground/validator/v10" - "github.com/openimsdk/open-im-server/v3/pkg/authverify" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" "github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics" + "github.com/openimsdk/open-im-server/v3/pkg/common/servererrs" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" - "github.com/redis/go-redis/v9" + "github.com/openimsdk/protocol/constant" + "github.com/openimsdk/protocol/msggateway" + "github.com/openimsdk/tools/discovery" + "github.com/openimsdk/tools/errs" + "github.com/openimsdk/tools/log" + "github.com/openimsdk/tools/utils/stringutil" "golang.org/x/sync/errgroup" ) @@ -48,8 +44,7 @@ type LongConnServer interface { GetUserAllCons(userID string) ([]*Client, bool) GetUserPlatformCons(userID string, platform int) ([]*Client, bool, bool) Validate(s any) error - SetCacheHandler(cache cache.MsgModel) - SetDiscoveryRegistry(client discoveryregistry.SvcDiscoveryRegistry, config *config.GlobalConfig) + SetDiscoveryRegistry(client discovery.SvcDiscoveryRegistry, config *Config) KickUserConn(client *Client) error UnRegister(c *Client) SetKickHandlerInfo(i *kickHandler) @@ -58,15 +53,8 @@ type LongConnServer interface { MessageHandler } -// bufferPool is unused -// var bufferPool = sync.Pool{ -// New: func() any { -// return make([]byte, 1024) -// }, -// } - type WsServer struct { - globalConfig *config.GlobalConfig + msgGatewayConfig *Config port int wsMaxConnNum int64 registerChan chan *Client @@ -79,12 +67,13 @@ type WsServer struct { handshakeTimeout time.Duration writeBufferSize int validate *validator.Validate - cache cache.MsgModel userClient *rpcclient.UserRpcClient - disCov discoveryregistry.SvcDiscoveryRegistry + authClient *rpcclient.Auth + disCov discovery.SvcDiscoveryRegistry Compressor Encoder MessageHandler + webhookClient *webhook.Client } type kickHandler struct { @@ -93,9 +82,10 @@ type kickHandler struct { newClient *Client } -func (ws *WsServer) SetDiscoveryRegistry(disCov discoveryregistry.SvcDiscoveryRegistry, config *config.GlobalConfig) { - ws.MessageHandler = NewGrpcHandler(ws.validate, disCov, config) - u := rpcclient.NewUserRpcClient(disCov, config) +func (ws *WsServer) SetDiscoveryRegistry(disCov discovery.SvcDiscoveryRegistry, config *Config) { + ws.MessageHandler = NewGrpcHandler(ws.validate, disCov, &config.Share.RpcRegisterName) + u := rpcclient.NewUserRpcClient(disCov, config.Share.RpcRegisterName.User, config.Share.IMAdminUserID) + ws.authClient = rpcclient.NewAuth(disCov, config.Share.RpcRegisterName.Auth) ws.userClient = &u ws.disCov = disCov } @@ -107,30 +97,17 @@ func (ws *WsServer) SetUserOnlineStatus(ctx context.Context, client *Client, sta } switch status { case constant.Online: - err := CallbackUserOnline(ctx, ws.globalConfig, client.UserID, client.PlatformID, client.IsBackground, client.ctx.GetConnID()) - if err != nil { - log.ZWarn(ctx, "CallbackUserOnline err", err) - } + ws.webhookAfterUserOnline(ctx, &ws.msgGatewayConfig.WebhooksConfig.AfterUserOnline, client.UserID, client.PlatformID, client.IsBackground, client.ctx.GetConnID()) case constant.Offline: - err := CallbackUserOffline(ctx, ws.globalConfig, client.UserID, client.PlatformID, client.ctx.GetConnID()) - if err != nil { - log.ZWarn(ctx, "CallbackUserOffline err", err) - } + ws.webhookAfterUserOffline(ctx, &ws.msgGatewayConfig.WebhooksConfig.AfterUserOffline, client.UserID, client.PlatformID, client.ctx.GetConnID()) } } -func (ws *WsServer) SetCacheHandler(cache cache.MsgModel) { - ws.cache = cache -} - func (ws *WsServer) UnRegister(c *Client) { ws.unregisterChan <- c } -func (ws *WsServer) Validate(s any) error { - if s == nil { - return errs.Wrap(errors.New("input cannot be nil")) - } +func (ws *WsServer) Validate(_ any) error { return nil } @@ -142,14 +119,14 @@ func (ws *WsServer) GetUserPlatformCons(userID string, platform int) ([]*Client, return ws.clients.Get(userID, platform) } -func NewWsServer(globalConfig *config.GlobalConfig, opts ...Option) (*WsServer, error) { +func NewWsServer(msgGatewayConfig *Config, opts ...Option) (*WsServer, error) { var config configs for _, o := range opts { o(&config) } v := validator.New() return &WsServer{ - globalConfig: globalConfig, + msgGatewayConfig: msgGatewayConfig, port: config.port, wsMaxConnNum: config.maxConnNum, writeBufferSize: config.writeBufferSize, @@ -166,6 +143,7 @@ func NewWsServer(globalConfig *config.GlobalConfig, opts ...Option) (*WsServer, clients: newUserMap(), Compressor: NewGzipCompressor(), Encoder: NewGobEncoder(), + webhookClient: webhook.NewWebhookClient(msgGatewayConfig.WebhooksConfig.URL), }, nil } @@ -176,7 +154,7 @@ func (ws *WsServer) Run(done chan error) error { shutdownDone = make(chan struct{}, 1) ) - server := http.Server{Addr: ":" + utils.IntToString(ws.port), Handler: nil} + server := http.Server{Addr: ":" + stringutil.IntToString(ws.port), Handler: nil} go func() { for { @@ -196,9 +174,9 @@ func (ws *WsServer) Run(done chan error) error { go func() { http.HandleFunc("/", ws.wsHandler) err := server.ListenAndServe() + defer close(netDone) if err != nil && err != http.ErrServerClosed { - netErr = errs.Wrap(err, "ws start err", server.Addr) - close(netDone) + netErr = errs.WrapMsg(err, "ws start err", server.Addr) } }() ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) @@ -208,7 +186,7 @@ func (ws *WsServer) Run(done chan error) error { case err = <-done: sErr := server.Shutdown(ctx) if sErr != nil { - return errs.Wrap(sErr, "shutdown err") + return errs.WrapMsg(sErr, "shutdown err") } close(shutdownDone) if err != nil { @@ -223,7 +201,7 @@ func (ws *WsServer) Run(done chan error) error { var concurrentRequest = 3 func (ws *WsServer) sendUserOnlineInfoToOtherNode(ctx context.Context, client *Client) error { - conns, err := ws.disCov.GetConns(ctx, ws.globalConfig.RpcRegisterName.OpenImMessageGatewayName) + conns, err := ws.disCov.GetConns(ctx, ws.msgGatewayConfig.Share.RpcRegisterName.MessageGateway) if err != nil { return err } @@ -279,7 +257,8 @@ func (ws *WsServer) registerClient(client *Client) { if clientOK { ws.clients.Set(client.UserID, client) // There is already a connection to the platform - log.ZInfo(client.ctx, "repeat login", "userID", client.UserID, "platformID", client.PlatformID, "old remote addr", getRemoteAdders(oldClients)) + log.ZInfo(client.ctx, "repeat login", "userID", client.UserID, "platformID", + client.PlatformID, "old remote addr", getRemoteAdders(oldClients)) ws.onlineUserConnNum.Add(1) } else { ws.clients.Set(client.UserID, client) @@ -288,13 +267,14 @@ func (ws *WsServer) registerClient(client *Client) { } wg := sync.WaitGroup{} - if ws.globalConfig.Envs.Discovery == "zookeeper" { + if ws.msgGatewayConfig.Share.Env == "zookeeper" { wg.Add(1) go func() { defer wg.Done() _ = ws.sendUserOnlineInfoToOtherNode(client.ctx, client) }() } + wg.Add(1) go func() { defer wg.Done() @@ -331,7 +311,7 @@ func (ws *WsServer) KickUserConn(client *Client) error { } func (ws *WsServer) multiTerminalLoginChecker(clientOK bool, oldClients []*Client, newClient *Client) { - switch ws.globalConfig.MultiLoginPolicy { + switch ws.msgGatewayConfig.MsgGateway.MultiLoginPolicy { case constant.DefalutNotKick: case constant.PCAndOther: if constant.PlatformIDToClass(newClient.PlatformID) == constant.TerminalPC { @@ -349,57 +329,13 @@ func (ws *WsServer) multiTerminalLoginChecker(clientOK bool, oldClients []*Clien log.ZWarn(c.ctx, "KickOnlineMessage", err) } } - m, err := ws.cache.GetTokensWithoutError( - newClient.ctx, - newClient.UserID, - newClient.PlatformID, - ) - if err != nil && err != redis.Nil { - log.ZWarn( - newClient.ctx, - "get token from redis err", - err, - "userID", - newClient.UserID, - "platformID", - newClient.PlatformID, - ) - return - } - if m == nil { - log.ZWarn( - newClient.ctx, - "m is nil", - errors.New("m is nil"), - "userID", - newClient.UserID, - "platformID", - newClient.PlatformID, - ) - return - } - log.ZDebug( - newClient.ctx, - "get token from redis", - "userID", - newClient.UserID, - "platformID", - newClient.PlatformID, - "tokenMap", - m, + ctx := mcontext.WithMustInfoCtx( + []string{newClient.ctx.GetOperationID(), newClient.ctx.GetUserID(), + constant.PlatformIDToName(newClient.PlatformID), newClient.ctx.GetConnID()}, ) - - for k := range m { - if k != newClient.ctx.GetToken() { - m[k] = constant.KickedToken - } - } - log.ZDebug(newClient.ctx, "set token map is ", "token map", m, "userID", - newClient.UserID, "token", newClient.ctx.GetToken()) - err = ws.cache.SetTokenMapByUidPid(newClient.ctx, newClient.UserID, newClient.PlatformID, m) - if err != nil { - log.ZWarn(newClient.ctx, "SetTokenMapByUidPid err", err, "userID", newClient.UserID, "platformID", newClient.PlatformID) - return + if _, err := ws.authClient.InvalidateToken(ctx, newClient.token, newClient.UserID, newClient.PlatformID); err != nil { + log.ZWarn(newClient.ctx, "InvalidateToken err", err, "userID", newClient.UserID, + "platformID", newClient.PlatformID) } } } @@ -413,107 +349,94 @@ func (ws *WsServer) unregisterClient(client *Client) { } ws.onlineUserConnNum.Add(-1) ws.SetUserOnlineStatus(client.ctx, client, constant.Offline) - log.ZInfo(client.ctx, "user offline", "close reason", client.closedErr, "online user Num", ws.onlineUserNum.Load(), "online user conn Num", + log.ZInfo(client.ctx, "user offline", "close reason", client.closedErr, "online user Num", + ws.onlineUserNum.Load(), "online user conn Num", ws.onlineUserConnNum.Load(), ) } -func (ws *WsServer) ParseWSArgs(r *http.Request) (args *WSArgs, err error) { - var v WSArgs - defer func() { - args = &v - }() - query := r.URL.Query() - v.MsgResp, _ = strconv.ParseBool(query.Get(MsgResp)) - if ws.onlineUserConnNum.Load() >= ws.wsMaxConnNum { - return nil, errs.ErrConnOverMaxNumLimit.Wrap("over max conn num limit") - } - if v.Token = query.Get(Token); v.Token == "" { - return nil, errs.ErrConnArgsErr.Wrap("token is empty") +// validateRespWithRequest checks if the response matches the expected userID and platformID. +func (ws *WsServer) validateRespWithRequest(ctx *UserConnContext, resp *pbAuth.ParseTokenResp) error { + userID := ctx.GetUserID() + platformID := stringutil.StringToInt32(ctx.GetPlatformID()) + if resp.UserID != userID { + return servererrs.ErrTokenInvalid.WrapMsg(fmt.Sprintf("token uid %s != userID %s", resp.UserID, userID)) } - if v.UserID = query.Get(WsUserID); v.UserID == "" { - return nil, errs.ErrConnArgsErr.Wrap("sendID is empty") + if resp.PlatformID != platformID { + return servererrs.ErrTokenInvalid.WrapMsg(fmt.Sprintf("token platform %d != platformID %d", resp.PlatformID, platformID)) } - platformIDStr := query.Get(PlatformID) - if platformIDStr == "" { - return nil, errs.ErrConnArgsErr.Wrap("platformID is empty") + return nil +} + +func (ws *WsServer) wsHandler(w http.ResponseWriter, r *http.Request) { + // Create a new connection context + connContext := newContext(w, r) + + // Check if the current number of online user connections exceeds the maximum limit + if ws.onlineUserConnNum.Load() >= ws.wsMaxConnNum { + // If it exceeds the maximum connection number, return an error via HTTP and stop processing + httpError(connContext, servererrs.ErrConnOverMaxNumLimit.WrapMsg("over max conn num limit")) + return } - platformID, err := strconv.Atoi(platformIDStr) + + // Parse essential arguments (e.g., user ID, Token) + err := connContext.ParseEssentialArgs() if err != nil { - return nil, errs.ErrConnArgsErr.Wrap("platformID is not int") - } - v.PlatformID = platformID - if err = authverify.WsVerifyToken(v.Token, v.UserID, ws.globalConfig.Secret, platformID); err != nil { - return nil, err - } - if query.Get(Compression) == GzipCompressionProtocol { - v.Compression = true - } - if r.Header.Get(Compression) == GzipCompressionProtocol { - v.Compression = true + // If there's an error during parsing, return an error via HTTP and stop processing + + httpError(connContext, err) + return } - m, err := ws.cache.GetTokensWithoutError(context.Background(), v.UserID, platformID) + + // Call the authentication client to parse the Token obtained from the context + resp, err := ws.authClient.ParseToken(connContext, connContext.GetToken()) if err != nil { - return nil, err - } - if v, ok := m[v.Token]; ok { - switch v { - case constant.NormalToken: - case constant.KickedToken: - return nil, errs.ErrTokenKicked.Wrap() - default: - return nil, errs.ErrTokenUnknown.Wrap(fmt.Sprintf("token status is %d", v)) + // If there's an error parsing the Token, decide whether to send the error message via WebSocket based on the context flag + shouldSendError := connContext.ShouldSendResp() + if shouldSendError { + // Create a WebSocket connection object and attempt to send the error message via WebSocket + wsLongConn := newGWebSocket(WebSocket, ws.handshakeTimeout, ws.writeBufferSize) + if err := wsLongConn.RespondWithError(err, w, r); err == nil { + // If the error message is successfully sent via WebSocket, stop processing + return + } } - } else { - return nil, errs.ErrTokenNotExist.Wrap() + // If sending via WebSocket is not required or fails, return the error via HTTP and stop processing + httpError(connContext, err) + return } - return &v, nil -} -type WSArgs struct { - Token string - UserID string - PlatformID int - Compression bool - MsgResp bool -} + // Validate the authentication response matches the request (e.g., user ID and platform ID) + err = ws.validateRespWithRequest(connContext, resp) + if err != nil { + // If validation fails, return an error via HTTP and stop processing + httpError(connContext, err) + return + } -func (ws *WsServer) wsHandler(w http.ResponseWriter, r *http.Request) { - connContext := newContext(w, r) - args, pErr := ws.ParseWSArgs(r) - var wsLongConn *GWebSocket - if args.MsgResp { - wsLongConn = newGWebSocket(WebSocket, ws.handshakeTimeout, ws.writeBufferSize) - if err := wsLongConn.GenerateLongConn(w, r); err != nil { - httpError(connContext, err) - return - } - data, err := json.Marshal(apiresp.ParseError(pErr)) - if err != nil { - _ = wsLongConn.Close() - return - } - if err := wsLongConn.WriteMessage(MessageText, data); err != nil { - _ = wsLongConn.Close() - return - } - if pErr != nil { - _ = wsLongConn.Close() - return - } + // Create a WebSocket long connection object + wsLongConn := newGWebSocket(WebSocket, ws.handshakeTimeout, ws.writeBufferSize) + if err := wsLongConn.GenerateLongConn(w, r); err != nil { + //If the creation of the long connection fails, the error is handled internally during the handshake process. + log.ZWarn(connContext, "long connection fails", err) + return } else { - if pErr != nil { - httpError(connContext, pErr) - return - } - wsLongConn = newGWebSocket(WebSocket, ws.handshakeTimeout, ws.writeBufferSize) - if err := wsLongConn.GenerateLongConn(w, r); err != nil { - httpError(connContext, err) - return + // Check if a normal response should be sent via WebSocket + shouldSendSuccessResp := connContext.ShouldSendResp() + if shouldSendSuccessResp { + // Attempt to send a success message through WebSocket + if err := wsLongConn.RespondWithSuccess(); err != nil { + // If the success message is successfully sent, end further processing + return + } } } + + // Retrieve a client object from the client pool, reset its state, and associate it with the current WebSocket long connection client := ws.clientPool.Get().(*Client) - client.ResetClient(connContext, wsLongConn, connContext.GetBackground(), args.Compression, ws, args.Token) + client.ResetClient(connContext, wsLongConn, ws) + + // Register the client with the server and start message processing ws.registerChan <- client go client.readMessage() } diff --git a/internal/msggateway/user_map.go b/internal/msggateway/user_map.go index 89eb20de6c..79cc53d1bc 100644 --- a/internal/msggateway/user_map.go +++ b/internal/msggateway/user_map.go @@ -18,7 +18,8 @@ import ( "context" "sync" - "github.com/OpenIMSDK/tools/log" + "github.com/openimsdk/tools/log" + "github.com/openimsdk/tools/utils/datautil" ) type UserMap struct { @@ -54,6 +55,7 @@ func (u *UserMap) Get(key string, platformID int) ([]*Client, bool, bool) { return nil, userExisted, false } +// Set adds a client to the map. func (u *UserMap) Set(key string, v *Client) { allClients, existed := u.m.Load(key) if existed { @@ -63,6 +65,7 @@ func (u *UserMap) Set(key string, v *Client) { u.m.Store(key, oldClients) } else { log.ZDebug(context.Background(), "Set not existed", "user_id", key, "client_user_id", v.UserID) + var clients []*Client clients = append(clients, v) u.m.Store(key, clients) @@ -98,14 +101,10 @@ func (u *UserMap) delete(key string, connRemoteAddr string) (isDeleteUser bool) return false } -func (u *UserMap) deleteClients(key string, clientsToDelete []*Client) (isDeleteUser bool) { - // Convert the slice of clients to delete into a map for efficient lookup. - deleteMap := make(map[string]struct{}) - for _, client := range clientsToDelete { - deleteMap[client.ctx.GetRemoteAddr()] = struct{}{} - } - - // Load the current clients associated with the key. +func (u *UserMap) deleteClients(key string, clients []*Client) (isDeleteUser bool) { + m := datautil.SliceToMapAny(clients, func(c *Client) (string, struct{}) { + return c.ctx.GetRemoteAddr(), struct{}{} + }) allClients, existed := u.m.Load(key) if !existed { // If the key doesn't exist, return false. @@ -116,7 +115,7 @@ func (u *UserMap) deleteClients(key string, clientsToDelete []*Client) (isDelete oldClients := allClients.([]*Client) var remainingClients []*Client for _, client := range oldClients { - if _, shouldBeDeleted := deleteMap[client.ctx.GetRemoteAddr()]; !shouldBeDeleted { + if _, shouldBeDeleted := m[client.ctx.GetRemoteAddr()]; !shouldBeDeleted { remainingClients = append(remainingClients, client) } } diff --git a/internal/msgtransfer/init.go b/internal/msgtransfer/init.go index ee62db9c1a..685e847b86 100644 --- a/internal/msgtransfer/init.go +++ b/internal/msgtransfer/init.go @@ -16,23 +16,26 @@ package msgtransfer import ( "context" - "errors" "fmt" + "github.com/openimsdk/tools/db/mongoutil" + "github.com/openimsdk/tools/db/redisutil" + "github.com/openimsdk/tools/utils/datautil" "net/http" "os" "os/signal" "syscall" - "github.com/OpenIMSDK/tools/errs" - "github.com/OpenIMSDK/tools/mw" "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/unrelation" + "github.com/openimsdk/open-im-server/v3/pkg/common/db/mgo" kdisc "github.com/openimsdk/open-im-server/v3/pkg/common/discoveryregister" "github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" - util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" + "github.com/openimsdk/tools/errs" + "github.com/openimsdk/tools/log" + "github.com/openimsdk/tools/mw" + "github.com/openimsdk/tools/system/program" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/collectors" "github.com/prometheus/client_golang/prometheus/promhttp" @@ -50,59 +53,67 @@ type MsgTransfer struct { // and handle the deletion notification message deleted subscriptions topic: msg_to_mongo ctx context.Context cancel context.CancelFunc - config *config.GlobalConfig } -func StartTransfer(config *config.GlobalConfig, prometheusPort int) error { - rdb, err := cache.NewRedis(config) - if err != nil { - return err - } +type Config struct { + MsgTransfer config.MsgTransfer + RedisConfig config.Redis + MongodbConfig config.Mongo + KafkaConfig config.Kafka + ZookeeperConfig config.ZooKeeper + Share config.Share + WebhooksConfig config.Webhooks +} - mongo, err := unrelation.NewMongo(config) +func Start(ctx context.Context, index int, config *Config) error { + log.CInfo(ctx, "MSG-TRANSFER server is initializing", "prometheusPorts", + config.MsgTransfer.Prometheus.Ports, "index", index) + mgocli, err := mongoutil.NewMongoDB(ctx, config.MongodbConfig.Build()) if err != nil { return err } - - if err = mongo.CreateMsgIndex(); err != nil { + rdb, err := redisutil.NewRedisClient(ctx, config.RedisConfig.Build()) + if err != nil { return err } - client, err := kdisc.NewDiscoveryRegister(config) + client, err := kdisc.NewDiscoveryRegister(&config.ZookeeperConfig, &config.Share) if err != nil { return err } - if err := client.CreateRpcRootNodes(config.GetServiceNames()); err != nil { + if err := client.CreateRpcRootNodes(config.Share.RpcRegisterName.GetServiceNames()); err != nil { return err } - client.AddOption(mw.GrpcClient(), grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithDefaultServiceConfig(fmt.Sprintf(`{"LoadBalancingPolicy": "%s"}`, "round_robin"))) - msgModel := cache.NewMsgCacheModel(rdb, config) - msgDocModel := unrelation.NewMsgMongoDriver(mongo.GetDatabase(config.Mongo.Database)) - msgDatabase, err := controller.NewCommonMsgDatabase(msgDocModel, msgModel, config) + client.AddOption(mw.GrpcClient(), grpc.WithTransportCredentials(insecure.NewCredentials()), + grpc.WithDefaultServiceConfig(fmt.Sprintf(`{"LoadBalancingPolicy": "%s"}`, "round_robin"))) + //todo MsgCacheTimeout + msgModel := cache.NewMsgCache(rdb, config.RedisConfig.EnablePipeline) + seqModel := cache.NewSeqCache(rdb) + msgDocModel, err := mgo.NewMsgMongo(mgocli.GetDB()) if err != nil { return err } - conversationRpcClient := rpcclient.NewConversationRpcClient(client, config) - groupRpcClient := rpcclient.NewGroupRpcClient(client, config) - msgTransfer, err := NewMsgTransfer(config, msgDatabase, &conversationRpcClient, &groupRpcClient) + msgDatabase, err := controller.NewCommonMsgDatabase(msgDocModel, msgModel, seqModel, &config.KafkaConfig) if err != nil { return err } - return msgTransfer.Start(prometheusPort, config) + conversationRpcClient := rpcclient.NewConversationRpcClient(client, config.Share.RpcRegisterName.Conversation) + groupRpcClient := rpcclient.NewGroupRpcClient(client, config.Share.RpcRegisterName.Group) + msgTransfer, err := NewMsgTransfer(&config.KafkaConfig, msgDatabase, &conversationRpcClient, &groupRpcClient) + if err != nil { + return err + } + return msgTransfer.Start(index, config) } -func NewMsgTransfer( - config *config.GlobalConfig, - msgDatabase controller.CommonMsgDatabase, - conversationRpcClient *rpcclient.ConversationRpcClient, - groupRpcClient *rpcclient.GroupRpcClient, -) (*MsgTransfer, error) { - historyCH, err := NewOnlineHistoryRedisConsumerHandler(config, msgDatabase, conversationRpcClient, groupRpcClient) +func NewMsgTransfer(kafkaConf *config.Kafka, msgDatabase controller.CommonMsgDatabase, + conversationRpcClient *rpcclient.ConversationRpcClient, groupRpcClient *rpcclient.GroupRpcClient) (*MsgTransfer, error) { + historyCH, err := NewOnlineHistoryRedisConsumerHandler(kafkaConf, msgDatabase, conversationRpcClient, groupRpcClient) if err != nil { return nil, err } - historyMongoCH, err := NewOnlineHistoryMongoConsumerHandler(config, msgDatabase) + historyMongoCH, err := NewOnlineHistoryMongoConsumerHandler(kafkaConf, msgDatabase) if err != nil { return nil, err } @@ -110,14 +121,13 @@ func NewMsgTransfer( return &MsgTransfer{ historyCH: historyCH, historyMongoCH: historyMongoCH, - config: config, }, nil } -func (m *MsgTransfer) Start(prometheusPort int, config *config.GlobalConfig) error { - fmt.Println("start msg transfer", "prometheusPort:", prometheusPort) - if prometheusPort <= 0 { - return errs.Wrap(errors.New("prometheusPort not correct")) +func (m *MsgTransfer) Start(index int, config *Config) error { + prometheusPort, err := datautil.GetElemByIndex(config.MsgTransfer.Prometheus.Ports, index) + if err != nil { + return err } m.ctx, m.cancel = context.WithCancel(context.Background()) @@ -129,17 +139,17 @@ func (m *MsgTransfer) Start(prometheusPort int, config *config.GlobalConfig) err go m.historyCH.historyConsumerGroup.RegisterHandleAndConsumer(m.ctx, m.historyCH) go m.historyMongoCH.historyConsumerGroup.RegisterHandleAndConsumer(m.ctx, m.historyMongoCH) - if config.Prometheus.Enable { + if config.MsgTransfer.Prometheus.Enable { go func() { proreg := prometheus.NewRegistry() proreg.MustRegister( collectors.NewGoCollector(), ) - proreg.MustRegister(prommetrics.GetGrpcCusMetrics("Transfer", config)...) + proreg.MustRegister(prommetrics.GetGrpcCusMetrics("Transfer", &config.Share)...) http.Handle("/metrics", promhttp.HandlerFor(proreg, promhttp.HandlerOpts{Registry: proreg})) err := http.ListenAndServe(fmt.Sprintf(":%d", prometheusPort), nil) if err != nil && err != http.ErrServerClosed { - netErr = errs.Wrap(err, fmt.Sprintf("prometheus start err: %d", prometheusPort)) + netErr = errs.WrapMsg(err, "prometheus start error", "prometheusPort", prometheusPort) netDone <- struct{}{} } }() @@ -149,7 +159,7 @@ func (m *MsgTransfer) Start(prometheusPort int, config *config.GlobalConfig) err signal.Notify(sigs, syscall.SIGTERM) select { case <-sigs: - util.SIGTERMExit() + program.SIGTERMExit() // graceful close kafka client. m.cancel() m.historyCH.historyConsumerGroup.Close() diff --git a/internal/msgtransfer/online_history_msg_handler.go b/internal/msgtransfer/online_history_msg_handler.go index 50fc933690..9960aa5189 100644 --- a/internal/msgtransfer/online_history_msg_handler.go +++ b/internal/msgtransfer/online_history_msg_handler.go @@ -23,18 +23,19 @@ import ( "time" "github.com/IBM/sarama" - "github.com/OpenIMSDK/protocol/constant" - "github.com/OpenIMSDK/protocol/sdkws" - "github.com/OpenIMSDK/tools/errs" - "github.com/OpenIMSDK/tools/log" - "github.com/OpenIMSDK/tools/mcontext" - "github.com/OpenIMSDK/tools/utils" "github.com/go-redis/redis" "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" - "github.com/openimsdk/open-im-server/v3/pkg/common/kafka" "github.com/openimsdk/open-im-server/v3/pkg/msgprocessor" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" + "github.com/openimsdk/protocol/constant" + "github.com/openimsdk/protocol/sdkws" + "github.com/openimsdk/tools/errs" + "github.com/openimsdk/tools/log" + "github.com/openimsdk/tools/mcontext" + "github.com/openimsdk/tools/mq/kafka" + "github.com/openimsdk/tools/utils/idutil" + "github.com/openimsdk/tools/utils/stringutil" "google.golang.org/protobuf/proto" ) @@ -80,12 +81,12 @@ type OnlineHistoryRedisConsumerHandler struct { groupRpcClient *rpcclient.GroupRpcClient } -func NewOnlineHistoryRedisConsumerHandler( - config *config.GlobalConfig, - database controller.CommonMsgDatabase, - conversationRpcClient *rpcclient.ConversationRpcClient, - groupRpcClient *rpcclient.GroupRpcClient, -) (*OnlineHistoryRedisConsumerHandler, error) { +func NewOnlineHistoryRedisConsumerHandler(kafkaConf *config.Kafka, database controller.CommonMsgDatabase, + conversationRpcClient *rpcclient.ConversationRpcClient, groupRpcClient *rpcclient.GroupRpcClient) (*OnlineHistoryRedisConsumerHandler, error) { + historyConsumerGroup, err := kafka.NewMConsumerGroup(kafkaConf.Build(), kafkaConf.ToRedisGroupID, []string{kafkaConf.ToRedisTopic}) + if err != nil { + return nil, err + } var och OnlineHistoryRedisConsumerHandler och.msgDatabase = database och.msgDistributionCh = make(chan Cmd2Value) // no buffer channel @@ -96,32 +97,7 @@ func NewOnlineHistoryRedisConsumerHandler( } och.conversationRpcClient = conversationRpcClient och.groupRpcClient = groupRpcClient - var err error - - var tlsConfig *kafka.TLSConfig - if config.Kafka.TLS != nil { - tlsConfig = &kafka.TLSConfig{ - CACrt: config.Kafka.TLS.CACrt, - ClientCrt: config.Kafka.TLS.ClientCrt, - ClientKey: config.Kafka.TLS.ClientKey, - ClientKeyPwd: config.Kafka.TLS.ClientKeyPwd, - InsecureSkipVerify: false, - } - } - - och.historyConsumerGroup, err = kafka.NewMConsumerGroup(&kafka.MConsumerGroupConfig{ - KafkaVersion: sarama.V2_0_0_0, - OffsetsInitial: sarama.OffsetNewest, - IsReturnErr: false, - UserName: config.Kafka.Username, - Password: config.Kafka.Password, - }, []string{config.Kafka.LatestMsgToRedis.Topic}, - config.Kafka.Addr, - config.Kafka.ConsumerGroupID.MsgToRedis, - tlsConfig, - ) - // statistics.NewStatistics(&och.singleMsgSuccessCount, config.Config.ModuleName.MsgTransferName, fmt.Sprintf("%d - // second singleMsgCount insert to mongo", constant.StatisticsTimeInterval), constant.StatisticsTimeInterval) + och.historyConsumerGroup = historyConsumerGroup return &och, err } @@ -265,22 +241,13 @@ func (och *OnlineHistoryRedisConsumerHandler) handleNotification( } } -func (och *OnlineHistoryRedisConsumerHandler) toPushTopic( - ctx context.Context, - key, conversationID string, - msgs []*sdkws.MsgData, -) { +func (och *OnlineHistoryRedisConsumerHandler) toPushTopic(ctx context.Context, key, conversationID string, msgs []*sdkws.MsgData) { for _, v := range msgs { och.msgDatabase.MsgToPushMQ(ctx, key, conversationID, v) // nolint: errcheck - } } -func (och *OnlineHistoryRedisConsumerHandler) handleMsg( - ctx context.Context, - key, conversationID string, - storageList, notStorageList []*sdkws.MsgData, -) { +func (och *OnlineHistoryRedisConsumerHandler) handleMsg(ctx context.Context, key, conversationID string, storageList, notStorageList []*sdkws.MsgData) { och.toPushTopic(ctx, key, conversationID, notStorageList) if len(storageList) > 0 { lastSeq, isNewConversation, err := och.msgDatabase.BatchInsertChat2Cache(ctx, conversationID, storageList) @@ -290,7 +257,7 @@ func (och *OnlineHistoryRedisConsumerHandler) handleMsg( } if isNewConversation { switch storageList[0].SessionType { - case constant.SuperGroupChatType: + case constant.ReadGroupChatType: log.ZInfo(ctx, "group chat first create conversation", "conversationID", conversationID) userIDs, err := och.groupRpcClient.GetGroupMemberIDs(ctx, storageList[0].GroupID) @@ -349,14 +316,8 @@ func (och *OnlineHistoryRedisConsumerHandler) MessagesDistributionHandle() { for i, header := range consumerMessages[i].Headers { arr = append(arr, strconv.Itoa(i), string(header.Key), string(header.Value)) } - log.ZInfo( - ctx, - "consumer.kafka.GetContextWithMQHeader", - "len", - len(consumerMessages[i].Headers), - "header", - strings.Join(arr, ", "), - ) + log.ZInfo(ctx, "consumer.kafka.GetContextWithMQHeader", "len", len(consumerMessages[i].Headers), + "header", strings.Join(arr, ", ")) ctxMsg.ctx = kafka.GetContextWithMQHeader(consumerMessages[i].Headers) ctxMsg.message = msgFromMQ log.ZDebug( @@ -381,7 +342,7 @@ func (och *OnlineHistoryRedisConsumerHandler) MessagesDistributionHandle() { log.ZDebug(ctx, "generate map list users len", "length", len(aggregationMsgs)) for uniqueKey, v := range aggregationMsgs { if len(v) >= 0 { - hashCode := utils.GetHashCode(uniqueKey) + hashCode := stringutil.GetHashCode(uniqueKey) channelID := hashCode % ChannelNum newCtx := withAggregationCtx(ctx, v) log.ZDebug( @@ -472,7 +433,7 @@ func (och *OnlineHistoryRedisConsumerHandler) ConsumeClaim( rwLock.Unlock() start := time.Now() - ctx := mcontext.WithTriggerIDContext(context.Background(), utils.OperationIDGenerator()) + ctx := mcontext.WithTriggerIDContext(context.Background(), idutil.OperationIDGenerator()) log.ZDebug(ctx, "timer trigger msg consumer start", "length", len(buffer)) for i := 0; i < len(buffer)/split; i++ { och.msgDistributionCh <- Cmd2Value{Cmd: ConsumerMsgs, Value: TriggerChannelValue{ diff --git a/internal/msgtransfer/online_msg_to_mongo_handler.go b/internal/msgtransfer/online_msg_to_mongo_handler.go index 045f822206..978302e768 100644 --- a/internal/msgtransfer/online_msg_to_mongo_handler.go +++ b/internal/msgtransfer/online_msg_to_mongo_handler.go @@ -18,42 +18,22 @@ import ( "context" "github.com/IBM/sarama" - pbmsg "github.com/OpenIMSDK/protocol/msg" - "github.com/OpenIMSDK/tools/log" "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" - kfk "github.com/openimsdk/open-im-server/v3/pkg/common/kafka" "github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics" + pbmsg "github.com/openimsdk/protocol/msg" + "github.com/openimsdk/tools/log" + "github.com/openimsdk/tools/mq/kafka" "google.golang.org/protobuf/proto" ) type OnlineHistoryMongoConsumerHandler struct { - historyConsumerGroup *kfk.MConsumerGroup + historyConsumerGroup *kafka.MConsumerGroup msgDatabase controller.CommonMsgDatabase } -func NewOnlineHistoryMongoConsumerHandler(config *config.GlobalConfig, database controller.CommonMsgDatabase) (*OnlineHistoryMongoConsumerHandler, error) { - var tlsConfig *kfk.TLSConfig - if config.Kafka.TLS != nil { - tlsConfig = &kfk.TLSConfig{ - CACrt: config.Kafka.TLS.CACrt, - ClientCrt: config.Kafka.TLS.ClientCrt, - ClientKey: config.Kafka.TLS.ClientKey, - ClientKeyPwd: config.Kafka.TLS.ClientKeyPwd, - InsecureSkipVerify: false, - } - } - historyConsumerGroup, err := kfk.NewMConsumerGroup(&kfk.MConsumerGroupConfig{ - KafkaVersion: sarama.V2_0_0_0, - OffsetsInitial: sarama.OffsetNewest, - IsReturnErr: false, - UserName: config.Kafka.Username, - Password: config.Kafka.Password, - }, []string{config.Kafka.MsgToMongo.Topic}, - config.Kafka.Addr, - config.Kafka.ConsumerGroupID.MsgToMongo, - tlsConfig, - ) +func NewOnlineHistoryMongoConsumerHandler(kafkaConf *config.Kafka, database controller.CommonMsgDatabase) (*OnlineHistoryMongoConsumerHandler, error) { + historyConsumerGroup, err := kafka.NewMConsumerGroup(kafkaConf.Build(), kafkaConf.ToMongoGroupID, []string{kafkaConf.ToMongoTopic}) if err != nil { return nil, err } @@ -65,12 +45,7 @@ func NewOnlineHistoryMongoConsumerHandler(config *config.GlobalConfig, database return mc, nil } -func (mc *OnlineHistoryMongoConsumerHandler) handleChatWs2Mongo( - ctx context.Context, - cMsg *sarama.ConsumerMessage, - key string, - session sarama.ConsumerGroupSession, -) { +func (mc *OnlineHistoryMongoConsumerHandler) handleChatWs2Mongo(ctx context.Context, cMsg *sarama.ConsumerMessage, key string, session sarama.ConsumerGroupSession) { msg := cMsg.Value msgFromMQ := pbmsg.MsgDataToMongoByMQ{} err := proto.Unmarshal(msg, &msgFromMQ) diff --git a/internal/push/callback.go b/internal/push/callback.go index 6415d63d6b..8897295827 100644 --- a/internal/push/callback.go +++ b/internal/push/callback.go @@ -16,122 +16,135 @@ package push import ( "context" + "encoding/json" + "github.com/openimsdk/open-im-server/v3/pkg/common/webhook" - "github.com/OpenIMSDK/protocol/constant" - "github.com/OpenIMSDK/protocol/sdkws" - "github.com/OpenIMSDK/tools/mcontext" - "github.com/OpenIMSDK/tools/utils" "github.com/openimsdk/open-im-server/v3/pkg/callbackstruct" "github.com/openimsdk/open-im-server/v3/pkg/common/config" - "github.com/openimsdk/open-im-server/v3/pkg/common/http" + "github.com/openimsdk/protocol/constant" + "github.com/openimsdk/protocol/sdkws" + "github.com/openimsdk/tools/mcontext" + "github.com/openimsdk/tools/utils/datautil" ) -func callbackOfflinePush( - ctx context.Context, - config *config.GlobalConfig, - userIDs []string, - msg *sdkws.MsgData, - offlinePushUserIDs *[]string, -) error { - if !config.Callback.CallbackOfflinePush.Enable || msg.ContentType == constant.Typing { - return nil - } - req := &callbackstruct.CallbackBeforePushReq{ - UserStatusBatchCallbackReq: callbackstruct.UserStatusBatchCallbackReq{ - UserStatusBaseCallback: callbackstruct.UserStatusBaseCallback{ - CallbackCommand: callbackstruct.CallbackOfflinePushCommand, - OperationID: mcontext.GetOperationID(ctx), - PlatformID: int(msg.SenderPlatformID), - Platform: constant.PlatformIDToName(int(msg.SenderPlatformID)), +func (c *ConsumerHandler) webhookBeforeOfflinePush(ctx context.Context, before *config.BeforeConfig, userIDs []string, msg *sdkws.MsgData, offlinePushUserIDs *[]string) error { + return webhook.WithCondition(ctx, before, func(ctx context.Context) error { + if msg.ContentType == constant.Typing { + return nil + } + req := &callbackstruct.CallbackBeforePushReq{ + UserStatusBatchCallbackReq: callbackstruct.UserStatusBatchCallbackReq{ + UserStatusBaseCallback: callbackstruct.UserStatusBaseCallback{ + CallbackCommand: callbackstruct.CallbackBeforeOfflinePushCommand, + OperationID: mcontext.GetOperationID(ctx), + PlatformID: int(msg.SenderPlatformID), + Platform: constant.PlatformIDToName(int(msg.SenderPlatformID)), + }, + UserIDList: userIDs, }, - UserIDList: userIDs, - }, - OfflinePushInfo: msg.OfflinePushInfo, - ClientMsgID: msg.ClientMsgID, - SendID: msg.SendID, - GroupID: msg.GroupID, - ContentType: msg.ContentType, - SessionType: msg.SessionType, - AtUserIDs: msg.AtUserIDList, - Content: GetContent(msg), - } + OfflinePushInfo: msg.OfflinePushInfo, + ClientMsgID: msg.ClientMsgID, + SendID: msg.SendID, + GroupID: msg.GroupID, + ContentType: msg.ContentType, + SessionType: msg.SessionType, + AtUserIDs: msg.AtUserIDList, + Content: GetContent(msg), + } - resp := &callbackstruct.CallbackBeforePushResp{} - if err := http.CallBackPostReturn(ctx, config.Callback.CallbackUrl, req, resp, config.Callback.CallbackOfflinePush); err != nil { - return err - } + resp := &callbackstruct.CallbackBeforePushResp{} - if len(resp.UserIDs) != 0 { - *offlinePushUserIDs = resp.UserIDs - } - if resp.OfflinePushInfo != nil { - msg.OfflinePushInfo = resp.OfflinePushInfo - } - return nil -} + if err := c.webhookClient.SyncPost(ctx, req.GetCallbackCommand(), req, resp, before); err != nil { + return err + } -func callbackOnlinePush(ctx context.Context, config *config.GlobalConfig, userIDs []string, msg *sdkws.MsgData) error { - if !config.Callback.CallbackOnlinePush.Enable || utils.Contain(msg.SendID, userIDs...) || msg.ContentType == constant.Typing { + if len(resp.UserIDs) != 0 { + *offlinePushUserIDs = resp.UserIDs + } + if resp.OfflinePushInfo != nil { + msg.OfflinePushInfo = resp.OfflinePushInfo + } return nil - } - req := callbackstruct.CallbackBeforePushReq{ - UserStatusBatchCallbackReq: callbackstruct.UserStatusBatchCallbackReq{ - UserStatusBaseCallback: callbackstruct.UserStatusBaseCallback{ - CallbackCommand: callbackstruct.CallbackOnlinePushCommand, - OperationID: mcontext.GetOperationID(ctx), - PlatformID: int(msg.SenderPlatformID), - Platform: constant.PlatformIDToName(int(msg.SenderPlatformID)), + }) +} + +func (c *ConsumerHandler) webhookBeforeOnlinePush(ctx context.Context, before *config.BeforeConfig, userIDs []string, msg *sdkws.MsgData) error { + return webhook.WithCondition(ctx, before, func(ctx context.Context) error { + if datautil.Contain(msg.SendID, userIDs...) || msg.ContentType == constant.Typing { + return nil + } + req := callbackstruct.CallbackBeforePushReq{ + UserStatusBatchCallbackReq: callbackstruct.UserStatusBatchCallbackReq{ + UserStatusBaseCallback: callbackstruct.UserStatusBaseCallback{ + CallbackCommand: callbackstruct.CallbackBeforeOnlinePushCommand, + OperationID: mcontext.GetOperationID(ctx), + PlatformID: int(msg.SenderPlatformID), + Platform: constant.PlatformIDToName(int(msg.SenderPlatformID)), + }, + UserIDList: userIDs, }, - UserIDList: userIDs, - }, - ClientMsgID: msg.ClientMsgID, - SendID: msg.SendID, - GroupID: msg.GroupID, - ContentType: msg.ContentType, - SessionType: msg.SessionType, - AtUserIDs: msg.AtUserIDList, - Content: GetContent(msg), - } - resp := &callbackstruct.CallbackBeforePushResp{} - if err := http.CallBackPostReturn(ctx, config.Callback.CallbackUrl, req, resp, config.Callback.CallbackOnlinePush); err != nil { - return err - } - return nil + ClientMsgID: msg.ClientMsgID, + SendID: msg.SendID, + GroupID: msg.GroupID, + ContentType: msg.ContentType, + SessionType: msg.SessionType, + AtUserIDs: msg.AtUserIDList, + Content: GetContent(msg), + } + resp := &callbackstruct.CallbackBeforePushResp{} + if err := c.webhookClient.SyncPost(ctx, req.GetCallbackCommand(), req, resp, before); err != nil { + return err + } + return nil + }) } -func callbackBeforeSuperGroupOnlinePush( +func (c *ConsumerHandler) webhookBeforeGroupOnlinePush( ctx context.Context, - config *config.GlobalConfig, + before *config.BeforeConfig, groupID string, msg *sdkws.MsgData, pushToUserIDs *[]string, ) error { - if !config.Callback.CallbackBeforeSuperGroupOnlinePush.Enable || msg.ContentType == constant.Typing { + return webhook.WithCondition(ctx, before, func(ctx context.Context) error { + if msg.ContentType == constant.Typing { + return nil + } + req := callbackstruct.CallbackBeforeSuperGroupOnlinePushReq{ + UserStatusBaseCallback: callbackstruct.UserStatusBaseCallback{ + CallbackCommand: callbackstruct.CallbackBeforeGroupOnlinePushCommand, + OperationID: mcontext.GetOperationID(ctx), + PlatformID: int(msg.SenderPlatformID), + Platform: constant.PlatformIDToName(int(msg.SenderPlatformID)), + }, + ClientMsgID: msg.ClientMsgID, + SendID: msg.SendID, + GroupID: groupID, + ContentType: msg.ContentType, + SessionType: msg.SessionType, + AtUserIDs: msg.AtUserIDList, + Content: GetContent(msg), + Seq: msg.Seq, + } + resp := &callbackstruct.CallbackBeforeSuperGroupOnlinePushResp{} + if err := c.webhookClient.SyncPost(ctx, req.GetCallbackCommand(), req, resp, before); err != nil { + return err + } + if len(resp.UserIDs) != 0 { + *pushToUserIDs = resp.UserIDs + } return nil - } - req := callbackstruct.CallbackBeforeSuperGroupOnlinePushReq{ - UserStatusBaseCallback: callbackstruct.UserStatusBaseCallback{ - CallbackCommand: callbackstruct.CallbackSuperGroupOnlinePushCommand, - OperationID: mcontext.GetOperationID(ctx), - PlatformID: int(msg.SenderPlatformID), - Platform: constant.PlatformIDToName(int(msg.SenderPlatformID)), - }, - ClientMsgID: msg.ClientMsgID, - SendID: msg.SendID, - GroupID: groupID, - ContentType: msg.ContentType, - SessionType: msg.SessionType, - AtUserIDs: msg.AtUserIDList, - Content: GetContent(msg), - Seq: msg.Seq, - } - resp := &callbackstruct.CallbackBeforeSuperGroupOnlinePushResp{} - if err := http.CallBackPostReturn(ctx, config.Callback.CallbackUrl, req, resp, config.Callback.CallbackBeforeSuperGroupOnlinePush); err != nil { - return err - } + }) +} - if len(resp.UserIDs) != 0 { - *pushToUserIDs = resp.UserIDs +func GetContent(msg *sdkws.MsgData) string { + if msg.ContentType >= constant.NotificationBegin && msg.ContentType <= constant.NotificationEnd { + var notification sdkws.NotificationElem + if err := json.Unmarshal(msg.Content, ¬ification); err != nil { + return "" + } + return notification.Detail + } else { + return string(msg.Content) } - return nil } diff --git a/internal/push/consumer_init.go b/internal/push/consumer_init.go deleted file mode 100644 index 351b63f46d..0000000000 --- a/internal/push/consumer_init.go +++ /dev/null @@ -1,41 +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 push - -import ( - "context" - - "github.com/openimsdk/open-im-server/v3/pkg/common/config" -) - -type Consumer struct { - pushCh ConsumerHandler - // successCount is unused - // successCount uint64 -} - -func NewConsumer(config *config.GlobalConfig, pusher *Pusher) (*Consumer, error) { - c, err := NewConsumerHandler(config, pusher) - if err != nil { - return nil, err - } - return &Consumer{ - pushCh: *c, - }, nil -} - -func (c *Consumer) Start() { - go c.pushCh.pushConsumerGroup.RegisterHandleAndConsumer(context.Background(), &c.pushCh) -} diff --git a/internal/push/offlinepush/dummy/push.go b/internal/push/offlinepush/dummy/push.go index f147886d9a..028e7edd34 100644 --- a/internal/push/offlinepush/dummy/push.go +++ b/internal/push/offlinepush/dummy/push.go @@ -16,8 +16,7 @@ package dummy import ( "context" - - "github.com/openimsdk/open-im-server/v3/internal/push/offlinepush" + "github.com/openimsdk/open-im-server/v3/internal/push/offlinepush/options" ) func NewClient() *Dummy { @@ -27,6 +26,6 @@ func NewClient() *Dummy { type Dummy struct { } -func (d *Dummy) Push(ctx context.Context, userIDs []string, title, content string, opts *offlinepush.Opts) error { +func (d *Dummy) Push(ctx context.Context, userIDs []string, title, content string, opts *options.Opts) error { return nil } diff --git a/internal/push/offlinepush/fcm/push.go b/internal/push/offlinepush/fcm/push.go index ed65a5af60..34ad1c0d6c 100644 --- a/internal/push/offlinepush/fcm/push.go +++ b/internal/push/offlinepush/fcm/push.go @@ -16,14 +16,15 @@ package fcm import ( "context" + "github.com/openimsdk/open-im-server/v3/internal/push/offlinepush/options" "path/filepath" firebase "firebase.google.com/go" "firebase.google.com/go/messaging" - "github.com/OpenIMSDK/protocol/constant" - "github.com/openimsdk/open-im-server/v3/internal/push/offlinepush" "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" + "github.com/openimsdk/protocol/constant" + "github.com/openimsdk/tools/errs" "github.com/redis/go-redis/v9" "google.golang.org/api/option" ) @@ -34,29 +35,32 @@ var Terminal = []int{constant.IOSPlatformID, constant.AndroidPlatformID, constan type Fcm struct { fcmMsgCli *messaging.Client - cache cache.MsgModel + cache cache.ThirdCache } // NewClient initializes a new FCM client using the Firebase Admin SDK. // It requires the FCM service account credentials file located within the project's configuration directory. -func NewClient(globalConfig *config.GlobalConfig, cache cache.MsgModel) *Fcm { - projectRoot := config.GetProjectRoot() - credentialsFilePath := filepath.Join(projectRoot, "config", globalConfig.Push.Fcm.ServiceAccount) +func NewClient(pushConf *config.Push, cache cache.ThirdCache) (*Fcm, error) { + projectRoot, err := config.GetProjectRoot() + if err != nil { + return nil, err + } + credentialsFilePath := filepath.Join(projectRoot, "config", pushConf.FCM.ServiceAccount) opt := option.WithCredentialsFile(credentialsFilePath) fcmApp, err := firebase.NewApp(context.Background(), nil, opt) if err != nil { - return nil + return nil, errs.Wrap(err) } ctx := context.Background() fcmMsgClient, err := fcmApp.Messaging(ctx) if err != nil { - return nil + return nil, errs.Wrap(err) } - return &Fcm{fcmMsgCli: fcmMsgClient, cache: cache} + return &Fcm{fcmMsgCli: fcmMsgClient, cache: cache}, nil } -func (f *Fcm) Push(ctx context.Context, userIDs []string, title, content string, opts *offlinepush.Opts) error { +func (f *Fcm) Push(ctx context.Context, userIDs []string, title, content string, opts *options.Opts) error { // accounts->registrationToken allTokens := make(map[string][]string, 0) for _, account := range userIDs { diff --git a/internal/push/offlinepush/getui/body.go b/internal/push/offlinepush/getui/body.go index 46479163ff..a96ff4efcd 100644 --- a/internal/push/offlinepush/getui/body.go +++ b/internal/push/offlinepush/getui/body.go @@ -133,13 +133,13 @@ type Payload struct { IsSignal bool `json:"isSignal"` } -func newPushReq(config *config.GlobalConfig, title, content string) PushReq { +func newPushReq(pushConf *config.Push, title, content string) PushReq { pushReq := PushReq{PushMessage: &PushMessage{Notification: &Notification{ Title: title, Body: content, ClickType: "startapp", - ChannelID: config.Push.GeTui.ChannelID, - ChannelName: config.Push.GeTui.ChannelName, + ChannelID: pushConf.GeTui.ChannelID, + ChannelName: pushConf.GeTui.ChannelName, }}} return pushReq } diff --git a/internal/push/offlinepush/getui/push.go b/internal/push/offlinepush/getui/push.go index 1a95727e5c..8ecea3a622 100644 --- a/internal/push/offlinepush/getui/push.go +++ b/internal/push/offlinepush/getui/push.go @@ -18,25 +18,24 @@ import ( "context" "crypto/sha256" "encoding/hex" - "errors" + "github.com/openimsdk/open-im-server/v3/internal/push/offlinepush/options" "strconv" "sync" "time" - "github.com/OpenIMSDK/tools/errs" - "github.com/OpenIMSDK/tools/log" - "github.com/OpenIMSDK/tools/mcontext" - "github.com/OpenIMSDK/tools/utils/splitter" - "github.com/openimsdk/open-im-server/v3/internal/push/offlinepush" "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" - http2 "github.com/openimsdk/open-im-server/v3/pkg/common/http" + "github.com/openimsdk/tools/errs" + "github.com/openimsdk/tools/log" + "github.com/openimsdk/tools/mcontext" + "github.com/openimsdk/tools/utils/httputil" + "github.com/openimsdk/tools/utils/splitter" "github.com/redis/go-redis/v9" ) var ( - ErrTokenExpire = errors.New("token expire") - ErrUserIDEmpty = errors.New("userIDs is empty") + ErrTokenExpire = errs.New("token expire") + ErrUserIDEmpty = errs.New("userIDs is empty") ) const ( @@ -45,32 +44,34 @@ const ( taskURL = "/push/list/message" batchPushURL = "/push/list/alias" - // codes. + // Codes. tokenExpireCode = 10001 tokenExpireTime = 60 * 60 * 23 taskIDTTL = 1000 * 60 * 60 * 24 ) type Client struct { - cache cache.MsgModel + cache cache.ThirdCache tokenExpireTime int64 taskIDTTL int64 - config *config.GlobalConfig + pushConf *config.Push + httpClient *httputil.HTTPClient } -func NewClient(config *config.GlobalConfig, cache cache.MsgModel) *Client { +func NewClient(pushConf *config.Push, cache cache.ThirdCache) *Client { return &Client{cache: cache, tokenExpireTime: tokenExpireTime, taskIDTTL: taskIDTTL, - config: config, + pushConf: pushConf, + httpClient: httputil.NewHTTPClient(httputil.NewClientConfig()), } } -func (g *Client) Push(ctx context.Context, userIDs []string, title, content string, opts *offlinepush.Opts) error { +func (g *Client) Push(ctx context.Context, userIDs []string, title, content string, opts *options.Opts) error { token, err := g.cache.GetGetuiToken(ctx) if err != nil { if errs.Unwrap(err) == redis.Nil { - log.ZInfo(ctx, "getui token not exist in redis") + log.ZDebug(ctx, "getui token not exist in redis") token, err = g.getTokenAndSave2Redis(ctx) if err != nil { return err @@ -79,7 +80,7 @@ func (g *Client) Push(ctx context.Context, userIDs []string, title, content stri return err } } - pushReq := newPushReq(g.config, title, content) + pushReq := newPushReq(g.pushConf, title, content) pushReq.setPushChannel(title, content) if len(userIDs) > 1 { maxNum := 999 @@ -114,13 +115,13 @@ func (g *Client) Push(ctx context.Context, userIDs []string, title, content stri func (g *Client) Auth(ctx context.Context, timeStamp int64) (token string, expireTime int64, err error) { h := sha256.New() h.Write( - []byte(g.config.Push.GeTui.AppKey + strconv.Itoa(int(timeStamp)) + g.config.Push.GeTui.MasterSecret), + []byte(g.pushConf.GeTui.AppKey + strconv.Itoa(int(timeStamp)) + g.pushConf.GeTui.MasterSecret), ) sign := hex.EncodeToString(h.Sum(nil)) reqAuth := AuthReq{ Sign: sign, Timestamp: strconv.Itoa(int(timeStamp)), - AppKey: g.config.Push.GeTui.AppKey, + AppKey: g.pushConf.GeTui.AppKey, } respAuth := AuthResp{} err = g.request(ctx, authURL, reqAuth, "", &respAuth) @@ -163,7 +164,7 @@ func (g *Client) request(ctx context.Context, url string, input any, token strin header := map[string]string{"token": token} resp := &Resp{} resp.Data = output - return g.postReturn(ctx, g.config.Push.GeTui.PushUrl+url, header, input, resp, 3) + return g.postReturn(ctx, g.pushConf.GeTui.PushUrl+url, header, input, resp, 3) } func (g *Client) postReturn( @@ -174,7 +175,7 @@ func (g *Client) postReturn( output RespI, timeout int, ) error { - err := http2.PostReturn(ctx, url, header, input, output, timeout) + err := g.httpClient.PostReturn(ctx, url, header, input, output, timeout) if err != nil { return err } diff --git a/internal/push/offlinepush/jpush/body/audience.go b/internal/push/offlinepush/jpush/body/audience.go index 43a7148b84..9db66ffe69 100644 --- a/internal/push/offlinepush/jpush/body/audience.go +++ b/internal/push/offlinepush/jpush/body/audience.go @@ -32,8 +32,8 @@ func (a *Audience) set(key string, v []string) { a.audience = make(map[string][]string) a.Object = a.audience } - //v, ok = this.audience[key] - //if ok { + // v, ok = this.audience[key] + // if ok { // return //} a.audience[key] = v diff --git a/internal/push/offlinepush/jpush/body/notification.go b/internal/push/offlinepush/jpush/body/notification.go index b25882ea58..42e59c46cf 100644 --- a/internal/push/offlinepush/jpush/body/notification.go +++ b/internal/push/offlinepush/jpush/body/notification.go @@ -56,8 +56,8 @@ func (n *Notification) SetExtras(extras Extras) { n.Android.Extras = extras } -func (n *Notification) SetAndroidIntent(config *config.GlobalConfig) { - n.Android.Intent.URL = config.Push.Jpns.PushIntent +func (n *Notification) SetAndroidIntent(pushConf *config.Push) { + n.Android.Intent.URL = pushConf.JPNS.PushIntent } func (n *Notification) IOSEnableMutableContent() { diff --git a/internal/push/offlinepush/jpush/body/platform.go b/internal/push/offlinepush/jpush/body/platform.go index 1ef136f2c5..5654165fa4 100644 --- a/internal/push/offlinepush/jpush/body/platform.go +++ b/internal/push/offlinepush/jpush/body/platform.go @@ -15,9 +15,9 @@ package body import ( - "errors" + "github.com/openimsdk/tools/errs" - "github.com/OpenIMSDK/protocol/constant" + "github.com/openimsdk/protocol/constant" ) const ( @@ -39,7 +39,7 @@ func (p *Platform) Set(os string) error { } else { switch p.Os.(type) { case string: - return errors.New("platform is all") + return errs.New("platform is all") default: } } @@ -61,7 +61,7 @@ func (p *Platform) Set(os string) error { p.osArry = append(p.osArry, os) p.Os = p.osArry default: - return errors.New("unknow platform") + return errs.New("unknow platform") } return nil @@ -74,7 +74,7 @@ func (p *Platform) SetPlatform(platform string) error { case constant.IOSPlatformStr: return p.SetIOS() default: - return errors.New("platform err") + return errs.New("platform err") } } diff --git a/internal/push/offlinepush/jpush/push.go b/internal/push/offlinepush/jpush/push.go index 2ced4bfd3d..dac52597f5 100644 --- a/internal/push/offlinepush/jpush/push.go +++ b/internal/push/offlinepush/jpush/push.go @@ -18,19 +18,22 @@ import ( "context" "encoding/base64" "fmt" + "github.com/openimsdk/open-im-server/v3/internal/push/offlinepush/options" - "github.com/openimsdk/open-im-server/v3/internal/push/offlinepush" "github.com/openimsdk/open-im-server/v3/internal/push/offlinepush/jpush/body" "github.com/openimsdk/open-im-server/v3/pkg/common/config" - http2 "github.com/openimsdk/open-im-server/v3/pkg/common/http" + "github.com/openimsdk/tools/utils/httputil" ) type JPush struct { - config *config.GlobalConfig + pushConf *config.Push + httpClient *httputil.HTTPClient } -func NewClient(config *config.GlobalConfig) *JPush { - return &JPush{config: config} +func NewClient(pushConf *config.Push) *JPush { + return &JPush{pushConf: pushConf, + httpClient: httputil.NewHTTPClient(httputil.NewClientConfig()), + } } func (j *JPush) Auth(apiKey, secretKey string, timeStamp int64) (token string, err error) { @@ -48,7 +51,7 @@ func (j *JPush) getAuthorization(appKey string, masterSecret string) string { return Authorization } -func (j *JPush) Push(ctx context.Context, userIDs []string, title, content string, opts *offlinepush.Opts) error { +func (j *JPush) Push(ctx context.Context, userIDs []string, title, content string, opts *options.Opts) error { var pf body.Platform pf.SetAll() var au body.Audience @@ -61,12 +64,12 @@ func (j *JPush) Push(ctx context.Context, userIDs []string, title, content strin no.IOSEnableMutableContent() no.SetExtras(extras) no.SetAlert(title) - no.SetAndroidIntent(j.config) + no.SetAndroidIntent(j.pushConf) var msg body.Message msg.SetMsgContent(content) var opt body.Options - opt.SetApnsProduction(j.config.IOSPush.Production) + opt.SetApnsProduction(j.pushConf.IOSPush.Production) var pushObj body.PushObj pushObj.SetPlatform(&pf) pushObj.SetAudience(&au) @@ -78,11 +81,11 @@ func (j *JPush) Push(ctx context.Context, userIDs []string, title, content strin } func (j *JPush) request(ctx context.Context, po body.PushObj, resp any, timeout int) error { - return http2.PostReturn( + return j.httpClient.PostReturn( ctx, - j.config.Push.Jpns.PushUrl, + j.pushConf.JPNS.PushURL, map[string]string{ - "Authorization": j.getAuthorization(j.config.Push.Jpns.AppKey, j.config.Push.Jpns.MasterSecret), + "Authorization": j.getAuthorization(j.pushConf.JPNS.AppKey, j.pushConf.JPNS.MasterSecret), }, po, resp, diff --git a/internal/push/offlinepush/offlinepush_interface.go b/internal/push/offlinepush/offlinepush_interface.go deleted file mode 100644 index a5d4051f90..0000000000 --- a/internal/push/offlinepush/offlinepush_interface.go +++ /dev/null @@ -1,37 +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 offlinepush - -import ( - "context" -) - -// OfflinePusher Offline Pusher. -type OfflinePusher interface { - Push(ctx context.Context, userIDs []string, title, content string, opts *Opts) error -} - -// Opts opts. -type Opts struct { - Signal *Signal - IOSPushSound string - IOSBadgeCount bool - Ex string -} - -// Signal message id. -type Signal struct { - ClientMsgID string -} diff --git a/internal/push/offlinepush/offlinepusher.go b/internal/push/offlinepush/offlinepusher.go new file mode 100644 index 0000000000..0706be64a4 --- /dev/null +++ b/internal/push/offlinepush/offlinepusher.go @@ -0,0 +1,52 @@ +// 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 offlinepush + +import ( + "context" + "github.com/openimsdk/open-im-server/v3/internal/push/offlinepush/dummy" + "github.com/openimsdk/open-im-server/v3/internal/push/offlinepush/fcm" + "github.com/openimsdk/open-im-server/v3/internal/push/offlinepush/getui" + "github.com/openimsdk/open-im-server/v3/internal/push/offlinepush/jpush" + "github.com/openimsdk/open-im-server/v3/internal/push/offlinepush/options" + "github.com/openimsdk/open-im-server/v3/pkg/common/config" + "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" +) + +const ( + geTUI = "getui" + firebase = "fcm" + jPush = "jpush" +) + +// OfflinePusher Offline Pusher. +type OfflinePusher interface { + Push(ctx context.Context, userIDs []string, title, content string, opts *options.Opts) error +} + +func NewOfflinePusher(pushConf *config.Push, cache cache.ThirdCache) (OfflinePusher, error) { + var offlinePusher OfflinePusher + switch pushConf.Enable { + case geTUI: + offlinePusher = getui.NewClient(pushConf, cache) + case firebase: + return fcm.NewClient(pushConf, cache) + case jPush: + offlinePusher = jpush.NewClient(pushConf) + default: + offlinePusher = dummy.NewClient() + } + return offlinePusher, nil +} diff --git a/internal/push/offlinepush/options/options.go b/internal/push/offlinepush/options/options.go new file mode 100644 index 0000000000..056f6b7113 --- /dev/null +++ b/internal/push/offlinepush/options/options.go @@ -0,0 +1,14 @@ +package options + +// Opts opts. +type Opts struct { + Signal *Signal + IOSPushSound string + IOSBadgeCount bool + Ex string +} + +// Signal message id. +type Signal struct { + ClientMsgID string +} diff --git a/internal/push/onlinepusher.go b/internal/push/onlinepusher.go new file mode 100644 index 0000000000..30bdf3e2ed --- /dev/null +++ b/internal/push/onlinepusher.go @@ -0,0 +1,204 @@ +package push + +import ( + "context" + "github.com/openimsdk/protocol/msggateway" + "github.com/openimsdk/protocol/sdkws" + "github.com/openimsdk/tools/discovery" + "github.com/openimsdk/tools/log" + "github.com/openimsdk/tools/utils/datautil" + "golang.org/x/sync/errgroup" + "google.golang.org/grpc" + "sync" +) + +const ( + KUBERNETES = "k8s" + ZOOKEEPER = "zookeeper" +) + +type OnlinePusher interface { + GetConnsAndOnlinePush(ctx context.Context, msg *sdkws.MsgData, + pushToUserIDs []string) (wsResults []*msggateway.SingleMsgToUserResults, err error) + GetOnlinePushFailedUserIDs(ctx context.Context, msg *sdkws.MsgData, wsResults []*msggateway.SingleMsgToUserResults, + pushToUserIDs *[]string) []string +} + +type emptyOnlinePUsher struct{} + +func newEmptyOnlinePUsher() *emptyOnlinePUsher { + return &emptyOnlinePUsher{} +} + +func (emptyOnlinePUsher) GetConnsAndOnlinePush(ctx context.Context, msg *sdkws.MsgData, + pushToUserIDs []string) (wsResults []*msggateway.SingleMsgToUserResults, err error) { + log.ZWarn(ctx, "emptyOnlinePUsher GetConnsAndOnlinePush", nil) + return nil, nil +} +func (u emptyOnlinePUsher) GetOnlinePushFailedUserIDs(ctx context.Context, msg *sdkws.MsgData, + wsResults []*msggateway.SingleMsgToUserResults, pushToUserIDs *[]string) []string { + log.ZWarn(ctx, "emptyOnlinePUsher GetOnlinePushFailedUserIDs", nil) + return nil +} + +func NewOnlinePusher(disCov discovery.SvcDiscoveryRegistry, config *Config) OnlinePusher { + switch config.Share.Env { + case KUBERNETES: + return NewK8sStaticConsistentHash(disCov, config) + case ZOOKEEPER: + return NewDefaultAllNode(disCov, config) + default: + return newEmptyOnlinePUsher() + } +} + +type DefaultAllNode struct { + disCov discovery.SvcDiscoveryRegistry + config *Config +} + +func NewDefaultAllNode(disCov discovery.SvcDiscoveryRegistry, config *Config) *DefaultAllNode { + return &DefaultAllNode{disCov: disCov, config: config} +} + +func (d *DefaultAllNode) GetConnsAndOnlinePush(ctx context.Context, msg *sdkws.MsgData, + pushToUserIDs []string) (wsResults []*msggateway.SingleMsgToUserResults, err error) { + conns, err := d.disCov.GetConns(ctx, d.config.Share.RpcRegisterName.MessageGateway) + log.ZDebug(ctx, "get gateway conn", "conn length", len(conns)) + if err != nil { + return nil, err + } + + var ( + mu sync.Mutex + wg = errgroup.Group{} + input = &msggateway.OnlineBatchPushOneMsgReq{MsgData: msg, PushToUserIDs: pushToUserIDs} + maxWorkers = d.config.RpcConfig.MaxConcurrentWorkers + ) + + if maxWorkers < 3 { + maxWorkers = 3 + } + + wg.SetLimit(maxWorkers) + + // Online push message + for _, conn := range conns { + conn := conn // loop var safe + wg.Go(func() error { + msgClient := msggateway.NewMsgGatewayClient(conn) + reply, err := msgClient.SuperGroupOnlineBatchPushOneMsg(ctx, input) + if err != nil { + return nil + } + + log.ZDebug(ctx, "push result", "reply", reply) + if reply != nil && reply.SinglePushResult != nil { + mu.Lock() + wsResults = append(wsResults, reply.SinglePushResult...) + mu.Unlock() + } + + return nil + }) + } + + _ = wg.Wait() + + // always return nil + return wsResults, nil +} + +func (d *DefaultAllNode) GetOnlinePushFailedUserIDs(_ context.Context, msg *sdkws.MsgData, + wsResults []*msggateway.SingleMsgToUserResults, pushToUserIDs *[]string) []string { + + onlineSuccessUserIDs := []string{msg.SendID} + for _, v := range wsResults { + //message sender do not need offline push + if msg.SendID == v.UserID { + continue + } + // mobile online push success + if v.OnlinePush { + onlineSuccessUserIDs = append(onlineSuccessUserIDs, v.UserID) + } + + } + + return datautil.SliceSub(*pushToUserIDs, onlineSuccessUserIDs) +} + +type K8sStaticConsistentHash struct { + disCov discovery.SvcDiscoveryRegistry + config *Config +} + +func NewK8sStaticConsistentHash(disCov discovery.SvcDiscoveryRegistry, config *Config) *K8sStaticConsistentHash { + return &K8sStaticConsistentHash{disCov: disCov, config: config} +} + +func (k *K8sStaticConsistentHash) GetConnsAndOnlinePush(ctx context.Context, msg *sdkws.MsgData, + pushToUserIDs []string) (wsResults []*msggateway.SingleMsgToUserResults, err error) { + + var usersHost = make(map[string][]string) + for _, v := range pushToUserIDs { + tHost, err := k.disCov.GetUserIdHashGatewayHost(ctx, v) + if err != nil { + log.ZError(ctx, "get msg gateway hash error", err) + return nil, err + } + tUsers, tbl := usersHost[tHost] + if tbl { + tUsers = append(tUsers, v) + usersHost[tHost] = tUsers + } else { + usersHost[tHost] = []string{v} + } + } + log.ZDebug(ctx, "genUsers send hosts struct:", "usersHost", usersHost) + var usersConns = make(map[*grpc.ClientConn][]string) + for host, userIds := range usersHost { + tconn, _ := k.disCov.GetConn(ctx, host) + usersConns[tconn] = userIds + } + var ( + mu sync.Mutex + wg = errgroup.Group{} + maxWorkers = k.config.RpcConfig.MaxConcurrentWorkers + ) + if maxWorkers < 3 { + maxWorkers = 3 + } + wg.SetLimit(maxWorkers) + for conn, userIds := range usersConns { + tcon := conn + tuserIds := userIds + wg.Go(func() error { + input := &msggateway.OnlineBatchPushOneMsgReq{MsgData: msg, PushToUserIDs: tuserIds} + msgClient := msggateway.NewMsgGatewayClient(tcon) + reply, err := msgClient.SuperGroupOnlineBatchPushOneMsg(ctx, input) + if err != nil { + return nil + } + log.ZDebug(ctx, "push result", "reply", reply) + if reply != nil && reply.SinglePushResult != nil { + mu.Lock() + wsResults = append(wsResults, reply.SinglePushResult...) + mu.Unlock() + } + return nil + }) + } + _ = wg.Wait() + return wsResults, nil +} +func (k *K8sStaticConsistentHash) GetOnlinePushFailedUserIDs(_ context.Context, _ *sdkws.MsgData, + wsResults []*msggateway.SingleMsgToUserResults, _ *[]string) []string { + var needOfflinePushUserIDs []string + for _, v := range wsResults { + if !v.OnlinePush { + needOfflinePushUserIDs = append(needOfflinePushUserIDs, v.UserID) + } + } + return needOfflinePushUserIDs +} diff --git a/internal/push/push.go b/internal/push/push.go new file mode 100644 index 0000000000..18012a8646 --- /dev/null +++ b/internal/push/push.go @@ -0,0 +1,71 @@ +package push + +import ( + "context" + "github.com/openimsdk/open-im-server/v3/internal/push/offlinepush" + "github.com/openimsdk/open-im-server/v3/pkg/common/config" + "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" + "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" + pbpush "github.com/openimsdk/protocol/push" + "github.com/openimsdk/tools/db/redisutil" + "github.com/openimsdk/tools/discovery" + "google.golang.org/grpc" +) + +type pushServer struct { + database controller.PushDatabase + disCov discovery.SvcDiscoveryRegistry + offlinePusher offlinepush.OfflinePusher + pushCh *ConsumerHandler +} + +type Config struct { + RpcConfig config.Push + RedisConfig config.Redis + MongodbConfig config.Mongo + KafkaConfig config.Kafka + ZookeeperConfig config.ZooKeeper + NotificationConfig config.Notification + Share config.Share + WebhooksConfig config.Webhooks + LocalCacheConfig config.LocalCache +} + +func (p pushServer) PushMsg(ctx context.Context, req *pbpush.PushMsgReq) (*pbpush.PushMsgResp, error) { + //todo reserved Interface + return nil, nil +} + +func (p pushServer) DelUserPushToken(ctx context.Context, + req *pbpush.DelUserPushTokenReq) (resp *pbpush.DelUserPushTokenResp, err error) { + if err = p.database.DelFcmToken(ctx, req.UserID, int(req.PlatformID)); err != nil { + return nil, err + } + return &pbpush.DelUserPushTokenResp{}, nil +} + +func Start(ctx context.Context, config *Config, client discovery.SvcDiscoveryRegistry, server *grpc.Server) error { + rdb, err := redisutil.NewRedisClient(ctx, config.RedisConfig.Build()) + if err != nil { + return err + } + cacheModel := cache.NewThirdCache(rdb) + offlinePusher, err := offlinepush.NewOfflinePusher(&config.RpcConfig, cacheModel) + if err != nil { + return err + } + database := controller.NewPushDatabase(cacheModel) + + consumer, err := NewConsumerHandler(config, offlinePusher, rdb, client) + if err != nil { + return err + } + pbpush.RegisterPushMsgServiceServer(server, &pushServer{ + database: database, + disCov: client, + offlinePusher: offlinePusher, + pushCh: consumer, + }) + go consumer.pushConsumerGroup.RegisterHandleAndConsumer(ctx, consumer) + return nil +} diff --git a/internal/push/push_handler.go b/internal/push/push_handler.go index 0e68e76b3d..2246fb3f68 100644 --- a/internal/push/push_handler.go +++ b/internal/push/push_handler.go @@ -16,49 +16,64 @@ package push import ( "context" + "encoding/json" + "github.com/openimsdk/open-im-server/v3/internal/push/offlinepush" + "github.com/openimsdk/open-im-server/v3/internal/push/offlinepush/options" + "github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics" + "github.com/openimsdk/open-im-server/v3/pkg/common/webhook" + "github.com/openimsdk/open-im-server/v3/pkg/msgprocessor" + "github.com/openimsdk/open-im-server/v3/pkg/rpccache" + "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" + "github.com/openimsdk/open-im-server/v3/pkg/util/conversationutil" + "github.com/openimsdk/protocol/sdkws" + "github.com/openimsdk/tools/discovery" + "github.com/openimsdk/tools/mcontext" + "github.com/openimsdk/tools/utils/jsonutil" + "github.com/redis/go-redis/v9" "github.com/IBM/sarama" - "github.com/OpenIMSDK/protocol/constant" - pbchat "github.com/OpenIMSDK/protocol/msg" - pbpush "github.com/OpenIMSDK/protocol/push" - "github.com/OpenIMSDK/tools/log" - "github.com/OpenIMSDK/tools/utils" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" - kfk "github.com/openimsdk/open-im-server/v3/pkg/common/kafka" + "github.com/openimsdk/protocol/constant" + pbchat "github.com/openimsdk/protocol/msg" + pbpush "github.com/openimsdk/protocol/push" + "github.com/openimsdk/tools/log" + "github.com/openimsdk/tools/mq/kafka" + "github.com/openimsdk/tools/utils/datautil" + "github.com/openimsdk/tools/utils/timeutil" "google.golang.org/protobuf/proto" ) type ConsumerHandler struct { - pushConsumerGroup *kfk.MConsumerGroup - pusher *Pusher + pushConsumerGroup *kafka.MConsumerGroup + offlinePusher offlinepush.OfflinePusher + onlinePusher OnlinePusher + groupLocalCache *rpccache.GroupLocalCache + conversationLocalCache *rpccache.ConversationLocalCache + msgRpcClient rpcclient.MessageRpcClient + conversationRpcClient rpcclient.ConversationRpcClient + groupRpcClient rpcclient.GroupRpcClient + webhookClient *webhook.Client + config *Config } -func NewConsumerHandler(config *config.GlobalConfig, pusher *Pusher) (*ConsumerHandler, error) { +func NewConsumerHandler(config *Config, offlinePusher offlinepush.OfflinePusher, rdb redis.UniversalClient, + client discovery.SvcDiscoveryRegistry) (*ConsumerHandler, error) { var consumerHandler ConsumerHandler - consumerHandler.pusher = pusher var err error - var tlsConfig *kfk.TLSConfig - if config.Kafka.TLS != nil { - tlsConfig = &kfk.TLSConfig{ - CACrt: config.Kafka.TLS.CACrt, - ClientCrt: config.Kafka.TLS.ClientCrt, - ClientKey: config.Kafka.TLS.ClientKey, - ClientKeyPwd: config.Kafka.TLS.ClientKeyPwd, - InsecureSkipVerify: false, - } - } - consumerHandler.pushConsumerGroup, err = kfk.NewMConsumerGroup(&kfk.MConsumerGroupConfig{ - KafkaVersion: sarama.V2_0_0_0, - OffsetsInitial: sarama.OffsetNewest, - IsReturnErr: false, - UserName: config.Kafka.Username, - Password: config.Kafka.Password, - }, []string{config.Kafka.MsgToPush.Topic}, config.Kafka.Addr, - config.Kafka.ConsumerGroupID.MsgToPush, - tlsConfig) + consumerHandler.pushConsumerGroup, err = kafka.NewMConsumerGroup(config.KafkaConfig.Build(), config.KafkaConfig.ToPushGroupID, + []string{config.KafkaConfig.ToPushTopic}) if err != nil { return nil, err } + consumerHandler.offlinePusher = offlinePusher + consumerHandler.onlinePusher = NewOnlinePusher(client, config) + consumerHandler.groupRpcClient = rpcclient.NewGroupRpcClient(client, config.Share.RpcRegisterName.Group) + consumerHandler.groupLocalCache = rpccache.NewGroupLocalCache(consumerHandler.groupRpcClient, &config.LocalCacheConfig, rdb) + consumerHandler.msgRpcClient = rpcclient.NewMessageRpcClient(client, config.Share.RpcRegisterName.Msg) + consumerHandler.conversationRpcClient = rpcclient.NewConversationRpcClient(client, config.Share.RpcRegisterName.Conversation) + consumerHandler.conversationLocalCache = rpccache.NewConversationLocalCache(consumerHandler.conversationRpcClient, + &config.LocalCacheConfig, rdb) + consumerHandler.webhookClient = webhook.NewWebhookClient(config.WebhooksConfig.URL) + consumerHandler.config = config return &consumerHandler, nil } @@ -73,38 +88,35 @@ func (c *ConsumerHandler) handleMs2PsChat(ctx context.Context, msg []byte) { ConversationID: msgFromMQ.ConversationID, } sec := msgFromMQ.MsgData.SendTime / 1000 - nowSec := utils.GetCurrentTimestampBySecond() + nowSec := timeutil.GetCurrentTimestampBySecond() log.ZDebug(ctx, "push msg", "msg", pbData.String(), "sec", sec, "nowSec", nowSec) if nowSec-sec > 10 { return } var err error switch msgFromMQ.MsgData.SessionType { - case constant.SuperGroupChatType: - err = c.pusher.Push2SuperGroup(ctx, pbData.MsgData.GroupID, pbData.MsgData) + case constant.ReadGroupChatType: + err = c.Push2SuperGroup(ctx, pbData.MsgData.GroupID, pbData.MsgData) default: var pushUserIDList []string - isSenderSync := utils.GetSwitchFromOptions(pbData.MsgData.Options, constant.IsSenderSync) + isSenderSync := datautil.GetSwitchFromOptions(pbData.MsgData.Options, constant.IsSenderSync) if !isSenderSync || pbData.MsgData.SendID == pbData.MsgData.RecvID { pushUserIDList = append(pushUserIDList, pbData.MsgData.RecvID) } else { pushUserIDList = append(pushUserIDList, pbData.MsgData.RecvID, pbData.MsgData.SendID) } - err = c.pusher.Push2User(ctx, pushUserIDList, pbData.MsgData) + err = c.Push2User(ctx, pushUserIDList, pbData.MsgData) } if err != nil { - if err == errNoOfflinePusher { - log.ZWarn(ctx, "offline push failed", err, "msg", pbData.String()) - } else { - log.ZError(ctx, "push failed", err, "msg", pbData.String()) - } + log.ZError(ctx, "push failed", err, "msg", pbData.String()) } } -func (ConsumerHandler) Setup(_ sarama.ConsumerGroupSession) error { return nil } -func (ConsumerHandler) Cleanup(_ sarama.ConsumerGroupSession) error { return nil } -func (c *ConsumerHandler) ConsumeClaim(sess sarama.ConsumerGroupSession, - claim sarama.ConsumerGroupClaim, -) error { + +func (*ConsumerHandler) Setup(sarama.ConsumerGroupSession) error { return nil } + +func (*ConsumerHandler) Cleanup(sarama.ConsumerGroupSession) error { return nil } + +func (c *ConsumerHandler) ConsumeClaim(sess sarama.ConsumerGroupSession, claim sarama.ConsumerGroupClaim) error { for msg := range claim.Messages() { ctx := c.pushConsumerGroup.GetContextFromMsg(msg) c.handleMs2PsChat(ctx, msg.Value) @@ -112,3 +124,243 @@ func (c *ConsumerHandler) ConsumeClaim(sess sarama.ConsumerGroupSession, } return nil } + +// Push2User Suitable for two types of conversations, one is SingleChatType and the other is NotificationChatType. +func (c *ConsumerHandler) Push2User(ctx context.Context, userIDs []string, msg *sdkws.MsgData) error { + log.ZDebug(ctx, "Get msg from msg_transfer And push msg", "userIDs", userIDs, "msg", msg.String()) + if err := c.webhookBeforeOnlinePush(ctx, &c.config.WebhooksConfig.BeforeOnlinePush, userIDs, msg); err != nil { + return err + } + wsResults, err := c.onlinePusher.GetConnsAndOnlinePush(ctx, msg, userIDs) + if err != nil { + return err + } + + log.ZDebug(ctx, "single and notification push result", "result", wsResults, "msg", msg, "push_to_userID", userIDs) + + if !c.shouldPushOffline(ctx, msg) { + return nil + } + + for _, v := range wsResults { + //message sender do not need offline push + if msg.SendID == v.UserID { + continue + } + //receiver online push success + if v.OnlinePush { + return nil + } + } + offlinePUshUserID := []string{msg.RecvID} + + //receiver offline push + if err = c.webhookBeforeOfflinePush(ctx, &c.config.WebhooksConfig.BeforeOfflinePush, + offlinePUshUserID, msg, nil); err != nil { + return err + } + + err = c.offlinePushMsg(ctx, msg, offlinePUshUserID) + if err != nil { + return err + } + + return nil +} + +func (c *ConsumerHandler) shouldPushOffline(_ context.Context, msg *sdkws.MsgData) bool { + isOfflinePush := datautil.GetSwitchFromOptions(msg.Options, constant.IsOfflinePush) + if !isOfflinePush { + return false + } + if msg.ContentType == constant.SignalingNotification { + return false + } + return true +} + +func (c *ConsumerHandler) Push2SuperGroup(ctx context.Context, groupID string, msg *sdkws.MsgData) (err error) { + log.ZDebug(ctx, "Get super group msg from msg_transfer and push msg", "msg", msg.String(), "groupID", groupID) + var pushToUserIDs []string + if err = c.webhookBeforeGroupOnlinePush(ctx, &c.config.WebhooksConfig.BeforeGroupOnlinePush, groupID, msg, + &pushToUserIDs); err != nil { + return err + } + + err = c.groupMessagesHandler(ctx, groupID, &pushToUserIDs, msg) + if err != nil { + return err + } + + wsResults, err := c.onlinePusher.GetConnsAndOnlinePush(ctx, msg, pushToUserIDs) + if err != nil { + return err + } + + log.ZDebug(ctx, "group push result", "result", wsResults, "msg", msg) + + if !c.shouldPushOffline(ctx, msg) { + return nil + } + needOfflinePushUserIDs := c.onlinePusher.GetOnlinePushFailedUserIDs(ctx, msg, wsResults, &pushToUserIDs) + + //filter some user, like don not disturb or don't need offline push etc. + needOfflinePushUserIDs, err = c.filterGroupMessageOfflinePush(ctx, groupID, msg, needOfflinePushUserIDs) + if err != nil { + return err + } + // Use offline push messaging + if len(needOfflinePushUserIDs) > 0 { + var offlinePushUserIDs []string + err = c.webhookBeforeOfflinePush(ctx, &c.config.WebhooksConfig.BeforeOfflinePush, needOfflinePushUserIDs, msg, &offlinePushUserIDs) + if err != nil { + return err + } + + if len(offlinePushUserIDs) > 0 { + needOfflinePushUserIDs = offlinePushUserIDs + } + + err = c.offlinePushMsg(ctx, msg, needOfflinePushUserIDs) + if err != nil { + log.ZError(ctx, "offlinePushMsg failed", err, "groupID", groupID, "msg", msg) + return err + } + + } + + return nil +} +func (c *ConsumerHandler) groupMessagesHandler(ctx context.Context, groupID string, pushToUserIDs *[]string, msg *sdkws.MsgData) (err error) { + if len(*pushToUserIDs) == 0 { + *pushToUserIDs, err = c.groupLocalCache.GetGroupMemberIDs(ctx, groupID) + if err != nil { + return err + } + switch msg.ContentType { + case constant.MemberQuitNotification: + var tips sdkws.MemberQuitTips + if unmarshalNotificationElem(msg.Content, &tips) != nil { + return err + } + if err = c.DeleteMemberAndSetConversationSeq(ctx, groupID, []string{tips.QuitUser.UserID}); err != nil { + log.ZError(ctx, "MemberQuitNotification DeleteMemberAndSetConversationSeq", err, "groupID", groupID, "userID", tips.QuitUser.UserID) + } + *pushToUserIDs = append(*pushToUserIDs, tips.QuitUser.UserID) + case constant.MemberKickedNotification: + var tips sdkws.MemberKickedTips + if unmarshalNotificationElem(msg.Content, &tips) != nil { + return err + } + kickedUsers := datautil.Slice(tips.KickedUserList, func(e *sdkws.GroupMemberFullInfo) string { return e.UserID }) + if err = c.DeleteMemberAndSetConversationSeq(ctx, groupID, kickedUsers); err != nil { + log.ZError(ctx, "MemberKickedNotification DeleteMemberAndSetConversationSeq", err, "groupID", groupID, "userIDs", kickedUsers) + } + + *pushToUserIDs = append(*pushToUserIDs, kickedUsers...) + case constant.GroupDismissedNotification: + if msgprocessor.IsNotification(msgprocessor.GetConversationIDByMsg(msg)) { // 消息先到,通知后到 + var tips sdkws.GroupDismissedTips + if unmarshalNotificationElem(msg.Content, &tips) != nil { + return err + } + log.ZInfo(ctx, "GroupDismissedNotificationInfo****", "groupID", groupID, "num", len(*pushToUserIDs), "list", pushToUserIDs) + if len(c.config.Share.IMAdminUserID) > 0 { + ctx = mcontext.WithOpUserIDContext(ctx, c.config.Share.IMAdminUserID[0]) + } + defer func(groupID string) { + if err = c.groupRpcClient.DismissGroup(ctx, groupID); err != nil { + log.ZError(ctx, "DismissGroup Notification clear members", err, "groupID", groupID) + } + }(groupID) + } + } + } + return err +} + +func (c *ConsumerHandler) offlinePushMsg(ctx context.Context, msg *sdkws.MsgData, offlinePushUserIDs []string) error { + title, content, opts, err := c.getOfflinePushInfos(msg) + if err != nil { + return err + } + err = c.offlinePusher.Push(ctx, offlinePushUserIDs, title, content, opts) + if err != nil { + prommetrics.MsgOfflinePushFailedCounter.Inc() + return err + } + return nil +} + +func (c *ConsumerHandler) filterGroupMessageOfflinePush(ctx context.Context, groupID string, msg *sdkws.MsgData, + offlinePushUserIDs []string) (userIDs []string, err error) { + + //todo local cache Obtain the difference set through local comparison. + needOfflinePushUserIDs, err := c.conversationRpcClient.GetConversationOfflinePushUserIDs( + ctx, conversationutil.GenGroupConversationID(groupID), offlinePushUserIDs) + if err != nil { + return nil, err + } + return needOfflinePushUserIDs, nil +} + +func (c *ConsumerHandler) getOfflinePushInfos(msg *sdkws.MsgData) (title, content string, opts *options.Opts, err error) { + type AtTextElem struct { + Text string `json:"text,omitempty"` + AtUserList []string `json:"atUserList,omitempty"` + IsAtSelf bool `json:"isAtSelf"` + } + + opts = &options.Opts{Signal: &options.Signal{}} + if msg.OfflinePushInfo != nil { + opts.IOSBadgeCount = msg.OfflinePushInfo.IOSBadgeCount + opts.IOSPushSound = msg.OfflinePushInfo.IOSPushSound + opts.Ex = msg.OfflinePushInfo.Ex + } + + if msg.OfflinePushInfo != nil { + title = msg.OfflinePushInfo.Title + content = msg.OfflinePushInfo.Desc + } + if title == "" { + switch msg.ContentType { + case constant.Text: + fallthrough + case constant.Picture: + fallthrough + case constant.Voice: + fallthrough + case constant.Video: + fallthrough + case constant.File: + title = constant.ContentType2PushContent[int64(msg.ContentType)] + case constant.AtText: + ac := AtTextElem{} + _ = jsonutil.JsonStringToStruct(string(msg.Content), &ac) + case constant.SignalingNotification: + title = constant.ContentType2PushContent[constant.SignalMsg] + default: + title = constant.ContentType2PushContent[constant.Common] + } + } + if content == "" { + content = title + } + return +} +func (c *ConsumerHandler) DeleteMemberAndSetConversationSeq(ctx context.Context, groupID string, userIDs []string) error { + conversationID := msgprocessor.GetConversationIDBySessionType(constant.ReadGroupChatType, groupID) + maxSeq, err := c.msgRpcClient.GetConversationMaxSeq(ctx, conversationID) + if err != nil { + return err + } + return c.conversationRpcClient.SetConversationMaxSeq(ctx, userIDs, conversationID, maxSeq) +} +func unmarshalNotificationElem(bytes []byte, t any) error { + var notification sdkws.NotificationElem + if err := json.Unmarshal(bytes, ¬ification); err != nil { + return err + } + + return json.Unmarshal([]byte(notification.Detail), t) +} diff --git a/internal/push/push_rpc_server.go b/internal/push/push_rpc_server.go deleted file mode 100644 index b68b06666e..0000000000 --- a/internal/push/push_rpc_server.go +++ /dev/null @@ -1,107 +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 push - -import ( - "context" - - "github.com/OpenIMSDK/protocol/constant" - pbpush "github.com/OpenIMSDK/protocol/push" - "github.com/OpenIMSDK/tools/discoveryregistry" - "github.com/OpenIMSDK/tools/log" - "github.com/OpenIMSDK/tools/utils" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" - "github.com/openimsdk/open-im-server/v3/pkg/rpccache" - "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" - "google.golang.org/grpc" -) - -type pushServer struct { - pusher *Pusher - config *config.GlobalConfig -} - -func Start(config *config.GlobalConfig, client discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) error { - rdb, err := cache.NewRedis(config) - if err != nil { - return err - } - cacheModel := cache.NewMsgCacheModel(rdb, config) - offlinePusher := NewOfflinePusher(config, cacheModel) - database := controller.NewPushDatabase(cacheModel) - groupRpcClient := rpcclient.NewGroupRpcClient(client, config) - conversationRpcClient := rpcclient.NewConversationRpcClient(client, config) - msgRpcClient := rpcclient.NewMessageRpcClient(client, config) - pusher := NewPusher( - config, - client, - offlinePusher, - database, - rpccache.NewGroupLocalCache(groupRpcClient, rdb), - rpccache.NewConversationLocalCache(conversationRpcClient, rdb), - &conversationRpcClient, - &groupRpcClient, - &msgRpcClient, - ) - - pbpush.RegisterPushMsgServiceServer(server, &pushServer{ - pusher: pusher, - config: config, - }) - - consumer, err := NewConsumer(config, pusher) - if err != nil { - return err - } - - consumer.Start() - - return nil -} - -func (r *pushServer) PushMsg(ctx context.Context, pbData *pbpush.PushMsgReq) (resp *pbpush.PushMsgResp, err error) { - switch pbData.MsgData.SessionType { - case constant.SuperGroupChatType: - err = r.pusher.Push2SuperGroup(ctx, pbData.MsgData.GroupID, pbData.MsgData) - default: - var pushUserIDList []string - isSenderSync := utils.GetSwitchFromOptions(pbData.MsgData.Options, constant.IsSenderSync) - if !isSenderSync { - pushUserIDList = append(pushUserIDList, pbData.MsgData.RecvID) - } else { - pushUserIDList = append(pushUserIDList, pbData.MsgData.RecvID, pbData.MsgData.SendID) - } - err = r.pusher.Push2User(ctx, pushUserIDList, pbData.MsgData) - } - if err != nil { - if err != errNoOfflinePusher { - return nil, err - } - log.ZWarn(ctx, "offline push failed", err, "msg", pbData.String()) - } - return &pbpush.PushMsgResp{}, nil -} - -func (r *pushServer) DelUserPushToken( - ctx context.Context, - req *pbpush.DelUserPushTokenReq, -) (resp *pbpush.DelUserPushTokenResp, err error) { - if err = r.pusher.database.DelFcmToken(ctx, req.UserID, int(req.PlatformID)); err != nil { - return nil, err - } - return &pbpush.DelUserPushTokenResp{}, nil -} diff --git a/internal/push/push_to_client.go b/internal/push/push_to_client.go deleted file mode 100644 index d7f30ebce0..0000000000 --- a/internal/push/push_to_client.go +++ /dev/null @@ -1,522 +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 push - -import ( - "context" - "encoding/json" - "errors" - "sync" - - "github.com/OpenIMSDK/protocol/constant" - "github.com/OpenIMSDK/protocol/conversation" - "github.com/OpenIMSDK/protocol/msggateway" - "github.com/OpenIMSDK/protocol/sdkws" - "github.com/OpenIMSDK/tools/discoveryregistry" - "github.com/OpenIMSDK/tools/log" - "github.com/OpenIMSDK/tools/mcontext" - "github.com/OpenIMSDK/tools/utils" - "github.com/openimsdk/open-im-server/v3/internal/push/offlinepush" - "github.com/openimsdk/open-im-server/v3/internal/push/offlinepush/dummy" - "github.com/openimsdk/open-im-server/v3/internal/push/offlinepush/fcm" - "github.com/openimsdk/open-im-server/v3/internal/push/offlinepush/getui" - "github.com/openimsdk/open-im-server/v3/internal/push/offlinepush/jpush" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" - "github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics" - "github.com/openimsdk/open-im-server/v3/pkg/msgprocessor" - "github.com/openimsdk/open-im-server/v3/pkg/rpccache" - "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" - "golang.org/x/sync/errgroup" - "google.golang.org/grpc" -) - -type Pusher struct { - config *config.GlobalConfig - database controller.PushDatabase - discov discoveryregistry.SvcDiscoveryRegistry - offlinePusher offlinepush.OfflinePusher - groupLocalCache *rpccache.GroupLocalCache - conversationLocalCache *rpccache.ConversationLocalCache - msgRpcClient *rpcclient.MessageRpcClient - conversationRpcClient *rpcclient.ConversationRpcClient - groupRpcClient *rpcclient.GroupRpcClient -} - -var errNoOfflinePusher = errors.New("no offlinePusher is configured") - -func NewPusher(config *config.GlobalConfig, discov discoveryregistry.SvcDiscoveryRegistry, offlinePusher offlinepush.OfflinePusher, database controller.PushDatabase, - groupLocalCache *rpccache.GroupLocalCache, conversationLocalCache *rpccache.ConversationLocalCache, - conversationRpcClient *rpcclient.ConversationRpcClient, groupRpcClient *rpcclient.GroupRpcClient, msgRpcClient *rpcclient.MessageRpcClient, -) *Pusher { - return &Pusher{ - config: config, - discov: discov, - database: database, - offlinePusher: offlinePusher, - groupLocalCache: groupLocalCache, - conversationLocalCache: conversationLocalCache, - msgRpcClient: msgRpcClient, - conversationRpcClient: conversationRpcClient, - groupRpcClient: groupRpcClient, - } -} - -func NewOfflinePusher(config *config.GlobalConfig, cache cache.MsgModel) offlinepush.OfflinePusher { - var offlinePusher offlinepush.OfflinePusher - switch config.Push.Enable { - case "getui": - offlinePusher = getui.NewClient(config, cache) - case "fcm": - offlinePusher = fcm.NewClient(config, cache) - case "jpush": - offlinePusher = jpush.NewClient(config) - default: - offlinePusher = dummy.NewClient() - } - return offlinePusher -} - -func (p *Pusher) DeleteMemberAndSetConversationSeq(ctx context.Context, groupID string, userIDs []string) error { - conevrsationID := msgprocessor.GetConversationIDBySessionType(constant.SuperGroupChatType, groupID) - maxSeq, err := p.msgRpcClient.GetConversationMaxSeq(ctx, conevrsationID) - if err != nil { - return err - } - return p.conversationRpcClient.SetConversationMaxSeq(ctx, userIDs, conevrsationID, maxSeq) -} - -func (p *Pusher) Push2User(ctx context.Context, userIDs []string, msg *sdkws.MsgData) error { - log.ZDebug(ctx, "Get msg from msg_transfer And push msg", "userIDs", userIDs, "msg", msg.String()) - if err := callbackOnlinePush(ctx, p.config, userIDs, msg); err != nil { - return err - } - // push - wsResults, err := p.GetConnsAndOnlinePush(ctx, msg, userIDs) - if err != nil { - return err - } - - isOfflinePush := utils.GetSwitchFromOptions(msg.Options, constant.IsOfflinePush) - log.ZDebug(ctx, "push_result", "ws push result", wsResults, "sendData", msg, "isOfflinePush", isOfflinePush, "push_to_userID", userIDs) - - if !isOfflinePush { - return nil - } - - if len(wsResults) == 0 { - return nil - } - onlinePushSuccUserIDSet := utils.SliceSet(utils.Filter(wsResults, func(e *msggateway.SingleMsgToUserResults) (string, bool) { - return e.UserID, e.OnlinePush && e.UserID != "" - })) - offlinePushUserIDList := utils.Filter(wsResults, func(e *msggateway.SingleMsgToUserResults) (string, bool) { - _, exist := onlinePushSuccUserIDSet[e.UserID] - return e.UserID, !exist && e.UserID != "" && e.UserID != msg.SendID - }) - - if len(offlinePushUserIDList) > 0 { - if err = callbackOfflinePush(ctx, p.config, offlinePushUserIDList, msg, &[]string{}); err != nil { - return err - } - err = p.offlinePushMsg(ctx, msg.SendID, msg, offlinePushUserIDList) - if err != nil { - return err - } - } - return nil -} - -func (p *Pusher) UnmarshalNotificationElem(bytes []byte, t any) error { - var notification sdkws.NotificationElem - if err := json.Unmarshal(bytes, ¬ification); err != nil { - return err - } - - return json.Unmarshal([]byte(notification.Detail), t) -} - -/* -k8s deployment,offline push group messages function. -*/ -func (p *Pusher) k8sOfflinePush2SuperGroup(ctx context.Context, groupID string, msg *sdkws.MsgData, wsResults []*msggateway.SingleMsgToUserResults) error { - - var needOfflinePushUserIDs []string - for _, v := range wsResults { - if !v.OnlinePush { - needOfflinePushUserIDs = append(needOfflinePushUserIDs, v.UserID) - } - } - if len(needOfflinePushUserIDs) > 0 { - var offlinePushUserIDs []string - err := callbackOfflinePush(ctx, p.config, needOfflinePushUserIDs, msg, &offlinePushUserIDs) - if err != nil { - return err - } - - if len(offlinePushUserIDs) > 0 { - needOfflinePushUserIDs = offlinePushUserIDs - } - if msg.ContentType != constant.SignalingNotification { - resp, err := p.conversationRpcClient.Client.GetConversationOfflinePushUserIDs( - ctx, - &conversation.GetConversationOfflinePushUserIDsReq{ConversationID: utils.GenGroupConversationID(groupID), UserIDs: needOfflinePushUserIDs}, - ) - if err != nil { - return err - } - if len(resp.UserIDs) > 0 { - err = p.offlinePushMsg(ctx, groupID, msg, resp.UserIDs) - if err != nil { - log.ZError(ctx, "offlinePushMsg failed", err, "groupID", groupID, "msg", msg) - return err - } - } - } - - } - return nil -} -func (p *Pusher) Push2SuperGroup(ctx context.Context, groupID string, msg *sdkws.MsgData) (err error) { - log.ZDebug(ctx, "Get super group msg from msg_transfer and push msg", "msg", msg.String(), "groupID", groupID) - var pushToUserIDs []string - if err = callbackBeforeSuperGroupOnlinePush(ctx, p.config, groupID, msg, &pushToUserIDs); err != nil { - return err - } - - if len(pushToUserIDs) == 0 { - pushToUserIDs, err = p.groupLocalCache.GetGroupMemberIDs(ctx, groupID) - if err != nil { - return err - } - - switch msg.ContentType { - case constant.MemberQuitNotification: - var tips sdkws.MemberQuitTips - if p.UnmarshalNotificationElem(msg.Content, &tips) != nil { - return err - } - defer func(groupID string, userIDs []string) { - if err = p.DeleteMemberAndSetConversationSeq(ctx, groupID, userIDs); err != nil { - log.ZError(ctx, "MemberQuitNotification DeleteMemberAndSetConversationSeq", err, "groupID", groupID, "userIDs", userIDs) - } - }(groupID, []string{tips.QuitUser.UserID}) - pushToUserIDs = append(pushToUserIDs, tips.QuitUser.UserID) - case constant.MemberKickedNotification: - var tips sdkws.MemberKickedTips - if p.UnmarshalNotificationElem(msg.Content, &tips) != nil { - return err - } - kickedUsers := utils.Slice(tips.KickedUserList, func(e *sdkws.GroupMemberFullInfo) string { return e.UserID }) - defer func(groupID string, userIDs []string) { - if err = p.DeleteMemberAndSetConversationSeq(ctx, groupID, userIDs); err != nil { - log.ZError(ctx, "MemberKickedNotification DeleteMemberAndSetConversationSeq", err, "groupID", groupID, "userIDs", userIDs) - } - }(groupID, kickedUsers) - pushToUserIDs = append(pushToUserIDs, kickedUsers...) - case constant.GroupDismissedNotification: - // Messages arrive first, notifications arrive later - if msgprocessor.IsNotification(msgprocessor.GetConversationIDByMsg(msg)) { - var tips sdkws.GroupDismissedTips - if p.UnmarshalNotificationElem(msg.Content, &tips) != nil { - return err - } - log.ZInfo(ctx, "GroupDismissedNotificationInfo****", "groupID", groupID, "num", len(pushToUserIDs), "list", pushToUserIDs) - if len(p.config.Manager.UserID) > 0 { - ctx = mcontext.WithOpUserIDContext(ctx, p.config.Manager.UserID[0]) - } - if len(p.config.Manager.UserID) == 0 && len(p.config.IMAdmin.UserID) > 0 { - ctx = mcontext.WithOpUserIDContext(ctx, p.config.IMAdmin.UserID[0]) - } - defer func(groupID string) { - if err = p.groupRpcClient.DismissGroup(ctx, groupID); err != nil { - log.ZError(ctx, "DismissGroup Notification clear members", err, "groupID", groupID) - } - }(groupID) - } - } - } - - wsResults, err := p.GetConnsAndOnlinePush(ctx, msg, pushToUserIDs) - if err != nil { - return err - } - - log.ZDebug(ctx, "get conn and online push success", "result", wsResults, "msg", msg) - isOfflinePush := utils.GetSwitchFromOptions(msg.Options, constant.IsOfflinePush) - if isOfflinePush && p.config.Envs.Discovery == "k8s" { - return p.k8sOfflinePush2SuperGroup(ctx, groupID, msg, wsResults) - } - if isOfflinePush && p.config.Envs.Discovery == "zookeeper" { - var ( - onlineSuccessUserIDs = []string{msg.SendID} - webAndPcBackgroundUserIDs []string - ) - - for _, v := range wsResults { - if v.OnlinePush && v.UserID != msg.SendID { - onlineSuccessUserIDs = append(onlineSuccessUserIDs, v.UserID) - } - - if v.OnlinePush { - continue - } - - if len(v.Resp) == 0 { - continue - } - - for _, singleResult := range v.Resp { - if singleResult.ResultCode != -2 { - continue - } - - isPC := constant.PlatformIDToName(int(singleResult.RecvPlatFormID)) == constant.TerminalPC - isWebID := singleResult.RecvPlatFormID == constant.WebPlatformID - - if isPC || isWebID { - webAndPcBackgroundUserIDs = append(webAndPcBackgroundUserIDs, v.UserID) - } - } - } - - needOfflinePushUserIDs := utils.DifferenceString(onlineSuccessUserIDs, pushToUserIDs) - - // Use offline push messaging - if len(needOfflinePushUserIDs) > 0 { - var offlinePushUserIDs []string - err = callbackOfflinePush(ctx, p.config, needOfflinePushUserIDs, msg, &offlinePushUserIDs) - if err != nil { - return err - } - - if len(offlinePushUserIDs) > 0 { - needOfflinePushUserIDs = offlinePushUserIDs - } - if msg.ContentType != constant.SignalingNotification { - resp, err := p.conversationRpcClient.Client.GetConversationOfflinePushUserIDs( - ctx, - &conversation.GetConversationOfflinePushUserIDsReq{ConversationID: utils.GenGroupConversationID(groupID), UserIDs: needOfflinePushUserIDs}, - ) - if err != nil { - return err - } - if len(resp.UserIDs) > 0 { - err = p.offlinePushMsg(ctx, groupID, msg, resp.UserIDs) - if err != nil { - log.ZError(ctx, "offlinePushMsg failed", err, "groupID", groupID, "msg", msg) - return err - } - if _, err := p.GetConnsAndOnlinePush(ctx, msg, utils.IntersectString(resp.UserIDs, webAndPcBackgroundUserIDs)); err != nil { - log.ZError(ctx, "offlinePushMsg failed", err, "groupID", groupID, "msg", msg, "userIDs", utils.IntersectString(needOfflinePushUserIDs, webAndPcBackgroundUserIDs)) - return err - } - } - } - - } - } - return nil -} - -func (p *Pusher) k8sOnlinePush(ctx context.Context, msg *sdkws.MsgData, pushToUserIDs []string) (wsResults []*msggateway.SingleMsgToUserResults, err error) { - var usersHost = make(map[string][]string) - for _, v := range pushToUserIDs { - tHost, err := p.discov.GetUserIdHashGatewayHost(ctx, v) - if err != nil { - log.ZError(ctx, "get msggateway hash error", err) - return nil, err - } - tUsers, tbl := usersHost[tHost] - if tbl { - tUsers = append(tUsers, v) - usersHost[tHost] = tUsers - } else { - usersHost[tHost] = []string{v} - } - } - log.ZDebug(ctx, "genUsers send hosts struct:", "usersHost", usersHost) - var usersConns = make(map[*grpc.ClientConn][]string) - for host, userIds := range usersHost { - tconn, _ := p.discov.GetConn(ctx, host) - usersConns[tconn] = userIds - } - var ( - mu sync.Mutex - wg = errgroup.Group{} - maxWorkers = p.config.Push.MaxConcurrentWorkers - ) - if maxWorkers < 3 { - maxWorkers = 3 - } - wg.SetLimit(maxWorkers) - for conn, userIds := range usersConns { - tcon := conn - tuserIds := userIds - wg.Go(func() error { - input := &msggateway.OnlineBatchPushOneMsgReq{MsgData: msg, PushToUserIDs: tuserIds} - msgClient := msggateway.NewMsgGatewayClient(tcon) - reply, err := msgClient.SuperGroupOnlineBatchPushOneMsg(ctx, input) - if err != nil { - return nil - } - log.ZDebug(ctx, "push result", "reply", reply) - if reply != nil && reply.SinglePushResult != nil { - mu.Lock() - wsResults = append(wsResults, reply.SinglePushResult...) - mu.Unlock() - } - return nil - }) - } - _ = wg.Wait() - return wsResults, nil -} -func (p *Pusher) GetConnsAndOnlinePush(ctx context.Context, msg *sdkws.MsgData, pushToUserIDs []string) (wsResults []*msggateway.SingleMsgToUserResults, err error) { - if p.config.Envs.Discovery == "k8s" { - return p.k8sOnlinePush(ctx, msg, pushToUserIDs) - } - conns, err := p.discov.GetConns(ctx, p.config.RpcRegisterName.OpenImMessageGatewayName) - log.ZDebug(ctx, "get gateway conn", "conn length", len(conns)) - if err != nil { - return nil, err - } - - var ( - mu sync.Mutex - wg = errgroup.Group{} - input = &msggateway.OnlineBatchPushOneMsgReq{MsgData: msg, PushToUserIDs: pushToUserIDs} - maxWorkers = p.config.Push.MaxConcurrentWorkers - ) - - if maxWorkers < 3 { - maxWorkers = 3 - } - - wg.SetLimit(maxWorkers) - - // Online push message - for _, conn := range conns { - conn := conn // loop var safe - wg.Go(func() error { - msgClient := msggateway.NewMsgGatewayClient(conn) - reply, err := msgClient.SuperGroupOnlineBatchPushOneMsg(ctx, input) - if err != nil { - return nil - } - - log.ZDebug(ctx, "push result", "reply", reply) - if reply != nil && reply.SinglePushResult != nil { - mu.Lock() - wsResults = append(wsResults, reply.SinglePushResult...) - mu.Unlock() - } - - return nil - }) - } - - _ = wg.Wait() - - // always return nil - return wsResults, nil -} - -func (p *Pusher) offlinePushMsg(ctx context.Context, conversationID string, msg *sdkws.MsgData, offlinePushUserIDs []string) error { - title, content, opts, err := p.getOfflinePushInfos(conversationID, msg) - if err != nil { - return err - } - err = p.offlinePusher.Push(ctx, offlinePushUserIDs, title, content, opts) - if err != nil { - prommetrics.MsgOfflinePushFailedCounter.Inc() - return err - } - return nil -} - -func (p *Pusher) GetOfflinePushOpts(msg *sdkws.MsgData) (opts *offlinepush.Opts, err error) { - opts = &offlinepush.Opts{Signal: &offlinepush.Signal{}} - // if msg.ContentType > constant.SignalingNotificationBegin && msg.ContentType < constant.SignalingNotificationEnd { - // req := &sdkws.SignalReq{} - // if err := proto.Unmarshal(msg.Content, req); err != nil { - // return nil, utils.Wrap(err, "") - // } - // switch req.Payload.(type) { - // case *sdkws.SignalReq_Invite, *sdkws.SignalReq_InviteInGroup: - // opts.Signal = &offlinepush.Signal{ClientMsgID: msg.ClientMsgID} - // } - // } - if msg.OfflinePushInfo != nil { - opts.IOSBadgeCount = msg.OfflinePushInfo.IOSBadgeCount - opts.IOSPushSound = msg.OfflinePushInfo.IOSPushSound - opts.Ex = msg.OfflinePushInfo.Ex - } - return opts, nil -} - -func (p *Pusher) getOfflinePushInfos(conversationID string, msg *sdkws.MsgData) (title, content string, opts *offlinepush.Opts, err error) { - if p.offlinePusher == nil { - err = errNoOfflinePusher - return - } - - type atContent struct { - Text string `json:"text"` - AtUserList []string `json:"atUserList"` - IsAtSelf bool `json:"isAtSelf"` - } - - opts, err = p.GetOfflinePushOpts(msg) - if err != nil { - return - } - - if msg.OfflinePushInfo != nil { - title = msg.OfflinePushInfo.Title - content = msg.OfflinePushInfo.Desc - } - if title == "" { - switch msg.ContentType { - case constant.Text: - fallthrough - case constant.Picture: - fallthrough - case constant.Voice: - fallthrough - case constant.Video: - fallthrough - case constant.File: - title = constant.ContentType2PushContent[int64(msg.ContentType)] - case constant.AtText: - ac := atContent{} - _ = utils.JsonStringToStruct(string(msg.Content), &ac) - if utils.IsContain(conversationID, ac.AtUserList) { - title = constant.ContentType2PushContent[constant.AtText] + constant.ContentType2PushContent[constant.Common] - } else { - title = constant.ContentType2PushContent[constant.GroupMsg] - } - case constant.SignalingNotification: - title = constant.ContentType2PushContent[constant.SignalMsg] - default: - title = constant.ContentType2PushContent[constant.Common] - } - } - if content == "" { - content = title - } - return -} diff --git a/internal/push/tools.go b/internal/push/tools.go deleted file mode 100644 index 760c8c95bb..0000000000 --- a/internal/push/tools.go +++ /dev/null @@ -1,31 +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 push - -import ( - "github.com/OpenIMSDK/protocol/constant" - "github.com/OpenIMSDK/protocol/sdkws" - "google.golang.org/protobuf/proto" -) - -func GetContent(msg *sdkws.MsgData) string { - if msg.ContentType >= constant.NotificationBegin && msg.ContentType <= constant.NotificationEnd { - var tips sdkws.TipsComm - _ = proto.Unmarshal(msg.Content, &tips) - content := tips.JsonDetail - return content - } - return string(msg.Content) -} diff --git a/internal/rpc/auth/auth.go b/internal/rpc/auth/auth.go index eb1e2f68a0..c6d236b21b 100644 --- a/internal/rpc/auth/auth.go +++ b/internal/rpc/auth/auth.go @@ -16,45 +16,54 @@ package auth import ( "context" + "github.com/openimsdk/open-im-server/v3/pkg/common/config" + "github.com/openimsdk/tools/db/redisutil" + "github.com/redis/go-redis/v9" - pbauth "github.com/OpenIMSDK/protocol/auth" - "github.com/OpenIMSDK/protocol/constant" - "github.com/OpenIMSDK/protocol/msggateway" - "github.com/OpenIMSDK/tools/discoveryregistry" - "github.com/OpenIMSDK/tools/errs" - "github.com/OpenIMSDK/tools/log" - "github.com/OpenIMSDK/tools/mcontext" - "github.com/OpenIMSDK/tools/tokenverify" "github.com/openimsdk/open-im-server/v3/pkg/authverify" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" "github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics" + "github.com/openimsdk/open-im-server/v3/pkg/common/servererrs" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" + pbauth "github.com/openimsdk/protocol/auth" + "github.com/openimsdk/protocol/constant" + "github.com/openimsdk/protocol/msggateway" + "github.com/openimsdk/tools/discovery" + "github.com/openimsdk/tools/errs" + "github.com/openimsdk/tools/log" + "github.com/openimsdk/tools/mcontext" + "github.com/openimsdk/tools/tokenverify" "google.golang.org/grpc" ) type authServer struct { authDatabase controller.AuthDatabase userRpcClient *rpcclient.UserRpcClient - RegisterCenter discoveryregistry.SvcDiscoveryRegistry - config *config.GlobalConfig + RegisterCenter discovery.SvcDiscoveryRegistry + config *Config +} + +type Config struct { + RpcConfig config.Auth + RedisConfig config.Redis + ZookeeperConfig config.ZooKeeper + Share config.Share } -func Start(config *config.GlobalConfig, client discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) error { - rdb, err := cache.NewRedis(config) +func Start(ctx context.Context, config *Config, client discovery.SvcDiscoveryRegistry, server *grpc.Server) error { + rdb, err := redisutil.NewRedisClient(ctx, config.RedisConfig.Build()) if err != nil { return err } - userRpcClient := rpcclient.NewUserRpcClient(client, config) + userRpcClient := rpcclient.NewUserRpcClient(client, config.Share.RpcRegisterName.User, config.Share.IMAdminUserID) pbauth.RegisterAuthServer(server, &authServer{ userRpcClient: &userRpcClient, RegisterCenter: client, authDatabase: controller.NewAuthDatabase( - cache.NewMsgCacheModel(rdb, config), - config.Secret, - config.TokenPolicy.Expire, - config, + cache.NewTokenCacheModel(rdb), + config.Share.Secret, + config.RpcConfig.TokenPolicy.Expire, ), config: config, }) @@ -63,8 +72,8 @@ func Start(config *config.GlobalConfig, client discoveryregistry.SvcDiscoveryReg func (s *authServer) UserToken(ctx context.Context, req *pbauth.UserTokenReq) (*pbauth.UserTokenResp, error) { resp := pbauth.UserTokenResp{} - if req.Secret != s.config.Secret { - return nil, errs.ErrNoPermission.Wrap("secret invalid") + if req.Secret != s.config.Share.Secret { + return nil, errs.ErrNoPermission.WrapMsg("secret invalid") } if _, err := s.userRpcClient.GetUserInfo(ctx, req.UserID); err != nil { return nil, err @@ -75,20 +84,19 @@ func (s *authServer) UserToken(ctx context.Context, req *pbauth.UserTokenReq) (* } prommetrics.UserLoginCounter.Inc() resp.Token = token - resp.ExpireTimeSeconds = s.config.TokenPolicy.Expire * 24 * 60 * 60 + resp.ExpireTimeSeconds = s.config.RpcConfig.TokenPolicy.Expire * 24 * 60 * 60 return &resp, nil } func (s *authServer) GetUserToken(ctx context.Context, req *pbauth.GetUserTokenReq) (*pbauth.GetUserTokenResp, error) { - if err := authverify.CheckAdmin(ctx, s.config); err != nil { + if err := authverify.CheckAdmin(ctx, s.config.Share.IMAdminUserID); err != nil { return nil, err } resp := pbauth.GetUserTokenResp{} - if authverify.IsManagerUserID(req.UserID, s.config) { - return nil, errs.ErrNoPermission.Wrap("don't get Admin token") + if authverify.IsManagerUserID(req.UserID, s.config.Share.IMAdminUserID) { + return nil, errs.ErrNoPermission.WrapMsg("don't get Admin token") } - if _, err := s.userRpcClient.GetUserInfo(ctx, req.UserID); err != nil { return nil, err } @@ -97,12 +105,12 @@ func (s *authServer) GetUserToken(ctx context.Context, req *pbauth.GetUserTokenR return nil, err } resp.Token = token - resp.ExpireTimeSeconds = s.config.TokenPolicy.Expire * 24 * 60 * 60 + resp.ExpireTimeSeconds = s.config.RpcConfig.TokenPolicy.Expire * 24 * 60 * 60 return &resp, nil } func (s *authServer) parseToken(ctx context.Context, tokensString string) (claims *tokenverify.Claims, err error) { - claims, err = tokenverify.GetClaimFromToken(tokensString, authverify.Secret(s.config.Secret)) + claims, err = tokenverify.GetClaimFromToken(tokensString, authverify.Secret(s.config.Share.Secret)) if err != nil { return nil, errs.Wrap(err) } @@ -111,19 +119,19 @@ func (s *authServer) parseToken(ctx context.Context, tokensString string) (claim return nil, err } if len(m) == 0 { - return nil, errs.ErrTokenNotExist.Wrap() + return nil, servererrs.ErrTokenNotExist.Wrap() } if v, ok := m[tokensString]; ok { switch v { case constant.NormalToken: return claims, nil case constant.KickedToken: - return nil, errs.ErrTokenKicked.Wrap() + return nil, servererrs.ErrTokenKicked.Wrap() default: return nil, errs.Wrap(errs.ErrTokenUnknown) } } - return nil, errs.ErrTokenNotExist.Wrap() + return nil, servererrs.ErrTokenNotExist.Wrap() } func (s *authServer) ParseToken( @@ -136,13 +144,13 @@ func (s *authServer) ParseToken( return nil, err } resp.UserID = claims.UserID - resp.Platform = constant.PlatformIDToName(claims.PlatformID) + resp.PlatformID = int32(claims.PlatformID) resp.ExpireTimeSeconds = claims.ExpiresAt.Unix() return resp, nil } func (s *authServer) ForceLogout(ctx context.Context, req *pbauth.ForceLogoutReq) (*pbauth.ForceLogoutResp, error) { - if err := authverify.CheckAdmin(ctx, s.config); err != nil { + if err := authverify.CheckAdmin(ctx, s.config.Share.IMAdminUserID); err != nil { return nil, err } if err := s.forceKickOff(ctx, req.UserID, req.PlatformID, mcontext.GetOperationID(ctx)); err != nil { @@ -152,7 +160,7 @@ func (s *authServer) ForceLogout(ctx context.Context, req *pbauth.ForceLogoutReq } func (s *authServer) forceKickOff(ctx context.Context, userID string, platformID int32, operationID string) error { - conns, err := s.RegisterCenter.GetConns(ctx, s.config.RpcRegisterName.OpenImMessageGatewayName) + conns, err := s.RegisterCenter.GetConns(ctx, s.config.Share.RpcRegisterName.MessageGateway) if err != nil { return err } @@ -169,3 +177,27 @@ func (s *authServer) forceKickOff(ctx context.Context, userID string, platformID } return nil } +func (s *authServer) InvalidateToken(ctx context.Context, req *pbauth.InvalidateTokenReq) (*pbauth.InvalidateTokenResp, error) { + m, err := s.authDatabase.GetTokensWithoutError(ctx, req.UserID, int(req.PlatformID)) + if err != nil && err != redis.Nil { + return nil, err + } + if m == nil { + return nil, errs.New("token map is empty").Wrap() + } + log.ZDebug(ctx, "get token from redis", "userID", req.UserID, "platformID", + req.PlatformID, "tokenMap", m) + + for k := range m { + if k != req.GetPreservedToken() { + m[k] = constant.KickedToken + } + } + log.ZDebug(ctx, "set token map is ", "token map", m, "userID", + req.UserID, "token", req.GetPreservedToken()) + err = s.authDatabase.SetTokenMapByUidPid(ctx, req.UserID, int(req.PlatformID), m) + if err != nil { + return nil, err + } + return &pbauth.InvalidateTokenResp{}, nil +} diff --git a/internal/rpc/conversation/conversaion.go b/internal/rpc/conversation/conversaion.go index e78e4a18f0..1bf612923c 100644 --- a/internal/rpc/conversation/conversaion.go +++ b/internal/rpc/conversation/conversaion.go @@ -16,26 +16,25 @@ package conversation import ( "context" - "errors" + "github.com/openimsdk/open-im-server/v3/pkg/common/config" + "github.com/openimsdk/tools/db/redisutil" "sort" - "github.com/OpenIMSDK/protocol/constant" - pbconversation "github.com/OpenIMSDK/protocol/conversation" - "github.com/OpenIMSDK/protocol/sdkws" - "github.com/OpenIMSDK/tools/discoveryregistry" - "github.com/OpenIMSDK/tools/errs" - "github.com/OpenIMSDK/tools/log" - "github.com/OpenIMSDK/tools/tx" - "github.com/OpenIMSDK/tools/utils" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/convert" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" "github.com/openimsdk/open-im-server/v3/pkg/common/db/mgo" tablerelation "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/unrelation" + "github.com/openimsdk/open-im-server/v3/pkg/common/servererrs" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" - "github.com/openimsdk/open-im-server/v3/pkg/rpcclient/notification" + "github.com/openimsdk/protocol/constant" + pbconversation "github.com/openimsdk/protocol/conversation" + "github.com/openimsdk/protocol/sdkws" + "github.com/openimsdk/tools/db/mongoutil" + "github.com/openimsdk/tools/discovery" + "github.com/openimsdk/tools/errs" + "github.com/openimsdk/tools/log" + "github.com/openimsdk/tools/utils/datautil" "google.golang.org/grpc" ) @@ -44,33 +43,43 @@ type conversationServer struct { user *rpcclient.UserRpcClient groupRpcClient *rpcclient.GroupRpcClient conversationDatabase controller.ConversationDatabase - conversationNotificationSender *notification.ConversationNotificationSender - config *config.GlobalConfig + conversationNotificationSender *ConversationNotificationSender + config *Config +} + +type Config struct { + RpcConfig config.Conversation + RedisConfig config.Redis + MongodbConfig config.Mongo + ZookeeperConfig config.ZooKeeper + NotificationConfig config.Notification + Share config.Share + LocalCacheConfig config.LocalCache } -func Start(config *config.GlobalConfig, client discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) error { - rdb, err := cache.NewRedis(config) +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 } - mongo, err := unrelation.NewMongo(config) + rdb, err := redisutil.NewRedisClient(ctx, config.RedisConfig.Build()) if err != nil { return err } - conversationDB, err := mgo.NewConversationMongo(mongo.GetDatabase(config.Mongo.Database)) + conversationDB, err := mgo.NewConversationMongo(mgocli.GetDB()) if err != nil { return err } - groupRpcClient := rpcclient.NewGroupRpcClient(client, config) - msgRpcClient := rpcclient.NewMessageRpcClient(client, config) - userRpcClient := rpcclient.NewUserRpcClient(client, config) + groupRpcClient := rpcclient.NewGroupRpcClient(client, config.Share.RpcRegisterName.Group) + msgRpcClient := rpcclient.NewMessageRpcClient(client, config.Share.RpcRegisterName.Msg) + userRpcClient := rpcclient.NewUserRpcClient(client, config.Share.RpcRegisterName.User, config.Share.IMAdminUserID) + cache.InitLocalCache(&config.LocalCacheConfig) pbconversation.RegisterConversationServer(server, &conversationServer{ msgRpcClient: &msgRpcClient, user: &userRpcClient, - conversationNotificationSender: notification.NewConversationNotificationSender(config, &msgRpcClient), + conversationNotificationSender: NewConversationNotificationSender(&config.NotificationConfig, &msgRpcClient), groupRpcClient: &groupRpcClient, - conversationDatabase: controller.NewConversationDatabase(conversationDB, cache.NewConversationRedis(rdb, cache.GetDefaultOpt(), conversationDB), tx.NewMongo(mongo.GetClient())), - config: config, + conversationDatabase: controller.NewConversationDatabase(conversationDB, cache.NewConversationRedis(rdb, &config.LocalCacheConfig, cache.GetDefaultOpt(), conversationDB), mgocli.GetTx()), }) return nil } @@ -81,7 +90,7 @@ func (c *conversationServer) GetConversation(ctx context.Context, req *pbconvers return nil, err } if len(conversations) < 1 { - return nil, errs.ErrRecordNotFound.Wrap("conversation not found") + return nil, errs.ErrRecordNotFound.WrapMsg("conversation not found") } resp := &pbconversation.GetConversationResp{Conversation: &pbconversation.Conversation{}} resp.Conversation = convert.ConversationDB2Pb(conversations[0]) @@ -158,7 +167,7 @@ func (c *conversationServer) GetSortedConversationList(ctx context.Context, req c.conversationSort(conversation_isPinTime, resp, conversation_unreadCount, conversationMsg) c.conversationSort(conversation_notPinTime, resp, conversation_unreadCount, conversationMsg) - resp.ConversationElems = utils.Paginate(resp.ConversationElems, int(req.Pagination.GetPageNumber()), int(req.Pagination.GetShowNumber())) + resp.ConversationElems = datautil.Paginate(resp.ConversationElems, int(req.Pagination.GetPageNumber()), int(req.Pagination.GetShowNumber())) return resp, nil } @@ -184,32 +193,30 @@ func (c *conversationServer) GetConversations(ctx context.Context, req *pbconver func (c *conversationServer) SetConversation(ctx context.Context, req *pbconversation.SetConversationReq) (*pbconversation.SetConversationResp, error) { var conversation tablerelation.ConversationModel - if err := utils.CopyStructFields(&conversation, req.Conversation); err != nil { + if err := datautil.CopyStructFields(&conversation, req.Conversation); err != nil { return nil, err } err := c.conversationDatabase.SetUserConversations(ctx, req.Conversation.OwnerUserID, []*tablerelation.ConversationModel{&conversation}) if err != nil { return nil, err } - _ = c.conversationNotificationSender.ConversationChangeNotification(ctx, req.Conversation.OwnerUserID, []string{req.Conversation.ConversationID}) + c.conversationNotificationSender.ConversationChangeNotification(ctx, req.Conversation.OwnerUserID, []string{req.Conversation.ConversationID}) resp := &pbconversation.SetConversationResp{} return resp, nil } // nolint -func (c *conversationServer) SetConversations(ctx context.Context, - req *pbconversation.SetConversationsReq, -) (*pbconversation.SetConversationsResp, error) { +func (c *conversationServer) SetConversations(ctx context.Context, req *pbconversation.SetConversationsReq) (*pbconversation.SetConversationsResp, error) { if req.Conversation == nil { - return nil, errs.ErrArgs.Wrap("conversation must not be nil") + return nil, errs.ErrArgs.WrapMsg("conversation must not be nil") } - if req.Conversation.ConversationType == constant.GroupChatType { + if req.Conversation.ConversationType == constant.WriteGroupChatType { groupInfo, err := c.groupRpcClient.GetGroupInfo(ctx, req.Conversation.GroupID) if err != nil { return nil, err } if groupInfo.Status == constant.GroupStatusDismissed { - return nil, errs.ErrDismissedAlready.Wrap("group dismissed") + return nil, servererrs.ErrDismissedAlready.WrapMsg("group dismissed") } } var unequal int @@ -220,7 +227,7 @@ func (c *conversationServer) SetConversations(ctx context.Context, return nil, err } if len(cs) == 0 { - return nil, errs.ErrRecordNotFound.Wrap("conversation not found") + return nil, errs.ErrRecordNotFound.WrapMsg("conversation not found") } conv = *cs[0] } @@ -272,7 +279,7 @@ func (c *conversationServer) SetConversations(ctx context.Context, unequal++ } } - if req.Conversation.IsPrivateChat != nil && req.Conversation.ConversationType != constant.SuperGroupChatType { + if req.Conversation.IsPrivateChat != nil && req.Conversation.ConversationType != constant.ReadGroupChatType { var conversations []*tablerelation.ConversationModel for _, ownerUserID := range req.UserIDs { conversation2 := conversation @@ -280,45 +287,39 @@ func (c *conversationServer) SetConversations(ctx context.Context, conversation2.IsPrivateChat = req.Conversation.IsPrivateChat.Value conversations = append(conversations, &conversation2) } + if err := c.conversationDatabase.SyncPeerUserPrivateConversationTx(ctx, conversations); err != nil { return nil, err } for _, userID := range req.UserIDs { - err := c.conversationNotificationSender.ConversationSetPrivateNotification(ctx, userID, req.Conversation.UserID, + c.conversationNotificationSender.ConversationSetPrivateNotification(ctx, userID, req.Conversation.UserID, req.Conversation.IsPrivateChat.Value, req.Conversation.ConversationID) - if err != nil { - log.ZWarn(ctx, "send conversation set private notification failed", err, - "userID", userID, "conversationID", req.Conversation.ConversationID) - - continue - } } } + if req.Conversation.BurnDuration != nil { m["burn_duration"] = req.Conversation.BurnDuration.Value if req.Conversation.BurnDuration.Value != conv.BurnDuration { unequal++ } } + if err := c.conversationDatabase.SetUsersConversationFieldTx(ctx, req.UserIDs, &conversation, m); err != nil { return nil, err } + if unequal > 0 { for _, v := range req.UserIDs { c.conversationNotificationSender.ConversationChangeNotification(ctx, v, []string{req.Conversation.ConversationID}) } } + return &pbconversation.SetConversationsResp{}, nil } // Get user IDs with "Do Not Disturb" enabled in super large groups. func (c *conversationServer) GetRecvMsgNotNotifyUserIDs(ctx context.Context, req *pbconversation.GetRecvMsgNotNotifyUserIDsReq) (*pbconversation.GetRecvMsgNotNotifyUserIDsResp, error) { - //userIDs, err := c.conversationDatabase.FindRecvMsgNotNotifyUserIDs(ctx, req.GroupID) - //if err != nil { - // return nil, err - //} - //return &pbconversation.GetRecvMsgNotNotifyUserIDsResp{UserIDs: userIDs}, nil - return nil, errors.New("deprecated") + return nil, errs.New("deprecated") } // create conversation without notification for msg redis transfer. @@ -402,12 +403,9 @@ func (c *conversationServer) GetConversationsByConversationID( return &pbconversation.GetConversationsByConversationIDResp{Conversations: convert.ConversationsDB2Pb(conversations)}, nil } -func (c *conversationServer) GetConversationOfflinePushUserIDs( - ctx context.Context, - req *pbconversation.GetConversationOfflinePushUserIDsReq, -) (*pbconversation.GetConversationOfflinePushUserIDsResp, error) { +func (c *conversationServer) GetConversationOfflinePushUserIDs(ctx context.Context, req *pbconversation.GetConversationOfflinePushUserIDsReq) (*pbconversation.GetConversationOfflinePushUserIDsResp, error) { if req.ConversationID == "" { - return nil, errs.ErrArgs.Wrap("conversationID is empty") + return nil, errs.ErrArgs.WrapMsg("conversationID is empty") } if len(req.UserIDs) == 0 { return &pbconversation.GetConversationOfflinePushUserIDsResp{}, nil @@ -426,21 +424,16 @@ func (c *conversationServer) GetConversationOfflinePushUserIDs( for _, userID := range userIDs { delete(userIDSet, userID) } - return &pbconversation.GetConversationOfflinePushUserIDsResp{UserIDs: utils.Keys(userIDSet)}, nil + return &pbconversation.GetConversationOfflinePushUserIDsResp{UserIDs: datautil.Keys(userIDSet)}, nil } -func (c *conversationServer) conversationSort( - conversations map[int64]string, - resp *pbconversation.GetSortedConversationListResp, - conversation_unreadCount map[string]int64, - conversationMsg map[string]*pbconversation.ConversationElem, -) { +func (c *conversationServer) conversationSort(conversations map[int64]string, resp *pbconversation.GetSortedConversationListResp, conversation_unreadCount map[string]int64, conversationMsg map[string]*pbconversation.ConversationElem) { keys := []int64{} for key := range conversations { keys = append(keys, key) } - sort.Slice(keys[:], func(i, j int) bool { + sort.Slice(keys, func(i, j int) bool { return keys[i] > keys[j] }) index := 0 @@ -474,7 +467,7 @@ func (c *conversationServer) getConversationInfo( sendIDs = append(sendIDs, chatLog.RecvID) } sendIDs = append(sendIDs, chatLog.SendID) - case constant.GroupChatType, constant.SuperGroupChatType: + case constant.WriteGroupChatType, constant.ReadGroupChatType: groupIDs = append(groupIDs, chatLog.GroupID) sendIDs = append(sendIDs, chatLog.SendID) } @@ -500,7 +493,7 @@ func (c *conversationServer) getConversationInfo( for conversationID, chatLog := range chatLogs { pbchatLog := &pbconversation.ConversationElem{} msgInfo := &pbconversation.MsgInfo{} - if err := utils.CopyStructFields(msgInfo, chatLog); err != nil { + if err := datautil.CopyStructFields(msgInfo, chatLog); err != nil { return nil, err } switch chatLog.SessionType { @@ -516,7 +509,7 @@ func (c *conversationServer) getConversationInfo( msgInfo.FaceURL = send.FaceURL msgInfo.SenderName = send.Nickname } - case constant.GroupChatType, constant.SuperGroupChatType: + case constant.WriteGroupChatType, constant.ReadGroupChatType: msgInfo.GroupID = chatLog.GroupID if group, ok := groupMap[chatLog.GroupID]; ok { msgInfo.GroupName = group.GroupName @@ -536,10 +529,7 @@ func (c *conversationServer) getConversationInfo( return conversationMsg, nil } -func (c *conversationServer) GetConversationNotReceiveMessageUserIDs( - ctx context.Context, - req *pbconversation.GetConversationNotReceiveMessageUserIDsReq, -) (*pbconversation.GetConversationNotReceiveMessageUserIDsResp, error) { +func (c *conversationServer) GetConversationNotReceiveMessageUserIDs(ctx context.Context, req *pbconversation.GetConversationNotReceiveMessageUserIDsReq) (*pbconversation.GetConversationNotReceiveMessageUserIDsResp, error) { userIDs, err := c.conversationDatabase.GetConversationNotReceiveMessageUserIDs(ctx, req.ConversationID) if err != nil { return nil, err diff --git a/pkg/rpcclient/notification/conversation.go b/internal/rpc/conversation/notification.go similarity index 74% rename from pkg/rpcclient/notification/conversation.go rename to internal/rpc/conversation/notification.go index 1544d6a1f7..994e1d57ae 100644 --- a/pkg/rpcclient/notification/conversation.go +++ b/internal/rpc/conversation/notification.go @@ -12,29 +12,29 @@ // See the License for the specific language governing permissions and // limitations under the License. -package notification +package conversation import ( "context" - "github.com/OpenIMSDK/protocol/constant" - "github.com/OpenIMSDK/protocol/sdkws" "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" + "github.com/openimsdk/protocol/constant" + "github.com/openimsdk/protocol/sdkws" ) type ConversationNotificationSender struct { *rpcclient.NotificationSender } -func NewConversationNotificationSender(config *config.GlobalConfig, msgRpcClient *rpcclient.MessageRpcClient) *ConversationNotificationSender { - return &ConversationNotificationSender{rpcclient.NewNotificationSender(config, rpcclient.WithRpcClient(msgRpcClient))} +func NewConversationNotificationSender(conf *config.Notification, msgRpcClient *rpcclient.MessageRpcClient) *ConversationNotificationSender { + return &ConversationNotificationSender{rpcclient.NewNotificationSender(conf, rpcclient.WithRpcClient(msgRpcClient))} } // SetPrivate invote. func (c *ConversationNotificationSender) ConversationSetPrivateNotification(ctx context.Context, sendID, recvID string, isPrivateChat bool, conversationID string, -) error { +) { tips := &sdkws.ConversationSetPrivateTips{ RecvID: recvID, SendID: sendID, @@ -42,23 +42,23 @@ func (c *ConversationNotificationSender) ConversationSetPrivateNotification(ctx ConversationID: conversationID, } - return c.Notification(ctx, sendID, recvID, constant.ConversationPrivateChatNotification, tips) + c.Notification(ctx, sendID, recvID, constant.ConversationPrivateChatNotification, tips) } -func (c *ConversationNotificationSender) ConversationChangeNotification(ctx context.Context, userID string, conversationIDs []string) error { +func (c *ConversationNotificationSender) ConversationChangeNotification(ctx context.Context, userID string, conversationIDs []string) { tips := &sdkws.ConversationUpdateTips{ UserID: userID, ConversationIDList: conversationIDs, } - return c.Notification(ctx, userID, userID, constant.ConversationChangeNotification, tips) + c.Notification(ctx, userID, userID, constant.ConversationChangeNotification, tips) } func (c *ConversationNotificationSender) ConversationUnreadChangeNotification( ctx context.Context, userID, conversationID string, unreadCountTime, hasReadSeq int64, -) error { +) { tips := &sdkws.ConversationHasReadTips{ UserID: userID, ConversationID: conversationID, @@ -66,5 +66,5 @@ func (c *ConversationNotificationSender) ConversationUnreadChangeNotification( UnreadCountTime: unreadCountTime, } - return c.Notification(ctx, userID, userID, constant.ConversationUnreadNotification, tips) + c.Notification(ctx, userID, userID, constant.ConversationUnreadNotification, tips) } diff --git a/internal/rpc/friend/black.go b/internal/rpc/friend/black.go index 4e130360cd..1f52286f34 100644 --- a/internal/rpc/friend/black.go +++ b/internal/rpc/friend/black.go @@ -18,11 +18,11 @@ import ( "context" "time" - pbfriend "github.com/OpenIMSDK/protocol/friend" - "github.com/OpenIMSDK/tools/mcontext" "github.com/openimsdk/open-im-server/v3/pkg/authverify" "github.com/openimsdk/open-im-server/v3/pkg/common/convert" "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" + pbfriend "github.com/openimsdk/protocol/friend" + "github.com/openimsdk/tools/mcontext" ) func (s *friendServer) GetPaginationBlacks(ctx context.Context, req *pbfriend.GetPaginationBlacksReq) (resp *pbfriend.GetPaginationBlacksResp, err error) { @@ -57,15 +57,18 @@ func (s *friendServer) RemoveBlack(ctx context.Context, req *pbfriend.RemoveBlac if err := s.userRpcClient.Access(ctx, req.OwnerUserID); err != nil { return nil, err } + if err := s.blackDatabase.Delete(ctx, []*relation.BlackModel{{OwnerUserID: req.OwnerUserID, BlockUserID: req.BlackUserID}}); err != nil { return nil, err } + s.notificationSender.BlackDeletedNotification(ctx, req) + return &pbfriend.RemoveBlackResp{}, nil } func (s *friendServer) AddBlack(ctx context.Context, req *pbfriend.AddBlackReq) (*pbfriend.AddBlackResp, error) { - if err := authverify.CheckAccessV3(ctx, req.OwnerUserID, s.config); err != nil { + if err := authverify.CheckAccessV3(ctx, req.OwnerUserID, s.config.Share.IMAdminUserID); err != nil { return nil, err } _, err := s.userRpcClient.GetUsersInfo(ctx, []string{req.OwnerUserID, req.BlackUserID}) @@ -83,10 +86,6 @@ func (s *friendServer) AddBlack(ctx context.Context, req *pbfriend.AddBlackReq) if err := s.blackDatabase.Create(ctx, []*relation.BlackModel{&black}); err != nil { return nil, err } - - if err := s.notificationSender.BlackAddedNotification(ctx, req); err != nil { - return nil, err - } - + s.notificationSender.BlackAddedNotification(ctx, req) return &pbfriend.AddBlackResp{}, nil } diff --git a/internal/rpc/friend/callback.go b/internal/rpc/friend/callback.go index 78d4fc926f..0610cdb78a 100644 --- a/internal/rpc/friend/callback.go +++ b/internal/rpc/friend/callback.go @@ -16,85 +16,41 @@ package friend import ( "context" + "github.com/openimsdk/open-im-server/v3/pkg/common/webhook" - pbfriend "github.com/OpenIMSDK/protocol/friend" - "github.com/OpenIMSDK/tools/utils" cbapi "github.com/openimsdk/open-im-server/v3/pkg/callbackstruct" "github.com/openimsdk/open-im-server/v3/pkg/common/config" - "github.com/openimsdk/open-im-server/v3/pkg/common/http" + pbfriend "github.com/openimsdk/protocol/friend" ) -func CallbackBeforeAddFriend(ctx context.Context, globalConfig *config.GlobalConfig, req *pbfriend.ApplyToAddFriendReq) error { - if !globalConfig.Callback.CallbackBeforeAddFriend.Enable { - return nil - } - cbReq := &cbapi.CallbackBeforeAddFriendReq{ - CallbackCommand: cbapi.CallbackBeforeAddFriendCommand, - FromUserID: req.FromUserID, - ToUserID: req.ToUserID, - ReqMsg: req.ReqMsg, - Ex: req.Ex, - } - resp := &cbapi.CallbackBeforeAddFriendResp{} - if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, cbReq, resp, globalConfig.Callback.CallbackBeforeAddFriend); err != nil { - return err - } - return nil -} - -func CallbackBeforeSetFriendRemark(ctx context.Context, globalConfig *config.GlobalConfig, req *pbfriend.SetFriendRemarkReq) error { - if !globalConfig.Callback.CallbackBeforeSetFriendRemark.Enable { - return nil - } - cbReq := &cbapi.CallbackBeforeSetFriendRemarkReq{ - CallbackCommand: cbapi.CallbackBeforeSetFriendRemark, +func (s *friendServer) webhookAfterDeleteFriend(ctx context.Context, after *config.AfterConfig, req *pbfriend.DeleteFriendReq) { + cbReq := &cbapi.CallbackAfterDeleteFriendReq{ + CallbackCommand: cbapi.CallbackAfterDeleteFriendCommand, OwnerUserID: req.OwnerUserID, FriendUserID: req.FriendUserID, - Remark: req.Remark, - } - resp := &cbapi.CallbackBeforeSetFriendRemarkResp{} - if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, cbReq, resp, globalConfig.Callback.CallbackBeforeAddFriend); err != nil { - return err } - utils.NotNilReplace(&req.Remark, &resp.Remark) - return nil + s.webhookClient.AsyncPost(ctx, cbReq.GetCallbackCommand(), cbReq, &cbapi.CallbackAfterDeleteFriendResp{}, after) } -func CallbackAfterSetFriendRemark(ctx context.Context, globalConfig *config.GlobalConfig, req *pbfriend.SetFriendRemarkReq) error { - if !globalConfig.Callback.CallbackAfterSetFriendRemark.Enable { - return nil - } - cbReq := &cbapi.CallbackAfterSetFriendRemarkReq{ - CallbackCommand: cbapi.CallbackAfterSetFriendRemark, - OwnerUserID: req.OwnerUserID, - FriendUserID: req.FriendUserID, - Remark: req.Remark, - } - resp := &cbapi.CallbackAfterSetFriendRemarkResp{} - if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, cbReq, resp, globalConfig.Callback.CallbackBeforeAddFriend); err != nil { - return err - } - return nil -} -func CallbackBeforeAddBlack(ctx context.Context, globalConfig *config.GlobalConfig, req *pbfriend.AddBlackReq) error { - if !globalConfig.Callback.CallbackBeforeAddBlack.Enable { +func (s *friendServer) webhookBeforeAddFriend(ctx context.Context, before *config.BeforeConfig, req *pbfriend.ApplyToAddFriendReq) error { + return webhook.WithCondition(ctx, before, func(ctx context.Context) error { + cbReq := &cbapi.CallbackBeforeAddFriendReq{ + CallbackCommand: cbapi.CallbackBeforeAddFriendCommand, + FromUserID: req.FromUserID, + ToUserID: req.ToUserID, + ReqMsg: req.ReqMsg, + Ex: req.Ex, + } + resp := &cbapi.CallbackBeforeAddFriendResp{} + + if err := s.webhookClient.SyncPost(ctx, cbReq.GetCallbackCommand(), cbReq, resp, before); err != nil { + return err + } return nil - } - cbReq := &cbapi.CallbackBeforeAddBlackReq{ - CallbackCommand: cbapi.CallbackBeforeAddBlackCommand, - OwnerUserID: req.OwnerUserID, - BlackUserID: req.BlackUserID, - } - resp := &cbapi.CallbackBeforeAddBlackResp{} - if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, cbReq, resp, globalConfig.Callback.CallbackBeforeAddBlack); err != nil { - return err - } - return nil + }) } -func CallbackAfterAddFriend(ctx context.Context, globalConfig *config.GlobalConfig, req *pbfriend.ApplyToAddFriendReq) error { - if !globalConfig.Callback.CallbackAfterAddFriend.Enable { - return nil - } + +func (s *friendServer) webhookAfterAddFriend(ctx context.Context, after *config.AfterConfig, req *pbfriend.ApplyToAddFriendReq) { cbReq := &cbapi.CallbackAfterAddFriendReq{ CallbackCommand: cbapi.CallbackAfterAddFriendCommand, FromUserID: req.FromUserID, @@ -102,90 +58,100 @@ func CallbackAfterAddFriend(ctx context.Context, globalConfig *config.GlobalConf ReqMsg: req.ReqMsg, } resp := &cbapi.CallbackAfterAddFriendResp{} - if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, cbReq, resp, globalConfig.Callback.CallbackAfterAddFriend); err != nil { - return err - } - - return nil -} -func CallbackBeforeAddFriendAgree(ctx context.Context, globalConfig *config.GlobalConfig, req *pbfriend.RespondFriendApplyReq) error { - if !globalConfig.Callback.CallbackBeforeAddFriendAgree.Enable { - return nil - } - cbReq := &cbapi.CallbackBeforeAddFriendAgreeReq{ - CallbackCommand: cbapi.CallbackBeforeAddFriendAgreeCommand, - FromUserID: req.FromUserID, - ToUserID: req.ToUserID, - HandleMsg: req.HandleMsg, - HandleResult: req.HandleResult, - } - resp := &cbapi.CallbackBeforeAddFriendAgreeResp{} - if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, cbReq, resp, globalConfig.Callback.CallbackBeforeAddFriendAgree); err != nil { - return err - } - return nil + s.webhookClient.AsyncPost(ctx, cbReq.GetCallbackCommand(), cbReq, resp, after) } -func CallbackAfterDeleteFriend(ctx context.Context, globalConfig *config.GlobalConfig, req *pbfriend.DeleteFriendReq) error { - if !globalConfig.Callback.CallbackAfterDeleteFriend.Enable { - return nil - } - cbReq := &cbapi.CallbackAfterDeleteFriendReq{ - CallbackCommand: cbapi.CallbackAfterDeleteFriendCommand, + +func (s *friendServer) webhookAfterSetFriendRemark(ctx context.Context, after *config.AfterConfig, req *pbfriend.SetFriendRemarkReq) { + + cbReq := &cbapi.CallbackAfterSetFriendRemarkReq{ + CallbackCommand: cbapi.CallbackAfterSetFriendRemarkCommand, OwnerUserID: req.OwnerUserID, FriendUserID: req.FriendUserID, + Remark: req.Remark, } - resp := &cbapi.CallbackAfterDeleteFriendResp{} - if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, cbReq, resp, globalConfig.Callback.CallbackAfterDeleteFriend); err != nil { - return err - } - return nil -} -func CallbackBeforeImportFriends(ctx context.Context, globalConfig *config.GlobalConfig, req *pbfriend.ImportFriendReq) error { - if !globalConfig.Callback.CallbackBeforeImportFriends.Enable { - return nil - } - cbReq := &cbapi.CallbackBeforeImportFriendsReq{ - CallbackCommand: cbapi.CallbackBeforeImportFriendsCommand, - OwnerUserID: req.OwnerUserID, - FriendUserIDs: req.FriendUserIDs, - } - resp := &cbapi.CallbackBeforeImportFriendsResp{} - if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, cbReq, resp, globalConfig.Callback.CallbackBeforeImportFriends); err != nil { - return err - } - if len(resp.FriendUserIDs) != 0 { - req.FriendUserIDs = resp.FriendUserIDs - } - return nil + resp := &cbapi.CallbackAfterSetFriendRemarkResp{} + s.webhookClient.AsyncPost(ctx, cbReq.GetCallbackCommand(), cbReq, resp, after) } -func CallbackAfterImportFriends(ctx context.Context, globalConfig *config.GlobalConfig, req *pbfriend.ImportFriendReq) error { - if !globalConfig.Callback.CallbackAfterImportFriends.Enable { - return nil - } + +func (s *friendServer) webhookAfterImportFriends(ctx context.Context, after *config.AfterConfig, req *pbfriend.ImportFriendReq) { cbReq := &cbapi.CallbackAfterImportFriendsReq{ CallbackCommand: cbapi.CallbackAfterImportFriendsCommand, OwnerUserID: req.OwnerUserID, FriendUserIDs: req.FriendUserIDs, } resp := &cbapi.CallbackAfterImportFriendsResp{} - if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, cbReq, resp, globalConfig.Callback.CallbackAfterImportFriends); err != nil { - return err - } - return nil + s.webhookClient.AsyncPost(ctx, cbReq.GetCallbackCommand(), cbReq, resp, after) } -func CallbackAfterRemoveBlack(ctx context.Context, globalConfig *config.GlobalConfig, req *pbfriend.RemoveBlackReq) error { - if !globalConfig.Callback.CallbackAfterRemoveBlack.Enable { - return nil - } +func (s *friendServer) webhookAfterRemoveBlack(ctx context.Context, after *config.AfterConfig, req *pbfriend.RemoveBlackReq) { cbReq := &cbapi.CallbackAfterRemoveBlackReq{ CallbackCommand: cbapi.CallbackAfterRemoveBlackCommand, OwnerUserID: req.OwnerUserID, BlackUserID: req.BlackUserID, } resp := &cbapi.CallbackAfterRemoveBlackResp{} - if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, cbReq, resp, globalConfig.Callback.CallbackAfterRemoveBlack); err != nil { - return err - } - return nil + s.webhookClient.AsyncPost(ctx, cbReq.GetCallbackCommand(), cbReq, resp, after) +} + +func (s *friendServer) webhookBeforeSetFriendRemark(ctx context.Context, before *config.BeforeConfig, req *pbfriend.SetFriendRemarkReq) error { + return webhook.WithCondition(ctx, before, func(ctx context.Context) error { + cbReq := &cbapi.CallbackBeforeSetFriendRemarkReq{ + CallbackCommand: cbapi.CallbackBeforeSetFriendRemarkCommand, + OwnerUserID: req.OwnerUserID, + FriendUserID: req.FriendUserID, + Remark: req.Remark, + } + resp := &cbapi.CallbackBeforeSetFriendRemarkResp{} + if err := s.webhookClient.SyncPost(ctx, cbReq.GetCallbackCommand(), cbReq, resp, before); err != nil { + return err + } + if resp.Remark != "" { + req.Remark = resp.Remark + } + return nil + }) +} + +func (s *friendServer) webhookBeforeAddBlack(ctx context.Context, before *config.BeforeConfig, req *pbfriend.AddBlackReq) error { + return webhook.WithCondition(ctx, before, func(ctx context.Context) error { + cbReq := &cbapi.CallbackBeforeAddBlackReq{ + CallbackCommand: cbapi.CallbackBeforeAddBlackCommand, + OwnerUserID: req.OwnerUserID, + BlackUserID: req.BlackUserID, + } + resp := &cbapi.CallbackBeforeAddBlackResp{} + return s.webhookClient.SyncPost(ctx, cbReq.GetCallbackCommand(), cbReq, resp, before) + }) +} + +func (s *friendServer) webhookBeforeAddFriendAgree(ctx context.Context, before *config.BeforeConfig, req *pbfriend.RespondFriendApplyReq) error { + return webhook.WithCondition(ctx, before, func(ctx context.Context) error { + cbReq := &cbapi.CallbackBeforeAddFriendAgreeReq{ + CallbackCommand: cbapi.CallbackBeforeAddFriendAgreeCommand, + FromUserID: req.FromUserID, + ToUserID: req.ToUserID, + HandleMsg: req.HandleMsg, + HandleResult: req.HandleResult, + } + resp := &cbapi.CallbackBeforeAddFriendAgreeResp{} + return s.webhookClient.SyncPost(ctx, cbReq.GetCallbackCommand(), cbReq, resp, before) + }) +} + +func (s *friendServer) webhookBeforeImportFriends(ctx context.Context, before *config.BeforeConfig, req *pbfriend.ImportFriendReq) error { + return webhook.WithCondition(ctx, before, func(ctx context.Context) error { + cbReq := &cbapi.CallbackBeforeImportFriendsReq{ + CallbackCommand: cbapi.CallbackBeforeImportFriendsCommand, + OwnerUserID: req.OwnerUserID, + FriendUserIDs: req.FriendUserIDs, + } + resp := &cbapi.CallbackBeforeImportFriendsResp{} + if err := s.webhookClient.SyncPost(ctx, cbReq.GetCallbackCommand(), cbReq, resp, before); err != nil { + return err + } + if len(resp.FriendUserIDs) > 0 { + req.FriendUserIDs = resp.FriendUserIDs + } + return nil + }) } diff --git a/internal/rpc/friend/friend.go b/internal/rpc/friend/friend.go index 4df4085a9c..bffda3c04e 100644 --- a/internal/rpc/friend/friend.go +++ b/internal/rpc/friend/friend.go @@ -16,25 +16,25 @@ package friend import ( "context" + "github.com/openimsdk/open-im-server/v3/pkg/common/config" + "github.com/openimsdk/open-im-server/v3/pkg/common/webhook" + "github.com/openimsdk/tools/db/redisutil" - "github.com/OpenIMSDK/protocol/constant" - pbfriend "github.com/OpenIMSDK/protocol/friend" - "github.com/OpenIMSDK/protocol/sdkws" - registry "github.com/OpenIMSDK/tools/discoveryregistry" - "github.com/OpenIMSDK/tools/errs" - "github.com/OpenIMSDK/tools/log" - "github.com/OpenIMSDK/tools/tx" - "github.com/OpenIMSDK/tools/utils" "github.com/openimsdk/open-im-server/v3/pkg/authverify" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/convert" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" "github.com/openimsdk/open-im-server/v3/pkg/common/db/mgo" tablerelation "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/unrelation" + "github.com/openimsdk/open-im-server/v3/pkg/common/servererrs" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" - "github.com/openimsdk/open-im-server/v3/pkg/rpcclient/notification" + "github.com/openimsdk/protocol/constant" + pbfriend "github.com/openimsdk/protocol/friend" + "github.com/openimsdk/protocol/sdkws" + "github.com/openimsdk/tools/db/mongoutil" + "github.com/openimsdk/tools/discovery" + "github.com/openimsdk/tools/errs" + "github.com/openimsdk/tools/utils/datautil" "google.golang.org/grpc" ) @@ -42,67 +42,79 @@ type friendServer struct { friendDatabase controller.FriendDatabase blackDatabase controller.BlackDatabase userRpcClient *rpcclient.UserRpcClient - notificationSender *notification.FriendNotificationSender + notificationSender *FriendNotificationSender conversationRpcClient rpcclient.ConversationRpcClient - RegisterCenter registry.SvcDiscoveryRegistry - config *config.GlobalConfig + RegisterCenter discovery.SvcDiscoveryRegistry + config *Config + webhookClient *webhook.Client +} + +type Config struct { + RpcConfig config.Friend + RedisConfig config.Redis + MongodbConfig config.Mongo + ZookeeperConfig config.ZooKeeper + NotificationConfig config.Notification + Share config.Share + WebhooksConfig config.Webhooks + LocalCacheConfig config.LocalCache } -func Start(config *config.GlobalConfig, client registry.SvcDiscoveryRegistry, server *grpc.Server) error { - // Initialize MongoDB - mongo, err := unrelation.NewMongo(config) +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 } - - // Initialize Redis - rdb, err := cache.NewRedis(config) + rdb, err := redisutil.NewRedisClient(ctx, config.RedisConfig.Build()) if err != nil { return err } - friendMongoDB, err := mgo.NewFriendMongo(mongo.GetDatabase(config.Mongo.Database)) + friendMongoDB, err := mgo.NewFriendMongo(mgocli.GetDB()) if err != nil { return err } - friendRequestMongoDB, err := mgo.NewFriendRequestMongo(mongo.GetDatabase(config.Mongo.Database)) + friendRequestMongoDB, err := mgo.NewFriendRequestMongo(mgocli.GetDB()) if err != nil { return err } - blackMongoDB, err := mgo.NewBlackMongo(mongo.GetDatabase(config.Mongo.Database)) + blackMongoDB, err := mgo.NewBlackMongo(mgocli.GetDB()) if err != nil { return err } // Initialize RPC clients - userRpcClient := rpcclient.NewUserRpcClient(client, config) - msgRpcClient := rpcclient.NewMessageRpcClient(client, config) + userRpcClient := rpcclient.NewUserRpcClient(client, config.Share.RpcRegisterName.User, config.Share.IMAdminUserID) + msgRpcClient := rpcclient.NewMessageRpcClient(client, config.Share.RpcRegisterName.Msg) // Initialize notification sender - notificationSender := notification.NewFriendNotificationSender( - config, + notificationSender := NewFriendNotificationSender( + &config.NotificationConfig, &msgRpcClient, - notification.WithRpcFunc(userRpcClient.GetUsersInfo), + WithRpcFunc(userRpcClient.GetUsersInfo), ) + cache.InitLocalCache(&config.LocalCacheConfig) + // Register Friend server with refactored MongoDB and Redis integrations pbfriend.RegisterFriendServer(server, &friendServer{ friendDatabase: controller.NewFriendDatabase( friendMongoDB, friendRequestMongoDB, - cache.NewFriendCacheRedis(rdb, friendMongoDB, cache.GetDefaultOpt()), - tx.NewMongo(mongo.GetClient()), + cache.NewFriendCacheRedis(rdb, &config.LocalCacheConfig, friendMongoDB, cache.GetDefaultOpt()), + mgocli.GetTx(), ), blackDatabase: controller.NewBlackDatabase( blackMongoDB, - cache.NewBlackCacheRedis(rdb, blackMongoDB, cache.GetDefaultOpt()), + cache.NewBlackCacheRedis(rdb, &config.LocalCacheConfig, blackMongoDB, cache.GetDefaultOpt()), ), userRpcClient: &userRpcClient, notificationSender: notificationSender, RegisterCenter: client, - conversationRpcClient: rpcclient.NewConversationRpcClient(client, config), + conversationRpcClient: rpcclient.NewConversationRpcClient(client, config.Share.RpcRegisterName.Conversation), config: config, + webhookClient: webhook.NewWebhookClient(config.WebhooksConfig.URL), }) return nil @@ -111,18 +123,15 @@ func Start(config *config.GlobalConfig, client registry.SvcDiscoveryRegistry, se // ok. func (s *friendServer) ApplyToAddFriend(ctx context.Context, req *pbfriend.ApplyToAddFriendReq) (resp *pbfriend.ApplyToAddFriendResp, err error) { resp = &pbfriend.ApplyToAddFriendResp{} - if err := authverify.CheckAccessV3(ctx, req.FromUserID, s.config); err != nil { + if err := authverify.CheckAccessV3(ctx, req.FromUserID, s.config.Share.IMAdminUserID); err != nil { return nil, err } - if req.ToUserID == req.FromUserID { - return nil, errs.ErrCanNotAddYourself.Wrap("req.ToUserID", req.ToUserID) + return nil, servererrs.ErrCanNotAddYourself.WrapMsg("req.ToUserID", req.ToUserID) } - - if err = CallbackBeforeAddFriend(ctx, s.config, req); err != nil && err != errs.ErrCallbackContinue { + if err = s.webhookBeforeAddFriend(ctx, &s.config.WebhooksConfig.BeforeAddFriend, req); err != nil && err != servererrs.ErrCallbackContinue { return nil, err } - if _, err := s.userRpcClient.GetUsersInfoMap(ctx, []string{req.ToUserID, req.FromUserID}); err != nil { return nil, err } @@ -131,41 +140,33 @@ func (s *friendServer) ApplyToAddFriend(ctx context.Context, req *pbfriend.Apply if err != nil { return nil, err } - if in1 && in2 { - return nil, errs.ErrRelationshipAlready.Wrap() + return nil, servererrs.ErrRelationshipAlready.WrapMsg("already friends has f") } - if err = s.friendDatabase.AddFriendRequest(ctx, req.FromUserID, req.ToUserID, req.ReqMsg, req.Ex); err != nil { return nil, err } - - if err = s.notificationSender.FriendApplicationAddNotification(ctx, req); err != nil { - return nil, err - } - - if err = CallbackAfterAddFriend(ctx, s.config, req); err != nil && err != errs.ErrCallbackContinue { - return nil, err - } + s.notificationSender.FriendApplicationAddNotification(ctx, req) + s.webhookAfterAddFriend(ctx, &s.config.WebhooksConfig.AfterAddFriend, req) return resp, nil } // ok. func (s *friendServer) ImportFriends(ctx context.Context, req *pbfriend.ImportFriendReq) (resp *pbfriend.ImportFriendResp, err error) { - defer log.ZInfo(ctx, utils.GetFuncName()+" Return") - if err := authverify.CheckAdmin(ctx, s.config); err != nil { + if err := authverify.CheckAdmin(ctx, s.config.Share.IMAdminUserID); err != nil { return nil, err } if _, err := s.userRpcClient.GetUsersInfo(ctx, append([]string{req.OwnerUserID}, req.FriendUserIDs...)); err != nil { return nil, err } - if utils.Contain(req.OwnerUserID, req.FriendUserIDs...) { - return nil, errs.ErrCanNotAddYourself.Wrap() + if datautil.Contain(req.OwnerUserID, req.FriendUserIDs...) { + return nil, servererrs.ErrCanNotAddYourself.WrapMsg("can not add yourself") } - if utils.Duplicate(req.FriendUserIDs) { - return nil, errs.ErrArgs.Wrap("friend userID repeated") + if datautil.Duplicate(req.FriendUserIDs) { + return nil, errs.ErrArgs.WrapMsg("friend userID repeated") } - if err := CallbackBeforeImportFriends(ctx, s.config, req); err != nil { + + if err := s.webhookBeforeImportFriends(ctx, &s.config.WebhooksConfig.BeforeImportFriends, req); err != nil && err != servererrs.ErrCallbackContinue { return nil, err } @@ -179,17 +180,15 @@ func (s *friendServer) ImportFriends(ctx context.Context, req *pbfriend.ImportFr HandleResult: constant.FriendResponseAgree, }) } - if err := CallbackAfterImportFriends(ctx, s.config, req); err != nil { - return nil, err - } + + s.webhookAfterImportFriends(ctx, &s.config.WebhooksConfig.AfterImportFriends, req) return &pbfriend.ImportFriendResp{}, nil } // ok. func (s *friendServer) RespondFriendApply(ctx context.Context, req *pbfriend.RespondFriendApplyReq) (resp *pbfriend.RespondFriendApplyResp, err error) { - defer log.ZInfo(ctx, utils.GetFuncName()+" Return") resp = &pbfriend.RespondFriendApplyResp{} - if err := authverify.CheckAccessV3(ctx, req.ToUserID, s.config); err != nil { + if err := authverify.CheckAccessV3(ctx, req.ToUserID, s.config.Share.IMAdminUserID); err != nil { return nil, err } @@ -200,16 +199,14 @@ func (s *friendServer) RespondFriendApply(ctx context.Context, req *pbfriend.Res HandleResult: req.HandleResult, } if req.HandleResult == constant.FriendResponseAgree { - if err := CallbackBeforeAddFriendAgree(ctx, s.config, req); err != nil && err != errs.ErrCallbackContinue { + if err := s.webhookBeforeAddFriendAgree(ctx, &s.config.WebhooksConfig.BeforeAddFriendAgree, req); err != nil && err != servererrs.ErrCallbackContinue { return nil, err } err := s.friendDatabase.AgreeFriendRequest(ctx, &friendRequest) if err != nil { return nil, err } - if err := s.notificationSender.FriendApplicationAgreedNotification(ctx, req); err != nil { - return nil, err - } + s.notificationSender.FriendApplicationAgreedNotification(ctx, req) return resp, nil } if req.HandleResult == constant.FriendResponseRefuse { @@ -220,12 +217,11 @@ func (s *friendServer) RespondFriendApply(ctx context.Context, req *pbfriend.Res s.notificationSender.FriendApplicationRefusedNotification(ctx, req) return resp, nil } - return nil, errs.ErrArgs.Wrap("req.HandleResult != -1/1") + return nil, errs.ErrArgs.WrapMsg("req.HandleResult != -1/1") } // ok. func (s *friendServer) DeleteFriend(ctx context.Context, req *pbfriend.DeleteFriendReq) (resp *pbfriend.DeleteFriendResp, err error) { - defer log.ZInfo(ctx, utils.GetFuncName()+" Return") resp = &pbfriend.DeleteFriendResp{} if err := s.userRpcClient.Access(ctx, req.OwnerUserID); err != nil { return nil, err @@ -238,17 +234,13 @@ func (s *friendServer) DeleteFriend(ctx context.Context, req *pbfriend.DeleteFri return nil, err } s.notificationSender.FriendDeletedNotification(ctx, req) - if err := CallbackAfterDeleteFriend(ctx, s.config, req); err != nil { - return nil, err - } + s.webhookAfterDeleteFriend(ctx, &s.config.WebhooksConfig.AfterDeleteFriend, req) return resp, nil } // ok. func (s *friendServer) SetFriendRemark(ctx context.Context, req *pbfriend.SetFriendRemarkReq) (resp *pbfriend.SetFriendRemarkResp, err error) { - defer log.ZInfo(ctx, utils.GetFuncName()+" Return") - - if err = CallbackBeforeSetFriendRemark(ctx, s.config, req); err != nil && err != errs.ErrCallbackContinue { + if err = s.webhookBeforeSetFriendRemark(ctx, &s.config.WebhooksConfig.BeforeSetFriendRemark, req); err != nil && err != servererrs.ErrCallbackContinue { return nil, err } resp = &pbfriend.SetFriendRemarkResp{} @@ -262,19 +254,16 @@ func (s *friendServer) SetFriendRemark(ctx context.Context, req *pbfriend.SetFri if err := s.friendDatabase.UpdateRemark(ctx, req.OwnerUserID, req.FriendUserID, req.Remark); err != nil { return nil, err } - if err := CallbackAfterSetFriendRemark(ctx, s.config, req); err != nil && err != errs.ErrCallbackContinue { - return nil, err - } + s.webhookAfterSetFriendRemark(ctx, &s.config.WebhooksConfig.AfterSetFriendRemark, req) s.notificationSender.FriendRemarkSetNotification(ctx, req.OwnerUserID, req.FriendUserID) return resp, nil } // ok. func (s *friendServer) GetDesignatedFriends(ctx context.Context, req *pbfriend.GetDesignatedFriendsReq) (resp *pbfriend.GetDesignatedFriendsResp, err error) { - defer log.ZInfo(ctx, utils.GetFuncName()+" Return") resp = &pbfriend.GetDesignatedFriendsResp{} - if utils.Duplicate(req.FriendUserIDs) { - return nil, errs.ErrArgs.Wrap("friend userID repeated") + if datautil.Duplicate(req.FriendUserIDs) { + return nil, errs.ErrArgs.WrapMsg("friend userID repeated") } friends, err := s.friendDatabase.FindFriendsWithError(ctx, req.OwnerUserID, req.FriendUserIDs) if err != nil { @@ -303,7 +292,6 @@ func (s *friendServer) GetDesignatedFriendsApply(ctx context.Context, // Get received friend requests (i.e., those initiated by others). func (s *friendServer) GetPaginationFriendsApplyTo(ctx context.Context, req *pbfriend.GetPaginationFriendsApplyToReq) (resp *pbfriend.GetPaginationFriendsApplyToResp, err error) { - defer log.ZInfo(ctx, utils.GetFuncName()+" Return") if err := s.userRpcClient.Access(ctx, req.UserID); err != nil { return nil, err } @@ -321,7 +309,6 @@ func (s *friendServer) GetPaginationFriendsApplyTo(ctx context.Context, req *pbf } func (s *friendServer) GetPaginationFriendsApplyFrom(ctx context.Context, req *pbfriend.GetPaginationFriendsApplyFromReq) (resp *pbfriend.GetPaginationFriendsApplyFromResp, err error) { - defer log.ZInfo(ctx, utils.GetFuncName()+" Return") resp = &pbfriend.GetPaginationFriendsApplyFromResp{} if err := s.userRpcClient.Access(ctx, req.UserID); err != nil { return nil, err @@ -340,7 +327,6 @@ func (s *friendServer) GetPaginationFriendsApplyFrom(ctx context.Context, req *p // ok. func (s *friendServer) IsFriend(ctx context.Context, req *pbfriend.IsFriendReq) (resp *pbfriend.IsFriendResp, err error) { - defer log.ZInfo(ctx, utils.GetFuncName()+" Return") resp = &pbfriend.IsFriendResp{} resp.InUser1Friends, resp.InUser2Friends, err = s.friendDatabase.CheckIn(ctx, req.UserID1, req.UserID2) if err != nil { @@ -350,7 +336,6 @@ func (s *friendServer) IsFriend(ctx context.Context, req *pbfriend.IsFriendReq) } func (s *friendServer) GetPaginationFriends(ctx context.Context, req *pbfriend.GetPaginationFriendsReq) (resp *pbfriend.GetPaginationFriendsResp, err error) { - defer log.ZInfo(ctx, utils.GetFuncName()+" Return") if err := s.userRpcClient.Access(ctx, req.UserID); err != nil { return nil, err } @@ -368,7 +353,6 @@ func (s *friendServer) GetPaginationFriends(ctx context.Context, req *pbfriend.G } func (s *friendServer) GetFriendIDs(ctx context.Context, req *pbfriend.GetFriendIDsReq) (resp *pbfriend.GetFriendIDsResp, err error) { - defer log.ZInfo(ctx, utils.GetFuncName()+" Return") if err := s.userRpcClient.Access(ctx, req.UserID); err != nil { return nil, err } @@ -382,10 +366,10 @@ func (s *friendServer) GetFriendIDs(ctx context.Context, req *pbfriend.GetFriend func (s *friendServer) GetSpecifiedFriendsInfo(ctx context.Context, req *pbfriend.GetSpecifiedFriendsInfoReq) (*pbfriend.GetSpecifiedFriendsInfoResp, error) { if len(req.UserIDList) == 0 { - return nil, errs.ErrArgs.Wrap("userIDList is empty") + return nil, errs.ErrArgs.WrapMsg("userIDList is empty") } - if utils.Duplicate(req.UserIDList) { - return nil, errs.ErrArgs.Wrap("userIDList repeated") + if datautil.Duplicate(req.UserIDList) { + return nil, errs.ErrArgs.WrapMsg("userIDList repeated") } userMap, err := s.userRpcClient.GetUsersInfoMap(ctx, req.UserIDList) if err != nil { @@ -399,10 +383,10 @@ func (s *friendServer) GetSpecifiedFriendsInfo(ctx context.Context, req *pbfrien if err != nil { return nil, err } - friendMap := utils.SliceToMap(friends, func(e *tablerelation.FriendModel) string { + friendMap := datautil.SliceToMap(friends, func(e *tablerelation.FriendModel) string { return e.FriendUserID }) - blackMap := utils.SliceToMap(blacks, func(e *tablerelation.BlackModel) string { + blackMap := datautil.SliceToMap(blacks, func(e *tablerelation.BlackModel) string { return e.BlockUserID }) resp := &pbfriend.GetSpecifiedFriendsInfoResp{ @@ -449,10 +433,10 @@ func (s *friendServer) UpdateFriends( req *pbfriend.UpdateFriendsReq, ) (*pbfriend.UpdateFriendsResp, error) { if len(req.FriendUserIDs) == 0 { - return nil, errs.ErrArgs.Wrap("friendIDList is empty") + return nil, errs.ErrArgs.WrapMsg("friendIDList is empty") } - if utils.Duplicate(req.FriendUserIDs) { - return nil, errs.ErrArgs.Wrap("friendIDList repeated") + if datautil.Duplicate(req.FriendUserIDs) { + return nil, errs.ErrArgs.WrapMsg("friendIDList repeated") } _, err := s.friendDatabase.FindFriendsWithError(ctx, req.OwnerUserID, req.FriendUserIDs) @@ -477,9 +461,6 @@ func (s *friendServer) UpdateFriends( resp := &pbfriend.UpdateFriendsResp{} - err = s.notificationSender.FriendsInfoUpdateNotification(ctx, req.OwnerUserID, req.FriendUserIDs) - if err != nil { - return nil, errs.Wrap(err, "FriendsInfoUpdateNotification Error") - } + s.notificationSender.FriendsInfoUpdateNotification(ctx, req.OwnerUserID, req.FriendUserIDs) return resp, nil } diff --git a/pkg/rpcclient/notification/friend.go b/internal/rpc/friend/notification.go similarity index 72% rename from pkg/rpcclient/notification/friend.go rename to internal/rpc/friend/notification.go index 751bdf4757..f88c9664e6 100644 --- a/pkg/rpcclient/notification/friend.go +++ b/internal/rpc/friend/notification.go @@ -12,26 +12,27 @@ // See the License for the specific language governing permissions and // limitations under the License. -package notification +package friend import ( "context" - "github.com/OpenIMSDK/protocol/constant" - pbfriend "github.com/OpenIMSDK/protocol/friend" - "github.com/OpenIMSDK/protocol/sdkws" - "github.com/OpenIMSDK/tools/mcontext" "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/convert" "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" + "github.com/openimsdk/open-im-server/v3/pkg/rpcclient/notification" + "github.com/openimsdk/protocol/constant" + pbfriend "github.com/openimsdk/protocol/friend" + "github.com/openimsdk/protocol/sdkws" + "github.com/openimsdk/tools/mcontext" ) type FriendNotificationSender struct { *rpcclient.NotificationSender // Target not found err - getUsersInfo func(ctx context.Context, userIDs []string) ([]CommonUser, error) + getUsersInfo func(ctx context.Context, userIDs []string) ([]notification.CommonUser, error) // db controller db controller.FriendDatabase } @@ -48,7 +49,7 @@ func WithDBFunc( fn func(ctx context.Context, userIDs []string) (users []*relationtb.UserModel, err error), ) friendNotificationSenderOptions { return func(s *FriendNotificationSender) { - f := func(ctx context.Context, userIDs []string) (result []CommonUser, err error) { + f := func(ctx context.Context, userIDs []string) (result []notification.CommonUser, err error) { users, err := fn(ctx, userIDs) if err != nil { return nil, err @@ -66,7 +67,7 @@ func WithRpcFunc( fn func(ctx context.Context, userIDs []string) ([]*sdkws.UserInfo, error), ) friendNotificationSenderOptions { return func(s *FriendNotificationSender) { - f := func(ctx context.Context, userIDs []string) (result []CommonUser, err error) { + f := func(ctx context.Context, userIDs []string) (result []notification.CommonUser, err error) { users, err := fn(ctx, userIDs) if err != nil { return nil, err @@ -81,12 +82,12 @@ func WithRpcFunc( } func NewFriendNotificationSender( - config *config.GlobalConfig, + conf *config.Notification, msgRpcClient *rpcclient.MessageRpcClient, opts ...friendNotificationSenderOptions, ) *FriendNotificationSender { f := &FriendNotificationSender{ - NotificationSender: rpcclient.NewNotificationSender(config, rpcclient.WithRpcClient(msgRpcClient)), + NotificationSender: rpcclient.NewNotificationSender(conf, rpcclient.WithRpcClient(msgRpcClient)), } for _, opt := range opts { opt(f) @@ -121,39 +122,39 @@ func (f *FriendNotificationSender) getFromToUserNickname( return users[fromUserID].Nickname, users[toUserID].Nickname, nil } -func (f *FriendNotificationSender) UserInfoUpdatedNotification(ctx context.Context, changedUserID string) error { +func (f *FriendNotificationSender) UserInfoUpdatedNotification(ctx context.Context, changedUserID string) { tips := sdkws.UserInfoUpdatedTips{UserID: changedUserID} - return f.Notification(ctx, mcontext.GetOpUserID(ctx), changedUserID, constant.UserInfoUpdatedNotification, &tips) + f.Notification(ctx, mcontext.GetOpUserID(ctx), changedUserID, constant.UserInfoUpdatedNotification, &tips) } -func (f *FriendNotificationSender) FriendApplicationAddNotification(ctx context.Context, req *pbfriend.ApplyToAddFriendReq) error { +func (f *FriendNotificationSender) FriendApplicationAddNotification(ctx context.Context, req *pbfriend.ApplyToAddFriendReq) { tips := sdkws.FriendApplicationTips{FromToUserID: &sdkws.FromToUserID{ FromUserID: req.FromUserID, ToUserID: req.ToUserID, }} - return f.Notification(ctx, req.FromUserID, req.ToUserID, constant.FriendApplicationNotification, &tips) + f.Notification(ctx, req.FromUserID, req.ToUserID, constant.FriendApplicationNotification, &tips) } func (f *FriendNotificationSender) FriendApplicationAgreedNotification( ctx context.Context, req *pbfriend.RespondFriendApplyReq, -) error { +) { tips := sdkws.FriendApplicationApprovedTips{FromToUserID: &sdkws.FromToUserID{ FromUserID: req.FromUserID, ToUserID: req.ToUserID, }, HandleMsg: req.HandleMsg} - return f.Notification(ctx, req.ToUserID, req.FromUserID, constant.FriendApplicationApprovedNotification, &tips) + f.Notification(ctx, req.ToUserID, req.FromUserID, constant.FriendApplicationApprovedNotification, &tips) } func (f *FriendNotificationSender) FriendApplicationRefusedNotification( ctx context.Context, req *pbfriend.RespondFriendApplyReq, -) error { +) { tips := sdkws.FriendApplicationApprovedTips{FromToUserID: &sdkws.FromToUserID{ FromUserID: req.FromUserID, ToUserID: req.ToUserID, }, HandleMsg: req.HandleMsg} - return f.Notification(ctx, req.ToUserID, req.FromUserID, constant.FriendApplicationRejectedNotification, &tips) + f.Notification(ctx, req.ToUserID, req.FromUserID, constant.FriendApplicationRejectedNotification, &tips) } func (f *FriendNotificationSender) FriendAddedNotification( @@ -177,34 +178,37 @@ func (f *FriendNotificationSender) FriendAddedNotification( if err != nil { return err } - return f.Notification(ctx, fromUserID, toUserID, constant.FriendAddedNotification, &tips) + f.Notification(ctx, fromUserID, toUserID, constant.FriendAddedNotification, &tips) + return nil } -func (f *FriendNotificationSender) FriendDeletedNotification(ctx context.Context, req *pbfriend.DeleteFriendReq) error { +func (f *FriendNotificationSender) FriendDeletedNotification(ctx context.Context, req *pbfriend.DeleteFriendReq) { tips := sdkws.FriendDeletedTips{FromToUserID: &sdkws.FromToUserID{ FromUserID: req.OwnerUserID, ToUserID: req.FriendUserID, }} - return f.Notification(ctx, req.OwnerUserID, req.FriendUserID, constant.FriendDeletedNotification, &tips) + f.Notification(ctx, req.OwnerUserID, req.FriendUserID, constant.FriendDeletedNotification, &tips) } -func (f *FriendNotificationSender) FriendRemarkSetNotification(ctx context.Context, fromUserID, toUserID string) error { +func (f *FriendNotificationSender) FriendRemarkSetNotification(ctx context.Context, fromUserID, toUserID string) { tips := sdkws.FriendInfoChangedTips{FromToUserID: &sdkws.FromToUserID{}} tips.FromToUserID.FromUserID = fromUserID tips.FromToUserID.ToUserID = toUserID - return f.Notification(ctx, fromUserID, toUserID, constant.FriendRemarkSetNotification, &tips) + f.Notification(ctx, fromUserID, toUserID, constant.FriendRemarkSetNotification, &tips) } -func (f *FriendNotificationSender) FriendsInfoUpdateNotification(ctx context.Context, toUserID string, friendIDs []string) error { + +func (f *FriendNotificationSender) FriendsInfoUpdateNotification(ctx context.Context, toUserID string, friendIDs []string) { tips := sdkws.FriendsInfoUpdateTips{FromToUserID: &sdkws.FromToUserID{}} tips.FromToUserID.ToUserID = toUserID tips.FriendIDs = friendIDs - return f.Notification(ctx, toUserID, toUserID, constant.FriendsInfoUpdateNotification, &tips) + f.Notification(ctx, toUserID, toUserID, constant.FriendsInfoUpdateNotification, &tips) } -func (f *FriendNotificationSender) BlackAddedNotification(ctx context.Context, req *pbfriend.AddBlackReq) error { + +func (f *FriendNotificationSender) BlackAddedNotification(ctx context.Context, req *pbfriend.AddBlackReq) { tips := sdkws.BlackAddedTips{FromToUserID: &sdkws.FromToUserID{}} tips.FromToUserID.FromUserID = req.OwnerUserID tips.FromToUserID.ToUserID = req.BlackUserID - return f.Notification(ctx, req.OwnerUserID, req.BlackUserID, constant.BlackAddedNotification, &tips) + f.Notification(ctx, req.OwnerUserID, req.BlackUserID, constant.BlackAddedNotification, &tips) } func (f *FriendNotificationSender) BlackDeletedNotification(ctx context.Context, req *pbfriend.RemoveBlackReq) { @@ -212,19 +216,10 @@ func (f *FriendNotificationSender) BlackDeletedNotification(ctx context.Context, FromUserID: req.OwnerUserID, ToUserID: req.BlackUserID, }} - if err := f.Notification(ctx, req.OwnerUserID, req.BlackUserID, constant.BlackDeletedNotification, &blackDeletedTips); err != nil { - //err - } + f.Notification(ctx, req.OwnerUserID, req.BlackUserID, constant.BlackDeletedNotification, &blackDeletedTips) } -func (f *FriendNotificationSender) FriendInfoUpdatedNotification( - ctx context.Context, - changedUserID string, - needNotifiedUserID string, -) { +func (f *FriendNotificationSender) FriendInfoUpdatedNotification(ctx context.Context, changedUserID string, needNotifiedUserID string) { tips := sdkws.UserInfoUpdatedTips{UserID: changedUserID} - if err := f.Notification(ctx, mcontext.GetOpUserID(ctx), needNotifiedUserID, - constant.FriendInfoUpdatedNotification, &tips); err != nil { - // err - } + f.Notification(ctx, mcontext.GetOpUserID(ctx), needNotifiedUserID, constant.FriendInfoUpdatedNotification, &tips) } diff --git a/internal/rpc/group/cache.go b/internal/rpc/group/cache.go index 35c631effe..022a0f4ef6 100644 --- a/internal/rpc/group/cache.go +++ b/internal/rpc/group/cache.go @@ -17,27 +17,27 @@ package group import ( "context" - pbgroup "github.com/OpenIMSDK/protocol/group" "github.com/openimsdk/open-im-server/v3/pkg/common/convert" + pbgroup "github.com/openimsdk/protocol/group" ) -func (s *groupServer) GetGroupInfoCache( - ctx context.Context, - req *pbgroup.GetGroupInfoCacheReq, -) (resp *pbgroup.GetGroupInfoCacheResp, err error) { +// GetGroupInfoCache get group info from cache. +func (s *groupServer) GetGroupInfoCache(ctx context.Context, req *pbgroup.GetGroupInfoCacheReq) (*pbgroup.GetGroupInfoCacheResp, error) { group, err := s.db.TakeGroup(ctx, req.GroupID) if err != nil { return nil, err } - resp = &pbgroup.GetGroupInfoCacheResp{GroupInfo: convert.Db2PbGroupInfo(group, "", 0)} - return resp, nil + return &pbgroup.GetGroupInfoCacheResp{ + GroupInfo: convert.Db2PbGroupInfo(group, "", 0), + }, nil } -func (s *groupServer) GetGroupMemberCache(ctx context.Context, req *pbgroup.GetGroupMemberCacheReq) (resp *pbgroup.GetGroupMemberCacheResp, err error) { +func (s *groupServer) GetGroupMemberCache(ctx context.Context, req *pbgroup.GetGroupMemberCacheReq) (*pbgroup.GetGroupMemberCacheResp, error) { members, err := s.db.TakeGroupMember(ctx, req.GroupID, req.GroupMemberID) if err != nil { return nil, err } - resp = &pbgroup.GetGroupMemberCacheResp{Member: convert.Db2PbGroupMember(members)} - return resp, nil + return &pbgroup.GetGroupMemberCacheResp{ + Member: convert.Db2PbGroupMember(members), + }, nil } diff --git a/internal/rpc/group/callback.go b/internal/rpc/group/callback.go index e82177dde0..1690e3973f 100644 --- a/internal/rpc/group/callback.go +++ b/internal/rpc/group/callback.go @@ -16,70 +16,67 @@ package group import ( "context" - "time" - - "github.com/OpenIMSDK/protocol/constant" - "github.com/OpenIMSDK/protocol/group" - pbgroup "github.com/OpenIMSDK/protocol/group" - "github.com/OpenIMSDK/protocol/wrapperspb" - "github.com/OpenIMSDK/tools/log" - "github.com/OpenIMSDK/tools/mcontext" - "github.com/OpenIMSDK/tools/utils" "github.com/openimsdk/open-im-server/v3/pkg/apistruct" "github.com/openimsdk/open-im-server/v3/pkg/callbackstruct" "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" - "github.com/openimsdk/open-im-server/v3/pkg/common/http" + "github.com/openimsdk/open-im-server/v3/pkg/common/webhook" + "github.com/openimsdk/protocol/constant" + "github.com/openimsdk/protocol/group" + "github.com/openimsdk/protocol/wrapperspb" + "github.com/openimsdk/tools/log" + "github.com/openimsdk/tools/mcontext" + "github.com/openimsdk/tools/utils/datautil" + "time" ) -func CallbackBeforeCreateGroup(ctx context.Context, globalConfig *config.GlobalConfig, req *group.CreateGroupReq) (err error) { - if !globalConfig.Callback.CallbackBeforeCreateGroup.Enable { - return nil - } - cbReq := &callbackstruct.CallbackBeforeCreateGroupReq{ - CallbackCommand: callbackstruct.CallbackBeforeCreateGroupCommand, - OperationID: mcontext.GetOperationID(ctx), - GroupInfo: req.GroupInfo, - } - cbReq.InitMemberList = append(cbReq.InitMemberList, &apistruct.GroupAddMemberInfo{ - UserID: req.OwnerUserID, - RoleLevel: constant.GroupOwner, - }) - for _, userID := range req.AdminUserIDs { - cbReq.InitMemberList = append(cbReq.InitMemberList, &apistruct.GroupAddMemberInfo{ - UserID: userID, - RoleLevel: constant.GroupAdmin, - }) - } - for _, userID := range req.MemberUserIDs { +// CallbackBeforeCreateGroup callback before create group. +func (s *groupServer) webhookBeforeCreateGroup(ctx context.Context, before *config.BeforeConfig, req *group.CreateGroupReq) error { + return webhook.WithCondition(ctx, before, func(ctx context.Context) error { + cbReq := &callbackstruct.CallbackBeforeCreateGroupReq{ + CallbackCommand: callbackstruct.CallbackBeforeCreateGroupCommand, + OperationID: mcontext.GetOperationID(ctx), + GroupInfo: req.GroupInfo, + } cbReq.InitMemberList = append(cbReq.InitMemberList, &apistruct.GroupAddMemberInfo{ - UserID: userID, - RoleLevel: constant.GroupOrdinaryUsers, + UserID: req.OwnerUserID, + RoleLevel: constant.GroupOwner, }) - } - resp := &callbackstruct.CallbackBeforeCreateGroupResp{} - if err = http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, cbReq, resp, globalConfig.Callback.CallbackBeforeCreateGroup); err != nil { - return err - } - utils.NotNilReplace(&req.GroupInfo.GroupID, resp.GroupID) - utils.NotNilReplace(&req.GroupInfo.GroupName, resp.GroupName) - utils.NotNilReplace(&req.GroupInfo.Notification, resp.Notification) - utils.NotNilReplace(&req.GroupInfo.Introduction, resp.Introduction) - utils.NotNilReplace(&req.GroupInfo.FaceURL, resp.FaceURL) - utils.NotNilReplace(&req.GroupInfo.OwnerUserID, resp.OwnerUserID) - utils.NotNilReplace(&req.GroupInfo.Ex, resp.Ex) - utils.NotNilReplace(&req.GroupInfo.Status, resp.Status) - utils.NotNilReplace(&req.GroupInfo.CreatorUserID, resp.CreatorUserID) - utils.NotNilReplace(&req.GroupInfo.GroupType, resp.GroupType) - utils.NotNilReplace(&req.GroupInfo.NeedVerification, resp.NeedVerification) - utils.NotNilReplace(&req.GroupInfo.LookMemberInfo, resp.LookMemberInfo) - return nil -} + for _, userID := range req.AdminUserIDs { + cbReq.InitMemberList = append(cbReq.InitMemberList, &apistruct.GroupAddMemberInfo{ + UserID: userID, + RoleLevel: constant.GroupAdmin, + }) + } + for _, userID := range req.MemberUserIDs { + cbReq.InitMemberList = append(cbReq.InitMemberList, &apistruct.GroupAddMemberInfo{ + UserID: userID, + RoleLevel: constant.GroupOrdinaryUsers, + }) + } + resp := &callbackstruct.CallbackBeforeCreateGroupResp{} + + if err := s.webhookClient.SyncPost(ctx, cbReq.GetCallbackCommand(), cbReq, resp, before); err != nil { + return err + } -func CallbackAfterCreateGroup(ctx context.Context, globalConfig *config.GlobalConfig, req *group.CreateGroupReq) (err error) { - if !globalConfig.Callback.CallbackAfterCreateGroup.Enable { + datautil.NotNilReplace(&req.GroupInfo.GroupID, resp.GroupID) + datautil.NotNilReplace(&req.GroupInfo.GroupName, resp.GroupName) + datautil.NotNilReplace(&req.GroupInfo.Notification, resp.Notification) + datautil.NotNilReplace(&req.GroupInfo.Introduction, resp.Introduction) + datautil.NotNilReplace(&req.GroupInfo.FaceURL, resp.FaceURL) + datautil.NotNilReplace(&req.GroupInfo.OwnerUserID, resp.OwnerUserID) + datautil.NotNilReplace(&req.GroupInfo.Ex, resp.Ex) + datautil.NotNilReplace(&req.GroupInfo.Status, resp.Status) + datautil.NotNilReplace(&req.GroupInfo.CreatorUserID, resp.CreatorUserID) + datautil.NotNilReplace(&req.GroupInfo.GroupType, resp.GroupType) + datautil.NotNilReplace(&req.GroupInfo.NeedVerification, resp.NeedVerification) + datautil.NotNilReplace(&req.GroupInfo.LookMemberInfo, resp.LookMemberInfo) return nil - } + }) +} + +func (s *groupServer) webhookAfterCreateGroup(ctx context.Context, after *config.AfterConfig, req *group.CreateGroupReq) { cbReq := &callbackstruct.CallbackAfterCreateGroupReq{ CallbackCommand: callbackstruct.CallbackAfterCreateGroupCommand, GroupInfo: req.GroupInfo, @@ -100,239 +97,163 @@ func CallbackAfterCreateGroup(ctx context.Context, globalConfig *config.GlobalCo RoleLevel: constant.GroupOrdinaryUsers, }) } - resp := &callbackstruct.CallbackAfterCreateGroupResp{} - if err = http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, cbReq, resp, globalConfig.Callback.CallbackAfterCreateGroup); err != nil { - return err - } - return nil + s.webhookClient.AsyncPost(ctx, cbReq.GetCallbackCommand(), cbReq, &callbackstruct.CallbackAfterCreateGroupResp{}, after) } -func CallbackBeforeMemberJoinGroup( - ctx context.Context, - globalConfig *config.GlobalConfig, - groupMember *relation.GroupMemberModel, - groupEx string, -) (err error) { - if !globalConfig.Callback.CallbackBeforeMemberJoinGroup.Enable { +func (s *groupServer) webhookBeforeMemberJoinGroup(ctx context.Context, before *config.BeforeConfig, groupMember *relation.GroupMemberModel, groupEx string) error { + return webhook.WithCondition(ctx, before, func(ctx context.Context) error { + cbReq := &callbackstruct.CallbackBeforeMemberJoinGroupReq{ + CallbackCommand: callbackstruct.CallbackBeforeMemberJoinGroupCommand, + GroupID: groupMember.GroupID, + UserID: groupMember.UserID, + Ex: groupMember.Ex, + GroupEx: groupEx, + } + resp := &callbackstruct.CallbackBeforeMemberJoinGroupResp{} + if err := s.webhookClient.SyncPost(ctx, cbReq.GetCallbackCommand(), cbReq, resp, before); err != nil { + return err + } + + if resp.MuteEndTime != nil { + groupMember.MuteEndTime = time.UnixMilli(*resp.MuteEndTime) + } + datautil.NotNilReplace(&groupMember.FaceURL, resp.FaceURL) + datautil.NotNilReplace(&groupMember.Ex, resp.Ex) + datautil.NotNilReplace(&groupMember.Nickname, resp.Nickname) + datautil.NotNilReplace(&groupMember.RoleLevel, resp.RoleLevel) return nil - } - callbackReq := &callbackstruct.CallbackBeforeMemberJoinGroupReq{ - CallbackCommand: callbackstruct.CallbackBeforeMemberJoinGroupCommand, - GroupID: groupMember.GroupID, - UserID: groupMember.UserID, - Ex: groupMember.Ex, - GroupEx: groupEx, - } - resp := &callbackstruct.CallbackBeforeMemberJoinGroupResp{} - err = http.CallBackPostReturn( - ctx, - globalConfig.Callback.CallbackUrl, - callbackReq, - resp, - globalConfig.Callback.CallbackBeforeMemberJoinGroup, - ) - if err != nil { - return err - } - if resp.MuteEndTime != nil { - groupMember.MuteEndTime = time.UnixMilli(*resp.MuteEndTime) - } - utils.NotNilReplace(&groupMember.FaceURL, resp.FaceURL) - utils.NotNilReplace(&groupMember.Ex, resp.Ex) - utils.NotNilReplace(&groupMember.Nickname, resp.Nickname) - utils.NotNilReplace(&groupMember.RoleLevel, resp.RoleLevel) - return nil + }) } -func CallbackBeforeSetGroupMemberInfo(ctx context.Context, globalConfig *config.GlobalConfig, req *group.SetGroupMemberInfo) (err error) { - if !globalConfig.Callback.CallbackBeforeSetGroupMemberInfo.Enable { +func (s *groupServer) webhookBeforeSetGroupMemberInfo(ctx context.Context, before *config.BeforeConfig, req *group.SetGroupMemberInfo) error { + return webhook.WithCondition(ctx, before, func(ctx context.Context) error { + cbReq := callbackstruct.CallbackBeforeSetGroupMemberInfoReq{ + CallbackCommand: callbackstruct.CallbackBeforeSetGroupMemberInfoCommand, + GroupID: req.GroupID, + UserID: req.UserID, + } + if req.Nickname != nil { + cbReq.Nickname = &req.Nickname.Value + } + if req.FaceURL != nil { + cbReq.FaceURL = &req.FaceURL.Value + } + if req.RoleLevel != nil { + cbReq.RoleLevel = &req.RoleLevel.Value + } + if req.Ex != nil { + cbReq.Ex = &req.Ex.Value + } + resp := &callbackstruct.CallbackBeforeSetGroupMemberInfoResp{} + if err := s.webhookClient.SyncPost(ctx, cbReq.GetCallbackCommand(), cbReq, resp, before); err != nil { + return err + } + if resp.FaceURL != nil { + req.FaceURL = wrapperspb.String(*resp.FaceURL) + } + if resp.Nickname != nil { + req.Nickname = wrapperspb.String(*resp.Nickname) + } + if resp.RoleLevel != nil { + req.RoleLevel = wrapperspb.Int32(*resp.RoleLevel) + } + if resp.Ex != nil { + req.Ex = wrapperspb.String(*resp.Ex) + } return nil - } - callbackReq := callbackstruct.CallbackBeforeSetGroupMemberInfoReq{ - CallbackCommand: callbackstruct.CallbackBeforeSetGroupMemberInfoCommand, - GroupID: req.GroupID, - UserID: req.UserID, - } - if req.Nickname != nil { - callbackReq.Nickname = &req.Nickname.Value - } - if req.FaceURL != nil { - callbackReq.FaceURL = &req.FaceURL.Value - } - if req.RoleLevel != nil { - callbackReq.RoleLevel = &req.RoleLevel.Value - } - if req.Ex != nil { - callbackReq.Ex = &req.Ex.Value - } - resp := &callbackstruct.CallbackBeforeSetGroupMemberInfoResp{} - err = http.CallBackPostReturn( - ctx, - globalConfig.Callback.CallbackUrl, - callbackReq, - resp, - globalConfig.Callback.CallbackBeforeSetGroupMemberInfo, - ) - if err != nil { - return err - } - if resp.FaceURL != nil { - req.FaceURL = wrapperspb.String(*resp.FaceURL) - } - if resp.Nickname != nil { - req.Nickname = wrapperspb.String(*resp.Nickname) - } - if resp.RoleLevel != nil { - req.RoleLevel = wrapperspb.Int32(*resp.RoleLevel) - } - if resp.Ex != nil { - req.Ex = wrapperspb.String(*resp.Ex) - } - return nil + }) } -func CallbackAfterSetGroupMemberInfo(ctx context.Context, globalConfig *config.GlobalConfig, req *group.SetGroupMemberInfo) (err error) { - if !globalConfig.Callback.CallbackBeforeSetGroupMemberInfo.Enable { - return nil - } - callbackReq := callbackstruct.CallbackAfterSetGroupMemberInfoReq{ + +func (s *groupServer) webhookAfterSetGroupMemberInfo(ctx context.Context, after *config.AfterConfig, req *group.SetGroupMemberInfo) { + cbReq := callbackstruct.CallbackAfterSetGroupMemberInfoReq{ CallbackCommand: callbackstruct.CallbackAfterSetGroupMemberInfoCommand, GroupID: req.GroupID, UserID: req.UserID, } if req.Nickname != nil { - callbackReq.Nickname = &req.Nickname.Value + cbReq.Nickname = &req.Nickname.Value } if req.FaceURL != nil { - callbackReq.FaceURL = &req.FaceURL.Value + cbReq.FaceURL = &req.FaceURL.Value } if req.RoleLevel != nil { - callbackReq.RoleLevel = &req.RoleLevel.Value + cbReq.RoleLevel = &req.RoleLevel.Value } if req.Ex != nil { - callbackReq.Ex = &req.Ex.Value + cbReq.Ex = &req.Ex.Value } - resp := &callbackstruct.CallbackAfterSetGroupMemberInfoResp{} - if err = http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, callbackReq, resp, globalConfig.Callback.CallbackAfterSetGroupMemberInfo); err != nil { - return err - } - return nil + s.webhookClient.AsyncPost(ctx, cbReq.GetCallbackCommand(), cbReq, &callbackstruct.CallbackAfterSetGroupMemberInfoResp{}, after) } -func CallbackQuitGroup(ctx context.Context, globalConfig *config.GlobalConfig, req *group.QuitGroupReq) (err error) { - if !globalConfig.Callback.CallbackQuitGroup.Enable { - return nil - } +func (s *groupServer) webhookAfterQuitGroup(ctx context.Context, after *config.AfterConfig, req *group.QuitGroupReq) { cbReq := &callbackstruct.CallbackQuitGroupReq{ - CallbackCommand: callbackstruct.CallbackQuitGroupCommand, + CallbackCommand: callbackstruct.CallbackAfterQuitGroupCommand, GroupID: req.GroupID, UserID: req.UserID, } - resp := &callbackstruct.CallbackQuitGroupResp{} - if err = http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, cbReq, resp, globalConfig.Callback.CallbackQuitGroup); err != nil { - return err - } - return nil + s.webhookClient.AsyncPost(ctx, cbReq.GetCallbackCommand(), cbReq, &callbackstruct.CallbackQuitGroupResp{}, after) } -func CallbackKillGroupMember(ctx context.Context, globalConfig *config.GlobalConfig, req *pbgroup.KickGroupMemberReq) (err error) { - if !globalConfig.Callback.CallbackKillGroupMember.Enable { - return nil - } +func (s *groupServer) webhookAfterKickGroupMember(ctx context.Context, after *config.AfterConfig, req *group.KickGroupMemberReq) { cbReq := &callbackstruct.CallbackKillGroupMemberReq{ - CallbackCommand: callbackstruct.CallbackKillGroupCommand, + CallbackCommand: callbackstruct.CallbackAfterKickGroupCommand, GroupID: req.GroupID, KickedUserIDs: req.KickedUserIDs, } - resp := &callbackstruct.CallbackKillGroupMemberResp{} - if err = http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, cbReq, resp, globalConfig.Callback.CallbackQuitGroup); err != nil { - return err - } - return nil + s.webhookClient.AsyncPost(ctx, cbReq.GetCallbackCommand(), cbReq, &callbackstruct.CallbackKillGroupMemberResp{}, after) } -func CallbackDismissGroup(ctx context.Context, globalConfig *config.GlobalConfig, req *callbackstruct.CallbackDisMissGroupReq) (err error) { - if !globalConfig.Callback.CallbackDismissGroup.Enable { - return nil - } - req.CallbackCommand = callbackstruct.CallbackDisMissGroupCommand - resp := &callbackstruct.CallbackDisMissGroupResp{} - if err = http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, req, resp, globalConfig.Callback.CallbackQuitGroup); err != nil { - return err - } - return nil +func (s *groupServer) webhookAfterDismissGroup(ctx context.Context, after *config.AfterConfig, req *callbackstruct.CallbackDisMissGroupReq) { + req.CallbackCommand = callbackstruct.CallbackAfterDisMissGroupCommand + s.webhookClient.AsyncPost(ctx, req.GetCallbackCommand(), req, &callbackstruct.CallbackDisMissGroupResp{}, after) } -func CallbackApplyJoinGroupBefore(ctx context.Context, globalConfig *config.GlobalConfig, req *callbackstruct.CallbackJoinGroupReq) (err error) { - if !globalConfig.Callback.CallbackBeforeJoinGroup.Enable { +func (s *groupServer) webhookBeforeApplyJoinGroup(ctx context.Context, before *config.BeforeConfig, req *callbackstruct.CallbackJoinGroupReq) (err error) { + return webhook.WithCondition(ctx, before, func(ctx context.Context) error { + req.CallbackCommand = callbackstruct.CallbackBeforeJoinGroupCommand + resp := &callbackstruct.CallbackJoinGroupResp{} + if err := s.webhookClient.SyncPost(ctx, req.GetCallbackCommand(), req, resp, before); err != nil { + return err + } return nil - } - - req.CallbackCommand = callbackstruct.CallbackBeforeJoinGroupCommand - - resp := &callbackstruct.CallbackJoinGroupResp{} - if err = http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, req, resp, globalConfig.Callback.CallbackBeforeJoinGroup); err != nil { - return err - } - - return nil + }) } -func CallbackAfterTransferGroupOwner(ctx context.Context, globalConfig *config.GlobalConfig, req *pbgroup.TransferGroupOwnerReq) (err error) { - if !globalConfig.Callback.CallbackAfterTransferGroupOwner.Enable { - return nil - } - +func (s *groupServer) webhookAfterTransferGroupOwner(ctx context.Context, after *config.AfterConfig, req *group.TransferGroupOwnerReq) { cbReq := &callbackstruct.CallbackTransferGroupOwnerReq{ - CallbackCommand: callbackstruct.CallbackAfterTransferGroupOwner, + CallbackCommand: callbackstruct.CallbackAfterTransferGroupOwnerCommand, GroupID: req.GroupID, OldOwnerUserID: req.OldOwnerUserID, NewOwnerUserID: req.NewOwnerUserID, } - - resp := &callbackstruct.CallbackTransferGroupOwnerResp{} - if err = http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, cbReq, resp, globalConfig.Callback.CallbackAfterTransferGroupOwner); err != nil { - return err - } - return nil + s.webhookClient.AsyncPost(ctx, cbReq.GetCallbackCommand(), cbReq, &callbackstruct.CallbackTransferGroupOwnerResp{}, after) } -func CallbackBeforeInviteUserToGroup(ctx context.Context, globalConfig *config.GlobalConfig, req *group.InviteUserToGroupReq) (err error) { - if !globalConfig.Callback.CallbackBeforeInviteUserToGroup.Enable { - return nil - } - callbackReq := &callbackstruct.CallbackBeforeInviteUserToGroupReq{ - CallbackCommand: callbackstruct.CallbackBeforeInviteJoinGroupCommand, - OperationID: mcontext.GetOperationID(ctx), - GroupID: req.GroupID, - Reason: req.Reason, - InvitedUserIDs: req.InvitedUserIDs, - } +func (s *groupServer) webhookBeforeInviteUserToGroup(ctx context.Context, before *config.BeforeConfig, req *group.InviteUserToGroupReq) (err error) { + return webhook.WithCondition(ctx, before, func(ctx context.Context) error { + cbReq := &callbackstruct.CallbackBeforeInviteUserToGroupReq{ + CallbackCommand: callbackstruct.CallbackBeforeInviteJoinGroupCommand, + OperationID: mcontext.GetOperationID(ctx), + GroupID: req.GroupID, + Reason: req.Reason, + InvitedUserIDs: req.InvitedUserIDs, + } - resp := &callbackstruct.CallbackBeforeInviteUserToGroupResp{} - err = http.CallBackPostReturn( - ctx, - globalConfig.Callback.CallbackUrl, - callbackReq, - resp, - globalConfig.Callback.CallbackBeforeInviteUserToGroup, - ) + resp := &callbackstruct.CallbackBeforeInviteUserToGroupResp{} + if err := s.webhookClient.SyncPost(ctx, cbReq.GetCallbackCommand(), cbReq, resp, before); err != nil { + return err + } - if err != nil { - return err - } - - if len(resp.RefusedMembersAccount) > 0 { - // Handle the scenario where certain members are refused - // You might want to update the req.Members list or handle it as per your business logic - } - return nil + if len(resp.RefusedMembersAccount) > 0 { + // Handle the scenario where certain members are refused + // You might want to update the req.Members list or handle it as per your business logic + } + return nil + }) } -func CallbackAfterJoinGroup(ctx context.Context, globalConfig *config.GlobalConfig, req *group.JoinGroupReq) error { - if !globalConfig.Callback.CallbackAfterJoinGroup.Enable { - return nil - } - callbackReq := &callbackstruct.CallbackAfterJoinGroupReq{ +func (s *groupServer) webhookAfterJoinGroup(ctx context.Context, after *config.AfterConfig, req *group.JoinGroupReq) { + cbReq := &callbackstruct.CallbackAfterJoinGroupReq{ CallbackCommand: callbackstruct.CallbackAfterJoinGroupCommand, OperationID: mcontext.GetOperationID(ctx), GroupID: req.GroupID, @@ -340,68 +261,60 @@ func CallbackAfterJoinGroup(ctx context.Context, globalConfig *config.GlobalConf JoinSource: req.JoinSource, InviterUserID: req.InviterUserID, } - resp := &callbackstruct.CallbackAfterJoinGroupResp{} - if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, callbackReq, resp, globalConfig.Callback.CallbackAfterJoinGroup); err != nil { - return err - } - return nil + s.webhookClient.AsyncPost(ctx, cbReq.GetCallbackCommand(), cbReq, &callbackstruct.CallbackAfterJoinGroupResp{}, after) } -func CallbackBeforeSetGroupInfo(ctx context.Context, globalConfig *config.GlobalConfig, req *group.SetGroupInfoReq) error { - if !globalConfig.Callback.CallbackBeforeSetGroupInfo.Enable { - return nil - } - callbackReq := &callbackstruct.CallbackBeforeSetGroupInfoReq{ - CallbackCommand: callbackstruct.CallbackBeforeSetGroupInfoCommand, - GroupID: req.GroupInfoForSet.GroupID, - Notification: req.GroupInfoForSet.Notification, - Introduction: req.GroupInfoForSet.Introduction, - FaceURL: req.GroupInfoForSet.FaceURL, - GroupName: req.GroupInfoForSet.GroupName, - } +func (s *groupServer) webhookBeforeSetGroupInfo(ctx context.Context, before *config.BeforeConfig, req *group.SetGroupInfoReq) error { + return webhook.WithCondition(ctx, before, func(ctx context.Context) error { + cbReq := &callbackstruct.CallbackBeforeSetGroupInfoReq{ + CallbackCommand: callbackstruct.CallbackBeforeSetGroupInfoCommand, + GroupID: req.GroupInfoForSet.GroupID, + Notification: req.GroupInfoForSet.Notification, + Introduction: req.GroupInfoForSet.Introduction, + FaceURL: req.GroupInfoForSet.FaceURL, + GroupName: req.GroupInfoForSet.GroupName, + } + if req.GroupInfoForSet.Ex != nil { + cbReq.Ex = req.GroupInfoForSet.Ex.Value + } + log.ZDebug(ctx, "debug CallbackBeforeSetGroupInfo", "ex", cbReq.Ex) + if req.GroupInfoForSet.NeedVerification != nil { + cbReq.NeedVerification = req.GroupInfoForSet.NeedVerification.Value + } + if req.GroupInfoForSet.LookMemberInfo != nil { + cbReq.LookMemberInfo = req.GroupInfoForSet.LookMemberInfo.Value + } + if req.GroupInfoForSet.ApplyMemberFriend != nil { + cbReq.ApplyMemberFriend = req.GroupInfoForSet.ApplyMemberFriend.Value + } + resp := &callbackstruct.CallbackBeforeSetGroupInfoResp{} - if req.GroupInfoForSet.Ex != nil { - callbackReq.Ex = req.GroupInfoForSet.Ex.Value - } - log.ZDebug(ctx, "debug CallbackBeforeSetGroupInfo", callbackReq.Ex) - if req.GroupInfoForSet.NeedVerification != nil { - callbackReq.NeedVerification = req.GroupInfoForSet.NeedVerification.Value - } - if req.GroupInfoForSet.LookMemberInfo != nil { - callbackReq.LookMemberInfo = req.GroupInfoForSet.LookMemberInfo.Value - } - if req.GroupInfoForSet.ApplyMemberFriend != nil { - callbackReq.ApplyMemberFriend = req.GroupInfoForSet.ApplyMemberFriend.Value - } - resp := &callbackstruct.CallbackBeforeSetGroupInfoResp{} - - if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, callbackReq, resp, globalConfig.Callback.CallbackBeforeSetGroupInfo); err != nil { - return err - } + if err := s.webhookClient.SyncPost(ctx, cbReq.GetCallbackCommand(), cbReq, resp, before); err != nil { + return err + } - if resp.Ex != nil { - req.GroupInfoForSet.Ex = wrapperspb.String(*resp.Ex) - } - if resp.NeedVerification != nil { - req.GroupInfoForSet.NeedVerification = wrapperspb.Int32(*resp.NeedVerification) - } - if resp.LookMemberInfo != nil { - req.GroupInfoForSet.LookMemberInfo = wrapperspb.Int32(*resp.LookMemberInfo) - } - if resp.ApplyMemberFriend != nil { - req.GroupInfoForSet.ApplyMemberFriend = wrapperspb.Int32(*resp.ApplyMemberFriend) - } - utils.NotNilReplace(&req.GroupInfoForSet.GroupID, &resp.GroupID) - utils.NotNilReplace(&req.GroupInfoForSet.GroupName, &resp.GroupName) - utils.NotNilReplace(&req.GroupInfoForSet.FaceURL, &resp.FaceURL) - utils.NotNilReplace(&req.GroupInfoForSet.Introduction, &resp.Introduction) - return nil -} -func CallbackAfterSetGroupInfo(ctx context.Context, globalConfig *config.GlobalConfig, req *group.SetGroupInfoReq) error { - if !globalConfig.Callback.CallbackAfterSetGroupInfo.Enable { + if resp.Ex != nil { + req.GroupInfoForSet.Ex = wrapperspb.String(*resp.Ex) + } + if resp.NeedVerification != nil { + req.GroupInfoForSet.NeedVerification = wrapperspb.Int32(*resp.NeedVerification) + } + if resp.LookMemberInfo != nil { + req.GroupInfoForSet.LookMemberInfo = wrapperspb.Int32(*resp.LookMemberInfo) + } + if resp.ApplyMemberFriend != nil { + req.GroupInfoForSet.ApplyMemberFriend = wrapperspb.Int32(*resp.ApplyMemberFriend) + } + datautil.NotNilReplace(&req.GroupInfoForSet.GroupID, &resp.GroupID) + datautil.NotNilReplace(&req.GroupInfoForSet.GroupName, &resp.GroupName) + datautil.NotNilReplace(&req.GroupInfoForSet.FaceURL, &resp.FaceURL) + datautil.NotNilReplace(&req.GroupInfoForSet.Introduction, &resp.Introduction) return nil - } - callbackReq := &callbackstruct.CallbackAfterSetGroupInfoReq{ + }) +} + +func (s *groupServer) webhookAfterSetGroupInfo(ctx context.Context, after *config.AfterConfig, req *group.SetGroupInfoReq) { + cbReq := &callbackstruct.CallbackAfterSetGroupInfoReq{ CallbackCommand: callbackstruct.CallbackAfterSetGroupInfoCommand, GroupID: req.GroupInfoForSet.GroupID, Notification: req.GroupInfoForSet.Notification, @@ -410,20 +323,16 @@ func CallbackAfterSetGroupInfo(ctx context.Context, globalConfig *config.GlobalC GroupName: req.GroupInfoForSet.GroupName, } if req.GroupInfoForSet.Ex != nil { - callbackReq.Ex = &req.GroupInfoForSet.Ex.Value + cbReq.Ex = &req.GroupInfoForSet.Ex.Value } if req.GroupInfoForSet.NeedVerification != nil { - callbackReq.NeedVerification = &req.GroupInfoForSet.NeedVerification.Value + cbReq.NeedVerification = &req.GroupInfoForSet.NeedVerification.Value } if req.GroupInfoForSet.LookMemberInfo != nil { - callbackReq.LookMemberInfo = &req.GroupInfoForSet.LookMemberInfo.Value + cbReq.LookMemberInfo = &req.GroupInfoForSet.LookMemberInfo.Value } if req.GroupInfoForSet.ApplyMemberFriend != nil { - callbackReq.ApplyMemberFriend = &req.GroupInfoForSet.ApplyMemberFriend.Value - } - resp := &callbackstruct.CallbackAfterSetGroupInfoResp{} - if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, callbackReq, resp, globalConfig.Callback.CallbackAfterSetGroupInfo); err != nil { - return err + cbReq.ApplyMemberFriend = &req.GroupInfoForSet.ApplyMemberFriend.Value } - return nil + s.webhookClient.AsyncPost(ctx, cbReq.GetCallbackCommand(), cbReq, &callbackstruct.CallbackAfterSetGroupInfoResp{}, after) } diff --git a/internal/rpc/group/convert.go b/internal/rpc/group/convert.go index ab4d3a2a1b..86978ce3ae 100644 --- a/internal/rpc/group/convert.go +++ b/internal/rpc/group/convert.go @@ -15,8 +15,8 @@ package group import ( - "github.com/OpenIMSDK/protocol/sdkws" "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" + "github.com/openimsdk/protocol/sdkws" ) func (s *groupServer) groupDB2PB(group *relation.GroupModel, ownerUserID string, memberCount uint32) *sdkws.GroupInfo { @@ -41,10 +41,7 @@ func (s *groupServer) groupDB2PB(group *relation.GroupModel, ownerUserID string, } } -func (s *groupServer) groupMemberDB2PB( - member *relation.GroupMemberModel, - appMangerLevel int32, -) *sdkws.GroupMemberFullInfo { +func (s *groupServer) groupMemberDB2PB(member *relation.GroupMemberModel, appMangerLevel int32) *sdkws.GroupMemberFullInfo { return &sdkws.GroupMemberFullInfo{ GroupID: member.GroupID, UserID: member.UserID, diff --git a/internal/rpc/group/db_map.go b/internal/rpc/group/db_map.go index e4c18bb17b..b4b503b950 100644 --- a/internal/rpc/group/db_map.go +++ b/internal/rpc/group/db_map.go @@ -18,9 +18,9 @@ import ( "context" "time" - pbgroup "github.com/OpenIMSDK/protocol/group" - "github.com/OpenIMSDK/protocol/sdkws" - "github.com/OpenIMSDK/tools/mcontext" + pbgroup "github.com/openimsdk/protocol/group" + "github.com/openimsdk/protocol/sdkws" + "github.com/openimsdk/tools/mcontext" ) func UpdateGroupInfoMap(ctx context.Context, group *sdkws.GroupInfoForSet) map[string]any { diff --git a/internal/rpc/group/fill.go b/internal/rpc/group/fill.go index ac539de198..c504db8d6e 100644 --- a/internal/rpc/group/fill.go +++ b/internal/rpc/group/fill.go @@ -21,5 +21,5 @@ import ( ) func (s *groupServer) PopulateGroupMember(ctx context.Context, members ...*relationtb.GroupMemberModel) error { - return s.Notification.PopulateGroupMember(ctx, members...) + return s.notification.PopulateGroupMember(ctx, members...) } diff --git a/internal/rpc/group/group.go b/internal/rpc/group/group.go index 92d9e27d6a..13bd7f9beb 100644 --- a/internal/rpc/group/group.go +++ b/internal/rpc/group/group.go @@ -17,96 +17,108 @@ package group import ( "context" "fmt" + "github.com/openimsdk/open-im-server/v3/pkg/common/config" + "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" + "github.com/openimsdk/open-im-server/v3/pkg/common/webhook" "math/big" "math/rand" "strconv" "strings" "time" - "github.com/OpenIMSDK/protocol/constant" - pbconversation "github.com/OpenIMSDK/protocol/conversation" - pbgroup "github.com/OpenIMSDK/protocol/group" - "github.com/OpenIMSDK/protocol/sdkws" - "github.com/OpenIMSDK/protocol/wrapperspb" - "github.com/OpenIMSDK/tools/discoveryregistry" - "github.com/OpenIMSDK/tools/errs" - "github.com/OpenIMSDK/tools/log" - "github.com/OpenIMSDK/tools/mcontext" - "github.com/OpenIMSDK/tools/mw/specialerror" - "github.com/OpenIMSDK/tools/tx" - "github.com/OpenIMSDK/tools/utils" "github.com/openimsdk/open-im-server/v3/pkg/authverify" "github.com/openimsdk/open-im-server/v3/pkg/callbackstruct" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/convert" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" "github.com/openimsdk/open-im-server/v3/pkg/common/db/mgo" relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/unrelation" + "github.com/openimsdk/open-im-server/v3/pkg/common/servererrs" "github.com/openimsdk/open-im-server/v3/pkg/msgprocessor" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient/grouphash" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient/notification" + "github.com/openimsdk/protocol/constant" + pbconversation "github.com/openimsdk/protocol/conversation" + pbgroup "github.com/openimsdk/protocol/group" + "github.com/openimsdk/protocol/sdkws" + "github.com/openimsdk/protocol/wrapperspb" + "github.com/openimsdk/tools/db/mongoutil" + "github.com/openimsdk/tools/db/redisutil" + "github.com/openimsdk/tools/discovery" + "github.com/openimsdk/tools/errs" + "github.com/openimsdk/tools/log" + "github.com/openimsdk/tools/mcontext" + "github.com/openimsdk/tools/mw/specialerror" + "github.com/openimsdk/tools/utils/datautil" + "github.com/openimsdk/tools/utils/encrypt" "google.golang.org/grpc" ) -func Start(config *config.GlobalConfig, client discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) error { - mongo, err := unrelation.NewMongo(config) +type groupServer struct { + db controller.GroupDatabase + user rpcclient.UserRpcClient + notification *GroupNotificationSender + conversationRpcClient rpcclient.ConversationRpcClient + msgRpcClient rpcclient.MessageRpcClient + config *Config + webhookClient *webhook.Client +} + +type Config struct { + RpcConfig config.Group + RedisConfig config.Redis + MongodbConfig config.Mongo + ZookeeperConfig config.ZooKeeper + NotificationConfig config.Notification + Share config.Share + WebhooksConfig config.Webhooks + LocalCacheConfig config.LocalCache +} + +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 } - rdb, err := cache.NewRedis(config) + rdb, err := redisutil.NewRedisClient(ctx, config.RedisConfig.Build()) if err != nil { return err } - groupDB, err := mgo.NewGroupMongo(mongo.GetDatabase(config.Mongo.Database)) + groupDB, err := mgo.NewGroupMongo(mgocli.GetDB()) if err != nil { return err } - groupMemberDB, err := mgo.NewGroupMember(mongo.GetDatabase(config.Mongo.Database)) + groupMemberDB, err := mgo.NewGroupMember(mgocli.GetDB()) if err != nil { return err } - groupRequestDB, err := mgo.NewGroupRequestMgo(mongo.GetDatabase(config.Mongo.Database)) + groupRequestDB, err := mgo.NewGroupRequestMgo(mgocli.GetDB()) if err != nil { return err } - userRpcClient := rpcclient.NewUserRpcClient(client, config) - msgRpcClient := rpcclient.NewMessageRpcClient(client, config) - conversationRpcClient := rpcclient.NewConversationRpcClient(client, config) + userRpcClient := rpcclient.NewUserRpcClient(client, config.Share.RpcRegisterName.User, config.Share.IMAdminUserID) + msgRpcClient := rpcclient.NewMessageRpcClient(client, config.Share.RpcRegisterName.Msg) + conversationRpcClient := rpcclient.NewConversationRpcClient(client, config.Share.RpcRegisterName.Conversation) var gs groupServer - database := controller.NewGroupDatabase(rdb, groupDB, groupMemberDB, groupRequestDB, tx.NewMongo(mongo.GetClient()), grouphash.NewGroupHashFromGroupServer(&gs)) + database := controller.NewGroupDatabase(rdb, &config.LocalCacheConfig, groupDB, groupMemberDB, groupRequestDB, mgocli.GetTx(), grouphash.NewGroupHashFromGroupServer(&gs)) gs.db = database - gs.User = userRpcClient - gs.Notification = notification.NewGroupNotificationSender(database, &msgRpcClient, &userRpcClient, config, func(ctx context.Context, userIDs []string) ([]notification.CommonUser, error) { + gs.user = userRpcClient + gs.notification = NewGroupNotificationSender(database, &msgRpcClient, &userRpcClient, config, func(ctx context.Context, userIDs []string) ([]notification.CommonUser, error) { users, err := userRpcClient.GetUsersInfo(ctx, userIDs) if err != nil { return nil, err } - return utils.Slice(users, func(e *sdkws.UserInfo) notification.CommonUser { return e }), nil + return datautil.Slice(users, func(e *sdkws.UserInfo) notification.CommonUser { return e }), nil }) + cache.InitLocalCache(&config.LocalCacheConfig) gs.conversationRpcClient = conversationRpcClient gs.msgRpcClient = msgRpcClient gs.config = config + gs.webhookClient = webhook.NewWebhookClient(config.WebhooksConfig.URL) pbgroup.RegisterGroupServer(server, &gs) return nil } -type groupServer struct { - db controller.GroupDatabase - User rpcclient.UserRpcClient - Notification *notification.GroupNotificationSender - conversationRpcClient rpcclient.ConversationRpcClient - msgRpcClient rpcclient.MessageRpcClient - config *config.GlobalConfig -} - -func (s *groupServer) GetJoinedGroupIDs(ctx context.Context, req *pbgroup.GetJoinedGroupIDsReq) (*pbgroup.GetJoinedGroupIDsResp, error) { - //TODO implement me - panic("implement me") -} - func (s *groupServer) NotificationUserInfoUpdate(ctx context.Context, req *pbgroup.NotificationUserInfoUpdateReq) (*pbgroup.NotificationUserInfoUpdateResp, error) { members, err := s.db.FindGroupMemberUser(ctx, nil, req.UserID) if err != nil { @@ -120,9 +132,7 @@ func (s *groupServer) NotificationUserInfoUpdate(ctx context.Context, req *pbgro groupIDs = append(groupIDs, member.GroupID) } for _, groupID := range groupIDs { - if err = s.Notification.GroupMemberInfoSetNotification(ctx, groupID, req.UserID); err != nil { - return nil, err - } + s.notification.GroupMemberInfoSetNotification(ctx, groupID, req.UserID) } if err = s.db.DeleteGroupMemberHash(ctx, groupIDs); err != nil { return nil, err @@ -132,13 +142,13 @@ func (s *groupServer) NotificationUserInfoUpdate(ctx context.Context, req *pbgro } func (s *groupServer) CheckGroupAdmin(ctx context.Context, groupID string) error { - if !authverify.IsAppManagerUid(ctx, s.config) { + if !authverify.IsAppManagerUid(ctx, s.config.Share.IMAdminUserID) { groupMember, err := s.db.TakeGroupMember(ctx, groupID, mcontext.GetOpUserID(ctx)) if err != nil { return err } if !(groupMember.RoleLevel == constant.GroupOwner || groupMember.RoleLevel == constant.GroupAdmin) { - return errs.ErrNoPermission.Wrap("no group owner or admin") + return errs.ErrNoPermission.WrapMsg("no group owner or admin") } } return nil @@ -148,11 +158,11 @@ func (s *groupServer) GetPublicUserInfoMap(ctx context.Context, userIDs []string if len(userIDs) == 0 { return map[string]*sdkws.PublicUserInfo{}, nil } - users, err := s.User.GetPublicUserInfos(ctx, userIDs, complete) + users, err := s.user.GetPublicUserInfos(ctx, userIDs, complete) if err != nil { return nil, err } - return utils.SliceToMapAny(users, func(e *sdkws.PublicUserInfo) (string, *sdkws.PublicUserInfo) { + return datautil.SliceToMapAny(users, func(e *sdkws.PublicUserInfo) (string, *sdkws.PublicUserInfo) { return e.UserID, e }), nil } @@ -165,7 +175,7 @@ func (s *groupServer) GenGroupID(ctx context.Context, groupID *string) error { if *groupID != "" { _, err := s.db.TakeGroup(ctx, *groupID) if err == nil { - return errs.ErrGroupIDExisted.Wrap("group id existed " + *groupID) + return servererrs.ErrGroupIDExisted.WrapMsg("group id existed " + *groupID) } else if s.IsNotFound(err) { return nil } else { @@ -173,7 +183,7 @@ func (s *groupServer) GenGroupID(ctx context.Context, groupID *string) error { } } for i := 0; i < 10; i++ { - id := utils.Md5(strings.Join([]string{mcontext.GetOperationID(ctx), strconv.FormatInt(time.Now().UnixNano(), 10), strconv.Itoa(rand.Int())}, ",;,")) + id := encrypt.Md5(strings.Join([]string{mcontext.GetOperationID(ctx), strconv.FormatInt(time.Now().UnixNano(), 10), strconv.Itoa(rand.Int())}, ",;,")) bi := big.NewInt(0) bi.SetString(id[0:8], 16) id = bi.String() @@ -187,43 +197,49 @@ func (s *groupServer) GenGroupID(ctx context.Context, groupID *string) error { return err } } - return errs.ErrData.Wrap("group id gen error") + return servererrs.ErrData.WrapMsg("group id gen error") } func (s *groupServer) CreateGroup(ctx context.Context, req *pbgroup.CreateGroupReq) (*pbgroup.CreateGroupResp, error) { if req.GroupInfo.GroupType != constant.WorkingGroup { - return nil, errs.ErrArgs.Wrap(fmt.Sprintf("group type only supports %d", constant.WorkingGroup)) + return nil, errs.ErrArgs.WrapMsg(fmt.Sprintf("group type only supports %d", constant.WorkingGroup)) } if req.OwnerUserID == "" { - return nil, errs.ErrArgs.Wrap("no group owner") + return nil, errs.ErrArgs.WrapMsg("no group owner") } - if err := authverify.CheckAccessV3(ctx, req.OwnerUserID, s.config); err != nil { + if err := authverify.CheckAccessV3(ctx, req.OwnerUserID, s.config.Share.IMAdminUserID); err != nil { + return nil, err } userIDs := append(append(req.MemberUserIDs, req.AdminUserIDs...), req.OwnerUserID) opUserID := mcontext.GetOpUserID(ctx) - if !utils.Contain(opUserID, userIDs...) { + if !datautil.Contain(opUserID, userIDs...) { userIDs = append(userIDs, opUserID) } - if utils.Duplicate(userIDs) { - return nil, errs.ErrArgs.Wrap("group member repeated") + + if datautil.Duplicate(userIDs) { + return nil, errs.ErrArgs.WrapMsg("group member repeated") } - userMap, err := s.User.GetUsersInfoMap(ctx, userIDs) + + userMap, err := s.user.GetUsersInfoMap(ctx, userIDs) if err != nil { return nil, err } + if len(userMap) != len(userIDs) { - return nil, errs.ErrUserIDNotFound.Wrap("user not found") + return nil, servererrs.ErrUserIDNotFound.WrapMsg("user not found") } - // Callback Before create Group - if err := CallbackBeforeCreateGroup(ctx, s.config, req); err != nil { + + if err := s.webhookBeforeCreateGroup(ctx, &s.config.WebhooksConfig.BeforeCreateGroup, req); err != nil && err != servererrs.ErrCallbackContinue { return nil, err } + var groupMembers []*relationtb.GroupMemberModel group := convert.Pb2DBGroupInfo(req.GroupInfo) if err := s.GenGroupID(ctx, &group.GroupID); err != nil { return nil, err } + joinGroup := func(userID string, roleLevel int32) error { groupMember := &relationtb.GroupMemberModel{ GroupID: group.GroupID, @@ -235,7 +251,8 @@ func (s *groupServer) CreateGroup(ctx context.Context, req *pbgroup.CreateGroupR JoinTime: time.Now(), MuteEndTime: time.UnixMilli(0), } - if err := CallbackBeforeMemberJoinGroup(ctx, s.config, groupMember, group.Ex); err != nil { + + if err := s.webhookBeforeMemberJoinGroup(ctx, &s.config.WebhooksConfig.BeforeMemberJoinGroup, groupMember, group.Ex); err != nil && err != servererrs.ErrCallbackContinue { return err } groupMembers = append(groupMembers, groupMember) @@ -258,6 +275,7 @@ func (s *groupServer) CreateGroup(ctx context.Context, req *pbgroup.CreateGroupR return nil, err } resp := &pbgroup.CreateGroupResp{GroupInfo: &sdkws.GroupInfo{}} + resp.GroupInfo = convert.Db2PbGroupInfo(group, req.OwnerUserID, uint32(len(userIDs))) resp.GroupInfo.MemberCount = uint32(len(userIDs)) tips := &sdkws.GroupCreatedTips{ @@ -276,11 +294,10 @@ func (s *groupServer) CreateGroup(ctx context.Context, req *pbgroup.CreateGroupR if req.GroupInfo.GroupType == constant.SuperGroup { go func() { for _, userID := range userIDs { - s.Notification.SuperGroupNotification(ctx, userID, userID) + s.notification.SuperGroupNotification(ctx, userID, userID) } }() } else { - // s.Notification.GroupCreatedNotification(ctx, group, groupMembers, userMap) tips := &sdkws.GroupCreatedTips{ Group: resp.GroupInfo, OperationTime: group.CreateTime.UnixMilli(), @@ -294,8 +311,9 @@ func (s *groupServer) CreateGroup(ctx context.Context, req *pbgroup.CreateGroupR break } } - s.Notification.GroupCreatedNotification(ctx, tips) + s.notification.GroupCreatedNotification(ctx, tips) } + reqCallBackAfter := &pbgroup.CreateGroupReq{ MemberUserIDs: userIDs, GroupInfo: resp.GroupInfo, @@ -303,27 +321,25 @@ func (s *groupServer) CreateGroup(ctx context.Context, req *pbgroup.CreateGroupR AdminUserIDs: req.AdminUserIDs, } - if err := CallbackAfterCreateGroup(ctx, s.config, reqCallBackAfter); err != nil { - return nil, err - } + s.webhookAfterCreateGroup(ctx, &s.config.WebhooksConfig.AfterCreateGroup, reqCallBackAfter) return resp, nil } func (s *groupServer) GetJoinedGroupList(ctx context.Context, req *pbgroup.GetJoinedGroupListReq) (*pbgroup.GetJoinedGroupListResp, error) { - resp := &pbgroup.GetJoinedGroupListResp{} - if err := authverify.CheckAccessV3(ctx, req.FromUserID, s.config); err != nil { + if err := authverify.CheckAccessV3(ctx, req.FromUserID, s.config.Share.IMAdminUserID); err != nil { return nil, err } total, members, err := s.db.PageGetJoinGroup(ctx, req.FromUserID, req.Pagination) if err != nil { return nil, err } + var resp pbgroup.GetJoinedGroupListResp resp.Total = uint32(total) if len(members) == 0 { - return resp, nil + return &resp, nil } - groupIDs := utils.Slice(members, func(e *relationtb.GroupMemberModel) string { + groupIDs := datautil.Slice(members, func(e *relationtb.GroupMemberModel) string { return e.GroupID }) groups, err := s.db.FindGroup(ctx, groupIDs) @@ -341,10 +357,10 @@ func (s *groupServer) GetJoinedGroupList(ctx context.Context, req *pbgroup.GetJo if err := s.PopulateGroupMember(ctx, members...); err != nil { return nil, err } - ownerMap := utils.SliceToMap(owners, func(e *relationtb.GroupMemberModel) string { + ownerMap := datautil.SliceToMap(owners, func(e *relationtb.GroupMemberModel) string { return e.GroupID }) - resp.Groups = utils.Slice(utils.Order(groupIDs, groups, func(group *relationtb.GroupModel) string { + resp.Groups = datautil.Slice(datautil.Order(groupIDs, groups, func(group *relationtb.GroupModel) string { return group.GroupID }), func(group *relationtb.GroupModel) *sdkws.GroupInfo { var userID string @@ -353,17 +369,15 @@ func (s *groupServer) GetJoinedGroupList(ctx context.Context, req *pbgroup.GetJo } return convert.Db2PbGroupInfo(group, userID, groupMemberNum[group.GroupID]) }) - return resp, nil + return &resp, nil } func (s *groupServer) InviteUserToGroup(ctx context.Context, req *pbgroup.InviteUserToGroupReq) (*pbgroup.InviteUserToGroupResp, error) { - resp := &pbgroup.InviteUserToGroupResp{} - if len(req.InvitedUserIDs) == 0 { - return nil, errs.ErrArgs.Wrap("user empty") + return nil, errs.ErrArgs.WrapMsg("user empty") } - if utils.Duplicate(req.InvitedUserIDs) { - return nil, errs.ErrArgs.Wrap("userID duplicate") + if datautil.Duplicate(req.InvitedUserIDs) { + return nil, errs.ErrArgs.WrapMsg("userID duplicate") } group, err := s.db.TakeGroup(ctx, req.GroupID) if err != nil { @@ -371,18 +385,21 @@ func (s *groupServer) InviteUserToGroup(ctx context.Context, req *pbgroup.Invite } if group.Status == constant.GroupStatusDismissed { - return nil, errs.ErrDismissedAlready.Wrap() + return nil, servererrs.ErrDismissedAlready.WrapMsg("group dismissed checking group status found it dismissed") } - userMap, err := s.User.GetUsersInfoMap(ctx, req.InvitedUserIDs) + + userMap, err := s.user.GetUsersInfoMap(ctx, req.InvitedUserIDs) if err != nil { return nil, err } + if len(userMap) != len(req.InvitedUserIDs) { - return nil, errs.ErrRecordNotFound.Wrap("user not found") + return nil, errs.ErrRecordNotFound.WrapMsg("user not found") } + var groupMember *relationtb.GroupMemberModel var opUserID string - if !authverify.IsAppManagerUid(ctx, s.config) { + if !authverify.IsAppManagerUid(ctx, s.config.Share.IMAdminUserID) { opUserID = mcontext.GetOpUserID(ctx) var err error groupMember, err = s.db.TakeGroupMember(ctx, req.GroupID, opUserID) @@ -394,11 +411,12 @@ func (s *groupServer) InviteUserToGroup(ctx context.Context, req *pbgroup.Invite } } - if err := CallbackBeforeInviteUserToGroup(ctx, s.config, req); err != nil { + if err := s.webhookBeforeInviteUserToGroup(ctx, &s.config.WebhooksConfig.BeforeInviteUserToGroup, req); err != nil && err != servererrs.ErrCallbackContinue { return nil, err } + if group.NeedVerification == constant.AllNeedVerification { - if !authverify.IsAppManagerUid(ctx, s.config) { + if !authverify.IsAppManagerUid(ctx, s.config.Share.IMAdminUserID) { if !(groupMember.RoleLevel == constant.GroupOwner || groupMember.RoleLevel == constant.GroupAdmin) { var requests []*relationtb.GroupRequestModel for _, userID := range req.InvitedUserIDs { @@ -415,14 +433,14 @@ func (s *groupServer) InviteUserToGroup(ctx context.Context, req *pbgroup.Invite return nil, err } for _, request := range requests { - s.Notification.JoinGroupApplicationNotification(ctx, &pbgroup.JoinGroupReq{ + s.notification.JoinGroupApplicationNotification(ctx, &pbgroup.JoinGroupReq{ GroupID: request.GroupID, ReqMessage: request.ReqMsg, JoinSource: request.JoinSource, InviterUserID: request.InviterUserID, }) } - return resp, nil + return &pbgroup.InviteUserToGroupResp{}, nil } } } @@ -438,10 +456,12 @@ func (s *groupServer) InviteUserToGroup(ctx context.Context, req *pbgroup.Invite JoinTime: time.Now(), MuteEndTime: time.UnixMilli(0), } - if err := CallbackBeforeMemberJoinGroup(ctx, s.config, member, group.Ex); err != nil { + + if err := s.webhookBeforeMemberJoinGroup(ctx, &s.config.WebhooksConfig.BeforeMemberJoinGroup, groupMember, group.Ex); err != nil && err != servererrs.ErrCallbackContinue { return nil, err } groupMembers = append(groupMembers, member) + } if err := s.db.CreateGroup(ctx, nil, groupMembers); err != nil { return nil, err @@ -449,8 +469,8 @@ func (s *groupServer) InviteUserToGroup(ctx context.Context, req *pbgroup.Invite if err := s.conversationRpcClient.GroupChatFirstCreateConversation(ctx, req.GroupID, req.InvitedUserIDs); err != nil { return nil, err } - s.Notification.MemberInvitedNotification(ctx, req.GroupID, req.Reason, req.InvitedUserIDs) - return resp, nil + s.notification.MemberInvitedNotification(ctx, req.GroupID, req.Reason, req.InvitedUserIDs) + return &pbgroup.InviteUserToGroupResp{}, nil } func (s *groupServer) GetGroupAllMember(ctx context.Context, req *pbgroup.GetGroupAllMemberReq) (*pbgroup.GetGroupAllMemberResp, error) { @@ -461,15 +481,14 @@ func (s *groupServer) GetGroupAllMember(ctx context.Context, req *pbgroup.GetGro if err := s.PopulateGroupMember(ctx, members...); err != nil { return nil, err } - resp := &pbgroup.GetGroupAllMemberResp{} - resp.Members = utils.Slice(members, func(e *relationtb.GroupMemberModel) *sdkws.GroupMemberFullInfo { + var resp pbgroup.GetGroupAllMemberResp + resp.Members = datautil.Slice(members, func(e *relationtb.GroupMemberModel) *sdkws.GroupMemberFullInfo { return convert.Db2PbGroupMember(e) }) - return resp, nil + return &resp, nil } func (s *groupServer) GetGroupMemberList(ctx context.Context, req *pbgroup.GetGroupMemberListReq) (*pbgroup.GetGroupMemberListResp, error) { - resp := &pbgroup.GetGroupMemberListResp{} var ( total int64 members []*relationtb.GroupMemberModel @@ -501,31 +520,32 @@ func (s *groupServer) GetGroupMemberList(ctx context.Context, req *pbgroup.GetGr } } - GMembers := utils.Paginate(groupMembers, int(req.Pagination.GetPageNumber()), int(req.Pagination.GetShowNumber())) - resp.Members = utils.Batch(convert.Db2PbGroupMember, GMembers) - resp.Total = uint32(total) - return resp, nil - } - resp.Total = uint32(total) - resp.Members = utils.Batch(convert.Db2PbGroupMember, members) - return resp, nil + members := datautil.Paginate(groupMembers, int(req.Pagination.GetPageNumber()), int(req.Pagination.GetShowNumber())) + return &pbgroup.GetGroupMemberListResp{ + Total: uint32(total), + Members: datautil.Batch(convert.Db2PbGroupMember, members), + }, nil + } + return &pbgroup.GetGroupMemberListResp{ + Total: uint32(total), + Members: datautil.Batch(convert.Db2PbGroupMember, members), + }, nil } func (s *groupServer) KickGroupMember(ctx context.Context, req *pbgroup.KickGroupMemberReq) (*pbgroup.KickGroupMemberResp, error) { - resp := &pbgroup.KickGroupMemberResp{} group, err := s.db.TakeGroup(ctx, req.GroupID) if err != nil { return nil, err } if len(req.KickedUserIDs) == 0 { - return nil, errs.ErrArgs.Wrap("KickedUserIDs empty") + return nil, errs.ErrArgs.WrapMsg("KickedUserIDs empty") } - if utils.IsDuplicateStringSlice(req.KickedUserIDs) { - return nil, errs.ErrArgs.Wrap("KickedUserIDs duplicate") + if datautil.Duplicate(req.KickedUserIDs) { + return nil, errs.ErrArgs.WrapMsg("KickedUserIDs duplicate") } opUserID := mcontext.GetOpUserID(ctx) - if utils.IsContain(opUserID, req.KickedUserIDs) { - return nil, errs.ErrArgs.Wrap("opUserID in KickedUserIDs") + if datautil.Contain(opUserID, req.KickedUserIDs...) { + return nil, errs.ErrArgs.WrapMsg("opUserID in KickedUserIDs") } members, err := s.db.FindGroupMembers(ctx, req.GroupID, append(req.KickedUserIDs, opUserID)) if err != nil { @@ -538,27 +558,27 @@ func (s *groupServer) KickGroupMember(ctx context.Context, req *pbgroup.KickGrou for i, member := range members { memberMap[member.UserID] = members[i] } - isAppManagerUid := authverify.IsAppManagerUid(ctx, s.config) + isAppManagerUid := authverify.IsAppManagerUid(ctx, s.config.Share.IMAdminUserID) opMember := memberMap[opUserID] for _, userID := range req.KickedUserIDs { member, ok := memberMap[userID] if !ok { - return nil, errs.ErrUserIDNotFound.Wrap(userID) + return nil, servererrs.ErrUserIDNotFound.WrapMsg(userID) } if !isAppManagerUid { if opMember == nil { - return nil, errs.ErrNoPermission.Wrap("opUserID no in group") + return nil, errs.ErrNoPermission.WrapMsg("opUserID no in group") } switch opMember.RoleLevel { case constant.GroupOwner: case constant.GroupAdmin: if member.RoleLevel == constant.GroupOwner || member.RoleLevel == constant.GroupAdmin { - return nil, errs.ErrNoPermission.Wrap("group admins cannot remove the group owner and other admins") + return nil, errs.ErrNoPermission.WrapMsg("group admins cannot remove the group owner and other admins") } case constant.GroupOrdinaryUsers: - return nil, errs.ErrNoPermission.Wrap("opUserID no permission") + return nil, errs.ErrNoPermission.WrapMsg("opUserID no permission") default: - return nil, errs.ErrNoPermission.Wrap("opUserID roleLevel unknown") + return nil, errs.ErrNoPermission.WrapMsg("opUserID roleLevel unknown") } } } @@ -605,24 +625,21 @@ func (s *groupServer) KickGroupMember(ctx context.Context, req *pbgroup.KickGrou for _, userID := range req.KickedUserIDs { tips.KickedUserList = append(tips.KickedUserList, convert.Db2PbGroupMember(memberMap[userID])) } - s.Notification.MemberKickedNotification(ctx, tips) + s.notification.MemberKickedNotification(ctx, tips) if err := s.deleteMemberAndSetConversationSeq(ctx, req.GroupID, req.KickedUserIDs); err != nil { return nil, err } + s.webhookAfterKickGroupMember(ctx, &s.config.WebhooksConfig.AfterKickGroupMember, req) - if err := CallbackKillGroupMember(ctx, s.config, req); err != nil { - return nil, err - } - return resp, nil + return &pbgroup.KickGroupMemberResp{}, nil } func (s *groupServer) GetGroupMembersInfo(ctx context.Context, req *pbgroup.GetGroupMembersInfoReq) (*pbgroup.GetGroupMembersInfoResp, error) { - resp := &pbgroup.GetGroupMembersInfoResp{} if len(req.UserIDs) == 0 { - return nil, errs.ErrArgs.Wrap("userIDs empty") + return nil, errs.ErrArgs.WrapMsg("userIDs empty") } if req.GroupID == "" { - return nil, errs.ErrArgs.Wrap("groupID empty") + return nil, errs.ErrArgs.WrapMsg("groupID empty") } members, err := s.db.FindGroupMembers(ctx, req.GroupID, req.UserIDs) if err != nil { @@ -631,10 +648,11 @@ func (s *groupServer) GetGroupMembersInfo(ctx context.Context, req *pbgroup.GetG if err := s.PopulateGroupMember(ctx, members...); err != nil { return nil, err } - resp.Members = utils.Slice(members, func(e *relationtb.GroupMemberModel) *sdkws.GroupMemberFullInfo { - return convert.Db2PbGroupMember(e) - }) - return resp, nil + return &pbgroup.GetGroupMembersInfoResp{ + Members: datautil.Slice(members, func(e *relationtb.GroupMemberModel) *sdkws.GroupMemberFullInfo { + return convert.Db2PbGroupMember(e) + }), + }, nil } // GetGroupApplicationList handles functions that get a list of group requests. @@ -660,20 +678,20 @@ func (s *groupServer) GetGroupApplicationList(ctx context.Context, req *pbgroup. for _, gr := range groupRequests { userIDs = append(userIDs, gr.UserID) } - userIDs = utils.Distinct(userIDs) - userMap, err := s.User.GetPublicUserInfoMap(ctx, userIDs, true) + userIDs = datautil.Distinct(userIDs) + userMap, err := s.user.GetPublicUserInfoMap(ctx, userIDs, true) if err != nil { return nil, err } - groups, err := s.db.FindGroup(ctx, utils.Distinct(groupIDs)) + groups, err := s.db.FindGroup(ctx, datautil.Distinct(groupIDs)) if err != nil { return nil, err } - groupMap := utils.SliceToMap(groups, func(e *relationtb.GroupModel) string { + groupMap := datautil.SliceToMap(groups, func(e *relationtb.GroupModel) string { return e.GroupID }) - if ids := utils.Single(utils.Keys(groupMap), groupIDs); len(ids) > 0 { - return nil, errs.ErrGroupIDNotFound.Wrap(strings.Join(ids, ",")) + if ids := datautil.Single(datautil.Keys(groupMap), groupIDs); len(ids) > 0 { + return nil, servererrs.ErrGroupIDNotFound.WrapMsg(strings.Join(ids, ",")) } groupMemberNumMap, err := s.db.MapGroupMemberNum(ctx, groupIDs) if err != nil { @@ -686,10 +704,10 @@ func (s *groupServer) GetGroupApplicationList(ctx context.Context, req *pbgroup. if err := s.PopulateGroupMember(ctx, owners...); err != nil { return nil, err } - ownerMap := utils.SliceToMap(owners, func(e *relationtb.GroupMemberModel) string { + ownerMap := datautil.SliceToMap(owners, func(e *relationtb.GroupMemberModel) string { return e.GroupID }) - resp.GroupRequests = utils.Slice(groupRequests, func(e *relationtb.GroupRequestModel) *sdkws.GroupRequest { + resp.GroupRequests = datautil.Slice(groupRequests, func(e *relationtb.GroupRequestModel) *sdkws.GroupRequest { var ownerUserID string if owner, ok := ownerMap[e.GroupID]; ok { ownerUserID = owner.UserID @@ -700,9 +718,8 @@ func (s *groupServer) GetGroupApplicationList(ctx context.Context, req *pbgroup. } func (s *groupServer) GetGroupsInfo(ctx context.Context, req *pbgroup.GetGroupsInfoReq) (*pbgroup.GetGroupsInfoResp, error) { - resp := &pbgroup.GetGroupsInfoResp{} if len(req.GroupIDs) == 0 { - return nil, errs.ErrArgs.Wrap("groupID is empty") + return nil, errs.ErrArgs.WrapMsg("groupID is empty") } groups, err := s.db.FindGroup(ctx, req.GroupIDs) if err != nil { @@ -719,31 +736,31 @@ func (s *groupServer) GetGroupsInfo(ctx context.Context, req *pbgroup.GetGroupsI if err := s.PopulateGroupMember(ctx, owners...); err != nil { return nil, err } - ownerMap := utils.SliceToMap(owners, func(e *relationtb.GroupMemberModel) string { + ownerMap := datautil.SliceToMap(owners, func(e *relationtb.GroupMemberModel) string { return e.GroupID }) - resp.GroupInfos = utils.Slice(groups, func(e *relationtb.GroupModel) *sdkws.GroupInfo { - var ownerUserID string - if owner, ok := ownerMap[e.GroupID]; ok { - ownerUserID = owner.UserID - } - return convert.Db2PbGroupInfo(e, ownerUserID, groupMemberNumMap[e.GroupID]) - }) - return resp, nil + return &pbgroup.GetGroupsInfoResp{ + GroupInfos: datautil.Slice(groups, func(e *relationtb.GroupModel) *sdkws.GroupInfo { + var ownerUserID string + if owner, ok := ownerMap[e.GroupID]; ok { + ownerUserID = owner.UserID + } + return convert.Db2PbGroupInfo(e, ownerUserID, groupMemberNumMap[e.GroupID]) + }), + }, nil } func (s *groupServer) GroupApplicationResponse(ctx context.Context, req *pbgroup.GroupApplicationResponseReq) (*pbgroup.GroupApplicationResponseResp, error) { - defer log.ZInfo(ctx, utils.GetFuncName()+" Return") - if !utils.Contain(req.HandleResult, constant.GroupResponseAgree, constant.GroupResponseRefuse) { - return nil, errs.ErrArgs.Wrap("HandleResult unknown") + if !datautil.Contain(req.HandleResult, constant.GroupResponseAgree, constant.GroupResponseRefuse) { + return nil, errs.ErrArgs.WrapMsg("HandleResult unknown") } - if !authverify.IsAppManagerUid(ctx, s.config) { + if !authverify.IsAppManagerUid(ctx, s.config.Share.IMAdminUserID) { groupMember, err := s.db.TakeGroupMember(ctx, req.GroupID, mcontext.GetOpUserID(ctx)) if err != nil { return nil, err } if !(groupMember.RoleLevel == constant.GroupOwner || groupMember.RoleLevel == constant.GroupAdmin) { - return nil, errs.ErrNoPermission.Wrap("no group owner or admin") + return nil, errs.ErrNoPermission.WrapMsg("no group owner or admin") } } group, err := s.db.TakeGroup(ctx, req.GroupID) @@ -755,7 +772,7 @@ func (s *groupServer) GroupApplicationResponse(ctx context.Context, req *pbgroup return nil, err } if groupRequest.HandleResult != 0 { - return nil, errs.ErrGroupRequestHandled.Wrap("group request already processed") + return nil, servererrs.ErrGroupRequestHandled.WrapMsg("group request already processed") } var inGroup bool if _, err := s.db.TakeGroupMember(ctx, req.GroupID, req.FromUserID); err == nil { @@ -763,7 +780,7 @@ func (s *groupServer) GroupApplicationResponse(ctx context.Context, req *pbgroup } else if !s.IsNotFound(err) { return nil, err } - if _, err := s.User.GetPublicUserInfo(ctx, req.FromUserID); err != nil { + if _, err := s.user.GetPublicUserInfo(ctx, req.FromUserID); err != nil { return nil, err } var member *relationtb.GroupMemberModel @@ -781,7 +798,7 @@ func (s *groupServer) GroupApplicationResponse(ctx context.Context, req *pbgroup OperatorUserID: mcontext.GetOpUserID(ctx), Ex: groupRequest.Ex, } - if err = CallbackBeforeMemberJoinGroup(ctx, s.config, member, group.Ex); err != nil { + if err := s.webhookBeforeMemberJoinGroup(ctx, &s.config.WebhooksConfig.BeforeMemberJoinGroup, member, group.Ex); err != nil && err != servererrs.ErrCallbackContinue { return nil, err } } @@ -794,22 +811,21 @@ func (s *groupServer) GroupApplicationResponse(ctx context.Context, req *pbgroup if err := s.conversationRpcClient.GroupChatFirstCreateConversation(ctx, req.GroupID, []string{req.FromUserID}); err != nil { return nil, err } - s.Notification.GroupApplicationAcceptedNotification(ctx, req) + s.notification.GroupApplicationAcceptedNotification(ctx, req) if member == nil { log.ZDebug(ctx, "GroupApplicationResponse", "member is nil") } else { - s.Notification.MemberEnterNotification(ctx, req.GroupID, req.FromUserID) + s.notification.MemberEnterNotification(ctx, req.GroupID, req.FromUserID) } case constant.GroupResponseRefuse: - s.Notification.GroupApplicationRejectedNotification(ctx, req) + s.notification.GroupApplicationRejectedNotification(ctx, req) } return &pbgroup.GroupApplicationResponseResp{}, nil } -func (s *groupServer) JoinGroup(ctx context.Context, req *pbgroup.JoinGroupReq) (resp *pbgroup.JoinGroupResp, err error) { - defer log.ZInfo(ctx, "JoinGroup.Return") - user, err := s.User.GetUserInfo(ctx, req.InviterUserID) +func (s *groupServer) JoinGroup(ctx context.Context, req *pbgroup.JoinGroupReq) (*pbgroup.JoinGroupResp, error) { + user, err := s.user.GetUserInfo(ctx, req.InviterUserID) if err != nil { return nil, err } @@ -818,7 +834,7 @@ func (s *groupServer) JoinGroup(ctx context.Context, req *pbgroup.JoinGroupReq) return nil, err } if group.Status == constant.GroupStatusDismissed { - return nil, errs.ErrDismissedAlready.Wrap() + return nil, servererrs.ErrDismissedAlready.Wrap() } reqCall := &callbackstruct.CallbackJoinGroupReq{ @@ -829,17 +845,17 @@ func (s *groupServer) JoinGroup(ctx context.Context, req *pbgroup.JoinGroupReq) Ex: req.Ex, } - if err = CallbackApplyJoinGroupBefore(ctx, s.config, reqCall); err != nil { + if err := s.webhookBeforeApplyJoinGroup(ctx, &s.config.WebhooksConfig.BeforeApplyJoinGroup, reqCall); err != nil && err != servererrs.ErrCallbackContinue { return nil, err } + _, err = s.db.TakeGroupMember(ctx, req.GroupID, req.InviterUserID) if err == nil { - return nil, errs.ErrArgs.Wrap("already in group") - } else if !s.IsNotFound(err) && utils.Unwrap(err) != errs.ErrRecordNotFound { + return nil, errs.ErrArgs.Wrap() + } else if !s.IsNotFound(err) && errs.Unwrap(err) != errs.ErrRecordNotFound { return nil, err } - log.ZInfo(ctx, "JoinGroup.groupInfo", "group", group, "eq", group.NeedVerification == constant.Directly) - resp = &pbgroup.JoinGroupResp{} + log.ZDebug(ctx, "JoinGroup.groupInfo", "group", group, "eq", group.NeedVerification == constant.Directly) if group.NeedVerification == constant.Directly { groupMember := &relationtb.GroupMemberModel{ GroupID: group.GroupID, @@ -850,9 +866,11 @@ func (s *groupServer) JoinGroup(ctx context.Context, req *pbgroup.JoinGroupReq) JoinTime: time.Now(), MuteEndTime: time.UnixMilli(0), } - if err := CallbackBeforeMemberJoinGroup(ctx, s.config, groupMember, group.Ex); err != nil { + + if err := s.webhookBeforeMemberJoinGroup(ctx, &s.config.WebhooksConfig.BeforeMemberJoinGroup, groupMember, group.Ex); err != nil && err != servererrs.ErrCallbackContinue { return nil, err } + if err := s.db.CreateGroup(ctx, nil, []*relationtb.GroupMemberModel{groupMember}); err != nil { return nil, err } @@ -860,11 +878,10 @@ func (s *groupServer) JoinGroup(ctx context.Context, req *pbgroup.JoinGroupReq) if err := s.conversationRpcClient.GroupChatFirstCreateConversation(ctx, req.GroupID, []string{req.InviterUserID}); err != nil { return nil, err } - s.Notification.MemberEnterNotification(ctx, req.GroupID, req.InviterUserID) - if err = CallbackAfterJoinGroup(ctx, s.config, req); err != nil { - return nil, err - } - return resp, nil + s.notification.MemberEnterNotification(ctx, req.GroupID, req.InviterUserID) + s.webhookAfterJoinGroup(ctx, &s.config.WebhooksConfig.AfterJoinGroup, req) + + return &pbgroup.JoinGroupResp{}, nil } groupRequest := relationtb.GroupRequestModel{ UserID: req.InviterUserID, @@ -878,16 +895,15 @@ func (s *groupServer) JoinGroup(ctx context.Context, req *pbgroup.JoinGroupReq) if err = s.db.CreateGroupRequest(ctx, []*relationtb.GroupRequestModel{&groupRequest}); err != nil { return nil, err } - s.Notification.JoinGroupApplicationNotification(ctx, req) - return resp, nil + s.notification.JoinGroupApplicationNotification(ctx, req) + return &pbgroup.JoinGroupResp{}, nil } func (s *groupServer) QuitGroup(ctx context.Context, req *pbgroup.QuitGroupReq) (*pbgroup.QuitGroupResp, error) { - resp := &pbgroup.QuitGroupResp{} if req.UserID == "" { req.UserID = mcontext.GetOpUserID(ctx) } else { - if err := authverify.CheckAccessV3(ctx, req.UserID, s.config); err != nil { + if err := authverify.CheckAccessV3(ctx, req.UserID, s.config.Share.IMAdminUserID); err != nil { return nil, err } } @@ -896,7 +912,7 @@ func (s *groupServer) QuitGroup(ctx context.Context, req *pbgroup.QuitGroupReq) return nil, err } if member.RoleLevel == constant.GroupOwner { - return nil, errs.ErrNoPermission.Wrap("group owner can't quit") + return nil, errs.ErrNoPermission.WrapMsg("group owner can't quit") } if err := s.PopulateGroupMember(ctx, member); err != nil { return nil, err @@ -905,20 +921,17 @@ func (s *groupServer) QuitGroup(ctx context.Context, req *pbgroup.QuitGroupReq) if err != nil { return nil, err } - _ = s.Notification.MemberQuitNotification(ctx, s.groupMemberDB2PB(member, 0)) + s.notification.MemberQuitNotification(ctx, s.groupMemberDB2PB(member, 0)) if err := s.deleteMemberAndSetConversationSeq(ctx, req.GroupID, []string{req.UserID}); err != nil { return nil, err } + s.webhookAfterQuitGroup(ctx, &s.config.WebhooksConfig.AfterQuitGroup, req) - // callback - if err := CallbackQuitGroup(ctx, s.config, req); err != nil { - return nil, err - } - return resp, nil + return &pbgroup.QuitGroupResp{}, nil } func (s *groupServer) deleteMemberAndSetConversationSeq(ctx context.Context, groupID string, userIDs []string) error { - conevrsationID := msgprocessor.GetConversationIDBySessionType(constant.SuperGroupChatType, groupID) + conevrsationID := msgprocessor.GetConversationIDBySessionType(constant.ReadGroupChatType, groupID) maxSeq, err := s.msgRpcClient.GetConversationMaxSeq(ctx, conevrsationID) if err != nil { return err @@ -928,30 +941,31 @@ func (s *groupServer) deleteMemberAndSetConversationSeq(ctx context.Context, gro func (s *groupServer) SetGroupInfo(ctx context.Context, req *pbgroup.SetGroupInfoReq) (*pbgroup.SetGroupInfoResp, error) { var opMember *relationtb.GroupMemberModel - if !authverify.IsAppManagerUid(ctx, s.config) { + if !authverify.IsAppManagerUid(ctx, s.config.Share.IMAdminUserID) { var err error opMember, err = s.db.TakeGroupMember(ctx, req.GroupInfoForSet.GroupID, mcontext.GetOpUserID(ctx)) if err != nil { return nil, err } if !(opMember.RoleLevel == constant.GroupOwner || opMember.RoleLevel == constant.GroupAdmin) { - return nil, errs.ErrNoPermission.Wrap("no group owner or admin") + return nil, errs.ErrNoPermission.WrapMsg("no group owner or admin") } if err := s.PopulateGroupMember(ctx, opMember); err != nil { return nil, err } } - if err := CallbackBeforeSetGroupInfo(ctx, s.config, req); err != nil { + + if err := s.webhookBeforeSetGroupInfo(ctx, &s.config.WebhooksConfig.BeforeSetGroupInfo, req); err != nil && err != servererrs.ErrCallbackContinue { return nil, err } + group, err := s.db.TakeGroup(ctx, req.GroupInfoForSet.GroupID) if err != nil { return nil, err } if group.Status == constant.GroupStatusDismissed { - return nil, errs.Wrap(errs.ErrDismissedAlready) + return nil, servererrs.ErrDismissedAlready.Wrap() } - resp := &pbgroup.SetGroupInfoResp{} count, err := s.db.FindGroupMemberNum(ctx, group.GroupID) if err != nil { @@ -966,7 +980,7 @@ func (s *groupServer) SetGroupInfo(ctx context.Context, req *pbgroup.SetGroupInf } update := UpdateGroupInfoMap(ctx, req.GroupInfoForSet) if len(update) == 0 { - return resp, nil + return &pbgroup.SetGroupInfoResp{}, nil } if err := s.db.UpdateGroup(ctx, group.GroupID, update); err != nil { return nil, err @@ -988,8 +1002,8 @@ func (s *groupServer) SetGroupInfo(ctx context.Context, req *pbgroup.SetGroupInf num-- func() { conversation := &pbconversation.ConversationReq{ - ConversationID: msgprocessor.GetConversationIDBySessionType(constant.SuperGroupChatType, req.GroupInfoForSet.GroupID), - ConversationType: constant.SuperGroupChatType, + ConversationID: msgprocessor.GetConversationIDBySessionType(constant.ReadGroupChatType, req.GroupInfoForSet.GroupID), + ConversationType: constant.ReadGroupChatType, GroupID: req.GroupInfoForSet.GroupID, } resp, err := s.GetGroupMemberUserIDs(ctx, &pbgroup.GetGroupMemberUserIDsReq{GroupID: req.GroupInfoForSet.GroupID}) @@ -1002,32 +1016,31 @@ func (s *groupServer) SetGroupInfo(ctx context.Context, req *pbgroup.SetGroupInf log.ZWarn(ctx, "SetConversations", err, resp.UserIDs, conversation) } }() - _ = s.Notification.GroupInfoSetAnnouncementNotification(ctx, &sdkws.GroupInfoSetAnnouncementTips{Group: tips.Group, OpUser: tips.OpUser}) + s.notification.GroupInfoSetAnnouncementNotification(ctx, &sdkws.GroupInfoSetAnnouncementTips{Group: tips.Group, OpUser: tips.OpUser}) } if req.GroupInfoForSet.GroupName != "" { num-- - _ = s.Notification.GroupInfoSetNameNotification(ctx, &sdkws.GroupInfoSetNameTips{Group: tips.Group, OpUser: tips.OpUser}) + s.notification.GroupInfoSetNameNotification(ctx, &sdkws.GroupInfoSetNameTips{Group: tips.Group, OpUser: tips.OpUser}) } if num > 0 { - _ = s.Notification.GroupInfoSetNotification(ctx, tips) - } - if err := CallbackAfterSetGroupInfo(ctx, s.config, req); err != nil { - return nil, err + s.notification.GroupInfoSetNotification(ctx, tips) } - return resp, nil + + s.webhookAfterSetGroupInfo(ctx, &s.config.WebhooksConfig.AfterSetGroupInfo, req) + + return &pbgroup.SetGroupInfoResp{}, nil } func (s *groupServer) TransferGroupOwner(ctx context.Context, req *pbgroup.TransferGroupOwnerReq) (*pbgroup.TransferGroupOwnerResp, error) { - resp := &pbgroup.TransferGroupOwnerResp{} group, err := s.db.TakeGroup(ctx, req.GroupID) if err != nil { return nil, err } if group.Status == constant.GroupStatusDismissed { - return nil, errs.ErrDismissedAlready.Wrap("") + return nil, servererrs.ErrDismissedAlready.Wrap() } if req.OldOwnerUserID == req.NewOwnerUserID { - return nil, errs.ErrArgs.Wrap("OldOwnerUserID == NewOwnerUserID") + return nil, errs.ErrArgs.WrapMsg("OldOwnerUserID == NewOwnerUserID") } members, err := s.db.FindGroupMembers(ctx, req.GroupID, []string{req.OldOwnerUserID, req.NewOwnerUserID}) if err != nil { @@ -1036,41 +1049,39 @@ func (s *groupServer) TransferGroupOwner(ctx context.Context, req *pbgroup.Trans if err := s.PopulateGroupMember(ctx, members...); err != nil { return nil, err } - memberMap := utils.SliceToMap(members, func(e *relationtb.GroupMemberModel) string { return e.UserID }) - if ids := utils.Single([]string{req.OldOwnerUserID, req.NewOwnerUserID}, utils.Keys(memberMap)); len(ids) > 0 { - return nil, errs.ErrArgs.Wrap("user not in group " + strings.Join(ids, ",")) + memberMap := datautil.SliceToMap(members, func(e *relationtb.GroupMemberModel) string { return e.UserID }) + if ids := datautil.Single([]string{req.OldOwnerUserID, req.NewOwnerUserID}, datautil.Keys(memberMap)); len(ids) > 0 { + return nil, errs.ErrArgs.WrapMsg("user not in group " + strings.Join(ids, ",")) } oldOwner := memberMap[req.OldOwnerUserID] if oldOwner == nil { - return nil, errs.ErrArgs.Wrap("OldOwnerUserID not in group " + req.NewOwnerUserID) + return nil, errs.ErrArgs.WrapMsg("OldOwnerUserID not in group " + req.NewOwnerUserID) } newOwner := memberMap[req.NewOwnerUserID] if newOwner == nil { - return nil, errs.ErrArgs.Wrap("NewOwnerUser not in group " + req.NewOwnerUserID) + return nil, errs.ErrArgs.WrapMsg("NewOwnerUser not in group " + req.NewOwnerUserID) } - if !authverify.IsAppManagerUid(ctx, s.config) { + if !authverify.IsAppManagerUid(ctx, s.config.Share.IMAdminUserID) { if !(mcontext.GetOpUserID(ctx) == oldOwner.UserID && oldOwner.RoleLevel == constant.GroupOwner) { - return nil, errs.ErrNoPermission.Wrap("no permission transfer group owner") + return nil, errs.ErrNoPermission.WrapMsg("no permission transfer group owner") } } if err := s.db.TransferGroupOwner(ctx, req.GroupID, req.OldOwnerUserID, req.NewOwnerUserID, newOwner.RoleLevel); err != nil { return nil, err } - if err := CallbackAfterTransferGroupOwner(ctx, s.config, req); err != nil { - return nil, err - } - s.Notification.GroupOwnerTransferredNotification(ctx, req) - return resp, nil + s.webhookAfterTransferGroupOwner(ctx, &s.config.WebhooksConfig.AfterTransferGroupOwner, req) + + s.notification.GroupOwnerTransferredNotification(ctx, req) + return &pbgroup.TransferGroupOwnerResp{}, nil } func (s *groupServer) GetGroups(ctx context.Context, req *pbgroup.GetGroupsReq) (*pbgroup.GetGroupsResp, error) { - resp := &pbgroup.GetGroupsResp{} var ( group []*relationtb.GroupModel err error ) - + var resp pbgroup.GetGroupsResp if req.GroupID != "" { group, err = s.db.FindGroup(ctx, []string{req.GroupID}) resp.Total = uint32(len(group)) @@ -1084,7 +1095,7 @@ func (s *groupServer) GetGroups(ctx context.Context, req *pbgroup.GetGroupsReq) return nil, err } - groupIDs := utils.Slice(group, func(e *relationtb.GroupModel) string { + groupIDs := datautil.Slice(group, func(e *relationtb.GroupModel) string { return e.GroupID }) @@ -1093,14 +1104,14 @@ func (s *groupServer) GetGroups(ctx context.Context, req *pbgroup.GetGroupsReq) return nil, err } - ownerMemberMap := utils.SliceToMap(ownerMembers, func(e *relationtb.GroupMemberModel) string { + ownerMemberMap := datautil.SliceToMap(ownerMembers, func(e *relationtb.GroupMemberModel) string { return e.GroupID }) groupMemberNumMap, err := s.db.MapGroupMemberNum(ctx, groupIDs) if err != nil { return nil, err } - resp.Groups = utils.Slice(group, func(group *relationtb.GroupModel) *pbgroup.CMSGroup { + resp.Groups = datautil.Slice(group, func(group *relationtb.GroupModel) *pbgroup.CMSGroup { var ( userID string username string @@ -1111,28 +1122,27 @@ func (s *groupServer) GetGroups(ctx context.Context, req *pbgroup.GetGroupsReq) } return convert.Db2PbCMSGroup(group, userID, username, groupMemberNumMap[group.GroupID]) }) - return resp, nil + return &resp, nil } func (s *groupServer) GetGroupMembersCMS(ctx context.Context, req *pbgroup.GetGroupMembersCMSReq) (*pbgroup.GetGroupMembersCMSResp, error) { - resp := &pbgroup.GetGroupMembersCMSResp{} total, members, err := s.db.SearchGroupMember(ctx, req.UserName, req.GroupID, req.Pagination) if err != nil { return nil, err } + var resp pbgroup.GetGroupMembersCMSResp resp.Total = uint32(total) if err := s.PopulateGroupMember(ctx, members...); err != nil { return nil, err } - resp.Members = utils.Slice(members, func(e *relationtb.GroupMemberModel) *sdkws.GroupMemberFullInfo { + resp.Members = datautil.Slice(members, func(e *relationtb.GroupMemberModel) *sdkws.GroupMemberFullInfo { return convert.Db2PbGroupMember(e) }) - return resp, nil + return &resp, nil } func (s *groupServer) GetUserReqApplicationList(ctx context.Context, req *pbgroup.GetUserReqApplicationListReq) (*pbgroup.GetUserReqApplicationListResp, error) { - resp := &pbgroup.GetUserReqApplicationListResp{} - user, err := s.User.GetPublicUserInfo(ctx, req.UserID) + user, err := s.user.GetPublicUserInfo(ctx, req.UserID) if err != nil { return nil, err } @@ -1140,18 +1150,17 @@ func (s *groupServer) GetUserReqApplicationList(ctx context.Context, req *pbgrou if err != nil { return nil, err } - resp.Total = uint32(total) if len(requests) == 0 { - return resp, nil + return &pbgroup.GetUserReqApplicationListResp{Total: uint32(total)}, nil } - groupIDs := utils.Distinct(utils.Slice(requests, func(e *relationtb.GroupRequestModel) string { + groupIDs := datautil.Distinct(datautil.Slice(requests, func(e *relationtb.GroupRequestModel) string { return e.GroupID })) groups, err := s.db.FindGroup(ctx, groupIDs) if err != nil { return nil, err } - groupMap := utils.SliceToMap(groups, func(e *relationtb.GroupModel) string { + groupMap := datautil.SliceToMap(groups, func(e *relationtb.GroupModel) string { return e.GroupID }) owners, err := s.db.FindGroupsOwner(ctx, groupIDs) @@ -1161,33 +1170,33 @@ func (s *groupServer) GetUserReqApplicationList(ctx context.Context, req *pbgrou if err := s.PopulateGroupMember(ctx, owners...); err != nil { return nil, err } - ownerMap := utils.SliceToMap(owners, func(e *relationtb.GroupMemberModel) string { + ownerMap := datautil.SliceToMap(owners, func(e *relationtb.GroupMemberModel) string { return e.GroupID }) groupMemberNum, err := s.db.MapGroupMemberNum(ctx, groupIDs) if err != nil { return nil, err } - resp.GroupRequests = utils.Slice(requests, func(e *relationtb.GroupRequestModel) *sdkws.GroupRequest { - var ownerUserID string - if owner, ok := ownerMap[e.GroupID]; ok { - ownerUserID = owner.UserID - } - return convert.Db2PbGroupRequest(e, user, convert.Db2PbGroupInfo(groupMap[e.GroupID], ownerUserID, groupMemberNum[e.GroupID])) - }) - return resp, nil + return &pbgroup.GetUserReqApplicationListResp{ + Total: uint32(total), + GroupRequests: datautil.Slice(requests, func(e *relationtb.GroupRequestModel) *sdkws.GroupRequest { + var ownerUserID string + if owner, ok := ownerMap[e.GroupID]; ok { + ownerUserID = owner.UserID + } + return convert.Db2PbGroupRequest(e, user, convert.Db2PbGroupInfo(groupMap[e.GroupID], ownerUserID, groupMemberNum[e.GroupID])) + }), + }, nil } func (s *groupServer) DismissGroup(ctx context.Context, req *pbgroup.DismissGroupReq) (*pbgroup.DismissGroupResp, error) { - defer log.ZInfo(ctx, "DismissGroup.return") - resp := &pbgroup.DismissGroupResp{} owner, err := s.db.TakeGroupOwner(ctx, req.GroupID) if err != nil { return nil, err } - if !authverify.IsAppManagerUid(ctx, s.config) { + if !authverify.IsAppManagerUid(ctx, s.config.Share.IMAdminUserID) { if owner.UserID != mcontext.GetOpUserID(ctx) { - return nil, errs.ErrNoPermission.Wrap("not group owner") + return nil, errs.ErrNoPermission.WrapMsg("not group owner") } } if err := s.PopulateGroupMember(ctx, owner); err != nil { @@ -1198,7 +1207,7 @@ func (s *groupServer) DismissGroup(ctx context.Context, req *pbgroup.DismissGrou return nil, err } if !req.DeleteMember && group.Status == constant.GroupStatusDismissed { - return nil, errs.ErrDismissedAlready.Wrap("group status is dismissed") + return nil, servererrs.ErrDismissedAlready.WrapMsg("group status is dismissed") } if err := s.db.DismissGroup(ctx, req.GroupID, req.DeleteMember); err != nil { return nil, err @@ -1215,27 +1224,25 @@ func (s *groupServer) DismissGroup(ctx context.Context, req *pbgroup.DismissGrou if mcontext.GetOpUserID(ctx) == owner.UserID { tips.OpUser = s.groupMemberDB2PB(owner, 0) } - s.Notification.GroupDismissedNotification(ctx, tips) + s.notification.GroupDismissedNotification(ctx, tips) } membersID, err := s.db.FindGroupMemberUserID(ctx, group.GroupID) if err != nil { return nil, err } - reqCall := &callbackstruct.CallbackDisMissGroupReq{ + cbReq := &callbackstruct.CallbackDisMissGroupReq{ GroupID: req.GroupID, OwnerID: owner.UserID, MembersID: membersID, GroupType: string(group.GroupType), } - if err := CallbackDismissGroup(ctx, s.config, reqCall); err != nil { - return nil, err - } - return resp, nil + s.webhookAfterDismissGroup(ctx, &s.config.WebhooksConfig.AfterDismissGroup, cbReq) + + return &pbgroup.DismissGroupResp{}, nil } func (s *groupServer) MuteGroupMember(ctx context.Context, req *pbgroup.MuteGroupMemberReq) (*pbgroup.MuteGroupMemberResp, error) { - resp := &pbgroup.MuteGroupMemberResp{} member, err := s.db.TakeGroupMember(ctx, req.GroupID, req.UserID) if err != nil { return nil, err @@ -1243,21 +1250,21 @@ func (s *groupServer) MuteGroupMember(ctx context.Context, req *pbgroup.MuteGrou if err := s.PopulateGroupMember(ctx, member); err != nil { return nil, err } - if !authverify.IsAppManagerUid(ctx, s.config) { + if !authverify.IsAppManagerUid(ctx, s.config.Share.IMAdminUserID) { opMember, err := s.db.TakeGroupMember(ctx, req.GroupID, mcontext.GetOpUserID(ctx)) if err != nil { return nil, err } switch member.RoleLevel { case constant.GroupOwner: - return nil, errs.ErrNoPermission.Wrap("set group owner mute") + return nil, errs.ErrNoPermission.WrapMsg("set group owner mute") case constant.GroupAdmin: if opMember.RoleLevel != constant.GroupOwner { - return nil, errs.ErrNoPermission.Wrap("set group admin mute") + return nil, errs.ErrNoPermission.WrapMsg("set group admin mute") } case constant.GroupOrdinaryUsers: if !(opMember.RoleLevel == constant.GroupAdmin || opMember.RoleLevel == constant.GroupOwner) { - return nil, errs.ErrNoPermission.Wrap("set group ordinary users mute") + return nil, errs.ErrNoPermission.WrapMsg("set group ordinary users mute") } } } @@ -1265,8 +1272,8 @@ func (s *groupServer) MuteGroupMember(ctx context.Context, req *pbgroup.MuteGrou if err := s.db.UpdateGroupMember(ctx, member.GroupID, member.UserID, data); err != nil { return nil, err } - s.Notification.GroupMemberMutedNotification(ctx, req.GroupID, req.UserID, req.MutedSeconds) - return resp, nil + s.notification.GroupMemberMutedNotification(ctx, req.GroupID, req.UserID, req.MutedSeconds) + return &pbgroup.MuteGroupMemberResp{}, nil } func (s *groupServer) CancelMuteGroupMember(ctx context.Context, req *pbgroup.CancelMuteGroupMemberReq) (*pbgroup.CancelMuteGroupMemberResp, error) { @@ -1277,21 +1284,21 @@ func (s *groupServer) CancelMuteGroupMember(ctx context.Context, req *pbgroup.Ca if err := s.PopulateGroupMember(ctx, member); err != nil { return nil, err } - if !authverify.IsAppManagerUid(ctx, s.config) { + if !authverify.IsAppManagerUid(ctx, s.config.Share.IMAdminUserID) { opMember, err := s.db.TakeGroupMember(ctx, req.GroupID, mcontext.GetOpUserID(ctx)) if err != nil { return nil, err } switch member.RoleLevel { case constant.GroupOwner: - return nil, errs.ErrNoPermission.Wrap("set group owner mute") + return nil, errs.ErrNoPermission.WrapMsg("set group owner mute") case constant.GroupAdmin: if opMember.RoleLevel != constant.GroupOwner { - return nil, errs.ErrNoPermission.Wrap("set group admin mute") + return nil, errs.ErrNoPermission.WrapMsg("set group admin mute") } case constant.GroupOrdinaryUsers: if !(opMember.RoleLevel == constant.GroupAdmin || opMember.RoleLevel == constant.GroupOwner) { - return nil, errs.ErrNoPermission.Wrap("set group ordinary users mute") + return nil, errs.ErrNoPermission.WrapMsg("set group ordinary users mute") } } } @@ -1299,44 +1306,41 @@ func (s *groupServer) CancelMuteGroupMember(ctx context.Context, req *pbgroup.Ca if err := s.db.UpdateGroupMember(ctx, member.GroupID, member.UserID, data); err != nil { return nil, err } - s.Notification.GroupMemberCancelMutedNotification(ctx, req.GroupID, req.UserID) + s.notification.GroupMemberCancelMutedNotification(ctx, req.GroupID, req.UserID) return &pbgroup.CancelMuteGroupMemberResp{}, nil } func (s *groupServer) MuteGroup(ctx context.Context, req *pbgroup.MuteGroupReq) (*pbgroup.MuteGroupResp, error) { - resp := &pbgroup.MuteGroupResp{} if err := s.CheckGroupAdmin(ctx, req.GroupID); err != nil { return nil, err } if err := s.db.UpdateGroup(ctx, req.GroupID, UpdateGroupStatusMap(constant.GroupStatusMuted)); err != nil { return nil, err } - s.Notification.GroupMutedNotification(ctx, req.GroupID) - return resp, nil + s.notification.GroupMutedNotification(ctx, req.GroupID) + return &pbgroup.MuteGroupResp{}, nil } func (s *groupServer) CancelMuteGroup(ctx context.Context, req *pbgroup.CancelMuteGroupReq) (*pbgroup.CancelMuteGroupResp, error) { - resp := &pbgroup.CancelMuteGroupResp{} if err := s.CheckGroupAdmin(ctx, req.GroupID); err != nil { return nil, err } if err := s.db.UpdateGroup(ctx, req.GroupID, UpdateGroupStatusMap(constant.GroupOk)); err != nil { return nil, err } - s.Notification.GroupCancelMutedNotification(ctx, req.GroupID) - return resp, nil + s.notification.GroupCancelMutedNotification(ctx, req.GroupID) + return &pbgroup.CancelMuteGroupResp{}, nil } func (s *groupServer) SetGroupMemberInfo(ctx context.Context, req *pbgroup.SetGroupMemberInfoReq) (*pbgroup.SetGroupMemberInfoResp, error) { - resp := &pbgroup.SetGroupMemberInfoResp{} if len(req.Members) == 0 { - return nil, errs.ErrArgs.Wrap("members empty") + return nil, errs.ErrArgs.WrapMsg("members empty") } opUserID := mcontext.GetOpUserID(ctx) if opUserID == "" { - return nil, errs.ErrNoPermission.Wrap("no op user id") + return nil, errs.ErrNoPermission.WrapMsg("no op user id") } - isAppManagerUid := authverify.IsAppManagerUid(ctx, s.config) + isAppManagerUid := authverify.IsAppManagerUid(ctx, s.config.Share.IMAdminUserID) for i := range req.Members { req.Members[i].FaceURL = nil } @@ -1345,10 +1349,10 @@ func (s *groupServer) SetGroupMemberInfo(ctx context.Context, req *pbgroup.SetGr if member.RoleLevel != nil { switch member.RoleLevel.Value { case constant.GroupOwner: - return nil, errs.ErrNoPermission.Wrap("cannot set ungroup owner") + return nil, errs.ErrNoPermission.WrapMsg("cannot set ungroup owner") case constant.GroupAdmin, constant.GroupOrdinaryUsers: default: - return nil, errs.ErrArgs.Wrap("invalid role level") + return nil, errs.ErrArgs.WrapMsg("invalid role level") } } groupMembers[member.GroupID] = append(groupMembers[member.GroupID], req.Members[i]) @@ -1358,7 +1362,7 @@ func (s *groupServer) SetGroupMemberInfo(ctx context.Context, req *pbgroup.SetGr userIDs := make([]string, 0, len(members)+1) for _, member := range members { if _, ok := temp[member.UserID]; ok { - return nil, errs.ErrArgs.Wrap(fmt.Sprintf("repeat group %s user %s", member.GroupID, member.UserID)) + return nil, errs.ErrArgs.WrapMsg(fmt.Sprintf("repeat group %s user %s", member.GroupID, member.UserID)) } temp[member.UserID] = struct{}{} userIDs = append(userIDs, member.UserID) @@ -1386,22 +1390,22 @@ func (s *groupServer) SetGroupMemberInfo(ctx context.Context, req *pbgroup.SetGr case constant.GroupAdmin: for _, member := range dbMembers { if member.RoleLevel == constant.GroupOwner { - return nil, errs.ErrNoPermission.Wrap("admin can not change group owner") + return nil, errs.ErrNoPermission.WrapMsg("admin can not change group owner") } if member.RoleLevel == constant.GroupAdmin && member.UserID != opUserID { - return nil, errs.ErrNoPermission.Wrap("admin can not change other group admin") + return nil, errs.ErrNoPermission.WrapMsg("admin can not change other group admin") } } case constant.GroupOrdinaryUsers: for _, member := range dbMembers { if !(member.RoleLevel == constant.GroupOrdinaryUsers && member.UserID == opUserID) { - return nil, errs.ErrNoPermission.Wrap("ordinary users can not change other role level") + return nil, errs.ErrNoPermission.WrapMsg("ordinary users can not change other role level") } } default: for _, member := range dbMembers { if member.RoleLevel >= roleLevel { - return nil, errs.ErrNoPermission.Wrap("can not change higher role level") + return nil, errs.ErrNoPermission.WrapMsg("can not change higher role level") } } } @@ -1409,21 +1413,24 @@ func (s *groupServer) SetGroupMemberInfo(ctx context.Context, req *pbgroup.SetGr } case 1: if opUserIndex >= 0 { - return nil, errs.ErrArgs.Wrap("user not in group") + return nil, errs.ErrArgs.WrapMsg("user not in group") } if !isAppManagerUid { - return nil, errs.ErrNoPermission.Wrap("user not in group") + return nil, errs.ErrNoPermission.WrapMsg("user not in group") } default: - return nil, errs.ErrArgs.Wrap("user not in group") + return nil, errs.ErrArgs.WrapMsg("user not in group") } } + for i := 0; i < len(req.Members); i++ { - if err := CallbackBeforeSetGroupMemberInfo(ctx, s.config, req.Members[i]); err != nil { + + if err := s.webhookBeforeSetGroupMemberInfo(ctx, &s.config.WebhooksConfig.BeforeSetGroupMemberInfo, req.Members[i]); err != nil && err != servererrs.ErrCallbackContinue { return nil, err } + } - if err := s.db.UpdateGroupMembers(ctx, utils.Slice(req.Members, func(e *pbgroup.SetGroupMemberInfo) *relationtb.BatchUpdateGroupMember { + if err := s.db.UpdateGroupMembers(ctx, datautil.Slice(req.Members, func(e *pbgroup.SetGroupMemberInfo) *relationtb.BatchUpdateGroupMember { return &relationtb.BatchUpdateGroupMember{ GroupID: e.GroupID, UserID: e.UserID, @@ -1436,59 +1443,56 @@ func (s *groupServer) SetGroupMemberInfo(ctx context.Context, req *pbgroup.SetGr if member.RoleLevel != nil { switch member.RoleLevel.Value { case constant.GroupAdmin: - s.Notification.GroupMemberSetToAdminNotification(ctx, member.GroupID, member.UserID) + s.notification.GroupMemberSetToAdminNotification(ctx, member.GroupID, member.UserID) case constant.GroupOrdinaryUsers: - s.Notification.GroupMemberSetToOrdinaryUserNotification(ctx, member.GroupID, member.UserID) + s.notification.GroupMemberSetToOrdinaryUserNotification(ctx, member.GroupID, member.UserID) } } if member.Nickname != nil || member.FaceURL != nil || member.Ex != nil { - s.Notification.GroupMemberInfoSetNotification(ctx, member.GroupID, member.UserID) + s.notification.GroupMemberInfoSetNotification(ctx, member.GroupID, member.UserID) } } for i := 0; i < len(req.Members); i++ { - if err := CallbackAfterSetGroupMemberInfo(ctx, s.config, req.Members[i]); err != nil { - return nil, err - } + s.webhookAfterSetGroupMemberInfo(ctx, &s.config.WebhooksConfig.AfterSetGroupMemberInfo, req.Members[i]) } - return resp, nil + return &pbgroup.SetGroupMemberInfoResp{}, nil } func (s *groupServer) GetGroupAbstractInfo(ctx context.Context, req *pbgroup.GetGroupAbstractInfoReq) (*pbgroup.GetGroupAbstractInfoResp, error) { - resp := &pbgroup.GetGroupAbstractInfoResp{} if len(req.GroupIDs) == 0 { - return nil, errs.ErrArgs.Wrap("groupIDs empty") + return nil, errs.ErrArgs.WrapMsg("groupIDs empty") } - if utils.Duplicate(req.GroupIDs) { - return nil, errs.ErrArgs.Wrap("groupIDs duplicate") + if datautil.Duplicate(req.GroupIDs) { + return nil, errs.ErrArgs.WrapMsg("groupIDs duplicate") } groups, err := s.db.FindGroup(ctx, req.GroupIDs) if err != nil { return nil, err } - if ids := utils.Single(req.GroupIDs, utils.Slice(groups, func(group *relationtb.GroupModel) string { + if ids := datautil.Single(req.GroupIDs, datautil.Slice(groups, func(group *relationtb.GroupModel) string { return group.GroupID })); len(ids) > 0 { - return nil, errs.ErrGroupIDNotFound.Wrap("not found group " + strings.Join(ids, ",")) + return nil, servererrs.ErrGroupIDNotFound.WrapMsg("not found group " + strings.Join(ids, ",")) } groupUserMap, err := s.db.MapGroupMemberUserID(ctx, req.GroupIDs) if err != nil { return nil, err } - if ids := utils.Single(req.GroupIDs, utils.Keys(groupUserMap)); len(ids) > 0 { - return nil, errs.ErrGroupIDNotFound.Wrap(fmt.Sprintf("group %s not found member", strings.Join(ids, ","))) + if ids := datautil.Single(req.GroupIDs, datautil.Keys(groupUserMap)); len(ids) > 0 { + return nil, servererrs.ErrGroupIDNotFound.WrapMsg(fmt.Sprintf("group %s not found member", strings.Join(ids, ","))) } - resp.GroupAbstractInfos = utils.Slice(groups, func(group *relationtb.GroupModel) *pbgroup.GroupAbstractInfo { - users := groupUserMap[group.GroupID] - return convert.Db2PbGroupAbstractInfo(group.GroupID, users.MemberNum, users.Hash) - }) - return resp, nil + return &pbgroup.GetGroupAbstractInfoResp{ + GroupAbstractInfos: datautil.Slice(groups, func(group *relationtb.GroupModel) *pbgroup.GroupAbstractInfo { + users := groupUserMap[group.GroupID] + return convert.Db2PbGroupAbstractInfo(group.GroupID, users.MemberNum, users.Hash) + }), + }, nil } func (s *groupServer) GetUserInGroupMembers(ctx context.Context, req *pbgroup.GetUserInGroupMembersReq) (*pbgroup.GetUserInGroupMembersResp, error) { - resp := &pbgroup.GetUserInGroupMembersResp{} if len(req.GroupIDs) == 0 { - return nil, errs.ErrArgs.Wrap("groupIDs empty") + return nil, errs.ErrArgs.WrapMsg("groupIDs empty") } members, err := s.db.FindGroupMemberUser(ctx, req.GroupIDs, req.UserID) if err != nil { @@ -1497,25 +1501,26 @@ func (s *groupServer) GetUserInGroupMembers(ctx context.Context, req *pbgroup.Ge if err := s.PopulateGroupMember(ctx, members...); err != nil { return nil, err } - resp.Members = utils.Slice(members, func(e *relationtb.GroupMemberModel) *sdkws.GroupMemberFullInfo { - return convert.Db2PbGroupMember(e) - }) - return resp, nil + return &pbgroup.GetUserInGroupMembersResp{ + Members: datautil.Slice(members, func(e *relationtb.GroupMemberModel) *sdkws.GroupMemberFullInfo { + return convert.Db2PbGroupMember(e) + }), + }, nil } -func (s *groupServer) GetGroupMemberUserIDs(ctx context.Context, req *pbgroup.GetGroupMemberUserIDsReq) (resp *pbgroup.GetGroupMemberUserIDsResp, err error) { - resp = &pbgroup.GetGroupMemberUserIDsResp{} - resp.UserIDs, err = s.db.FindGroupMemberUserID(ctx, req.GroupID) +func (s *groupServer) GetGroupMemberUserIDs(ctx context.Context, req *pbgroup.GetGroupMemberUserIDsReq) (*pbgroup.GetGroupMemberUserIDsResp, error) { + userIDs, err := s.db.FindGroupMemberUserID(ctx, req.GroupID) if err != nil { return nil, err } - return resp, nil + return &pbgroup.GetGroupMemberUserIDsResp{ + UserIDs: userIDs, + }, nil } func (s *groupServer) GetGroupMemberRoleLevel(ctx context.Context, req *pbgroup.GetGroupMemberRoleLevelReq) (*pbgroup.GetGroupMemberRoleLevelResp, error) { - resp := &pbgroup.GetGroupMemberRoleLevelResp{} if len(req.RoleLevels) == 0 { - return nil, errs.ErrArgs.Wrap("RoleLevels empty") + return nil, errs.ErrArgs.WrapMsg("RoleLevels empty") } members, err := s.db.FindGroupMemberRoleLevels(ctx, req.GroupID, req.RoleLevels) if err != nil { @@ -1524,33 +1529,33 @@ func (s *groupServer) GetGroupMemberRoleLevel(ctx context.Context, req *pbgroup. if err := s.PopulateGroupMember(ctx, members...); err != nil { return nil, err } - resp.Members = utils.Slice(members, func(e *relationtb.GroupMemberModel) *sdkws.GroupMemberFullInfo { - return convert.Db2PbGroupMember(e) - }) - return resp, nil + return &pbgroup.GetGroupMemberRoleLevelResp{ + Members: datautil.Slice(members, func(e *relationtb.GroupMemberModel) *sdkws.GroupMemberFullInfo { + return convert.Db2PbGroupMember(e) + }), + }, nil } func (s *groupServer) GetGroupUsersReqApplicationList(ctx context.Context, req *pbgroup.GetGroupUsersReqApplicationListReq) (*pbgroup.GetGroupUsersReqApplicationListResp, error) { - resp := &pbgroup.GetGroupUsersReqApplicationListResp{} requests, err := s.db.FindGroupRequests(ctx, req.GroupID, req.UserIDs) if err != nil { return nil, err } if len(requests) == 0 { - return resp, nil + return &pbgroup.GetGroupUsersReqApplicationListResp{}, nil } - groupIDs := utils.Distinct(utils.Slice(requests, func(e *relationtb.GroupRequestModel) string { + groupIDs := datautil.Distinct(datautil.Slice(requests, func(e *relationtb.GroupRequestModel) string { return e.GroupID })) groups, err := s.db.FindGroup(ctx, groupIDs) if err != nil { return nil, err } - groupMap := utils.SliceToMap(groups, func(e *relationtb.GroupModel) string { + groupMap := datautil.SliceToMap(groups, func(e *relationtb.GroupModel) string { return e.GroupID }) - if ids := utils.Single(groupIDs, utils.Keys(groupMap)); len(ids) > 0 { - return nil, errs.ErrGroupIDNotFound.Wrap(strings.Join(ids, ",")) + if ids := datautil.Single(groupIDs, datautil.Keys(groupMap)); len(ids) > 0 { + return nil, servererrs.ErrGroupIDNotFound.WrapMsg(strings.Join(ids, ",")) } owners, err := s.db.FindGroupsOwner(ctx, groupIDs) if err != nil { @@ -1559,20 +1564,21 @@ func (s *groupServer) GetGroupUsersReqApplicationList(ctx context.Context, req * if err := s.PopulateGroupMember(ctx, owners...); err != nil { return nil, err } - ownerMap := utils.SliceToMap(owners, func(e *relationtb.GroupMemberModel) string { + ownerMap := datautil.SliceToMap(owners, func(e *relationtb.GroupMemberModel) string { return e.GroupID }) groupMemberNum, err := s.db.MapGroupMemberNum(ctx, groupIDs) if err != nil { return nil, err } - resp.GroupRequests = utils.Slice(requests, func(e *relationtb.GroupRequestModel) *sdkws.GroupRequest { - var ownerUserID string - if owner, ok := ownerMap[e.GroupID]; ok { - ownerUserID = owner.UserID - } - return convert.Db2PbGroupRequest(e, nil, convert.Db2PbGroupInfo(groupMap[e.GroupID], ownerUserID, groupMemberNum[e.GroupID])) - }) - resp.Total = int64(len(resp.GroupRequests)) - return resp, nil + return &pbgroup.GetGroupUsersReqApplicationListResp{ + Total: int64(len(requests)), + GroupRequests: datautil.Slice(requests, func(e *relationtb.GroupRequestModel) *sdkws.GroupRequest { + var ownerUserID string + if owner, ok := ownerMap[e.GroupID]; ok { + ownerUserID = owner.UserID + } + return convert.Db2PbGroupRequest(e, nil, convert.Db2PbGroupInfo(groupMap[e.GroupID], ownerUserID, groupMemberNum[e.GroupID])) + }), + }, nil } diff --git a/pkg/rpcclient/notification/group.go b/internal/rpc/group/notification.go similarity index 57% rename from pkg/rpcclient/notification/group.go rename to internal/rpc/group/notification.go index c72aa839b2..6d7cebcbc6 100644 --- a/pkg/rpcclient/notification/group.go +++ b/internal/rpc/group/notification.go @@ -12,35 +12,31 @@ // See the License for the specific language governing permissions and // limitations under the License. -package notification +package group import ( "context" "fmt" + "github.com/openimsdk/open-im-server/v3/pkg/rpcclient/notification" - "github.com/OpenIMSDK/protocol/constant" - pbgroup "github.com/OpenIMSDK/protocol/group" - "github.com/OpenIMSDK/protocol/sdkws" - "github.com/OpenIMSDK/tools/errs" - "github.com/OpenIMSDK/tools/log" - "github.com/OpenIMSDK/tools/mcontext" - "github.com/OpenIMSDK/tools/utils" "github.com/openimsdk/open-im-server/v3/pkg/authverify" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" + "github.com/openimsdk/open-im-server/v3/pkg/common/servererrs" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" + "github.com/openimsdk/protocol/constant" + pbgroup "github.com/openimsdk/protocol/group" + "github.com/openimsdk/protocol/sdkws" + "github.com/openimsdk/tools/errs" + "github.com/openimsdk/tools/log" + "github.com/openimsdk/tools/mcontext" + "github.com/openimsdk/tools/utils/datautil" + "github.com/openimsdk/tools/utils/stringutil" ) -func NewGroupNotificationSender( - db controller.GroupDatabase, - msgRpcClient *rpcclient.MessageRpcClient, - userRpcClient *rpcclient.UserRpcClient, - config *config.GlobalConfig, - fn func(ctx context.Context, userIDs []string) ([]CommonUser, error), -) *GroupNotificationSender { +func NewGroupNotificationSender(db controller.GroupDatabase, msgRpcClient *rpcclient.MessageRpcClient, userRpcClient *rpcclient.UserRpcClient, config *Config, fn func(ctx context.Context, userIDs []string) ([]notification.CommonUser, error)) *GroupNotificationSender { return &GroupNotificationSender{ - NotificationSender: rpcclient.NewNotificationSender(config, rpcclient.WithRpcClient(msgRpcClient), rpcclient.WithUserRpcClient(userRpcClient)), + NotificationSender: rpcclient.NewNotificationSender(&config.NotificationConfig, rpcclient.WithRpcClient(msgRpcClient), rpcclient.WithUserRpcClient(userRpcClient)), getUsersInfo: fn, db: db, config: config, @@ -49,9 +45,9 @@ func NewGroupNotificationSender( type GroupNotificationSender struct { *rpcclient.NotificationSender - getUsersInfo func(ctx context.Context, userIDs []string) ([]CommonUser, error) + getUsersInfo func(ctx context.Context, userIDs []string) ([]notification.CommonUser, error) db controller.GroupDatabase - config *config.GlobalConfig + config *Config } func (g *GroupNotificationSender) PopulateGroupMember(ctx context.Context, members ...*relation.GroupMemberModel) error { @@ -65,11 +61,11 @@ func (g *GroupNotificationSender) PopulateGroupMember(ctx context.Context, membe } } if len(emptyUserIDs) > 0 { - users, err := g.getUsersInfo(ctx, utils.Keys(emptyUserIDs)) + users, err := g.getUsersInfo(ctx, datautil.Keys(emptyUserIDs)) if err != nil { return err } - userMap := make(map[string]CommonUser) + userMap := make(map[string]notification.CommonUser) for i, user := range users { userMap[user.GetUserID()] = users[i] } @@ -95,7 +91,7 @@ func (g *GroupNotificationSender) getUser(ctx context.Context, userID string) (* return nil, err } if len(users) == 0 { - return nil, errs.ErrUserIDNotFound.Wrap(fmt.Sprintf("user %s not found", userID)) + return nil, servererrs.ErrUserIDNotFound.WrapMsg(fmt.Sprintf("user %s not found", userID)) } return &sdkws.PublicUserInfo{ UserID: users[0].GetUserID(), @@ -177,7 +173,7 @@ func (g *GroupNotificationSender) getGroupMember(ctx context.Context, groupID st return nil, err } if len(members) == 0 { - return nil, errs.ErrInternalServer.Wrap(fmt.Sprintf("group %s member %s not found", groupID, userID)) + return nil, errs.ErrInternalServer.WrapMsg(fmt.Sprintf("group %s member %s not found", groupID, userID)) } return members[0], nil } @@ -191,7 +187,7 @@ func (g *GroupNotificationSender) getGroupOwnerAndAdminUserID(ctx context.Contex return nil, err } fn := func(e *relation.GroupMemberModel) string { return e.UserID } - return utils.Slice(members, fn), nil + return datautil.Slice(members, fn), nil } //nolint:unused @@ -248,11 +244,11 @@ func (g *GroupNotificationSender) groupMemberDB2PB(member *relation.GroupMemberM func (g *GroupNotificationSender) fillOpUser(ctx context.Context, opUser **sdkws.GroupMemberFullInfo, groupID string) (err error) { if opUser == nil { - return errs.ErrInternalServer.Wrap("**sdkws.GroupMemberFullInfo is nil") + return errs.ErrInternalServer.WrapMsg("**sdkws.GroupMemberFullInfo is nil") } userID := mcontext.GetOpUserID(ctx) if groupID != "" { - if authverify.IsManagerUserID(userID, g.config) { + if authverify.IsManagerUserID(userID, g.config.Share.IMAdminUserID) { *opUser = &sdkws.GroupMemberFullInfo{ GroupID: groupID, UserID: userID, @@ -291,121 +287,122 @@ func (g *GroupNotificationSender) fillOpUser(ctx context.Context, opUser **sdkws return nil } -func (g *GroupNotificationSender) GroupCreatedNotification(ctx context.Context, tips *sdkws.GroupCreatedTips) (err error) { - defer log.ZDebug(ctx, "return") +func (g *GroupNotificationSender) GroupCreatedNotification(ctx context.Context, tips *sdkws.GroupCreatedTips) { + var err error defer func() { if err != nil { - log.ZError(ctx, utils.GetFuncName(1)+" failed", err) + log.ZError(ctx, stringutil.GetFuncName(1)+" failed", err) } }() - if err := g.fillOpUser(ctx, &tips.OpUser, tips.Group.GroupID); err != nil { - return err + if err = g.fillOpUser(ctx, &tips.OpUser, tips.Group.GroupID); err != nil { + return } - return g.Notification(ctx, mcontext.GetOpUserID(ctx), tips.Group.GroupID, constant.GroupCreatedNotification, tips) + g.Notification(ctx, mcontext.GetOpUserID(ctx), tips.Group.GroupID, constant.GroupCreatedNotification, tips) } -func (g *GroupNotificationSender) GroupInfoSetNotification(ctx context.Context, tips *sdkws.GroupInfoSetTips) (err error) { - defer log.ZDebug(ctx, "return") +func (g *GroupNotificationSender) GroupInfoSetNotification(ctx context.Context, tips *sdkws.GroupInfoSetTips) { + var err error defer func() { if err != nil { - log.ZError(ctx, utils.GetFuncName(1)+" failed", err) + log.ZError(ctx, stringutil.GetFuncName(1)+" failed", err) } }() - if err := g.fillOpUser(ctx, &tips.OpUser, tips.Group.GroupID); err != nil { - return err + if err = g.fillOpUser(ctx, &tips.OpUser, tips.Group.GroupID); err != nil { + return } - return g.Notification(ctx, mcontext.GetOpUserID(ctx), tips.Group.GroupID, constant.GroupInfoSetNotification, tips, rpcclient.WithRpcGetUserName()) + g.Notification(ctx, mcontext.GetOpUserID(ctx), tips.Group.GroupID, constant.GroupInfoSetNotification, tips, rpcclient.WithRpcGetUserName()) } -func (g *GroupNotificationSender) GroupInfoSetNameNotification(ctx context.Context, tips *sdkws.GroupInfoSetNameTips) (err error) { - defer log.ZDebug(ctx, "return") +func (g *GroupNotificationSender) GroupInfoSetNameNotification(ctx context.Context, tips *sdkws.GroupInfoSetNameTips) { + var err error defer func() { if err != nil { - log.ZError(ctx, utils.GetFuncName(1)+" failed", err) + log.ZError(ctx, stringutil.GetFuncName(1)+" failed", err) } }() - if err := g.fillOpUser(ctx, &tips.OpUser, tips.Group.GroupID); err != nil { - return err + if err = g.fillOpUser(ctx, &tips.OpUser, tips.Group.GroupID); err != nil { + return } - return g.Notification(ctx, mcontext.GetOpUserID(ctx), tips.Group.GroupID, constant.GroupInfoSetNameNotification, tips) + g.Notification(ctx, mcontext.GetOpUserID(ctx), tips.Group.GroupID, constant.GroupInfoSetNameNotification, tips) } -func (g *GroupNotificationSender) GroupInfoSetAnnouncementNotification(ctx context.Context, tips *sdkws.GroupInfoSetAnnouncementTips) (err error) { - defer log.ZDebug(ctx, "return") +func (g *GroupNotificationSender) GroupInfoSetAnnouncementNotification(ctx context.Context, tips *sdkws.GroupInfoSetAnnouncementTips) { + var err error defer func() { if err != nil { - log.ZError(ctx, utils.GetFuncName(1)+" failed", err) + log.ZError(ctx, stringutil.GetFuncName(1)+" failed", err) } }() - if err := g.fillOpUser(ctx, &tips.OpUser, tips.Group.GroupID); err != nil { - return err + if err = g.fillOpUser(ctx, &tips.OpUser, tips.Group.GroupID); err != nil { + return } - return g.Notification(ctx, mcontext.GetOpUserID(ctx), tips.Group.GroupID, constant.GroupInfoSetAnnouncementNotification, tips, rpcclient.WithRpcGetUserName()) + g.Notification(ctx, mcontext.GetOpUserID(ctx), tips.Group.GroupID, constant.GroupInfoSetAnnouncementNotification, tips, rpcclient.WithRpcGetUserName()) } -func (g *GroupNotificationSender) JoinGroupApplicationNotification(ctx context.Context, req *pbgroup.JoinGroupReq) (err error) { - defer log.ZDebug(ctx, "return") +func (g *GroupNotificationSender) JoinGroupApplicationNotification(ctx context.Context, req *pbgroup.JoinGroupReq) { + var err error defer func() { if err != nil { - log.ZError(ctx, utils.GetFuncName(1)+" failed", err) + log.ZError(ctx, stringutil.GetFuncName(1)+" failed", err) } }() - group, err := g.getGroupInfo(ctx, req.GroupID) + var group *sdkws.GroupInfo + group, err = g.getGroupInfo(ctx, req.GroupID) if err != nil { - return err + return } - user, err := g.getUser(ctx, req.InviterUserID) + var user *sdkws.PublicUserInfo + user, err = g.getUser(ctx, req.InviterUserID) if err != nil { - return err + return } userIDs, err := g.getGroupOwnerAndAdminUserID(ctx, req.GroupID) if err != nil { - return err + return } userIDs = append(userIDs, req.InviterUserID, mcontext.GetOpUserID(ctx)) tips := &sdkws.JoinGroupApplicationTips{Group: group, Applicant: user, ReqMsg: req.ReqMessage} - for _, userID := range utils.Distinct(userIDs) { - err = g.Notification(ctx, mcontext.GetOpUserID(ctx), userID, constant.JoinGroupApplicationNotification, tips) - if err != nil { - log.ZError(ctx, "JoinGroupApplicationNotification failed", err, "group", req.GroupID, "userID", userID) - } + for _, userID := range datautil.Distinct(userIDs) { + g.Notification(ctx, mcontext.GetOpUserID(ctx), userID, constant.JoinGroupApplicationNotification, tips) } - return nil } -func (g *GroupNotificationSender) MemberQuitNotification(ctx context.Context, member *sdkws.GroupMemberFullInfo) (err error) { - defer log.ZDebug(ctx, "return") +func (g *GroupNotificationSender) MemberQuitNotification(ctx context.Context, member *sdkws.GroupMemberFullInfo) { + var err error defer func() { if err != nil { - log.ZError(ctx, utils.GetFuncName(1)+" failed", err) + log.ZError(ctx, stringutil.GetFuncName(1)+" failed", err) } }() - group, err := g.getGroupInfo(ctx, member.GroupID) + var group *sdkws.GroupInfo + group, err = g.getGroupInfo(ctx, member.GroupID) if err != nil { - return err + return } tips := &sdkws.MemberQuitTips{Group: group, QuitUser: member} - return g.Notification(ctx, mcontext.GetOpUserID(ctx), member.GroupID, constant.MemberQuitNotification, tips) + g.Notification(ctx, mcontext.GetOpUserID(ctx), member.GroupID, constant.MemberQuitNotification, tips) } -func (g *GroupNotificationSender) GroupApplicationAcceptedNotification(ctx context.Context, req *pbgroup.GroupApplicationResponseReq) (err error) { - defer log.ZDebug(ctx, "return") +func (g *GroupNotificationSender) GroupApplicationAcceptedNotification(ctx context.Context, req *pbgroup.GroupApplicationResponseReq) { + var err error defer func() { if err != nil { - log.ZError(ctx, utils.GetFuncName(1)+" failed", err) + log.ZError(ctx, stringutil.GetFuncName(1)+" failed", err) } }() - group, err := g.getGroupInfo(ctx, req.GroupID) + var group *sdkws.GroupInfo + group, err = g.getGroupInfo(ctx, req.GroupID) if err != nil { - return err + return } - userIDs, err := g.getGroupOwnerAndAdminUserID(ctx, req.GroupID) + var userIDs []string + userIDs, err = g.getGroupOwnerAndAdminUserID(ctx, req.GroupID) if err != nil { - return err + return } tips := &sdkws.GroupApplicationAcceptedTips{Group: group, HandleMsg: req.HandledMsg} if err = g.fillOpUser(ctx, &tips.OpUser, tips.Group.GroupID); err != nil { - return err + return } for _, userID := range append(userIDs, req.FromUserID) { if userID == req.FromUserID { @@ -413,32 +410,30 @@ func (g *GroupNotificationSender) GroupApplicationAcceptedNotification(ctx conte } else { tips.ReceiverAs = 1 } - err = g.Notification(ctx, mcontext.GetOpUserID(ctx), userID, constant.GroupApplicationAcceptedNotification, tips) - if err != nil { - log.ZError(ctx, "failed", err) - } + g.Notification(ctx, mcontext.GetOpUserID(ctx), userID, constant.GroupApplicationAcceptedNotification, tips) } - return nil } -func (g *GroupNotificationSender) GroupApplicationRejectedNotification(ctx context.Context, req *pbgroup.GroupApplicationResponseReq) (err error) { - defer log.ZDebug(ctx, "return") +func (g *GroupNotificationSender) GroupApplicationRejectedNotification(ctx context.Context, req *pbgroup.GroupApplicationResponseReq) { + var err error defer func() { if err != nil { - log.ZError(ctx, utils.GetFuncName(1)+" failed", err) + log.ZError(ctx, stringutil.GetFuncName(1)+" failed", err) } }() - group, err := g.getGroupInfo(ctx, req.GroupID) + var group *sdkws.GroupInfo + group, err = g.getGroupInfo(ctx, req.GroupID) if err != nil { - return err + return } - userIDs, err := g.getGroupOwnerAndAdminUserID(ctx, req.GroupID) + var userIDs []string + userIDs, err = g.getGroupOwnerAndAdminUserID(ctx, req.GroupID) if err != nil { - return err + return } tips := &sdkws.GroupApplicationRejectedTips{Group: group, HandleMsg: req.HandledMsg} if err = g.fillOpUser(ctx, &tips.OpUser, tips.Group.GroupID); err != nil { - return err + return } for _, userID := range append(userIDs, req.FromUserID) { if userID == req.FromUserID { @@ -446,265 +441,281 @@ func (g *GroupNotificationSender) GroupApplicationRejectedNotification(ctx conte } else { tips.ReceiverAs = 1 } - err = g.Notification(ctx, mcontext.GetOpUserID(ctx), userID, constant.GroupApplicationRejectedNotification, tips) - if err != nil { - log.ZError(ctx, "failed", err) - } + g.Notification(ctx, mcontext.GetOpUserID(ctx), userID, constant.GroupApplicationRejectedNotification, tips) } - return nil } -func (g *GroupNotificationSender) GroupOwnerTransferredNotification(ctx context.Context, req *pbgroup.TransferGroupOwnerReq) (err error) { - defer log.ZDebug(ctx, "return") +func (g *GroupNotificationSender) GroupOwnerTransferredNotification(ctx context.Context, req *pbgroup.TransferGroupOwnerReq) { + var err error defer func() { if err != nil { - log.ZError(ctx, utils.GetFuncName(1)+" failed", err) + log.ZError(ctx, stringutil.GetFuncName(1)+" failed", err) } }() - group, err := g.getGroupInfo(ctx, req.GroupID) + var group *sdkws.GroupInfo + group, err = g.getGroupInfo(ctx, req.GroupID) if err != nil { - return err + return } opUserID := mcontext.GetOpUserID(ctx) - member, err := g.getGroupMemberMap(ctx, req.GroupID, []string{opUserID, req.NewOwnerUserID}) + var member map[string]*sdkws.GroupMemberFullInfo + member, err = g.getGroupMemberMap(ctx, req.GroupID, []string{opUserID, req.NewOwnerUserID}) if err != nil { - return err + return } tips := &sdkws.GroupOwnerTransferredTips{Group: group, OpUser: member[opUserID], NewGroupOwner: member[req.NewOwnerUserID]} - if err := g.fillOpUser(ctx, &tips.OpUser, tips.Group.GroupID); err != nil { - return err + if err = g.fillOpUser(ctx, &tips.OpUser, tips.Group.GroupID); err != nil { + return } - return g.Notification(ctx, mcontext.GetOpUserID(ctx), group.GroupID, constant.GroupOwnerTransferredNotification, tips) + g.Notification(ctx, mcontext.GetOpUserID(ctx), group.GroupID, constant.GroupOwnerTransferredNotification, tips) } -func (g *GroupNotificationSender) MemberKickedNotification(ctx context.Context, tips *sdkws.MemberKickedTips) (err error) { - defer log.ZDebug(ctx, "return") +func (g *GroupNotificationSender) MemberKickedNotification(ctx context.Context, tips *sdkws.MemberKickedTips) { + var err error defer func() { if err != nil { - log.ZError(ctx, utils.GetFuncName(1)+" failed", err) + log.ZError(ctx, stringutil.GetFuncName(1)+" failed", err) } }() - if err := g.fillOpUser(ctx, &tips.OpUser, tips.Group.GroupID); err != nil { - return err + if err = g.fillOpUser(ctx, &tips.OpUser, tips.Group.GroupID); err != nil { + return } - return g.Notification(ctx, mcontext.GetOpUserID(ctx), tips.Group.GroupID, constant.MemberKickedNotification, tips) + g.Notification(ctx, mcontext.GetOpUserID(ctx), tips.Group.GroupID, constant.MemberKickedNotification, tips) } -func (g *GroupNotificationSender) MemberInvitedNotification(ctx context.Context, groupID, reason string, invitedUserIDList []string) (err error) { - defer log.ZDebug(ctx, "return") +func (g *GroupNotificationSender) MemberInvitedNotification(ctx context.Context, groupID, reason string, invitedUserIDList []string) { + var err error defer func() { if err != nil { - log.ZError(ctx, utils.GetFuncName(1)+" failed", err) + log.ZError(ctx, stringutil.GetFuncName(1)+" failed", err) } }() - group, err := g.getGroupInfo(ctx, groupID) + var group *sdkws.GroupInfo + group, err = g.getGroupInfo(ctx, groupID) if err != nil { - return err + return } + + var users []*sdkws.GroupMemberFullInfo + users, err = g.getGroupMembers(ctx, groupID, invitedUserIDList) if err != nil { - return err - } - users, err := g.getGroupMembers(ctx, groupID, invitedUserIDList) - if err != nil { - return err + return } tips := &sdkws.MemberInvitedTips{Group: group, InvitedUserList: users} - if err := g.fillOpUser(ctx, &tips.OpUser, tips.Group.GroupID); err != nil { - return err - } - return g.Notification(ctx, mcontext.GetOpUserID(ctx), group.GroupID, constant.MemberInvitedNotification, tips) + err = g.fillOpUser(ctx, &tips.OpUser, tips.Group.GroupID) + g.Notification(ctx, mcontext.GetOpUserID(ctx), group.GroupID, constant.MemberInvitedNotification, tips) } -func (g *GroupNotificationSender) MemberEnterNotification(ctx context.Context, groupID string, entrantUserID string) (err error) { - defer log.ZDebug(ctx, "return") +func (g *GroupNotificationSender) MemberEnterNotification(ctx context.Context, groupID string, entrantUserID string) { + var err error defer func() { if err != nil { - log.ZError(ctx, utils.GetFuncName(1)+" failed", err) + log.ZError(ctx, stringutil.GetFuncName(1)+" failed", err) } }() - group, err := g.getGroupInfo(ctx, groupID) + var group *sdkws.GroupInfo + group, err = g.getGroupInfo(ctx, groupID) if err != nil { - return err + return } - user, err := g.getGroupMember(ctx, groupID, entrantUserID) + var user *sdkws.GroupMemberFullInfo + user, err = g.getGroupMember(ctx, groupID, entrantUserID) if err != nil { - return err + return } tips := &sdkws.MemberEnterTips{Group: group, EntrantUser: user} - return g.Notification(ctx, mcontext.GetOpUserID(ctx), group.GroupID, constant.MemberEnterNotification, tips) + g.Notification(ctx, mcontext.GetOpUserID(ctx), group.GroupID, constant.MemberEnterNotification, tips) } -func (g *GroupNotificationSender) GroupDismissedNotification(ctx context.Context, tips *sdkws.GroupDismissedTips) (err error) { - defer log.ZDebug(ctx, "return") +func (g *GroupNotificationSender) GroupDismissedNotification(ctx context.Context, tips *sdkws.GroupDismissedTips) { + var err error defer func() { if err != nil { - log.ZError(ctx, utils.GetFuncName(1)+" failed", err) + log.ZError(ctx, stringutil.GetFuncName(1)+" failed", err) } }() - if err := g.fillOpUser(ctx, &tips.OpUser, tips.Group.GroupID); err != nil { - return err + if err = g.fillOpUser(ctx, &tips.OpUser, tips.Group.GroupID); err != nil { + return } - return g.Notification(ctx, mcontext.GetOpUserID(ctx), tips.Group.GroupID, constant.GroupDismissedNotification, tips) + g.Notification(ctx, mcontext.GetOpUserID(ctx), tips.Group.GroupID, constant.GroupDismissedNotification, tips) } -func (g *GroupNotificationSender) GroupMemberMutedNotification(ctx context.Context, groupID, groupMemberUserID string, mutedSeconds uint32) (err error) { - defer log.ZDebug(ctx, "return") +func (g *GroupNotificationSender) GroupMemberMutedNotification(ctx context.Context, groupID, groupMemberUserID string, mutedSeconds uint32) { + var err error defer func() { if err != nil { - log.ZError(ctx, utils.GetFuncName(1)+" failed", err) + log.ZError(ctx, stringutil.GetFuncName(1)+" failed", err) } }() - group, err := g.getGroupInfo(ctx, groupID) + var group *sdkws.GroupInfo + group, err = g.getGroupInfo(ctx, groupID) if err != nil { - return err + return } - user, err := g.getGroupMemberMap(ctx, groupID, []string{mcontext.GetOpUserID(ctx), groupMemberUserID}) + var user map[string]*sdkws.GroupMemberFullInfo + user, err = g.getGroupMemberMap(ctx, groupID, []string{mcontext.GetOpUserID(ctx), groupMemberUserID}) if err != nil { - return err + return } tips := &sdkws.GroupMemberMutedTips{ Group: group, MutedSeconds: mutedSeconds, OpUser: user[mcontext.GetOpUserID(ctx)], MutedUser: user[groupMemberUserID], } - if err := g.fillOpUser(ctx, &tips.OpUser, tips.Group.GroupID); err != nil { - return err + if err = g.fillOpUser(ctx, &tips.OpUser, tips.Group.GroupID); err != nil { + return } - return g.Notification(ctx, mcontext.GetOpUserID(ctx), group.GroupID, constant.GroupMemberMutedNotification, tips) + g.Notification(ctx, mcontext.GetOpUserID(ctx), group.GroupID, constant.GroupMemberMutedNotification, tips) } -func (g *GroupNotificationSender) GroupMemberCancelMutedNotification(ctx context.Context, groupID, groupMemberUserID string) (err error) { - defer log.ZDebug(ctx, "return") +func (g *GroupNotificationSender) GroupMemberCancelMutedNotification(ctx context.Context, groupID, groupMemberUserID string) { + var err error defer func() { if err != nil { - log.ZError(ctx, utils.GetFuncName(1)+" failed", err) + log.ZError(ctx, stringutil.GetFuncName(1)+" failed", err) } }() - group, err := g.getGroupInfo(ctx, groupID) + var group *sdkws.GroupInfo + group, err = g.getGroupInfo(ctx, groupID) if err != nil { - return err + return } - user, err := g.getGroupMemberMap(ctx, groupID, []string{mcontext.GetOpUserID(ctx), groupMemberUserID}) + var user map[string]*sdkws.GroupMemberFullInfo + user, err = g.getGroupMemberMap(ctx, groupID, []string{mcontext.GetOpUserID(ctx), groupMemberUserID}) if err != nil { - return err + return } tips := &sdkws.GroupMemberCancelMutedTips{Group: group, OpUser: user[mcontext.GetOpUserID(ctx)], MutedUser: user[groupMemberUserID]} - if err := g.fillOpUser(ctx, &tips.OpUser, tips.Group.GroupID); err != nil { - return err + if err = g.fillOpUser(ctx, &tips.OpUser, tips.Group.GroupID); err != nil { + return } - return g.Notification(ctx, mcontext.GetOpUserID(ctx), group.GroupID, constant.GroupMemberCancelMutedNotification, tips) + g.Notification(ctx, mcontext.GetOpUserID(ctx), group.GroupID, constant.GroupMemberCancelMutedNotification, tips) } -func (g *GroupNotificationSender) GroupMutedNotification(ctx context.Context, groupID string) (err error) { - defer log.ZDebug(ctx, "return") +func (g *GroupNotificationSender) GroupMutedNotification(ctx context.Context, groupID string) { + var err error defer func() { if err != nil { - log.ZError(ctx, utils.GetFuncName(1)+" failed", err) + log.ZError(ctx, stringutil.GetFuncName(1)+" failed", err) } }() - group, err := g.getGroupInfo(ctx, groupID) + var group *sdkws.GroupInfo + group, err = g.getGroupInfo(ctx, groupID) if err != nil { - return err + return } - users, err := g.getGroupMembers(ctx, groupID, []string{mcontext.GetOpUserID(ctx)}) + var users []*sdkws.GroupMemberFullInfo + users, err = g.getGroupMembers(ctx, groupID, []string{mcontext.GetOpUserID(ctx)}) if err != nil { - return err + return } tips := &sdkws.GroupMutedTips{Group: group} if len(users) > 0 { tips.OpUser = users[0] } - if err := g.fillOpUser(ctx, &tips.OpUser, tips.Group.GroupID); err != nil { - return err + if err = g.fillOpUser(ctx, &tips.OpUser, tips.Group.GroupID); err != nil { + return } - return g.Notification(ctx, mcontext.GetOpUserID(ctx), group.GroupID, constant.GroupMutedNotification, tips) + g.Notification(ctx, mcontext.GetOpUserID(ctx), group.GroupID, constant.GroupMutedNotification, tips) } -func (g *GroupNotificationSender) GroupCancelMutedNotification(ctx context.Context, groupID string) (err error) { - defer log.ZDebug(ctx, "return") +func (g *GroupNotificationSender) GroupCancelMutedNotification(ctx context.Context, groupID string) { + var err error defer func() { if err != nil { - log.ZError(ctx, utils.GetFuncName(1)+" failed", err) + log.ZError(ctx, stringutil.GetFuncName(1)+" failed", err) } }() - group, err := g.getGroupInfo(ctx, groupID) + var group *sdkws.GroupInfo + group, err = g.getGroupInfo(ctx, groupID) if err != nil { - return err + return } - users, err := g.getGroupMembers(ctx, groupID, []string{mcontext.GetOpUserID(ctx)}) + var users []*sdkws.GroupMemberFullInfo + users, err = g.getGroupMembers(ctx, groupID, []string{mcontext.GetOpUserID(ctx)}) if err != nil { - return err + return } tips := &sdkws.GroupCancelMutedTips{Group: group} if len(users) > 0 { tips.OpUser = users[0] } - if err := g.fillOpUser(ctx, &tips.OpUser, tips.Group.GroupID); err != nil { - return err + if err = g.fillOpUser(ctx, &tips.OpUser, tips.Group.GroupID); err != nil { + return } - return g.Notification(ctx, mcontext.GetOpUserID(ctx), group.GroupID, constant.GroupCancelMutedNotification, tips) + g.Notification(ctx, mcontext.GetOpUserID(ctx), group.GroupID, constant.GroupCancelMutedNotification, tips) } -func (g *GroupNotificationSender) GroupMemberInfoSetNotification(ctx context.Context, groupID, groupMemberUserID string) (err error) { - group, err := g.getGroupInfo(ctx, groupID) +func (g *GroupNotificationSender) GroupMemberInfoSetNotification(ctx context.Context, groupID, groupMemberUserID string) { + var err error + defer func() { + if err != nil { + log.ZError(ctx, stringutil.GetFuncName(1)+" failed", err) + } + }() + var group *sdkws.GroupInfo + group, err = g.getGroupInfo(ctx, groupID) if err != nil { - return err + return } - user, err := g.getGroupMemberMap(ctx, groupID, []string{groupMemberUserID}) + var user map[string]*sdkws.GroupMemberFullInfo + user, err = g.getGroupMemberMap(ctx, groupID, []string{groupMemberUserID}) if err != nil { - return err + return } tips := &sdkws.GroupMemberInfoSetTips{Group: group, OpUser: user[mcontext.GetOpUserID(ctx)], ChangedUser: user[groupMemberUserID]} - if err := g.fillOpUser(ctx, &tips.OpUser, tips.Group.GroupID); err != nil { - return err + if err = g.fillOpUser(ctx, &tips.OpUser, tips.Group.GroupID); err != nil { + return } - return g.Notification(ctx, mcontext.GetOpUserID(ctx), group.GroupID, constant.GroupMemberInfoSetNotification, tips) + g.Notification(ctx, mcontext.GetOpUserID(ctx), group.GroupID, constant.GroupMemberInfoSetNotification, tips) } -func (g *GroupNotificationSender) GroupMemberSetToAdminNotification(ctx context.Context, groupID, groupMemberUserID string) (err error) { - group, err := g.getGroupInfo(ctx, groupID) +func (g *GroupNotificationSender) GroupMemberSetToAdminNotification(ctx context.Context, groupID, groupMemberUserID string) { + var err error + defer func() { + if err != nil { + log.ZError(ctx, stringutil.GetFuncName(1)+" failed", err) + } + }() + var group *sdkws.GroupInfo + group, err = g.getGroupInfo(ctx, groupID) if err != nil { - return err + return } user, err := g.getGroupMemberMap(ctx, groupID, []string{mcontext.GetOpUserID(ctx), groupMemberUserID}) if err != nil { - return err + return } tips := &sdkws.GroupMemberInfoSetTips{Group: group, OpUser: user[mcontext.GetOpUserID(ctx)], ChangedUser: user[groupMemberUserID]} - if err := g.fillOpUser(ctx, &tips.OpUser, tips.Group.GroupID); err != nil { - return err + if err = g.fillOpUser(ctx, &tips.OpUser, tips.Group.GroupID); err != nil { + return } - return g.Notification(ctx, mcontext.GetOpUserID(ctx), group.GroupID, constant.GroupMemberSetToAdminNotification, tips) + g.Notification(ctx, mcontext.GetOpUserID(ctx), group.GroupID, constant.GroupMemberSetToAdminNotification, tips) } -func (g *GroupNotificationSender) GroupMemberSetToOrdinaryUserNotification(ctx context.Context, groupID, groupMemberUserID string) (err error) { - defer log.ZDebug(ctx, "return") +func (g *GroupNotificationSender) GroupMemberSetToOrdinaryUserNotification(ctx context.Context, groupID, groupMemberUserID string) { + var err error defer func() { if err != nil { - log.ZError(ctx, utils.GetFuncName(1)+" failed", err) + log.ZError(ctx, stringutil.GetFuncName(1)+" failed", err) } }() - group, err := g.getGroupInfo(ctx, groupID) + var group *sdkws.GroupInfo + group, err = g.getGroupInfo(ctx, groupID) if err != nil { - return err + return } - user, err := g.getGroupMemberMap(ctx, groupID, []string{mcontext.GetOpUserID(ctx), groupMemberUserID}) + var user map[string]*sdkws.GroupMemberFullInfo + user, err = g.getGroupMemberMap(ctx, groupID, []string{mcontext.GetOpUserID(ctx), groupMemberUserID}) if err != nil { - return err + return } tips := &sdkws.GroupMemberInfoSetTips{Group: group, OpUser: user[mcontext.GetOpUserID(ctx)], ChangedUser: user[groupMemberUserID]} - if err := g.fillOpUser(ctx, &tips.OpUser, tips.Group.GroupID); err != nil { - return err + if err = g.fillOpUser(ctx, &tips.OpUser, tips.Group.GroupID); err != nil { + return } - return g.Notification(ctx, mcontext.GetOpUserID(ctx), group.GroupID, constant.GroupMemberSetToOrdinaryUserNotification, tips) + g.Notification(ctx, mcontext.GetOpUserID(ctx), group.GroupID, constant.GroupMemberSetToOrdinaryUserNotification, tips) } -func (g *GroupNotificationSender) SuperGroupNotification(ctx context.Context, sendID, recvID string) (err error) { - defer log.ZDebug(ctx, "return") - defer func() { - if err != nil { - log.ZError(ctx, utils.GetFuncName(1)+" failed", err) - } - }() - err = g.Notification(ctx, sendID, recvID, constant.SuperGroupUpdateNotification, nil) - return err +func (g *GroupNotificationSender) SuperGroupNotification(ctx context.Context, sendID, recvID string) { + g.Notification(ctx, sendID, recvID, constant.SuperGroupUpdateNotification, nil) } diff --git a/internal/rpc/group/statistics.go b/internal/rpc/group/statistics.go index d909e95035..6adb1261af 100644 --- a/internal/rpc/group/statistics.go +++ b/internal/rpc/group/statistics.go @@ -18,13 +18,13 @@ import ( "context" "time" - "github.com/OpenIMSDK/protocol/group" - "github.com/OpenIMSDK/tools/errs" + "github.com/openimsdk/protocol/group" + "github.com/openimsdk/tools/errs" ) func (s *groupServer) GroupCreateCount(ctx context.Context, req *group.GroupCreateCountReq) (*group.GroupCreateCountResp, error) { if req.Start > req.End { - return nil, errs.ErrArgs.Wrap("start > end") + return nil, errs.ErrArgs.WrapMsg("start > end: %d > %d", req.Start, req.End) } total, err := s.db.CountTotal(ctx, nil) if err != nil { diff --git a/internal/rpc/group/super_group.go b/internal/rpc/group/super_group.go deleted file mode 100644 index f893a79c23..0000000000 --- a/internal/rpc/group/super_group.go +++ /dev/null @@ -1,30 +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 group - -import ( - "context" - "errors" - - pbgroup "github.com/OpenIMSDK/protocol/group" -) - -func (s *groupServer) GetJoinedSuperGroupList(context.Context, *pbgroup.GetJoinedSuperGroupListReq) (*pbgroup.GetJoinedSuperGroupListResp, error) { - return nil, errors.New("deprecated") -} - -func (s *groupServer) GetSuperGroupsInfo(context.Context, *pbgroup.GetSuperGroupsInfoReq) (resp *pbgroup.GetSuperGroupsInfoResp, err error) { - return nil, errors.New("deprecated") -} diff --git a/internal/rpc/msg/as_read.go b/internal/rpc/msg/as_read.go index ef7c72368d..bfba4824fe 100644 --- a/internal/rpc/msg/as_read.go +++ b/internal/rpc/msg/as_read.go @@ -17,19 +17,20 @@ package msg import ( "context" - "github.com/OpenIMSDK/protocol/constant" - "github.com/OpenIMSDK/protocol/msg" - "github.com/OpenIMSDK/protocol/sdkws" - "github.com/OpenIMSDK/tools/errs" - "github.com/OpenIMSDK/tools/log" - utils2 "github.com/OpenIMSDK/tools/utils" cbapi "github.com/openimsdk/open-im-server/v3/pkg/callbackstruct" + "github.com/openimsdk/protocol/constant" + "github.com/openimsdk/protocol/msg" + "github.com/openimsdk/protocol/sdkws" + "github.com/openimsdk/tools/errs" + "github.com/openimsdk/tools/log" + "github.com/openimsdk/tools/utils/datautil" "github.com/redis/go-redis/v9" ) -func (m *msgServer) GetConversationsHasReadAndMaxSeq(ctx context.Context, req *msg.GetConversationsHasReadAndMaxSeqReq) (resp *msg.GetConversationsHasReadAndMaxSeqResp, err error) { +func (m *msgServer) GetConversationsHasReadAndMaxSeq(ctx context.Context, req *msg.GetConversationsHasReadAndMaxSeqReq) (*msg.GetConversationsHasReadAndMaxSeqResp, error) { var conversationIDs []string if len(req.ConversationIDs) == 0 { + var err error conversationIDs, err = m.ConversationLocalCache.GetConversationIDs(ctx, req.UserID) if err != nil { return nil, err @@ -37,14 +38,17 @@ func (m *msgServer) GetConversationsHasReadAndMaxSeq(ctx context.Context, req *m } else { conversationIDs = req.ConversationIDs } + hasReadSeqs, err := m.MsgDatabase.GetHasReadSeqs(ctx, req.UserID, conversationIDs) if err != nil { return nil, err } + conversations, err := m.ConversationLocalCache.GetConversations(ctx, req.UserID, conversationIDs) if err != nil { return nil, err } + conversationMaxSeqMap := make(map[string]int64) for _, conversation := range conversations { if conversation.MaxSeq != 0 { @@ -55,95 +59,77 @@ func (m *msgServer) GetConversationsHasReadAndMaxSeq(ctx context.Context, req *m if err != nil { return nil, err } - resp = &msg.GetConversationsHasReadAndMaxSeqResp{Seqs: make(map[string]*msg.Seqs)} - for conversarionID, maxSeq := range maxSeqs { - resp.Seqs[conversarionID] = &msg.Seqs{ - HasReadSeq: hasReadSeqs[conversarionID], + resp := &msg.GetConversationsHasReadAndMaxSeqResp{Seqs: make(map[string]*msg.Seqs)} + for conversationID, maxSeq := range maxSeqs { + resp.Seqs[conversationID] = &msg.Seqs{ + HasReadSeq: hasReadSeqs[conversationID], MaxSeq: maxSeq, } - if v, ok := conversationMaxSeqMap[conversarionID]; ok { - resp.Seqs[conversarionID].MaxSeq = v + if v, ok := conversationMaxSeqMap[conversationID]; ok { + resp.Seqs[conversationID].MaxSeq = v } } return resp, nil } -func (m *msgServer) SetConversationHasReadSeq( - ctx context.Context, - req *msg.SetConversationHasReadSeqReq, -) (resp *msg.SetConversationHasReadSeqResp, err error) { +func (m *msgServer) SetConversationHasReadSeq(ctx context.Context, req *msg.SetConversationHasReadSeqReq) (*msg.SetConversationHasReadSeqResp, error) { maxSeq, err := m.MsgDatabase.GetMaxSeq(ctx, req.ConversationID) if err != nil { - return + return nil, err } if req.HasReadSeq > maxSeq { - return nil, errs.ErrArgs.Wrap("hasReadSeq must not be bigger than maxSeq") + return nil, errs.ErrArgs.WrapMsg("hasReadSeq must not be bigger than maxSeq") } if err := m.MsgDatabase.SetHasReadSeq(ctx, req.UserID, req.ConversationID, req.HasReadSeq); err != nil { return nil, err } - if err = m.sendMarkAsReadNotification(ctx, req.ConversationID, constant.SingleChatType, req.UserID, - req.UserID, nil, req.HasReadSeq); err != nil { - return - } + m.sendMarkAsReadNotification(ctx, req.ConversationID, constant.SingleChatType, req.UserID, req.UserID, nil, req.HasReadSeq) return &msg.SetConversationHasReadSeqResp{}, nil } -func (m *msgServer) MarkMsgsAsRead( - ctx context.Context, - req *msg.MarkMsgsAsReadReq, -) (resp *msg.MarkMsgsAsReadResp, err error) { +func (m *msgServer) MarkMsgsAsRead(ctx context.Context, req *msg.MarkMsgsAsReadReq) (*msg.MarkMsgsAsReadResp, error) { if len(req.Seqs) < 1 { - return nil, errs.ErrArgs.Wrap("seqs must not be empty") + return nil, errs.ErrArgs.WrapMsg("seqs must not be empty") } maxSeq, err := m.MsgDatabase.GetMaxSeq(ctx, req.ConversationID) if err != nil { - return + return nil, err } hasReadSeq := req.Seqs[len(req.Seqs)-1] if hasReadSeq > maxSeq { - return nil, errs.ErrArgs.Wrap("hasReadSeq must not be bigger than maxSeq") + return nil, errs.ErrArgs.WrapMsg("hasReadSeq must not be bigger than maxSeq") } conversation, err := m.ConversationLocalCache.GetConversation(ctx, req.UserID, req.ConversationID) if err != nil { - return + return nil, err } - if err = m.MsgDatabase.MarkSingleChatMsgsAsRead(ctx, req.UserID, req.ConversationID, req.Seqs); err != nil { - return + if err := m.MsgDatabase.MarkSingleChatMsgsAsRead(ctx, req.UserID, req.ConversationID, req.Seqs); err != nil { + return nil, err } - currentHasReadSeq, err := m.MsgDatabase.GetHasReadSeq(ctx, req.UserID, req.ConversationID) if err != nil && errs.Unwrap(err) != redis.Nil { - return + return nil, err } if hasReadSeq > currentHasReadSeq { err = m.MsgDatabase.SetHasReadSeq(ctx, req.UserID, req.ConversationID, hasReadSeq) if err != nil { - return + return nil, err } } - req_callback := &cbapi.CallbackSingleMsgReadReq{ + reqCallback := &cbapi.CallbackSingleMsgReadReq{ ConversationID: conversation.ConversationID, UserID: req.UserID, Seqs: req.Seqs, ContentType: conversation.ConversationType, } - if err = CallbackSingleMsgRead(ctx, m.config, req_callback); err != nil { - return nil, err - } - - if err = m.sendMarkAsReadNotification(ctx, req.ConversationID, conversation.ConversationType, req.UserID, - m.conversationAndGetRecvID(conversation, req.UserID), req.Seqs, hasReadSeq); err != nil { - return - } + m.webhookAfterSingleMsgRead(ctx, &m.config.WebhooksConfig.AfterSingleMsgRead, reqCallback) + m.sendMarkAsReadNotification(ctx, req.ConversationID, conversation.ConversationType, req.UserID, + m.conversationAndGetRecvID(conversation, req.UserID), req.Seqs, hasReadSeq) return &msg.MarkMsgsAsReadResp{}, nil } -func (m *msgServer) MarkConversationAsRead( - ctx context.Context, - req *msg.MarkConversationAsReadReq, -) (resp *msg.MarkConversationAsReadResp, err error) { +func (m *msgServer) MarkConversationAsRead(ctx context.Context, req *msg.MarkConversationAsReadReq) (*msg.MarkConversationAsReadResp, error) { conversation, err := m.ConversationLocalCache.GetConversation(ctx, req.UserID, req.ConversationID) if err != nil { return nil, err @@ -154,15 +140,14 @@ func (m *msgServer) MarkConversationAsRead( } var seqs []int64 - log.ZDebug(ctx, "MarkConversationAsRead", "hasReadSeq", hasReadSeq, - "req.HasReadSeq", req.HasReadSeq) + log.ZDebug(ctx, "MarkConversationAsRead", "hasReadSeq", hasReadSeq, "req.HasReadSeq", req.HasReadSeq) if conversation.ConversationType == constant.SingleChatType { for i := hasReadSeq + 1; i <= req.HasReadSeq; i++ { seqs = append(seqs, i) } - //avoid client missed call MarkConversationMessageAsRead by order + // avoid client missed call MarkConversationMessageAsRead by order for _, val := range req.Seqs { - if !utils2.Contain(val, seqs...) { + if !datautil.Contain(val, seqs...) { seqs = append(seqs, val) } } @@ -179,12 +164,9 @@ func (m *msgServer) MarkConversationAsRead( } hasReadSeq = req.HasReadSeq } - if err = m.sendMarkAsReadNotification(ctx, req.ConversationID, conversation.ConversationType, req.UserID, - m.conversationAndGetRecvID(conversation, req.UserID), seqs, hasReadSeq); err != nil { - return nil, err - } - - } else if conversation.ConversationType == constant.SuperGroupChatType || + m.sendMarkAsReadNotification(ctx, req.ConversationID, conversation.ConversationType, req.UserID, + m.conversationAndGetRecvID(conversation, req.UserID), seqs, hasReadSeq) + } else if conversation.ConversationType == constant.ReadGroupChatType || conversation.ConversationType == constant.NotificationChatType { if req.HasReadSeq > hasReadSeq { err = m.MsgDatabase.SetHasReadSeq(ctx, req.UserID, req.ConversationID, req.HasReadSeq) @@ -193,11 +175,8 @@ func (m *msgServer) MarkConversationAsRead( } hasReadSeq = req.HasReadSeq } - if err = m.sendMarkAsReadNotification(ctx, req.ConversationID, constant.SingleChatType, req.UserID, - req.UserID, seqs, hasReadSeq); err != nil { - return nil, err - } - + m.sendMarkAsReadNotification(ctx, req.ConversationID, constant.SingleChatType, req.UserID, + req.UserID, seqs, hasReadSeq) } reqCall := &cbapi.CallbackGroupMsgReadReq{ @@ -206,30 +185,18 @@ func (m *msgServer) MarkConversationAsRead( UnreadMsgNum: req.HasReadSeq, ContentType: int64(conversation.ConversationType), } - if err := CallbackGroupMsgRead(ctx, m.config, reqCall); err != nil { - return nil, err - } + m.webhookAfterGroupMsgRead(ctx, &m.config.WebhooksConfig.AfterGroupMsgRead, reqCall) return &msg.MarkConversationAsReadResp{}, nil } -func (m *msgServer) sendMarkAsReadNotification( - ctx context.Context, - conversationID string, - sessionType int32, - sendID, recvID string, - seqs []int64, - hasReadSeq int64, -) error { +func (m *msgServer) sendMarkAsReadNotification(ctx context.Context, conversationID string, sessionType int32, sendID, recvID string, seqs []int64, hasReadSeq int64) { tips := &sdkws.MarkAsReadTips{ MarkAsReadUserID: sendID, ConversationID: conversationID, Seqs: seqs, HasReadSeq: hasReadSeq, } - err := m.notificationSender.NotificationWithSesstionType(ctx, sendID, recvID, constant.HasReadReceipt, sessionType, tips) - if err != nil { - log.ZWarn(ctx, "send has read Receipt err", err) - } - return nil + m.notificationSender.NotificationWithSessionType(ctx, sendID, recvID, constant.HasReadReceipt, sessionType, tips) + } diff --git a/internal/rpc/msg/callback.go b/internal/rpc/msg/callback.go index 927bbe0c22..10404675eb 100644 --- a/internal/rpc/msg/callback.go +++ b/internal/rpc/msg/callback.go @@ -16,16 +16,15 @@ package msg import ( "context" + "github.com/openimsdk/open-im-server/v3/pkg/common/webhook" - "github.com/OpenIMSDK/protocol/constant" - pbchat "github.com/OpenIMSDK/protocol/msg" - "github.com/OpenIMSDK/protocol/sdkws" - "github.com/OpenIMSDK/tools/log" - "github.com/OpenIMSDK/tools/mcontext" - "github.com/OpenIMSDK/tools/utils" cbapi "github.com/openimsdk/open-im-server/v3/pkg/callbackstruct" "github.com/openimsdk/open-im-server/v3/pkg/common/config" - "github.com/openimsdk/open-im-server/v3/pkg/common/http" + "github.com/openimsdk/protocol/constant" + pbchat "github.com/openimsdk/protocol/msg" + "github.com/openimsdk/protocol/sdkws" + "github.com/openimsdk/tools/mcontext" + "github.com/openimsdk/tools/utils/datautil" "google.golang.org/protobuf/proto" ) @@ -62,138 +61,118 @@ func GetContent(msg *sdkws.MsgData) string { } } -func callbackBeforeSendSingleMsg(ctx context.Context, globalConfig *config.GlobalConfig, msg *pbchat.SendMsgReq) error { - if !globalConfig.Callback.CallbackBeforeSendSingleMsg.Enable || msg.MsgData.ContentType == constant.Typing { +func (m *msgServer) webhookBeforeSendSingleMsg(ctx context.Context, before *config.BeforeConfig, msg *pbchat.SendMsgReq) error { + return webhook.WithCondition(ctx, before, func(ctx context.Context) error { + if msg.MsgData.ContentType == constant.Typing { + return nil + } + cbReq := &cbapi.CallbackBeforeSendSingleMsgReq{ + CommonCallbackReq: toCommonCallback(ctx, msg, cbapi.CallbackBeforeSendSingleMsgCommand), + RecvID: msg.MsgData.RecvID, + } + resp := &cbapi.CallbackBeforeSendSingleMsgResp{} + if err := m.webhookClient.SyncPost(ctx, cbReq.GetCallbackCommand(), cbReq, resp, before); err != nil { + return err + } + return nil - } - req := &cbapi.CallbackBeforeSendSingleMsgReq{ - CommonCallbackReq: toCommonCallback(ctx, msg, cbapi.CallbackBeforeSendSingleMsgCommand), - RecvID: msg.MsgData.RecvID, - } - resp := &cbapi.CallbackBeforeSendSingleMsgResp{} - if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, req, resp, globalConfig.Callback.CallbackBeforeSendSingleMsg); err != nil { - return err - } - return nil + }) } -func callbackAfterSendSingleMsg(ctx context.Context, globalConfig *config.GlobalConfig, msg *pbchat.SendMsgReq) error { - if !globalConfig.Callback.CallbackAfterSendSingleMsg.Enable || msg.MsgData.ContentType == constant.Typing { - return nil +func (m *msgServer) webhookAfterSendSingleMsg(ctx context.Context, after *config.AfterConfig, msg *pbchat.SendMsgReq) { + if msg.MsgData.ContentType == constant.Typing { + return } - req := &cbapi.CallbackAfterSendSingleMsgReq{ + cbReq := &cbapi.CallbackAfterSendSingleMsgReq{ CommonCallbackReq: toCommonCallback(ctx, msg, cbapi.CallbackAfterSendSingleMsgCommand), RecvID: msg.MsgData.RecvID, } - resp := &cbapi.CallbackAfterSendSingleMsgResp{} - if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, req, resp, globalConfig.Callback.CallbackAfterSendSingleMsg); err != nil { - return err - } - return nil + m.webhookClient.AsyncPost(ctx, cbReq.GetCallbackCommand(), cbReq, &cbapi.CallbackAfterSendSingleMsgResp{}, after) } -func callbackBeforeSendGroupMsg(ctx context.Context, globalConfig *config.GlobalConfig, msg *pbchat.SendMsgReq) error { - if !globalConfig.Callback.CallbackBeforeSendGroupMsg.Enable || msg.MsgData.ContentType == constant.Typing { +func (m *msgServer) webhookBeforeSendGroupMsg(ctx context.Context, before *config.BeforeConfig, msg *pbchat.SendMsgReq) error { + return webhook.WithCondition(ctx, before, func(ctx context.Context) error { + if msg.MsgData.ContentType == constant.Typing { + return nil + } + cbReq := &cbapi.CallbackBeforeSendGroupMsgReq{ + CommonCallbackReq: toCommonCallback(ctx, msg, cbapi.CallbackBeforeSendGroupMsgCommand), + GroupID: msg.MsgData.GroupID, + } + resp := &cbapi.CallbackBeforeSendGroupMsgResp{} + if err := m.webhookClient.SyncPost(ctx, cbReq.GetCallbackCommand(), cbReq, resp, before); err != nil { + return err + } return nil - } - req := &cbapi.CallbackBeforeSendGroupMsgReq{ - CommonCallbackReq: toCommonCallback(ctx, msg, cbapi.CallbackBeforeSendGroupMsgCommand), - GroupID: msg.MsgData.GroupID, - } - resp := &cbapi.CallbackBeforeSendGroupMsgResp{} - if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, req, resp, globalConfig.Callback.CallbackBeforeSendGroupMsg); err != nil { - return err - } - return nil + }) } -func callbackAfterSendGroupMsg(ctx context.Context, globalConfig *config.GlobalConfig, msg *pbchat.SendMsgReq) error { - if !globalConfig.Callback.CallbackAfterSendGroupMsg.Enable || msg.MsgData.ContentType == constant.Typing { - return nil +func (m *msgServer) webhookAfterSendGroupMsg(ctx context.Context, after *config.AfterConfig, msg *pbchat.SendMsgReq) { + if msg.MsgData.ContentType == constant.Typing { + return } - req := &cbapi.CallbackAfterSendGroupMsgReq{ + cbReq := &cbapi.CallbackAfterSendGroupMsgReq{ CommonCallbackReq: toCommonCallback(ctx, msg, cbapi.CallbackAfterSendGroupMsgCommand), GroupID: msg.MsgData.GroupID, } - resp := &cbapi.CallbackAfterSendGroupMsgResp{} - if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, req, resp, globalConfig.Callback.CallbackAfterSendGroupMsg); err != nil { - return err - } - return nil + m.webhookClient.AsyncPost(ctx, cbReq.GetCallbackCommand(), cbReq, &cbapi.CallbackAfterSendGroupMsgResp{}, after) } -func callbackMsgModify(ctx context.Context, globalConfig *config.GlobalConfig, msg *pbchat.SendMsgReq) error { - if !globalConfig.Callback.CallbackMsgModify.Enable || msg.MsgData.ContentType != constant.Text { +func (m *msgServer) webhookBeforeMsgModify(ctx context.Context, before *config.BeforeConfig, msg *pbchat.SendMsgReq) error { + return webhook.WithCondition(ctx, before, func(ctx context.Context) error { + if msg.MsgData.ContentType != constant.Text { + return nil + } + cbReq := &cbapi.CallbackMsgModifyCommandReq{ + CommonCallbackReq: toCommonCallback(ctx, msg, cbapi.CallbackBeforeMsgModifyCommand), + } + resp := &cbapi.CallbackMsgModifyCommandResp{} + if err := m.webhookClient.SyncPost(ctx, cbReq.GetCallbackCommand(), cbReq, resp, before); err != nil { + return err + } + + if resp.Content != nil { + msg.MsgData.Content = []byte(*resp.Content) + } + datautil.NotNilReplace(msg.MsgData.OfflinePushInfo, resp.OfflinePushInfo) + datautil.NotNilReplace(&msg.MsgData.RecvID, resp.RecvID) + datautil.NotNilReplace(&msg.MsgData.GroupID, resp.GroupID) + datautil.NotNilReplace(&msg.MsgData.ClientMsgID, resp.ClientMsgID) + datautil.NotNilReplace(&msg.MsgData.ServerMsgID, resp.ServerMsgID) + datautil.NotNilReplace(&msg.MsgData.SenderPlatformID, resp.SenderPlatformID) + datautil.NotNilReplace(&msg.MsgData.SenderNickname, resp.SenderNickname) + datautil.NotNilReplace(&msg.MsgData.SenderFaceURL, resp.SenderFaceURL) + datautil.NotNilReplace(&msg.MsgData.SessionType, resp.SessionType) + datautil.NotNilReplace(&msg.MsgData.MsgFrom, resp.MsgFrom) + datautil.NotNilReplace(&msg.MsgData.ContentType, resp.ContentType) + datautil.NotNilReplace(&msg.MsgData.Status, resp.Status) + datautil.NotNilReplace(&msg.MsgData.Options, resp.Options) + datautil.NotNilReplace(&msg.MsgData.AtUserIDList, resp.AtUserIDList) + datautil.NotNilReplace(&msg.MsgData.AttachedInfo, resp.AttachedInfo) + datautil.NotNilReplace(&msg.MsgData.Ex, resp.Ex) return nil - } - req := &cbapi.CallbackMsgModifyCommandReq{ - CommonCallbackReq: toCommonCallback(ctx, msg, cbapi.CallbackMsgModifyCommand), - } - resp := &cbapi.CallbackMsgModifyCommandResp{} - if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, req, resp, globalConfig.Callback.CallbackMsgModify); err != nil { - return err - } - if resp.Content != nil { - msg.MsgData.Content = []byte(*resp.Content) - } - utils.NotNilReplace(msg.MsgData.OfflinePushInfo, resp.OfflinePushInfo) - utils.NotNilReplace(&msg.MsgData.RecvID, resp.RecvID) - utils.NotNilReplace(&msg.MsgData.GroupID, resp.GroupID) - utils.NotNilReplace(&msg.MsgData.ClientMsgID, resp.ClientMsgID) - utils.NotNilReplace(&msg.MsgData.ServerMsgID, resp.ServerMsgID) - utils.NotNilReplace(&msg.MsgData.SenderPlatformID, resp.SenderPlatformID) - utils.NotNilReplace(&msg.MsgData.SenderNickname, resp.SenderNickname) - utils.NotNilReplace(&msg.MsgData.SenderFaceURL, resp.SenderFaceURL) - utils.NotNilReplace(&msg.MsgData.SessionType, resp.SessionType) - utils.NotNilReplace(&msg.MsgData.MsgFrom, resp.MsgFrom) - utils.NotNilReplace(&msg.MsgData.ContentType, resp.ContentType) - utils.NotNilReplace(&msg.MsgData.Status, resp.Status) - utils.NotNilReplace(&msg.MsgData.Options, resp.Options) - utils.NotNilReplace(&msg.MsgData.AtUserIDList, resp.AtUserIDList) - utils.NotNilReplace(&msg.MsgData.AttachedInfo, resp.AttachedInfo) - utils.NotNilReplace(&msg.MsgData.Ex, resp.Ex) - log.ZDebug(ctx, "callbackMsgModify", "msg", msg.MsgData) - return nil + }) } -func CallbackGroupMsgRead(ctx context.Context, globalConfig *config.GlobalConfig, req *cbapi.CallbackGroupMsgReadReq) error { - if !globalConfig.Callback.CallbackGroupMsgRead.Enable { - return nil - } - req.CallbackCommand = cbapi.CallbackGroupMsgReadCommand - resp := &cbapi.CallbackGroupMsgReadResp{} - if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, req, resp, globalConfig.Callback.CallbackGroupMsgRead); err != nil { - return err - } - return nil +func (m *msgServer) webhookAfterGroupMsgRead(ctx context.Context, after *config.AfterConfig, req *cbapi.CallbackGroupMsgReadReq) { + req.CallbackCommand = cbapi.CallbackAfterGroupMsgReadCommand + m.webhookClient.AsyncPost(ctx, req.GetCallbackCommand(), req, &cbapi.CallbackGroupMsgReadResp{}, after) } -func CallbackSingleMsgRead(ctx context.Context, globalConfig *config.GlobalConfig, req *cbapi.CallbackSingleMsgReadReq) error { - if !globalConfig.Callback.CallbackSingleMsgRead.Enable { - return nil - } - req.CallbackCommand = cbapi.CallbackSingleMsgRead +func (m *msgServer) webhookAfterSingleMsgRead(ctx context.Context, after *config.AfterConfig, req *cbapi.CallbackSingleMsgReadReq) { - resp := &cbapi.CallbackSingleMsgReadResp{} + req.CallbackCommand = cbapi.CallbackAfterSingleMsgReadCommand + + m.webhookClient.AsyncPost(ctx, req.GetCallbackCommand(), req, &cbapi.CallbackSingleMsgReadResp{}, after) - if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, req, resp, globalConfig.Callback.CallbackSingleMsgRead); err != nil { - return err - } - return nil } -func CallbackAfterRevokeMsg(ctx context.Context, globalConfig *config.GlobalConfig, req *pbchat.RevokeMsgReq) error { - if !globalConfig.Callback.CallbackAfterRevokeMsg.Enable { - return nil - } + +func (m *msgServer) webhookAfterRevokeMsg(ctx context.Context, after *config.AfterConfig, req *pbchat.RevokeMsgReq) { callbackReq := &cbapi.CallbackAfterRevokeMsgReq{ CallbackCommand: cbapi.CallbackAfterRevokeMsgCommand, ConversationID: req.ConversationID, Seq: req.Seq, UserID: req.UserID, } - resp := &cbapi.CallbackAfterRevokeMsgResp{} - if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, callbackReq, resp, globalConfig.Callback.CallbackAfterRevokeMsg); err != nil { - return err - } - return nil + m.webhookClient.AsyncPost(ctx, callbackReq.GetCallbackCommand(), callbackReq, &cbapi.CallbackAfterRevokeMsgResp{}, after) } diff --git a/internal/rpc/msg/delete.go b/internal/rpc/msg/delete.go index 14e24d23e1..e19bba867e 100644 --- a/internal/rpc/msg/delete.go +++ b/internal/rpc/msg/delete.go @@ -17,13 +17,13 @@ package msg import ( "context" - "github.com/OpenIMSDK/protocol/constant" - "github.com/OpenIMSDK/protocol/conversation" - "github.com/OpenIMSDK/protocol/msg" - "github.com/OpenIMSDK/protocol/sdkws" - "github.com/OpenIMSDK/tools/log" - "github.com/OpenIMSDK/tools/utils" "github.com/openimsdk/open-im-server/v3/pkg/authverify" + "github.com/openimsdk/protocol/constant" + "github.com/openimsdk/protocol/conversation" + "github.com/openimsdk/protocol/msg" + "github.com/openimsdk/protocol/sdkws" + "github.com/openimsdk/tools/log" + "github.com/openimsdk/tools/utils/timeutil" ) func (m *msgServer) getMinSeqs(maxSeqs map[string]int64) map[string]int64 { @@ -41,11 +41,8 @@ func (m *msgServer) validateDeleteSyncOpt(opt *msg.DeleteSyncOpt) (isSyncSelf, i return opt.IsSyncSelf, opt.IsSyncOther } -func (m *msgServer) ClearConversationsMsg( - ctx context.Context, - req *msg.ClearConversationsMsgReq, -) (*msg.ClearConversationsMsgResp, error) { - if err := authverify.CheckAccessV3(ctx, req.UserID, m.config); err != nil { +func (m *msgServer) ClearConversationsMsg(ctx context.Context, req *msg.ClearConversationsMsgReq) (*msg.ClearConversationsMsgResp, error) { + if err := authverify.CheckAccessV3(ctx, req.UserID, m.config.Share.IMAdminUserID); err != nil { return nil, err } if err := m.clearConversation(ctx, req.ConversationIDs, req.UserID, req.DeleteSyncOpt); err != nil { @@ -54,18 +51,14 @@ func (m *msgServer) ClearConversationsMsg( return &msg.ClearConversationsMsgResp{}, nil } -func (m *msgServer) UserClearAllMsg( - ctx context.Context, - req *msg.UserClearAllMsgReq, -) (*msg.UserClearAllMsgResp, error) { - if err := authverify.CheckAccessV3(ctx, req.UserID, m.config); err != nil { +func (m *msgServer) UserClearAllMsg(ctx context.Context, req *msg.UserClearAllMsgReq) (*msg.UserClearAllMsgResp, error) { + if err := authverify.CheckAccessV3(ctx, req.UserID, m.config.Share.IMAdminUserID); err != nil { return nil, err } conversationIDs, err := m.ConversationLocalCache.GetConversationIDs(ctx, req.UserID) if err != nil { return nil, err } - log.ZDebug(ctx, "GetMaxSeq", "conversationIDs", conversationIDs) if err := m.clearConversation(ctx, conversationIDs, req.UserID, req.DeleteSyncOpt); err != nil { return nil, err } @@ -73,7 +66,7 @@ func (m *msgServer) UserClearAllMsg( } func (m *msgServer) DeleteMsgs(ctx context.Context, req *msg.DeleteMsgsReq) (*msg.DeleteMsgsResp, error) { - if err := authverify.CheckAccessV3(ctx, req.UserID, m.config); err != nil { + if err := authverify.CheckAccessV3(ctx, req.UserID, m.config.Share.IMAdminUserID); err != nil { return nil, err } isSyncSelf, isSyncOther := m.validateDeleteSyncOpt(req.DeleteSyncOpt) @@ -86,7 +79,7 @@ func (m *msgServer) DeleteMsgs(ctx context.Context, req *msg.DeleteMsgsReq) (*ms return nil, err } tips := &sdkws.DeleteMsgsTips{UserID: req.UserID, ConversationID: req.ConversationID, Seqs: req.Seqs} - m.notificationSender.NotificationWithSesstionType( + m.notificationSender.NotificationWithSessionType( ctx, req.UserID, m.conversationAndGetRecvID(conversations[0], req.UserID), @@ -100,16 +93,13 @@ func (m *msgServer) DeleteMsgs(ctx context.Context, req *msg.DeleteMsgsReq) (*ms } if isSyncSelf { tips := &sdkws.DeleteMsgsTips{UserID: req.UserID, ConversationID: req.ConversationID, Seqs: req.Seqs} - m.notificationSender.NotificationWithSesstionType(ctx, req.UserID, req.UserID, constant.DeleteMsgsNotification, constant.SingleChatType, tips) + m.notificationSender.NotificationWithSessionType(ctx, req.UserID, req.UserID, constant.DeleteMsgsNotification, constant.SingleChatType, tips) } } return &msg.DeleteMsgsResp{}, nil } -func (m *msgServer) DeleteMsgPhysicalBySeq( - ctx context.Context, - req *msg.DeleteMsgPhysicalBySeqReq, -) (*msg.DeleteMsgPhysicalBySeqResp, error) { +func (m *msgServer) DeleteMsgPhysicalBySeq(ctx context.Context, req *msg.DeleteMsgPhysicalBySeqReq) (*msg.DeleteMsgPhysicalBySeqResp, error) { err := m.MsgDatabase.DeleteMsgsPhysicalBySeqs(ctx, req.ConversationID, req.Seqs) if err != nil { return nil, err @@ -117,37 +107,20 @@ func (m *msgServer) DeleteMsgPhysicalBySeq( return &msg.DeleteMsgPhysicalBySeqResp{}, nil } -func (m *msgServer) DeleteMsgPhysical( - ctx context.Context, - req *msg.DeleteMsgPhysicalReq, -) (*msg.DeleteMsgPhysicalResp, error) { - if err := authverify.CheckAdmin(ctx, m.config); err != nil { +func (m *msgServer) DeleteMsgPhysical(ctx context.Context, req *msg.DeleteMsgPhysicalReq) (*msg.DeleteMsgPhysicalResp, error) { + if err := authverify.CheckAdmin(ctx, m.config.Share.IMAdminUserID); err != nil { return nil, err } - remainTime := utils.GetCurrentTimestampBySecond() - req.Timestamp + remainTime := timeutil.GetCurrentTimestampBySecond() - req.Timestamp for _, conversationID := range req.ConversationIDs { if err := m.MsgDatabase.DeleteConversationMsgsAndSetMinSeq(ctx, conversationID, remainTime); err != nil { - log.ZWarn( - ctx, - "DeleteConversationMsgsAndSetMinSeq error", - err, - "conversationID", - conversationID, - "err", - err, - ) + log.ZWarn(ctx, "DeleteConversationMsgsAndSetMinSeq error", err, "conversationID", conversationID, "err", err) } } return &msg.DeleteMsgPhysicalResp{}, nil } -func (m *msgServer) clearConversation( - ctx context.Context, - conversationIDs []string, - userID string, - deleteSyncOpt *msg.DeleteSyncOpt, -) error { - defer log.ZDebug(ctx, "clearConversation return line") +func (m *msgServer) clearConversation(ctx context.Context, conversationIDs []string, userID string, deleteSyncOpt *msg.DeleteSyncOpt) error { conversations, err := m.Conversation.GetConversationsByConversationID(ctx, conversationIDs) if err != nil { return err @@ -171,14 +144,7 @@ func (m *msgServer) clearConversation( // notification 2 self if isSyncSelf { tips := &sdkws.ClearConversationTips{UserID: userID, ConversationIDs: existConversationIDs} - m.notificationSender.NotificationWithSesstionType( - ctx, - userID, - userID, - constant.ClearConversationNotification, - constant.SingleChatType, - tips, - ) + m.notificationSender.NotificationWithSessionType(ctx, userID, userID, constant.ClearConversationNotification, constant.SingleChatType, tips) } } else { if err := m.MsgDatabase.SetMinSeqs(ctx, m.getMinSeqs(maxSeqs)); err != nil { @@ -186,7 +152,7 @@ func (m *msgServer) clearConversation( } for _, conversation := range existConversations { tips := &sdkws.ClearConversationTips{UserID: userID, ConversationIDs: []string{conversation.ConversationID}} - m.notificationSender.NotificationWithSesstionType(ctx, userID, m.conversationAndGetRecvID(conversation, userID), constant.ClearConversationNotification, conversation.ConversationType, tips) + m.notificationSender.NotificationWithSessionType(ctx, userID, m.conversationAndGetRecvID(conversation, userID), constant.ClearConversationNotification, conversation.ConversationType, tips) } } if err := m.MsgDatabase.UserSetHasReadSeqs(ctx, userID, maxSeqs); err != nil { diff --git a/internal/rpc/msg/message_interceptor.go b/internal/rpc/msg/message_interceptor.go deleted file mode 100644 index 97eac613d9..0000000000 --- a/internal/rpc/msg/message_interceptor.go +++ /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. - -package msg - -import ( - "context" - - "github.com/OpenIMSDK/protocol/constant" - "github.com/OpenIMSDK/protocol/msg" - "github.com/OpenIMSDK/protocol/sdkws" - "github.com/OpenIMSDK/tools/errs" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" -) - -type MessageInterceptorFunc func(ctx context.Context, globalConfig *config.GlobalConfig, req *msg.SendMsgReq) (*sdkws.MsgData, error) - -func MessageHasReadEnabled(_ context.Context, globalConfig *config.GlobalConfig, req *msg.SendMsgReq) (*sdkws.MsgData, error) { - switch { - case req.MsgData.ContentType == constant.HasReadReceipt && req.MsgData.SessionType == constant.SingleChatType: - if !globalConfig.SingleMessageHasReadReceiptEnable { - return nil, errs.ErrMessageHasReadDisable.Wrap() - } - return req.MsgData, nil - case req.MsgData.ContentType == constant.HasReadReceipt && req.MsgData.SessionType == constant.SuperGroupChatType: - if !globalConfig.GroupMessageHasReadReceiptEnable { - return nil, errs.ErrMessageHasReadDisable.Wrap() - } - return req.MsgData, nil - } - return req.MsgData, nil -} diff --git a/internal/rpc/msg/msg_status.go b/internal/rpc/msg/msg_status.go index 80c5833a50..b524d6236a 100644 --- a/internal/rpc/msg/msg_status.go +++ b/internal/rpc/msg/msg_status.go @@ -17,15 +17,12 @@ package msg import ( "context" - "github.com/OpenIMSDK/protocol/constant" - pbmsg "github.com/OpenIMSDK/protocol/msg" - "github.com/OpenIMSDK/tools/mcontext" + "github.com/openimsdk/protocol/constant" + pbmsg "github.com/openimsdk/protocol/msg" + "github.com/openimsdk/tools/mcontext" ) -func (m *msgServer) SetSendMsgStatus( - ctx context.Context, - req *pbmsg.SetSendMsgStatusReq, -) (*pbmsg.SetSendMsgStatusResp, error) { +func (m *msgServer) SetSendMsgStatus(ctx context.Context, req *pbmsg.SetSendMsgStatusReq) (*pbmsg.SetSendMsgStatusResp, error) { resp := &pbmsg.SetSendMsgStatusResp{} if err := m.MsgDatabase.SetSendMsgStatus(ctx, mcontext.GetOperationID(ctx), req.Status); err != nil { return nil, err @@ -33,10 +30,7 @@ func (m *msgServer) SetSendMsgStatus( return resp, nil } -func (m *msgServer) GetSendMsgStatus( - ctx context.Context, - req *pbmsg.GetSendMsgStatusReq, -) (*pbmsg.GetSendMsgStatusResp, error) { +func (m *msgServer) GetSendMsgStatus(ctx context.Context, req *pbmsg.GetSendMsgStatusReq) (*pbmsg.GetSendMsgStatusResp, error) { resp := &pbmsg.GetSendMsgStatusResp{} status, err := m.MsgDatabase.GetSendMsgStatus(ctx, mcontext.GetOperationID(ctx)) if IsNotFound(err) { diff --git a/pkg/rpcclient/notification/msg.go b/internal/rpc/msg/notification.go similarity index 61% rename from pkg/rpcclient/notification/msg.go rename to internal/rpc/msg/notification.go index beaef1d969..3b13676bf6 100644 --- a/pkg/rpcclient/notification/msg.go +++ b/internal/rpc/msg/notification.go @@ -12,40 +12,39 @@ // See the License for the specific language governing permissions and // limitations under the License. -package notification +package msg import ( "context" - "github.com/OpenIMSDK/protocol/constant" - "github.com/OpenIMSDK/protocol/sdkws" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" + "github.com/openimsdk/protocol/constant" + "github.com/openimsdk/protocol/sdkws" ) type MsgNotificationSender struct { *rpcclient.NotificationSender } -func NewMsgNotificationSender(config *config.GlobalConfig, opts ...rpcclient.NotificationSenderOptions) *MsgNotificationSender { - return &MsgNotificationSender{rpcclient.NewNotificationSender(config, opts...)} +func NewMsgNotificationSender(config *Config, opts ...rpcclient.NotificationSenderOptions) *MsgNotificationSender { + return &MsgNotificationSender{rpcclient.NewNotificationSender(&config.NotificationConfig, opts...)} } -func (m *MsgNotificationSender) UserDeleteMsgsNotification(ctx context.Context, userID, conversationID string, seqs []int64) error { +func (m *MsgNotificationSender) UserDeleteMsgsNotification(ctx context.Context, userID, conversationID string, seqs []int64) { tips := sdkws.DeleteMsgsTips{ UserID: userID, ConversationID: conversationID, Seqs: seqs, } - return m.Notification(ctx, userID, userID, constant.DeleteMsgsNotification, &tips) + m.Notification(ctx, userID, userID, constant.DeleteMsgsNotification, &tips) } -func (m *MsgNotificationSender) MarkAsReadNotification(ctx context.Context, conversationID string, sesstionType int32, sendID, recvID string, seqs []int64, hasReadSeq int64) error { +func (m *MsgNotificationSender) MarkAsReadNotification(ctx context.Context, conversationID string, sessionType int32, sendID, recvID string, seqs []int64, hasReadSeq int64) { tips := &sdkws.MarkAsReadTips{ MarkAsReadUserID: sendID, ConversationID: conversationID, Seqs: seqs, HasReadSeq: hasReadSeq, } - return m.NotificationWithSesstionType(ctx, sendID, recvID, constant.HasReadReceipt, sesstionType, tips) + m.NotificationWithSessionType(ctx, sendID, recvID, constant.HasReadReceipt, sessionType, tips) } diff --git a/internal/rpc/msg/revoke.go b/internal/rpc/msg/revoke.go index 99690b0cc7..7dbc307a19 100644 --- a/internal/rpc/msg/revoke.go +++ b/internal/rpc/msg/revoke.go @@ -19,29 +19,29 @@ import ( "encoding/json" "time" - "github.com/OpenIMSDK/protocol/constant" - "github.com/OpenIMSDK/protocol/msg" - "github.com/OpenIMSDK/protocol/sdkws" - "github.com/OpenIMSDK/tools/errs" - "github.com/OpenIMSDK/tools/log" - "github.com/OpenIMSDK/tools/mcontext" - "github.com/OpenIMSDK/tools/utils" "github.com/openimsdk/open-im-server/v3/pkg/authverify" - unrelationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/unrelation" + "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" + "github.com/openimsdk/open-im-server/v3/pkg/common/servererrs" + "github.com/openimsdk/protocol/constant" + "github.com/openimsdk/protocol/msg" + "github.com/openimsdk/protocol/sdkws" + "github.com/openimsdk/tools/errs" + "github.com/openimsdk/tools/log" + "github.com/openimsdk/tools/mcontext" + "github.com/openimsdk/tools/utils/datautil" ) func (m *msgServer) RevokeMsg(ctx context.Context, req *msg.RevokeMsgReq) (*msg.RevokeMsgResp, error) { - defer log.ZDebug(ctx, "RevokeMsg return line") if req.UserID == "" { - return nil, errs.ErrArgs.Wrap("user_id is empty") + return nil, errs.ErrArgs.WrapMsg("user_id is empty") } if req.ConversationID == "" { - return nil, errs.ErrArgs.Wrap("conversation_id is empty") + return nil, errs.ErrArgs.WrapMsg("conversation_id is empty") } if req.Seq < 0 { - return nil, errs.ErrArgs.Wrap("seq is invalid") + return nil, errs.ErrArgs.WrapMsg("seq is invalid") } - if err := authverify.CheckAccessV3(ctx, req.UserID, m.config); err != nil { + if err := authverify.CheckAccessV3(ctx, req.UserID, m.config.Share.IMAdminUserID); err != nil { return nil, err } user, err := m.UserLocalCache.GetUserInfo(ctx, req.UserID) @@ -53,24 +53,24 @@ func (m *msgServer) RevokeMsg(ctx context.Context, req *msg.RevokeMsgReq) (*msg. return nil, err } if len(msgs) == 0 || msgs[0] == nil { - return nil, errs.ErrRecordNotFound.Wrap("msg not found") + return nil, errs.ErrRecordNotFound.WrapMsg("msg not found") } if msgs[0].ContentType == constant.MsgRevokeNotification { - return nil, errs.ErrMsgAlreadyRevoke.Wrap("msg already revoke") + return nil, servererrs.ErrMsgAlreadyRevoke.WrapMsg("msg already revoke") } data, _ := json.Marshal(msgs[0]) - log.ZInfo(ctx, "GetMsgBySeqs", "conversationID", req.ConversationID, "seq", req.Seq, "msg", string(data)) + log.ZDebug(ctx, "GetMsgBySeqs", "conversationID", req.ConversationID, "seq", req.Seq, "msg", string(data)) var role int32 - if !authverify.IsAppManagerUid(ctx, m.config) { + if !authverify.IsAppManagerUid(ctx, m.config.Share.IMAdminUserID) { switch msgs[0].SessionType { case constant.SingleChatType: - if err := authverify.CheckAccessV3(ctx, msgs[0].SendID, m.config); err != nil { + if err := authverify.CheckAccessV3(ctx, msgs[0].SendID, m.config.Share.IMAdminUserID); err != nil { return nil, err } role = user.AppMangerLevel - case constant.SuperGroupChatType: - members, err := m.GroupLocalCache.GetGroupMemberInfoMap(ctx, msgs[0].GroupID, utils.Distinct([]string{req.UserID, msgs[0].SendID})) + case constant.ReadGroupChatType: + members, err := m.GroupLocalCache.GetGroupMemberInfoMap(ctx, msgs[0].GroupID, datautil.Distinct([]string{req.UserID, msgs[0].SendID})) if err != nil { return nil, err } @@ -79,21 +79,21 @@ func (m *msgServer) RevokeMsg(ctx context.Context, req *msg.RevokeMsgReq) (*msg. case constant.GroupOwner: case constant.GroupAdmin: if members[msgs[0].SendID].RoleLevel != constant.GroupOrdinaryUsers { - return nil, errs.ErrNoPermission.Wrap("no permission") + return nil, errs.ErrNoPermission.WrapMsg("no permission") } default: - return nil, errs.ErrNoPermission.Wrap("no permission") + return nil, errs.ErrNoPermission.WrapMsg("no permission") } } if member := members[req.UserID]; member != nil { role = member.RoleLevel } default: - return nil, errs.ErrInternalServer.Wrap("msg sessionType not supported") + return nil, errs.ErrInternalServer.WrapMsg("msg sessionType not supported") } } now := time.Now().UnixMilli() - err = m.MsgDatabase.RevokeMsg(ctx, req.ConversationID, req.Seq, &unrelationtb.RevokeModel{ + err = m.MsgDatabase.RevokeMsg(ctx, req.ConversationID, req.Seq, &relation.RevokeModel{ Role: role, UserID: req.UserID, Nickname: user.Nickname, @@ -104,11 +104,9 @@ func (m *msgServer) RevokeMsg(ctx context.Context, req *msg.RevokeMsgReq) (*msg. } revokerUserID := mcontext.GetOpUserID(ctx) var flag bool - if len(m.config.Manager.UserID) > 0 { - flag = utils.Contain(revokerUserID, m.config.Manager.UserID...) - } - if len(m.config.Manager.UserID) == 0 && len(m.config.IMAdmin.UserID) > 0 { - flag = utils.Contain(revokerUserID, m.config.IMAdmin.UserID...) + + if len(m.config.Share.IMAdminUserID) > 0 { + flag = datautil.Contain(revokerUserID, m.config.Share.IMAdminUserID...) } tips := sdkws.RevokeMsgTips{ RevokerUserID: revokerUserID, @@ -120,16 +118,12 @@ func (m *msgServer) RevokeMsg(ctx context.Context, req *msg.RevokeMsgReq) (*msg. IsAdminRevoke: flag, } var recvID string - if msgs[0].SessionType == constant.SuperGroupChatType { + if msgs[0].SessionType == constant.ReadGroupChatType { recvID = msgs[0].GroupID } else { recvID = msgs[0].RecvID } - if err := m.notificationSender.NotificationWithSesstionType(ctx, req.UserID, recvID, constant.MsgRevokeNotification, msgs[0].SessionType, &tips); err != nil { - return nil, err - } - if err = CallbackAfterRevokeMsg(ctx, m.config, req); err != nil { - return nil, err - } + m.notificationSender.NotificationWithSessionType(ctx, req.UserID, recvID, constant.MsgRevokeNotification, msgs[0].SessionType, &tips) + m.webhookAfterRevokeMsg(ctx, &m.config.WebhooksConfig.AfterRevokeMsg, req) return &msg.RevokeMsgResp{}, nil } diff --git a/internal/rpc/msg/send.go b/internal/rpc/msg/send.go index ea59c40cff..4a2d21019b 100644 --- a/internal/rpc/msg/send.go +++ b/internal/rpc/msg/send.go @@ -17,67 +17,59 @@ package msg import ( "context" - "github.com/OpenIMSDK/protocol/constant" - pbconversation "github.com/OpenIMSDK/protocol/conversation" - pbmsg "github.com/OpenIMSDK/protocol/msg" - "github.com/OpenIMSDK/protocol/sdkws" - "github.com/OpenIMSDK/protocol/wrapperspb" - "github.com/OpenIMSDK/tools/errs" - "github.com/OpenIMSDK/tools/log" - "github.com/OpenIMSDK/tools/mcontext" - "github.com/OpenIMSDK/tools/utils" "github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics" "github.com/openimsdk/open-im-server/v3/pkg/msgprocessor" + "github.com/openimsdk/open-im-server/v3/pkg/util/conversationutil" + "github.com/openimsdk/protocol/constant" + pbconversation "github.com/openimsdk/protocol/conversation" + pbmsg "github.com/openimsdk/protocol/msg" + "github.com/openimsdk/protocol/sdkws" + "github.com/openimsdk/protocol/wrapperspb" + "github.com/openimsdk/tools/errs" + "github.com/openimsdk/tools/log" + "github.com/openimsdk/tools/mcontext" + "github.com/openimsdk/tools/utils/datautil" + "github.com/openimsdk/tools/utils/stringutil" ) -func (m *msgServer) SendMsg(ctx context.Context, req *pbmsg.SendMsgReq) (resp *pbmsg.SendMsgResp, error error) { - resp = &pbmsg.SendMsgResp{} +func (m *msgServer) SendMsg(ctx context.Context, req *pbmsg.SendMsgReq) (*pbmsg.SendMsgResp, error) { if req.MsgData != nil { - flag := isMessageHasReadEnabled(req.MsgData, m.config) - if !flag { - return nil, errs.ErrMessageHasReadDisable.Wrap() - } m.encapsulateMsgData(req.MsgData) switch req.MsgData.SessionType { case constant.SingleChatType: return m.sendMsgSingleChat(ctx, req) case constant.NotificationChatType: return m.sendMsgNotification(ctx, req) - case constant.SuperGroupChatType: + case constant.ReadGroupChatType: return m.sendMsgSuperGroupChat(ctx, req) default: - return nil, errs.ErrArgs.Wrap("unknown sessionType") + return nil, errs.ErrArgs.WrapMsg("unknown sessionType") } - } else { - return nil, errs.ErrArgs.Wrap("msgData is nil") } + return nil, errs.ErrArgs.WrapMsg("msgData is nil") } -func (m *msgServer) sendMsgSuperGroupChat( - ctx context.Context, - req *pbmsg.SendMsgReq, -) (resp *pbmsg.SendMsgResp, err error) { +func (m *msgServer) sendMsgSuperGroupChat(ctx context.Context, req *pbmsg.SendMsgReq) (resp *pbmsg.SendMsgResp, err error) { if err = m.messageVerification(ctx, req); err != nil { prommetrics.GroupChatMsgProcessFailedCounter.Inc() return nil, err } - if err = callbackBeforeSendGroupMsg(ctx, m.config, req); err != nil { + + if err = m.webhookBeforeSendGroupMsg(ctx, &m.config.WebhooksConfig.BeforeSendGroupMsg, req); err != nil { return nil, err } - - if err := callbackMsgModify(ctx, m.config, req); err != nil { + if err := m.webhookBeforeMsgModify(ctx, &m.config.WebhooksConfig.BeforeMsgModify, req); err != nil { return nil, err } - err = m.MsgDatabase.MsgToMQ(ctx, utils.GenConversationUniqueKeyForGroup(req.MsgData.GroupID), req.MsgData) + err = m.MsgDatabase.MsgToMQ(ctx, conversationutil.GenConversationUniqueKeyForGroup(req.MsgData.GroupID), req.MsgData) if err != nil { return nil, err } if req.MsgData.ContentType == constant.AtText { go m.setConversationAtInfo(ctx, req.MsgData) } - if err = callbackAfterSendGroupMsg(ctx, m.config, req); err != nil { - log.ZWarn(ctx, "CallbackAfterSendGroupMsg", err) - } + + m.webhookAfterSendGroupMsg(ctx, &m.config.WebhooksConfig.AfterSendGroupMsg, req) prommetrics.GroupChatMsgProcessSuccessCounter.Inc() resp = &pbmsg.SendMsgResp{} resp.SendTime = req.MsgData.SendTime @@ -95,43 +87,39 @@ func (m *msgServer) setConversationAtInfo(nctx context.Context, msg *sdkws.MsgDa ConversationType: msg.SessionType, GroupID: msg.GroupID, } - tagAll := utils.IsContain(constant.AtAllString, msg.AtUserIDList) + tagAll := datautil.Contain(constant.AtAllString, msg.AtUserIDList...) if tagAll { memberUserIDList, err := m.GroupLocalCache.GetGroupMemberIDs(ctx, msg.GroupID) if err != nil { log.ZWarn(ctx, "GetGroupMemberIDs", err) return } - atUserID = utils.DifferenceString([]string{constant.AtAllString}, msg.AtUserIDList) + atUserID = stringutil.DifferenceString([]string{constant.AtAllString}, msg.AtUserIDList) if len(atUserID) == 0 { // just @everyone conversation.GroupAtType = &wrapperspb.Int32Value{Value: constant.AtAll} - } else { //@Everyone and @other people + } else { // @Everyone and @other people conversation.GroupAtType = &wrapperspb.Int32Value{Value: constant.AtAllAtMe} err = m.Conversation.SetConversations(ctx, atUserID, conversation) if err != nil { log.ZWarn(ctx, "SetConversations", err, "userID", atUserID, "conversation", conversation) } - memberUserIDList = utils.DifferenceString(atUserID, memberUserIDList) + memberUserIDList = stringutil.DifferenceString(atUserID, memberUserIDList) } conversation.GroupAtType = &wrapperspb.Int32Value{Value: constant.AtAll} err = m.Conversation.SetConversations(ctx, memberUserIDList, conversation) if err != nil { log.ZWarn(ctx, "SetConversations", err, "userID", memberUserIDList, "conversation", conversation) } - } else { - conversation.GroupAtType = &wrapperspb.Int32Value{Value: constant.AtMe} - err := m.Conversation.SetConversations(ctx, msg.AtUserIDList, conversation) - if err != nil { - log.ZWarn(ctx, "SetConversations", err, msg.AtUserIDList, conversation) - } + } + conversation.GroupAtType = &wrapperspb.Int32Value{Value: constant.AtMe} + err := m.Conversation.SetConversations(ctx, msg.AtUserIDList, conversation) + if err != nil { + log.ZWarn(ctx, "SetConversations", err, msg.AtUserIDList, conversation) } } -func (m *msgServer) sendMsgNotification( - ctx context.Context, - req *pbmsg.SendMsgReq, -) (resp *pbmsg.SendMsgResp, err error) { - if err := m.MsgDatabase.MsgToMQ(ctx, utils.GenConversationUniqueKeyForSingle(req.MsgData.SendID, req.MsgData.RecvID), req.MsgData); err != nil { +func (m *msgServer) sendMsgNotification(ctx context.Context, req *pbmsg.SendMsgReq) (resp *pbmsg.SendMsgResp, err error) { + if err := m.MsgDatabase.MsgToMQ(ctx, conversationutil.GenConversationUniqueKeyForSingle(req.MsgData.SendID, req.MsgData.RecvID), req.MsgData); err != nil { return nil, err } resp = &pbmsg.SendMsgResp{ @@ -143,7 +131,6 @@ func (m *msgServer) sendMsgNotification( } func (m *msgServer) sendMsgSingleChat(ctx context.Context, req *pbmsg.SendMsgReq) (resp *pbmsg.SendMsgResp, err error) { - log.ZDebug(ctx, "sendMsgSingleChat return") if err := m.messageVerification(ctx, req); err != nil { return nil, err } @@ -153,7 +140,7 @@ func (m *msgServer) sendMsgSingleChat(ctx context.Context, req *pbmsg.SendMsgReq isSend, err = m.modifyMessageByUserMessageReceiveOpt( ctx, req.MsgData.RecvID, - utils.GenConversationIDForSingle(req.MsgData.SendID, req.MsgData.RecvID), + conversationutil.GenConversationIDForSingle(req.MsgData.SendID, req.MsgData.RecvID), constant.SingleChatType, req, ) @@ -165,31 +152,23 @@ func (m *msgServer) sendMsgSingleChat(ctx context.Context, req *pbmsg.SendMsgReq prommetrics.SingleChatMsgProcessFailedCounter.Inc() return nil, nil } else { - if err = callbackBeforeSendSingleMsg(ctx, m.config, req); err != nil { + if err = m.webhookBeforeSendSingleMsg(ctx, &m.config.WebhooksConfig.BeforeSendSingleMsg, req); err != nil { return nil, err } - - if err := callbackMsgModify(ctx, m.config, req); err != nil { + if err := m.webhookBeforeMsgModify(ctx, &m.config.WebhooksConfig.BeforeMsgModify, req); err != nil { return nil, err } - if err := m.MsgDatabase.MsgToMQ(ctx, utils.GenConversationUniqueKeyForSingle(req.MsgData.SendID, req.MsgData.RecvID), req.MsgData); err != nil { + + if err := m.MsgDatabase.MsgToMQ(ctx, conversationutil.GenConversationUniqueKeyForSingle(req.MsgData.SendID, req.MsgData.RecvID), req.MsgData); err != nil { prommetrics.SingleChatMsgProcessFailedCounter.Inc() return nil, err } - err = callbackAfterSendSingleMsg(ctx, m.config, req) - if err != nil { - log.ZWarn(ctx, "CallbackAfterSendSingleMsg", err, "req", req) - } - resp = &pbmsg.SendMsgResp{ + m.webhookAfterSendSingleMsg(ctx, &m.config.WebhooksConfig.AfterSendSingleMsg, req) + prommetrics.SingleChatMsgProcessSuccessCounter.Inc() + return &pbmsg.SendMsgResp{ ServerMsgID: req.MsgData.ServerMsgID, ClientMsgID: req.MsgData.ClientMsgID, SendTime: req.MsgData.SendTime, - } - prommetrics.SingleChatMsgProcessSuccessCounter.Inc() - return resp, nil + }, nil } } - -func (m *msgServer) BatchSendMsg(ctx context.Context, in *pbmsg.BatchSendMessageReq) (*pbmsg.BatchSendMessageResp, error) { - return nil, nil -} diff --git a/internal/rpc/msg/seq.go b/internal/rpc/msg/seq.go index dfc2ad0b1b..27465c2105 100644 --- a/internal/rpc/msg/seq.go +++ b/internal/rpc/msg/seq.go @@ -17,13 +17,10 @@ package msg import ( "context" - pbmsg "github.com/OpenIMSDK/protocol/msg" + pbmsg "github.com/openimsdk/protocol/msg" ) -func (m *msgServer) GetConversationMaxSeq( - ctx context.Context, - req *pbmsg.GetConversationMaxSeqReq, -) (resp *pbmsg.GetConversationMaxSeqResp, err error) { +func (m *msgServer) GetConversationMaxSeq(ctx context.Context, req *pbmsg.GetConversationMaxSeqReq) (*pbmsg.GetConversationMaxSeqResp, error) { maxSeq, err := m.MsgDatabase.GetMaxSeq(ctx, req.ConversationID) if err != nil { return nil, err diff --git a/internal/rpc/msg/server.go b/internal/rpc/msg/server.go index f2d735a70c..3f4df8d4b7 100644 --- a/internal/rpc/msg/server.go +++ b/internal/rpc/msg/server.go @@ -15,69 +15,84 @@ package msg import ( - "github.com/OpenIMSDK/protocol/constant" - "github.com/OpenIMSDK/protocol/conversation" - "github.com/OpenIMSDK/protocol/msg" - "github.com/OpenIMSDK/tools/discoveryregistry" + "context" "github.com/openimsdk/open-im-server/v3/pkg/common/config" + "github.com/openimsdk/open-im-server/v3/pkg/common/webhook" + "github.com/openimsdk/protocol/sdkws" + "github.com/openimsdk/tools/db/mongoutil" + "github.com/openimsdk/tools/db/redisutil" + "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/unrelation" + "github.com/openimsdk/open-im-server/v3/pkg/common/db/mgo" "github.com/openimsdk/open-im-server/v3/pkg/rpccache" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" + "github.com/openimsdk/protocol/constant" + "github.com/openimsdk/protocol/conversation" + "github.com/openimsdk/protocol/msg" + "github.com/openimsdk/tools/discovery" "google.golang.org/grpc" ) +type MessageInterceptorFunc func(ctx context.Context, globalConfig *Config, req *msg.SendMsgReq) (*sdkws.MsgData, error) type ( + // MessageInterceptorChain defines a chain of message interceptor functions. MessageInterceptorChain []MessageInterceptorFunc - msgServer struct { - RegisterCenter discoveryregistry.SvcDiscoveryRegistry - MsgDatabase controller.CommonMsgDatabase - Conversation *rpcclient.ConversationRpcClient - UserLocalCache *rpccache.UserLocalCache - FriendLocalCache *rpccache.FriendLocalCache - GroupLocalCache *rpccache.GroupLocalCache - ConversationLocalCache *rpccache.ConversationLocalCache - Handlers MessageInterceptorChain - notificationSender *rpcclient.NotificationSender - config *config.GlobalConfig + + // MsgServer encapsulates dependencies required for message handling. + msgServer struct { + RegisterCenter discovery.SvcDiscoveryRegistry // Service discovery registry for service registration. + MsgDatabase controller.CommonMsgDatabase // Interface for message database operations. + Conversation *rpcclient.ConversationRpcClient // RPC client for conversation service. + UserLocalCache *rpccache.UserLocalCache // Local cache for user data. + FriendLocalCache *rpccache.FriendLocalCache // Local cache for friend data. + GroupLocalCache *rpccache.GroupLocalCache // Local cache for group data. + ConversationLocalCache *rpccache.ConversationLocalCache // Local cache for conversation data. + Handlers MessageInterceptorChain // Chain of handlers for processing messages. + notificationSender *rpcclient.NotificationSender // RPC client for sending notifications. + config *Config // Global configuration settings. + webhookClient *webhook.Client + } + + Config struct { + RpcConfig config.Msg + RedisConfig config.Redis + MongodbConfig config.Mongo + KafkaConfig config.Kafka + ZookeeperConfig config.ZooKeeper + NotificationConfig config.Notification + Share config.Share + WebhooksConfig config.Webhooks + LocalCacheConfig config.LocalCache } ) func (m *msgServer) addInterceptorHandler(interceptorFunc ...MessageInterceptorFunc) { m.Handlers = append(m.Handlers, interceptorFunc...) -} -//func (m *msgServer) execInterceptorHandler(ctx context.Context, config *config.GlobalConfig, req *msg.SendMsgReq) error { -// for _, handler := range m.Handlers { -// msgData, err := handler(ctx, config, req) -// if err != nil { -// return err -// } -// req.MsgData = msgData -// } -// return nil -//} +} -func Start(config *config.GlobalConfig, client discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) error { - rdb, err := cache.NewRedis(config) +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 } - mongo, err := unrelation.NewMongo(config) + rdb, err := redisutil.NewRedisClient(ctx, config.RedisConfig.Build()) if err != nil { return err } - if err := mongo.CreateMsgIndex(); err != nil { + msgDocModel, err := mgo.NewMsgMongo(mgocli.GetDB()) + if err != nil { return err } - cacheModel := cache.NewMsgCacheModel(rdb, config) - msgDocModel := unrelation.NewMsgMongoDriver(mongo.GetDatabase(config.Mongo.Database)) - conversationClient := rpcclient.NewConversationRpcClient(client, config) - userRpcClient := rpcclient.NewUserRpcClient(client, config) - groupRpcClient := rpcclient.NewGroupRpcClient(client, config) - friendRpcClient := rpcclient.NewFriendRpcClient(client, config) - msgDatabase, err := controller.NewCommonMsgDatabase(msgDocModel, cacheModel, config) + //todo MsgCacheTimeout + msgModel := cache.NewMsgCache(rdb, config.RedisConfig.EnablePipeline) + seqModel := cache.NewSeqCache(rdb) + conversationClient := rpcclient.NewConversationRpcClient(client, config.Share.RpcRegisterName.Conversation) + userRpcClient := rpcclient.NewUserRpcClient(client, config.Share.RpcRegisterName.User, config.Share.IMAdminUserID) + groupRpcClient := rpcclient.NewGroupRpcClient(client, config.Share.RpcRegisterName.Group) + friendRpcClient := rpcclient.NewFriendRpcClient(client, config.Share.RpcRegisterName.Friend) + msgDatabase, err := controller.NewCommonMsgDatabase(msgDocModel, msgModel, seqModel, &config.KafkaConfig) if err != nil { return err } @@ -85,28 +100,29 @@ func Start(config *config.GlobalConfig, client discoveryregistry.SvcDiscoveryReg Conversation: &conversationClient, MsgDatabase: msgDatabase, RegisterCenter: client, - UserLocalCache: rpccache.NewUserLocalCache(userRpcClient, rdb), - GroupLocalCache: rpccache.NewGroupLocalCache(groupRpcClient, rdb), - ConversationLocalCache: rpccache.NewConversationLocalCache(conversationClient, rdb), - FriendLocalCache: rpccache.NewFriendLocalCache(friendRpcClient, rdb), + UserLocalCache: rpccache.NewUserLocalCache(userRpcClient, &config.LocalCacheConfig, rdb), + GroupLocalCache: rpccache.NewGroupLocalCache(groupRpcClient, &config.LocalCacheConfig, rdb), + ConversationLocalCache: rpccache.NewConversationLocalCache(conversationClient, &config.LocalCacheConfig, rdb), + FriendLocalCache: rpccache.NewFriendLocalCache(friendRpcClient, &config.LocalCacheConfig, rdb), config: config, + webhookClient: webhook.NewWebhookClient(config.WebhooksConfig.URL), } - s.notificationSender = rpcclient.NewNotificationSender(config, rpcclient.WithLocalSendMsg(s.SendMsg)) - s.addInterceptorHandler(MessageHasReadEnabled) + + s.notificationSender = rpcclient.NewNotificationSender(&config.NotificationConfig, rpcclient.WithLocalSendMsg(s.SendMsg)) msg.RegisterMsgServer(server, s) return nil } -func (m *msgServer) conversationAndGetRecvID(conversation *conversation.Conversation, userID string) (recvID string) { +func (m *msgServer) conversationAndGetRecvID(conversation *conversation.Conversation, userID string) string { if conversation.ConversationType == constant.SingleChatType || conversation.ConversationType == constant.NotificationChatType { if userID == conversation.OwnerUserID { - recvID = conversation.UserID + return conversation.UserID } else { - recvID = conversation.OwnerUserID + return conversation.OwnerUserID } - } else if conversation.ConversationType == constant.SuperGroupChatType { - recvID = conversation.GroupID + } else if conversation.ConversationType == constant.ReadGroupChatType { + return conversation.GroupID } - return + return "" } diff --git a/internal/rpc/msg/statistics.go b/internal/rpc/msg/statistics.go index e62954dea4..15a0aaa577 100644 --- a/internal/rpc/msg/statistics.go +++ b/internal/rpc/msg/statistics.go @@ -18,28 +18,20 @@ import ( "context" "time" - "github.com/OpenIMSDK/protocol/msg" - "github.com/OpenIMSDK/protocol/sdkws" - "github.com/OpenIMSDK/tools/utils" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/unrelation" + "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" + "github.com/openimsdk/protocol/msg" + "github.com/openimsdk/protocol/sdkws" + "github.com/openimsdk/tools/utils/datautil" ) func (m *msgServer) GetActiveUser(ctx context.Context, req *msg.GetActiveUserReq) (*msg.GetActiveUserResp, error) { - msgCount, userCount, users, dateCount, err := m.MsgDatabase.RangeUserSendCount( - ctx, - time.UnixMilli(req.Start), - time.UnixMilli(req.End), - req.Group, - req.Ase, - req.Pagination.PageNumber, - req.Pagination.ShowNumber, - ) + msgCount, userCount, users, dateCount, err := m.MsgDatabase.RangeUserSendCount(ctx, time.UnixMilli(req.Start), time.UnixMilli(req.End), req.Group, req.Ase, req.Pagination.PageNumber, req.Pagination.ShowNumber) if err != nil { return nil, err } var pbUsers []*msg.ActiveUser if len(users) > 0 { - userIDs := utils.Slice(users, func(e *unrelation.UserCount) string { return e.UserID }) + userIDs := datautil.Slice(users, func(e *relation.UserCount) string { return e.UserID }) userMap, err := m.UserLocalCache.GetUsersInfoMap(ctx, userIDs) if err != nil { return nil, err @@ -68,20 +60,13 @@ func (m *msgServer) GetActiveUser(ctx context.Context, req *msg.GetActiveUserReq } func (m *msgServer) GetActiveGroup(ctx context.Context, req *msg.GetActiveGroupReq) (*msg.GetActiveGroupResp, error) { - msgCount, groupCount, groups, dateCount, err := m.MsgDatabase.RangeGroupSendCount( - ctx, - time.UnixMilli(req.Start), - time.UnixMilli(req.End), - req.Ase, - req.Pagination.PageNumber, - req.Pagination.ShowNumber, - ) + msgCount, groupCount, groups, dateCount, err := m.MsgDatabase.RangeGroupSendCount(ctx, time.UnixMilli(req.Start), time.UnixMilli(req.End), req.Ase, req.Pagination.PageNumber, req.Pagination.ShowNumber) if err != nil { return nil, err } var pbgroups []*msg.ActiveGroup if len(groups) > 0 { - groupIDs := utils.Slice(groups, func(e *unrelation.GroupCount) string { return e.GroupID }) + groupIDs := datautil.Slice(groups, func(e *relation.GroupCount) string { return e.GroupID }) resp, err := m.GroupLocalCache.GetGroupInfos(ctx, groupIDs) if err != nil { return nil, err diff --git a/internal/rpc/msg/sync_msg.go b/internal/rpc/msg/sync_msg.go index 0a8b3f89e7..afb79506ee 100644 --- a/internal/rpc/msg/sync_msg.go +++ b/internal/rpc/msg/sync_msg.go @@ -16,20 +16,19 @@ package msg import ( "context" + "github.com/openimsdk/open-im-server/v3/pkg/util/conversationutil" + "github.com/openimsdk/tools/utils/datautil" + "github.com/openimsdk/tools/utils/timeutil" - "github.com/OpenIMSDK/protocol/constant" - "github.com/OpenIMSDK/protocol/msg" - "github.com/OpenIMSDK/protocol/sdkws" - "github.com/OpenIMSDK/tools/log" - "github.com/OpenIMSDK/tools/utils" "github.com/openimsdk/open-im-server/v3/pkg/authverify" "github.com/openimsdk/open-im-server/v3/pkg/msgprocessor" + "github.com/openimsdk/protocol/constant" + "github.com/openimsdk/protocol/msg" + "github.com/openimsdk/protocol/sdkws" + "github.com/openimsdk/tools/log" ) -func (m *msgServer) PullMessageBySeqs( - ctx context.Context, - req *sdkws.PullMessageBySeqsReq, -) (*sdkws.PullMessageBySeqsResp, error) { +func (m *msgServer) PullMessageBySeqs(ctx context.Context, req *sdkws.PullMessageBySeqsReq) (*sdkws.PullMessageBySeqsResp, error) { resp := &sdkws.PullMessageBySeqsResp{} resp.Msgs = make(map[string]*sdkws.PullMsgs) resp.NotificationMsgs = make(map[string]*sdkws.PullMsgs) @@ -88,7 +87,7 @@ func (m *msgServer) PullMessageBySeqs( } func (m *msgServer) GetMaxSeq(ctx context.Context, req *sdkws.GetMaxSeqReq) (*sdkws.GetMaxSeqResp, error) { - if err := authverify.CheckAccessV3(ctx, req.UserID, m.config); err != nil { + if err := authverify.CheckAccessV3(ctx, req.UserID, m.config.Share.IMAdminUserID); err != nil { return nil, err } conversationIDs, err := m.ConversationLocalCache.GetConversationIDs(ctx, req.UserID) @@ -96,9 +95,9 @@ func (m *msgServer) GetMaxSeq(ctx context.Context, req *sdkws.GetMaxSeqReq) (*sd return nil, err } for _, conversationID := range conversationIDs { - conversationIDs = append(conversationIDs, utils.GetNotificationConversationIDByConversationID(conversationID)) + conversationIDs = append(conversationIDs, conversationutil.GetNotificationConversationIDByConversationID(conversationID)) } - conversationIDs = append(conversationIDs, utils.GetSelfNotificationConversationID(req.UserID)) + conversationIDs = append(conversationIDs, conversationutil.GetSelfNotificationConversationID(req.UserID)) log.ZDebug(ctx, "GetMaxSeq", "conversationIDs", conversationIDs) maxSeqs, err := m.MsgDatabase.GetMaxSeqs(ctx, conversationIDs) if err != nil { @@ -133,7 +132,7 @@ func (m *msgServer) SearchMessage(ctx context.Context, req *msg.SearchMessageReq switch chatLog.SessionType { case constant.SingleChatType, constant.NotificationChatType: recvIDs = append(recvIDs, chatLog.RecvID) - case constant.GroupChatType, constant.SuperGroupChatType: + case constant.WriteGroupChatType, constant.ReadGroupChatType: groupIDs = append(groupIDs, chatLog.GroupID) } } @@ -175,7 +174,7 @@ func (m *msgServer) SearchMessage(ctx context.Context, req *msg.SearchMessageReq // Construct response with updated information for _, chatLog := range chatLogs { pbchatLog := &msg.ChatLog{} - utils.CopyStructFields(pbchatLog, chatLog) + datautil.CopyStructFields(pbchatLog, chatLog) pbchatLog.SendTime = chatLog.SendTime pbchatLog.CreateTime = chatLog.CreateTime if chatLog.SenderNickname == "" { @@ -184,7 +183,7 @@ func (m *msgServer) SearchMessage(ctx context.Context, req *msg.SearchMessageReq switch chatLog.SessionType { case constant.SingleChatType, constant.NotificationChatType: pbchatLog.RecvNickname = recvMap[chatLog.RecvID] - case constant.GroupChatType, constant.SuperGroupChatType: + case constant.WriteGroupChatType, constant.ReadGroupChatType: groupInfo := groupMap[chatLog.GroupID] pbchatLog.SenderFaceURL = groupInfo.FaceURL pbchatLog.GroupMemberCount = groupInfo.MemberCount // Reflects actual member count @@ -200,5 +199,5 @@ func (m *msgServer) SearchMessage(ctx context.Context, req *msg.SearchMessageReq } func (m *msgServer) GetServerTime(ctx context.Context, _ *msg.GetServerTimeReq) (*msg.GetServerTimeResp, error) { - return &msg.GetServerTimeResp{ServerTime: utils.GetCurrentTimestampByMill()}, nil + return &msg.GetServerTimeResp{ServerTime: timeutil.GetCurrentTimestampByMill()}, nil } diff --git a/internal/rpc/msg/utils.go b/internal/rpc/msg/utils.go index 48665562ad..69b4d0bf6d 100644 --- a/internal/rpc/msg/utils.go +++ b/internal/rpc/msg/utils.go @@ -15,34 +15,13 @@ package msg import ( - "github.com/OpenIMSDK/protocol/constant" - "github.com/OpenIMSDK/protocol/sdkws" - "github.com/OpenIMSDK/tools/utils" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" + "github.com/openimsdk/tools/errs" "github.com/redis/go-redis/v9" "go.mongodb.org/mongo-driver/mongo" ) -func isMessageHasReadEnabled(msgData *sdkws.MsgData, config *config.GlobalConfig) bool { - switch { - case msgData.ContentType == constant.HasReadReceipt && msgData.SessionType == constant.SingleChatType: - if config.SingleMessageHasReadReceiptEnable { - return true - } else { - return false - } - case msgData.ContentType == constant.HasReadReceipt && msgData.SessionType == constant.SuperGroupChatType: - if config.GroupMessageHasReadReceiptEnable { - return true - } else { - return false - } - } - return true -} - func IsNotFound(err error) bool { - switch utils.Unwrap(err) { + switch errs.Unwrap(err) { case redis.Nil, mongo.ErrNoDocuments: return true default: diff --git a/internal/rpc/msg/verify.go b/internal/rpc/msg/verify.go index 5bfd7013ea..33879bfe7b 100644 --- a/internal/rpc/msg/verify.go +++ b/internal/rpc/msg/verify.go @@ -16,16 +16,18 @@ package msg import ( "context" + "github.com/openimsdk/open-im-server/v3/pkg/common/servererrs" + "github.com/openimsdk/tools/utils/datautil" + "github.com/openimsdk/tools/utils/encrypt" + "github.com/openimsdk/tools/utils/timeutil" "math/rand" "strconv" "time" - "github.com/OpenIMSDK/protocol/constant" - "github.com/OpenIMSDK/protocol/msg" - "github.com/OpenIMSDK/protocol/sdkws" - "github.com/OpenIMSDK/tools/errs" - "github.com/OpenIMSDK/tools/log" - "github.com/OpenIMSDK/tools/utils" + "github.com/openimsdk/protocol/constant" + "github.com/openimsdk/protocol/msg" + "github.com/openimsdk/protocol/sdkws" + "github.com/openimsdk/tools/errs" ) var ExcludeContentType = []int{constant.HasReadReceipt} @@ -50,10 +52,7 @@ type MessageRevoked struct { func (m *msgServer) messageVerification(ctx context.Context, data *msg.SendMsgReq) error { switch data.MsgData.SessionType { case constant.SingleChatType: - if len(m.config.Manager.UserID) > 0 && utils.IsContain(data.MsgData.SendID, m.config.Manager.UserID) { - return nil - } - if utils.IsContain(data.MsgData.SendID, m.config.IMAdmin.UserID) { + if datautil.Contain(data.MsgData.SendID, m.config.Share.IMAdminUserID...) { return nil } if data.MsgData.ContentType <= constant.NotificationEnd && @@ -65,35 +64,33 @@ func (m *msgServer) messageVerification(ctx context.Context, data *msg.SendMsgRe return err } if black { - return errs.ErrBlockedByPeer.Wrap() + return servererrs.ErrBlockedByPeer.Wrap() } - if m.config.MessageVerify.FriendVerify != nil && *m.config.MessageVerify.FriendVerify { + if m.config.RpcConfig.FriendVerify { friend, err := m.FriendLocalCache.IsFriend(ctx, data.MsgData.SendID, data.MsgData.RecvID) if err != nil { return err } if !friend { - return errs.ErrNotPeersFriend.Wrap() + return servererrs.ErrNotPeersFriend.Wrap() } return nil } return nil - case constant.SuperGroupChatType: + case constant.ReadGroupChatType: groupInfo, err := m.GroupLocalCache.GetGroupInfo(ctx, data.MsgData.GroupID) if err != nil { return err } if groupInfo.Status == constant.GroupStatusDismissed && data.MsgData.ContentType != constant.GroupDismissedNotification { - return errs.ErrDismissedAlready.Wrap() + return servererrs.ErrDismissedAlready.Wrap() } if groupInfo.GroupType == constant.SuperGroup { return nil } - if len(m.config.Manager.UserID) > 0 && utils.IsContain(data.MsgData.SendID, m.config.Manager.UserID) { - return nil - } - if utils.IsContain(data.MsgData.SendID, m.config.IMAdmin.UserID) { + + if datautil.Contain(data.MsgData.SendID, m.config.Share.IMAdminUserID...) { return nil } if data.MsgData.ContentType <= constant.NotificationEnd && @@ -105,13 +102,13 @@ func (m *msgServer) messageVerification(ctx context.Context, data *msg.SendMsgRe return err } if _, ok := memberIDs[data.MsgData.SendID]; !ok { - return errs.ErrNotInGroupYet.Wrap() + return servererrs.ErrNotInGroupYet.Wrap() } groupMemberInfo, err := m.GroupLocalCache.GetGroupMember(ctx, data.MsgData.GroupID, data.MsgData.SendID) if err != nil { if errs.ErrRecordNotFound.Is(err) { - return errs.ErrNotInGroupYet.Wrap(err.Error()) + return servererrs.ErrNotInGroupYet.WrapMsg(err.Error()) } return err } @@ -119,10 +116,10 @@ func (m *msgServer) messageVerification(ctx context.Context, data *msg.SendMsgRe return nil } else { if groupMemberInfo.MuteEndTime >= time.Now().UnixMilli() { - return errs.ErrMutedInGroup.Wrap() + return servererrs.ErrMutedInGroup.Wrap() } if groupInfo.Status == constant.GroupStatusMuted && groupMemberInfo.RoleLevel != constant.GroupAdmin { - return errs.ErrMutedGroup.Wrap() + return servererrs.ErrMutedGroup.Wrap() } } return nil @@ -134,7 +131,7 @@ func (m *msgServer) messageVerification(ctx context.Context, data *msg.SendMsgRe func (m *msgServer) encapsulateMsgData(msg *sdkws.MsgData) { msg.ServerMsgID = GetMsgID(msg.SendID) if msg.SendTime == 0 { - msg.SendTime = utils.GetCurrentTimestampByMill() + msg.SendTime = timeutil.GetCurrentTimestampByMill() } switch msg.ContentType { case constant.Text: @@ -159,36 +156,30 @@ func (m *msgServer) encapsulateMsgData(msg *sdkws.MsgData) { fallthrough case constant.Quote: case constant.Revoke: - utils.SetSwitchFromOptions(msg.Options, constant.IsUnreadCount, false) - utils.SetSwitchFromOptions(msg.Options, constant.IsOfflinePush, false) + datautil.SetSwitchFromOptions(msg.Options, constant.IsUnreadCount, false) + datautil.SetSwitchFromOptions(msg.Options, constant.IsOfflinePush, false) case constant.HasReadReceipt: - utils.SetSwitchFromOptions(msg.Options, constant.IsConversationUpdate, false) - utils.SetSwitchFromOptions(msg.Options, constant.IsSenderConversationUpdate, false) - utils.SetSwitchFromOptions(msg.Options, constant.IsUnreadCount, false) - utils.SetSwitchFromOptions(msg.Options, constant.IsOfflinePush, false) + datautil.SetSwitchFromOptions(msg.Options, constant.IsConversationUpdate, false) + datautil.SetSwitchFromOptions(msg.Options, constant.IsSenderConversationUpdate, false) + datautil.SetSwitchFromOptions(msg.Options, constant.IsUnreadCount, false) + datautil.SetSwitchFromOptions(msg.Options, constant.IsOfflinePush, false) case constant.Typing: - utils.SetSwitchFromOptions(msg.Options, constant.IsHistory, false) - utils.SetSwitchFromOptions(msg.Options, constant.IsPersistent, false) - utils.SetSwitchFromOptions(msg.Options, constant.IsSenderSync, false) - utils.SetSwitchFromOptions(msg.Options, constant.IsConversationUpdate, false) - utils.SetSwitchFromOptions(msg.Options, constant.IsSenderConversationUpdate, false) - utils.SetSwitchFromOptions(msg.Options, constant.IsUnreadCount, false) - utils.SetSwitchFromOptions(msg.Options, constant.IsOfflinePush, false) + datautil.SetSwitchFromOptions(msg.Options, constant.IsHistory, false) + datautil.SetSwitchFromOptions(msg.Options, constant.IsPersistent, false) + datautil.SetSwitchFromOptions(msg.Options, constant.IsSenderSync, false) + datautil.SetSwitchFromOptions(msg.Options, constant.IsConversationUpdate, false) + datautil.SetSwitchFromOptions(msg.Options, constant.IsSenderConversationUpdate, false) + datautil.SetSwitchFromOptions(msg.Options, constant.IsUnreadCount, false) + datautil.SetSwitchFromOptions(msg.Options, constant.IsOfflinePush, false) } } func GetMsgID(sendID string) string { - t := time.Now().Format("2006-01-02 15:04:05") - return utils.Md5(t + "-" + sendID + "-" + strconv.Itoa(rand.Int())) + t := timeutil.GetCurrentTimeFormatted() + return encrypt.Md5(t + "-" + sendID + "-" + strconv.Itoa(rand.Int())) } -func (m *msgServer) modifyMessageByUserMessageReceiveOpt( - ctx context.Context, - userID, conversationID string, - sessionType int, - pb *msg.SendMsgReq, -) (bool, error) { - defer log.ZDebug(ctx, "modifyMessageByUserMessageReceiveOpt return") +func (m *msgServer) modifyMessageByUserMessageReceiveOpt(ctx context.Context, userID, conversationID string, sessionType int, pb *msg.SendMsgReq) (bool, error) { opt, err := m.UserLocalCache.GetUserGlobalMsgRecvOpt(ctx, userID) if err != nil { return false, err @@ -201,10 +192,9 @@ func (m *msgServer) modifyMessageByUserMessageReceiveOpt( if pb.MsgData.Options == nil { pb.MsgData.Options = make(map[string]bool, 10) } - utils.SetSwitchFromOptions(pb.MsgData.Options, constant.IsOfflinePush, false) + datautil.SetSwitchFromOptions(pb.MsgData.Options, constant.IsOfflinePush, false) return true, nil } - // conversationID := utils.GetConversationIDBySessionType(conversationID, sessionType) singleOpt, err := m.ConversationLocalCache.GetSingleConversationRecvMsgOpt(ctx, userID, conversationID) if errs.ErrRecordNotFound.Is(err) { return true, nil @@ -215,7 +205,7 @@ func (m *msgServer) modifyMessageByUserMessageReceiveOpt( case constant.ReceiveMessage: return true, nil case constant.NotReceiveMessage: - if utils.IsContainInt(int(pb.MsgData.ContentType), ExcludeContentType) { + if datautil.Contain(int(pb.MsgData.ContentType), ExcludeContentType...) { return true, nil } return false, nil @@ -223,7 +213,7 @@ func (m *msgServer) modifyMessageByUserMessageReceiveOpt( if pb.MsgData.Options == nil { pb.MsgData.Options = make(map[string]bool, 10) } - utils.SetSwitchFromOptions(pb.MsgData.Options, constant.IsOfflinePush, false) + datautil.SetSwitchFromOptions(pb.MsgData.Options, constant.IsOfflinePush, false) return true, nil } return true, nil diff --git a/internal/rpc/third/log.go b/internal/rpc/third/log.go index 97428254c7..7712851ed9 100644 --- a/internal/rpc/third/log.go +++ b/internal/rpc/third/log.go @@ -17,16 +17,16 @@ package third import ( "context" "crypto/rand" - "fmt" "time" - "github.com/OpenIMSDK/protocol/constant" - "github.com/OpenIMSDK/protocol/third" - "github.com/OpenIMSDK/tools/errs" - "github.com/OpenIMSDK/tools/utils" - utils2 "github.com/OpenIMSDK/tools/utils" "github.com/openimsdk/open-im-server/v3/pkg/authverify" relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" + "github.com/openimsdk/open-im-server/v3/pkg/common/servererrs" + "github.com/openimsdk/protocol/constant" + "github.com/openimsdk/protocol/third" + "github.com/openimsdk/tools/errs" + "github.com/openimsdk/tools/utils/datautil" + "github.com/openimsdk/tools/utils/stringutil" ) func genLogID() string { @@ -45,7 +45,7 @@ func genLogID() string { } func (t *thirdServer) UploadLogs(ctx context.Context, req *third.UploadLogsReq) (*third.UploadLogsResp, error) { - var DBlogs []*relationtb.LogModel + var dbLogs []*relationtb.LogModel userID := ctx.Value(constant.OpUserID).(string) platform := constant.PlatformID2Name[int(req.Platform)] for _, fileURL := range req.FileURLs { @@ -70,11 +70,11 @@ func (t *thirdServer) UploadLogs(ctx context.Context, req *third.UploadLogsReq) } } if log.LogID == "" { - return nil, errs.ErrData.Wrap("LogModel id gen error") + return nil, servererrs.ErrData.WrapMsg("LogModel id gen error") } - DBlogs = append(DBlogs, &log) + dbLogs = append(dbLogs, &log) } - err := t.thirdDatabase.UploadLogs(ctx, DBlogs) + err := t.thirdDatabase.UploadLogs(ctx, dbLogs) if err != nil { return nil, err } @@ -82,7 +82,7 @@ func (t *thirdServer) UploadLogs(ctx context.Context, req *third.UploadLogsReq) } func (t *thirdServer) DeleteLogs(ctx context.Context, req *third.DeleteLogsReq) (*third.DeleteLogsResp, error) { - if err := authverify.CheckAdmin(ctx, t.config); err != nil { + if err := authverify.CheckAdmin(ctx, t.config.Share.IMAdminUserID); err != nil { return nil, err } userID := "" @@ -94,8 +94,8 @@ func (t *thirdServer) DeleteLogs(ctx context.Context, req *third.DeleteLogsReq) for _, log := range logs { logIDs = append(logIDs, log.LogID) } - if ids := utils2.Single(req.LogIDs, logIDs); len(ids) > 0 { - return nil, errs.ErrRecordNotFound.Wrap(fmt.Sprintf("logIDs not found%#v", ids)) + if ids := datautil.Single(req.LogIDs, logIDs); len(ids) > 0 { + return nil, errs.ErrRecordNotFound.WrapMsg("logIDs not found", "logIDs", ids) } err = t.thirdDatabase.DeleteLogs(ctx, req.LogIDs, userID) if err != nil { @@ -110,7 +110,7 @@ func dbToPbLogInfos(logs []*relationtb.LogModel) []*third.LogInfo { return &third.LogInfo{ Filename: log.FileName, UserID: log.UserID, - Platform: utils.StringToInt32(log.Platform), + Platform: stringutil.StringToInt32(log.Platform), Url: log.Url, CreateTime: log.CreateTime.UnixMilli(), LogID: log.LogID, @@ -119,11 +119,11 @@ func dbToPbLogInfos(logs []*relationtb.LogModel) []*third.LogInfo { Ex: log.Ex, } } - return utils.Slice(logs, db2pbForLogInfo) + return datautil.Slice(logs, db2pbForLogInfo) } func (t *thirdServer) SearchLogs(ctx context.Context, req *third.SearchLogsReq) (*third.SearchLogsResp, error) { - if err := authverify.CheckAdmin(ctx, t.config); err != nil { + if err := authverify.CheckAdmin(ctx, t.config.Share.IMAdminUserID); err != nil { return nil, err } var ( @@ -131,7 +131,7 @@ func (t *thirdServer) SearchLogs(ctx context.Context, req *third.SearchLogsReq) userIDs []string ) if req.StartTime > req.EndTime { - return nil, errs.ErrArgs.Wrap("startTime>endTime") + return nil, errs.ErrArgs.WrapMsg("startTime>endTime") } if req.StartTime == 0 && req.EndTime == 0 { t := time.Date(2019, time.January, 1, 0, 0, 0, 0, time.UTC) diff --git a/internal/rpc/third/s3.go b/internal/rpc/third/s3.go index f79b73a993..21d982268e 100644 --- a/internal/rpc/third/s3.go +++ b/internal/rpc/third/s3.go @@ -23,15 +23,16 @@ import ( "strconv" "time" - "github.com/OpenIMSDK/protocol/third" - "github.com/OpenIMSDK/tools/errs" - "github.com/OpenIMSDK/tools/log" - "github.com/OpenIMSDK/tools/mcontext" - "github.com/OpenIMSDK/tools/utils" "github.com/google/uuid" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/s3" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/s3/cont" "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" + "github.com/openimsdk/open-im-server/v3/pkg/common/servererrs" + "github.com/openimsdk/protocol/third" + "github.com/openimsdk/tools/errs" + "github.com/openimsdk/tools/log" + "github.com/openimsdk/tools/mcontext" + "github.com/openimsdk/tools/s3" + "github.com/openimsdk/tools/s3/cont" + "github.com/openimsdk/tools/utils/datautil" ) func (t *thirdServer) PartLimit(ctx context.Context, req *third.PartLimitReq) (*third.PartLimitResp, error) { @@ -52,7 +53,6 @@ func (t *thirdServer) PartSize(ctx context.Context, req *third.PartSizeReq) (*th } func (t *thirdServer) InitiateMultipartUpload(ctx context.Context, req *third.InitiateMultipartUploadReq) (*third.InitiateMultipartUploadResp, error) { - defer log.ZDebug(ctx, "return") if err := t.checkUploadName(ctx, req.Name); err != nil { return nil, err } @@ -74,7 +74,7 @@ func (t *thirdServer) InitiateMultipartUpload(ctx context.Context, req *third.In return nil, err } return &third.InitiateMultipartUploadResp{ - Url: t.apiAddress(obj.Name), + Url: t.apiAddress(req.UrlPrefix, obj.Name), }, nil } return nil, err @@ -107,8 +107,7 @@ func (t *thirdServer) InitiateMultipartUpload(ctx context.Context, req *third.In } func (t *thirdServer) AuthSign(ctx context.Context, req *third.AuthSignReq) (*third.AuthSignResp, error) { - defer log.ZDebug(ctx, "return") - partNumbers := utils.Slice(req.PartNumbers, func(partNumber int32) int { return int(partNumber) }) + partNumbers := datautil.Slice(req.PartNumbers, func(partNumber int32) int { return int(partNumber) }) result, err := t.s3dataBase.AuthSign(ctx, req.UploadID, partNumbers) if err != nil { return nil, err @@ -131,7 +130,6 @@ func (t *thirdServer) AuthSign(ctx context.Context, req *third.AuthSignReq) (*th } func (t *thirdServer) CompleteMultipartUpload(ctx context.Context, req *third.CompleteMultipartUploadReq) (*third.CompleteMultipartUploadResp, error) { - defer log.ZDebug(ctx, "return") if err := t.checkUploadName(ctx, req.Name); err != nil { return nil, err } @@ -153,7 +151,7 @@ func (t *thirdServer) CompleteMultipartUpload(ctx context.Context, req *third.Co return nil, err } return &third.CompleteMultipartUploadResp{ - Url: t.apiAddress(obj.Name), + Url: t.apiAddress(req.UrlPrefix, obj.Name), }, nil } @@ -169,7 +167,7 @@ func (t *thirdServer) AccessURL(ctx context.Context, req *third.AccessURLReq) (* opt.Image.Height, _ = strconv.Atoi(req.Query["height"]) log.ZDebug(ctx, "AccessURL image", "name", req.Name, "option", opt.Image) default: - return nil, errs.ErrArgs.Wrap("invalid query type") + return nil, errs.ErrArgs.WrapMsg("invalid query type") } } expireTime, rawURL, err := t.s3dataBase.AccessURL(ctx, req.Name, t.defaultExpire, opt) @@ -184,10 +182,10 @@ func (t *thirdServer) AccessURL(ctx context.Context, req *third.AccessURLReq) (* func (t *thirdServer) InitiateFormData(ctx context.Context, req *third.InitiateFormDataReq) (*third.InitiateFormDataResp, error) { if req.Name == "" { - return nil, errs.ErrArgs.Wrap("name is empty") + return nil, errs.ErrArgs.WrapMsg("name is empty") } if req.Size <= 0 { - return nil, errs.ErrArgs.Wrap("size must be greater than 0") + return nil, errs.ErrArgs.WrapMsg("size must be greater than 0") } if err := t.checkUploadName(ctx, req.Name); err != nil { return nil, err @@ -209,7 +207,7 @@ func (t *thirdServer) InitiateFormData(ctx context.Context, req *third.InitiateF } uid, err := uuid.NewRandom() if err != nil { - return nil, errs.Wrap(err, "uuid NewRandom failed") + return nil, errs.WrapMsg(err, "uuid NewRandom failed") } if key == "" { date := time.Now().Format("20060102") @@ -224,7 +222,7 @@ func (t *thirdServer) InitiateFormData(ctx context.Context, req *third.InitiateF } mateData, err := json.Marshal(&mate) if err != nil { - return nil, errs.Wrap(err, "marshal failed") + return nil, errs.WrapMsg(err, "marshal failed") } resp, err := t.s3dataBase.FormData(ctx, key, req.Size, req.ContentType, duration) if err != nil { @@ -237,7 +235,7 @@ func (t *thirdServer) InitiateFormData(ctx context.Context, req *third.InitiateF Header: toPbMapArray(resp.Header), FormData: resp.FormData, Expires: resp.Expires.UnixMilli(), - SuccessCodes: utils.Slice(resp.SuccessCodes, func(code int) int32 { + SuccessCodes: datautil.Slice(resp.SuccessCodes, func(code int) int32 { return int32(code) }), }, nil @@ -245,15 +243,15 @@ func (t *thirdServer) InitiateFormData(ctx context.Context, req *third.InitiateF func (t *thirdServer) CompleteFormData(ctx context.Context, req *third.CompleteFormDataReq) (*third.CompleteFormDataResp, error) { if req.Id == "" { - return nil, errs.ErrArgs.Wrap("id is empty") + return nil, errs.ErrArgs.WrapMsg("id is empty") } data, err := base64.RawStdEncoding.DecodeString(req.Id) if err != nil { - return nil, errs.ErrArgs.Wrap("invalid id " + err.Error()) + return nil, errs.ErrArgs.WrapMsg("invalid id " + err.Error()) } var mate FormDataMate if err := json.Unmarshal(data, &mate); err != nil { - return nil, errs.ErrArgs.Wrap("invalid id " + err.Error()) + return nil, errs.ErrArgs.WrapMsg("invalid id " + err.Error()) } if err := t.checkUploadName(ctx, mate.Name); err != nil { return nil, err @@ -263,7 +261,7 @@ func (t *thirdServer) CompleteFormData(ctx context.Context, req *third.CompleteF return nil, err } if info.Size > 0 && info.Size != mate.Size { - return nil, errs.ErrData.Wrap("file size mismatch") + return nil, servererrs.ErrData.WrapMsg("file size mismatch") } obj := &relation.ObjectModel{ Name: mate.Name, @@ -278,11 +276,11 @@ func (t *thirdServer) CompleteFormData(ctx context.Context, req *third.CompleteF if err := t.s3dataBase.SetObject(ctx, obj); err != nil { return nil, err } - return &third.CompleteFormDataResp{Url: t.apiAddress(mate.Name)}, nil + return &third.CompleteFormDataResp{Url: t.apiAddress(req.UrlPrefix, mate.Name)}, nil } -func (t *thirdServer) apiAddress(name string) string { - return t.apiURL + name +func (t *thirdServer) apiAddress(prefix, name string) string { + return prefix + name } type FormDataMate struct { diff --git a/internal/rpc/third/third.go b/internal/rpc/third/third.go index 928fb0f42c..ad87fa6f5c 100644 --- a/internal/rpc/third/third.go +++ b/internal/rpc/third/third.go @@ -17,73 +17,95 @@ package third import ( "context" "fmt" + "github.com/openimsdk/open-im-server/v3/pkg/common/config" "net/url" "time" - "github.com/OpenIMSDK/protocol/third" - "github.com/OpenIMSDK/tools/discoveryregistry" - "github.com/OpenIMSDK/tools/errs" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" "github.com/openimsdk/open-im-server/v3/pkg/common/db/mgo" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/s3" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/s3/cos" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/s3/minio" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/s3/oss" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/unrelation" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" + "github.com/openimsdk/protocol/third" + "github.com/openimsdk/tools/db/mongoutil" + "github.com/openimsdk/tools/db/redisutil" + "github.com/openimsdk/tools/discovery" + "github.com/openimsdk/tools/errs" + "github.com/openimsdk/tools/s3" + "github.com/openimsdk/tools/s3/cos" + "github.com/openimsdk/tools/s3/minio" + "github.com/openimsdk/tools/s3/oss" "google.golang.org/grpc" ) -func Start(config *config.GlobalConfig, client discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) error { - mongo, err := unrelation.NewMongo(config) +type thirdServer struct { + apiURL string + thirdDatabase controller.ThirdDatabase + s3dataBase controller.S3Database + userRpcClient rpcclient.UserRpcClient + defaultExpire time.Duration + config *Config +} +type Config struct { + RpcConfig config.Third + RedisConfig config.Redis + MongodbConfig config.Mongo + ZookeeperConfig config.ZooKeeper + NotificationConfig config.Notification + Share config.Share + MinioConfig config.Minio + LocalCacheConfig config.LocalCache +} + +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 + } + rdb, err := redisutil.NewRedisClient(ctx, config.RedisConfig.Build()) if err != nil { return err } - logdb, err := mgo.NewLogMongo(mongo.GetDatabase(config.Mongo.Database)) + logdb, err := mgo.NewLogMongo(mgocli.GetDB()) if err != nil { return err } - s3db, err := mgo.NewS3Mongo(mongo.GetDatabase(config.Mongo.Database)) + s3db, err := mgo.NewS3Mongo(mgocli.GetDB()) if err != nil { return err } - apiURL := config.Object.ApiURL + apiURL := config.MinioConfig.URL if apiURL == "" { return errs.Wrap(fmt.Errorf("api is empty")) } - if _, err := url.Parse(config.Object.ApiURL); err != nil { + if _, err := url.Parse(config.MinioConfig.URL); err != nil { return err } if apiURL[len(apiURL)-1] != '/' { apiURL += "/" } apiURL += "object/" - rdb, err := cache.NewRedis(config) - if err != nil { - return err - } + // Select the oss method according to the profile policy - enable := config.Object.Enable + enable := config.RpcConfig.Object.Enable var o s3.Interface switch enable { case "minio": - o, err = minio.NewMinio(cache.NewMinioCache(rdb), minio.Config(config.Object.Minio)) + o, err = minio.NewMinio(ctx, cache.NewMinioCache(rdb), *config.MinioConfig.Build()) case "cos": - o, err = cos.NewCos(cos.Config(config.Object.Cos)) + o, err = cos.NewCos(*config.RpcConfig.Object.Cos.Build()) case "oss": - o, err = oss.NewOSS(oss.Config(config.Object.Oss)) + o, err = oss.NewOSS(*config.RpcConfig.Object.Oss.Build()) default: err = fmt.Errorf("invalid object enable: %s", enable) } if err != nil { return err } + cache.InitLocalCache(&config.LocalCacheConfig) third.RegisterThirdServer(server, &thirdServer{ apiURL: apiURL, - thirdDatabase: controller.NewThirdDatabase(cache.NewMsgCacheModel(rdb, config), logdb), - userRpcClient: rpcclient.NewUserRpcClient(client, config), + thirdDatabase: controller.NewThirdDatabase(cache.NewThirdCache(rdb), logdb), + userRpcClient: rpcclient.NewUserRpcClient(client, config.Share.RpcRegisterName.User, config.Share.IMAdminUserID), s3dataBase: controller.NewS3Database(rdb, o, s3db), defaultExpire: time.Hour * 24 * 7, config: config, @@ -91,15 +113,6 @@ func Start(config *config.GlobalConfig, client discoveryregistry.SvcDiscoveryReg return nil } -type thirdServer struct { - apiURL string - thirdDatabase controller.ThirdDatabase - s3dataBase controller.S3Database - userRpcClient rpcclient.UserRpcClient - defaultExpire time.Duration - config *config.GlobalConfig -} - func (t *thirdServer) FcmUpdateToken(ctx context.Context, req *third.FcmUpdateTokenReq) (resp *third.FcmUpdateTokenResp, err error) { err = t.thirdDatabase.FcmUpdateToken(ctx, req.Account, int(req.PlatformID), req.FcmToken, req.ExpireTime) if err != nil { diff --git a/internal/rpc/third/tool.go b/internal/rpc/third/tool.go index d8491d3549..ac4be39689 100644 --- a/internal/rpc/third/tool.go +++ b/internal/rpc/third/tool.go @@ -16,15 +16,14 @@ package third import ( "context" - "errors" "fmt" "strings" "unicode/utf8" - "github.com/OpenIMSDK/protocol/third" - "github.com/OpenIMSDK/tools/errs" - "github.com/OpenIMSDK/tools/mcontext" "github.com/openimsdk/open-im-server/v3/pkg/authverify" + "github.com/openimsdk/protocol/third" + "github.com/openimsdk/tools/errs" + "github.com/openimsdk/tools/mcontext" ) func toPbMapArray(m map[string][]string) []*third.KeyValues { @@ -43,21 +42,21 @@ func toPbMapArray(m map[string][]string) []*third.KeyValues { func (t *thirdServer) checkUploadName(ctx context.Context, name string) error { if name == "" { - return errs.ErrArgs.Wrap("name is empty") + return errs.ErrArgs.WrapMsg("name is empty") } if name[0] == '/' { - return errs.ErrArgs.Wrap("name cannot start with `/`") + return errs.ErrArgs.WrapMsg("name cannot start with `/`") } if err := checkValidObjectName(name); err != nil { - return errs.ErrArgs.Wrap(err.Error()) + return errs.ErrArgs.WrapMsg(err.Error()) } opUserID := mcontext.GetOpUserID(ctx) if opUserID == "" { - return errs.ErrNoPermission.Wrap("opUserID is empty") + return errs.ErrNoPermission.WrapMsg("opUserID is empty") } - if !authverify.IsManagerUserID(opUserID, t.config) { + if !authverify.IsManagerUserID(opUserID, t.config.Share.IMAdminUserID) { if !strings.HasPrefix(name, opUserID+"/") { - return errs.ErrNoPermission.Wrap(fmt.Sprintf("name must start with `%s/`", opUserID)) + return errs.ErrNoPermission.WrapMsg(fmt.Sprintf("name must start with `%s/`", opUserID)) } } return nil @@ -65,21 +64,21 @@ func (t *thirdServer) checkUploadName(ctx context.Context, name string) error { func checkValidObjectNamePrefix(objectName string) error { if len(objectName) > 1024 { - return errors.New("object name cannot be longer than 1024 characters") + return errs.New("object name cannot be longer than 1024 characters") } if !utf8.ValidString(objectName) { - return errors.New("object name with non UTF-8 strings are not supported") + return errs.New("object name with non UTF-8 strings are not supported") } return nil } func checkValidObjectName(objectName string) error { if strings.TrimSpace(objectName) == "" { - return errors.New("object name cannot be empty") + return errs.New("object name cannot be empty") } return checkValidObjectNamePrefix(objectName) } func (t *thirdServer) IsManagerUserID(opUserID string) bool { - return authverify.IsManagerUserID(opUserID, t.config) + return authverify.IsManagerUserID(opUserID, t.config.Share.IMAdminUserID) } diff --git a/internal/rpc/user/callback.go b/internal/rpc/user/callback.go index 34f211973d..1bdf399d22 100644 --- a/internal/rpc/user/callback.go +++ b/internal/rpc/user/callback.go @@ -16,118 +16,101 @@ package user import ( "context" + "github.com/openimsdk/open-im-server/v3/pkg/common/webhook" + "github.com/openimsdk/tools/utils/datautil" - pbuser "github.com/OpenIMSDK/protocol/user" - "github.com/OpenIMSDK/tools/utils" cbapi "github.com/openimsdk/open-im-server/v3/pkg/callbackstruct" "github.com/openimsdk/open-im-server/v3/pkg/common/config" - "github.com/openimsdk/open-im-server/v3/pkg/common/http" + pbuser "github.com/openimsdk/protocol/user" ) -func CallbackBeforeUpdateUserInfo(ctx context.Context, globalConfig *config.GlobalConfig, req *pbuser.UpdateUserInfoReq) error { - if !globalConfig.Callback.CallbackBeforeUpdateUserInfo.Enable { +func (s *userServer) webhookBeforeUpdateUserInfo(ctx context.Context, before *config.BeforeConfig, req *pbuser.UpdateUserInfoReq) error { + return webhook.WithCondition(ctx, before, func(ctx context.Context) error { + cbReq := &cbapi.CallbackBeforeUpdateUserInfoReq{ + CallbackCommand: cbapi.CallbackBeforeUpdateUserInfoCommand, + UserID: req.UserInfo.UserID, + FaceURL: &req.UserInfo.FaceURL, + Nickname: &req.UserInfo.Nickname, + } + resp := &cbapi.CallbackBeforeUpdateUserInfoResp{} + if err := s.webhookClient.SyncPost(ctx, cbReq.GetCallbackCommand(), cbReq, resp, before); err != nil { + return err + } + + datautil.NotNilReplace(&req.UserInfo.FaceURL, resp.FaceURL) + datautil.NotNilReplace(&req.UserInfo.Ex, resp.Ex) + datautil.NotNilReplace(&req.UserInfo.Nickname, resp.Nickname) return nil - } - cbReq := &cbapi.CallbackBeforeUpdateUserInfoReq{ - CallbackCommand: cbapi.CallbackBeforeUpdateUserInfoCommand, - UserID: req.UserInfo.UserID, - FaceURL: &req.UserInfo.FaceURL, - Nickname: &req.UserInfo.Nickname, - } - resp := &cbapi.CallbackBeforeUpdateUserInfoResp{} - if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, cbReq, resp, globalConfig.Callback.CallbackBeforeUpdateUserInfo); err != nil { - return err - } - utils.NotNilReplace(&req.UserInfo.FaceURL, resp.FaceURL) - utils.NotNilReplace(&req.UserInfo.Ex, resp.Ex) - utils.NotNilReplace(&req.UserInfo.Nickname, resp.Nickname) - return nil + }) } -func CallbackAfterUpdateUserInfo(ctx context.Context, globalConfig *config.GlobalConfig, req *pbuser.UpdateUserInfoReq) error { - if !globalConfig.Callback.CallbackAfterUpdateUserInfo.Enable { - return nil - } + +func (s *userServer) webhookAfterUpdateUserInfo(ctx context.Context, after *config.AfterConfig, req *pbuser.UpdateUserInfoReq) { cbReq := &cbapi.CallbackAfterUpdateUserInfoReq{ CallbackCommand: cbapi.CallbackAfterUpdateUserInfoCommand, UserID: req.UserInfo.UserID, FaceURL: req.UserInfo.FaceURL, Nickname: req.UserInfo.Nickname, } - resp := &cbapi.CallbackAfterUpdateUserInfoResp{} - if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, cbReq, resp, globalConfig.Callback.CallbackBeforeUpdateUserInfo); err != nil { - return err - } - return nil + s.webhookClient.AsyncPost(ctx, cbReq.GetCallbackCommand(), cbReq, &cbapi.CallbackAfterUpdateUserInfoResp{}, after) } -func CallbackBeforeUpdateUserInfoEx(ctx context.Context, globalConfig *config.GlobalConfig, req *pbuser.UpdateUserInfoExReq) error { - if !globalConfig.Callback.CallbackBeforeUpdateUserInfoEx.Enable { + +func (s *userServer) webhookBeforeUpdateUserInfoEx(ctx context.Context, before *config.BeforeConfig, req *pbuser.UpdateUserInfoExReq) error { + return webhook.WithCondition(ctx, before, func(ctx context.Context) error { + cbReq := &cbapi.CallbackBeforeUpdateUserInfoExReq{ + CallbackCommand: cbapi.CallbackBeforeUpdateUserInfoExCommand, + UserID: req.UserInfo.UserID, + FaceURL: req.UserInfo.FaceURL, + Nickname: req.UserInfo.Nickname, + } + resp := &cbapi.CallbackBeforeUpdateUserInfoExResp{} + if err := s.webhookClient.SyncPost(ctx, cbReq.GetCallbackCommand(), cbReq, resp, before); err != nil { + return err + } + + datautil.NotNilReplace(req.UserInfo.FaceURL, resp.FaceURL) + datautil.NotNilReplace(req.UserInfo.Ex, resp.Ex) + datautil.NotNilReplace(req.UserInfo.Nickname, resp.Nickname) return nil - } - cbReq := &cbapi.CallbackBeforeUpdateUserInfoExReq{ - CallbackCommand: cbapi.CallbackBeforeUpdateUserInfoExCommand, - UserID: req.UserInfo.UserID, - FaceURL: req.UserInfo.FaceURL, - Nickname: req.UserInfo.Nickname, - } - resp := &cbapi.CallbackBeforeUpdateUserInfoExResp{} - if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, cbReq, resp, globalConfig.Callback.CallbackBeforeUpdateUserInfoEx); err != nil { - return err - } - utils.NotNilReplace(req.UserInfo.FaceURL, resp.FaceURL) - utils.NotNilReplace(req.UserInfo.Ex, resp.Ex) - utils.NotNilReplace(req.UserInfo.Nickname, resp.Nickname) - return nil + }) } -func CallbackAfterUpdateUserInfoEx(ctx context.Context, globalConfig *config.GlobalConfig, req *pbuser.UpdateUserInfoExReq) error { - if !globalConfig.Callback.CallbackAfterUpdateUserInfoEx.Enable { - return nil - } + +func (s *userServer) webhookAfterUpdateUserInfoEx(ctx context.Context, after *config.AfterConfig, req *pbuser.UpdateUserInfoExReq) { cbReq := &cbapi.CallbackAfterUpdateUserInfoExReq{ CallbackCommand: cbapi.CallbackAfterUpdateUserInfoExCommand, UserID: req.UserInfo.UserID, FaceURL: req.UserInfo.FaceURL, Nickname: req.UserInfo.Nickname, } - resp := &cbapi.CallbackAfterUpdateUserInfoExResp{} - if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, cbReq, resp, globalConfig.Callback.CallbackBeforeUpdateUserInfoEx); err != nil { - return err - } - return nil + s.webhookClient.AsyncPost(ctx, cbReq.GetCallbackCommand(), cbReq, &cbapi.CallbackAfterUpdateUserInfoExResp{}, after) } -func CallbackBeforeUserRegister(ctx context.Context, globalConfig *config.GlobalConfig, req *pbuser.UserRegisterReq) error { - if !globalConfig.Callback.CallbackBeforeUserRegister.Enable { - return nil - } - cbReq := &cbapi.CallbackBeforeUserRegisterReq{ - CallbackCommand: cbapi.CallbackBeforeUserRegisterCommand, - Secret: req.Secret, - Users: req.Users, - } +func (s *userServer) webhookBeforeUserRegister(ctx context.Context, before *config.BeforeConfig, req *pbuser.UserRegisterReq) error { + return webhook.WithCondition(ctx, before, func(ctx context.Context) error { + cbReq := &cbapi.CallbackBeforeUserRegisterReq{ + CallbackCommand: cbapi.CallbackBeforeUserRegisterCommand, + Secret: req.Secret, + Users: req.Users, + } - resp := &cbapi.CallbackBeforeUserRegisterResp{} - if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, cbReq, resp, globalConfig.Callback.CallbackBeforeUpdateUserInfo); err != nil { - return err - } - if len(resp.Users) != 0 { - req.Users = resp.Users - } - return nil -} + resp := &cbapi.CallbackBeforeUserRegisterResp{} + + if err := s.webhookClient.SyncPost(ctx, cbReq.GetCallbackCommand(), cbReq, resp, before); err != nil { + return err + } -func CallbackAfterUserRegister(ctx context.Context, globalConfig *config.GlobalConfig, req *pbuser.UserRegisterReq) error { - if !globalConfig.Callback.CallbackAfterUserRegister.Enable { + if len(resp.Users) != 0 { + req.Users = resp.Users + } return nil - } + }) +} + +func (s *userServer) webhookAfterUserRegister(ctx context.Context, after *config.AfterConfig, req *pbuser.UserRegisterReq) { cbReq := &cbapi.CallbackAfterUserRegisterReq{ CallbackCommand: cbapi.CallbackAfterUserRegisterCommand, Secret: req.Secret, Users: req.Users, } - resp := &cbapi.CallbackAfterUserRegisterResp{} - if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, cbReq, resp, globalConfig.Callback.CallbackAfterUpdateUserInfo); err != nil { - return err - } - return nil + s.webhookClient.AsyncPost(ctx, cbReq.GetCallbackCommand(), cbReq, &cbapi.CallbackAfterUserRegisterResp{}, after) } diff --git a/pkg/rpcclient/notification/user.go b/internal/rpc/user/notification.go similarity index 72% rename from pkg/rpcclient/notification/user.go rename to internal/rpc/user/notification.go index 610967fd55..348cd56281 100644 --- a/pkg/rpcclient/notification/user.go +++ b/internal/rpc/user/notification.go @@ -12,22 +12,22 @@ // See the License for the specific language governing permissions and // limitations under the License. -package notification +package user import ( "context" + "github.com/openimsdk/open-im-server/v3/pkg/rpcclient/notification" - "github.com/OpenIMSDK/protocol/constant" - "github.com/OpenIMSDK/protocol/sdkws" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" + "github.com/openimsdk/protocol/constant" + "github.com/openimsdk/protocol/sdkws" ) type UserNotificationSender struct { *rpcclient.NotificationSender - getUsersInfo func(ctx context.Context, userIDs []string) ([]CommonUser, error) + getUsersInfo func(ctx context.Context, userIDs []string) ([]notification.CommonUser, error) // db controller db controller.UserDatabase } @@ -44,7 +44,7 @@ func WithUserFunc( fn func(ctx context.Context, userIDs []string) (users []*relationtb.UserModel, err error), ) userNotificationSenderOptions { return func(u *UserNotificationSender) { - f := func(ctx context.Context, userIDs []string) (result []CommonUser, err error) { + f := func(ctx context.Context, userIDs []string) (result []notification.CommonUser, err error) { users, err := fn(ctx, userIDs) if err != nil { return nil, err @@ -58,13 +58,9 @@ func WithUserFunc( } } -func NewUserNotificationSender( - config *config.GlobalConfig, - msgRpcClient *rpcclient.MessageRpcClient, - opts ...userNotificationSenderOptions, -) *UserNotificationSender { +func NewUserNotificationSender(config *Config, msgRpcClient *rpcclient.MessageRpcClient, opts ...userNotificationSenderOptions) *UserNotificationSender { f := &UserNotificationSender{ - NotificationSender: rpcclient.NewNotificationSender(config, rpcclient.WithRpcClient(msgRpcClient)), + NotificationSender: rpcclient.NewNotificationSender(&config.NotificationConfig, rpcclient.WithRpcClient(msgRpcClient)), } for _, opt := range opts { opt(f) @@ -101,24 +97,24 @@ func NewUserNotificationSender( func (u *UserNotificationSender) UserStatusChangeNotification( ctx context.Context, tips *sdkws.UserStatusChangeTips, -) error { - return u.Notification(ctx, tips.FromUserID, tips.ToUserID, constant.UserStatusChangeNotification, tips) +) { + u.Notification(ctx, tips.FromUserID, tips.ToUserID, constant.UserStatusChangeNotification, tips) } func (u *UserNotificationSender) UserCommandUpdateNotification( ctx context.Context, tips *sdkws.UserCommandUpdateTips, -) error { - return u.Notification(ctx, tips.FromUserID, tips.ToUserID, constant.UserCommandUpdateNotification, tips) +) { + u.Notification(ctx, tips.FromUserID, tips.ToUserID, constant.UserCommandUpdateNotification, tips) } func (u *UserNotificationSender) UserCommandAddNotification( ctx context.Context, tips *sdkws.UserCommandAddTips, -) error { - return u.Notification(ctx, tips.FromUserID, tips.ToUserID, constant.UserCommandAddNotification, tips) +) { + u.Notification(ctx, tips.FromUserID, tips.ToUserID, constant.UserCommandAddNotification, tips) } func (u *UserNotificationSender) UserCommandDeleteNotification( ctx context.Context, tips *sdkws.UserCommandDeleteTips, -) error { - return u.Notification(ctx, tips.FromUserID, tips.ToUserID, constant.UserCommandDeleteNotification, tips) +) { + u.Notification(ctx, tips.FromUserID, tips.ToUserID, constant.UserCommandDeleteNotification, tips) } diff --git a/internal/rpc/user/statistics.go b/internal/rpc/user/statistics.go index 42068f2ce6..709c0146b5 100644 --- a/internal/rpc/user/statistics.go +++ b/internal/rpc/user/statistics.go @@ -18,27 +18,24 @@ import ( "context" "time" - pbuser "github.com/OpenIMSDK/protocol/user" - "github.com/OpenIMSDK/tools/errs" + pbuser "github.com/openimsdk/protocol/user" + "github.com/openimsdk/tools/errs" ) -func (s *userServer) UserRegisterCount( - ctx context.Context, - req *pbuser.UserRegisterCountReq, -) (*pbuser.UserRegisterCountResp, error) { +func (s *userServer) UserRegisterCount(ctx context.Context, req *pbuser.UserRegisterCountReq) (*pbuser.UserRegisterCountResp, error) { if req.Start > req.End { - return nil, errs.ErrArgs.Wrap("start > end") + return nil, errs.ErrArgs.WrapMsg("start > end") } - total, err := s.CountTotal(ctx, nil) + total, err := s.db.CountTotal(ctx, nil) if err != nil { return nil, err } start := time.UnixMilli(req.Start) - before, err := s.CountTotal(ctx, &start) + before, err := s.db.CountTotal(ctx, &start) if err != nil { return nil, err } - count, err := s.CountRangeEverydayTotal(ctx, start, time.UnixMilli(req.End)) + count, err := s.db.CountRangeEverydayTotal(ctx, start, time.UnixMilli(req.End)) if err != nil { return nil, err } diff --git a/internal/rpc/user/user.go b/internal/rpc/user/user.go index 3d13cd7b6f..c453ac9f85 100644 --- a/internal/rpc/user/user.go +++ b/internal/rpc/user/user.go @@ -16,91 +16,100 @@ package user import ( "context" - "fmt" + "github.com/openimsdk/open-im-server/v3/internal/rpc/friend" + "github.com/openimsdk/open-im-server/v3/pkg/common/config" + "github.com/openimsdk/open-im-server/v3/pkg/common/webhook" + "github.com/openimsdk/tools/db/redisutil" "math/rand" "strings" "time" - "github.com/OpenIMSDK/protocol/constant" - "github.com/OpenIMSDK/protocol/sdkws" - pbuser "github.com/OpenIMSDK/protocol/user" - registry "github.com/OpenIMSDK/tools/discoveryregistry" - "github.com/OpenIMSDK/tools/errs" - "github.com/OpenIMSDK/tools/log" - "github.com/OpenIMSDK/tools/pagination" - "github.com/OpenIMSDK/tools/tx" - "github.com/OpenIMSDK/tools/utils" "github.com/openimsdk/open-im-server/v3/pkg/authverify" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/convert" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" "github.com/openimsdk/open-im-server/v3/pkg/common/db/mgo" "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" tablerelation "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/unrelation" + "github.com/openimsdk/open-im-server/v3/pkg/common/servererrs" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" - "github.com/openimsdk/open-im-server/v3/pkg/rpcclient/notification" + "github.com/openimsdk/protocol/constant" + "github.com/openimsdk/protocol/sdkws" + pbuser "github.com/openimsdk/protocol/user" + "github.com/openimsdk/tools/db/mongoutil" + "github.com/openimsdk/tools/db/pagination" + registry "github.com/openimsdk/tools/discovery" + "github.com/openimsdk/tools/errs" + "github.com/openimsdk/tools/log" + "github.com/openimsdk/tools/utils/datautil" "google.golang.org/grpc" ) type userServer struct { - controller.UserDatabase - friendNotificationSender *notification.FriendNotificationSender - userNotificationSender *notification.UserNotificationSender + db controller.UserDatabase + friendNotificationSender *friend.FriendNotificationSender + userNotificationSender *UserNotificationSender friendRpcClient *rpcclient.FriendRpcClient groupRpcClient *rpcclient.GroupRpcClient RegisterCenter registry.SvcDiscoveryRegistry - config *config.GlobalConfig + config *Config + webhookClient *webhook.Client } -func (s *userServer) GetGroupOnlineUser(ctx context.Context, req *pbuser.GetGroupOnlineUserReq) (*pbuser.GetGroupOnlineUserResp, error) { - //TODO implement me - panic("implement me") +type Config struct { + RpcConfig config.User + RedisConfig config.Redis + MongodbConfig config.Mongo + KafkaConfig config.Kafka + ZookeeperConfig config.ZooKeeper + NotificationConfig config.Notification + Share config.Share + WebhooksConfig config.Webhooks + LocalCacheConfig config.LocalCache } -func Start(config *config.GlobalConfig, client registry.SvcDiscoveryRegistry, server *grpc.Server) error { - rdb, err := cache.NewRedis(config) +func Start(ctx context.Context, config *Config, client registry.SvcDiscoveryRegistry, server *grpc.Server) error { + mgocli, err := mongoutil.NewMongoDB(ctx, config.MongodbConfig.Build()) if err != nil { return err } - mongo, err := unrelation.NewMongo(config) + rdb, err := redisutil.NewRedisClient(ctx, config.RedisConfig.Build()) if err != nil { return err } users := make([]*tablerelation.UserModel, 0) - if len(config.IMAdmin.UserID) != len(config.IMAdmin.Nickname) { - return errs.Wrap(fmt.Errorf("the count of ImAdmin.UserID is not equal to the count of ImAdmin.Nickname")) - } - for k, v := range config.IMAdmin.UserID { - users = append(users, &tablerelation.UserModel{UserID: v, Nickname: config.IMAdmin.Nickname[k], AppMangerLevel: constant.AppNotificationAdmin}) + + for _, v := range config.Share.IMAdminUserID { + users = append(users, &tablerelation.UserModel{UserID: v, Nickname: v, AppMangerLevel: constant.AppNotificationAdmin}) } - userDB, err := mgo.NewUserMongo(mongo.GetDatabase(config.Mongo.Database)) + userDB, err := mgo.NewUserMongo(mgocli.GetDB()) if err != nil { return err } - cache := cache.NewUserCacheRedis(rdb, userDB, cache.GetDefaultOpt()) - userMongoDB := unrelation.NewUserMongoDriver(mongo.GetDatabase(config.Mongo.Database)) - database := controller.NewUserDatabase(userDB, cache, tx.NewMongo(mongo.GetClient()), userMongoDB) - friendRpcClient := rpcclient.NewFriendRpcClient(client, config) - groupRpcClient := rpcclient.NewGroupRpcClient(client, config) - msgRpcClient := rpcclient.NewMessageRpcClient(client, config) + userCache := cache.NewUserCacheRedis(rdb, &config.LocalCacheConfig, userDB, cache.GetDefaultOpt()) + userMongoDB := mgo.NewUserMongoDriver(mgocli.GetDB()) + database := controller.NewUserDatabase(userDB, userCache, mgocli.GetTx(), userMongoDB) + friendRpcClient := rpcclient.NewFriendRpcClient(client, config.Share.RpcRegisterName.Friend) + groupRpcClient := rpcclient.NewGroupRpcClient(client, config.Share.RpcRegisterName.Group) + msgRpcClient := rpcclient.NewMessageRpcClient(client, config.Share.RpcRegisterName.Msg) + cache.InitLocalCache(&config.LocalCacheConfig) u := &userServer{ - UserDatabase: database, + db: database, RegisterCenter: client, friendRpcClient: &friendRpcClient, groupRpcClient: &groupRpcClient, - friendNotificationSender: notification.NewFriendNotificationSender(config, &msgRpcClient, notification.WithDBFunc(database.FindWithError)), - userNotificationSender: notification.NewUserNotificationSender(config, &msgRpcClient, notification.WithUserFunc(database.FindWithError)), + friendNotificationSender: friend.NewFriendNotificationSender(&config.NotificationConfig, &msgRpcClient, friend.WithDBFunc(database.FindWithError)), + userNotificationSender: NewUserNotificationSender(config, &msgRpcClient, WithUserFunc(database.FindWithError)), config: config, + webhookClient: webhook.NewWebhookClient(config.WebhooksConfig.URL), } pbuser.RegisterUserServer(server, u) - return u.UserDatabase.InitOnce(context.Background(), users) + return u.db.InitOnce(context.Background(), users) } func (s *userServer) GetDesignateUsers(ctx context.Context, req *pbuser.GetDesignateUsersReq) (resp *pbuser.GetDesignateUsersResp, err error) { resp = &pbuser.GetDesignateUsersResp{} - users, err := s.FindWithError(ctx, req.UserIDs) + users, err := s.db.FindWithError(ctx, req.UserIDs) if err != nil { return nil, err } @@ -108,20 +117,26 @@ func (s *userServer) GetDesignateUsers(ctx context.Context, req *pbuser.GetDesig return resp, nil } +// deprecated: + +//UpdateUserInfo + func (s *userServer) UpdateUserInfo(ctx context.Context, req *pbuser.UpdateUserInfoReq) (resp *pbuser.UpdateUserInfoResp, err error) { resp = &pbuser.UpdateUserInfoResp{} - err = authverify.CheckAccessV3(ctx, req.UserInfo.UserID, s.config) + err = authverify.CheckAccessV3(ctx, req.UserInfo.UserID, s.config.Share.IMAdminUserID) if err != nil { return nil, err } - if err := CallbackBeforeUpdateUserInfo(ctx, s.config, req); err != nil { + + if err := s.webhookBeforeUpdateUserInfo(ctx, &s.config.WebhooksConfig.BeforeUpdateUserInfo, req); err != nil { return nil, err } + data := convert.UserPb2DBMap(req.UserInfo) - if err := s.UpdateByMap(ctx, req.UserInfo.UserID, data); err != nil { + if err := s.db.UpdateByMap(ctx, req.UserInfo.UserID, data); err != nil { return nil, err } - _ = s.friendNotificationSender.UserInfoUpdatedNotification(ctx, req.UserInfo.UserID) + s.friendNotificationSender.UserInfoUpdatedNotification(ctx, req.UserInfo.UserID) friends, err := s.friendRpcClient.GetFriendIDs(ctx, req.UserInfo.UserID) if err != nil { return nil, err @@ -134,9 +149,7 @@ func (s *userServer) UpdateUserInfo(ctx context.Context, req *pbuser.UpdateUserI for _, friendID := range friends { s.friendNotificationSender.FriendInfoUpdatedNotification(ctx, req.UserInfo.UserID, friendID) } - if err = CallbackAfterUpdateUserInfo(ctx, s.config, req); err != nil { - return nil, err - } + s.webhookAfterUpdateUserInfo(ctx, &s.config.WebhooksConfig.AfterUpdateUserInfo, req) if err = s.groupRpcClient.NotificationUserInfoUpdate(ctx, req.UserInfo.UserID); err != nil { return nil, err } @@ -144,19 +157,18 @@ func (s *userServer) UpdateUserInfo(ctx context.Context, req *pbuser.UpdateUserI } func (s *userServer) UpdateUserInfoEx(ctx context.Context, req *pbuser.UpdateUserInfoExReq) (resp *pbuser.UpdateUserInfoExResp, err error) { resp = &pbuser.UpdateUserInfoExResp{} - err = authverify.CheckAccessV3(ctx, req.UserInfo.UserID, s.config) + err = authverify.CheckAccessV3(ctx, req.UserInfo.UserID, s.config.Share.IMAdminUserID) if err != nil { return nil, err } - - if err = CallbackBeforeUpdateUserInfoEx(ctx, s.config, req); err != nil { + if err = s.webhookBeforeUpdateUserInfoEx(ctx, &s.config.WebhooksConfig.BeforeUpdateUserInfoEx, req); err != nil { return nil, err } data := convert.UserPb2DBMapEx(req.UserInfo) - if err = s.UpdateByMap(ctx, req.UserInfo.UserID, data); err != nil { + if err = s.db.UpdateByMap(ctx, req.UserInfo.UserID, data); err != nil { return nil, err } - _ = s.friendNotificationSender.UserInfoUpdatedNotification(ctx, req.UserInfo.UserID) + s.friendNotificationSender.UserInfoUpdatedNotification(ctx, req.UserInfo.UserID) friends, err := s.friendRpcClient.GetFriendIDs(ctx, req.UserInfo.UserID) if err != nil { return nil, err @@ -169,9 +181,7 @@ func (s *userServer) UpdateUserInfoEx(ctx context.Context, req *pbuser.UpdateUse for _, friendID := range friends { s.friendNotificationSender.FriendInfoUpdatedNotification(ctx, req.UserInfo.UserID, friendID) } - if err := CallbackAfterUpdateUserInfoEx(ctx, s.config, req); err != nil { - return nil, err - } + s.webhookAfterUpdateUserInfoEx(ctx, &s.config.WebhooksConfig.AfterUpdateUserInfoEx, req) if err := s.groupRpcClient.NotificationUserInfoUpdate(ctx, req.UserInfo.UserID); err != nil { return nil, err } @@ -179,12 +189,12 @@ func (s *userServer) UpdateUserInfoEx(ctx context.Context, req *pbuser.UpdateUse } func (s *userServer) SetGlobalRecvMessageOpt(ctx context.Context, req *pbuser.SetGlobalRecvMessageOptReq) (resp *pbuser.SetGlobalRecvMessageOptResp, err error) { resp = &pbuser.SetGlobalRecvMessageOptResp{} - if _, err := s.FindWithError(ctx, []string{req.UserID}); err != nil { + if _, err := s.db.FindWithError(ctx, []string{req.UserID}); err != nil { return nil, err } m := make(map[string]any, 1) m["global_recv_msg_opt"] = req.GlobalRecvMsgOpt - if err := s.UpdateByMap(ctx, req.UserID, m); err != nil { + if err := s.db.UpdateByMap(ctx, req.UserID, m); err != nil { return nil, err } s.friendNotificationSender.UserInfoUpdatedNotification(ctx, req.UserID) @@ -193,14 +203,14 @@ func (s *userServer) SetGlobalRecvMessageOpt(ctx context.Context, req *pbuser.Se func (s *userServer) AccountCheck(ctx context.Context, req *pbuser.AccountCheckReq) (resp *pbuser.AccountCheckResp, err error) { resp = &pbuser.AccountCheckResp{} - if utils.Duplicate(req.CheckUserIDs) { - return nil, errs.ErrArgs.Wrap("userID repeated") + if datautil.Duplicate(req.CheckUserIDs) { + return nil, errs.ErrArgs.WrapMsg("userID repeated") } - err = authverify.CheckAdmin(ctx, s.config) + err = authverify.CheckAdmin(ctx, s.config.Share.IMAdminUserID) if err != nil { return nil, err } - users, err := s.Find(ctx, req.CheckUserIDs) + users, err := s.db.Find(ctx, req.CheckUserIDs) if err != nil { return nil, err } @@ -222,13 +232,13 @@ func (s *userServer) AccountCheck(ctx context.Context, req *pbuser.AccountCheckR func (s *userServer) GetPaginationUsers(ctx context.Context, req *pbuser.GetPaginationUsersReq) (resp *pbuser.GetPaginationUsersResp, err error) { if req.UserID == "" && req.NickName == "" { - total, users, err := s.PageFindUser(ctx, constant.IMOrdinaryUser, constant.AppOrdinaryUsers, req.Pagination) + total, users, err := s.db.PageFindUser(ctx, constant.IMOrdinaryUser, constant.AppOrdinaryUsers, req.Pagination) if err != nil { return nil, err } return &pbuser.GetPaginationUsersResp{Total: int32(total), Users: convert.UsersDB2Pb(users)}, err } else { - total, users, err := s.PageFindUserWithKeyword(ctx, constant.IMOrdinaryUser, constant.AppOrdinaryUsers, req.UserID, req.NickName, req.Pagination) + total, users, err := s.db.PageFindUserWithKeyword(ctx, constant.IMOrdinaryUser, constant.AppOrdinaryUsers, req.UserID, req.NickName, req.Pagination) if err != nil { return nil, err } @@ -241,33 +251,33 @@ func (s *userServer) GetPaginationUsers(ctx context.Context, req *pbuser.GetPagi func (s *userServer) UserRegister(ctx context.Context, req *pbuser.UserRegisterReq) (resp *pbuser.UserRegisterResp, err error) { resp = &pbuser.UserRegisterResp{} if len(req.Users) == 0 { - return nil, errs.ErrArgs.Wrap("users is empty") + return nil, errs.ErrArgs.WrapMsg("users is empty") } - if req.Secret != s.config.Secret { - log.ZDebug(ctx, "UserRegister", s.config.Secret, req.Secret) - return nil, errs.ErrNoPermission.Wrap("secret invalid") + if req.Secret != s.config.Share.Secret { + log.ZDebug(ctx, "UserRegister", s.config.Share.Secret, req.Secret) + return nil, errs.ErrNoPermission.WrapMsg("secret invalid") } - if utils.DuplicateAny(req.Users, func(e *sdkws.UserInfo) string { return e.UserID }) { - return nil, errs.ErrArgs.Wrap("userID repeated") + if datautil.DuplicateAny(req.Users, func(e *sdkws.UserInfo) string { return e.UserID }) { + return nil, errs.ErrArgs.WrapMsg("userID repeated") } userIDs := make([]string, 0) for _, user := range req.Users { if user.UserID == "" { - return nil, errs.ErrArgs.Wrap("userID is empty") + return nil, errs.ErrArgs.WrapMsg("userID is empty") } if strings.Contains(user.UserID, ":") { - return nil, errs.ErrArgs.Wrap("userID contains ':' is invalid userID") + return nil, errs.ErrArgs.WrapMsg("userID contains ':' is invalid userID") } userIDs = append(userIDs, user.UserID) } - exist, err := s.IsExist(ctx, userIDs) + exist, err := s.db.IsExist(ctx, userIDs) if err != nil { return nil, err } if exist { - return nil, errs.ErrRegisteredAlready.Wrap("userID registered already") + return nil, servererrs.ErrRegisteredAlready.WrapMsg("userID registered already") } - if err := CallbackBeforeUserRegister(ctx, s.config, req); err != nil { + if err := s.webhookBeforeUserRegister(ctx, &s.config.WebhooksConfig.BeforeUserRegister, req); err != nil { return nil, err } now := time.Now() @@ -283,18 +293,16 @@ func (s *userServer) UserRegister(ctx context.Context, req *pbuser.UserRegisterR GlobalRecvMsgOpt: user.GlobalRecvMsgOpt, }) } - if err := s.Create(ctx, users); err != nil { + if err := s.db.Create(ctx, users); err != nil { return nil, err } - if err := CallbackAfterUserRegister(ctx, s.config, req); err != nil { - return nil, err - } + s.webhookAfterUserRegister(ctx, &s.config.WebhooksConfig.AfterUserRegister, req) return resp, nil } func (s *userServer) GetGlobalRecvMessageOpt(ctx context.Context, req *pbuser.GetGlobalRecvMessageOptReq) (resp *pbuser.GetGlobalRecvMessageOptResp, err error) { - user, err := s.FindWithError(ctx, []string{req.UserID}) + user, err := s.db.FindWithError(ctx, []string{req.UserID}) if err != nil { return nil, err } @@ -303,7 +311,7 @@ func (s *userServer) GetGlobalRecvMessageOpt(ctx context.Context, req *pbuser.Ge // GetAllUserID Get user account by page. func (s *userServer) GetAllUserID(ctx context.Context, req *pbuser.GetAllUserIDReq) (resp *pbuser.GetAllUserIDResp, err error) { - total, userIDs, err := s.UserDatabase.GetAllUserID(ctx, req.Pagination) + total, userIDs, err := s.db.GetAllUserID(ctx, req.Pagination) if err != nil { return nil, err } @@ -313,18 +321,18 @@ func (s *userServer) GetAllUserID(ctx context.Context, req *pbuser.GetAllUserIDR // SubscribeOrCancelUsersStatus Subscribe online or cancel online users. func (s *userServer) SubscribeOrCancelUsersStatus(ctx context.Context, req *pbuser.SubscribeOrCancelUsersStatusReq) (resp *pbuser.SubscribeOrCancelUsersStatusResp, err error) { if req.Genre == constant.SubscriberUser { - err = s.UserDatabase.SubscribeUsersStatus(ctx, req.UserID, req.UserIDs) + err = s.db.SubscribeUsersStatus(ctx, req.UserID, req.UserIDs) if err != nil { return nil, err } var status []*pbuser.OnlineStatus - status, err = s.UserDatabase.GetUserStatus(ctx, req.UserIDs) + status, err = s.db.GetUserStatus(ctx, req.UserIDs) if err != nil { return nil, err } return &pbuser.SubscribeOrCancelUsersStatusResp{StatusList: status}, nil } else if req.Genre == constant.Unsubscribe { - err = s.UserDatabase.UnsubscribeUsersStatus(ctx, req.UserID, req.UserIDs) + err = s.db.UnsubscribeUsersStatus(ctx, req.UserID, req.UserIDs) if err != nil { return nil, err } @@ -335,7 +343,7 @@ func (s *userServer) SubscribeOrCancelUsersStatus(ctx context.Context, req *pbus // GetUserStatus Get the online status of the user. func (s *userServer) GetUserStatus(ctx context.Context, req *pbuser.GetUserStatusReq) (resp *pbuser.GetUserStatusResp, err error) { - onlineStatusList, err := s.UserDatabase.GetUserStatus(ctx, req.UserIDs) + onlineStatusList, err := s.db.GetUserStatus(ctx, req.UserIDs) if err != nil { return nil, err } @@ -345,11 +353,11 @@ func (s *userServer) GetUserStatus(ctx context.Context, req *pbuser.GetUserStatu // SetUserStatus Synchronize user's online status. func (s *userServer) SetUserStatus(ctx context.Context, req *pbuser.SetUserStatusReq) (resp *pbuser.SetUserStatusResp, err error) { - err = s.UserDatabase.SetUserStatus(ctx, req.UserID, req.Status, req.PlatformID) + err = s.db.SetUserStatus(ctx, req.UserID, req.Status, req.PlatformID) if err != nil { return nil, err } - list, err := s.UserDatabase.GetSubscribedList(ctx, req.UserID) + list, err := s.db.GetSubscribedList(ctx, req.UserID) if err != nil { return nil, err } @@ -369,11 +377,11 @@ func (s *userServer) SetUserStatus(ctx context.Context, req *pbuser.SetUserStatu // GetSubscribeUsersStatus Get the online status of subscribers. func (s *userServer) GetSubscribeUsersStatus(ctx context.Context, req *pbuser.GetSubscribeUsersStatusReq) (*pbuser.GetSubscribeUsersStatusResp, error) { - userList, err := s.UserDatabase.GetAllSubscribeList(ctx, req.UserID) + userList, err := s.db.GetAllSubscribeList(ctx, req.UserID) if err != nil { return nil, err } - onlineStatusList, err := s.UserDatabase.GetUserStatus(ctx, userList) + onlineStatusList, err := s.db.GetUserStatus(ctx, userList) if err != nil { return nil, err } @@ -382,7 +390,7 @@ func (s *userServer) GetSubscribeUsersStatus(ctx context.Context, // ProcessUserCommandAdd user general function add. func (s *userServer) ProcessUserCommandAdd(ctx context.Context, req *pbuser.ProcessUserCommandAddReq) (*pbuser.ProcessUserCommandAddResp, error) { - err := authverify.CheckAccessV3(ctx, req.UserID, s.config) + err := authverify.CheckAccessV3(ctx, req.UserID, s.config.Share.IMAdminUserID) if err != nil { return nil, err } @@ -395,8 +403,8 @@ func (s *userServer) ProcessUserCommandAdd(ctx context.Context, req *pbuser.Proc if req.Ex != nil { value = req.Ex.Value } - // Assuming you have a method in s.UserDatabase to add a user command - err = s.UserDatabase.AddUserCommand(ctx, req.UserID, req.Type, req.Uuid, value, ex) + // Assuming you have a method in s.db to add a user command + err = s.db.AddUserCommand(ctx, req.UserID, req.Type, req.Uuid, value, ex) if err != nil { return nil, err } @@ -404,21 +412,18 @@ func (s *userServer) ProcessUserCommandAdd(ctx context.Context, req *pbuser.Proc FromUserID: req.UserID, ToUserID: req.UserID, } - err = s.userNotificationSender.UserCommandAddNotification(ctx, tips) - if err != nil { - return nil, err - } + s.userNotificationSender.UserCommandAddNotification(ctx, tips) return &pbuser.ProcessUserCommandAddResp{}, nil } // ProcessUserCommandDelete user general function delete. func (s *userServer) ProcessUserCommandDelete(ctx context.Context, req *pbuser.ProcessUserCommandDeleteReq) (*pbuser.ProcessUserCommandDeleteResp, error) { - err := authverify.CheckAccessV3(ctx, req.UserID, s.config) + err := authverify.CheckAccessV3(ctx, req.UserID, s.config.Share.IMAdminUserID) if err != nil { return nil, err } - err = s.UserDatabase.DeleteUserCommand(ctx, req.UserID, req.Type, req.Uuid) + err = s.db.DeleteUserCommand(ctx, req.UserID, req.Type, req.Uuid) if err != nil { return nil, err } @@ -426,17 +431,13 @@ func (s *userServer) ProcessUserCommandDelete(ctx context.Context, req *pbuser.P FromUserID: req.UserID, ToUserID: req.UserID, } - err = s.userNotificationSender.UserCommandDeleteNotification(ctx, tips) - if err != nil { - return nil, err - } - + s.userNotificationSender.UserCommandDeleteNotification(ctx, tips) return &pbuser.ProcessUserCommandDeleteResp{}, nil } // ProcessUserCommandUpdate user general function update. func (s *userServer) ProcessUserCommandUpdate(ctx context.Context, req *pbuser.ProcessUserCommandUpdateReq) (*pbuser.ProcessUserCommandUpdateResp, error) { - err := authverify.CheckAccessV3(ctx, req.UserID, s.config) + err := authverify.CheckAccessV3(ctx, req.UserID, s.config.Share.IMAdminUserID) if err != nil { return nil, err } @@ -450,8 +451,8 @@ func (s *userServer) ProcessUserCommandUpdate(ctx context.Context, req *pbuser.P val["ex"] = req.Ex.Value } - // Assuming you have a method in s.UserDatabase to update a user command - err = s.UserDatabase.UpdateUserCommand(ctx, req.UserID, req.Type, req.Uuid, val) + // Assuming you have a method in s.db to update a user command + err = s.db.UpdateUserCommand(ctx, req.UserID, req.Type, req.Uuid, val) if err != nil { return nil, err } @@ -459,21 +460,18 @@ func (s *userServer) ProcessUserCommandUpdate(ctx context.Context, req *pbuser.P FromUserID: req.UserID, ToUserID: req.UserID, } - err = s.userNotificationSender.UserCommandUpdateNotification(ctx, tips) - if err != nil { - return nil, err - } + s.userNotificationSender.UserCommandUpdateNotification(ctx, tips) return &pbuser.ProcessUserCommandUpdateResp{}, nil } func (s *userServer) ProcessUserCommandGet(ctx context.Context, req *pbuser.ProcessUserCommandGetReq) (*pbuser.ProcessUserCommandGetResp, error) { - err := authverify.CheckAccessV3(ctx, req.UserID, s.config) + err := authverify.CheckAccessV3(ctx, req.UserID, s.config.Share.IMAdminUserID) if err != nil { return nil, err } // Fetch user commands from the database - commands, err := s.UserDatabase.GetUserCommands(ctx, req.UserID, req.Type) + commands, err := s.db.GetUserCommands(ctx, req.UserID, req.Type) if err != nil { return nil, err } @@ -497,12 +495,12 @@ func (s *userServer) ProcessUserCommandGet(ctx context.Context, req *pbuser.Proc } func (s *userServer) ProcessUserCommandGetAll(ctx context.Context, req *pbuser.ProcessUserCommandGetAllReq) (*pbuser.ProcessUserCommandGetAllResp, error) { - err := authverify.CheckAccessV3(ctx, req.UserID, s.config) + err := authverify.CheckAccessV3(ctx, req.UserID, s.config.Share.IMAdminUserID) if err != nil { return nil, err } // Fetch user commands from the database - commands, err := s.UserDatabase.GetAllUserCommands(ctx, req.UserID) + commands, err := s.db.GetAllUserCommands(ctx, req.UserID) if err != nil { return nil, err } @@ -526,14 +524,14 @@ func (s *userServer) ProcessUserCommandGetAll(ctx context.Context, req *pbuser.P } func (s *userServer) AddNotificationAccount(ctx context.Context, req *pbuser.AddNotificationAccountReq) (*pbuser.AddNotificationAccountResp, error) { - if err := authverify.CheckIMAdmin(ctx, s.config); err != nil { + if err := authverify.CheckAdmin(ctx, s.config.Share.IMAdminUserID); err != nil { return nil, err } if req.UserID == "" { for i := 0; i < 20; i++ { userId := s.genUserID() - _, err := s.UserDatabase.FindWithError(ctx, []string{userId}) + _, err := s.db.FindWithError(ctx, []string{userId}) if err == nil { continue } @@ -541,12 +539,12 @@ func (s *userServer) AddNotificationAccount(ctx context.Context, req *pbuser.Add break } if req.UserID == "" { - return nil, errs.ErrInternalServer.Wrap("gen user id failed") + return nil, errs.ErrInternalServer.WrapMsg("gen user id failed") } } else { - _, err := s.UserDatabase.FindWithError(ctx, []string{req.UserID}) + _, err := s.db.FindWithError(ctx, []string{req.UserID}) if err == nil { - return nil, errs.ErrArgs.Wrap("userID is used") + return nil, errs.ErrArgs.WrapMsg("userID is used") } } @@ -557,7 +555,7 @@ func (s *userServer) AddNotificationAccount(ctx context.Context, req *pbuser.Add CreateTime: time.Now(), AppMangerLevel: constant.AppNotificationAdmin, } - if err := s.UserDatabase.Create(ctx, []*tablerelation.UserModel{user}); err != nil { + if err := s.db.Create(ctx, []*tablerelation.UserModel{user}); err != nil { return nil, err } @@ -569,11 +567,11 @@ func (s *userServer) AddNotificationAccount(ctx context.Context, req *pbuser.Add } func (s *userServer) UpdateNotificationAccountInfo(ctx context.Context, req *pbuser.UpdateNotificationAccountInfoReq) (*pbuser.UpdateNotificationAccountInfoResp, error) { - if err := authverify.CheckIMAdmin(ctx, s.config); err != nil { + if err := authverify.CheckAdmin(ctx, s.config.Share.IMAdminUserID); err != nil { return nil, err } - if _, err := s.UserDatabase.FindWithError(ctx, []string{req.UserID}); err != nil { + if _, err := s.db.FindWithError(ctx, []string{req.UserID}); err != nil { return nil, errs.ErrArgs.Wrap() } @@ -587,7 +585,7 @@ func (s *userServer) UpdateNotificationAccountInfo(ctx context.Context, req *pbu user["face_url"] = req.FaceURL } - if err := s.UserDatabase.UpdateByMap(ctx, req.UserID, user); err != nil { + if err := s.db.UpdateByMap(ctx, req.UserID, user); err != nil { return nil, err } @@ -596,7 +594,7 @@ func (s *userServer) UpdateNotificationAccountInfo(ctx context.Context, req *pbu func (s *userServer) SearchNotificationAccount(ctx context.Context, req *pbuser.SearchNotificationAccountReq) (*pbuser.SearchNotificationAccountResp, error) { // Check if user is an admin - if err := authverify.CheckIMAdmin(ctx, s.config); err != nil { + if err := authverify.CheckAdmin(ctx, s.config.Share.IMAdminUserID); err != nil { return nil, err } @@ -606,7 +604,7 @@ func (s *userServer) SearchNotificationAccount(ctx context.Context, req *pbuser. // If a keyword is provided in the request if req.Keyword != "" { // Find users by keyword - users, err = s.UserDatabase.Find(ctx, []string{req.Keyword}) + users, err = s.db.Find(ctx, []string{req.Keyword}) if err != nil { return nil, err } @@ -618,7 +616,7 @@ func (s *userServer) SearchNotificationAccount(ctx context.Context, req *pbuser. } // Find users by nickname if no users found by keyword - users, err = s.UserDatabase.FindByNickname(ctx, req.Keyword) + users, err = s.db.FindByNickname(ctx, req.Keyword) if err != nil { return nil, err } @@ -627,7 +625,7 @@ func (s *userServer) SearchNotificationAccount(ctx context.Context, req *pbuser. } // If no keyword, find users with notification settings - users, err = s.UserDatabase.FindNotification(ctx, constant.AppNotificationAdmin) + users, err = s.db.FindNotification(ctx, constant.AppNotificationAdmin) if err != nil { return nil, err } @@ -638,17 +636,17 @@ func (s *userServer) SearchNotificationAccount(ctx context.Context, req *pbuser. func (s *userServer) GetNotificationAccount(ctx context.Context, req *pbuser.GetNotificationAccountReq) (*pbuser.GetNotificationAccountResp, error) { if req.UserID == "" { - return nil, errs.ErrArgs.Wrap("userID is empty") + return nil, errs.ErrArgs.WrapMsg("userID is empty") } - user, err := s.UserDatabase.GetUserByID(ctx, req.UserID) + user, err := s.db.GetUserByID(ctx, req.UserID) if err != nil { - return nil, errs.ErrUserIDNotFound.Wrap() + return nil, servererrs.ErrUserIDNotFound.Wrap() } if user.AppMangerLevel == constant.AppAdmin || user.AppMangerLevel == constant.AppNotificationAdmin { return &pbuser.GetNotificationAccountResp{}, nil } - return nil, errs.ErrNoPermission.Wrap("notification messages cannot be sent for this ID") + return nil, errs.ErrNoPermission.WrapMsg("notification messages cannot be sent for this ID") } func (s *userServer) genUserID() string { @@ -670,7 +668,7 @@ func (s *userServer) userModelToResp(users []*relation.UserModel, pagination pag accounts := make([]*pbuser.NotificationAccountInfo, 0) var total int64 for _, v := range users { - if v.AppMangerLevel == constant.AppNotificationAdmin && !utils.IsContain(v.UserID, s.config.IMAdmin.UserID) { + if v.AppMangerLevel == constant.AppNotificationAdmin && !datautil.Contain(v.UserID, s.config.Share.IMAdminUserID...) { temp := &pbuser.NotificationAccountInfo{ UserID: v.UserID, FaceURL: v.FaceURL, @@ -681,7 +679,7 @@ func (s *userServer) userModelToResp(users []*relation.UserModel, pagination pag } } - notificationAccounts := utils.Paginate(accounts, int(pagination.GetPageNumber()), int(pagination.GetShowNumber())) + notificationAccounts := datautil.Paginate(accounts, int(pagination.GetPageNumber()), int(pagination.GetShowNumber())) return &pbuser.SearchNotificationAccountResp{Total: total, NotificationAccounts: notificationAccounts} } diff --git a/internal/tools/conversation.go b/internal/tools/conversation.go index b555a33614..3e2a88ffd6 100644 --- a/internal/tools/conversation.go +++ b/internal/tools/conversation.go @@ -19,14 +19,15 @@ import ( "math/rand" "time" - "github.com/OpenIMSDK/protocol/sdkws" - "github.com/OpenIMSDK/tools/log" - "github.com/OpenIMSDK/tools/mcontext" - "github.com/OpenIMSDK/tools/utils" "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" + "github.com/openimsdk/protocol/sdkws" + "github.com/openimsdk/tools/log" + "github.com/openimsdk/tools/mcontext" + "github.com/openimsdk/tools/utils/idutil" + "github.com/openimsdk/tools/utils/stringutil" ) -//func (c *MsgTool) ConversationsDestructMsgs() { +// func (c *MsgTool) ConversationsDestructMsgs() { // log.ZInfo(context.Background(), "start msg destruct cron task") // ctx := mcontext.NewCtx(utils.GetSelfFuncName()) // conversations, err := c.conversationDatabase.GetConversationIDsNeedDestruct(ctx) @@ -70,7 +71,7 @@ import ( func (c *MsgTool) ConversationsDestructMsgs() { log.ZInfo(context.Background(), "start msg destruct cron task") - ctx := mcontext.NewCtx(utils.GetSelfFuncName()) + ctx := mcontext.NewCtx(stringutil.GetSelfFuncName()) num, err := c.conversationDatabase.GetAllConversationIDsNumber(ctx) if err != nil { log.ZError(ctx, "GetAllConversationIDsNumber failed", err) @@ -117,7 +118,7 @@ func (c *MsgTool) ConversationsDestructMsgs() { } } for _, conversation := range temp { - ctx = mcontext.NewCtx(utils.GetSelfFuncName() + "-" + utils.OperationIDGenerator() + "-" + conversation.ConversationID + "-" + conversation.OwnerUserID) + ctx = mcontext.NewCtx(stringutil.GetSelfFuncName() + "-" + idutil.OperationIDGenerator() + "-" + conversation.ConversationID + "-" + conversation.OwnerUserID) log.ZDebug( ctx, "UserMsgsDestruct", @@ -141,9 +142,7 @@ func (c *MsgTool) ConversationsDestructMsgs() { log.ZError(ctx, "updateUsersConversationField failed", err, "conversationID", conversation.ConversationID, "ownerUserID", conversation.OwnerUserID) continue } - if err := c.msgNotificationSender.UserDeleteMsgsNotification(ctx, conversation.OwnerUserID, conversation.ConversationID, seqs); err != nil { - log.ZError(ctx, "userDeleteMsgsNotification failed", err, "conversationID", conversation.ConversationID, "ownerUserID", conversation.OwnerUserID) - } + c.msgNotificationSender.UserDeleteMsgsNotification(ctx, conversation.OwnerUserID, conversation.ConversationID, seqs) } } } diff --git a/internal/tools/cron_task.go b/internal/tools/cron_task.go index 7535e9b96d..82ce95eda9 100644 --- a/internal/tools/cron_task.go +++ b/internal/tools/cron_task.go @@ -16,46 +16,58 @@ package tools import ( "context" - "fmt" + "github.com/openimsdk/open-im-server/v3/pkg/common/config" + "github.com/openimsdk/tools/db/redisutil" "os" "os/signal" "syscall" "time" - "github.com/OpenIMSDK/tools/errs" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" + "github.com/openimsdk/tools/errs" + "github.com/openimsdk/tools/log" "github.com/redis/go-redis/v9" "github.com/robfig/cron/v3" ) -func StartTask(config *config.GlobalConfig) error { - fmt.Println("cron task start, config", config.ChatRecordsClearTime) +type CronTaskConfig struct { + CronTask config.CronTask + RedisConfig config.Redis + MongodbConfig config.Mongo + ZookeeperConfig config.ZooKeeper + Share config.Share + KafkaConfig config.Kafka +} + +func Start(ctx context.Context, config *CronTaskConfig) error { + + log.CInfo(ctx, "CRON-TASK server is initializing", "chatRecordsClearTime", + config.CronTask.ChatRecordsClearTime, "msgDestructTime", config.CronTask.MsgDestructTime) - msgTool, err := InitMsgTool(config) + msgTool, err := InitMsgTool(ctx, config) if err != nil { return err } msgTool.convertTools() - rdb, err := cache.NewRedis(config) + rdb, err := redisutil.NewRedisClient(ctx, config.RedisConfig.Build()) if err != nil { return err } // register cron tasks var crontab = cron.New() - fmt.Printf("Start chatRecordsClearTime cron task, cron config: %s\n", config.ChatRecordsClearTime) - _, err = crontab.AddFunc(config.ChatRecordsClearTime, cronWrapFunc(config, rdb, "cron_clear_msg_and_fix_seq", msgTool.AllConversationClearMsgAndFixSeq)) + + _, err = crontab.AddFunc(config.CronTask.ChatRecordsClearTime, + cronWrapFunc(config, rdb, "cron_clear_msg_and_fix_seq", msgTool.AllConversationClearMsgAndFixSeq)) if err != nil { return errs.Wrap(err) } - fmt.Printf("Start msgDestruct cron task, cron config: %s\n", config.MsgDestructTime) - _, err = crontab.AddFunc(config.MsgDestructTime, cronWrapFunc(config, rdb, "cron_conversations_destruct_msgs", msgTool.ConversationsDestructMsgs)) + _, err = crontab.AddFunc(config.CronTask.MsgDestructTime, + cronWrapFunc(config, rdb, "cron_conversations_destruct_msgs", msgTool.ConversationsDestructMsgs)) if err != nil { - return errs.Wrap(err, "cron_conversations_destruct_msgs") + return errs.WrapMsg(err, "cron_conversations_destruct_msgs") } // start crontab @@ -66,10 +78,10 @@ func StartTask(config *config.GlobalConfig) error { <-sigs // stop crontab, Wait for the running task to exit. - ctx := crontab.Stop() + cronCtx := crontab.Stop() select { - case <-ctx.Done(): + case <-cronCtx.Done(): // graceful exit case <-time.After(15 * time.Second): @@ -91,8 +103,8 @@ func netlock(rdb redis.UniversalClient, key string, ttl time.Duration) bool { return ok } -func cronWrapFunc(config *config.GlobalConfig, rdb redis.UniversalClient, key string, fn func()) func() { - enableCronLocker := config.EnableCronLocker +func cronWrapFunc(config *CronTaskConfig, rdb redis.UniversalClient, key string, fn func()) func() { + enableCronLocker := config.CronTask.EnableCronLocker return func() { // if don't enable cron-locker, call fn directly. if !enableCronLocker { diff --git a/internal/tools/cron_task_test.go b/internal/tools/cron_task_test.go index 17346b1c51..0bea8a4361 100644 --- a/internal/tools/cron_task_test.go +++ b/internal/tools/cron_task_test.go @@ -15,22 +15,11 @@ package tools import ( - "flag" - "fmt" - "math/rand" - "os" - "sync" "testing" "time" - "github.com/OpenIMSDK/tools/errs" - "gopkg.in/yaml.v3" - "github.com/redis/go-redis/v9" - "github.com/robfig/cron/v3" "github.com/stretchr/testify/assert" - - "github.com/openimsdk/open-im-server/v3/pkg/common/config" ) func TestDisLock(t *testing.T) { @@ -51,74 +40,74 @@ func TestDisLock(t *testing.T) { assert.Equal(t, true, netlock(rdb, "cron-2", 2*time.Second)) } -func TestCronWrapFunc(t *testing.T) { - rdb := redis.NewClient(&redis.Options{}) - defer rdb.Close() - - once := sync.Once{} - done := make(chan struct{}, 1) - cb := func() { - once.Do(func() { - close(done) - }) - } - - start := time.Now() - key := fmt.Sprintf("cron-%v", rand.Int31()) - crontab := cron.New(cron.WithSeconds()) - crontab.AddFunc("*/1 * * * * *", cronWrapFunc(config.NewGlobalConfig(), rdb, key, cb)) - crontab.Start() - <-done - - dur := time.Since(start) - assert.LessOrEqual(t, dur.Seconds(), float64(2*time.Second)) - crontab.Stop() -} - -func TestCronWrapFuncWithNetlock(t *testing.T) { - conf, err := initCfg() - if err != nil { - panic(err) - } - conf.EnableCronLocker = true - rdb := redis.NewClient(&redis.Options{}) - defer rdb.Close() - - done := make(chan string, 10) - - crontab := cron.New(cron.WithSeconds()) - - key := fmt.Sprintf("cron-%v", rand.Int31()) - crontab.AddFunc("*/1 * * * * *", cronWrapFunc(conf, rdb, key, func() { - done <- "host1" - })) - crontab.AddFunc("*/1 * * * * *", cronWrapFunc(conf, rdb, key, func() { - done <- "host2" - })) - crontab.Start() - - time.Sleep(12 * time.Second) - // the ttl of netlock is 5s, so expected value is 2. - assert.Equal(t, len(done), 2) - - crontab.Stop() -} - -func initCfg() (*config.GlobalConfig, error) { - const ( - defaultCfgPath = "../../../../../config/config.yaml" - ) - - cfgPath := flag.String("c", defaultCfgPath, "Path to the configuration file") - data, err := os.ReadFile(*cfgPath) - if err != nil { - return nil, errs.Wrap(err, "ReadFile unmarshal failed") - } - - conf := config.NewGlobalConfig() - err = yaml.Unmarshal(data, &conf) - if err != nil { - return nil, errs.Wrap(err, "InitConfig unmarshal failed") - } - return conf, nil -} +//func TestCronWrapFunc(t *testing.T) { +// rdb := redis.NewClient(&redis.Options{}) +// defer rdb.Close() +// +// once := sync.Once{} +// done := make(chan struct{}, 1) +// cb := func() { +// once.Do(func() { +// close(done) +// }) +// } +// +// start := time.Now() +// key := fmt.Sprintf("cron-%v", rand.Int31()) +// crontab := cron.New(cron.WithSeconds()) +// crontab.AddFunc("*/1 * * * * *", cronWrapFunc(config.NewGlobalConfig(), rdb, key, cb)) +// crontab.Start() +// <-done +// +// dur := time.Since(start) +// assert.LessOrEqual(t, dur.Seconds(), float64(2*time.Second)) +// crontab.Stop() +//} +// +//func TestCronWrapFuncWithNetlock(t *testing.T) { +// conf, err := initCfg() +// if err != nil { +// panic(err) +// } +// conf.EnableCronLocker = true +// rdb := redis.NewClient(&redis.Options{}) +// defer rdb.Close() +// +// done := make(chan string, 10) +// +// crontab := cron.New(cron.WithSeconds()) +// +// key := fmt.Sprintf("cron-%v", rand.Int31()) +// crontab.AddFunc("*/1 * * * * *", cronWrapFunc(conf, rdb, key, func() { +// done <- "host1" +// })) +// crontab.AddFunc("*/1 * * * * *", cronWrapFunc(conf, rdb, key, func() { +// done <- "host2" +// })) +// crontab.Start() +// +// time.Sleep(12 * time.Second) +// // the ttl of netlock is 5s, so expected value is 2. +// assert.Equal(t, len(done), 2) +// +// crontab.Stop() +//} +// +//func initCfg() (*config.GlobalConfig, error) { +// const ( +// defaultCfgPath = "../../../../../config/config.yaml" +// ) +// +// cfgPath := flag.String("c", defaultCfgPath, "Path to the configuration file") +// data, err := os.ReadFile(*cfgPath) +// if err != nil { +// return nil, errs.WrapMsg(err, "ReadFile unmarshal failed") +// } +// +// conf := config.NewGlobalConfig() +// err = yaml.Unmarshal(data, &conf) +// if err != nil { +// return nil, errs.WrapMsg(err, "InitConfig unmarshal failed") +// } +// return conf, nil +//} diff --git a/internal/tools/msg.go b/internal/tools/msg.go index 67c3895cb2..42af1efdc2 100644 --- a/internal/tools/msg.go +++ b/internal/tools/msg.go @@ -17,27 +17,18 @@ package tools import ( "context" "fmt" + "github.com/openimsdk/open-im-server/v3/internal/rpc/msg" "math" "math/rand" - "github.com/OpenIMSDK/protocol/sdkws" - "github.com/OpenIMSDK/tools/errs" - "github.com/OpenIMSDK/tools/log" - "github.com/OpenIMSDK/tools/mcontext" - "github.com/OpenIMSDK/tools/mw" - "github.com/OpenIMSDK/tools/tx" - "github.com/OpenIMSDK/tools/utils" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/mgo" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/unrelation" - kdisc "github.com/openimsdk/open-im-server/v3/pkg/common/discoveryregister" - "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" - "github.com/openimsdk/open-im-server/v3/pkg/rpcclient/notification" + "github.com/openimsdk/open-im-server/v3/pkg/util/conversationutil" + "github.com/openimsdk/protocol/sdkws" + "github.com/openimsdk/tools/errs" + "github.com/openimsdk/tools/log" + "github.com/openimsdk/tools/mcontext" + "github.com/openimsdk/tools/utils/stringutil" "github.com/redis/go-redis/v9" - "google.golang.org/grpc" - "google.golang.org/grpc/credentials/insecure" ) type MsgTool struct { @@ -45,13 +36,13 @@ type MsgTool struct { conversationDatabase controller.ConversationDatabase userDatabase controller.UserDatabase groupDatabase controller.GroupDatabase - msgNotificationSender *notification.MsgNotificationSender - Config *config.GlobalConfig + msgNotificationSender *msg.MsgNotificationSender + config *CronTaskConfig } func NewMsgTool(msgDatabase controller.CommonMsgDatabase, userDatabase controller.UserDatabase, groupDatabase controller.GroupDatabase, conversationDatabase controller.ConversationDatabase, - msgNotificationSender *notification.MsgNotificationSender, config *config.GlobalConfig, + msgNotificationSender *msg.MsgNotificationSender, config *CronTaskConfig, ) *MsgTool { return &MsgTool{ msgDatabase: msgDatabase, @@ -59,69 +50,71 @@ func NewMsgTool(msgDatabase controller.CommonMsgDatabase, userDatabase controlle groupDatabase: groupDatabase, conversationDatabase: conversationDatabase, msgNotificationSender: msgNotificationSender, - Config: config, + config: config, } } -func InitMsgTool(config *config.GlobalConfig) (*MsgTool, error) { - rdb, err := cache.NewRedis(config) - if err != nil { - return nil, err - } - mongo, err := unrelation.NewMongo(config) - if err != nil { - return nil, err - } - discov, err := kdisc.NewDiscoveryRegister(config) - if err != nil { - return nil, err - } - discov.AddOption(mw.GrpcClient(), grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithDefaultServiceConfig(fmt.Sprintf(`{"LoadBalancingPolicy": "%s"}`, "round_robin"))) - userDB, err := mgo.NewUserMongo(mongo.GetDatabase(config.Mongo.Database)) - if err != nil { - return nil, err - } - msgDatabase, err := controller.InitCommonMsgDatabase(rdb, mongo.GetDatabase(config.Mongo.Database), config) - if err != nil { - return nil, err - } - userMongoDB := unrelation.NewUserMongoDriver(mongo.GetDatabase(config.Mongo.Database)) - ctxTx := tx.NewMongo(mongo.GetClient()) - userDatabase := controller.NewUserDatabase( - userDB, - cache.NewUserCacheRedis(rdb, userDB, cache.GetDefaultOpt()), - ctxTx, - userMongoDB, - ) - groupDB, err := mgo.NewGroupMongo(mongo.GetDatabase(config.Mongo.Database)) - if err != nil { - return nil, err - } - groupMemberDB, err := mgo.NewGroupMember(mongo.GetDatabase(config.Mongo.Database)) - if err != nil { - return nil, err - } - groupRequestDB, err := mgo.NewGroupRequestMgo(mongo.GetDatabase(config.Mongo.Database)) - if err != nil { - return nil, err - } - conversationDB, err := mgo.NewConversationMongo(mongo.GetDatabase(config.Mongo.Database)) - if err != nil { - return nil, err - } - groupDatabase := controller.NewGroupDatabase(rdb, groupDB, groupMemberDB, groupRequestDB, ctxTx, nil) - conversationDatabase := controller.NewConversationDatabase( - conversationDB, - cache.NewConversationRedis(rdb, cache.GetDefaultOpt(), conversationDB), - ctxTx, - ) - msgRpcClient := rpcclient.NewMessageRpcClient(discov, config) - msgNotificationSender := notification.NewMsgNotificationSender(config, rpcclient.WithRpcClient(&msgRpcClient)) - msgTool := NewMsgTool(msgDatabase, userDatabase, groupDatabase, conversationDatabase, msgNotificationSender, config) - return msgTool, nil +func InitMsgTool(ctx context.Context, config *CronTaskConfig) (*MsgTool, error) { + ch := make(chan int) + <-ch + //mgocli, err := mongoutil.NewMongoDB(ctx, config.MongodbConfig.Build()) + //if err != nil { + // return nil, err + //} + //rdb, err := redisutil.NewRedisClient(ctx, config.RedisConfig.Build()) + //if err != nil { + // return nil, err + //} + //discov, err := kdisc.NewDiscoveryRegister(&config.ZookeeperConfig, &config.Share) + //if err != nil { + // return nil, err + //} + //discov.AddOption(mw.GrpcClient(), grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithDefaultServiceConfig(fmt.Sprintf(`{"LoadBalancingPolicy": "%s"}`, "round_robin"))) + //userDB, err := mgo.NewUserMongo(mgocli.GetDB()) + //if err != nil { + // return nil, err + //} + ////msgDatabase, err := controller.InitCommonMsgDatabase(rdb, mgocli.GetDB(), config) + //if err != nil { + // return nil, err + //} + //userMongoDB := mgo.NewUserMongoDriver(mgocli.GetDB()) + //userDatabase := controller.NewUserDatabase( + // userDB, + // cache.NewUserCacheRedis(rdb, userDB, cache.GetDefaultOpt()), + // mgocli.GetTx(), + // userMongoDB, + //) + //groupDB, err := mgo.NewGroupMongo(mgocli.GetDB()) + //if err != nil { + // return nil, err + //} + //groupMemberDB, err := mgo.NewGroupMember(mgocli.GetDB()) + //if err != nil { + // return nil, err + //} + //groupRequestDB, err := mgo.NewGroupRequestMgo(mgocli.GetDB()) + //if err != nil { + // return nil, err + //} + //conversationDB, err := mgo.NewConversationMongo(mgocli.GetDB()) + //if err != nil { + // return nil, err + //} + //groupDatabase := controller.NewGroupDatabase(rdb, groupDB, groupMemberDB, groupRequestDB, mgocli.GetTx(), nil) + //conversationDatabase := controller.NewConversationDatabase( + // conversationDB, + // cache.NewConversationRedis(rdb, cache.GetDefaultOpt(), conversationDB), + // mgocli.GetTx(), + //) + //msgRpcClient := rpcclient.NewMessageRpcClient(discov, config.Share.RpcRegisterName.Msg) + //msgNotificationSender := notification.NewMsgNotificationSender(config, rpcclient.WithRpcClient(&msgRpcClient)) + //msgTool := NewMsgTool(msgDatabase, userDatabase, groupDatabase, conversationDatabase, msgNotificationSender, config) + //return msgTool, nil + return nil, nil } -//func (c *MsgTool) AllConversationClearMsgAndFixSeq() { +// func (c *MsgTool) AllConversationClearMsgAndFixSeq() { // ctx := mcontext.NewCtx(utils.GetSelfFuncName()) // log.ZInfo(ctx, "============================ start del cron task ============================") // conversationIDs, err := c.conversationDatabase.GetAllConversationIDs(ctx) @@ -137,7 +130,7 @@ func InitMsgTool(config *config.GlobalConfig) (*MsgTool, error) { //} func (c *MsgTool) AllConversationClearMsgAndFixSeq() { - ctx := mcontext.NewCtx(utils.GetSelfFuncName()) + ctx := mcontext.NewCtx(stringutil.GetSelfFuncName()) log.ZInfo(ctx, "============================ start del cron task ============================") num, err := c.conversationDatabase.GetAllConversationIDsNumber(ctx) if err != nil { @@ -179,8 +172,9 @@ func (c *MsgTool) AllConversationClearMsgAndFixSeq() { func (c *MsgTool) ClearConversationsMsg(ctx context.Context, conversationIDs []string) { for _, conversationID := range conversationIDs { - if err := c.msgDatabase.DeleteConversationMsgsAndSetMinSeq(ctx, conversationID, int64(c.Config.RetainChatRecords*24*60*60)); err != nil { - log.ZError(ctx, "DeleteUserSuperGroupMsgsAndSetMinSeq failed", err, "conversationID", conversationID, "DBRetainChatRecords", c.Config.RetainChatRecords) + if err := c.msgDatabase.DeleteConversationMsgsAndSetMinSeq(ctx, conversationID, int64(c.config.CronTask.RetainChatRecords*24*60*60)); err != nil { + log.ZError(ctx, "DeleteUserSuperGroupMsgsAndSetMinSeq failed", err, "conversationID", + conversationID, "DBRetainChatRecords", c.config.CronTask.RetainChatRecords) } if err := c.checkMaxSeq(ctx, conversationID); err != nil { log.ZError(ctx, "fixSeq failed", err, "conversationID", conversationID) @@ -220,7 +214,7 @@ func (c *MsgTool) FixAllSeq(ctx context.Context) error { return err } for _, conversationID := range conversationIDs { - conversationIDs = append(conversationIDs, utils.GetNotificationConversationIDByConversationID(conversationID)) + conversationIDs = append(conversationIDs, conversationutil.GetNotificationConversationIDByConversationID(conversationID)) } for _, conversationID := range conversationIDs { if err := c.checkMaxSeq(ctx, conversationID); err != nil { diff --git a/internal/tools/msg_doc_convert.go b/internal/tools/msg_doc_convert.go index eea1b69e8a..e7625ce215 100644 --- a/internal/tools/msg_doc_convert.go +++ b/internal/tools/msg_doc_convert.go @@ -15,10 +15,10 @@ package tools import ( - "github.com/OpenIMSDK/protocol/constant" - "github.com/OpenIMSDK/tools/log" - "github.com/OpenIMSDK/tools/mcontext" "github.com/openimsdk/open-im-server/v3/pkg/msgprocessor" + "github.com/openimsdk/protocol/constant" + "github.com/openimsdk/tools/log" + "github.com/openimsdk/tools/mcontext" ) func (c *MsgTool) convertTools() { diff --git a/magefile.go b/magefile.go new file mode 100644 index 0000000000..98ffa48f3f --- /dev/null +++ b/magefile.go @@ -0,0 +1,43 @@ +//go:build mage +// +build mage + +package main + +import ( + "github.com/openimsdk/gomake/mageutil" + "os" + "strings" +) + +var Default = Build + +func Build() { + platforms := os.Getenv("PLATFORMS") + if platforms == "" { + platforms = mageutil.DetectPlatform() + } + + for _, platform := range strings.Split(platforms, " ") { + mageutil.CompileForPlatform(platform) + } + + mageutil.PrintGreen("All binaries under cmd and tools were successfully compiled.") +} + +func Start() { + mageutil.InitForSSC() + err := setMaxOpenFiles() + if err != nil { + mageutil.PrintRed("setMaxOpenFiles failed " + err.Error()) + os.Exit(1) + } + mageutil.StartToolsAndServices() +} + +func Stop() { + mageutil.StopAndCheckBinaries() +} + +func Check() { + mageutil.CheckAndReportBinariesStatus() +} diff --git a/magefile_unix.go b/magefile_unix.go new file mode 100644 index 0000000000..ff6b6de4e4 --- /dev/null +++ b/magefile_unix.go @@ -0,0 +1,20 @@ +//go:build mage && !windows +// +build mage,!windows + +package main + +import ( + "github.com/openimsdk/gomake/mageutil" + "syscall" +) + +func setMaxOpenFiles() error { + var rLimit syscall.Rlimit + err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rLimit) + if err != nil { + return err + } + rLimit.Max = uint64(mageutil.MaxFileDescriptors) + rLimit.Cur = uint64(mageutil.MaxFileDescriptors) + return syscall.Setrlimit(syscall.RLIMIT_NOFILE, &rLimit) +} diff --git a/magefile_windows.go b/magefile_windows.go new file mode 100644 index 0000000000..7441bfd9ce --- /dev/null +++ b/magefile_windows.go @@ -0,0 +1,8 @@ +//go:build mage +// +build mage + +package main + +func setMaxOpenFiles() error { + return nil +} diff --git a/pkg/apistruct/doc.go b/pkg/apistruct/doc.go index 2f14045844..6be41c9e53 100644 --- a/pkg/apistruct/doc.go +++ b/pkg/apistruct/doc.go @@ -1,4 +1,4 @@ -// Copyright © 2023 OpenIM. All rights reserved. +// 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. diff --git a/pkg/apistruct/manage.go b/pkg/apistruct/manage.go index f9f542835a..e79b477222 100644 --- a/pkg/apistruct/manage.go +++ b/pkg/apistruct/manage.go @@ -15,7 +15,7 @@ package apistruct import ( - sdkws "github.com/OpenIMSDK/protocol/sdkws" + sdkws "github.com/openimsdk/protocol/sdkws" ) // SendMsg defines the structure for sending messages with various metadata. diff --git a/pkg/apistruct/msg.go b/pkg/apistruct/msg.go index d1ce427fc5..f4a9f884c4 100644 --- a/pkg/apistruct/msg.go +++ b/pkg/apistruct/msg.go @@ -29,6 +29,7 @@ type PictureElem struct { BigPicture PictureBaseInfo `mapstructure:"bigPicture" validate:"required"` SnapshotPicture PictureBaseInfo `mapstructure:"snapshotPicture" validate:"required"` } + type SoundElem struct { UUID string `mapstructure:"uuid"` SoundPath string `mapstructure:"soundPath"` @@ -36,6 +37,7 @@ type SoundElem struct { DataSize int64 `mapstructure:"dataSize"` Duration int64 `mapstructure:"duration" validate:"required,min=1"` } + type VideoElem struct { VideoPath string `mapstructure:"videoPath"` VideoUUID string `mapstructure:"videoUUID"` @@ -50,6 +52,7 @@ type VideoElem struct { SnapshotWidth int32 `mapstructure:"snapshotWidth" validate:"required"` SnapshotHeight int32 `mapstructure:"snapshotHeight" validate:"required"` } + type FileElem struct { FilePath string `mapstructure:"filePath"` UUID string `mapstructure:"uuid"` diff --git a/pkg/authverify/doc.go b/pkg/authverify/doc.go index f9173a7084..14d63a4108 100644 --- a/pkg/authverify/doc.go +++ b/pkg/authverify/doc.go @@ -1,4 +1,4 @@ -// Copyright © 2023 OpenIM. All rights reserved. +// 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. diff --git a/pkg/authverify/token.go b/pkg/authverify/token.go index 8127e08dfd..a96d6de201 100644 --- a/pkg/authverify/token.go +++ b/pkg/authverify/token.go @@ -18,12 +18,10 @@ import ( "context" "fmt" - "github.com/OpenIMSDK/tools/errs" - "github.com/OpenIMSDK/tools/mcontext" - "github.com/OpenIMSDK/tools/tokenverify" - "github.com/OpenIMSDK/tools/utils" "github.com/golang-jwt/jwt/v4" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" + "github.com/openimsdk/open-im-server/v3/pkg/common/servererrs" + "github.com/openimsdk/tools/mcontext" + "github.com/openimsdk/tools/utils/datautil" ) func Secret(secret string) jwt.Keyfunc { @@ -32,63 +30,29 @@ func Secret(secret string) jwt.Keyfunc { } } -func CheckAccessV3(ctx context.Context, ownerUserID string, config *config.GlobalConfig) (err error) { +func CheckAccessV3(ctx context.Context, ownerUserID string, imAdminUserID []string) (err error) { opUserID := mcontext.GetOpUserID(ctx) - if len(config.Manager.UserID) > 0 && utils.IsContain(opUserID, config.Manager.UserID) { - return nil - } - if utils.IsContain(opUserID, config.IMAdmin.UserID) { + if datautil.Contain(opUserID, imAdminUserID...) { return nil } if opUserID == ownerUserID { return nil } - return errs.ErrNoPermission.Wrap("ownerUserID", ownerUserID) + return servererrs.ErrNoPermission.WrapMsg("ownerUserID", ownerUserID) } -func IsAppManagerUid(ctx context.Context, config *config.GlobalConfig) bool { - return (len(config.Manager.UserID) > 0 && utils.IsContain(mcontext.GetOpUserID(ctx), config.Manager.UserID)) || - utils.IsContain(mcontext.GetOpUserID(ctx), config.IMAdmin.UserID) +func IsAppManagerUid(ctx context.Context, imAdminUserID []string) bool { + return datautil.Contain(mcontext.GetOpUserID(ctx), imAdminUserID...) } -func CheckAdmin(ctx context.Context, config *config.GlobalConfig) error { - if len(config.Manager.UserID) > 0 && utils.IsContain(mcontext.GetOpUserID(ctx), config.Manager.UserID) { - return nil - } - if utils.IsContain(mcontext.GetOpUserID(ctx), config.IMAdmin.UserID) { - return nil - } - return errs.ErrNoPermission.Wrap(fmt.Sprintf("user %s is not admin userID", mcontext.GetOpUserID(ctx))) -} +func CheckAdmin(ctx context.Context, imAdminUserID []string) error { -func CheckIMAdmin(ctx context.Context, config *config.GlobalConfig) error { - if utils.IsContain(mcontext.GetOpUserID(ctx), config.IMAdmin.UserID) { - return nil - } - if len(config.Manager.UserID) > 0 && utils.IsContain(mcontext.GetOpUserID(ctx), config.Manager.UserID) { + if datautil.Contain(mcontext.GetOpUserID(ctx), imAdminUserID...) { return nil } - return errs.ErrNoPermission.Wrap(fmt.Sprintf("user %s is not CheckIMAdmin userID", mcontext.GetOpUserID(ctx))) -} - -func ParseRedisInterfaceToken(redisToken any, secret string) (*tokenverify.Claims, error) { - return tokenverify.GetClaimFromToken(string(redisToken.([]uint8)), Secret(secret)) -} - -func IsManagerUserID(opUserID string, config *config.GlobalConfig) bool { - return (len(config.Manager.UserID) > 0 && utils.IsContain(opUserID, config.Manager.UserID)) || utils.IsContain(opUserID, config.IMAdmin.UserID) + return servererrs.ErrNoPermission.WrapMsg(fmt.Sprintf("user %s is not admin userID", mcontext.GetOpUserID(ctx))) } -func WsVerifyToken(token, userID, secret string, platformID int) error { - claim, err := tokenverify.GetClaimFromToken(token, Secret(secret)) - if err != nil { - return err - } - if claim.UserID != userID { - return errs.ErrTokenInvalid.Wrap(fmt.Sprintf("token uid %s != userID %s", claim.UserID, userID)) - } - if claim.PlatformID != platformID { - return errs.ErrTokenInvalid.Wrap(fmt.Sprintf("token platform %d != %d", claim.PlatformID, platformID)) - } - return nil +func IsManagerUserID(opUserID string, imAdminUserID []string) bool { + return datautil.Contain(opUserID, imAdminUserID...) } diff --git a/pkg/callbackstruct/common.go b/pkg/callbackstruct/common.go index c58b9e415e..d6714f5f20 100644 --- a/pkg/callbackstruct/common.go +++ b/pkg/callbackstruct/common.go @@ -14,7 +14,10 @@ package callbackstruct -import "github.com/OpenIMSDK/tools/errs" +import ( + "github.com/openimsdk/open-im-server/v3/pkg/common/servererrs" + "github.com/openimsdk/tools/errs" +) const ( Next = 1 @@ -61,7 +64,7 @@ type CommonCallbackResp struct { } func (c CommonCallbackResp) Parse() error { - if c.ActionCode != errs.NoError || c.NextCode == Next { + if c.ActionCode == servererrs.NoError && c.NextCode == Next { return errs.NewCodeError(int(c.ErrCode), c.ErrMsg).WithDetail(c.ErrDlt) } return nil diff --git a/pkg/callbackstruct/constant.go b/pkg/callbackstruct/constant.go index f3bcf1383d..66e1598cda 100644 --- a/pkg/callbackstruct/constant.go +++ b/pkg/callbackstruct/constant.go @@ -14,47 +14,44 @@ package callbackstruct -const CallbackBeforeInviteJoinGroupCommand = "callbackBeforeInviteJoinGroupCommand" -const CallbackAfterJoinGroupCommand = "callbackAfterJoinGroupCommand" -const CallbackAfterSetGroupInfoCommand = "callbackAfterSetGroupInfoCommand" -const CallbackBeforeSetGroupInfoCommand = "callbackBeforeSetGroupInfoCommand" - -const CallbackAfterRevokeMsgCommand = "callbackBeforeAfterMsgCommand" -const CallbackBeforeAddBlackCommand = "callbackBeforeAddBlackCommand" -const CallbackAfterAddFriendCommand = "callbackAfterAddFriendCommand" -const CallbackBeforeAddFriendAgreeCommand = "callbackBeforeAddFriendAgreeCommand" - -const CallbackAfterDeleteFriendCommand = "callbackAfterDeleteFriendCommand" -const CallbackBeforeImportFriendsCommand = "callbackBeforeImportFriendsCommand" -const CallbackAfterImportFriendsCommand = "callbackAfterImportFriendsCommand" -const CallbackAfterRemoveBlackCommand = "callbackAfterRemoveBlackCommand" - const ( - CallbackQuitGroupCommand = "callbackQuitGroupCommand" - CallbackKillGroupCommand = "callbackKillGroupCommand" - CallbackDisMissGroupCommand = "callbackDisMissGroupCommand" + CallbackBeforeInviteJoinGroupCommand = "callbackBeforeInviteJoinGroupCommand" + CallbackAfterJoinGroupCommand = "callbackAfterJoinGroupCommand" + CallbackAfterSetGroupInfoCommand = "callbackAfterSetGroupInfoCommand" + CallbackBeforeSetGroupInfoCommand = "callbackBeforeSetGroupInfoCommand" + CallbackAfterRevokeMsgCommand = "callbackBeforeAfterMsgCommand" + CallbackBeforeAddBlackCommand = "callbackBeforeAddBlackCommand" + CallbackAfterAddFriendCommand = "callbackAfterAddFriendCommand" + CallbackBeforeAddFriendAgreeCommand = "callbackBeforeAddFriendAgreeCommand" + CallbackAfterDeleteFriendCommand = "callbackAfterDeleteFriendCommand" + CallbackBeforeImportFriendsCommand = "callbackBeforeImportFriendsCommand" + CallbackAfterImportFriendsCommand = "callbackAfterImportFriendsCommand" + CallbackAfterRemoveBlackCommand = "callbackAfterRemoveBlackCommand" + CallbackAfterQuitGroupCommand = "callbackAfterQuitGroupCommand" + CallbackAfterKickGroupCommand = "callbackAfterKickGroupCommand" + CallbackAfterDisMissGroupCommand = "callbackAfterDisMissGroupCommand" CallbackBeforeJoinGroupCommand = "callbackBeforeJoinGroupCommand" - CallbackGroupMsgReadCommand = "callbackGroupMsgReadCommand" - CallbackMsgModifyCommand = "callbackMsgModifyCommand" + CallbackAfterGroupMsgReadCommand = "callbackAfterGroupMsgReadCommand" + CallbackBeforeMsgModifyCommand = "callbackBeforeMsgModifyCommand" CallbackAfterUpdateUserInfoCommand = "callbackAfterUpdateUserInfoCommand" CallbackAfterUpdateUserInfoExCommand = "callbackAfterUpdateUserInfoExCommand" CallbackBeforeUpdateUserInfoExCommand = "callbackBeforeUpdateUserInfoExCommand" CallbackBeforeUserRegisterCommand = "callbackBeforeUserRegisterCommand" CallbackAfterUserRegisterCommand = "callbackAfterUserRegisterCommand" - CallbackAfterTransferGroupOwner = "callbackAfterTransferGroupOwner" - CallbackBeforeSetFriendRemark = "callbackBeforeSetFriendRemark" - CallbackAfterSetFriendRemark = "callbackAfterSetFriendRemark" - CallbackSingleMsgRead = "callbackSingleMsgRead" + CallbackAfterTransferGroupOwnerCommand = "callbackAfterTransferGroupOwnerCommand" + CallbackBeforeSetFriendRemarkCommand = "callbackBeforeSetFriendRemarkCommand" + CallbackAfterSetFriendRemarkCommand = "callbackAfterSetFriendRemarkCommand" + CallbackAfterSingleMsgReadCommand = "callbackAfterSingleMsgReadCommand" CallbackBeforeSendSingleMsgCommand = "callbackBeforeSendSingleMsgCommand" CallbackAfterSendSingleMsgCommand = "callbackAfterSendSingleMsgCommand" CallbackBeforeSendGroupMsgCommand = "callbackBeforeSendGroupMsgCommand" CallbackAfterSendGroupMsgCommand = "callbackAfterSendGroupMsgCommand" - CallbackUserOnlineCommand = "callbackUserOnlineCommand" - CallbackUserOfflineCommand = "callbackUserOfflineCommand" - CallbackUserKickOffCommand = "callbackUserKickOffCommand" - CallbackOfflinePushCommand = "callbackOfflinePushCommand" - CallbackOnlinePushCommand = "callbackOnlinePushCommand" - CallbackSuperGroupOnlinePushCommand = "callbackSuperGroupOnlinePushCommand" + CallbackAfterUserOnlineCommand = "callbackAfterUserOnlineCommand" + CallbackAfterUserOfflineCommand = "callbackAfterUserOfflineCommand" + CallbackAfterUserKickOffCommand = "callbackAfterUserKickOffCommand" + CallbackBeforeOfflinePushCommand = "callbackBeforeOfflinePushCommand" + CallbackBeforeOnlinePushCommand = "callbackBeforeOnlinePushCommand" + CallbackBeforeGroupOnlinePushCommand = "callbackBeforeGroupOnlinePushCommand" CallbackBeforeAddFriendCommand = "callbackBeforeAddFriendCommand" CallbackBeforeUpdateUserInfoCommand = "callbackBeforeUpdateUserInfoCommand" CallbackBeforeCreateGroupCommand = "callbackBeforeCreateGroupCommand" diff --git a/pkg/callbackstruct/doc.go b/pkg/callbackstruct/doc.go index c3445c60e7..965186c6c2 100644 --- a/pkg/callbackstruct/doc.go +++ b/pkg/callbackstruct/doc.go @@ -1,4 +1,4 @@ -// Copyright © 2023 OpenIM. All rights reserved. +// 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. diff --git a/pkg/callbackstruct/group.go b/pkg/callbackstruct/group.go index 467061a4aa..e78d45ab4c 100644 --- a/pkg/callbackstruct/group.go +++ b/pkg/callbackstruct/group.go @@ -15,8 +15,8 @@ package callbackstruct import ( - common "github.com/OpenIMSDK/protocol/sdkws" "github.com/openimsdk/open-im-server/v3/pkg/apistruct" + common "github.com/openimsdk/protocol/sdkws" ) type CallbackCommand string diff --git a/pkg/callbackstruct/message.go b/pkg/callbackstruct/message.go index 2864e28b1e..902fa61105 100644 --- a/pkg/callbackstruct/message.go +++ b/pkg/callbackstruct/message.go @@ -15,7 +15,7 @@ package callbackstruct import ( - sdkws "github.com/OpenIMSDK/protocol/sdkws" + sdkws "github.com/openimsdk/protocol/sdkws" ) type CallbackBeforeSendSingleMsgReq struct { diff --git a/pkg/callbackstruct/push.go b/pkg/callbackstruct/push.go index 0566c35e2d..0b0f29b51b 100644 --- a/pkg/callbackstruct/push.go +++ b/pkg/callbackstruct/push.go @@ -14,7 +14,7 @@ package callbackstruct -import common "github.com/OpenIMSDK/protocol/sdkws" +import common "github.com/openimsdk/protocol/sdkws" type CallbackBeforePushReq struct { UserStatusBatchCallbackReq diff --git a/pkg/callbackstruct/revoke.go b/pkg/callbackstruct/revoke.go index 1f5e0b0c11..b36985ed35 100644 --- a/pkg/callbackstruct/revoke.go +++ b/pkg/callbackstruct/revoke.go @@ -20,6 +20,7 @@ type CallbackAfterRevokeMsgReq struct { Seq int64 `json:"seq"` UserID string `json:"userID"` } + type CallbackAfterRevokeMsgResp struct { CommonCallbackResp } diff --git a/pkg/callbackstruct/user.go b/pkg/callbackstruct/user.go index 98536882d8..504c7ffb7e 100644 --- a/pkg/callbackstruct/user.go +++ b/pkg/callbackstruct/user.go @@ -15,8 +15,8 @@ package callbackstruct import ( - "github.com/OpenIMSDK/protocol/sdkws" - "github.com/OpenIMSDK/protocol/wrapperspb" + "github.com/openimsdk/protocol/sdkws" + "github.com/openimsdk/protocol/wrapperspb" ) type CallbackBeforeUpdateUserInfoReq struct { @@ -26,6 +26,7 @@ type CallbackBeforeUpdateUserInfoReq struct { FaceURL *string `json:"faceURL"` Ex *string `json:"ex"` } + type CallbackBeforeUpdateUserInfoResp struct { CommonCallbackResp Nickname *string `json:"nickName"` diff --git a/pkg/common/cachekey/doc.go b/pkg/common/cachekey/doc.go new file mode 100644 index 0000000000..4975537ec6 --- /dev/null +++ b/pkg/common/cachekey/doc.go @@ -0,0 +1,15 @@ +// 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 cachekey // import "github.com/openimsdk/open-im-server/v3/pkg/common/cachekey" diff --git a/pkg/common/cachekey/token.go b/pkg/common/cachekey/token.go new file mode 100644 index 0000000000..94468dc315 --- /dev/null +++ b/pkg/common/cachekey/token.go @@ -0,0 +1,11 @@ +package cachekey + +import "github.com/openimsdk/protocol/constant" + +const ( + UidPidToken = "UID_PID_TOKEN_STATUS:" +) + +func GetTokenKey(userID string, platformID int) string { + return UidPidToken + userID + ":" + constant.PlatformIDToName(platformID) +} diff --git a/pkg/common/cmd/api.go b/pkg/common/cmd/api.go index bee16fdad4..022fb10978 100644 --- a/pkg/common/cmd/api.go +++ b/pkg/common/cmd/api.go @@ -15,43 +15,40 @@ package cmd import ( - "github.com/OpenIMSDK/protocol/constant" + "context" "github.com/openimsdk/open-im-server/v3/internal/api" "github.com/openimsdk/open-im-server/v3/pkg/common/config" + "github.com/openimsdk/tools/system/program" "github.com/spf13/cobra" ) type ApiCmd struct { *RootCmd - initFunc func(config *config.GlobalConfig, port int, promPort int) error + ctx context.Context + configMap map[string]any + apiConfig *api.Config } func NewApiCmd() *ApiCmd { - ret := &ApiCmd{RootCmd: NewRootCmd("api"), initFunc: api.Start} - ret.SetRootCmdPt(ret) - ret.addPreRun() - ret.addRunE() - return ret -} - -func (a *ApiCmd) addPreRun() { - a.Command.PreRun = func(cmd *cobra.Command, args []string) { - a.port = a.getPortFlag(cmd) - a.prometheusPort = a.getPrometheusPortFlag(cmd) + var apiConfig api.Config + ret := &ApiCmd{apiConfig: &apiConfig} + ret.configMap = map[string]any{ + OpenIMAPICfgFileName: &apiConfig.RpcConfig, + ZookeeperConfigFileName: &apiConfig.ZookeeperConfig, + ShareFileName: &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 { + return ret.runE() } + return ret } -func (a *ApiCmd) addRunE() { - a.Command.RunE = func(cmd *cobra.Command, args []string) error { - return a.initFunc(a.config, a.port, a.prometheusPort) - } +func (a *ApiCmd) Exec() error { + return a.Execute() } -func (a *ApiCmd) GetPortFromConfig(portType string) int { - if portType == constant.FlagPort { - return a.config.Api.OpenImApiPort[0] - } else if portType == constant.FlagPrometheusPort { - return a.config.Prometheus.ApiPrometheusPort[0] - } - return 0 +func (a *ApiCmd) runE() error { + return api.Start(a.ctx, a.Index(), a.apiConfig) } diff --git a/pkg/common/cmd/auth.go b/pkg/common/cmd/auth.go new file mode 100644 index 0000000000..5ed02ffd00 --- /dev/null +++ b/pkg/common/cmd/auth.go @@ -0,0 +1,59 @@ +// 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 + +import ( + "context" + "github.com/openimsdk/open-im-server/v3/internal/rpc/auth" + "github.com/openimsdk/open-im-server/v3/pkg/common/config" + "github.com/openimsdk/open-im-server/v3/pkg/common/startrpc" + "github.com/openimsdk/tools/system/program" + "github.com/spf13/cobra" +) + +type AuthRpcCmd struct { + *RootCmd + ctx context.Context + configMap map[string]any + authConfig *auth.Config +} + +func NewAuthRpcCmd() *AuthRpcCmd { + var authConfig auth.Config + ret := &AuthRpcCmd{authConfig: &authConfig} + ret.configMap = map[string]any{ + OpenIMRPCAuthCfgFileName: &authConfig.RpcConfig, + RedisConfigFileName: &authConfig.RedisConfig, + ZookeeperConfigFileName: &authConfig.ZookeeperConfig, + ShareFileName: &authConfig.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 *AuthRpcCmd) Exec() error { + return a.Execute() +} + +func (a *AuthRpcCmd) runE() error { + return startrpc.Start(a.ctx, &a.authConfig.ZookeeperConfig, &a.authConfig.RpcConfig.Prometheus, a.authConfig.RpcConfig.RPC.ListenIP, + a.authConfig.RpcConfig.RPC.RegisterIP, a.authConfig.RpcConfig.RPC.Ports, + a.Index(), a.authConfig.Share.RpcRegisterName.Auth, &a.authConfig.Share, a.authConfig, auth.Start) +} diff --git a/pkg/common/cmd/constant.go b/pkg/common/cmd/constant.go index c332ce3a62..55eb4a069f 100644 --- a/pkg/common/cmd/constant.go +++ b/pkg/common/cmd/constant.go @@ -14,13 +14,83 @@ package cmd +import ( + "strings" +) + +var ( + FileName string + NotificationFileName string + ShareFileName string + WebhooksConfigFileName string + LocalCacheConfigFileName string + KafkaConfigFileName string + RedisConfigFileName string + ZookeeperConfigFileName string + MongodbConfigFileName string + MinioConfigFileName string + LogConfigFileName string + OpenIMAPICfgFileName string + OpenIMCronTaskCfgFileName string + OpenIMMsgGatewayCfgFileName string + OpenIMMsgTransferCfgFileName string + OpenIMPushCfgFileName string + OpenIMRPCAuthCfgFileName string + OpenIMRPCConversationCfgFileName string + OpenIMRPCFriendCfgFileName string + OpenIMRPCGroupCfgFileName string + OpenIMRPCMsgCfgFileName string + OpenIMRPCThirdCfgFileName string + OpenIMRPCUserCfgFileName string +) + +var ConfigEnvPrefixMap map[string]string + +func init() { + FileName = "config.yaml" + NotificationFileName = "notification.yml" + ShareFileName = "share.yml" + WebhooksConfigFileName = "webhooks.yml" + LocalCacheConfigFileName = "local-cache.yml" + KafkaConfigFileName = "kafka.yml" + RedisConfigFileName = "redis.yml" + ZookeeperConfigFileName = "zookeeper.yml" + MongodbConfigFileName = "mongodb.yml" + MinioConfigFileName = "minio.yml" + LogConfigFileName = "log.yml" + OpenIMAPICfgFileName = "openim-api.yml" + OpenIMCronTaskCfgFileName = "openim-crontask.yml" + OpenIMMsgGatewayCfgFileName = "openim-msggateway.yml" + OpenIMMsgTransferCfgFileName = "openim-msgtransfer.yml" + OpenIMPushCfgFileName = "openim-push.yml" + OpenIMRPCAuthCfgFileName = "openim-rpc-auth.yml" + OpenIMRPCConversationCfgFileName = "openim-rpc-conversation.yml" + OpenIMRPCFriendCfgFileName = "openim-rpc-friend.yml" + OpenIMRPCGroupCfgFileName = "openim-rpc-group.yml" + OpenIMRPCMsgCfgFileName = "openim-rpc-msg.yml" + OpenIMRPCThirdCfgFileName = "openim-rpc-third.yml" + OpenIMRPCUserCfgFileName = "openim-rpc-user.yml" + + ConfigEnvPrefixMap = make(map[string]string) + fileNames := []string{ + FileName, NotificationFileName, ShareFileName, WebhooksConfigFileName, + KafkaConfigFileName, RedisConfigFileName, ZookeeperConfigFileName, + MongodbConfigFileName, MinioConfigFileName, LogConfigFileName, + OpenIMAPICfgFileName, OpenIMCronTaskCfgFileName, OpenIMMsgGatewayCfgFileName, + OpenIMMsgTransferCfgFileName, OpenIMPushCfgFileName, OpenIMRPCAuthCfgFileName, + OpenIMRPCConversationCfgFileName, OpenIMRPCFriendCfgFileName, OpenIMRPCGroupCfgFileName, + OpenIMRPCMsgCfgFileName, OpenIMRPCThirdCfgFileName, OpenIMRPCUserCfgFileName, + } + + for _, fileName := range fileNames { + envKey := strings.TrimSuffix(strings.TrimSuffix(fileName, ".yml"), ".yaml") + envKey = "IMENV_" + envKey + envKey = strings.ToUpper(strings.ReplaceAll(envKey, "-", "_")) + ConfigEnvPrefixMap[fileName] = envKey + } +} + const ( - RpcPushServer = "push" - RpcAuthServer = "auth" - RpcConversationServer = "conversation" - RpcFriendServer = "friend" - RpcGroupServer = "group" - RpcMsgServer = "msg" - RpcThirdServer = "third" - RpcUserServer = "user" + FlagConf = "config_folder_path" + FlagTransferIndex = "index" ) diff --git a/pkg/common/cmd/conversation.go b/pkg/common/cmd/conversation.go new file mode 100644 index 0000000000..0a617c7296 --- /dev/null +++ b/pkg/common/cmd/conversation.go @@ -0,0 +1,61 @@ +// 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 + +import ( + "context" + "github.com/openimsdk/open-im-server/v3/internal/rpc/conversation" + "github.com/openimsdk/open-im-server/v3/pkg/common/config" + "github.com/openimsdk/open-im-server/v3/pkg/common/startrpc" + "github.com/openimsdk/tools/system/program" + "github.com/spf13/cobra" +) + +type ConversationRpcCmd struct { + *RootCmd + ctx context.Context + configMap map[string]any + conversationConfig *conversation.Config +} + +func NewConversationRpcCmd() *ConversationRpcCmd { + var conversationConfig conversation.Config + ret := &ConversationRpcCmd{conversationConfig: &conversationConfig} + ret.configMap = map[string]any{ + OpenIMRPCConversationCfgFileName: &conversationConfig.RpcConfig, + RedisConfigFileName: &conversationConfig.RedisConfig, + ZookeeperConfigFileName: &conversationConfig.ZookeeperConfig, + MongodbConfigFileName: &conversationConfig.MongodbConfig, + ShareFileName: &conversationConfig.Share, + NotificationFileName: &conversationConfig.NotificationConfig, + LocalCacheConfigFileName: &conversationConfig.LocalCacheConfig, + } + 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 *ConversationRpcCmd) Exec() error { + return a.Execute() +} + +func (a *ConversationRpcCmd) runE() error { + return startrpc.Start(a.ctx, &a.conversationConfig.ZookeeperConfig, &a.conversationConfig.RpcConfig.Prometheus, a.conversationConfig.RpcConfig.RPC.ListenIP, + a.conversationConfig.RpcConfig.RPC.RegisterIP, a.conversationConfig.RpcConfig.RPC.Ports, + a.Index(), a.conversationConfig.Share.RpcRegisterName.Conversation, &a.conversationConfig.Share, a.conversationConfig, conversation.Start) +} diff --git a/pkg/common/cmd/cron_task.go b/pkg/common/cmd/cron_task.go index d8c9dd2a8b..0e94cf52ce 100644 --- a/pkg/common/cmd/cron_task.go +++ b/pkg/common/cmd/cron_task.go @@ -15,34 +15,43 @@ package cmd import ( + "context" "github.com/openimsdk/open-im-server/v3/internal/tools" "github.com/openimsdk/open-im-server/v3/pkg/common/config" + "github.com/openimsdk/tools/system/program" "github.com/spf13/cobra" ) type CronTaskCmd struct { *RootCmd - initFunc func(config *config.GlobalConfig) error + ctx context.Context + configMap map[string]any + cronTaskConfig *tools.CronTaskConfig } func NewCronTaskCmd() *CronTaskCmd { - ret := &CronTaskCmd{RootCmd: NewRootCmd("cronTask", WithCronTaskLogName()), - initFunc: tools.StartTask} - ret.addRunE() - ret.SetRootCmdPt(ret) - return ret -} - -func (c *CronTaskCmd) addRunE() { - c.Command.RunE = func(cmd *cobra.Command, args []string) error { - return c.initFunc(c.config) + var cronTaskConfig tools.CronTaskConfig + ret := &CronTaskCmd{cronTaskConfig: &cronTaskConfig} + ret.configMap = map[string]any{ + OpenIMCronTaskCfgFileName: &cronTaskConfig.CronTask, + RedisConfigFileName: &cronTaskConfig.RedisConfig, + MongodbConfigFileName: &cronTaskConfig.MongodbConfig, + ZookeeperConfigFileName: &cronTaskConfig.ZookeeperConfig, + ShareFileName: &cronTaskConfig.Share, + KafkaConfigFileName: &cronTaskConfig.KafkaConfig, } + 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 (c *CronTaskCmd) Exec() error { - return c.Execute() +func (a *CronTaskCmd) Exec() error { + return a.Execute() } -func (c *CronTaskCmd) GetPortFromConfig(portType string) int { - return 0 +func (a *CronTaskCmd) runE() error { + return tools.Start(a.ctx, a.cronTaskConfig) } diff --git a/pkg/common/cmd/doc.go b/pkg/common/cmd/doc.go index 991a85eb9a..96d80b64ac 100644 --- a/pkg/common/cmd/doc.go +++ b/pkg/common/cmd/doc.go @@ -1,4 +1,4 @@ -// Copyright © 2023 OpenIM. All rights reserved. +// 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. diff --git a/pkg/common/cmd/friend.go b/pkg/common/cmd/friend.go new file mode 100644 index 0000000000..b8d46f77ef --- /dev/null +++ b/pkg/common/cmd/friend.go @@ -0,0 +1,62 @@ +// 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 + +import ( + "context" + "github.com/openimsdk/open-im-server/v3/internal/rpc/friend" + "github.com/openimsdk/open-im-server/v3/pkg/common/config" + "github.com/openimsdk/open-im-server/v3/pkg/common/startrpc" + "github.com/openimsdk/tools/system/program" + "github.com/spf13/cobra" +) + +type FriendRpcCmd struct { + *RootCmd + ctx context.Context + configMap map[string]any + friendConfig *friend.Config +} + +func NewFriendRpcCmd() *FriendRpcCmd { + var friendConfig friend.Config + ret := &FriendRpcCmd{friendConfig: &friendConfig} + ret.configMap = map[string]any{ + OpenIMRPCFriendCfgFileName: &friendConfig.RpcConfig, + RedisConfigFileName: &friendConfig.RedisConfig, + ZookeeperConfigFileName: &friendConfig.ZookeeperConfig, + MongodbConfigFileName: &friendConfig.MongodbConfig, + ShareFileName: &friendConfig.Share, + NotificationFileName: &friendConfig.NotificationConfig, + WebhooksConfigFileName: &friendConfig.WebhooksConfig, + LocalCacheConfigFileName: &friendConfig.LocalCacheConfig, + } + 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 *FriendRpcCmd) Exec() error { + return a.Execute() +} + +func (a *FriendRpcCmd) runE() error { + return startrpc.Start(a.ctx, &a.friendConfig.ZookeeperConfig, &a.friendConfig.RpcConfig.Prometheus, a.friendConfig.RpcConfig.RPC.ListenIP, + a.friendConfig.RpcConfig.RPC.RegisterIP, a.friendConfig.RpcConfig.RPC.Ports, + a.Index(), a.friendConfig.Share.RpcRegisterName.Friend, &a.friendConfig.Share, a.friendConfig, friend.Start) +} diff --git a/pkg/common/cmd/group.go b/pkg/common/cmd/group.go new file mode 100644 index 0000000000..8bf9778249 --- /dev/null +++ b/pkg/common/cmd/group.go @@ -0,0 +1,62 @@ +// 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 + +import ( + "context" + "github.com/openimsdk/open-im-server/v3/internal/rpc/group" + "github.com/openimsdk/open-im-server/v3/pkg/common/config" + "github.com/openimsdk/open-im-server/v3/pkg/common/startrpc" + "github.com/openimsdk/tools/system/program" + "github.com/spf13/cobra" +) + +type GroupRpcCmd struct { + *RootCmd + ctx context.Context + configMap map[string]any + groupConfig *group.Config +} + +func NewGroupRpcCmd() *GroupRpcCmd { + var groupConfig group.Config + ret := &GroupRpcCmd{groupConfig: &groupConfig} + ret.configMap = map[string]any{ + OpenIMRPCGroupCfgFileName: &groupConfig.RpcConfig, + RedisConfigFileName: &groupConfig.RedisConfig, + ZookeeperConfigFileName: &groupConfig.ZookeeperConfig, + MongodbConfigFileName: &groupConfig.MongodbConfig, + ShareFileName: &groupConfig.Share, + NotificationFileName: &groupConfig.NotificationConfig, + WebhooksConfigFileName: &groupConfig.WebhooksConfig, + LocalCacheConfigFileName: &groupConfig.LocalCacheConfig, + } + 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 *GroupRpcCmd) Exec() error { + return a.Execute() +} + +func (a *GroupRpcCmd) runE() error { + return startrpc.Start(a.ctx, &a.groupConfig.ZookeeperConfig, &a.groupConfig.RpcConfig.Prometheus, a.groupConfig.RpcConfig.RPC.ListenIP, + a.groupConfig.RpcConfig.RPC.RegisterIP, a.groupConfig.RpcConfig.RPC.Ports, + a.Index(), a.groupConfig.Share.RpcRegisterName.Group, &a.groupConfig.Share, a.groupConfig, group.Start) +} diff --git a/pkg/common/cmd/msg.go b/pkg/common/cmd/msg.go new file mode 100644 index 0000000000..a3b521b4b7 --- /dev/null +++ b/pkg/common/cmd/msg.go @@ -0,0 +1,63 @@ +// 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 + +import ( + "context" + "github.com/openimsdk/open-im-server/v3/internal/rpc/msg" + "github.com/openimsdk/open-im-server/v3/pkg/common/config" + "github.com/openimsdk/open-im-server/v3/pkg/common/startrpc" + "github.com/openimsdk/tools/system/program" + "github.com/spf13/cobra" +) + +type MsgRpcCmd struct { + *RootCmd + ctx context.Context + configMap map[string]any + msgConfig *msg.Config +} + +func NewMsgRpcCmd() *MsgRpcCmd { + var msgConfig msg.Config + ret := &MsgRpcCmd{msgConfig: &msgConfig} + ret.configMap = map[string]any{ + OpenIMRPCMsgCfgFileName: &msgConfig.RpcConfig, + RedisConfigFileName: &msgConfig.RedisConfig, + ZookeeperConfigFileName: &msgConfig.ZookeeperConfig, + MongodbConfigFileName: &msgConfig.MongodbConfig, + KafkaConfigFileName: &msgConfig.KafkaConfig, + ShareFileName: &msgConfig.Share, + NotificationFileName: &msgConfig.NotificationConfig, + WebhooksConfigFileName: &msgConfig.WebhooksConfig, + LocalCacheConfigFileName: &msgConfig.LocalCacheConfig, + } + 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 *MsgRpcCmd) Exec() error { + return a.Execute() +} + +func (a *MsgRpcCmd) runE() error { + return startrpc.Start(a.ctx, &a.msgConfig.ZookeeperConfig, &a.msgConfig.RpcConfig.Prometheus, a.msgConfig.RpcConfig.RPC.ListenIP, + a.msgConfig.RpcConfig.RPC.RegisterIP, a.msgConfig.RpcConfig.RPC.Ports, + a.Index(), a.msgConfig.Share.RpcRegisterName.Msg, &a.msgConfig.Share, a.msgConfig, msg.Start) +} diff --git a/pkg/common/cmd/msg_gateway.go b/pkg/common/cmd/msg_gateway.go index 37aedd933d..897fd70087 100644 --- a/pkg/common/cmd/msg_gateway.go +++ b/pkg/common/cmd/msg_gateway.go @@ -15,61 +15,43 @@ package cmd import ( - "log" + "context" + "github.com/openimsdk/open-im-server/v3/pkg/common/config" - "github.com/OpenIMSDK/protocol/constant" "github.com/openimsdk/open-im-server/v3/internal/msggateway" + + "github.com/openimsdk/tools/system/program" "github.com/spf13/cobra" ) type MsgGatewayCmd struct { *RootCmd + ctx context.Context + configMap map[string]any + msgGatewayConfig *msggateway.Config } func NewMsgGatewayCmd() *MsgGatewayCmd { - ret := &MsgGatewayCmd{NewRootCmd("msgGateway")} - ret.addRunE() - ret.SetRootCmdPt(ret) - return ret -} - -func (m *MsgGatewayCmd) AddWsPortFlag() { - m.Command.Flags().IntP(constant.FlagWsPort, "w", 0, "ws server listen port") -} - -func (m *MsgGatewayCmd) getWsPortFlag(cmd *cobra.Command) int { - port, err := cmd.Flags().GetInt(constant.FlagWsPort) - if err != nil { - log.Println("Error getting ws port flag:", err) - } - if port == 0 { - port = m.PortFromConfig(constant.FlagWsPort) + var msgGatewayConfig msggateway.Config + ret := &MsgGatewayCmd{msgGatewayConfig: &msgGatewayConfig} + ret.configMap = map[string]any{ + OpenIMMsgGatewayCfgFileName: &msgGatewayConfig.MsgGateway, + ZookeeperConfigFileName: &msgGatewayConfig.ZookeeperConfig, + ShareFileName: &msgGatewayConfig.Share, + WebhooksConfigFileName: &msgGatewayConfig.WebhooksConfig, } - return port -} - -func (m *MsgGatewayCmd) addRunE() { - m.Command.RunE = func(cmd *cobra.Command, args []string) error { - return msggateway.RunWsAndServer(m.config, m.getPortFlag(cmd), m.getWsPortFlag(cmd), m.getPrometheusPortFlag(cmd)) + 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 (m *MsgGatewayCmd) Exec() error { return m.Execute() } -func (m *MsgGatewayCmd) GetPortFromConfig(portType string) int { - switch portType { - case constant.FlagWsPort: - return m.config.LongConnSvr.OpenImWsPort[0] - - case constant.FlagPort: - return m.config.LongConnSvr.OpenImMessageGatewayPort[0] - - case constant.FlagPrometheusPort: - return m.config.Prometheus.MessageGatewayPrometheusPort[0] - - default: - return 0 - } +func (m *MsgGatewayCmd) runE() error { + return msggateway.Start(m.ctx, m.Index(), m.msgGatewayConfig) } diff --git a/pkg/common/cmd/msg_gateway_test.go b/pkg/common/cmd/msg_gateway_test.go index c0ea2b057c..d820627b50 100644 --- a/pkg/common/cmd/msg_gateway_test.go +++ b/pkg/common/cmd/msg_gateway_test.go @@ -15,11 +15,12 @@ package cmd import ( - "testing" - - "github.com/OpenIMSDK/protocol/constant" + "github.com/openimsdk/protocol/auth" + "github.com/openimsdk/tools/apiresp" + "github.com/openimsdk/tools/utils/jsonutil" "github.com/stretchr/testify/mock" - "gotest.tools/assert" + "math" + "testing" ) // MockRootCmd is a mock type for the RootCmd type @@ -32,20 +33,29 @@ func (m *MockRootCmd) Execute() error { return args.Error(0) } -func TestMsgGatewayCmd_GetPortFromConfig(t *testing.T) { - msgGatewayCmd := &MsgGatewayCmd{RootCmd: &RootCmd{}} - tests := []struct { - portType string - want int - }{ - {constant.FlagWsPort, 8080}, // Replace 8080 with the expected port from the config - {constant.FlagPort, 8081}, // Replace 8081 with the expected port from the config - {"invalid", 0}, +func TestName(t *testing.T) { + resp := &apiresp.ApiResponse{ + ErrCode: 1234, + ErrMsg: "test", + ErrDlt: "4567", + Data: &auth.UserTokenResp{ + Token: "1234567", + ExpireTimeSeconds: math.MaxInt64, + }, + } + data, err := resp.MarshalJSON() + if err != nil { + panic(err) } - for _, tt := range tests { - t.Run(tt.portType, func(t *testing.T) { - got := msgGatewayCmd.GetPortFromConfig(tt.portType) - assert.Equal(t, tt.want, got) - }) + t.Log(string(data)) + + var rReso apiresp.ApiResponse + rReso.Data = &auth.UserTokenResp{} + + if err := jsonutil.JsonUnmarshal(data, &rReso); err != nil { + panic(err) } + + t.Logf("%+v\n", rReso) + } diff --git a/pkg/common/cmd/msg_transfer.go b/pkg/common/cmd/msg_transfer.go index d98154f3a3..86f42dc56f 100644 --- a/pkg/common/cmd/msg_transfer.go +++ b/pkg/common/cmd/msg_transfer.go @@ -15,53 +15,44 @@ package cmd import ( - "fmt" - - "github.com/OpenIMSDK/protocol/constant" + "context" "github.com/openimsdk/open-im-server/v3/internal/msgtransfer" + "github.com/openimsdk/open-im-server/v3/pkg/common/config" + "github.com/openimsdk/tools/system/program" "github.com/spf13/cobra" ) type MsgTransferCmd struct { *RootCmd + ctx context.Context + configMap map[string]any + msgTransferConfig *msgtransfer.Config } func NewMsgTransferCmd() *MsgTransferCmd { - ret := &MsgTransferCmd{NewRootCmd("msgTransfer")} - ret.addRunE() - ret.SetRootCmdPt(ret) - return ret -} - -func (m *MsgTransferCmd) addRunE() { - m.Command.RunE = func(cmd *cobra.Command, args []string) error { - return msgtransfer.StartTransfer(m.config, m.getPrometheusPortFlag(cmd)) + var msgTransferConfig msgtransfer.Config + ret := &MsgTransferCmd{msgTransferConfig: &msgTransferConfig} + ret.configMap = map[string]any{ + OpenIMMsgTransferCfgFileName: &msgTransferConfig.MsgTransfer, + RedisConfigFileName: &msgTransferConfig.RedisConfig, + MongodbConfigFileName: &msgTransferConfig.MongodbConfig, + KafkaConfigFileName: &msgTransferConfig.KafkaConfig, + ZookeeperConfigFileName: &msgTransferConfig.ZookeeperConfig, + ShareFileName: &msgTransferConfig.Share, + WebhooksConfigFileName: &msgTransferConfig.WebhooksConfig, + } + 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 (m *MsgTransferCmd) Exec() error { return m.Execute() } -func (m *MsgTransferCmd) GetPortFromConfig(portType string) int { - if portType == constant.FlagPort { - return 0 - } else if portType == constant.FlagPrometheusPort { - n := m.getTransferProgressFlagValue() - return m.config.Prometheus.MessageTransferPrometheusPort[n] - } - return 0 -} - -func (m *MsgTransferCmd) AddTransferProgressFlag() { - m.Command.Flags().IntP(constant.FlagTransferProgressIndex, "n", 0, "transfer progress index") -} - -func (m *MsgTransferCmd) getTransferProgressFlagValue() int { - nIndex, err := m.Command.Flags().GetInt(constant.FlagTransferProgressIndex) - if err != nil { - fmt.Println("get transfer cmd error,make sure it is k8s env or not") - return 0 - } - return nIndex +func (m *MsgTransferCmd) runE() error { + return msgtransfer.Start(m.ctx, m.Index(), m.msgTransferConfig) } diff --git a/pkg/common/cmd/msg_utils.go b/pkg/common/cmd/msg_utils.go index df15acd87f..fc5eaceae8 100644 --- a/pkg/common/cmd/msg_utils.go +++ b/pkg/common/cmd/msg_utils.go @@ -15,8 +15,10 @@ package cmd import ( + "context" + "github.com/openimsdk/open-im-server/v3/internal/tools" - util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" + "github.com/openimsdk/tools/system/program" "github.com/spf13/cobra" ) @@ -28,6 +30,14 @@ type MsgUtilsCmd struct { func (m *MsgUtilsCmd) AddUserIDFlag() { m.Command.PersistentFlags().StringP("userID", "u", "", "openIM userID") } +func (m *MsgUtilsCmd) AddIndexFlag() { + m.Command.PersistentFlags().IntP(FlagTransferIndex, "i", 0, "process startup sequence number") +} + +func (m *MsgUtilsCmd) AddConfigDirFlag() { + m.Command.PersistentFlags().StringP(FlagConf, "c", "", "path of config directory") + +} func (m *MsgUtilsCmd) getUserIDFlag(cmdLines *cobra.Command) string { userID, _ := cmdLines.Flags().GetString("userID") @@ -44,7 +54,7 @@ func (m *MsgUtilsCmd) AddFixAllFlag() { } */ func (m *MsgUtilsCmd) AddClearAllFlag() { - m.Command.PersistentFlags().BoolP("clearAll", "c", false, "openIM clear all seqs") + m.Command.PersistentFlags().BoolP("clearAll", "", false, "openIM clear all seqs") } /* func (m *MsgUtilsCmd) getClearAllFlag(cmdLines *cobra.Command) bool { @@ -136,9 +146,9 @@ func NewSeqCmd() *SeqCmd { func (s *SeqCmd) GetSeqCmd() *cobra.Command { s.Command.Run = func(cmdLines *cobra.Command, args []string) { - _, err := tools.InitMsgTool(s.MsgTool.Config) + _, err := tools.InitMsgTool(context.Background(), nil) if err != nil { - util.ExitWithError(err) + program.ExitWithError(err) } userID := s.getUserIDFlag(cmdLines) superGroupID := s.getSuperGroupIDFlag(cmdLines) diff --git a/pkg/common/cmd/push.go b/pkg/common/cmd/push.go new file mode 100644 index 0000000000..0140ced237 --- /dev/null +++ b/pkg/common/cmd/push.go @@ -0,0 +1,63 @@ +// 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 + +import ( + "context" + "github.com/openimsdk/open-im-server/v3/internal/push" + "github.com/openimsdk/open-im-server/v3/pkg/common/config" + "github.com/openimsdk/open-im-server/v3/pkg/common/startrpc" + "github.com/openimsdk/tools/system/program" + "github.com/spf13/cobra" +) + +type PushRpcCmd struct { + *RootCmd + ctx context.Context + configMap map[string]any + pushConfig *push.Config +} + +func NewPushRpcCmd() *PushRpcCmd { + var pushConfig push.Config + ret := &PushRpcCmd{pushConfig: &pushConfig} + ret.configMap = map[string]any{ + OpenIMPushCfgFileName: &pushConfig.RpcConfig, + RedisConfigFileName: &pushConfig.RedisConfig, + ZookeeperConfigFileName: &pushConfig.ZookeeperConfig, + MongodbConfigFileName: &pushConfig.MongodbConfig, + KafkaConfigFileName: &pushConfig.KafkaConfig, + ShareFileName: &pushConfig.Share, + NotificationFileName: &pushConfig.NotificationConfig, + WebhooksConfigFileName: &pushConfig.WebhooksConfig, + LocalCacheConfigFileName: &pushConfig.LocalCacheConfig, + } + 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 *PushRpcCmd) Exec() error { + return a.Execute() +} + +func (a *PushRpcCmd) runE() error { + return startrpc.Start(a.ctx, &a.pushConfig.ZookeeperConfig, &a.pushConfig.RpcConfig.Prometheus, a.pushConfig.RpcConfig.RPC.ListenIP, + a.pushConfig.RpcConfig.RPC.RegisterIP, a.pushConfig.RpcConfig.RPC.Ports, + a.Index(), a.pushConfig.Share.RpcRegisterName.Push, &a.pushConfig.Share, a.pushConfig, push.Start) +} diff --git a/pkg/common/cmd/root.go b/pkg/common/cmd/root.go index 478942a5bb..9002813676 100644 --- a/pkg/common/cmd/root.go +++ b/pkg/common/cmd/root.go @@ -16,34 +16,34 @@ package cmd import ( "fmt" + "path/filepath" - "github.com/OpenIMSDK/protocol/constant" - "github.com/OpenIMSDK/tools/errs" - "github.com/OpenIMSDK/tools/log" "github.com/openimsdk/open-im-server/v3/pkg/common/config" - config2 "github.com/openimsdk/open-im-server/v3/pkg/common/config" + "github.com/openimsdk/tools/errs" + "github.com/openimsdk/tools/log" "github.com/spf13/cobra" ) -type RootCmdPt interface { - GetPortFromConfig(portType string) int -} - type RootCmd struct { Command cobra.Command - Name string + processName string port int prometheusPort int - cmdItf RootCmdPt - config *config.GlobalConfig + log config.Log + index int +} + +func (r *RootCmd) Index() int { + return r.index } -func (rc *RootCmd) Port() int { - return rc.port +func (r *RootCmd) Port() int { + return r.port } type CmdOpts struct { loggerPrefixName string + configMap map[string]any } func WithCronTaskLogName() func(*CmdOpts) { @@ -57,41 +57,63 @@ func WithLogName(logName string) func(*CmdOpts) { opts.loggerPrefixName = logName } } +func WithConfigMap(configMap map[string]any) func(*CmdOpts) { + return func(opts *CmdOpts) { + opts.configMap = configMap + } +} -func NewRootCmd(name string, opts ...func(*CmdOpts)) *RootCmd { - rootCmd := &RootCmd{Name: name, config: config.NewGlobalConfig()} +func NewRootCmd(processName string, opts ...func(*CmdOpts)) *RootCmd { + rootCmd := &RootCmd{processName: processName} cmd := cobra.Command{ - Use: "Start openIM application", - Short: fmt.Sprintf(`Start %s `, name), - Long: fmt.Sprintf(`Start %s `, name), + Use: "Start openIM application", + Long: fmt.Sprintf(`Start %s `, processName), PersistentPreRunE: func(cmd *cobra.Command, args []string) error { return rootCmd.persistentPreRun(cmd, opts...) }, + SilenceUsage: true, + SilenceErrors: false, } + cmd.Flags().StringP(FlagConf, "c", "", "path of config directory") + cmd.Flags().IntP(FlagTransferIndex, "i", 0, "process startup sequence number") + rootCmd.Command = cmd - rootCmd.addConfFlag() return rootCmd } -func (rc *RootCmd) persistentPreRun(cmd *cobra.Command, opts ...func(*CmdOpts)) error { - if err := rc.initializeConfiguration(cmd); err != nil { - return fmt.Errorf("failed to get configuration from command: %w", err) +func (r *RootCmd) persistentPreRun(cmd *cobra.Command, opts ...func(*CmdOpts)) error { + cmdOpts := r.applyOptions(opts...) + if err := r.initializeConfiguration(cmd, cmdOpts); err != nil { + return err } - cmdOpts := rc.applyOptions(opts...) - - if err := rc.initializeLogger(cmdOpts); err != nil { - return errs.Wrap(err, "failed to initialize logger") + if err := r.initializeLogger(cmdOpts); err != nil { + return errs.WrapMsg(err, "failed to initialize logger") } return nil } -func (rc *RootCmd) initializeConfiguration(cmd *cobra.Command) error { - return rc.getConfFromCmdAndInit(cmd) +func (r *RootCmd) initializeConfiguration(cmd *cobra.Command, opts *CmdOpts) error { + configDirectory, _, err := r.getFlag(cmd) + if err != nil { + return err + } + // 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) + if err != nil { + return err + } + } + // Load common log configuration file + return config.LoadConfig(filepath.Join(configDirectory, LogConfigFileName), + ConfigEnvPrefixMap[LogConfigFileName], &r.log) } -func (rc *RootCmd) applyOptions(opts ...func(*CmdOpts)) *CmdOpts { +func (r *RootCmd) applyOptions(opts ...func(*CmdOpts)) *CmdOpts { cmdOpts := defaultCmdOpts() for _, opt := range opts { opt(cmdOpts) @@ -100,92 +122,45 @@ func (rc *RootCmd) applyOptions(opts ...func(*CmdOpts)) *CmdOpts { return cmdOpts } -func (rc *RootCmd) initializeLogger(cmdOpts *CmdOpts) error { - logConfig := rc.config.Log - - return log.InitFromConfig( +func (r *RootCmd) initializeLogger(cmdOpts *CmdOpts) error { + err := log.InitFromConfig( cmdOpts.loggerPrefixName, - rc.Name, - logConfig.RemainLogLevel, - logConfig.IsStdout, - logConfig.IsJson, - logConfig.StorageLocation, - logConfig.RemainRotationCount, - logConfig.RotationTime, + r.processName, + r.log.RemainLogLevel, + r.log.IsStdout, + r.log.IsJson, + r.log.StorageLocation, + r.log.RemainRotationCount, + r.log.RotationTime, + config.Version, ) + if err != nil { + return errs.Wrap(err) + } + return errs.Wrap(log.InitConsoleLogger(r.processName, r.log.RemainLogLevel, r.log.IsJson, config.Version)) + } func defaultCmdOpts() *CmdOpts { return &CmdOpts{ - loggerPrefixName: "openim-all", + loggerPrefixName: "openim-service-log", } } -func (r *RootCmd) SetRootCmdPt(cmdItf RootCmdPt) { - r.cmdItf = cmdItf -} - -func (r *RootCmd) addConfFlag() { - r.Command.Flags().StringP(constant.FlagConf, "c", "", "path to config file folder") -} - -func (r *RootCmd) AddPortFlag() { - r.Command.Flags().IntP(constant.FlagPort, "p", 0, "server listen port") -} - -func (r *RootCmd) getPortFlag(cmd *cobra.Command) int { - port, err := cmd.Flags().GetInt(constant.FlagPort) +func (r *RootCmd) getFlag(cmd *cobra.Command) (string, int, error) { + configDirectory, err := cmd.Flags().GetString(FlagConf) if err != nil { - // Wrapping the error with additional context - return 0 + return "", 0, errs.Wrap(err) } - if port == 0 { - port = r.PortFromConfig(constant.FlagPort) - } - return port -} - -// // GetPortFlag returns the port flag. -func (r *RootCmd) GetPortFlag() int { - return r.port -} - -func (r *RootCmd) AddPrometheusPortFlag() { - r.Command.Flags().IntP(constant.FlagPrometheusPort, "", 0, "server prometheus listen port") -} - -func (r *RootCmd) getPrometheusPortFlag(cmd *cobra.Command) int { - port, err := cmd.Flags().GetInt(constant.FlagPrometheusPort) - if err != nil || port == 0 { - port = r.PortFromConfig(constant.FlagPrometheusPort) - if err != nil { - return 0 - } + index, err := cmd.Flags().GetInt(FlagTransferIndex) + if err != nil { + return "", 0, errs.Wrap(err) } - return port -} - -func (r *RootCmd) GetPrometheusPortFlag() int { - return r.prometheusPort -} - -func (r *RootCmd) getConfFromCmdAndInit(cmdLines *cobra.Command) error { - configFolderPath, _ := cmdLines.Flags().GetString(constant.FlagConf) - fmt.Println("The directory of the configuration file to start the process:", configFolderPath) - return config2.InitConfig(r.config, configFolderPath) + r.index = index + return configDirectory, index, nil } func (r *RootCmd) Execute() error { return r.Command.Execute() } - -func (r *RootCmd) AddCommand(cmds ...*cobra.Command) { - r.Command.AddCommand(cmds...) -} - -func (r *RootCmd) PortFromConfig(portType string) int { - // Retrieve the port and cache it - port := r.cmdItf.GetPortFromConfig(portType) - return port -} diff --git a/pkg/common/cmd/rpc.go b/pkg/common/cmd/rpc.go deleted file mode 100644 index 9c6dbddd6f..0000000000 --- a/pkg/common/cmd/rpc.go +++ /dev/null @@ -1,156 +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 cmd - -import ( - "errors" - - "github.com/OpenIMSDK/protocol/constant" - "github.com/OpenIMSDK/tools/discoveryregistry" - "github.com/OpenIMSDK/tools/errs" - config2 "github.com/openimsdk/open-im-server/v3/pkg/common/config" - "github.com/openimsdk/open-im-server/v3/pkg/common/startrpc" - "github.com/spf13/cobra" - "google.golang.org/grpc" -) - -type rpcInitFuc func(config *config2.GlobalConfig, disCov discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) error - -type RpcCmd struct { - *RootCmd - RpcRegisterName string - initFunc rpcInitFuc -} - -func NewRpcCmd(name string, initFunc rpcInitFuc) *RpcCmd { - ret := &RpcCmd{RootCmd: NewRootCmd(name), initFunc: initFunc} - ret.addPreRun() - ret.addRunE() - ret.SetRootCmdPt(ret) - return ret -} - -func (a *RpcCmd) addPreRun() { - a.Command.PreRun = func(cmd *cobra.Command, args []string) { - a.port = a.getPortFlag(cmd) - a.prometheusPort = a.getPrometheusPortFlag(cmd) - } -} - -func (a *RpcCmd) addRunE() { - a.Command.RunE = func(cmd *cobra.Command, args []string) error { - rpcRegisterName, err := a.GetRpcRegisterNameFromConfig() - if err != nil { - return err - } else { - return a.StartSvr(rpcRegisterName, a.initFunc) - } - } -} - -func (a *RpcCmd) Exec() error { - return a.Execute() -} - -func (a *RpcCmd) StartSvr(name string, rpcFn func(config *config2.GlobalConfig, disCov discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) error) error { - if a.GetPortFlag() == 0 { - return errs.Wrap(errors.New("port is required")) - } - return startrpc.Start(a.GetPortFlag(), name, a.GetPrometheusPortFlag(), a.config, rpcFn) -} - -func (a *RpcCmd) GetPortFromConfig(portType string) int { - switch a.Name { - case RpcPushServer: - if portType == constant.FlagPort { - return a.config.RpcPort.OpenImPushPort[0] - } - if portType == constant.FlagPrometheusPort { - return a.config.Prometheus.PushPrometheusPort[0] - } - case RpcAuthServer: - if portType == constant.FlagPort { - return a.config.RpcPort.OpenImAuthPort[0] - } - if portType == constant.FlagPrometheusPort { - return a.config.Prometheus.AuthPrometheusPort[0] - } - case RpcConversationServer: - if portType == constant.FlagPort { - return a.config.RpcPort.OpenImConversationPort[0] - } - if portType == constant.FlagPrometheusPort { - return a.config.Prometheus.ConversationPrometheusPort[0] - } - case RpcFriendServer: - if portType == constant.FlagPort { - return a.config.RpcPort.OpenImFriendPort[0] - } - if portType == constant.FlagPrometheusPort { - return a.config.Prometheus.FriendPrometheusPort[0] - } - case RpcGroupServer: - if portType == constant.FlagPort { - return a.config.RpcPort.OpenImGroupPort[0] - } - if portType == constant.FlagPrometheusPort { - return a.config.Prometheus.GroupPrometheusPort[0] - } - case RpcMsgServer: - if portType == constant.FlagPort { - return a.config.RpcPort.OpenImMessagePort[0] - } - if portType == constant.FlagPrometheusPort { - return a.config.Prometheus.MessagePrometheusPort[0] - } - case RpcThirdServer: - if portType == constant.FlagPort { - return a.config.RpcPort.OpenImThirdPort[0] - } - if portType == constant.FlagPrometheusPort { - return a.config.Prometheus.ThirdPrometheusPort[0] - } - case RpcUserServer: - if portType == constant.FlagPort { - return a.config.RpcPort.OpenImUserPort[0] - } - if portType == constant.FlagPrometheusPort { - return a.config.Prometheus.UserPrometheusPort[0] - } - } - return 0 -} - -func (a *RpcCmd) GetRpcRegisterNameFromConfig() (string, error) { - switch a.Name { - case RpcPushServer: - return a.config.RpcRegisterName.OpenImPushName, nil - case RpcAuthServer: - return a.config.RpcRegisterName.OpenImAuthName, nil - case RpcConversationServer: - return a.config.RpcRegisterName.OpenImConversationName, nil - case RpcFriendServer: - return a.config.RpcRegisterName.OpenImFriendName, nil - case RpcGroupServer: - return a.config.RpcRegisterName.OpenImGroupName, nil - case RpcMsgServer: - return a.config.RpcRegisterName.OpenImMsgName, nil - case RpcThirdServer: - return a.config.RpcRegisterName.OpenImThirdName, nil - case RpcUserServer: - return a.config.RpcRegisterName.OpenImUserName, nil - } - return "", errs.Wrap(errors.New("can not get rpc register name"), a.Name) -} diff --git a/pkg/common/cmd/third.go b/pkg/common/cmd/third.go new file mode 100644 index 0000000000..0dfa7d5be5 --- /dev/null +++ b/pkg/common/cmd/third.go @@ -0,0 +1,62 @@ +// 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 + +import ( + "context" + "github.com/openimsdk/open-im-server/v3/internal/rpc/third" + "github.com/openimsdk/open-im-server/v3/pkg/common/config" + "github.com/openimsdk/open-im-server/v3/pkg/common/startrpc" + "github.com/openimsdk/tools/system/program" + "github.com/spf13/cobra" +) + +type ThirdRpcCmd struct { + *RootCmd + ctx context.Context + configMap map[string]any + thirdConfig *third.Config +} + +func NewThirdRpcCmd() *ThirdRpcCmd { + var thirdConfig third.Config + ret := &ThirdRpcCmd{thirdConfig: &thirdConfig} + ret.configMap = map[string]any{ + OpenIMRPCThirdCfgFileName: &thirdConfig.RpcConfig, + RedisConfigFileName: &thirdConfig.RedisConfig, + ZookeeperConfigFileName: &thirdConfig.ZookeeperConfig, + MongodbConfigFileName: &thirdConfig.MongodbConfig, + ShareFileName: &thirdConfig.Share, + NotificationFileName: &thirdConfig.NotificationConfig, + MinioConfigFileName: &thirdConfig.MinioConfig, + LocalCacheConfigFileName: &thirdConfig.LocalCacheConfig, + } + 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 *ThirdRpcCmd) Exec() error { + return a.Execute() +} + +func (a *ThirdRpcCmd) runE() error { + return startrpc.Start(a.ctx, &a.thirdConfig.ZookeeperConfig, &a.thirdConfig.RpcConfig.Prometheus, a.thirdConfig.RpcConfig.RPC.ListenIP, + a.thirdConfig.RpcConfig.RPC.RegisterIP, a.thirdConfig.RpcConfig.RPC.Ports, + a.Index(), a.thirdConfig.Share.RpcRegisterName.Third, &a.thirdConfig.Share, a.thirdConfig, third.Start) +} diff --git a/pkg/common/cmd/user.go b/pkg/common/cmd/user.go new file mode 100644 index 0000000000..315b93256c --- /dev/null +++ b/pkg/common/cmd/user.go @@ -0,0 +1,63 @@ +// 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 + +import ( + "context" + "github.com/openimsdk/open-im-server/v3/internal/rpc/user" + "github.com/openimsdk/open-im-server/v3/pkg/common/config" + "github.com/openimsdk/open-im-server/v3/pkg/common/startrpc" + "github.com/openimsdk/tools/system/program" + "github.com/spf13/cobra" +) + +type UserRpcCmd struct { + *RootCmd + ctx context.Context + configMap map[string]any + userConfig *user.Config +} + +func NewUserRpcCmd() *UserRpcCmd { + var userConfig user.Config + ret := &UserRpcCmd{userConfig: &userConfig} + ret.configMap = map[string]any{ + OpenIMRPCUserCfgFileName: &userConfig.RpcConfig, + RedisConfigFileName: &userConfig.RedisConfig, + ZookeeperConfigFileName: &userConfig.ZookeeperConfig, + MongodbConfigFileName: &userConfig.MongodbConfig, + KafkaConfigFileName: &userConfig.KafkaConfig, + ShareFileName: &userConfig.Share, + NotificationFileName: &userConfig.NotificationConfig, + WebhooksConfigFileName: &userConfig.WebhooksConfig, + LocalCacheConfigFileName: &userConfig.LocalCacheConfig, + } + 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 *UserRpcCmd) Exec() error { + return a.Execute() +} + +func (a *UserRpcCmd) runE() error { + return startrpc.Start(a.ctx, &a.userConfig.ZookeeperConfig, &a.userConfig.RpcConfig.Prometheus, a.userConfig.RpcConfig.RPC.ListenIP, + a.userConfig.RpcConfig.RPC.RegisterIP, a.userConfig.RpcConfig.RPC.Ports, + a.Index(), a.userConfig.Share.RpcRegisterName.User, &a.userConfig.Share, a.userConfig, user.Start) +} diff --git a/pkg/common/config/config.go b/pkg/common/config/config.go index 8bc8713551..19edccbab2 100644 --- a/pkg/common/config/config.go +++ b/pkg/common/config/config.go @@ -15,433 +15,509 @@ package config import ( - "bytes" + "fmt" + "github.com/openimsdk/tools/db/mongoutil" + "github.com/openimsdk/tools/db/redisutil" + "github.com/openimsdk/tools/mq/kafka" + "github.com/openimsdk/tools/s3/cos" + "github.com/openimsdk/tools/s3/minio" + "github.com/openimsdk/tools/s3/oss" "time" - - "github.com/OpenIMSDK/tools/discoveryregistry" - "gopkg.in/yaml.v3" ) -var Config GlobalConfig +type CacheConfig struct { + Topic string `mapstructure:"topic"` + SlotNum int `mapstructure:"slotNum"` + SlotSize int `mapstructure:"slotSize"` + SuccessExpire int `mapstructure:"successExpire"` + FailedExpire int `mapstructure:"failedExpire"` +} -const ConfKey = "conf" +type LocalCache struct { + User CacheConfig `mapstructure:"user"` + Group CacheConfig `mapstructure:"group"` + Friend CacheConfig `mapstructure:"friend"` + Conversation CacheConfig `mapstructure:"conversation"` +} -type CallBackConfig struct { - Enable bool `yaml:"enable"` - CallbackTimeOut int `yaml:"timeout"` - CallbackFailedContinue *bool `yaml:"failedContinue"` +type Log struct { + StorageLocation string `mapstructure:"storageLocation"` + RotationTime uint `mapstructure:"rotationTime"` + RemainRotationCount uint `mapstructure:"remainRotationCount"` + RemainLogLevel int `mapstructure:"remainLogLevel"` + IsStdout bool `mapstructure:"isStdout"` + IsJson bool `mapstructure:"isJson"` + WithStack bool `mapstructure:"withStack"` } -type NotificationConf struct { - IsSendMsg bool `yaml:"isSendMsg"` - ReliabilityLevel int `yaml:"reliabilityLevel"` // 1 online 2 persistent - UnreadCount bool `yaml:"unreadCount"` - OfflinePush POfflinePush `yaml:"offlinePush"` +type Minio struct { + Bucket string `mapstructure:"bucket"` + Port int `mapstructure:"port"` + AccessKeyID string `mapstructure:"accessKeyID"` + SecretAccessKey string `mapstructure:"secretAccessKey"` + SessionToken string `mapstructure:"sessionToken"` + InternalIP string `mapstructure:"internalIP"` + ExternalIP string `mapstructure:"externalIP"` + URL string `mapstructure:"url"` + PublicRead bool `mapstructure:"publicRead"` } -type POfflinePush struct { - Enable bool `yaml:"enable"` - Title string `yaml:"title"` - Desc string `yaml:"desc"` - Ext string `yaml:"ext"` +type Mongo struct { + URI string `mapstructure:"uri"` + Address []string `mapstructure:"address"` + Database string `mapstructure:"database"` + Username string `mapstructure:"username"` + Password string `mapstructure:"password"` + MaxPoolSize int `mapstructure:"maxPoolSize"` + MaxRetry int `mapstructure:"maxRetry"` +} +type Kafka struct { + Username string `mapstructure:"username"` + Password string `mapstructure:"password"` + ProducerAck string `mapstructure:"producerAck"` + CompressType string `mapstructure:"compressType"` + Address []string `mapstructure:"address"` + ToRedisTopic string `mapstructure:"toRedisTopic"` + ToMongoTopic string `mapstructure:"toMongoTopic"` + ToPushTopic string `mapstructure:"toPushTopic"` + ToRedisGroupID string `mapstructure:"toRedisGroupID"` + ToMongoGroupID string `mapstructure:"toMongoGroupID"` + ToPushGroupID string `mapstructure:"toPushGroupID"` + Tls TLSConfig `mapstructure:"tls"` +} +type TLSConfig struct { + EnableTLS bool `mapstructure:"enableTLS"` + CACrt string `mapstructure:"caCrt"` + ClientCrt string `mapstructure:"clientCrt"` + ClientKey string `mapstructure:"clientKey"` + ClientKeyPwd string `mapstructure:"clientKeyPwd"` + InsecureSkipVerify bool `mapstructure:"insecureSkipVerify"` } -type MYSQL struct { - Address []string `yaml:"address"` - Username string `yaml:"username"` - Password string `yaml:"password"` - Database string `yaml:"database"` - MaxOpenConn int `yaml:"maxOpenConn"` - MaxIdleConn int `yaml:"maxIdleConn"` - MaxLifeTime int `yaml:"maxLifeTime"` - LogLevel int `yaml:"logLevel"` - SlowThreshold int `yaml:"slowThreshold"` +type API struct { + Api struct { + ListenIP string `mapstructure:"listenIP"` + Ports []int `mapstructure:"ports"` + } `mapstructure:"api"` + Prometheus struct { + Enable bool `mapstructure:"enable"` + Ports []int `mapstructure:"ports"` + GrafanaURL string `mapstructure:"grafanaURL"` + } `mapstructure:"prometheus"` } -type GlobalConfig struct { - Envs struct { - Discovery string `yaml:"discovery"` - } - Zookeeper struct { - Schema string `yaml:"schema"` - ZkAddr []string `yaml:"address"` - Username string `yaml:"username"` - Password string `yaml:"password"` - } `yaml:"zookeeper"` - - Mysql *MYSQL `yaml:"mysql"` - - Mongo struct { - Uri string `yaml:"uri"` - Address []string `yaml:"address"` - Database string `yaml:"database"` - Username string `yaml:"username"` - Password string `yaml:"password"` - MaxPoolSize int `yaml:"maxPoolSize"` - } `yaml:"mongo"` - - Redis struct { - ClusterMode bool `yaml:"clusterMode"` - Address []string `yaml:"address"` - Username string `yaml:"username"` - Password string `yaml:"password"` - EnablePipeline bool `yaml:"enablePipeline"` - } `yaml:"redis"` - - Kafka struct { - Username string `yaml:"username"` - Password string `yaml:"password"` - ProducerAck string `yaml:"producerAck"` - CompressType string `yaml:"compressType"` - Addr []string `yaml:"addr"` - TLS *struct { - CACrt string `yaml:"caCrt"` - ClientCrt string `yaml:"clientCrt"` - ClientKey string `yaml:"clientKey"` - ClientKeyPwd string `yaml:"clientKeyPwd"` - InsecureSkipVerify bool `yaml:"insecureSkipVerify"` - } `yaml:"tls"` - LatestMsgToRedis struct { - Topic string `yaml:"topic"` - } `yaml:"latestMsgToRedis"` - MsgToMongo struct { - Topic string `yaml:"topic"` - } `yaml:"offlineMsgToMongo"` - MsgToPush struct { - Topic string `yaml:"topic"` - } `yaml:"msgToPush"` - ConsumerGroupID struct { - MsgToRedis string `yaml:"msgToRedis"` - MsgToMongo string `yaml:"msgToMongo"` - MsgToMySql string `yaml:"msgToMySql"` - MsgToPush string `yaml:"msgToPush"` - } `yaml:"consumerGroupID"` - } `yaml:"kafka"` - - Rpc struct { - RegisterIP string `yaml:"registerIP"` - ListenIP string `yaml:"listenIP"` - } `yaml:"rpc"` +type CronTask struct { + ChatRecordsClearTime string `mapstructure:"chatRecordsClearTime"` + MsgDestructTime string `mapstructure:"msgDestructTime"` + RetainChatRecords int `mapstructure:"retainChatRecords"` + EnableCronLocker bool `yaml:"enableCronLocker"` +} - Api struct { - OpenImApiPort []int `yaml:"openImApiPort"` - ListenIP string `yaml:"listenIP"` - } `yaml:"api"` - - Object struct { - Enable string `yaml:"enable"` - ApiURL string `yaml:"apiURL"` - Minio struct { - Bucket string `yaml:"bucket"` - Endpoint string `yaml:"endpoint"` - AccessKeyID string `yaml:"accessKeyID"` - SecretAccessKey string `yaml:"secretAccessKey"` - SessionToken string `yaml:"sessionToken"` - SignEndpoint string `yaml:"signEndpoint"` - PublicRead bool `yaml:"publicRead"` - } `yaml:"minio"` - Cos struct { - BucketURL string `yaml:"bucketURL"` - SecretID string `yaml:"secretID"` - SecretKey string `yaml:"secretKey"` - SessionToken string `yaml:"sessionToken"` - PublicRead bool `yaml:"publicRead"` - } `yaml:"cos"` - Oss struct { - Endpoint string `yaml:"endpoint"` - Bucket string `yaml:"bucket"` - BucketURL string `yaml:"bucketURL"` - AccessKeyID string `yaml:"accessKeyID"` - AccessKeySecret string `yaml:"accessKeySecret"` - SessionToken string `yaml:"sessionToken"` - PublicRead bool `yaml:"publicRead"` - } `yaml:"oss"` - Kodo struct { - Endpoint string `yaml:"endpoint"` - Bucket string `yaml:"bucket"` - BucketURL string `yaml:"bucketURL"` - AccessKeyID string `yaml:"accessKeyID"` - AccessKeySecret string `yaml:"accessKeySecret"` - SessionToken string `yaml:"sessionToken"` - PublicRead bool `yaml:"publicRead"` - } `yaml:"kodo"` - Aws struct { - Endpoint string `yaml:"endpoint"` - Region string `yaml:"region"` - Bucket string `yaml:"bucket"` - AccessKeyID string `yaml:"accessKeyID"` - AccessKeySecret string `yaml:"accessKeySecret"` - PublicRead bool `yaml:"publicRead"` - } `yaml:"aws"` - } `yaml:"object"` - - RpcPort struct { - OpenImUserPort []int `yaml:"openImUserPort"` - OpenImFriendPort []int `yaml:"openImFriendPort"` - OpenImMessagePort []int `yaml:"openImMessagePort"` - OpenImMessageGatewayPort []int `yaml:"openImMessageGatewayPort"` - OpenImGroupPort []int `yaml:"openImGroupPort"` - OpenImAuthPort []int `yaml:"openImAuthPort"` - OpenImPushPort []int `yaml:"openImPushPort"` - OpenImConversationPort []int `yaml:"openImConversationPort"` - OpenImRtcPort []int `yaml:"openImRtcPort"` - OpenImThirdPort []int `yaml:"openImThirdPort"` - } `yaml:"rpcPort"` - - RpcRegisterName struct { - OpenImUserName string `yaml:"openImUserName"` - OpenImFriendName string `yaml:"openImFriendName"` - OpenImMsgName string `yaml:"openImMsgName"` - OpenImPushName string `yaml:"openImPushName"` - OpenImMessageGatewayName string `yaml:"openImMessageGatewayName"` - OpenImGroupName string `yaml:"openImGroupName"` - OpenImAuthName string `yaml:"openImAuthName"` - OpenImConversationName string `yaml:"openImConversationName"` - OpenImThirdName string `yaml:"openImThirdName"` - } `yaml:"rpcRegisterName"` - - Log struct { - StorageLocation string `yaml:"storageLocation"` - RotationTime uint `yaml:"rotationTime"` - RemainRotationCount uint `yaml:"remainRotationCount"` - RemainLogLevel int `yaml:"remainLogLevel"` - IsStdout bool `yaml:"isStdout"` - IsJson bool `yaml:"isJson"` - WithStack bool `yaml:"withStack"` - } `yaml:"log"` +type OfflinePushConfig struct { + Enable bool `mapstructure:"enable"` + Title string `mapstructure:"title"` + Desc string `mapstructure:"desc"` + Ext string `mapstructure:"ext"` +} + +type NotificationConfig struct { + IsSendMsg bool `mapstructure:"isSendMsg"` + ReliabilityLevel int `mapstructure:"reliabilityLevel"` + UnreadCount bool `mapstructure:"unreadCount"` + OfflinePush OfflinePushConfig `mapstructure:"offlinePush"` +} + +type Notification struct { + GroupCreated NotificationConfig `mapstructure:"groupCreated"` + GroupInfoSet NotificationConfig `mapstructure:"groupInfoSet"` + JoinGroupApplication NotificationConfig `mapstructure:"joinGroupApplication"` + MemberQuit NotificationConfig `mapstructure:"memberQuit"` + GroupApplicationAccepted NotificationConfig `mapstructure:"groupApplicationAccepted"` + GroupApplicationRejected NotificationConfig `mapstructure:"groupApplicationRejected"` + GroupOwnerTransferred NotificationConfig `mapstructure:"groupOwnerTransferred"` + MemberKicked NotificationConfig `mapstructure:"memberKicked"` + MemberInvited NotificationConfig `mapstructure:"memberInvited"` + MemberEnter NotificationConfig `mapstructure:"memberEnter"` + GroupDismissed NotificationConfig `mapstructure:"groupDismissed"` + GroupMuted NotificationConfig `mapstructure:"groupMuted"` + GroupCancelMuted NotificationConfig `mapstructure:"groupCancelMuted"` + GroupMemberMuted NotificationConfig `mapstructure:"groupMemberMuted"` + GroupMemberCancelMuted NotificationConfig `mapstructure:"groupMemberCancelMuted"` + GroupMemberInfoSet NotificationConfig `mapstructure:"groupMemberInfoSet"` + GroupMemberSetToAdmin NotificationConfig `yaml:"groupMemberSetToAdmin"` + GroupMemberSetToOrdinary NotificationConfig `yaml:"groupMemberSetToOrdinaryUser"` + GroupInfoSetAnnouncement NotificationConfig `mapstructure:"groupInfoSetAnnouncement"` + GroupInfoSetName NotificationConfig `mapstructure:"groupInfoSetName"` + FriendApplicationAdded NotificationConfig `mapstructure:"friendApplicationAdded"` + FriendApplicationApproved NotificationConfig `mapstructure:"friendApplicationApproved"` + FriendApplicationRejected NotificationConfig `mapstructure:"friendApplicationRejected"` + FriendAdded NotificationConfig `mapstructure:"friendAdded"` + FriendDeleted NotificationConfig `mapstructure:"friendDeleted"` + FriendRemarkSet NotificationConfig `mapstructure:"friendRemarkSet"` + BlackAdded NotificationConfig `mapstructure:"blackAdded"` + BlackDeleted NotificationConfig `mapstructure:"blackDeleted"` + FriendInfoUpdated NotificationConfig `mapstructure:"friendInfoUpdated"` + UserInfoUpdated NotificationConfig `mapstructure:"userInfoUpdated"` + UserStatusChanged NotificationConfig `mapstructure:"userStatusChanged"` + ConversationChanged NotificationConfig `mapstructure:"conversationChanged"` + ConversationSetPrivate NotificationConfig `mapstructure:"conversationSetPrivate"` +} +type Prometheus struct { + Enable bool `mapstructure:"enable"` + Ports []int `mapstructure:"ports"` +} + +type MsgGateway struct { + RPC struct { + RegisterIP string `mapstructure:"registerIP"` + Ports []int `mapstructure:"ports"` + } `mapstructure:"rpc"` + Prometheus Prometheus `mapstructure:"prometheus"` + ListenIP string `mapstructure:"listenIP"` LongConnSvr struct { - OpenImMessageGatewayPort []int `yaml:"openImMessageGatewayPort"` - OpenImWsPort []int `yaml:"openImWsPort"` - WebsocketMaxConnNum int `yaml:"websocketMaxConnNum"` - WebsocketMaxMsgLen int `yaml:"websocketMaxMsgLen"` - WebsocketTimeout int `yaml:"websocketTimeout"` - WebsocketWriteBufferSize int `yaml:"websocketWriteBufferSize"` - } `yaml:"longConnSvr"` - - Push struct { - MaxConcurrentWorkers int `yaml:"maxConcurrentWorkers"` - Enable string `yaml:"enable"` - GeTui struct { - PushUrl string `yaml:"pushUrl"` - AppKey string `yaml:"appKey"` - Intent string `yaml:"intent"` - MasterSecret string `yaml:"masterSecret"` - ChannelID string `yaml:"channelID"` - ChannelName string `yaml:"channelName"` - } `yaml:"geTui"` - Fcm struct { - ServiceAccount string `yaml:"serviceAccount"` - } `yaml:"fcm"` - Jpns struct { - AppKey string `yaml:"appKey"` - MasterSecret string `yaml:"masterSecret"` - PushUrl string `yaml:"pushUrl"` - PushIntent string `yaml:"pushIntent"` - } `yaml:"jpns"` - } - Manager struct { - UserID []string `yaml:"userID"` - Nickname []string `yaml:"nickname"` - } `yaml:"manager"` - - IMAdmin struct { - UserID []string `yaml:"userID"` - Nickname []string `yaml:"nickname"` - } `yaml:"im-admin"` - - MultiLoginPolicy int `yaml:"multiLoginPolicy"` - ChatPersistenceMysql bool `yaml:"chatPersistenceMysql"` - MsgCacheTimeout int `yaml:"msgCacheTimeout"` - GroupMessageHasReadReceiptEnable bool `yaml:"groupMessageHasReadReceiptEnable"` - SingleMessageHasReadReceiptEnable bool `yaml:"singleMessageHasReadReceiptEnable"` - RetainChatRecords int `yaml:"retainChatRecords"` - ChatRecordsClearTime string `yaml:"chatRecordsClearTime"` - MsgDestructTime string `yaml:"msgDestructTime"` - Secret string `yaml:"secret"` - EnableCronLocker bool `yaml:"enableCronLocker"` - TokenPolicy struct { - Expire int64 `yaml:"expire"` - } `yaml:"tokenPolicy"` - MessageVerify struct { - FriendVerify *bool `yaml:"friendVerify"` - } `yaml:"messageVerify"` - - LocalCache localCache `yaml:"localCache"` + Ports []int `mapstructure:"ports"` + WebsocketMaxConnNum int `mapstructure:"websocketMaxConnNum"` + WebsocketMaxMsgLen int `mapstructure:"websocketMaxMsgLen"` + WebsocketTimeout int `mapstructure:"websocketTimeout"` + } `mapstructure:"longConnSvr"` + MultiLoginPolicy int `mapstructure:"multiLoginPolicy"` +} +type MsgTransfer struct { + Prometheus Prometheus `mapstructure:"prometheus"` +} + +type Push struct { + RPC struct { + RegisterIP string `mapstructure:"registerIP"` + ListenIP string `mapstructure:"listenIP"` + Ports []int `mapstructure:"ports"` + } `mapstructure:"rpc"` + Prometheus Prometheus `mapstructure:"prometheus"` + MaxConcurrentWorkers int `mapstructure:"maxConcurrentWorkers"` + Enable string `mapstructure:"enable"` + GeTui struct { + PushUrl string `mapstructure:"pushUrl"` + MasterSecret string `mapstructure:"masterSecret"` + AppKey string `mapstructure:"appKey"` + Intent string `mapstructure:"intent"` + ChannelID string `mapstructure:"channelID"` + ChannelName string `mapstructure:"channelName"` + } `mapstructure:"geTui"` + FCM struct { + ServiceAccount string `mapstructure:"serviceAccount"` + } `mapstructure:"fcm"` + JPNS struct { + AppKey string `mapstructure:"appKey"` + MasterSecret string `mapstructure:"masterSecret"` + PushURL string `mapstructure:"pushURL"` + PushIntent string `mapstructure:"pushIntent"` + } `mapstructure:"jpns"` IOSPush struct { - PushSound string `yaml:"pushSound"` - BadgeCount bool `yaml:"badgeCount"` - Production bool `yaml:"production"` - } `yaml:"iosPush"` - Callback struct { - CallbackUrl string `yaml:"url"` - CallbackBeforeSendSingleMsg CallBackConfig `yaml:"beforeSendSingleMsg"` - CallbackAfterSendSingleMsg CallBackConfig `yaml:"afterSendSingleMsg"` - CallbackBeforeSendGroupMsg CallBackConfig `yaml:"beforeSendGroupMsg"` - CallbackAfterSendGroupMsg CallBackConfig `yaml:"afterSendGroupMsg"` - CallbackMsgModify CallBackConfig `yaml:"msgModify"` - CallbackSingleMsgRead CallBackConfig `yaml:"singleMsgRead"` - CallbackGroupMsgRead CallBackConfig `yaml:"groupMsgRead"` - CallbackUserOnline CallBackConfig `yaml:"userOnline"` - CallbackUserOffline CallBackConfig `yaml:"userOffline"` - CallbackUserKickOff CallBackConfig `yaml:"userKickOff"` - CallbackOfflinePush CallBackConfig `yaml:"offlinePush"` - CallbackOnlinePush CallBackConfig `yaml:"onlinePush"` - CallbackBeforeSuperGroupOnlinePush CallBackConfig `yaml:"superGroupOnlinePush"` - CallbackBeforeAddFriend CallBackConfig `yaml:"beforeAddFriend"` - CallbackBeforeSetFriendRemark CallBackConfig `yaml:"callbackBeforeSetFriendRemark"` - CallbackAfterSetFriendRemark CallBackConfig `yaml:"callbackAfterSetFriendRemark"` - CallbackBeforeUpdateUserInfo CallBackConfig `yaml:"beforeUpdateUserInfo"` - CallbackBeforeUpdateUserInfoEx CallBackConfig `yaml:"beforeUpdateUserInfoEx"` - CallbackAfterUpdateUserInfoEx CallBackConfig `yaml:"afterUpdateUserInfoEx"` - CallbackBeforeUserRegister CallBackConfig `yaml:"beforeUserRegister"` - CallbackAfterUpdateUserInfo CallBackConfig `yaml:"updateUserInfo"` - CallbackAfterUserRegister CallBackConfig `yaml:"afterUserRegister"` - CallbackBeforeCreateGroup CallBackConfig `yaml:"beforeCreateGroup"` - CallbackAfterCreateGroup CallBackConfig `yaml:"afterCreateGroup"` - CallbackBeforeMemberJoinGroup CallBackConfig `yaml:"beforeMemberJoinGroup"` - CallbackBeforeSetGroupMemberInfo CallBackConfig `yaml:"beforeSetGroupMemberInfo"` - CallbackAfterSetGroupMemberInfo CallBackConfig `yaml:"afterSetGroupMemberInfo"` - CallbackQuitGroup CallBackConfig `yaml:"quitGroup"` - CallbackKillGroupMember CallBackConfig `yaml:"killGroupMember"` - CallbackDismissGroup CallBackConfig `yaml:"dismissGroup"` - CallbackBeforeJoinGroup CallBackConfig `yaml:"joinGroup"` - CallbackAfterTransferGroupOwner CallBackConfig `yaml:"transferGroupOwner"` - CallbackBeforeInviteUserToGroup CallBackConfig `yaml:"beforeInviteUserToGroup"` - CallbackAfterJoinGroup CallBackConfig `yaml:"joinGroupAfter"` - CallbackAfterSetGroupInfo CallBackConfig `yaml:"setGroupInfoAfter"` - CallbackBeforeSetGroupInfo CallBackConfig `yaml:"setGroupInfoBefore"` - CallbackAfterRevokeMsg CallBackConfig `yaml:"revokeMsgAfter"` - CallbackBeforeAddBlack CallBackConfig `yaml:"addBlackBefore"` - CallbackAfterAddFriend CallBackConfig `yaml:"addFriendAfter"` - CallbackBeforeAddFriendAgree CallBackConfig `yaml:"addFriendAgreeBefore"` - - CallbackAfterDeleteFriend CallBackConfig `yaml:"deleteFriendAfter"` - CallbackBeforeImportFriends CallBackConfig `yaml:"importFriendsBefore"` - CallbackAfterImportFriends CallBackConfig `yaml:"importFriendsAfter"` - CallbackAfterRemoveBlack CallBackConfig `yaml:"removeBlackAfter"` - } `yaml:"callback"` + PushSound string `mapstructure:"pushSound"` + BadgeCount bool `mapstructure:"badgeCount"` + Production bool `mapstructure:"production"` + } `mapstructure:"iosPush"` +} - Prometheus struct { - Enable bool `yaml:"enable"` - GrafanaUrl string `yaml:"grafanaUrl"` - ApiPrometheusPort []int `yaml:"apiPrometheusPort"` - UserPrometheusPort []int `yaml:"userPrometheusPort"` - FriendPrometheusPort []int `yaml:"friendPrometheusPort"` - MessagePrometheusPort []int `yaml:"messagePrometheusPort"` - MessageGatewayPrometheusPort []int `yaml:"messageGatewayPrometheusPort"` - GroupPrometheusPort []int `yaml:"groupPrometheusPort"` - AuthPrometheusPort []int `yaml:"authPrometheusPort"` - PushPrometheusPort []int `yaml:"pushPrometheusPort"` - ConversationPrometheusPort []int `yaml:"conversationPrometheusPort"` - RtcPrometheusPort []int `yaml:"rtcPrometheusPort"` - MessageTransferPrometheusPort []int `yaml:"messageTransferPrometheusPort"` - ThirdPrometheusPort []int `yaml:"thirdPrometheusPort"` - } `yaml:"prometheus"` - Notification notification `yaml:"notification"` -} - -func NewGlobalConfig() *GlobalConfig { - return &GlobalConfig{} -} - -type notification struct { - GroupCreated NotificationConf `yaml:"groupCreated"` - GroupInfoSet NotificationConf `yaml:"groupInfoSet"` - JoinGroupApplication NotificationConf `yaml:"joinGroupApplication"` - MemberQuit NotificationConf `yaml:"memberQuit"` - GroupApplicationAccepted NotificationConf `yaml:"groupApplicationAccepted"` - GroupApplicationRejected NotificationConf `yaml:"groupApplicationRejected"` - GroupOwnerTransferred NotificationConf `yaml:"groupOwnerTransferred"` - MemberKicked NotificationConf `yaml:"memberKicked"` - MemberInvited NotificationConf `yaml:"memberInvited"` - MemberEnter NotificationConf `yaml:"memberEnter"` - GroupDismissed NotificationConf `yaml:"groupDismissed"` - GroupMuted NotificationConf `yaml:"groupMuted"` - GroupCancelMuted NotificationConf `yaml:"groupCancelMuted"` - GroupMemberMuted NotificationConf `yaml:"groupMemberMuted"` - GroupMemberCancelMuted NotificationConf `yaml:"groupMemberCancelMuted"` - GroupMemberInfoSet NotificationConf `yaml:"groupMemberInfoSet"` - GroupMemberSetToAdmin NotificationConf `yaml:"groupMemberSetToAdmin"` - GroupMemberSetToOrdinary NotificationConf `yaml:"groupMemberSetToOrdinaryUser"` - GroupInfoSetAnnouncement NotificationConf `yaml:"groupInfoSetAnnouncement"` - GroupInfoSetName NotificationConf `yaml:"groupInfoSetName"` - ////////////////////////user/////////////////////// - UserInfoUpdated NotificationConf `yaml:"userInfoUpdated"` - UserStatusChanged NotificationConf `yaml:"userStatusChanged"` - //////////////////////friend/////////////////////// - FriendApplicationAdded NotificationConf `yaml:"friendApplicationAdded"` - FriendApplicationApproved NotificationConf `yaml:"friendApplicationApproved"` - FriendApplicationRejected NotificationConf `yaml:"friendApplicationRejected"` - FriendAdded NotificationConf `yaml:"friendAdded"` - FriendDeleted NotificationConf `yaml:"friendDeleted"` - FriendRemarkSet NotificationConf `yaml:"friendRemarkSet"` - BlackAdded NotificationConf `yaml:"blackAdded"` - BlackDeleted NotificationConf `yaml:"blackDeleted"` - FriendInfoUpdated NotificationConf `yaml:"friendInfoUpdated"` - //////////////////////conversation/////////////////////// - ConversationChanged NotificationConf `yaml:"conversationChanged"` - ConversationSetPrivate NotificationConf `yaml:"conversationSetPrivate"` +type Auth struct { + RPC struct { + RegisterIP string `mapstructure:"registerIP"` + ListenIP string `mapstructure:"listenIP"` + Ports []int `mapstructure:"ports"` + } `mapstructure:"rpc"` + Prometheus Prometheus `mapstructure:"prometheus"` + TokenPolicy struct { + Expire int64 `mapstructure:"expire"` + } `mapstructure:"tokenPolicy"` } -type LocalCache struct { - Topic string `yaml:"topic"` - SlotNum int `yaml:"slotNum"` - SlotSize int `yaml:"slotSize"` - SuccessExpire int `yaml:"successExpire"` // second - FailedExpire int `yaml:"failedExpire"` // second +type Conversation struct { + RPC struct { + RegisterIP string `mapstructure:"registerIP"` + ListenIP string `mapstructure:"listenIP"` + Ports []int `mapstructure:"ports"` + } `mapstructure:"rpc"` + Prometheus Prometheus `mapstructure:"prometheus"` } -func (l LocalCache) Failed() time.Duration { - return time.Second * time.Duration(l.FailedExpire) +type Friend struct { + RPC struct { + RegisterIP string `mapstructure:"registerIP"` + ListenIP string `mapstructure:"listenIP"` + Ports []int `mapstructure:"ports"` + } `mapstructure:"rpc"` + Prometheus Prometheus `mapstructure:"prometheus"` } -func (l LocalCache) Success() time.Duration { - return time.Second * time.Duration(l.SuccessExpire) +type Group struct { + RPC struct { + RegisterIP string `mapstructure:"registerIP"` + ListenIP string `mapstructure:"listenIP"` + Ports []int `mapstructure:"ports"` + } `mapstructure:"rpc"` + Prometheus Prometheus `mapstructure:"prometheus"` } -func (l LocalCache) Enable() bool { - return l.Topic != "" && l.SlotNum > 0 && l.SlotSize > 0 +type Msg struct { + RPC struct { + RegisterIP string `mapstructure:"registerIP"` + ListenIP string `mapstructure:"listenIP"` + Ports []int `mapstructure:"ports"` + } `mapstructure:"rpc"` + Prometheus Prometheus `mapstructure:"prometheus"` + FriendVerify bool `mapstructure:"friendVerify"` } -type localCache struct { - User LocalCache `yaml:"user"` - Group LocalCache `yaml:"group"` - Friend LocalCache `yaml:"friend"` - Conversation LocalCache `yaml:"conversation"` +type Third struct { + RPC struct { + RegisterIP string `mapstructure:"registerIP"` + ListenIP string `mapstructure:"listenIP"` + Ports []int `mapstructure:"ports"` + } `mapstructure:"rpc"` + Prometheus Prometheus `mapstructure:"prometheus"` + Object struct { + Enable string `mapstructure:"enable"` + Cos Cos `mapstructure:"cos"` + Oss Oss `mapstructure:"oss"` + Kodo struct { + Endpoint string `mapstructure:"endpoint"` + Bucket string `mapstructure:"bucket"` + BucketURL string `mapstructure:"bucketURL"` + AccessKeyID string `mapstructure:"accessKeyID"` + AccessKeySecret string `mapstructure:"accessKeySecret"` + SessionToken string `mapstructure:"sessionToken"` + PublicRead bool `mapstructure:"publicRead"` + } `mapstructure:"kodo"` + Aws struct { + Endpoint string `mapstructure:"endpoint"` + Region string `mapstructure:"region"` + Bucket string `mapstructure:"bucket"` + AccessKeyID string `mapstructure:"accessKeyID"` + AccessKeySecret string `mapstructure:"accessKeySecret"` + PublicRead bool `mapstructure:"publicRead"` + } `mapstructure:"aws"` + } `mapstructure:"object"` +} +type Cos struct { + BucketURL string `mapstructure:"bucketURL"` + SecretID string `mapstructure:"secretID"` + SecretKey string `mapstructure:"secretKey"` + SessionToken string `mapstructure:"sessionToken"` + PublicRead bool `mapstructure:"publicRead"` +} +type Oss struct { + Endpoint string `mapstructure:"endpoint"` + Bucket string `mapstructure:"bucket"` + BucketURL string `mapstructure:"bucketURL"` + AccessKeyID string `mapstructure:"accessKeyID"` + AccessKeySecret string `mapstructure:"accessKeySecret"` + SessionToken string `mapstructure:"sessionToken"` + PublicRead bool `mapstructure:"publicRead"` } -func (c *GlobalConfig) GetServiceNames() []string { +type User struct { + RPC struct { + RegisterIP string `mapstructure:"registerIP"` + ListenIP string `mapstructure:"listenIP"` + Ports []int `mapstructure:"ports"` + } `mapstructure:"rpc"` + Prometheus Prometheus `mapstructure:"prometheus"` +} + +type Redis struct { + Address []string `mapstructure:"address"` + Username string `mapstructure:"username"` + Password string `mapstructure:"password"` + EnablePipeline bool `mapstructure:"enablePipeline"` + ClusterMode bool `mapstructure:"clusterMode"` + DB int `mapstructure:"db"` + MaxRetry int `mapstructure:"MaxRetry"` +} + +type BeforeConfig struct { + Enable bool `mapstructure:"enable"` + Timeout int `mapstructure:"timeout"` + FailedContinue bool `mapstructure:"failedContinue"` +} + +type AfterConfig struct { + Enable bool `mapstructure:"enable"` + Timeout int `mapstructure:"timeout"` +} + +type Share struct { + Secret string `mapstructure:"secret"` + Env string `mapstructure:"env"` + RpcRegisterName RpcRegisterName `mapstructure:"rpcRegisterName"` + IMAdminUserID []string `mapstructure:"imAdminUserID"` +} +type RpcRegisterName struct { + User string `mapstructure:"user"` + Friend string `mapstructure:"friend"` + Msg string `mapstructure:"msg"` + Push string `mapstructure:"push"` + MessageGateway string `mapstructure:"messageGateway"` + Group string `mapstructure:"group"` + Auth string `mapstructure:"auth"` + Conversation string `mapstructure:"conversation"` + Third string `mapstructure:"third"` +} + +func (r *RpcRegisterName) GetServiceNames() []string { return []string{ - c.RpcRegisterName.OpenImUserName, - c.RpcRegisterName.OpenImFriendName, - c.RpcRegisterName.OpenImMsgName, - c.RpcRegisterName.OpenImPushName, - c.RpcRegisterName.OpenImMessageGatewayName, - c.RpcRegisterName.OpenImGroupName, - c.RpcRegisterName.OpenImAuthName, - c.RpcRegisterName.OpenImConversationName, - c.RpcRegisterName.OpenImThirdName, + r.User, + r.Friend, + r.Msg, + r.Push, + r.MessageGateway, + r.Group, + r.Auth, + r.Conversation, + r.Third, + } +} + +// FullConfig stores all configurations for before and after events +type Webhooks struct { + URL string `mapstructure:"url"` + BeforeSendSingleMsg BeforeConfig `mapstructure:"beforeSendSingleMsg"` + BeforeUpdateUserInfoEx BeforeConfig `mapstructure:"beforeUpdateUserInfoEx"` + AfterUpdateUserInfoEx AfterConfig `mapstructure:"afterUpdateUserInfoEx"` + AfterSendSingleMsg AfterConfig `mapstructure:"afterSendSingleMsg"` + BeforeSendGroupMsg BeforeConfig `mapstructure:"beforeSendGroupMsg"` + BeforeMsgModify BeforeConfig `mapstructure:"beforeMsgModify"` + AfterSendGroupMsg AfterConfig `mapstructure:"afterSendGroupMsg"` + AfterUserOnline AfterConfig `mapstructure:"afterUserOnline"` + AfterUserOffline AfterConfig `mapstructure:"afterUserOffline"` + AfterUserKickOff AfterConfig `mapstructure:"afterUserKickOff"` + BeforeOfflinePush BeforeConfig `mapstructure:"beforeOfflinePush"` + BeforeOnlinePush BeforeConfig `mapstructure:"beforeOnlinePush"` + BeforeGroupOnlinePush BeforeConfig `mapstructure:"beforeGroupOnlinePush"` + BeforeAddFriend BeforeConfig `mapstructure:"beforeAddFriend"` + BeforeUpdateUserInfo BeforeConfig `mapstructure:"beforeUpdateUserInfo"` + AfterUpdateUserInfo AfterConfig `mapstructure:"afterUpdateUserInfo"` + BeforeCreateGroup BeforeConfig `mapstructure:"beforeCreateGroup"` + AfterCreateGroup AfterConfig `mapstructure:"afterCreateGroup"` + BeforeMemberJoinGroup BeforeConfig `mapstructure:"beforeMemberJoinGroup"` + BeforeSetGroupMemberInfo BeforeConfig `mapstructure:"beforeSetGroupMemberInfo"` + AfterSetGroupMemberInfo AfterConfig `mapstructure:"afterSetGroupMemberInfo"` + AfterQuitGroup AfterConfig `mapstructure:"afterQuitGroup"` + AfterKickGroupMember AfterConfig `mapstructure:"afterKickGroupMember"` + AfterDismissGroup AfterConfig `mapstructure:"afterDismissGroup"` + BeforeApplyJoinGroup BeforeConfig `mapstructure:"beforeApplyJoinGroup"` + AfterGroupMsgRead AfterConfig `mapstructure:"afterGroupMsgRead"` + AfterSingleMsgRead AfterConfig `mapstructure:"afterSingleMsgRead"` + BeforeUserRegister BeforeConfig `mapstructure:"beforeUserRegister"` + AfterUserRegister AfterConfig `mapstructure:"afterUserRegister"` + AfterTransferGroupOwner AfterConfig `mapstructure:"afterTransferGroupOwner"` + BeforeSetFriendRemark BeforeConfig `mapstructure:"beforeSetFriendRemark"` + AfterSetFriendRemark AfterConfig `mapstructure:"afterSetFriendRemark"` + AfterGroupMsgRevoke AfterConfig `mapstructure:"afterGroupMsgRevoke"` + AfterJoinGroup AfterConfig `mapstructure:"afterJoinGroup"` + BeforeInviteUserToGroup BeforeConfig `mapstructure:"beforeInviteUserToGroup"` + AfterSetGroupInfo AfterConfig `mapstructure:"afterSetGroupInfo"` + BeforeSetGroupInfo BeforeConfig `mapstructure:"beforeSetGroupInfo"` + AfterRevokeMsg AfterConfig `mapstructure:"afterRevokeMsg"` + BeforeAddBlack BeforeConfig `mapstructure:"beforeAddBlack"` + AfterAddFriend AfterConfig `mapstructure:"afterAddFriend"` + BeforeAddFriendAgree BeforeConfig `mapstructure:"beforeAddFriendAgree"` + AfterDeleteFriend AfterConfig `mapstructure:"afterDeleteFriend"` + BeforeImportFriends BeforeConfig `mapstructure:"beforeImportFriends"` + AfterImportFriends AfterConfig `mapstructure:"afterImportFriends"` + AfterRemoveBlack AfterConfig `mapstructure:"afterRemoveBlack"` +} + +type ZooKeeper struct { + Schema string `mapstructure:"schema"` + Address []string `mapstructure:"address"` + Username string `mapstructure:"username"` + Password string `mapstructure:"password"` +} + +func (m *Mongo) Build() *mongoutil.Config { + return &mongoutil.Config{ + Uri: m.URI, + Address: m.Address, + Database: m.Database, + Username: m.Username, + Password: m.Password, + MaxPoolSize: m.MaxPoolSize, + MaxRetry: m.MaxRetry, + } +} + +func (r *Redis) Build() *redisutil.Config { + return &redisutil.Config{ + ClusterMode: r.ClusterMode, + Address: r.Address, + Username: r.Username, + Password: r.Password, + DB: r.DB, + MaxRetry: r.MaxRetry, } } -func (c *GlobalConfig) RegisterConf2Registry(registry discoveryregistry.SvcDiscoveryRegistry) error { - data, err := yaml.Marshal(c) - if err != nil { - return err +func (k *Kafka) Build() *kafka.Config { + return &kafka.Config{ + Username: k.Username, + Password: k.Password, + ProducerAck: k.ProducerAck, + CompressType: k.CompressType, + Addr: k.Address, + TLS: kafka.TLSConfig{ + EnableTLS: k.Tls.EnableTLS, + CACrt: k.Tls.CACrt, + ClientCrt: k.Tls.ClientCrt, + ClientKey: k.Tls.ClientKey, + ClientKeyPwd: k.Tls.ClientKeyPwd, + InsecureSkipVerify: k.Tls.InsecureSkipVerify, + }, } - return registry.RegisterConf2Registry(ConfKey, data) } +func (m *Minio) Build() *minio.Config { + return &minio.Config{ + Bucket: m.Bucket, + Endpoint: fmt.Sprintf("http://%s:%d", m.InternalIP, m.Port), + AccessKeyID: m.AccessKeyID, + SecretAccessKey: m.SecretAccessKey, + SessionToken: m.SessionToken, + SignEndpoint: fmt.Sprintf("http://%s:%d", m.ExternalIP, m.Port), + PublicRead: m.PublicRead, + } -func (c *GlobalConfig) GetConfFromRegistry(registry discoveryregistry.SvcDiscoveryRegistry) ([]byte, error) { - return registry.GetConfFromRegistry(ConfKey) +} +func (c *Cos) Build() *cos.Config { + return &cos.Config{ + BucketURL: c.BucketURL, + SecretID: c.SecretID, + SecretKey: c.SecretKey, + SessionToken: c.SessionToken, + PublicRead: c.PublicRead, + } } -func (c *GlobalConfig) EncodeConfig() []byte { - buf := bytes.NewBuffer(nil) - if err := yaml.NewEncoder(buf).Encode(c); err != nil { - panic(err) +func (o *Oss) Build() *oss.Config { + return &oss.Config{ + Endpoint: o.Endpoint, + Bucket: o.Bucket, + BucketURL: o.BucketURL, + AccessKeyID: o.AccessKeyID, + AccessKeySecret: o.AccessKeySecret, + SessionToken: o.SessionToken, + PublicRead: o.PublicRead, } - return buf.Bytes() +} + +func (l *CacheConfig) Failed() time.Duration { + return time.Second * time.Duration(l.FailedExpire) +} + +func (l *CacheConfig) Success() time.Duration { + return time.Second * time.Duration(l.SuccessExpire) +} + +func (l *CacheConfig) Enable() bool { + return l.Topic != "" && l.SlotNum > 0 && l.SlotSize > 0 } diff --git a/pkg/common/config/constant.go b/pkg/common/config/constant.go new file mode 100644 index 0000000000..f425a624ce --- /dev/null +++ b/pkg/common/config/constant.go @@ -0,0 +1,37 @@ +// 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 config + +const ConfKey = "conf" + +const ( + // DefaultDirPerm is used for creating general directories, allowing the owner to read, write, and execute, + // while the group and others can only read and execute. + DefaultDirPerm = 0755 + + // PrivateFilePerm is used for sensitive files, allowing only the owner to read and write. + PrivateFilePerm = 0600 + + // ExecFilePerm is used for executable files, allowing the owner to read, write, and execute, + // while the group and others can only read. + ExecFilePerm = 0754 + + // SharedDirPerm is used for shared directories, allowing the owner and group to read, write, and execute, + // with no permissions for others. + SharedDirPerm = 0770 + + // ReadOnlyDirPerm is used for read-only directories, allowing the owner, group, and others to only read. + ReadOnlyDirPerm = 0555 +) diff --git a/pkg/common/config/doc.go b/pkg/common/config/doc.go index 4b76cb9fa6..189a5b5834 100644 --- a/pkg/common/config/doc.go +++ b/pkg/common/config/doc.go @@ -1,4 +1,4 @@ -// Copyright © 2023 OpenIM. All rights reserved. +// 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. diff --git a/pkg/common/config/load_config.go b/pkg/common/config/load_config.go new file mode 100644 index 0000000000..9272896b45 --- /dev/null +++ b/pkg/common/config/load_config.go @@ -0,0 +1,27 @@ +package config + +import ( + "github.com/mitchellh/mapstructure" + "github.com/openimsdk/tools/errs" + "github.com/spf13/viper" + "strings" +) + +func LoadConfig(path string, envPrefix string, config any) error { + v := viper.New() + v.SetConfigFile(path) + v.SetEnvPrefix(envPrefix) + v.AutomaticEnv() + v.SetEnvKeyReplacer(strings.NewReplacer(".", "_")) + + if err := v.ReadInConfig(); err != nil { + return errs.WrapMsg(err, "failed to read config file", "path", path, "envPrefix", envPrefix) + } + + if err := v.Unmarshal(config, func(config *mapstructure.DecoderConfig) { + config.TagName = "mapstructure" + }); err != nil { + return errs.WrapMsg(err, "failed to unmarshal config", "path", path, "envPrefix", envPrefix) + } + return nil +} diff --git a/pkg/common/config/load_config_test.go b/pkg/common/config/load_config_test.go new file mode 100644 index 0000000000..575448393f --- /dev/null +++ b/pkg/common/config/load_config_test.go @@ -0,0 +1,36 @@ +package config + +import ( + "github.com/stretchr/testify/assert" + "testing" +) + +func TestLoadLogConfig(t *testing.T) { + var log Log + err := LoadConfig("../../../config/log.yml", "IMENV_LOG", &log) + assert.Nil(t, err) + assert.Equal(t, "../../../../logs/", log.StorageLocation) +} + +func TestLoadMinioConfig(t *testing.T) { + var storageConfig Minio + err := LoadConfig("../../../config/minio.yml", "IMENV_MINIO", &storageConfig) + assert.Nil(t, err) + assert.Equal(t, "openim", storageConfig.Bucket) +} + +func TestLoadWebhooksConfig(t *testing.T) { + var webhooks Webhooks + err := LoadConfig("../../../config/webhooks.yml", "IMENV_WEBHOOKS", &webhooks) + assert.Nil(t, err) + assert.Equal(t, 5, webhooks.BeforeAddBlack.Timeout) + +} + +func TestLoadOpenIMRpcUserConfig(t *testing.T) { + var user User + err := LoadConfig("../../../config/openim-rpc-user.yml", "IMENV_OPENIM_RPC_USER", &user) + assert.Nil(t, err) + assert.Equal(t, "0.0.0.0", user.RPC.ListenIP) + assert.Equal(t, []int{10110}, user.RPC.Ports) +} diff --git a/pkg/common/config/parse.go b/pkg/common/config/parse.go index bfbf6daf7b..28e9f5db60 100644 --- a/pkg/common/config/parse.go +++ b/pkg/common/config/parse.go @@ -16,15 +16,14 @@ package config import ( _ "embed" - "fmt" "os" "path/filepath" - "github.com/OpenIMSDK/protocol/constant" - "gopkg.in/yaml.v3" - "github.com/openimsdk/open-im-server/v3/pkg/msgprocessor" - "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" + "github.com/openimsdk/protocol/constant" + "github.com/openimsdk/tools/errs" + "github.com/openimsdk/tools/field" + "gopkg.in/yaml.v3" ) //go:embed version @@ -37,34 +36,33 @@ const ( ) // return absolude path join ../config/, this is k8s container config path. -func GetDefaultConfigPath() string { +func GetDefaultConfigPath() (string, error) { executablePath, err := os.Executable() if err != nil { - fmt.Println("GetDefaultConfigPath error:", err.Error()) - return "" + return "", errs.WrapMsg(err, "failed to get executable path") } - configPath, err := genutil.OutDir(filepath.Join(filepath.Dir(executablePath), "../config/")) + configPath, err := field.OutDir(filepath.Join(filepath.Dir(executablePath), "../config/")) if err != nil { - fmt.Fprintf(os.Stderr, "failed to get output directory: %v\n", err) - os.Exit(1) + return "", errs.WrapMsg(err, "failed to get output directory", "outDir", filepath.Join(filepath.Dir(executablePath), "../config/")) } - return configPath + return configPath, nil } // getProjectRoot returns the absolute path of the project root directory. -func GetProjectRoot() string { - executablePath, _ := os.Executable() - - projectRoot, err := genutil.OutDir(filepath.Join(filepath.Dir(executablePath), "../../../../..")) +func GetProjectRoot() (string, error) { + executablePath, err := os.Executable() + if err != nil { + return "", errs.Wrap(err) + } + projectRoot, err := field.OutDir(filepath.Join(filepath.Dir(executablePath), "../../../../..")) if err != nil { - fmt.Fprintf(os.Stderr, "failed to get output directory: %v\n", err) - os.Exit(1) + return "", errs.Wrap(err) } - return projectRoot + return projectRoot, nil } -func GetOptionsByNotification(cfg NotificationConf) msgprocessor.Options { +func GetOptionsByNotification(cfg NotificationConfig) msgprocessor.Options { opts := msgprocessor.NewOptions() if cfg.UnreadCount { @@ -91,37 +89,21 @@ func initConfig(config any, configName, configFolderPath string) error { _, err := os.Stat(configFolderPath) if err != nil { if !os.IsNotExist(err) { - fmt.Println("stat config path error:", err.Error()) - return fmt.Errorf("stat config path error: %w", err) + return errs.WrapMsg(err, "stat config path error", "config Folder Path", configFolderPath) + } + path, err := GetProjectRoot() + if err != nil { + return err } - configFolderPath = filepath.Join(GetProjectRoot(), "config", configName) - fmt.Println("flag's path,enviment's path,default path all is not exist,using project path:", configFolderPath) + configFolderPath = filepath.Join(path, "config", configName) } data, err := os.ReadFile(configFolderPath) if err != nil { - return fmt.Errorf("read file error: %w", err) + return errs.WrapMsg(err, "read file error", "config Folder Path", configFolderPath) } if err = yaml.Unmarshal(data, config); err != nil { - return fmt.Errorf("unmarshal yaml error: %w", err) + return errs.WrapMsg(err, "unmarshal yaml error", "config Folder Path", configFolderPath) } - fmt.Println("The path of the configuration file to start the process:", configFolderPath) return nil } - -func InitConfig(config *GlobalConfig, configFolderPath string) error { - if configFolderPath == "" { - envConfigPath := os.Getenv("OPENIMCONFIG") - if envConfigPath != "" { - configFolderPath = envConfigPath - } else { - configFolderPath = GetDefaultConfigPath() - } - } - - if err := initConfig(config, FileName, configFolderPath); err != nil { - return err - } - - return initConfig(&config.Notification, NotificationFileName, configFolderPath) -} diff --git a/pkg/common/config/parse_test.go b/pkg/common/config/parse_test.go deleted file mode 100644 index 35b019b837..0000000000 --- a/pkg/common/config/parse_test.go +++ /dev/null @@ -1,131 +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 config - -import ( - _ "embed" - "fmt" - "reflect" - "testing" - - "gopkg.in/yaml.v3" - - "github.com/openimsdk/open-im-server/v3/pkg/msgprocessor" -) - -func TestGetDefaultConfigPath(t *testing.T) { - tests := []struct { - name string - want string - }{ - // TODO: Add test cases. - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got, _ := GetDefaultConfigPath(); got != tt.want { - t.Errorf("GetDefaultConfigPath() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestGetProjectRoot(t *testing.T) { - tests := []struct { - name string - want string - }{ - // TODO: Add test cases. - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got, _ := GetProjectRoot(); got != tt.want { - t.Errorf("GetProjectRoot() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestGetOptionsByNotification(t *testing.T) { - type args struct { - cfg NotificationConf - } - tests := []struct { - name string - args args - want msgprocessor.Options - }{ - // TODO: Add test cases. - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := GetOptionsByNotification(tt.args.cfg); !reflect.DeepEqual(got, tt.want) { - t.Errorf("GetOptionsByNotification() = %v, want %v", got, tt.want) - } - }) - } -} - -func Test_initConfig(t *testing.T) { - type args struct { - config any - configName string - configFolderPath string - } - tests := []struct { - name string - args args - wantErr bool - }{ - // TODO: Add test cases. - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if err := initConfig(tt.args.config, tt.args.configName, tt.args.configFolderPath); (err != nil) != tt.wantErr { - t.Errorf("initConfig() error = %v, wantErr %v", err, tt.wantErr) - } - }) - } -} - -func TestInitConfig(t *testing.T) { - type args struct { - configFolderPath string - } - tests := []struct { - name string - args args - config *GlobalConfig - wantErr bool - }{ - // TODO: Add test cases. - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if err := InitConfig(tt.config, tt.args.configFolderPath); (err != nil) != tt.wantErr { - t.Errorf("InitConfig() error = %v, wantErr %v", err, tt.wantErr) - } - }) - } -} - -func TestName(t *testing.T) { - Config.LocalCache.Friend.Topic = "friend" - Config.LocalCache.Friend.SlotNum = 500 - Config.LocalCache.Friend.SlotSize = 20000 - - data, _ := yaml.Marshal(&Config) - - fmt.Println(string(data)) -} diff --git a/pkg/common/config/version b/pkg/common/config/version index 40c341bdcd..084e244cea 100644 --- a/pkg/common/config/version +++ b/pkg/common/config/version @@ -1 +1 @@ -3.6.0 +3.6.0 \ No newline at end of file diff --git a/pkg/common/convert/black.go b/pkg/common/convert/black.go index 683517fbca..635b1a5862 100644 --- a/pkg/common/convert/black.go +++ b/pkg/common/convert/black.go @@ -17,9 +17,9 @@ package convert import ( "context" - "github.com/OpenIMSDK/protocol/sdkws" - sdk "github.com/OpenIMSDK/protocol/sdkws" "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" + "github.com/openimsdk/protocol/sdkws" + sdk "github.com/openimsdk/protocol/sdkws" ) func BlackDB2Pb(ctx context.Context, blackDBs []*relation.BlackModel, f func(ctx context.Context, userIDs []string) (map[string]*sdkws.UserInfo, error)) (blackPbs []*sdk.BlackInfo, err error) { diff --git a/pkg/common/convert/conversation.go b/pkg/common/convert/conversation.go index b3f4913ebb..510f40d700 100644 --- a/pkg/common/convert/conversation.go +++ b/pkg/common/convert/conversation.go @@ -15,15 +15,15 @@ package convert import ( - "github.com/OpenIMSDK/protocol/conversation" - "github.com/OpenIMSDK/tools/utils" "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" + "github.com/openimsdk/protocol/conversation" + "github.com/openimsdk/tools/utils/datautil" ) func ConversationDB2Pb(conversationDB *relation.ConversationModel) *conversation.Conversation { conversationPB := &conversation.Conversation{} conversationPB.LatestMsgDestructTime = conversationDB.LatestMsgDestructTime.Unix() - if err := utils.CopyStructFields(conversationPB, conversationDB); err != nil { + if err := datautil.CopyStructFields(conversationPB, conversationDB); err != nil { return nil } return conversationPB @@ -32,7 +32,7 @@ func ConversationDB2Pb(conversationDB *relation.ConversationModel) *conversation func ConversationsDB2Pb(conversationsDB []*relation.ConversationModel) (conversationsPB []*conversation.Conversation) { for _, conversationDB := range conversationsDB { conversationPB := &conversation.Conversation{} - if err := utils.CopyStructFields(conversationPB, conversationDB); err != nil { + if err := datautil.CopyStructFields(conversationPB, conversationDB); err != nil { continue } conversationPB.LatestMsgDestructTime = conversationDB.LatestMsgDestructTime.Unix() @@ -43,7 +43,7 @@ func ConversationsDB2Pb(conversationsDB []*relation.ConversationModel) (conversa func ConversationPb2DB(conversationPB *conversation.Conversation) *relation.ConversationModel { conversationDB := &relation.ConversationModel{} - if err := utils.CopyStructFields(conversationDB, conversationPB); err != nil { + if err := datautil.CopyStructFields(conversationDB, conversationPB); err != nil { return nil } return conversationDB @@ -52,7 +52,7 @@ func ConversationPb2DB(conversationPB *conversation.Conversation) *relation.Conv func ConversationsPb2DB(conversationsPB []*conversation.Conversation) (conversationsDB []*relation.ConversationModel) { for _, conversationPB := range conversationsPB { conversationDB := &relation.ConversationModel{} - if err := utils.CopyStructFields(conversationDB, conversationPB); err != nil { + if err := datautil.CopyStructFields(conversationDB, conversationPB); err != nil { continue } conversationsDB = append(conversationsDB, conversationDB) diff --git a/pkg/common/convert/doc.go b/pkg/common/convert/doc.go index 29c1144c1a..623b4a5c05 100644 --- a/pkg/common/convert/doc.go +++ b/pkg/common/convert/doc.go @@ -1,4 +1,4 @@ -// Copyright © 2023 OpenIM. All rights reserved. +// 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. diff --git a/pkg/common/convert/friend.go b/pkg/common/convert/friend.go index 4231eb49d1..ad8f9071e1 100644 --- a/pkg/common/convert/friend.go +++ b/pkg/common/convert/friend.go @@ -18,19 +18,20 @@ import ( "context" "fmt" - "github.com/OpenIMSDK/protocol/sdkws" - "github.com/OpenIMSDK/tools/utils" "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" + "github.com/openimsdk/protocol/sdkws" + "github.com/openimsdk/tools/utils/datautil" + "github.com/openimsdk/tools/utils/timeutil" ) func FriendPb2DB(friend *sdkws.FriendInfo) *relation.FriendModel { dbFriend := &relation.FriendModel{} - err := utils.CopyStructFields(dbFriend, friend) + err := datautil.CopyStructFields(dbFriend, friend) if err != nil { return nil } dbFriend.FriendUserID = friend.FriendUser.UserID - dbFriend.CreateTime = utils.UnixSecondToTime(friend.CreateTime) + dbFriend.CreateTime = timeutil.UnixSecondToTime(friend.CreateTime) return dbFriend } @@ -71,7 +72,7 @@ func FriendsDB2Pb( } for _, friend := range friendsDB { friendPb := &sdkws.FriendInfo{FriendUser: &sdkws.UserInfo{}} - err := utils.CopyStructFields(friendPb, friend) + err := datautil.CopyStructFields(friendPb, friend) if err != nil { return nil, err } @@ -88,10 +89,7 @@ func FriendsDB2Pb( } -func FriendRequestDB2Pb(ctx context.Context, - friendRequests []*relation.FriendRequestModel, - getUsers func(ctx context.Context, userIDs []string) (map[string]*sdkws.UserInfo, error), -) ([]*sdkws.FriendRequest, error) { +func FriendRequestDB2Pb(ctx context.Context, friendRequests []*relation.FriendRequestModel, getUsers func(ctx context.Context, userIDs []string) (map[string]*sdkws.UserInfo, error)) ([]*sdkws.FriendRequest, error) { if len(friendRequests) == 0 { return nil, nil } @@ -100,7 +98,7 @@ func FriendRequestDB2Pb(ctx context.Context, userIDMap[friendRequest.ToUserID] = struct{}{} userIDMap[friendRequest.FromUserID] = struct{}{} } - users, err := getUsers(ctx, utils.Keys(userIDMap)) + users, err := getUsers(ctx, datautil.Keys(userIDMap)) if err != nil { return nil, err } diff --git a/pkg/common/convert/group.go b/pkg/common/convert/group.go index 63372f21dc..9b7353cfdc 100644 --- a/pkg/common/convert/group.go +++ b/pkg/common/convert/group.go @@ -17,9 +17,9 @@ package convert import ( "time" - pbgroup "github.com/OpenIMSDK/protocol/group" - sdkws "github.com/OpenIMSDK/protocol/sdkws" "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" + pbgroup "github.com/openimsdk/protocol/group" + sdkws "github.com/openimsdk/protocol/sdkws" ) func Db2PbGroupInfo(m *relation.GroupModel, ownerUserID string, memberCount uint32) *sdkws.GroupInfo { @@ -55,12 +55,7 @@ func Pb2DbGroupRequest(req *pbgroup.GroupApplicationResponseReq, handleUserID st } } -func Db2PbCMSGroup( - m *relation.GroupModel, - ownerUserID string, - ownerUserName string, - memberCount uint32, -) *pbgroup.CMSGroup { +func Db2PbCMSGroup(m *relation.GroupModel, ownerUserID string, ownerUserName string, memberCount uint32) *pbgroup.CMSGroup { return &pbgroup.CMSGroup{ GroupInfo: Db2PbGroupInfo(m, ownerUserID, memberCount), GroupOwnerUserID: ownerUserID, @@ -85,11 +80,7 @@ func Db2PbGroupMember(m *relation.GroupMemberModel) *sdkws.GroupMemberFullInfo { } } -func Db2PbGroupRequest( - m *relation.GroupRequestModel, - user *sdkws.PublicUserInfo, - group *sdkws.GroupInfo, -) *sdkws.GroupRequest { +func Db2PbGroupRequest(m *relation.GroupRequestModel, user *sdkws.PublicUserInfo, group *sdkws.GroupInfo) *sdkws.GroupRequest { return &sdkws.GroupRequest{ UserInfo: user, GroupInfo: group, @@ -137,7 +128,7 @@ func Pb2DBGroupInfo(m *sdkws.GroupInfo) *relation.GroupModel { } } -//func Pb2DbGroupMember(m *sdkws.UserInfo) *relation.GroupMemberModel { +// func Pb2DbGroupMember(m *sdkws.UserInfo) *relation.GroupMemberModel { // return &relation.GroupMemberModel{ // UserID: m.UserID, // Nickname: m.Nickname, diff --git a/pkg/common/convert/msg.go b/pkg/common/convert/msg.go index 34638049b2..594a0ffc2c 100644 --- a/pkg/common/convert/msg.go +++ b/pkg/common/convert/msg.go @@ -15,16 +15,16 @@ package convert import ( - "github.com/OpenIMSDK/protocol/constant" - "github.com/OpenIMSDK/protocol/sdkws" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/unrelation" + "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" + "github.com/openimsdk/protocol/constant" + "github.com/openimsdk/protocol/sdkws" ) -func MsgPb2DB(msg *sdkws.MsgData) *unrelation.MsgDataModel { +func MsgPb2DB(msg *sdkws.MsgData) *relation.MsgDataModel { if msg == nil { return nil } - var msgDataModel unrelation.MsgDataModel + var msgDataModel relation.MsgDataModel msgDataModel.SendID = msg.SendID msgDataModel.RecvID = msg.RecvID msgDataModel.GroupID = msg.GroupID @@ -43,7 +43,7 @@ func MsgPb2DB(msg *sdkws.MsgData) *unrelation.MsgDataModel { msgDataModel.Status = msg.Status msgDataModel.Options = msg.Options if msg.OfflinePushInfo != nil { - msgDataModel.OfflinePush = &unrelation.OfflinePushModel{ + msgDataModel.OfflinePush = &relation.OfflinePushModel{ Title: msg.OfflinePushInfo.Title, Desc: msg.OfflinePushInfo.Desc, Ex: msg.OfflinePushInfo.Ex, @@ -57,7 +57,7 @@ func MsgPb2DB(msg *sdkws.MsgData) *unrelation.MsgDataModel { return &msgDataModel } -func MsgDB2Pb(msgModel *unrelation.MsgDataModel) *sdkws.MsgData { +func MsgDB2Pb(msgModel *relation.MsgDataModel) *sdkws.MsgData { if msgModel == nil { return nil } diff --git a/pkg/common/convert/user.go b/pkg/common/convert/user.go index 38afd8c199..a9378e1a0f 100644 --- a/pkg/common/convert/user.go +++ b/pkg/common/convert/user.go @@ -17,8 +17,8 @@ package convert import ( "time" - "github.com/OpenIMSDK/protocol/sdkws" relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" + "github.com/openimsdk/protocol/sdkws" ) func UsersDB2Pb(users []*relationtb.UserModel) []*sdkws.UserInfo { diff --git a/pkg/common/convert/user_test.go b/pkg/common/convert/user_test.go index a24efb53cc..88eb812d27 100644 --- a/pkg/common/convert/user_test.go +++ b/pkg/common/convert/user_test.go @@ -18,7 +18,7 @@ import ( "reflect" "testing" - "github.com/OpenIMSDK/protocol/sdkws" + "github.com/openimsdk/protocol/sdkws" relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" ) diff --git a/pkg/common/db/cache/black.go b/pkg/common/db/cache/black.go index a5304b4b0d..615f2cbf1e 100644 --- a/pkg/common/db/cache/black.go +++ b/pkg/common/db/cache/black.go @@ -18,11 +18,11 @@ import ( "context" "time" - "github.com/OpenIMSDK/tools/log" "github.com/dtm-labs/rockscache" "github.com/openimsdk/open-im-server/v3/pkg/common/cachekey" "github.com/openimsdk/open-im-server/v3/pkg/common/config" relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" + "github.com/openimsdk/tools/log" "github.com/redis/go-redis/v9" ) @@ -48,10 +48,10 @@ type BlackCacheRedis struct { blackDB relationtb.BlackModelInterface } -func NewBlackCacheRedis(rdb redis.UniversalClient, blackDB relationtb.BlackModelInterface, options rockscache.Options) BlackCache { +func NewBlackCacheRedis(rdb redis.UniversalClient, localCache *config.LocalCache, blackDB relationtb.BlackModelInterface, options rockscache.Options) BlackCache { rcClient := rockscache.NewClient(rdb, options) mc := NewMetaCacheRedis(rcClient) - b := config.Config.LocalCache.Friend + b := localCache.Friend log.ZDebug(context.Background(), "black local cache init", "Topic", b.Topic, "SlotNum", b.SlotNum, "SlotSize", b.SlotSize, "enable", b.Enable()) mc.SetTopic(b.Topic) mc.SetRawRedisClient(rdb) diff --git a/pkg/common/db/cache/config.go b/pkg/common/db/cache/config.go index c760e0c033..bb5bd449b9 100644 --- a/pkg/common/db/cache/config.go +++ b/pkg/common/db/cache/config.go @@ -27,29 +27,26 @@ var ( subscribe map[string][]string ) -func getPublishKey(topic string, key []string) []string { - if topic == "" || len(key) == 0 { - return nil - } +func InitLocalCache(localCache *config.LocalCache) { once.Do(func() { list := []struct { - Local config.LocalCache + Local config.CacheConfig Keys []string }{ { - Local: config.Config.LocalCache.User, + Local: localCache.User, Keys: []string{cachekey.UserInfoKey, cachekey.UserGlobalRecvMsgOptKey}, }, { - Local: config.Config.LocalCache.Group, + Local: localCache.Group, Keys: []string{cachekey.GroupMemberIDsKey, cachekey.GroupInfoKey, cachekey.GroupMemberInfoKey}, }, { - Local: config.Config.LocalCache.Friend, + Local: localCache.Friend, Keys: []string{cachekey.FriendIDsKey, cachekey.BlackIDsKey}, }, { - Local: config.Config.LocalCache.Conversation, + Local: localCache.Conversation, Keys: []string{cachekey.ConversationKey, cachekey.ConversationIDsKey, cachekey.ConversationNotReceiveMessageUserIDsKey}, }, } @@ -60,6 +57,12 @@ func getPublishKey(topic string, key []string) []string { } } }) +} + +func getPublishKey(topic string, key []string) []string { + if topic == "" || len(key) == 0 { + return nil + } prefix, ok := subscribe[topic] if !ok { return nil diff --git a/pkg/common/db/cache/conversation.go b/pkg/common/db/cache/conversation.go index c8f752cd39..bd189f2a9c 100644 --- a/pkg/common/db/cache/conversation.go +++ b/pkg/common/db/cache/conversation.go @@ -20,24 +20,25 @@ import ( "strings" "time" - "github.com/OpenIMSDK/tools/log" - "github.com/OpenIMSDK/tools/utils" "github.com/dtm-labs/rockscache" "github.com/openimsdk/open-im-server/v3/pkg/common/cachekey" "github.com/openimsdk/open-im-server/v3/pkg/common/config" relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" + "github.com/openimsdk/tools/log" + "github.com/openimsdk/tools/utils/datautil" + "github.com/openimsdk/tools/utils/encrypt" "github.com/redis/go-redis/v9" ) const ( - //conversationKey = "CONVERSATION:" - //conversationIDsKey = "CONVERSATION_IDS:" - //conversationIDsHashKey = "CONVERSATION_IDS_HASH:" - //conversationHasReadSeqKey = "CONVERSATION_HAS_READ_SEQ:" - //recvMsgOptKey = "RECV_MSG_OPT:" - //superGroupRecvMsgNotNotifyUserIDsKey = "SUPER_GROUP_RECV_MSG_NOT_NOTIFY_USER_IDS:" - //superGroupRecvMsgNotNotifyUserIDsHashKey = "SUPER_GROUP_RECV_MSG_NOT_NOTIFY_USER_IDS_HASH:" - //conversationNotReceiveMessageUserIDsKey = "CONVERSATION_NOT_RECEIVE_MESSAGE_USER_IDS:". + // ConversationKey = "CONVERSATION:" + // conversationIDsKey = "CONVERSATION_IDS:" + // conversationIDsHashKey = "CONVERSATION_IDS_HASH:" + // conversationHasReadSeqKey = "CONVERSATION_HAS_READ_SEQ:" + // recvMsgOptKey = "RECV_MSG_OPT:" + // superGroupRecvMsgNotNotifyUserIDsKey = "SUPER_GROUP_RECV_MSG_NOT_NOTIFY_USER_IDS:" + // superGroupRecvMsgNotNotifyUserIDsHashKey = "SUPER_GROUP_RECV_MSG_NOT_NOTIFY_USER_IDS_HASH:" + // conversationNotReceiveMessageUserIDsKey = "CONVERSATION_NOT_RECEIVE_MESSAGE_USER_IDS:". conversationExpireTime = time.Second * 60 * 60 * 12 ) @@ -66,13 +67,13 @@ type ConversationCache interface { GetUserRecvMsgOpt(ctx context.Context, ownerUserID, conversationID string) (opt int, err error) DelUserRecvMsgOpt(ownerUserID, conversationID string) ConversationCache // get one super group recv msg but do not notification userID list - //GetSuperGroupRecvMsgNotNotifyUserIDs(ctx context.Context, groupID string) (userIDs []string, err error) + // GetSuperGroupRecvMsgNotNotifyUserIDs(ctx context.Context, groupID string) (userIDs []string, err error) DelSuperGroupRecvMsgNotNotifyUserIDs(groupID string) ConversationCache // get one super group recv msg but do not notification userID list hash - //GetSuperGroupRecvMsgNotNotifyUserIDsHash(ctx context.Context, groupID string) (hash uint64, err error) + // GetSuperGroupRecvMsgNotNotifyUserIDsHash(ctx context.Context, groupID string) (hash uint64, err error) DelSuperGroupRecvMsgNotNotifyUserIDsHash(groupID string) ConversationCache - //GetUserAllHasReadSeqs(ctx context.Context, ownerUserID string) (map[string]int64, error) + // GetUserAllHasReadSeqs(ctx context.Context, ownerUserID string) (map[string]int64, error) DelUserAllHasReadSeqs(ownerUserID string, conversationIDs ...string) ConversationCache GetConversationsByConversationID(ctx context.Context, @@ -82,10 +83,10 @@ type ConversationCache interface { DelConversationNotReceiveMessageUserIDs(conversationIDs ...string) ConversationCache } -func NewConversationRedis(rdb redis.UniversalClient, opts rockscache.Options, db relationtb.ConversationModelInterface) ConversationCache { +func NewConversationRedis(rdb redis.UniversalClient, localCache *config.LocalCache, opts rockscache.Options, db relationtb.ConversationModelInterface) ConversationCache { rcClient := rockscache.NewClient(rdb, opts) mc := NewMetaCacheRedis(rcClient) - c := config.Config.LocalCache.Conversation + c := localCache.Conversation log.ZDebug(context.Background(), "black local cache init", "Topic", c.Topic, "SlotNum", c.SlotNum, "SlotSize", c.SlotSize, "enable", c.Enable()) mc.SetTopic(c.Topic) mc.SetRawRedisClient(rdb) @@ -104,11 +105,11 @@ type ConversationRedisCache struct { expireTime time.Duration } -//func NewNewConversationRedis( +// func NewNewConversationRedis( // rdb redis.UniversalClient, // conversationDB *relation.ConversationGorm, // options rockscache.Options, -//) ConversationCache { +// ) ConversationCache { // rcClient := rockscache.NewClient(rdb, options) // // return &ConversationRedisCache{ @@ -188,9 +189,9 @@ func (c *ConversationRedisCache) GetUserConversationIDsHash(ctx context.Context, if err != nil { return 0, err } - utils.Sort(conversationIDs, true) + datautil.Sort(conversationIDs, true) bi := big.NewInt(0) - bi.SetString(utils.Md5(strings.Join(conversationIDs, ";"))[0:8], 16) + bi.SetString(encrypt.Md5(strings.Join(conversationIDs, ";"))[0:8], 16) return bi.Uint64(), nil }, ) @@ -232,15 +233,15 @@ func (c *ConversationRedisCache) DelConversations(ownerUserID string, conversati // } // } -// return 0, errors.New("not found key:" + key + " in keys") +// return 0, errs.New("not found key:" + key + " in keys") // } func (c *ConversationRedisCache) GetConversations(ctx context.Context, ownerUserID string, conversationIDs []string) ([]*relationtb.ConversationModel, error) { - //var keys []string - //for _, conversarionID := range conversationIDs { + // var keys []string + // for _, conversarionID := range conversationIDs { // keys = append(keys, c.getConversationKey(ownerUserID, conversarionID)) //} - //return batchGetCache( + // return batchGetCache( // ctx, // c.rcClient, // keys, @@ -262,11 +263,11 @@ func (c *ConversationRedisCache) GetUserAllConversations(ctx context.Context, ow if err != nil { return nil, err } - //var keys []string - //for _, conversarionID := range conversationIDs { + // var keys []string + // for _, conversarionID := range conversationIDs { // keys = append(keys, c.getConversationKey(ownerUserID, conversarionID)) //} - //return batchGetCache( + // return batchGetCache( // ctx, // c.rcClient, // keys, @@ -285,7 +286,7 @@ func (c *ConversationRedisCache) GetUserRecvMsgOpt(ctx context.Context, ownerUse }) } -//func (c *ConversationRedisCache) GetSuperGroupRecvMsgNotNotifyUserIDs(ctx context.Context, groupID string) (userIDs []string, err error) { +// func (c *ConversationRedisCache) GetSuperGroupRecvMsgNotNotifyUserIDs(ctx context.Context, groupID string) (userIDs []string, err error) { // return getCache(ctx, c.rcClient, c.getSuperGroupRecvNotNotifyUserIDsKey(groupID), c.expireTime, func(ctx context.Context) (userIDs []string, err error) { // return c.conversationDB.FindSuperGroupRecvMsgNotNotifyUserIDs(ctx, groupID) // }) @@ -316,7 +317,7 @@ func (c *ConversationRedisCache) DelSuperGroupRecvMsgNotNotifyUserIDs(groupID st return cache } -//func (c *ConversationRedisCache) GetSuperGroupRecvMsgNotNotifyUserIDsHash(ctx context.Context, groupID string) (hash uint64, err error) { +// func (c *ConversationRedisCache) GetSuperGroupRecvMsgNotNotifyUserIDsHash(ctx context.Context, groupID string) (hash uint64, err error) { // return getCache(ctx, c.rcClient, c.getSuperGroupRecvNotNotifyUserIDsHashKey(groupID), c.expireTime, func(ctx context.Context) (hash uint64, err error) { // userIDs, err := c.GetSuperGroupRecvMsgNotNotifyUserIDs(ctx, groupID) // if err != nil { @@ -337,30 +338,6 @@ func (c *ConversationRedisCache) DelSuperGroupRecvMsgNotNotifyUserIDsHash(groupI return cache } -/* func (c *ConversationRedisCache) getUserAllHasReadSeqsIndex(conversationID string, conversationIDs []string) (int, error) { - for _i, _conversationID := range conversationIDs { - if _conversationID == conversationID { - return _i, nil - } - } - - return 0, errors.New("not found key:" + conversationID + " in keys") -} */ - -/* func (c *ConversationRedisCache) GetUserAllHasReadSeqs(ctx context.Context, ownerUserID string) (map[string]int64, error) { - conversationIDs, err := c.GetUserConversationIDs(ctx, ownerUserID) - if err != nil { - return nil, err - } - var keys []string - for _, conversarionID := range conversationIDs { - keys = append(keys, c.getConversationHasReadSeqKey(ownerUserID, conversarionID)) - } - return batchGetCacheMap(ctx, c.rcClient, keys, conversationIDs, c.expireTime, c.getUserAllHasReadSeqsIndex, func(ctx context.Context) (map[string]int64, error) { - return c.conversationDB.GetUserAllHasReadSeqs(ctx, ownerUserID) - }) -} */ - func (c *ConversationRedisCache) DelUserAllHasReadSeqs(ownerUserID string, conversationIDs ...string) ConversationCache { cache := c.NewCache() for _, conversationID := range conversationIDs { diff --git a/pkg/common/db/cache/doc.go b/pkg/common/db/cache/doc.go index 77651e3dee..a5c237249e 100644 --- a/pkg/common/db/cache/doc.go +++ b/pkg/common/db/cache/doc.go @@ -1,4 +1,4 @@ -// Copyright © 2023 OpenIM. All rights reserved. +// 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. diff --git a/pkg/common/db/cache/friend.go b/pkg/common/db/cache/friend.go index 2d20705ef8..73fe5ea694 100644 --- a/pkg/common/db/cache/friend.go +++ b/pkg/common/db/cache/friend.go @@ -18,20 +18,20 @@ import ( "context" "time" - "github.com/OpenIMSDK/tools/log" - "github.com/OpenIMSDK/tools/utils" "github.com/dtm-labs/rockscache" "github.com/openimsdk/open-im-server/v3/pkg/common/cachekey" "github.com/openimsdk/open-im-server/v3/pkg/common/config" relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" + "github.com/openimsdk/tools/log" + "github.com/openimsdk/tools/utils/datautil" "github.com/redis/go-redis/v9" ) const ( friendExpireTime = time.Second * 60 * 60 * 12 - //friendIDsKey = "FRIEND_IDS:" - //TwoWayFriendsIDsKey = "COMMON_FRIENDS_IDS:" - //friendKey = "FRIEND_INFO:". + // FriendIDsKey = "FRIEND_IDS:" + // TwoWayFriendsIDsKey = "COMMON_FRIENDS_IDS:" + // friendKey = "FRIEND_INFO:". ) // FriendCache is an interface for caching friend-related data. @@ -58,11 +58,11 @@ type FriendCacheRedis struct { } // NewFriendCacheRedis creates a new instance of FriendCacheRedis. -func NewFriendCacheRedis(rdb redis.UniversalClient, friendDB relationtb.FriendModelInterface, +func NewFriendCacheRedis(rdb redis.UniversalClient, localCache *config.LocalCache, friendDB relationtb.FriendModelInterface, options rockscache.Options) FriendCache { rcClient := rockscache.NewClient(rdb, options) mc := NewMetaCacheRedis(rcClient) - f := config.Config.LocalCache.Friend + f := localCache.Friend log.ZDebug(context.Background(), "friend local cache init", "Topic", f.Topic, "SlotNum", f.SlotNum, "SlotSize", f.SlotSize, "enable", f.Enable()) mc.SetTopic(f.Topic) mc.SetRawRedisClient(rdb) @@ -129,7 +129,7 @@ func (f *FriendCacheRedis) GetTwoWayFriendIDs(ctx context.Context, ownerUserID s if err != nil { return nil, err } - if utils.IsContain(ownerUserID, friendFriendID) { + if datautil.Contain(ownerUserID, friendFriendID...) { twoWayFriendIDs = append(twoWayFriendIDs, ownerUserID) } } diff --git a/pkg/common/db/cache/group.go b/pkg/common/db/cache/group.go index 7022461cbb..66c2d65c48 100644 --- a/pkg/common/db/cache/group.go +++ b/pkg/common/db/cache/group.go @@ -19,26 +19,19 @@ import ( "fmt" "time" - "github.com/OpenIMSDK/protocol/constant" - "github.com/OpenIMSDK/tools/errs" - "github.com/OpenIMSDK/tools/log" - "github.com/OpenIMSDK/tools/utils" "github.com/dtm-labs/rockscache" "github.com/openimsdk/open-im-server/v3/pkg/common/cachekey" "github.com/openimsdk/open-im-server/v3/pkg/common/config" relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" + "github.com/openimsdk/protocol/constant" + "github.com/openimsdk/tools/errs" + "github.com/openimsdk/tools/log" + "github.com/openimsdk/tools/utils/datautil" "github.com/redis/go-redis/v9" ) const ( groupExpireTime = time.Second * 60 * 60 * 12 - //groupInfoKey = "GROUP_INFO:" - //groupMemberIDsKey = "GROUP_MEMBER_IDS:" - //groupMembersHashKey = "GROUP_MEMBERS_HASH2:" - //groupMemberInfoKey = "GROUP_MEMBER_INFO:" - //joinedGroupsKey = "JOIN_GROUPS_KEY:" - //groupMemberNumKey = "GROUP_MEMBER_NUM_CACHE:" - //groupRoleLevelMemberIDsKey = "GROUP_ROLE_LEVEL_MEMBER_IDS:". ) type GroupHash interface { @@ -94,6 +87,7 @@ type GroupCacheRedis struct { func NewGroupCacheRedis( rdb redis.UniversalClient, + localCache *config.LocalCache, groupDB relationtb.GroupModelInterface, groupMemberDB relationtb.GroupMemberModelInterface, groupRequestDB relationtb.GroupRequestModelInterface, @@ -102,7 +96,7 @@ func NewGroupCacheRedis( ) GroupCache { rcClient := rockscache.NewClient(rdb, opts) mc := NewMetaCacheRedis(rcClient) - g := config.Config.LocalCache.Group + g := localCache.Group mc.SetTopic(g.Topic) log.ZDebug(context.Background(), "group local cache init", "Topic", g.Topic, "SlotNum", g.SlotNum, "SlotSize", g.SlotSize, "enable", g.Enable()) mc.SetRawRedisClient(rdb) @@ -227,7 +221,7 @@ func (g *GroupCacheRedis) DelGroupAllRoleLevel(groupID string) GroupCache { func (g *GroupCacheRedis) GetGroupMembersHash(ctx context.Context, groupID string) (hashCode uint64, err error) { if g.groupHash == nil { - return 0, errs.ErrInternalServer.Wrap("group hash is nil") + return 0, errs.ErrInternalServer.WrapMsg("group hash is nil") } return getCache(ctx, g.rcClient, g.getGroupMembersHashKey(groupID), g.expireTime, func(ctx context.Context) (uint64, error) { return g.groupHash.GetGroupHash(ctx, groupID) @@ -236,7 +230,7 @@ func (g *GroupCacheRedis) GetGroupMembersHash(ctx context.Context, groupID strin func (g *GroupCacheRedis) GetGroupMemberHashMap(ctx context.Context, groupIDs []string) (map[string]*relationtb.GroupSimpleUserID, error) { if g.groupHash == nil { - return nil, errs.ErrInternalServer.Wrap("group hash is nil") + return nil, errs.ErrInternalServer.WrapMsg("group hash is nil") } res := make(map[string]*relationtb.GroupSimpleUserID) for _, groupID := range groupIDs { @@ -244,7 +238,7 @@ func (g *GroupCacheRedis) GetGroupMemberHashMap(ctx context.Context, groupIDs [] if err != nil { return nil, err } - log.ZInfo(ctx, "GetGroupMemberHashMap", "groupID", groupID, "hash", hash) + log.ZDebug(ctx, "GetGroupMemberHashMap", "groupID", groupID, "hash", hash) num, err := g.GetGroupMemberNum(ctx, groupID) if err != nil { return nil, err @@ -330,11 +324,11 @@ func (g *GroupCacheRedis) GetGroupMembersPage( return 0, nil, err } if userIDs != nil { - userIDs = utils.BothExist(userIDs, groupMemberIDs) + userIDs = datautil.BothExist(userIDs, groupMemberIDs) } else { userIDs = groupMemberIDs } - groupMembers, err = g.GetGroupMembersInfo(ctx, groupID, utils.Paginate(userIDs, int(showNumber), int(showNumber))) + groupMembers, err = g.GetGroupMembersInfo(ctx, groupID, datautil.Paginate(userIDs, int(showNumber), int(showNumber))) return uint32(len(userIDs)), groupMembers, err } @@ -390,7 +384,7 @@ func (g *GroupCacheRedis) GetGroupOwner(ctx context.Context, groupID string) (*r return nil, err } if len(members) == 0 { - return nil, errs.ErrRecordNotFound.Wrap(fmt.Sprintf("group %s owner not found", groupID)) + return nil, errs.ErrRecordNotFound.WrapMsg(fmt.Sprintf("group %s owner not found", groupID)) } return members[0], nil } diff --git a/pkg/common/db/cache/init_redis.go b/pkg/common/db/cache/init_redis.go deleted file mode 100644 index 8f4e2c592c..0000000000 --- a/pkg/common/db/cache/init_redis.go +++ /dev/null @@ -1,107 +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 cache - -import ( - "context" - "errors" - "fmt" - "os" - "strings" - "time" - - "github.com/OpenIMSDK/tools/errs" - "github.com/OpenIMSDK/tools/mw/specialerror" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" - "github.com/redis/go-redis/v9" -) - -var ( - // singleton pattern. - redisClient redis.UniversalClient -) - -const ( - maxRetry = 10 // number of retries -) - -// NewRedis Initialize redis connection. -func NewRedis(config *config.GlobalConfig) (redis.UniversalClient, error) { - if redisClient != nil { - return redisClient, nil - } - - // Read configuration from environment variables - overrideConfigFromEnv(config) - - if len(config.Redis.Address) == 0 { - return nil, errs.Wrap(errors.New("redis address is empty")) - } - specialerror.AddReplace(redis.Nil, errs.ErrRecordNotFound) - var rdb redis.UniversalClient - if len(config.Redis.Address) > 1 || config.Redis.ClusterMode { - rdb = redis.NewClusterClient(&redis.ClusterOptions{ - Addrs: config.Redis.Address, - Username: config.Redis.Username, - Password: config.Redis.Password, // no password set - PoolSize: 50, - MaxRetries: maxRetry, - }) - } else { - rdb = redis.NewClient(&redis.Options{ - Addr: config.Redis.Address[0], - Username: config.Redis.Username, - Password: config.Redis.Password, - DB: 0, // use default DB - PoolSize: 100, // connection pool size - MaxRetries: maxRetry, - }) - } - - var err error - ctx, cancel := context.WithTimeout(context.Background(), time.Second*10) - defer cancel() - err = rdb.Ping(ctx).Err() - if err != nil { - errMsg := fmt.Sprintf("address:%s, username:%s, password:%s, clusterMode:%t, enablePipeline:%t", config.Redis.Address, config.Redis.Username, - config.Redis.Password, config.Redis.ClusterMode, config.Redis.EnablePipeline) - return nil, errs.Wrap(err, errMsg) - } - redisClient = rdb - return rdb, err -} - -// overrideConfigFromEnv overrides configuration fields with environment variables if present. -func overrideConfigFromEnv(config *config.GlobalConfig) { - if envAddr := os.Getenv("REDIS_ADDRESS"); envAddr != "" { - if envPort := os.Getenv("REDIS_PORT"); envPort != "" { - addresses := strings.Split(envAddr, ",") - for i, addr := range addresses { - addresses[i] = addr + ":" + envPort - } - config.Redis.Address = addresses - } else { - config.Redis.Address = strings.Split(envAddr, ",") - } - } - - if envUser := os.Getenv("REDIS_USERNAME"); envUser != "" { - config.Redis.Username = envUser - } - - if envPass := os.Getenv("REDIS_PASSWORD"); envPass != "" { - config.Redis.Password = envPass - } -} diff --git a/pkg/common/db/cache/meta_cache.go b/pkg/common/db/cache/meta_cache.go index 431b7c867e..e633e4fbd0 100644 --- a/pkg/common/db/cache/meta_cache.go +++ b/pkg/common/db/cache/meta_cache.go @@ -17,15 +17,14 @@ package cache import ( "context" "encoding/json" - "errors" "fmt" "time" - "github.com/OpenIMSDK/tools/errs" - "github.com/OpenIMSDK/tools/log" - "github.com/OpenIMSDK/tools/mw/specialerror" - "github.com/OpenIMSDK/tools/utils" "github.com/dtm-labs/rockscache" + "github.com/openimsdk/tools/errs" + "github.com/openimsdk/tools/log" + "github.com/openimsdk/tools/mw/specialerror" + "github.com/openimsdk/tools/utils/datautil" "github.com/redis/go-redis/v9" ) @@ -35,7 +34,7 @@ const ( retryInterval = time.Millisecond * 100 ) -var errIndex = errors.New("err index") +var errIndex = errs.New("err index") type metaCache interface { ExecDel(ctx context.Context, distinct ...bool) error @@ -74,7 +73,7 @@ func (m *metaCacheRedis) Copy() metaCache { keys: keys, maxRetryTimes: m.maxRetryTimes, retryInterval: m.retryInterval, - redisClient: redisClient, + redisClient: m.redisClient, } } @@ -88,7 +87,7 @@ func (m *metaCacheRedis) SetRawRedisClient(cli redis.UniversalClient) { func (m *metaCacheRedis) ExecDel(ctx context.Context, distinct ...bool) error { if len(distinct) > 0 && distinct[0] { - m.keys = utils.Distinct(m.keys) + m.keys = datautil.Distinct(m.keys) } if len(m.keys) > 0 { log.ZDebug(ctx, "delete cache", "topic", m.topic, "keys", m.keys) @@ -150,7 +149,7 @@ func getCache[T any](ctx context.Context, rcClient *rockscache.Client, key strin } bs, err := json.Marshal(t) if err != nil { - return "", errs.Wrap(err, "marshal failed") + return "", errs.WrapMsg(err, "marshal failed") } write = true @@ -163,12 +162,12 @@ func getCache[T any](ctx context.Context, rcClient *rockscache.Client, key strin return t, nil } if v == "" { - return t, errs.ErrRecordNotFound.Wrap("cache is not found") + return t, errs.ErrRecordNotFound.WrapMsg("cache is not found") } err = json.Unmarshal([]byte(v), &t) if err != nil { errInfo := fmt.Sprintf("cache json.Unmarshal failed, key:%s, value:%s, expire:%s", key, v, expire) - return t, errs.Wrap(err, errInfo) + return t, errs.WrapMsg(err, errInfo) } return t, nil @@ -240,14 +239,14 @@ func batchGetCache2[T any, K comparable]( return res, nil } -//func batchGetCacheMap[T any]( +// func batchGetCacheMap[T any]( // ctx context.Context, // rcClient *rockscache.Client, // keys, originKeys []string, // expire time.Duration, // keyIndexFn func(s string, keys []string) (int, error), // fn func(ctx context.Context) (map[string]T, error), -//) (map[string]T, error) { +// ) (map[string]T, error) { // batchMap, err := rcClient.FetchBatch2(ctx, keys, expire, func(idxs []int) (m map[int]string, err error) { // tArrays, err := fn(ctx) // if err != nil { diff --git a/pkg/common/db/cache/msg.go b/pkg/common/db/cache/msg.go index b8e9dbc774..e8a86b71bd 100644 --- a/pkg/common/db/cache/msg.go +++ b/pkg/common/db/cache/msg.go @@ -20,30 +20,28 @@ import ( "strconv" "time" - "github.com/OpenIMSDK/protocol/constant" - "github.com/OpenIMSDK/protocol/sdkws" - "github.com/OpenIMSDK/tools/errs" - "github.com/OpenIMSDK/tools/log" - "github.com/OpenIMSDK/tools/utils" "github.com/gogo/protobuf/jsonpb" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/msgprocessor" + "github.com/openimsdk/protocol/constant" + "github.com/openimsdk/protocol/sdkws" + "github.com/openimsdk/tools/errs" + "github.com/openimsdk/tools/log" + "github.com/openimsdk/tools/utils/stringutil" "github.com/redis/go-redis/v9" "golang.org/x/sync/errgroup" ) +const msgCacheTimeout = 86400 * time.Second + const ( maxSeq = "MAX_SEQ:" minSeq = "MIN_SEQ:" conversationUserMinSeq = "CON_USER_MIN_SEQ:" hasReadSeq = "HAS_READ_SEQ:" - //appleDeviceToken = "DEVICE_TOKEN". getuiToken = "GETUI_TOKEN" getuiTaskID = "GETUI_TASK_ID" - //signalCache = "SIGNAL_CACHE:" - //signalListCache = "SIGNAL_LIST_CACHE:". - FCM_TOKEN = "FCM_TOKEN:" + FCM_TOKEN = "FCM_TOKEN:" messageCache = "MESSAGE_CACHE:" messageDelUserList = "MESSAGE_DEL_USER_LIST:" @@ -51,56 +49,17 @@ const ( sendMsgFailedFlag = "SEND_MSG_FAILED_FLAG:" userBadgeUnreadCountSum = "USER_BADGE_UNREAD_COUNT_SUM:" exTypeKeyLocker = "EX_LOCK:" - uidPidToken = "UID_PID_TOKEN_STATUS:" ) var concurrentLimit = 3 -type SeqCache interface { - SetMaxSeq(ctx context.Context, conversationID string, maxSeq int64) error - GetMaxSeqs(ctx context.Context, conversationIDs []string) (map[string]int64, error) - GetMaxSeq(ctx context.Context, conversationID string) (int64, error) - SetMinSeq(ctx context.Context, conversationID string, minSeq int64) error - SetMinSeqs(ctx context.Context, seqs map[string]int64) error - GetMinSeqs(ctx context.Context, conversationIDs []string) (map[string]int64, error) - GetMinSeq(ctx context.Context, conversationID string) (int64, error) - GetConversationUserMinSeq(ctx context.Context, conversationID string, userID string) (int64, error) - GetConversationUserMinSeqs(ctx context.Context, conversationID string, userIDs []string) (map[string]int64, error) - SetConversationUserMinSeq(ctx context.Context, conversationID string, userID string, minSeq int64) error - // seqs map: key userID value minSeq - SetConversationUserMinSeqs(ctx context.Context, conversationID string, seqs map[string]int64) (err error) - // seqs map: key conversationID value minSeq - SetUserConversationsMinSeqs(ctx context.Context, userID string, seqs map[string]int64) error - // has read seq - SetHasReadSeq(ctx context.Context, userID string, conversationID string, hasReadSeq int64) error - // k: user, v: seq - SetHasReadSeqs(ctx context.Context, conversationID string, hasReadSeqs map[string]int64) error - // k: conversation, v :seq - UserSetHasReadSeqs(ctx context.Context, userID string, hasReadSeqs map[string]int64) error - GetHasReadSeqs(ctx context.Context, userID string, conversationIDs []string) (map[string]int64, error) - GetHasReadSeq(ctx context.Context, userID string, conversationID string) (int64, error) -} - -type thirdCache interface { - SetFcmToken(ctx context.Context, account string, platformID int, fcmToken string, expireTime int64) (err error) - GetFcmToken(ctx context.Context, account string, platformID int) (string, error) - DelFcmToken(ctx context.Context, account string, platformID int) error - IncrUserBadgeUnreadCountSum(ctx context.Context, userID string) (int, error) - SetUserBadgeUnreadCountSum(ctx context.Context, userID string, value int) error - GetUserBadgeUnreadCountSum(ctx context.Context, userID string) (int, error) - SetGetuiToken(ctx context.Context, token string, expireTime int64) error - GetGetuiToken(ctx context.Context) (string, error) - SetGetuiTaskID(ctx context.Context, taskID string, expireTime int64) error - GetGetuiTaskID(ctx context.Context) (string, error) -} - -type MsgModel interface { - SeqCache - thirdCache - AddTokenFlag(ctx context.Context, userID string, platformID int, token string, flag int) error - GetTokensWithoutError(ctx context.Context, userID string, platformID int) (map[string]int, error) - SetTokenMapByUidPid(ctx context.Context, userID string, platformID int, m map[string]int) error - DeleteTokenByUidPid(ctx context.Context, userID string, platformID int, fields []string) error +//type MsgModel interface { +// SeqCache +// ThirdCache +// MsgCache +//} + +type MsgCache interface { GetMessagesBySeq(ctx context.Context, conversationID string, seqs []int64) (seqMsg []*sdkws.MsgData, failedSeqList []int64, err error) SetMessageToCache(ctx context.Context, conversationID string, msgs []*sdkws.MsgData) (int, error) UserDeleteMsgs(ctx context.Context, conversationID string, seqs []int64, userID string) error @@ -121,303 +80,31 @@ type MsgModel interface { UnLockMessageTypeKey(ctx context.Context, clientMsgID string, TypeKey string) error } -func NewMsgCacheModel(client redis.UniversalClient, config *config.GlobalConfig) MsgModel { - return &msgCache{rdb: client, config: config} +//func NewMsgCacheModel(client redis.UniversalClient, msgCacheTimeout int, redisConf *config.Redis) MsgModel { +// return &msgCache{rdb: client, msgCacheTimeout: msgCacheTimeout, redisConf: redisConf} +//} + +func NewMsgCache(client redis.UniversalClient, redisEnablePipeline bool) MsgCache { + return &msgCache{rdb: client, msgCacheTimeout: msgCacheTimeout, redisEnablePipeline: redisEnablePipeline} } type msgCache struct { metaCache - rdb redis.UniversalClient - config *config.GlobalConfig -} - -func (c *msgCache) getMaxSeqKey(conversationID string) string { - return maxSeq + conversationID -} - -func (c *msgCache) getMinSeqKey(conversationID string) string { - return minSeq + conversationID -} - -func (c *msgCache) getHasReadSeqKey(conversationID string, userID string) string { - return hasReadSeq + userID + ":" + conversationID -} - -func (c *msgCache) getConversationUserMinSeqKey(conversationID, userID string) string { - return conversationUserMinSeq + conversationID + "u:" + userID -} - -func (c *msgCache) setSeq(ctx context.Context, conversationID string, seq int64, getkey func(conversationID string) string) error { - return errs.Wrap(c.rdb.Set(ctx, getkey(conversationID), seq, 0).Err()) -} - -func (c *msgCache) getSeq(ctx context.Context, conversationID string, getkey func(conversationID string) string) (int64, error) { - val, err := c.rdb.Get(ctx, getkey(conversationID)).Int64() - if err != nil { - return 0, errs.Wrap(err) - } - return val, nil -} - -func (c *msgCache) getSeqs(ctx context.Context, items []string, getkey func(s string) string) (m map[string]int64, err error) { - m = make(map[string]int64, len(items)) - for i, v := range items { - res, err := c.rdb.Get(ctx, getkey(v)).Result() - if err != nil && err != redis.Nil { - return nil, errs.Wrap(err) - } - val := utils.StringToInt64(res) - if val != 0 { - m[items[i]] = val - } - } - - return m, nil -} - -func (c *msgCache) SetMaxSeq(ctx context.Context, conversationID string, maxSeq int64) error { - return c.setSeq(ctx, conversationID, maxSeq, c.getMaxSeqKey) -} - -func (c *msgCache) GetMaxSeqs(ctx context.Context, conversationIDs []string) (m map[string]int64, err error) { - return c.getSeqs(ctx, conversationIDs, c.getMaxSeqKey) -} - -func (c *msgCache) GetMaxSeq(ctx context.Context, conversationID string) (int64, error) { - return c.getSeq(ctx, conversationID, c.getMaxSeqKey) -} - -func (c *msgCache) SetMinSeq(ctx context.Context, conversationID string, minSeq int64) error { - return c.setSeq(ctx, conversationID, minSeq, c.getMinSeqKey) -} - -func (c *msgCache) setSeqs(ctx context.Context, seqs map[string]int64, getkey func(key string) string) error { - for conversationID, seq := range seqs { - if err := c.rdb.Set(ctx, getkey(conversationID), seq, 0).Err(); err != nil { - return errs.Wrap(err) - } - } - return nil -} - -func (c *msgCache) SetMinSeqs(ctx context.Context, seqs map[string]int64) error { - return c.setSeqs(ctx, seqs, c.getMinSeqKey) -} - -func (c *msgCache) GetMinSeqs(ctx context.Context, conversationIDs []string) (map[string]int64, error) { - return c.getSeqs(ctx, conversationIDs, c.getMinSeqKey) -} - -func (c *msgCache) GetMinSeq(ctx context.Context, conversationID string) (int64, error) { - return c.getSeq(ctx, conversationID, c.getMinSeqKey) -} - -func (c *msgCache) GetConversationUserMinSeq(ctx context.Context, conversationID string, userID string) (int64, error) { - val, err := c.rdb.Get(ctx, c.getConversationUserMinSeqKey(conversationID, userID)).Int64() - if err != nil { - return 0, errs.Wrap(err) - } - return val, nil -} - -func (c *msgCache) GetConversationUserMinSeqs(ctx context.Context, conversationID string, userIDs []string) (m map[string]int64, err error) { - return c.getSeqs(ctx, userIDs, func(userID string) string { - return c.getConversationUserMinSeqKey(conversationID, userID) - }) -} - -func (c *msgCache) SetConversationUserMinSeq(ctx context.Context, conversationID string, userID string, minSeq int64) error { - return errs.Wrap(c.rdb.Set(ctx, c.getConversationUserMinSeqKey(conversationID, userID), minSeq, 0).Err()) -} - -func (c *msgCache) SetConversationUserMinSeqs(ctx context.Context, conversationID string, seqs map[string]int64) (err error) { - return c.setSeqs(ctx, seqs, func(userID string) string { - return c.getConversationUserMinSeqKey(conversationID, userID) - }) -} - -func (c *msgCache) SetUserConversationsMinSeqs(ctx context.Context, userID string, seqs map[string]int64) (err error) { - return c.setSeqs(ctx, seqs, func(conversationID string) string { - return c.getConversationUserMinSeqKey(conversationID, userID) - }) -} - -func (c *msgCache) SetHasReadSeq(ctx context.Context, userID string, conversationID string, hasReadSeq int64) error { - return errs.Wrap(c.rdb.Set(ctx, c.getHasReadSeqKey(conversationID, userID), hasReadSeq, 0).Err()) -} - -func (c *msgCache) SetHasReadSeqs(ctx context.Context, conversationID string, hasReadSeqs map[string]int64) error { - return c.setSeqs(ctx, hasReadSeqs, func(userID string) string { - return c.getHasReadSeqKey(conversationID, userID) - }) -} - -func (c *msgCache) UserSetHasReadSeqs(ctx context.Context, userID string, hasReadSeqs map[string]int64) error { - return c.setSeqs(ctx, hasReadSeqs, func(conversationID string) string { - return c.getHasReadSeqKey(conversationID, userID) - }) -} - -func (c *msgCache) GetHasReadSeqs(ctx context.Context, userID string, conversationIDs []string) (map[string]int64, error) { - return c.getSeqs(ctx, conversationIDs, func(conversationID string) string { - return c.getHasReadSeqKey(conversationID, userID) - }) -} - -func (c *msgCache) GetHasReadSeq(ctx context.Context, userID string, conversationID string) (int64, error) { - val, err := c.rdb.Get(ctx, c.getHasReadSeqKey(conversationID, userID)).Int64() - if err != nil { - return 0, err - } - return val, nil -} - -func (c *msgCache) AddTokenFlag(ctx context.Context, userID string, platformID int, token string, flag int) error { - key := uidPidToken + userID + ":" + constant.PlatformIDToName(platformID) - return errs.Wrap(c.rdb.HSet(ctx, key, token, flag).Err()) -} - -func (c *msgCache) GetTokensWithoutError(ctx context.Context, userID string, platformID int) (map[string]int, error) { - key := uidPidToken + userID + ":" + constant.PlatformIDToName(platformID) - m, err := c.rdb.HGetAll(ctx, key).Result() - if err != nil { - return nil, errs.Wrap(err) - } - mm := make(map[string]int) - for k, v := range m { - mm[k] = utils.StringToInt(v) - } - - return mm, nil -} - -func (c *msgCache) SetTokenMapByUidPid(ctx context.Context, userID string, platform int, m map[string]int) error { - key := uidPidToken + userID + ":" + constant.PlatformIDToName(platform) - mm := make(map[string]any) - for k, v := range m { - mm[k] = v - } - - return errs.Wrap(c.rdb.HSet(ctx, key, mm).Err()) -} - -func (c *msgCache) DeleteTokenByUidPid(ctx context.Context, userID string, platform int, fields []string) error { - key := uidPidToken + userID + ":" + constant.PlatformIDToName(platform) - - return errs.Wrap(c.rdb.HDel(ctx, key, fields...).Err()) -} - -func (c *msgCache) getMessageCacheKey(conversationID string, seq int64) string { - return messageCache + conversationID + "_" + strconv.Itoa(int(seq)) + rdb redis.UniversalClient + msgCacheTimeout time.Duration + redisEnablePipeline bool } func (c *msgCache) allMessageCacheKey(conversationID string) string { return messageCache + conversationID + "_*" } -func (c *msgCache) GetMessagesBySeq(ctx context.Context, conversationID string, seqs []int64) (seqMsgs []*sdkws.MsgData, failedSeqs []int64, err error) { - if c.config.Redis.EnablePipeline { - return c.PipeGetMessagesBySeq(ctx, conversationID, seqs) - } - - return c.ParallelGetMessagesBySeq(ctx, conversationID, seqs) -} - -func (c *msgCache) PipeGetMessagesBySeq(ctx context.Context, conversationID string, seqs []int64) (seqMsgs []*sdkws.MsgData, failedSeqs []int64, err error) { - pipe := c.rdb.Pipeline() - - results := []*redis.StringCmd{} - for _, seq := range seqs { - results = append(results, pipe.Get(ctx, c.getMessageCacheKey(conversationID, seq))) - } - - _, err = pipe.Exec(ctx) - if err != nil && err != redis.Nil { - return seqMsgs, failedSeqs, errs.Wrap(err, "pipe.get") - } - - for idx, res := range results { - seq := seqs[idx] - if res.Err() != nil { - log.ZError(ctx, "GetMessagesBySeq failed", err, "conversationID", conversationID, "seq", seq, "err", res.Err()) - failedSeqs = append(failedSeqs, seq) - continue - } - - msg := sdkws.MsgData{} - if err = msgprocessor.String2Pb(res.Val(), &msg); err != nil { - log.ZError(ctx, "GetMessagesBySeq Unmarshal failed", err, "res", res, "conversationID", conversationID, "seq", seq) - failedSeqs = append(failedSeqs, seq) - continue - } - - if msg.Status == constant.MsgDeleted { - failedSeqs = append(failedSeqs, seq) - continue - } - - seqMsgs = append(seqMsgs, &msg) - } - - return -} - -func (c *msgCache) ParallelGetMessagesBySeq(ctx context.Context, conversationID string, seqs []int64) (seqMsgs []*sdkws.MsgData, failedSeqs []int64, err error) { - type entry struct { - err error - msg *sdkws.MsgData - } - - wg := errgroup.Group{} - wg.SetLimit(concurrentLimit) - - results := make([]entry, len(seqs)) // set slice len/cap to length of seqs. - for idx, seq := range seqs { - // closure safe var - idx := idx - seq := seq - - wg.Go(func() error { - res, err := c.rdb.Get(ctx, c.getMessageCacheKey(conversationID, seq)).Result() - if err != nil { - log.ZError(ctx, "GetMessagesBySeq failed", err, "conversationID", conversationID, "seq", seq) - results[idx] = entry{err: err} - return nil - } - - msg := sdkws.MsgData{} - if err = msgprocessor.String2Pb(res, &msg); err != nil { - log.ZError(ctx, "GetMessagesBySeq Unmarshal failed", err, "res", res, "conversationID", conversationID, "seq", seq) - results[idx] = entry{err: err} - return nil - } - - if msg.Status == constant.MsgDeleted { - results[idx] = entry{err: err} - return nil - } - - results[idx] = entry{msg: &msg} - return nil - }) - } - - _ = wg.Wait() - - for idx, res := range results { - if res.err != nil { - failedSeqs = append(failedSeqs, seqs[idx]) - continue - } - - seqMsgs = append(seqMsgs, res.msg) - } - - return +func (c *msgCache) getMessageCacheKey(conversationID string, seq int64) string { + return messageCache + conversationID + "_" + strconv.Itoa(int(seq)) } func (c *msgCache) SetMessageToCache(ctx context.Context, conversationID string, msgs []*sdkws.MsgData) (int, error) { - if c.config.Redis.EnablePipeline { + if c.redisEnablePipeline { return c.PipeSetMessageToCache(ctx, conversationID, msgs) } return c.ParallelSetMessageToCache(ctx, conversationID, msgs) @@ -432,7 +119,7 @@ func (c *msgCache) PipeSetMessageToCache(ctx context.Context, conversationID str } key := c.getMessageCacheKey(conversationID, msg.Seq) - _ = pipe.Set(ctx, key, s, time.Duration(c.config.MsgCacheTimeout)*time.Second) + _ = pipe.Set(ctx, key, s, c.msgCacheTimeout) } results, err := pipe.Exec(ctx) @@ -462,7 +149,7 @@ func (c *msgCache) ParallelSetMessageToCache(ctx context.Context, conversationID } key := c.getMessageCacheKey(conversationID, msg.Seq) - if err := c.rdb.Set(ctx, key, s, time.Duration(c.config.MsgCacheTimeout)*time.Second).Err(); err != nil { + if err := c.rdb.Set(ctx, key, s, c.msgCacheTimeout).Err(); err != nil { return errs.Wrap(err) } return nil @@ -471,7 +158,7 @@ func (c *msgCache) ParallelSetMessageToCache(ctx context.Context, conversationID err := wg.Wait() if err != nil { - return 0, errs.Wrap(err, "wg.Wait failed") + return 0, errs.WrapMsg(err, "wg.Wait failed") } return len(msgs), nil @@ -497,17 +184,17 @@ func (c *msgCache) UserDeleteMsgs(ctx context.Context, conversationID string, se if err != nil { return errs.Wrap(err) } - if err := c.rdb.Expire(ctx, delUserListKey, time.Duration(c.config.MsgCacheTimeout)*time.Second).Err(); err != nil { + if err := c.rdb.Expire(ctx, delUserListKey, c.msgCacheTimeout).Err(); err != nil { return errs.Wrap(err) } - if err := c.rdb.Expire(ctx, userDelListKey, time.Duration(c.config.MsgCacheTimeout)*time.Second).Err(); err != nil { + if err := c.rdb.Expire(ctx, userDelListKey, c.msgCacheTimeout).Err(); err != nil { return errs.Wrap(err) } } return nil - //pipe := c.rdb.Pipeline() - //for _, seq := range seqs { + // pipe := c.rdb.Pipeline() + // for _, seq := range seqs { // delUserListKey := c.getMessageDelUserListKey(conversationID, seq) // userDelListKey := c.getUserDelList(conversationID, userID) // err := pipe.SAdd(ctx, delUserListKey, userID).Err() @@ -525,8 +212,8 @@ func (c *msgCache) UserDeleteMsgs(ctx context.Context, conversationID string, se // return errs.Wrap(err) // } //} - //_, err := pipe.Exec(ctx) - //return errs.Wrap(err) + // _, err := pipe.Exec(ctx) + // return errs.Wrap(err) } func (c *msgCache) GetUserDelList(ctx context.Context, userID, conversationID string) (seqs []int64, err error) { @@ -536,7 +223,7 @@ func (c *msgCache) GetUserDelList(ctx context.Context, userID, conversationID st } seqs = make([]int64, len(result)) for i, v := range result { - seqs[i] = utils.StringToInt64(v) + seqs[i] = stringutil.StringToInt64(v) } return seqs, nil @@ -566,7 +253,7 @@ func (c *msgCache) DelUserDeleteMsgsList(ctx context.Context, conversationID str } } } - //for _, seq := range seqs { + // for _, seq := range seqs { // delUsers, err := c.rdb.SMembers(ctx, c.getMessageDelUserListKey(conversationID, seq)).Result() // if err != nil { // log.ZWarn(ctx, "DelUserDeleteMsgsList failed", err, "conversationID", conversationID, "seq", seq) @@ -605,7 +292,7 @@ func (c *msgCache) DelUserDeleteMsgsList(ctx context.Context, conversationID str } func (c *msgCache) DeleteMessages(ctx context.Context, conversationID string, seqs []int64) error { - if c.config.Redis.EnablePipeline { + if c.redisEnablePipeline { return c.PipeDeleteMessages(ctx, conversationID, seqs) } @@ -638,7 +325,7 @@ func (c *msgCache) PipeDeleteMessages(ctx context.Context, conversationID string results, err := pipe.Exec(ctx) if err != nil { - return errs.Wrap(err, "pipe.del") + return errs.WrapMsg(err, "pipe.del") } for _, res := range results { @@ -687,7 +374,7 @@ func (c *msgCache) DelMsgFromCache(ctx context.Context, userID string, seqs []in if err != nil { return errs.Wrap(err) } - if err := c.rdb.Set(ctx, key, s, time.Duration(c.config.MsgCacheTimeout)*time.Second).Err(); err != nil { + if err := c.rdb.Set(ctx, key, s, c.msgCacheTimeout).Err(); err != nil { return errs.Wrap(err) } } @@ -695,30 +382,6 @@ func (c *msgCache) DelMsgFromCache(ctx context.Context, userID string, seqs []in return nil } -func (c *msgCache) SetGetuiToken(ctx context.Context, token string, expireTime int64) error { - return errs.Wrap(c.rdb.Set(ctx, getuiToken, token, time.Duration(expireTime)*time.Second).Err()) -} - -func (c *msgCache) GetGetuiToken(ctx context.Context) (string, error) { - val, err := c.rdb.Get(ctx, getuiToken).Result() - if err != nil { - return "", errs.Wrap(err) - } - return val, nil -} - -func (c *msgCache) SetGetuiTaskID(ctx context.Context, taskID string, expireTime int64) error { - return errs.Wrap(c.rdb.Set(ctx, getuiTaskID, taskID, time.Duration(expireTime)*time.Second).Err()) -} - -func (c *msgCache) GetGetuiTaskID(ctx context.Context) (string, error) { - val, err := c.rdb.Get(ctx, getuiTaskID).Result() - if err != nil { - return "", errs.Wrap(err) - } - return val, nil -} - func (c *msgCache) SetSendMsgStatus(ctx context.Context, id string, status int32) error { return errs.Wrap(c.rdb.Set(ctx, sendMsgFailedFlag+id, status, time.Hour*24).Err()) } @@ -729,37 +392,6 @@ func (c *msgCache) GetSendMsgStatus(ctx context.Context, id string) (int32, erro return int32(result), errs.Wrap(err) } -func (c *msgCache) SetFcmToken(ctx context.Context, account string, platformID int, fcmToken string, expireTime int64) (err error) { - return errs.Wrap(c.rdb.Set(ctx, FCM_TOKEN+account+":"+strconv.Itoa(platformID), fcmToken, time.Duration(expireTime)*time.Second).Err()) -} - -func (c *msgCache) GetFcmToken(ctx context.Context, account string, platformID int) (string, error) { - val, err := c.rdb.Get(ctx, FCM_TOKEN+account+":"+strconv.Itoa(platformID)).Result() - if err != nil { - return "", errs.Wrap(err) - } - return val, nil -} - -func (c *msgCache) DelFcmToken(ctx context.Context, account string, platformID int) error { - return errs.Wrap(c.rdb.Del(ctx, FCM_TOKEN+account+":"+strconv.Itoa(platformID)).Err()) -} - -func (c *msgCache) IncrUserBadgeUnreadCountSum(ctx context.Context, userID string) (int, error) { - seq, err := c.rdb.Incr(ctx, userBadgeUnreadCountSum+userID).Result() - - return int(seq), errs.Wrap(err) -} - -func (c *msgCache) SetUserBadgeUnreadCountSum(ctx context.Context, userID string, value int) error { - return errs.Wrap(c.rdb.Set(ctx, userBadgeUnreadCountSum+userID, value, 0).Err()) -} - -func (c *msgCache) GetUserBadgeUnreadCountSum(ctx context.Context, userID string) (int, error) { - val, err := c.rdb.Get(ctx, userBadgeUnreadCountSum+userID).Int() - return val, errs.Wrap(err) -} - func (c *msgCache) LockMessageTypeKey(ctx context.Context, clientMsgID string, TypeKey string) error { key := exTypeKeyLocker + clientMsgID + "_" + TypeKey @@ -776,9 +408,9 @@ func (c *msgCache) getMessageReactionExPrefix(clientMsgID string, sessionType in switch sessionType { case constant.SingleChatType: return "EX_SINGLE_" + clientMsgID - case constant.GroupChatType: + case constant.WriteGroupChatType: return "EX_GROUP_" + clientMsgID - case constant.SuperGroupChatType: + case constant.ReadGroupChatType: return "EX_SUPER_GROUP_" + clientMsgID case constant.NotificationChatType: return "EX_NOTIFICATION" + clientMsgID @@ -818,3 +450,104 @@ func (c *msgCache) GetOneMessageAllReactionList(ctx context.Context, clientMsgID func (c *msgCache) DeleteOneMessageKey(ctx context.Context, clientMsgID string, sessionType int32, subKey string) error { return errs.Wrap(c.rdb.HDel(ctx, c.getMessageReactionExPrefix(clientMsgID, sessionType), subKey).Err()) } + +func (c *msgCache) GetMessagesBySeq(ctx context.Context, conversationID string, seqs []int64) (seqMsgs []*sdkws.MsgData, failedSeqs []int64, err error) { + if c.redisEnablePipeline { + return c.PipeGetMessagesBySeq(ctx, conversationID, seqs) + } + + return c.ParallelGetMessagesBySeq(ctx, conversationID, seqs) +} + +func (c *msgCache) PipeGetMessagesBySeq(ctx context.Context, conversationID string, seqs []int64) (seqMsgs []*sdkws.MsgData, failedSeqs []int64, err error) { + pipe := c.rdb.Pipeline() + + results := []*redis.StringCmd{} + for _, seq := range seqs { + results = append(results, pipe.Get(ctx, c.getMessageCacheKey(conversationID, seq))) + } + + _, err = pipe.Exec(ctx) + if err != nil && err != redis.Nil { + return seqMsgs, failedSeqs, errs.WrapMsg(err, "pipe.get") + } + + for idx, res := range results { + seq := seqs[idx] + if res.Err() != nil { + log.ZError(ctx, "GetMessagesBySeq failed", err, "conversationID", conversationID, "seq", seq, "err", res.Err()) + failedSeqs = append(failedSeqs, seq) + continue + } + + msg := sdkws.MsgData{} + if err = msgprocessor.String2Pb(res.Val(), &msg); err != nil { + log.ZError(ctx, "GetMessagesBySeq Unmarshal failed", err, "res", res, "conversationID", conversationID, "seq", seq) + failedSeqs = append(failedSeqs, seq) + continue + } + + if msg.Status == constant.MsgDeleted { + failedSeqs = append(failedSeqs, seq) + continue + } + + seqMsgs = append(seqMsgs, &msg) + } + + return +} + +func (c *msgCache) ParallelGetMessagesBySeq(ctx context.Context, conversationID string, seqs []int64) (seqMsgs []*sdkws.MsgData, failedSeqs []int64, err error) { + type entry struct { + err error + msg *sdkws.MsgData + } + + wg := errgroup.Group{} + wg.SetLimit(concurrentLimit) + + results := make([]entry, len(seqs)) // set slice len/cap to length of seqs. + for idx, seq := range seqs { + // closure safe var + idx := idx + seq := seq + + wg.Go(func() error { + res, err := c.rdb.Get(ctx, c.getMessageCacheKey(conversationID, seq)).Result() + if err != nil { + log.ZError(ctx, "GetMessagesBySeq failed", err, "conversationID", conversationID, "seq", seq) + results[idx] = entry{err: err} + return nil + } + + msg := sdkws.MsgData{} + if err = msgprocessor.String2Pb(res, &msg); err != nil { + log.ZError(ctx, "GetMessagesBySeq Unmarshal failed", err, "res", res, "conversationID", conversationID, "seq", seq) + results[idx] = entry{err: err} + return nil + } + + if msg.Status == constant.MsgDeleted { + results[idx] = entry{err: err} + return nil + } + + results[idx] = entry{msg: &msg} + return nil + }) + } + + _ = wg.Wait() + + for idx, res := range results { + if res.err != nil { + failedSeqs = append(failedSeqs, seqs[idx]) + continue + } + + seqMsgs = append(seqMsgs, res.msg) + } + + return +} diff --git a/pkg/common/db/cache/msg_test.go b/pkg/common/db/cache/msg_test.go index 65413199ab..481b4012c1 100644 --- a/pkg/common/db/cache/msg_test.go +++ b/pkg/common/db/cache/msg_test.go @@ -20,7 +20,7 @@ import ( "math/rand" "testing" - "github.com/OpenIMSDK/protocol/sdkws" + "github.com/openimsdk/protocol/sdkws" "github.com/redis/go-redis/v9" "github.com/stretchr/testify/assert" ) diff --git a/pkg/common/db/cache/s3.go b/pkg/common/db/cache/s3.go index 28e993be09..1610283ca4 100644 --- a/pkg/common/db/cache/s3.go +++ b/pkg/common/db/cache/s3.go @@ -16,12 +16,14 @@ package cache import ( "context" + "github.com/openimsdk/tools/s3/cont" + "github.com/openimsdk/tools/s3/minio" "strconv" "time" "github.com/dtm-labs/rockscache" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/s3" relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" + "github.com/openimsdk/tools/s3" "github.com/redis/go-redis/v9" ) @@ -83,7 +85,7 @@ type S3Cache interface { DelS3Key(engine string, keys ...string) S3Cache } -func NewS3Cache(rdb redis.UniversalClient, s3 s3.Interface) S3Cache { +func NewS3Cache(rdb redis.UniversalClient, s3 s3.Interface) cont.S3Cache { rcClient := rockscache.NewClient(rdb, rockscache.NewDefaultOptions()) return &s3CacheRedis{ rcClient: rcClient, @@ -100,7 +102,7 @@ type s3CacheRedis struct { expireTime time.Duration } -func (g *s3CacheRedis) NewCache() S3Cache { +func (g *s3CacheRedis) newCache() *s3CacheRedis { return &s3CacheRedis{ rcClient: g.rcClient, expireTime: g.expireTime, @@ -109,14 +111,14 @@ func (g *s3CacheRedis) NewCache() S3Cache { } } -func (g *s3CacheRedis) DelS3Key(engine string, keys ...string) S3Cache { - s3cache := g.NewCache() +func (g *s3CacheRedis) DelS3Key(ctx context.Context, engine string, keys ...string) error { + s3cache := g.newCache() ks := make([]string, 0, len(keys)) for _, key := range keys { ks = append(ks, g.getS3Key(engine, key)) } s3cache.AddKeys(ks...) - return s3cache + return s3cache.ExecDel(ctx) } func (g *s3CacheRedis) getS3Key(engine string, name string) string { @@ -137,7 +139,7 @@ type MinioCache interface { DelImageThumbnailKey(key string, format string, width int, height int) MinioCache } -func NewMinioCache(rdb redis.UniversalClient) MinioCache { +func NewMinioCache(rdb redis.UniversalClient) minio.Cache { rcClient := rockscache.NewClient(rdb, rockscache.NewDefaultOptions()) return &minioCacheRedis{ rcClient: rcClient, @@ -152,7 +154,7 @@ type minioCacheRedis struct { expireTime time.Duration } -func (g *minioCacheRedis) NewCache() MinioCache { +func (g *minioCacheRedis) newCache() *minioCacheRedis { return &minioCacheRedis{ rcClient: g.rcClient, expireTime: g.expireTime, @@ -160,20 +162,20 @@ func (g *minioCacheRedis) NewCache() MinioCache { } } -func (g *minioCacheRedis) DelObjectImageInfoKey(keys ...string) MinioCache { - s3cache := g.NewCache() +func (g *minioCacheRedis) DelObjectImageInfoKey(ctx context.Context, keys ...string) error { + s3cache := g.newCache() ks := make([]string, 0, len(keys)) for _, key := range keys { ks = append(ks, g.getObjectImageInfoKey(key)) } s3cache.AddKeys(ks...) - return s3cache + return s3cache.ExecDel(ctx) } -func (g *minioCacheRedis) DelImageThumbnailKey(key string, format string, width int, height int) MinioCache { - s3cache := g.NewCache() +func (g *minioCacheRedis) DelImageThumbnailKey(ctx context.Context, key string, format string, width int, height int) error { + s3cache := g.newCache() s3cache.AddKeys(g.getMinioImageThumbnailKey(key, format, width, height)) - return s3cache + return s3cache.ExecDel(ctx) } func (g *minioCacheRedis) getObjectImageInfoKey(key string) string { @@ -184,7 +186,7 @@ func (g *minioCacheRedis) getMinioImageThumbnailKey(key string, format string, w return "MINIO:THUMBNAIL:" + format + ":w" + strconv.Itoa(width) + ":h" + strconv.Itoa(height) + ":" + key } -func (g *minioCacheRedis) GetImageObjectKeyInfo(ctx context.Context, key string, fn func(ctx context.Context) (*MinioImageInfo, error)) (*MinioImageInfo, error) { +func (g *minioCacheRedis) GetImageObjectKeyInfo(ctx context.Context, key string, fn func(ctx context.Context) (*minio.ImageInfo, error)) (*minio.ImageInfo, error) { info, err := getCache(ctx, g.rcClient, g.getObjectImageInfoKey(key), g.expireTime, fn) if err != nil { return nil, err diff --git a/pkg/common/db/cache/seq.go b/pkg/common/db/cache/seq.go new file mode 100644 index 0000000000..6fbb091836 --- /dev/null +++ b/pkg/common/db/cache/seq.go @@ -0,0 +1,182 @@ +package cache + +import ( + "context" + "github.com/openimsdk/tools/errs" + "github.com/openimsdk/tools/utils/stringutil" + "github.com/redis/go-redis/v9" +) + +type SeqCache interface { + SetMaxSeq(ctx context.Context, conversationID string, maxSeq int64) error + GetMaxSeqs(ctx context.Context, conversationIDs []string) (map[string]int64, error) + GetMaxSeq(ctx context.Context, conversationID string) (int64, error) + SetMinSeq(ctx context.Context, conversationID string, minSeq int64) error + SetMinSeqs(ctx context.Context, seqs map[string]int64) error + GetMinSeqs(ctx context.Context, conversationIDs []string) (map[string]int64, error) + GetMinSeq(ctx context.Context, conversationID string) (int64, error) + GetConversationUserMinSeq(ctx context.Context, conversationID string, userID string) (int64, error) + GetConversationUserMinSeqs(ctx context.Context, conversationID string, userIDs []string) (map[string]int64, error) + SetConversationUserMinSeq(ctx context.Context, conversationID string, userID string, minSeq int64) error + // seqs map: key userID value minSeq + SetConversationUserMinSeqs(ctx context.Context, conversationID string, seqs map[string]int64) (err error) + // seqs map: key conversationID value minSeq + SetUserConversationsMinSeqs(ctx context.Context, userID string, seqs map[string]int64) error + // has read seq + SetHasReadSeq(ctx context.Context, userID string, conversationID string, hasReadSeq int64) error + // k: user, v: seq + SetHasReadSeqs(ctx context.Context, conversationID string, hasReadSeqs map[string]int64) error + // k: conversation, v :seq + UserSetHasReadSeqs(ctx context.Context, userID string, hasReadSeqs map[string]int64) error + GetHasReadSeqs(ctx context.Context, userID string, conversationIDs []string) (map[string]int64, error) + GetHasReadSeq(ctx context.Context, userID string, conversationID string) (int64, error) +} + +func NewSeqCache(rdb redis.UniversalClient) SeqCache { + return &seqCache{rdb: rdb} +} + +type seqCache struct { + rdb redis.UniversalClient +} + +func (c *seqCache) getMaxSeqKey(conversationID string) string { + return maxSeq + conversationID +} + +func (c *seqCache) getMinSeqKey(conversationID string) string { + return minSeq + conversationID +} + +func (c *seqCache) getHasReadSeqKey(conversationID string, userID string) string { + return hasReadSeq + userID + ":" + conversationID +} + +func (c *seqCache) getConversationUserMinSeqKey(conversationID, userID string) string { + return conversationUserMinSeq + conversationID + "u:" + userID +} + +func (c *seqCache) setSeq(ctx context.Context, conversationID string, seq int64, getkey func(conversationID string) string) error { + return errs.Wrap(c.rdb.Set(ctx, getkey(conversationID), seq, 0).Err()) +} + +func (c *seqCache) getSeq(ctx context.Context, conversationID string, getkey func(conversationID string) string) (int64, error) { + val, err := c.rdb.Get(ctx, getkey(conversationID)).Int64() + if err != nil { + return 0, errs.Wrap(err) + } + return val, nil +} + +func (c *seqCache) getSeqs(ctx context.Context, items []string, getkey func(s string) string) (m map[string]int64, err error) { + m = make(map[string]int64, len(items)) + for i, v := range items { + res, err := c.rdb.Get(ctx, getkey(v)).Result() + if err != nil && err != redis.Nil { + return nil, errs.Wrap(err) + } + val := stringutil.StringToInt64(res) + if val != 0 { + m[items[i]] = val + } + } + + return m, nil +} + +func (c *seqCache) SetMaxSeq(ctx context.Context, conversationID string, maxSeq int64) error { + return c.setSeq(ctx, conversationID, maxSeq, c.getMaxSeqKey) +} + +func (c *seqCache) GetMaxSeqs(ctx context.Context, conversationIDs []string) (m map[string]int64, err error) { + return c.getSeqs(ctx, conversationIDs, c.getMaxSeqKey) +} + +func (c *seqCache) GetMaxSeq(ctx context.Context, conversationID string) (int64, error) { + return c.getSeq(ctx, conversationID, c.getMaxSeqKey) +} + +func (c *seqCache) SetMinSeq(ctx context.Context, conversationID string, minSeq int64) error { + return c.setSeq(ctx, conversationID, minSeq, c.getMinSeqKey) +} + +func (c *seqCache) setSeqs(ctx context.Context, seqs map[string]int64, getkey func(key string) string) error { + for conversationID, seq := range seqs { + if err := c.rdb.Set(ctx, getkey(conversationID), seq, 0).Err(); err != nil { + return errs.Wrap(err) + } + } + return nil +} + +func (c *seqCache) SetMinSeqs(ctx context.Context, seqs map[string]int64) error { + return c.setSeqs(ctx, seqs, c.getMinSeqKey) +} + +func (c *seqCache) GetMinSeqs(ctx context.Context, conversationIDs []string) (map[string]int64, error) { + return c.getSeqs(ctx, conversationIDs, c.getMinSeqKey) +} + +func (c *seqCache) GetMinSeq(ctx context.Context, conversationID string) (int64, error) { + return c.getSeq(ctx, conversationID, c.getMinSeqKey) +} + +func (c *seqCache) GetConversationUserMinSeq(ctx context.Context, conversationID string, userID string) (int64, error) { + val, err := c.rdb.Get(ctx, c.getConversationUserMinSeqKey(conversationID, userID)).Int64() + if err != nil { + return 0, errs.Wrap(err) + } + return val, nil +} + +func (c *seqCache) GetConversationUserMinSeqs(ctx context.Context, conversationID string, userIDs []string) (m map[string]int64, err error) { + return c.getSeqs(ctx, userIDs, func(userID string) string { + return c.getConversationUserMinSeqKey(conversationID, userID) + }) +} + +func (c *seqCache) SetConversationUserMinSeq(ctx context.Context, conversationID string, userID string, minSeq int64) error { + return errs.Wrap(c.rdb.Set(ctx, c.getConversationUserMinSeqKey(conversationID, userID), minSeq, 0).Err()) +} + +func (c *seqCache) SetConversationUserMinSeqs(ctx context.Context, conversationID string, seqs map[string]int64) (err error) { + return c.setSeqs(ctx, seqs, func(userID string) string { + return c.getConversationUserMinSeqKey(conversationID, userID) + }) +} + +func (c *seqCache) SetUserConversationsMinSeqs(ctx context.Context, userID string, seqs map[string]int64) (err error) { + return c.setSeqs(ctx, seqs, func(conversationID string) string { + return c.getConversationUserMinSeqKey(conversationID, userID) + }) +} + +func (c *seqCache) SetHasReadSeq(ctx context.Context, userID string, conversationID string, hasReadSeq int64) error { + return errs.Wrap(c.rdb.Set(ctx, c.getHasReadSeqKey(conversationID, userID), hasReadSeq, 0).Err()) +} + +func (c *seqCache) SetHasReadSeqs(ctx context.Context, conversationID string, hasReadSeqs map[string]int64) error { + return c.setSeqs(ctx, hasReadSeqs, func(userID string) string { + return c.getHasReadSeqKey(conversationID, userID) + }) +} + +func (c *seqCache) UserSetHasReadSeqs(ctx context.Context, userID string, hasReadSeqs map[string]int64) error { + return c.setSeqs(ctx, hasReadSeqs, func(conversationID string) string { + return c.getHasReadSeqKey(conversationID, userID) + }) +} + +func (c *seqCache) GetHasReadSeqs(ctx context.Context, userID string, conversationIDs []string) (map[string]int64, error) { + return c.getSeqs(ctx, conversationIDs, func(conversationID string) string { + return c.getHasReadSeqKey(conversationID, userID) + }) +} + +func (c *seqCache) GetHasReadSeq(ctx context.Context, userID string, conversationID string) (int64, error) { + val, err := c.rdb.Get(ctx, c.getHasReadSeqKey(conversationID, userID)).Int64() + if err != nil { + return 0, err + } + return val, nil +} diff --git a/pkg/common/db/cache/third.go b/pkg/common/db/cache/third.go new file mode 100644 index 0000000000..d2900a32de --- /dev/null +++ b/pkg/common/db/cache/third.go @@ -0,0 +1,85 @@ +package cache + +import ( + "context" + "github.com/openimsdk/tools/errs" + "github.com/redis/go-redis/v9" + "strconv" + "time" +) + +type ThirdCache interface { + SetFcmToken(ctx context.Context, account string, platformID int, fcmToken string, expireTime int64) (err error) + GetFcmToken(ctx context.Context, account string, platformID int) (string, error) + DelFcmToken(ctx context.Context, account string, platformID int) error + IncrUserBadgeUnreadCountSum(ctx context.Context, userID string) (int, error) + SetUserBadgeUnreadCountSum(ctx context.Context, userID string, value int) error + GetUserBadgeUnreadCountSum(ctx context.Context, userID string) (int, error) + SetGetuiToken(ctx context.Context, token string, expireTime int64) error + GetGetuiToken(ctx context.Context) (string, error) + SetGetuiTaskID(ctx context.Context, taskID string, expireTime int64) error + GetGetuiTaskID(ctx context.Context) (string, error) +} + +func NewThirdCache(rdb redis.UniversalClient) ThirdCache { + return &thirdCache{rdb: rdb} +} + +type thirdCache struct { + rdb redis.UniversalClient +} + +func (c *thirdCache) SetFcmToken(ctx context.Context, account string, platformID int, fcmToken string, expireTime int64) (err error) { + return errs.Wrap(c.rdb.Set(ctx, FCM_TOKEN+account+":"+strconv.Itoa(platformID), fcmToken, time.Duration(expireTime)*time.Second).Err()) +} + +func (c *thirdCache) GetFcmToken(ctx context.Context, account string, platformID int) (string, error) { + val, err := c.rdb.Get(ctx, FCM_TOKEN+account+":"+strconv.Itoa(platformID)).Result() + if err != nil { + return "", errs.Wrap(err) + } + return val, nil +} + +func (c *thirdCache) DelFcmToken(ctx context.Context, account string, platformID int) error { + return errs.Wrap(c.rdb.Del(ctx, FCM_TOKEN+account+":"+strconv.Itoa(platformID)).Err()) +} + +func (c *thirdCache) IncrUserBadgeUnreadCountSum(ctx context.Context, userID string) (int, error) { + seq, err := c.rdb.Incr(ctx, userBadgeUnreadCountSum+userID).Result() + + return int(seq), errs.Wrap(err) +} + +func (c *thirdCache) SetUserBadgeUnreadCountSum(ctx context.Context, userID string, value int) error { + return errs.Wrap(c.rdb.Set(ctx, userBadgeUnreadCountSum+userID, value, 0).Err()) +} + +func (c *thirdCache) GetUserBadgeUnreadCountSum(ctx context.Context, userID string) (int, error) { + val, err := c.rdb.Get(ctx, userBadgeUnreadCountSum+userID).Int() + return val, errs.Wrap(err) +} + +func (c *thirdCache) SetGetuiToken(ctx context.Context, token string, expireTime int64) error { + return errs.Wrap(c.rdb.Set(ctx, getuiToken, token, time.Duration(expireTime)*time.Second).Err()) +} + +func (c *thirdCache) GetGetuiToken(ctx context.Context) (string, error) { + val, err := c.rdb.Get(ctx, getuiToken).Result() + if err != nil { + return "", errs.Wrap(err) + } + return val, nil +} + +func (c *thirdCache) SetGetuiTaskID(ctx context.Context, taskID string, expireTime int64) error { + return errs.Wrap(c.rdb.Set(ctx, getuiTaskID, taskID, time.Duration(expireTime)*time.Second).Err()) +} + +func (c *thirdCache) GetGetuiTaskID(ctx context.Context) (string, error) { + val, err := c.rdb.Get(ctx, getuiTaskID).Result() + if err != nil { + return "", errs.Wrap(err) + } + return val, nil +} diff --git a/pkg/common/db/cache/token.go b/pkg/common/db/cache/token.go new file mode 100644 index 0000000000..88580e932f --- /dev/null +++ b/pkg/common/db/cache/token.go @@ -0,0 +1,56 @@ +package cache + +import ( + "context" + + "github.com/openimsdk/open-im-server/v3/pkg/common/cachekey" + "github.com/openimsdk/tools/errs" + "github.com/openimsdk/tools/utils/stringutil" + "github.com/redis/go-redis/v9" +) + +func NewTokenCacheModel(rdb redis.UniversalClient) TokenModel { + return &tokenCache{ + rdb: rdb, + } +} + +type TokenModel interface { + AddTokenFlag(ctx context.Context, userID string, platformID int, token string, flag int) error + GetTokensWithoutError(ctx context.Context, userID string, platformID int) (map[string]int, error) + SetTokenMapByUidPid(ctx context.Context, userID string, platformID int, m map[string]int) error + DeleteTokenByUidPid(ctx context.Context, userID string, platformID int, fields []string) error +} + +type tokenCache struct { + rdb redis.UniversalClient +} + +func (c *tokenCache) AddTokenFlag(ctx context.Context, userID string, platformID int, token string, flag int) error { + return errs.Wrap(c.rdb.HSet(ctx, cachekey.GetTokenKey(userID, platformID), token, flag).Err()) +} + +func (c *tokenCache) GetTokensWithoutError(ctx context.Context, userID string, platformID int) (map[string]int, error) { + m, err := c.rdb.HGetAll(ctx, cachekey.GetTokenKey(userID, platformID)).Result() + if err != nil { + return nil, errs.Wrap(err) + } + mm := make(map[string]int) + for k, v := range m { + mm[k] = stringutil.StringToInt(v) + } + + return mm, nil +} + +func (c *tokenCache) SetTokenMapByUidPid(ctx context.Context, userID string, platformID int, m map[string]int) error { + mm := make(map[string]any) + for k, v := range m { + mm[k] = v + } + return errs.Wrap(c.rdb.HSet(ctx, cachekey.GetTokenKey(userID, platformID), mm).Err()) +} + +func (c *tokenCache) DeleteTokenByUidPid(ctx context.Context, userID string, platformID int, fields []string) error { + return errs.Wrap(c.rdb.HDel(ctx, cachekey.GetTokenKey(userID, platformID), fields...).Err()) +} diff --git a/pkg/common/db/cache/user.go b/pkg/common/db/cache/user.go index a60f558361..c10e9611a4 100644 --- a/pkg/common/db/cache/user.go +++ b/pkg/common/db/cache/user.go @@ -22,25 +22,22 @@ import ( "strconv" "time" - "github.com/OpenIMSDK/protocol/constant" - "github.com/OpenIMSDK/protocol/user" - "github.com/OpenIMSDK/tools/errs" - "github.com/OpenIMSDK/tools/log" "github.com/dtm-labs/rockscache" "github.com/openimsdk/open-im-server/v3/pkg/common/cachekey" "github.com/openimsdk/open-im-server/v3/pkg/common/config" relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" + "github.com/openimsdk/protocol/constant" + "github.com/openimsdk/protocol/user" + "github.com/openimsdk/tools/errs" + "github.com/openimsdk/tools/log" "github.com/redis/go-redis/v9" ) const ( - userExpireTime = time.Second * 60 * 60 * 12 - //userInfoKey = "USER_INFO:". - userGlobalRecvMsgOptKey = "USER_GLOBAL_RECV_MSG_OPT_KEY:" + userExpireTime = time.Second * 60 * 60 * 12 olineStatusKey = "ONLINE_STATUS:" userOlineStatusExpireTime = time.Second * 60 * 60 * 24 statusMod = 501 - platformID = "_PlatformIDSuffix" ) type UserCache interface { @@ -58,20 +55,16 @@ type UserCache interface { type UserCacheRedis struct { metaCache rdb redis.UniversalClient - //userDB relationtb.UserModelInterface + // userDB relationtb.UserModelInterface userDB relationtb.UserModelInterface expireTime time.Duration rcClient *rockscache.Client } -func NewUserCacheRedis( - rdb redis.UniversalClient, - userDB relationtb.UserModelInterface, - options rockscache.Options, -) UserCache { +func NewUserCacheRedis(rdb redis.UniversalClient, localCache *config.LocalCache, userDB relationtb.UserModelInterface, options rockscache.Options) UserCache { rcClient := rockscache.NewClient(rdb, options) mc := NewMetaCacheRedis(rcClient) - u := config.Config.LocalCache.User + u := localCache.User log.ZDebug(context.Background(), "user local cache init", "Topic", u.Topic, "SlotNum", u.SlotNum, "SlotSize", u.SlotSize, "enable", u.Enable()) mc.SetTopic(u.Topic) mc.SetRawRedisClient(rdb) @@ -294,7 +287,7 @@ func (u *UserCacheRedis) refreshStatusOnline(ctx context.Context, userID string, onlineStatus.UserID = userID newjsonData, err := json.Marshal(&onlineStatus) if err != nil { - return errs.Wrap(err, "json.Marshal failed") + return errs.WrapMsg(err, "json.Marshal failed") } _, err = u.rdb.HSet(ctx, key, userID, string(newjsonData)).Result() if err != nil { diff --git a/pkg/common/db/controller/auth.go b/pkg/common/db/controller/auth.go index 7cafa1c487..8190e5017a 100644 --- a/pkg/common/db/controller/auth.go +++ b/pkg/common/db/controller/auth.go @@ -17,13 +17,12 @@ package controller import ( "context" - "github.com/OpenIMSDK/protocol/constant" - "github.com/OpenIMSDK/tools/errs" - "github.com/OpenIMSDK/tools/tokenverify" "github.com/golang-jwt/jwt/v4" "github.com/openimsdk/open-im-server/v3/pkg/authverify" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" + "github.com/openimsdk/protocol/constant" + "github.com/openimsdk/tools/errs" + "github.com/openimsdk/tools/tokenverify" ) type AuthDatabase interface { @@ -31,17 +30,18 @@ type AuthDatabase interface { GetTokensWithoutError(ctx context.Context, userID string, platformID int) (map[string]int, error) // Create token CreateToken(ctx context.Context, userID string, platformID int) (string, error) + + SetTokenMapByUidPid(ctx context.Context, userID string, platformID int, m map[string]int) error } type authDatabase struct { - cache cache.MsgModel + cache cache.TokenModel accessSecret string accessExpire int64 - config *config.GlobalConfig } -func NewAuthDatabase(cache cache.MsgModel, accessSecret string, accessExpire int64, config *config.GlobalConfig) AuthDatabase { - return &authDatabase{cache: cache, accessSecret: accessSecret, accessExpire: accessExpire, config: config} +func NewAuthDatabase(cache cache.TokenModel, accessSecret string, accessExpire int64) AuthDatabase { + return &authDatabase{cache: cache, accessSecret: accessSecret, accessExpire: accessExpire} } // If the result is empty. @@ -49,6 +49,10 @@ func (a *authDatabase) GetTokensWithoutError(ctx context.Context, userID string, return a.cache.GetTokensWithoutError(ctx, userID, platformID) } +func (a *authDatabase) SetTokenMapByUidPid(ctx context.Context, userID string, platformID int, m map[string]int) error { + return a.cache.SetTokenMapByUidPid(ctx, userID, platformID, m) +} + // Create Token. func (a *authDatabase) CreateToken(ctx context.Context, userID string, platformID int) (string, error) { tokens, err := a.cache.GetTokensWithoutError(ctx, userID, platformID) @@ -57,7 +61,7 @@ func (a *authDatabase) CreateToken(ctx context.Context, userID string, platformI } var deleteTokenKey []string for k, v := range tokens { - _, err = tokenverify.GetClaimFromToken(k, authverify.Secret(a.config.Secret)) + _, err = tokenverify.GetClaimFromToken(k, authverify.Secret(a.accessSecret)) if err != nil || v != constant.NormalToken { deleteTokenKey = append(deleteTokenKey, k) } @@ -73,7 +77,7 @@ func (a *authDatabase) CreateToken(ctx context.Context, userID string, platformI token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) tokenString, err := token.SignedString([]byte(a.accessSecret)) if err != nil { - return "", errs.Wrap(err, "token.SignedString") + return "", errs.WrapMsg(err, "token.SignedString") } return tokenString, a.cache.AddTokenFlag(ctx, userID, platformID, tokenString, constant.NormalToken) } diff --git a/pkg/common/db/controller/black.go b/pkg/common/db/controller/black.go index c4b253c2f7..5991a9dfe5 100644 --- a/pkg/common/db/controller/black.go +++ b/pkg/common/db/controller/black.go @@ -17,11 +17,11 @@ package controller import ( "context" - "github.com/OpenIMSDK/tools/log" - "github.com/OpenIMSDK/tools/pagination" - "github.com/OpenIMSDK/tools/utils" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" + "github.com/openimsdk/tools/db/pagination" + "github.com/openimsdk/tools/log" + "github.com/openimsdk/tools/utils/datautil" ) type BlackDatabase interface { @@ -86,7 +86,7 @@ func (b *blackDatabase) CheckIn(ctx context.Context, userID1, userID2 string) (i return } log.ZDebug(ctx, "blackIDs", "user1BlackIDs", userID1BlackIDs, "user2BlackIDs", userID2BlackIDs) - return utils.IsContain(userID2, userID1BlackIDs), utils.IsContain(userID1, userID2BlackIDs), nil + return datautil.Contain(userID2, userID1BlackIDs...), datautil.Contain(userID1, userID2BlackIDs...), nil } // FindBlackIDs Get Blacklist List. diff --git a/pkg/common/db/controller/conversation.go b/pkg/common/db/controller/conversation.go index 3d46e4fbc4..567bcb2704 100644 --- a/pkg/common/db/controller/conversation.go +++ b/pkg/common/db/controller/conversation.go @@ -18,14 +18,15 @@ import ( "context" "time" - "github.com/OpenIMSDK/protocol/constant" - "github.com/OpenIMSDK/tools/log" - "github.com/OpenIMSDK/tools/pagination" - "github.com/OpenIMSDK/tools/tx" - "github.com/OpenIMSDK/tools/utils" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" "github.com/openimsdk/open-im-server/v3/pkg/msgprocessor" + "github.com/openimsdk/protocol/constant" + "github.com/openimsdk/tools/db/pagination" + "github.com/openimsdk/tools/db/tx" + "github.com/openimsdk/tools/log" + "github.com/openimsdk/tools/utils/datautil" + "github.com/openimsdk/tools/utils/stringutil" ) type ConversationDatabase interface { @@ -62,11 +63,11 @@ type ConversationDatabase interface { GetConversationIDsNeedDestruct(ctx context.Context) ([]*relationtb.ConversationModel, error) // GetConversationNotReceiveMessageUserIDs gets user IDs for users in a conversation who have not received messages. GetConversationNotReceiveMessageUserIDs(ctx context.Context, conversationID string) ([]string, error) - //GetUserAllHasReadSeqs(ctx context.Context, ownerUserID string) (map[string]int64, error) - //FindRecvMsgNotNotifyUserIDs(ctx context.Context, groupID string) ([]string, error) + // GetUserAllHasReadSeqs(ctx context.Context, ownerUserID string) (map[string]int64, error) + // FindRecvMsgNotNotifyUserIDs(ctx context.Context, groupID string) ([]string, error) } -func NewConversationDatabase(conversation relationtb.ConversationModelInterface, cache cache.ConversationCache, tx tx.CtxTx) ConversationDatabase { +func NewConversationDatabase(conversation relationtb.ConversationModelInterface, cache cache.ConversationCache, tx tx.Tx) ConversationDatabase { return &conversationDatabase{ conversationDB: conversation, cache: cache, @@ -77,7 +78,7 @@ func NewConversationDatabase(conversation relationtb.ConversationModelInterface, type conversationDatabase struct { conversationDB relationtb.ConversationModelInterface cache cache.ConversationCache - tx tx.CtxTx + tx tx.Tx } func (c *conversationDatabase) SetUsersConversationFieldTx(ctx context.Context, userIDs []string, conversation *relationtb.ConversationModel, fieldMap map[string]any) (err error) { @@ -105,13 +106,13 @@ func (c *conversationDatabase) SetUsersConversationFieldTx(ctx context.Context, cache = cache.DelConversationNotReceiveMessageUserIDs(conversation.ConversationID) } } - NotUserIDs := utils.DifferenceString(haveUserIDs, userIDs) + NotUserIDs := stringutil.DifferenceString(haveUserIDs, userIDs) log.ZDebug(ctx, "SetUsersConversationFieldTx", "NotUserIDs", NotUserIDs, "haveUserIDs", haveUserIDs, "userIDs", userIDs) var conversations []*relationtb.ConversationModel now := time.Now() for _, v := range NotUserIDs { temp := new(relationtb.ConversationModel) - if err = utils.CopyStructFields(temp, conversation); err != nil { + if err = datautil.CopyStructFields(temp, conversation); err != nil { return err } temp.OwnerUserID = v @@ -205,7 +206,7 @@ func (c *conversationDatabase) GetUserAllConversation(ctx context.Context, owner func (c *conversationDatabase) SetUserConversations(ctx context.Context, ownerUserID string, conversations []*relationtb.ConversationModel) error { return c.tx.Transaction(ctx, func(ctx context.Context) error { cache := c.cache.NewCache() - groupIDs := utils.Distinct(utils.Filter(conversations, func(e *relationtb.ConversationModel) (string, bool) { + groupIDs := datautil.Distinct(datautil.Filter(conversations, func(e *relationtb.ConversationModel) (string, bool) { return e.GroupID, e.GroupID != "" })) for _, groupID := range groupIDs { @@ -235,7 +236,7 @@ func (c *conversationDatabase) SetUserConversations(ctx context.Context, ownerUs var notExistConversations []*relationtb.ConversationModel for _, conversation := range conversations { - if !utils.IsContain(conversation.ConversationID, existConversationIDs) { + if !datautil.Contain(conversation.ConversationID, existConversationIDs...) { notExistConversations = append(notExistConversations, conversation) } } @@ -246,28 +247,28 @@ func (c *conversationDatabase) SetUserConversations(ctx context.Context, ownerUs } cache = cache.DelConversationIDs(ownerUserID). DelUserConversationIDsHash(ownerUserID). - DelConversationNotReceiveMessageUserIDs(utils.Slice(notExistConversations, func(e *relationtb.ConversationModel) string { return e.ConversationID })...) + DelConversationNotReceiveMessageUserIDs(datautil.Slice(notExistConversations, func(e *relationtb.ConversationModel) string { return e.ConversationID })...) } return cache.ExecDel(ctx) }) } -//func (c *conversationDatabase) FindRecvMsgNotNotifyUserIDs(ctx context.Context, groupID string) ([]string, error) { +// func (c *conversationDatabase) FindRecvMsgNotNotifyUserIDs(ctx context.Context, groupID string) ([]string, error) { // return c.cache.GetSuperGroupRecvMsgNotNotifyUserIDs(ctx, groupID) //} func (c *conversationDatabase) CreateGroupChatConversation(ctx context.Context, groupID string, userIDs []string) error { return c.tx.Transaction(ctx, func(ctx context.Context) error { cache := c.cache.NewCache() - conversationID := msgprocessor.GetConversationIDBySessionType(constant.SuperGroupChatType, groupID) + conversationID := msgprocessor.GetConversationIDBySessionType(constant.ReadGroupChatType, groupID) existConversationUserIDs, err := c.conversationDB.FindUserID(ctx, userIDs, []string{conversationID}) if err != nil { return err } - notExistUserIDs := utils.DifferenceString(userIDs, existConversationUserIDs) + notExistUserIDs := stringutil.DifferenceString(userIDs, existConversationUserIDs) var conversations []*relationtb.ConversationModel for _, v := range notExistUserIDs { - conversation := relationtb.ConversationModel{ConversationType: constant.SuperGroupChatType, GroupID: groupID, OwnerUserID: v, ConversationID: conversationID} + conversation := relationtb.ConversationModel{ConversationType: constant.ReadGroupChatType, GroupID: groupID, OwnerUserID: v, ConversationID: conversationID} conversations = append(conversations, &conversation) cache = cache.DelConversations(v, conversationID).DelConversationNotReceiveMessageUserIDs(conversationID) } diff --git a/pkg/common/db/controller/doc.go b/pkg/common/db/controller/doc.go index 72316f1280..97ec08799f 100644 --- a/pkg/common/db/controller/doc.go +++ b/pkg/common/db/controller/doc.go @@ -1,4 +1,4 @@ -// Copyright © 2023 OpenIM. All rights reserved. +// 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. diff --git a/pkg/common/db/controller/friend.go b/pkg/common/db/controller/friend.go index 3c81d922ce..49136f2288 100644 --- a/pkg/common/db/controller/friend.go +++ b/pkg/common/db/controller/friend.go @@ -19,15 +19,15 @@ import ( "fmt" "time" - "github.com/OpenIMSDK/protocol/constant" - "github.com/OpenIMSDK/tools/errs" - "github.com/OpenIMSDK/tools/log" - "github.com/OpenIMSDK/tools/mcontext" - "github.com/OpenIMSDK/tools/pagination" - "github.com/OpenIMSDK/tools/tx" - "github.com/OpenIMSDK/tools/utils" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" + "github.com/openimsdk/protocol/constant" + "github.com/openimsdk/tools/db/pagination" + "github.com/openimsdk/tools/db/tx" + "github.com/openimsdk/tools/errs" + "github.com/openimsdk/tools/log" + "github.com/openimsdk/tools/mcontext" + "github.com/openimsdk/tools/utils/datautil" ) type FriendDatabase interface { @@ -80,11 +80,11 @@ type FriendDatabase interface { type friendDatabase struct { friend relation.FriendModelInterface friendRequest relation.FriendRequestModelInterface - tx tx.CtxTx + tx tx.Tx cache cache.FriendCache } -func NewFriendDatabase(friend relation.FriendModelInterface, friendRequest relation.FriendRequestModelInterface, cache cache.FriendCache, tx tx.CtxTx) FriendDatabase { +func NewFriendDatabase(friend relation.FriendModelInterface, friendRequest relation.FriendRequestModelInterface, cache cache.FriendCache, tx tx.Tx) FriendDatabase { return &friendDatabase{friend: friend, friendRequest: friendRequest, cache: cache, tx: tx} } @@ -106,8 +106,8 @@ func (f *friendDatabase) CheckIn(ctx context.Context, userID1, userID2 string) ( } // Check if userID2 is in userID1's friend list and vice versa - inUser1Friends = utils.IsContain(userID2, userID1FriendIDs) - inUser2Friends = utils.IsContain(userID1, userID2FriendIDs) + inUser1Friends = datautil.Contain(userID2, userID1FriendIDs...) + inUser2Friends = datautil.Contain(userID1, userID2FriendIDs...) return inUser1Friends, inUser2Friends, nil } @@ -139,7 +139,7 @@ func (f *friendDatabase) AddFriendRequest(ctx context.Context, fromUserID, toUse func (f *friendDatabase) BecomeFriends(ctx context.Context, ownerUserID string, friendUserIDs []string, addSource int32) (err error) { return f.tx.Transaction(ctx, func(ctx context.Context) error { cache := f.cache.NewCache() - // User find friends + // user find friends fs1, err := f.friend.FindFriends(ctx, ownerUserID, friendUserIDs) if err != nil { return err @@ -148,7 +148,7 @@ func (f *friendDatabase) BecomeFriends(ctx context.Context, ownerUserID string, for _, v := range friendUserIDs { fs1 = append(fs1, &relation.FriendModel{OwnerUserID: ownerUserID, FriendUserID: v, AddSource: addSource, OperatorUserID: opUserID}) } - fs11 := utils.DistinctAny(fs1, func(e *relation.FriendModel) string { + fs11 := datautil.DistinctAny(fs1, func(e *relation.FriendModel) string { return e.FriendUserID }) @@ -165,7 +165,7 @@ func (f *friendDatabase) BecomeFriends(ctx context.Context, ownerUserID string, fs2 = append(fs2, &relation.FriendModel{OwnerUserID: v, FriendUserID: ownerUserID, AddSource: addSource, OperatorUserID: opUserID}) newFriendIDs = append(newFriendIDs, v) } - fs22 := utils.DistinctAny(fs2, func(e *relation.FriendModel) string { + fs22 := datautil.DistinctAny(fs2, func(e *relation.FriendModel) string { return e.OwnerUserID }) err = f.friend.Create(ctx, fs22) @@ -212,14 +212,13 @@ func (f *friendDatabase) RefuseFriendRequest(ctx context.Context, friendRequest // AgreeFriendRequest accepts a friend request. It first checks for an existing, unprocessed request. func (f *friendDatabase) AgreeFriendRequest(ctx context.Context, friendRequest *relation.FriendRequestModel) (err error) { return f.tx.Transaction(ctx, func(ctx context.Context) error { - defer log.ZDebug(ctx, "return line") now := time.Now() fr, err := f.friendRequest.Take(ctx, friendRequest.FromUserID, friendRequest.ToUserID) if err != nil { return err } if fr.HandleResult != 0 { - return errs.ErrArgs.Wrap("the friend request has been processed") + return errs.ErrArgs.WrapMsg("the friend request has been processed") } friendRequest.HandlerUserID = mcontext.GetOpUserID(ctx) friendRequest.HandleResult = constant.FriendResponseAgree @@ -246,7 +245,7 @@ func (f *friendDatabase) AgreeFriendRequest(ctx context.Context, friendRequest * if err != nil { return err } - existsMap := utils.SliceSet(utils.Slice(exists, func(friend *relation.FriendModel) [2]string { + existsMap := datautil.SliceSet(datautil.Slice(exists, func(friend *relation.FriendModel) [2]string { return [...]string{friend.OwnerUserID, friend.FriendUserID} // My - Friend })) var adds []*relation.FriendModel diff --git a/pkg/common/db/controller/group.go b/pkg/common/db/controller/group.go index 45bf87b6f1..ddf72b7bf1 100644 --- a/pkg/common/db/controller/group.go +++ b/pkg/common/db/controller/group.go @@ -16,15 +16,16 @@ package controller import ( "context" + "github.com/openimsdk/open-im-server/v3/pkg/common/config" "time" - "github.com/OpenIMSDK/protocol/constant" - "github.com/OpenIMSDK/tools/pagination" - "github.com/OpenIMSDK/tools/tx" - "github.com/OpenIMSDK/tools/utils" "github.com/dtm-labs/rockscache" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" + "github.com/openimsdk/protocol/constant" + "github.com/openimsdk/tools/db/pagination" + "github.com/openimsdk/tools/db/tx" + "github.com/openimsdk/tools/utils/datautil" "github.com/redis/go-redis/v9" ) @@ -107,10 +108,11 @@ type GroupDatabase interface { func NewGroupDatabase( rdb redis.UniversalClient, + localCache *config.LocalCache, groupDB relationtb.GroupModelInterface, groupMemberDB relationtb.GroupMemberModelInterface, groupRequestDB relationtb.GroupRequestModelInterface, - ctxTx tx.CtxTx, + ctxTx tx.Tx, groupHash cache.GroupHash, ) GroupDatabase { rcOptions := rockscache.NewDefaultOptions() @@ -121,7 +123,7 @@ func NewGroupDatabase( groupMemberDB: groupMemberDB, groupRequestDB: groupRequestDB, ctxTx: ctxTx, - cache: cache.NewGroupCacheRedis(rdb, groupDB, groupMemberDB, groupRequestDB, groupHash, rcOptions), + cache: cache.NewGroupCacheRedis(rdb, localCache, groupDB, groupMemberDB, groupRequestDB, groupHash, rcOptions), } } @@ -129,7 +131,7 @@ type groupDatabase struct { groupDB relationtb.GroupModelInterface groupMemberDB relationtb.GroupMemberModelInterface groupRequestDB relationtb.GroupRequestModelInterface - ctxTx tx.CtxTx + ctxTx tx.Tx cache cache.GroupCache } @@ -270,7 +272,7 @@ func (g *groupDatabase) PageGetJoinGroup(ctx context.Context, userID string, pag if err != nil { return 0, nil, err } - for _, groupID := range utils.Paginate(groupIDs, int(pagination.GetPageNumber()), int(pagination.GetShowNumber())) { + for _, groupID := range datautil.Paginate(groupIDs, int(pagination.GetPageNumber()), int(pagination.GetShowNumber())) { groupMembers, err := g.cache.GetGroupMembersInfo(ctx, groupID, []string{userID}) if err != nil { return 0, nil, err @@ -285,7 +287,7 @@ func (g *groupDatabase) PageGetGroupMember(ctx context.Context, groupID string, if err != nil { return 0, nil, err } - pageIDs := utils.Paginate(groupMemberIDs, int(pagination.GetPageNumber()), int(pagination.GetShowNumber())) + pageIDs := datautil.Paginate(groupMemberIDs, int(pagination.GetPageNumber()), int(pagination.GetShowNumber())) if len(pageIDs) == 0 { return int64(len(groupMemberIDs)), nil, nil } diff --git a/pkg/common/db/controller/msg.go b/pkg/common/db/controller/msg.go index ccf209b7a1..130e35d20e 100644 --- a/pkg/common/db/controller/msg.go +++ b/pkg/common/db/controller/msg.go @@ -17,22 +17,21 @@ package controller import ( "context" "encoding/json" - "errors" "time" - "github.com/OpenIMSDK/protocol/constant" - pbmsg "github.com/OpenIMSDK/protocol/msg" - "github.com/OpenIMSDK/protocol/sdkws" - "github.com/OpenIMSDK/tools/errs" - "github.com/OpenIMSDK/tools/log" - "github.com/OpenIMSDK/tools/utils" "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/convert" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" - unrelationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/unrelation" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/unrelation" - "github.com/openimsdk/open-im-server/v3/pkg/common/kafka" + "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" "github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics" + "github.com/openimsdk/protocol/constant" + pbmsg "github.com/openimsdk/protocol/msg" + "github.com/openimsdk/protocol/sdkws" + "github.com/openimsdk/tools/errs" + "github.com/openimsdk/tools/log" + "github.com/openimsdk/tools/mq/kafka" + "github.com/openimsdk/tools/utils/datautil" + "github.com/openimsdk/tools/utils/timeutil" "github.com/redis/go-redis/v9" "go.mongodb.org/mongo-driver/mongo" ) @@ -47,7 +46,7 @@ type CommonMsgDatabase interface { // BatchInsertChat2DB inserts a batch of messages into the database for a specific conversation. BatchInsertChat2DB(ctx context.Context, conversationID string, msgs []*sdkws.MsgData, currentMaxSeq int64) error // RevokeMsg revokes a message in a conversation. - RevokeMsg(ctx context.Context, conversationID string, seq int64, revoke *unrelationtb.RevokeModel) error + RevokeMsg(ctx context.Context, conversationID string, seq int64, revoke *relation.RevokeModel) error // MarkSingleChatMsgsAsRead marks messages as read for a single chat by sequence numbers. MarkSingleChatMsgsAsRead(ctx context.Context, userID string, conversationID string, seqs []int64) error // DeleteMessagesFromCache deletes message caches from Redis by sequence numbers. @@ -100,75 +99,54 @@ type CommonMsgDatabase interface { MsgToPushMQ(ctx context.Context, key, conversarionID string, msg2mq *sdkws.MsgData) (int32, int64, error) MsgToMongoMQ(ctx context.Context, key, conversarionID string, msgs []*sdkws.MsgData, lastSeq int64) error - RangeUserSendCount( - ctx context.Context, - start time.Time, - end time.Time, - group bool, - ase bool, - pageNumber int32, - showNumber int32, - ) (msgCount int64, userCount int64, users []*unrelationtb.UserCount, dateCount map[string]int64, err error) - RangeGroupSendCount( - ctx context.Context, - start time.Time, - end time.Time, - ase bool, - pageNumber int32, - showNumber int32, - ) (msgCount int64, userCount int64, groups []*unrelationtb.GroupCount, dateCount map[string]int64, err error) + RangeUserSendCount(ctx context.Context, start time.Time, end time.Time, group bool, ase bool, pageNumber int32, showNumber int32) (msgCount int64, userCount int64, users []*relation.UserCount, dateCount map[string]int64, err error) + RangeGroupSendCount(ctx context.Context, start time.Time, end time.Time, ase bool, pageNumber int32, showNumber int32) (msgCount int64, userCount int64, groups []*relation.GroupCount, dateCount map[string]int64, err error) ConvertMsgsDocLen(ctx context.Context, conversationIDs []string) } -func NewCommonMsgDatabase(msgDocModel unrelationtb.MsgDocModelInterface, cacheModel cache.MsgModel, config *config.GlobalConfig) (CommonMsgDatabase, error) { - producerConfig := &kafka.ProducerConfig{ - ProducerAck: config.Kafka.ProducerAck, - CompressType: config.Kafka.CompressType, - Username: config.Kafka.Username, - Password: config.Kafka.Password, - } - - var tlsConfig *kafka.TLSConfig - if config.Kafka.TLS != nil { - tlsConfig = &kafka.TLSConfig{ - CACrt: config.Kafka.TLS.CACrt, - ClientCrt: config.Kafka.TLS.ClientCrt, - ClientKey: config.Kafka.TLS.ClientKey, - ClientKeyPwd: config.Kafka.TLS.ClientKeyPwd, - InsecureSkipVerify: false, - } +func NewCommonMsgDatabase(msgDocModel relation.MsgDocModelInterface, msg cache.MsgCache, seq cache.SeqCache, kafkaConf *config.Kafka) (CommonMsgDatabase, error) { + conf, err := kafka.BuildProducerConfig(*kafkaConf.Build()) + if err != nil { + return nil, err } - producerToRedis, err := kafka.NewKafkaProducer(config.Kafka.Addr, config.Kafka.LatestMsgToRedis.Topic, producerConfig, tlsConfig) + producerToRedis, err := kafka.NewKafkaProducer(conf, kafkaConf.Address, kafkaConf.ToRedisTopic) if err != nil { return nil, err } - producerToMongo, err := kafka.NewKafkaProducer(config.Kafka.Addr, config.Kafka.MsgToMongo.Topic, producerConfig, tlsConfig) + producerToMongo, err := kafka.NewKafkaProducer(conf, kafkaConf.Address, kafkaConf.ToMongoTopic) if err != nil { return nil, err } - producerToPush, err := kafka.NewKafkaProducer(config.Kafka.Addr, config.Kafka.MsgToPush.Topic, producerConfig, tlsConfig) + producerToPush, err := kafka.NewKafkaProducer(conf, kafkaConf.Address, kafkaConf.ToPushTopic) if err != nil { return nil, err } return &commonMsgDatabase{ msgDocDatabase: msgDocModel, - cache: cacheModel, + msg: msg, + seq: seq, producer: producerToRedis, producerToMongo: producerToMongo, producerToPush: producerToPush, }, nil } -func InitCommonMsgDatabase(rdb redis.UniversalClient, database *mongo.Database, config *config.GlobalConfig) (CommonMsgDatabase, error) { - cacheModel := cache.NewMsgCacheModel(rdb, config) - msgDocModel := unrelation.NewMsgMongoDriver(database) - return NewCommonMsgDatabase(msgDocModel, cacheModel, config) -} +//func InitCommonMsgDatabase(rdb redis.UniversalClient, database *mongo.Database, config *tools.CronTaskConfig) (CommonMsgDatabase, error) { +// msgDocModel, err := mgo.NewMsgMongo(database) +// if err != nil { +// return nil, err +// } +// //todo MsgCacheTimeout +// msg := cache.NewMsgCache(rdb, 86400, config.RedisConfig.EnablePipeline) +// seq := cache.NewSeqCache(rdb) +// return NewCommonMsgDatabase(msgDocModel, msg, seq, &config.KafkaConfig) +//} type commonMsgDatabase struct { - msgDocDatabase unrelationtb.MsgDocModelInterface - msg unrelationtb.MsgDocModel - cache cache.MsgModel + msgDocDatabase relation.MsgDocModelInterface + msgTable relation.MsgDocModel + msg cache.MsgCache + seq cache.SeqCache producer *kafka.Producer producerToMongo *kafka.Producer producerToModify *kafka.Producer @@ -209,24 +187,24 @@ func (db *commonMsgDatabase) BatchInsertBlock(ctx context.Context, conversationI if len(fields) == 0 { return nil } - num := db.msg.GetSingleGocMsgNum() + num := db.msgTable.GetSingleGocMsgNum() // num = 100 for i, field := range fields { // Check the type of the field var ok bool switch key { case updateKeyMsg: - var msg *unrelationtb.MsgDataModel - msg, ok = field.(*unrelationtb.MsgDataModel) + var msg *relation.MsgDataModel + msg, ok = field.(*relation.MsgDataModel) if msg != nil && msg.Seq != firstSeq+int64(i) { - return errs.ErrInternalServer.Wrap("seq is invalid") + return errs.ErrInternalServer.WrapMsg("seq is invalid") } case updateKeyRevoke: - _, ok = field.(*unrelationtb.RevokeModel) + _, ok = field.(*relation.RevokeModel) default: - return errs.ErrInternalServer.Wrap("key is invalid") + return errs.ErrInternalServer.WrapMsg("key is invalid") } if !ok { - return errs.ErrInternalServer.Wrap("field type is invalid") + return errs.ErrInternalServer.WrapMsg("field type is invalid") } } // Returns true if the document exists in the database, false if the document does not exist in the database @@ -235,8 +213,8 @@ func (db *commonMsgDatabase) BatchInsertBlock(ctx context.Context, conversationI res *mongo.UpdateResult err error ) - docID := db.msg.GetDocID(conversationID, seq) - index := db.msg.GetMsgIndex(seq) + docID := db.msgTable.GetDocID(conversationID, seq) + index := db.msgTable.GetMsgIndex(seq) field := fields[i] switch key { case updateKeyMsg: @@ -261,31 +239,31 @@ func (db *commonMsgDatabase) BatchInsertBlock(ctx context.Context, conversationI continue // The current data has been updated, skip the current data } } - doc := unrelationtb.MsgDocModel{ - DocID: db.msg.GetDocID(conversationID, seq), - Msg: make([]*unrelationtb.MsgInfoModel, num), + doc := relation.MsgDocModel{ + DocID: db.msgTable.GetDocID(conversationID, seq), + Msg: make([]*relation.MsgInfoModel, num), } var insert int // Inserted data number for j := i; j < len(fields); j++ { seq = firstSeq + int64(j) - if db.msg.GetDocID(conversationID, seq) != doc.DocID { + if db.msgTable.GetDocID(conversationID, seq) != doc.DocID { break } insert++ switch key { case updateKeyMsg: - doc.Msg[db.msg.GetMsgIndex(seq)] = &unrelationtb.MsgInfoModel{ - Msg: fields[j].(*unrelationtb.MsgDataModel), + doc.Msg[db.msgTable.GetMsgIndex(seq)] = &relation.MsgInfoModel{ + Msg: fields[j].(*relation.MsgDataModel), } case updateKeyRevoke: - doc.Msg[db.msg.GetMsgIndex(seq)] = &unrelationtb.MsgInfoModel{ - Revoke: fields[j].(*unrelationtb.RevokeModel), + doc.Msg[db.msgTable.GetMsgIndex(seq)] = &relation.MsgInfoModel{ + Revoke: fields[j].(*relation.RevokeModel), } } } for i, model := range doc.Msg { if model == nil { - model = &unrelationtb.MsgInfoModel{} + model = &relation.MsgInfoModel{} doc.Msg[i] = model } if model.DelList == nil { @@ -308,16 +286,16 @@ func (db *commonMsgDatabase) BatchInsertBlock(ctx context.Context, conversationI func (db *commonMsgDatabase) BatchInsertChat2DB(ctx context.Context, conversationID string, msgList []*sdkws.MsgData, currentMaxSeq int64) error { if len(msgList) == 0 { - return errs.ErrArgs.Wrap("msgList is empty") + return errs.ErrArgs.WrapMsg("msgList is empty") } msgs := make([]any, len(msgList)) for i, msg := range msgList { if msg == nil { continue } - var offlinePushModel *unrelationtb.OfflinePushModel + var offlinePushModel *relation.OfflinePushModel if msg.OfflinePushInfo != nil { - offlinePushModel = &unrelationtb.OfflinePushModel{ + offlinePushModel = &relation.OfflinePushModel{ Title: msg.OfflinePushInfo.Title, Desc: msg.OfflinePushInfo.Desc, Ex: msg.OfflinePushInfo.Ex, @@ -325,7 +303,7 @@ func (db *commonMsgDatabase) BatchInsertChat2DB(ctx context.Context, conversatio IOSBadgeCount: msg.OfflinePushInfo.IOSBadgeCount, } } - msgs[i] = &unrelationtb.MsgDataModel{ + msgs[i] = &relation.MsgDataModel{ SendID: msg.SendID, RecvID: msg.RecvID, GroupID: msg.GroupID, @@ -352,15 +330,15 @@ func (db *commonMsgDatabase) BatchInsertChat2DB(ctx context.Context, conversatio return db.BatchInsertBlock(ctx, conversationID, msgs, updateKeyMsg, msgList[0].Seq) } -func (db *commonMsgDatabase) RevokeMsg(ctx context.Context, conversationID string, seq int64, revoke *unrelationtb.RevokeModel) error { +func (db *commonMsgDatabase) RevokeMsg(ctx context.Context, conversationID string, seq int64, revoke *relation.RevokeModel) error { return db.BatchInsertBlock(ctx, conversationID, []any{revoke}, updateKeyRevoke, seq) } func (db *commonMsgDatabase) MarkSingleChatMsgsAsRead(ctx context.Context, userID string, conversationID string, totalSeqs []int64) error { - for docID, seqs := range db.msg.GetDocIDSeqsMap(conversationID, totalSeqs) { + for docID, seqs := range db.msgTable.GetDocIDSeqsMap(conversationID, totalSeqs) { var indexes []int64 for _, seq := range seqs { - indexes = append(indexes, db.msg.GetMsgIndex(seq)) + indexes = append(indexes, db.msgTable.GetMsgIndex(seq)) } log.ZDebug(ctx, "MarkSingleChatMsgsAsRead", "userID", userID, "docID", docID, "indexes", indexes) if err := db.msgDocDatabase.MarkSingleChatMsgsAsRead(ctx, userID, docID, indexes); err != nil { @@ -372,25 +350,25 @@ func (db *commonMsgDatabase) MarkSingleChatMsgsAsRead(ctx context.Context, userI } func (db *commonMsgDatabase) DeleteMessagesFromCache(ctx context.Context, conversationID string, seqs []int64) error { - return db.cache.DeleteMessages(ctx, conversationID, seqs) + return db.msg.DeleteMessages(ctx, conversationID, seqs) } func (db *commonMsgDatabase) DelUserDeleteMsgsList(ctx context.Context, conversationID string, seqs []int64) { - db.cache.DelUserDeleteMsgsList(ctx, conversationID, seqs) + db.msg.DelUserDeleteMsgsList(ctx, conversationID, seqs) } func (db *commonMsgDatabase) BatchInsertChat2Cache(ctx context.Context, conversationID string, msgs []*sdkws.MsgData) (seq int64, isNew bool, err error) { - currentMaxSeq, err := db.cache.GetMaxSeq(ctx, conversationID) + currentMaxSeq, err := db.seq.GetMaxSeq(ctx, conversationID) if err != nil && errs.Unwrap(err) != redis.Nil { - log.ZError(ctx, "db.cache.GetMaxSeq", err) + log.ZError(ctx, "db.seq.GetMaxSeq", err) return 0, false, err } lenList := len(msgs) - if int64(lenList) > db.msg.GetSingleGocMsgNum() { - return 0, false, errors.New("too large") + if int64(lenList) > db.msgTable.GetSingleGocMsgNum() { + return 0, false, errs.New("message count exceeds limit", "limit", db.msgTable.GetSingleGocMsgNum()).Wrap() } if lenList < 1 { - return 0, false, errors.New("too short as 0") + return 0, false, errs.New("no messages to insert", "minCount", 1).Wrap() } if errs.Unwrap(err) == redis.Nil { isNew = true @@ -402,19 +380,22 @@ func (db *commonMsgDatabase) BatchInsertChat2Cache(ctx context.Context, conversa m.Seq = currentMaxSeq userSeqMap[m.SendID] = m.Seq } - failedNum, err := db.cache.SetMessageToCache(ctx, conversationID, msgs) + + failedNum, err := db.msg.SetMessageToCache(ctx, conversationID, msgs) if err != nil { prommetrics.MsgInsertRedisFailedCounter.Add(float64(failedNum)) log.ZError(ctx, "setMessageToCache error", err, "len", len(msgs), "conversationID", conversationID) } else { prommetrics.MsgInsertRedisSuccessCounter.Inc() } - err = db.cache.SetMaxSeq(ctx, conversationID, currentMaxSeq) + + err = db.seq.SetMaxSeq(ctx, conversationID, currentMaxSeq) if err != nil { - log.ZError(ctx, "db.cache.SetMaxSeq error", err, "conversationID", conversationID) + log.ZError(ctx, "db.seq.SetMaxSeq error", err, "conversationID", conversationID) prommetrics.SeqSetFailedCounter.Inc() } - err = db.cache.SetHasReadSeqs(ctx, conversationID, userSeqMap) + + err = db.seq.SetHasReadSeqs(ctx, conversationID, userSeqMap) if err != nil { log.ZError(ctx, "SetHasReadSeqs error", err, "userSeqMap", userSeqMap, "conversationID", conversationID) prommetrics.SeqSetFailedCounter.Inc() @@ -423,7 +404,7 @@ func (db *commonMsgDatabase) BatchInsertChat2Cache(ctx context.Context, conversa } func (db *commonMsgDatabase) getMsgBySeqs(ctx context.Context, userID, conversationID string, seqs []int64) (totalMsgs []*sdkws.MsgData, err error) { - for docID, seqs := range db.msg.GetDocIDSeqsMap(conversationID, seqs) { + for docID, seqs := range db.msgTable.GetDocIDSeqsMap(conversationID, seqs) { // log.ZDebug(ctx, "getMsgBySeqs", "docID", docID, "seqs", seqs) msgs, err := db.findMsgInfoBySeq(ctx, userID, docID, conversationID, seqs) if err != nil { @@ -436,7 +417,7 @@ func (db *commonMsgDatabase) getMsgBySeqs(ctx context.Context, userID, conversat return totalMsgs, nil } -func (db *commonMsgDatabase) handlerDBMsg(ctx context.Context, cache map[int64][]*unrelationtb.MsgInfoModel, userID, conversationID string, msg *unrelationtb.MsgInfoModel) { +func (db *commonMsgDatabase) handlerDBMsg(ctx context.Context, cache map[int64][]*relation.MsgInfoModel, userID, conversationID string, msg *relation.MsgInfoModel) { if msg.IsRead { msg.Msg.IsRead = true } @@ -458,12 +439,12 @@ func (db *commonMsgDatabase) handlerDBMsg(ctx context.Context, cache map[int64][ if quoteMsg.QuoteMessage == nil || quoteMsg.QuoteMessage.ContentType == constant.MsgRevokeNotification { return } - var msgs []*unrelationtb.MsgInfoModel + var msgs []*relation.MsgInfoModel if v, ok := cache[quoteMsg.QuoteMessage.Seq]; ok { msgs = v } else { if quoteMsg.QuoteMessage.Seq > 0 { - ms, err := db.msgDocDatabase.GetMsgBySeqIndexIn1Doc(ctx, userID, db.msg.GetDocID(conversationID, quoteMsg.QuoteMessage.Seq), []int64{quoteMsg.QuoteMessage.Seq}) + ms, err := db.msgDocDatabase.GetMsgBySeqIndexIn1Doc(ctx, userID, db.msgTable.GetDocID(conversationID, quoteMsg.QuoteMessage.Seq), []int64{quoteMsg.QuoteMessage.Seq}) if err != nil { log.ZError(ctx, "GetMsgBySeqIndexIn1Doc", err, "conversationID", conversationID, "seq", quoteMsg.QuoteMessage.Seq) return @@ -487,17 +468,17 @@ func (db *commonMsgDatabase) handlerDBMsg(ctx context.Context, cache map[int64][ return } msg.Msg.Content = string(data) - if _, err := db.msgDocDatabase.UpdateMsg(ctx, db.msg.GetDocID(conversationID, msg.Msg.Seq), db.msg.GetMsgIndex(msg.Msg.Seq), "msg", msg.Msg); err != nil { + if _, err := db.msgDocDatabase.UpdateMsg(ctx, db.msgTable.GetDocID(conversationID, msg.Msg.Seq), db.msgTable.GetMsgIndex(msg.Msg.Seq), "msg", msg.Msg); err != nil { log.ZError(ctx, "UpdateMsgContent", err) } } -func (db *commonMsgDatabase) findMsgInfoBySeq(ctx context.Context, userID, docID string, conversationID string, seqs []int64) (totalMsgs []*unrelationtb.MsgInfoModel, err error) { +func (db *commonMsgDatabase) findMsgInfoBySeq(ctx context.Context, userID, docID string, conversationID string, seqs []int64) (totalMsgs []*relation.MsgInfoModel, err error) { msgs, err := db.msgDocDatabase.GetMsgBySeqIndexIn1Doc(ctx, userID, docID, seqs) if err != nil { return nil, err } - tempCache := make(map[int64][]*unrelationtb.MsgInfoModel) + tempCache := make(map[int64][]*relation.MsgInfoModel) for _, msg := range msgs { db.handlerDBMsg(ctx, tempCache, userID, conversationID, msg) } @@ -506,7 +487,7 @@ func (db *commonMsgDatabase) findMsgInfoBySeq(ctx context.Context, userID, docID func (db *commonMsgDatabase) getMsgBySeqsRange(ctx context.Context, userID string, conversationID string, allSeqs []int64, begin, end int64) (seqMsgs []*sdkws.MsgData, err error) { log.ZDebug(ctx, "getMsgBySeqsRange", "conversationID", conversationID, "allSeqs", allSeqs, "begin", begin, "end", end) - for docID, seqs := range db.msg.GetDocIDSeqsMap(conversationID, allSeqs) { + for docID, seqs := range db.msgTable.GetDocIDSeqsMap(conversationID, allSeqs) { log.ZDebug(ctx, "getMsgBySeqsRange", "docID", docID, "seqs", seqs) msgs, err := db.findMsgInfoBySeq(ctx, userID, docID, conversationID, seqs) if err != nil { @@ -542,23 +523,23 @@ func (db *commonMsgDatabase) getMsgBySeqsRange(ctx context.Context, userID strin // "userMinSeq" can be set as the same value as the conversation's "maxSeq" at the moment they join the group. // This ensures that their message retrieval starts from the point they joined. func (db *commonMsgDatabase) GetMsgBySeqsRange(ctx context.Context, userID string, conversationID string, begin, end, num, userMaxSeq int64) (int64, int64, []*sdkws.MsgData, error) { - userMinSeq, err := db.cache.GetConversationUserMinSeq(ctx, conversationID, userID) + userMinSeq, err := db.seq.GetConversationUserMinSeq(ctx, conversationID, userID) if err != nil && errs.Unwrap(err) != redis.Nil { return 0, 0, nil, err } - minSeq, err := db.cache.GetMinSeq(ctx, conversationID) + minSeq, err := db.seq.GetMinSeq(ctx, conversationID) if err != nil && errs.Unwrap(err) != redis.Nil { return 0, 0, nil, err } if userMinSeq > minSeq { minSeq = userMinSeq } - //"minSeq" represents the startSeq value that the user can retrieve. + // "minSeq" represents the startSeq value that the user can retrieve. if minSeq > end { - log.ZInfo(ctx, "minSeq > end", "minSeq", minSeq, "end", end) + log.ZWarn(ctx, "minSeq > end", errs.New("minSeq>end"), "minSeq", minSeq, "end", end) return 0, 0, nil, nil } - maxSeq, err := db.cache.GetMaxSeq(ctx, conversationID) + maxSeq, err := db.seq.GetMaxSeq(ctx, conversationID) if err != nil && errs.Unwrap(err) != redis.Nil { return 0, 0, nil, err } @@ -568,7 +549,7 @@ func (db *commonMsgDatabase) GetMsgBySeqsRange(ctx context.Context, userID strin maxSeq = userMaxSeq } } - //"maxSeq" represents the endSeq value that the user can retrieve. + // "maxSeq" represents the endSeq value that the user can retrieve. if begin < minSeq { begin = minSeq @@ -576,9 +557,9 @@ func (db *commonMsgDatabase) GetMsgBySeqsRange(ctx context.Context, userID strin if end > maxSeq { end = maxSeq } - //"begin" and "end" represent the actual startSeq and endSeq values that the user can retrieve. + // "begin" and "end" represent the actual startSeq and endSeq values that the user can retrieve. if end < begin { - return 0, 0, nil, errs.ErrArgs.Wrap("seq end < begin") + return 0, 0, nil, errs.ErrArgs.WrapMsg("seq end < begin") } var seqs []int64 if end-begin+1 <= num { @@ -591,25 +572,13 @@ func (db *commonMsgDatabase) GetMsgBySeqsRange(ctx context.Context, userID strin } } - //167 178 10 - //if end-num < { - // - //} - //var seqs []int64 - //for i := end; i > end-num; i-- { - // if i >= begin { - // seqs = append([]int64{i}, seqs...) - // } else { - // break - // } - //} if len(seqs) == 0 { return 0, 0, nil, nil } newBegin := seqs[0] newEnd := seqs[len(seqs)-1] log.ZDebug(ctx, "GetMsgBySeqsRange", "first seqs", seqs, "newBegin", newBegin, "newEnd", newEnd) - cachedMsgs, failedSeqs, err := db.cache.GetMessagesBySeq(ctx, conversationID, seqs) + cachedMsgs, failedSeqs, err := db.msg.GetMessagesBySeq(ctx, conversationID, seqs) if err != nil { if err != redis.Nil { @@ -618,13 +587,13 @@ func (db *commonMsgDatabase) GetMsgBySeqsRange(ctx context.Context, userID strin } var successMsgs []*sdkws.MsgData if len(cachedMsgs) > 0 { - delSeqs, err := db.cache.GetUserDelList(ctx, userID, conversationID) + delSeqs, err := db.msg.GetUserDelList(ctx, userID, conversationID) if err != nil && errs.Unwrap(err) != redis.Nil { return 0, 0, nil, err } var cacheDelNum int for _, msg := range cachedMsgs { - if !utils.Contain(msg.Seq, delSeqs...) { + if !datautil.Contain(msg.Seq, delSeqs...) { successMsgs = append(successMsgs, msg) } else { cacheDelNum += 1 @@ -635,7 +604,7 @@ func (db *commonMsgDatabase) GetMsgBySeqsRange(ctx context.Context, userID strin for i := 1; i <= cacheDelNum; { newSeq := newBegin - int64(i) if newSeq >= begin { - if !utils.Contain(newSeq, delSeqs...) { + if !datautil.Contain(newSeq, delSeqs...) { log.ZDebug(ctx, "seq del in cache, a new seq in range append", "new seq", newSeq) reGetSeqsCache = append(reGetSeqsCache, newSeq) i++ @@ -646,7 +615,7 @@ func (db *commonMsgDatabase) GetMsgBySeqsRange(ctx context.Context, userID strin } if len(reGetSeqsCache) > 0 { log.ZDebug(ctx, "reGetSeqsCache", "reGetSeqsCache", reGetSeqsCache) - cachedMsgs, failedSeqs2, err := db.cache.GetMessagesBySeq(ctx, conversationID, reGetSeqsCache) + cachedMsgs, failedSeqs2, err := db.msg.GetMessagesBySeq(ctx, conversationID, reGetSeqsCache) if err != nil { if err != redis.Nil { @@ -676,15 +645,15 @@ func (db *commonMsgDatabase) GetMsgBySeqsRange(ctx context.Context, userID strin } func (db *commonMsgDatabase) GetMsgBySeqs(ctx context.Context, userID string, conversationID string, seqs []int64) (int64, int64, []*sdkws.MsgData, error) { - userMinSeq, err := db.cache.GetConversationUserMinSeq(ctx, conversationID, userID) + userMinSeq, err := db.seq.GetConversationUserMinSeq(ctx, conversationID, userID) if err != nil && errs.Unwrap(err) != redis.Nil { return 0, 0, nil, err } - minSeq, err := db.cache.GetMinSeq(ctx, conversationID) + minSeq, err := db.seq.GetMinSeq(ctx, conversationID) if err != nil && errs.Unwrap(err) != redis.Nil { return 0, 0, nil, err } - maxSeq, err := db.cache.GetMaxSeq(ctx, conversationID) + maxSeq, err := db.seq.GetMaxSeq(ctx, conversationID) if err != nil && errs.Unwrap(err) != redis.Nil { return 0, 0, nil, err } @@ -697,28 +666,14 @@ func (db *commonMsgDatabase) GetMsgBySeqs(ctx context.Context, userID string, co newSeqs = append(newSeqs, seq) } } - successMsgs, failedSeqs, err := db.cache.GetMessagesBySeq(ctx, conversationID, newSeqs) + successMsgs, failedSeqs, err := db.msg.GetMessagesBySeq(ctx, conversationID, newSeqs) if err != nil { if err != redis.Nil { log.ZError(ctx, "get message from redis exception", err, "failedSeqs", failedSeqs, "conversationID", conversationID) } } - log.ZInfo( - ctx, - "db.cache.GetMessagesBySeq", - "userID", - userID, - "conversationID", - conversationID, - "seqs", - seqs, - "successMsgs", - len(successMsgs), - "failedSeqs", - failedSeqs, - "conversationID", - conversationID, - ) + log.ZDebug(ctx, "db.seq.GetMessagesBySeq", "userID", userID, "conversationID", conversationID, "seqs", + seqs, "len(successMsgs)", len(successMsgs), "failedSeqs", failedSeqs) if len(failedSeqs) > 0 { mongoMsgs, err := db.getMsgBySeqs(ctx, userID, conversationID, failedSeqs) @@ -739,17 +694,17 @@ func (db *commonMsgDatabase) DeleteConversationMsgsAndSetMinSeq(ctx context.Cont if err != nil { return err } - log.ZInfo(ctx, "DeleteConversationMsgsAndSetMinSeq", "conversationID", conversationID, "minSeq", minSeq) + log.ZDebug(ctx, "DeleteConversationMsgsAndSetMinSeq", "conversationID", conversationID, "minSeq", minSeq) if minSeq == 0 { return nil } if remainTime == 0 { - err = db.cache.CleanUpOneConversationAllMsg(ctx, conversationID) + err = db.msg.CleanUpOneConversationAllMsg(ctx, conversationID) if err != nil { log.ZWarn(ctx, "CleanUpOneUserAllMsg", err, "conversationID", conversationID) } } - return db.cache.SetMinSeq(ctx, conversationID, minSeq) + return db.seq.SetMinSeq(ctx, conversationID, minSeq) } func (db *commonMsgDatabase) UserMsgsDestruct(ctx context.Context, userID string, conversationID string, destructTime int64, lastMsgDestructTime time.Time) (seqs []int64, err error) { @@ -759,7 +714,7 @@ func (db *commonMsgDatabase) UserMsgsDestruct(ctx context.Context, userID string msgDocModel, err := db.msgDocDatabase.GetMsgDocModelByIndex(ctx, conversationID, index, 1) if err != nil || msgDocModel.DocID == "" { if err != nil { - if err == unrelation.ErrMsgListNotExist { + if err == relation.ErrMsgListNotExist { log.ZDebug(ctx, "not doc find", "conversationID", conversationID, "userID", userID, "index", index) } else { log.ZError(ctx, "deleteMsgRecursion GetUserMsgListByIndex failed", err, "conversationID", conversationID, "index", index) @@ -769,14 +724,14 @@ func (db *commonMsgDatabase) UserMsgsDestruct(ctx context.Context, userID string break } index++ - //&& msgDocModel.Msg[0].Msg.SendTime > lastMsgDestructTime.UnixMilli() + // && msgDocModel.Msg[0].Msg.SendTime > lastMsgDestructTime.UnixMilli() if len(msgDocModel.Msg) > 0 { i := 0 var over bool for _, msg := range msgDocModel.Msg { i++ if msg != nil && msg.Msg != nil && msg.Msg.SendTime+destructTime*1000 <= time.Now().UnixMilli() { - if msg.Msg.SendTime+destructTime*1000 > lastMsgDestructTime.UnixMilli() && !utils.Contain(userID, msg.DelList...) { + if msg.Msg.SendTime+destructTime*1000 > lastMsgDestructTime.UnixMilli() && !datautil.Contain(userID, msg.DelList...) { seqs = append(seqs, msg.Msg.Seq) } } else { @@ -794,12 +749,12 @@ func (db *commonMsgDatabase) UserMsgsDestruct(ctx context.Context, userID string log.ZDebug(ctx, "UserMsgsDestruct", "conversationID", conversationID, "userID", userID, "seqs", seqs) if len(seqs) > 0 { userMinSeq := seqs[len(seqs)-1] + 1 - currentUserMinSeq, err := db.cache.GetConversationUserMinSeq(ctx, conversationID, userID) + currentUserMinSeq, err := db.seq.GetConversationUserMinSeq(ctx, conversationID, userID) if err != nil && errs.Unwrap(err) != redis.Nil { return nil, err } if currentUserMinSeq < userMinSeq { - if err := db.cache.SetConversationUserMinSeq(ctx, conversationID, userID, userMinSeq); err != nil { + if err := db.seq.SetConversationUserMinSeq(ctx, conversationID, userID, userMinSeq); err != nil { return nil, err } } @@ -826,7 +781,7 @@ func (db *commonMsgDatabase) deleteMsgRecursion(ctx context.Context, conversatio msgDocModel, err := db.msgDocDatabase.GetMsgDocModelByIndex(ctx, conversationID, index, 1) if err != nil || msgDocModel.DocID == "" { if err != nil { - if err == unrelation.ErrMsgListNotExist { + if err == relation.ErrMsgListNotExist { log.ZDebug(ctx, "deleteMsgRecursion ErrMsgListNotExist", "conversationID", conversationID, "index:", index) } else { log.ZError(ctx, "deleteMsgRecursion GetUserMsgListByIndex failed", err, "conversationID", conversationID, "index", index) @@ -840,10 +795,10 @@ func (db *commonMsgDatabase) deleteMsgRecursion(ctx context.Context, conversatio return delStruct.getSetMinSeq() + 1, nil } log.ZDebug(ctx, "doc info", "conversationID", conversationID, "index", index, "docID", msgDocModel.DocID, "len", len(msgDocModel.Msg)) - if int64(len(msgDocModel.Msg)) > db.msg.GetSingleGocMsgNum() { + if int64(len(msgDocModel.Msg)) > db.msgTable.GetSingleGocMsgNum() { log.ZWarn(ctx, "msgs too large", nil, "lenth", len(msgDocModel.Msg), "docID:", msgDocModel.DocID) } - if msgDocModel.IsFull() && msgDocModel.Msg[len(msgDocModel.Msg)-1].Msg.SendTime+(remainTime*1000) < utils.GetCurrentTimestampByMill() { + if msgDocModel.IsFull() && msgDocModel.Msg[len(msgDocModel.Msg)-1].Msg.SendTime+(remainTime*1000) < timeutil.GetCurrentTimestampByMill() { log.ZDebug(ctx, "doc is full and all msg is expired", "docID", msgDocModel.DocID) delStruct.delDocIDs = append(delStruct.delDocIDs, msgDocModel.DocID) delStruct.minSeq = msgDocModel.Msg[len(msgDocModel.Msg)-1].Msg.Seq @@ -851,7 +806,7 @@ func (db *commonMsgDatabase) deleteMsgRecursion(ctx context.Context, conversatio var delMsgIndexs []int for i, MsgInfoModel := range msgDocModel.Msg { if MsgInfoModel != nil && MsgInfoModel.Msg != nil { - if utils.GetCurrentTimestampByMill() > MsgInfoModel.Msg.SendTime+(remainTime*1000) { + if timeutil.GetCurrentTimestampByMill() > MsgInfoModel.Msg.SendTime+(remainTime*1000) { delMsgIndexs = append(delMsgIndexs, i) } } @@ -868,13 +823,13 @@ func (db *commonMsgDatabase) deleteMsgRecursion(ctx context.Context, conversatio } func (db *commonMsgDatabase) DeleteMsgsPhysicalBySeqs(ctx context.Context, conversationID string, allSeqs []int64) error { - if err := db.cache.DeleteMessages(ctx, conversationID, allSeqs); err != nil { + if err := db.msg.DeleteMessages(ctx, conversationID, allSeqs); err != nil { return err } - for docID, seqs := range db.msg.GetDocIDSeqsMap(conversationID, allSeqs) { + for docID, seqs := range db.msgTable.GetDocIDSeqsMap(conversationID, allSeqs) { var indexes []int for _, seq := range seqs { - indexes = append(indexes, int(db.msg.GetMsgIndex(seq))) + indexes = append(indexes, int(db.msgTable.GetMsgIndex(seq))) } if err := db.msgDocDatabase.DeleteMsgsInOneDocByIndex(ctx, docID, indexes); err != nil { return err @@ -884,7 +839,7 @@ func (db *commonMsgDatabase) DeleteMsgsPhysicalBySeqs(ctx context.Context, conve } func (db *commonMsgDatabase) DeleteUserMsgsBySeqs(ctx context.Context, userID string, conversationID string, seqs []int64) error { - cachedMsgs, _, err := db.cache.GetMessagesBySeq(ctx, conversationID, seqs) + cachedMsgs, _, err := db.msg.GetMessagesBySeq(ctx, conversationID, seqs) if err != nil && errs.Unwrap(err) != redis.Nil { log.ZWarn(ctx, "DeleteUserMsgsBySeqs", err, "conversationID", conversationID, "seqs", seqs) return err @@ -894,14 +849,14 @@ func (db *commonMsgDatabase) DeleteUserMsgsBySeqs(ctx context.Context, userID st for _, msg := range cachedMsgs { cacheSeqs = append(cacheSeqs, msg.Seq) } - if err := db.cache.UserDeleteMsgs(ctx, conversationID, cacheSeqs, userID); err != nil { + if err := db.msg.UserDeleteMsgs(ctx, conversationID, cacheSeqs, userID); err != nil { return err } } - for docID, seqs := range db.msg.GetDocIDSeqsMap(conversationID, seqs) { + for docID, seqs := range db.msgTable.GetDocIDSeqsMap(conversationID, seqs) { for _, seq := range seqs { - if _, err := db.msgDocDatabase.PushUnique(ctx, docID, db.msg.GetMsgIndex(seq), "del_list", []string{userID}); err != nil { + if _, err := db.msgDocDatabase.PushUnique(ctx, docID, db.msgTable.GetMsgIndex(seq), "del_list", []string{userID}); err != nil { return err } } @@ -915,91 +870,91 @@ func (db *commonMsgDatabase) DeleteMsgsBySeqs(ctx context.Context, conversationI func (db *commonMsgDatabase) CleanUpUserConversationsMsgs(ctx context.Context, user string, conversationIDs []string) { for _, conversationID := range conversationIDs { - maxSeq, err := db.cache.GetMaxSeq(ctx, conversationID) + maxSeq, err := db.seq.GetMaxSeq(ctx, conversationID) if err != nil { if err == redis.Nil { - log.ZInfo(ctx, "max seq is nil", "conversationID", conversationID) + log.ZDebug(ctx, "max seq is nil", "conversationID", conversationID) } else { log.ZError(ctx, "get max seq failed", err, "conversationID", conversationID) } continue } - if err := db.cache.SetMinSeq(ctx, conversationID, maxSeq+1); err != nil { + if err := db.seq.SetMinSeq(ctx, conversationID, maxSeq+1); err != nil { log.ZError(ctx, "set min seq failed", err, "conversationID", conversationID, "minSeq", maxSeq+1) } } } func (db *commonMsgDatabase) SetMaxSeq(ctx context.Context, conversationID string, maxSeq int64) error { - return db.cache.SetMaxSeq(ctx, conversationID, maxSeq) + return db.seq.SetMaxSeq(ctx, conversationID, maxSeq) } func (db *commonMsgDatabase) GetMaxSeqs(ctx context.Context, conversationIDs []string) (map[string]int64, error) { - return db.cache.GetMaxSeqs(ctx, conversationIDs) + return db.seq.GetMaxSeqs(ctx, conversationIDs) } func (db *commonMsgDatabase) GetMaxSeq(ctx context.Context, conversationID string) (int64, error) { - return db.cache.GetMaxSeq(ctx, conversationID) + return db.seq.GetMaxSeq(ctx, conversationID) } func (db *commonMsgDatabase) SetMinSeq(ctx context.Context, conversationID string, minSeq int64) error { - return db.cache.SetMinSeq(ctx, conversationID, minSeq) + return db.seq.SetMinSeq(ctx, conversationID, minSeq) } func (db *commonMsgDatabase) SetMinSeqs(ctx context.Context, seqs map[string]int64) error { - return db.cache.SetMinSeqs(ctx, seqs) + return db.seq.SetMinSeqs(ctx, seqs) } func (db *commonMsgDatabase) GetMinSeqs(ctx context.Context, conversationIDs []string) (map[string]int64, error) { - return db.cache.GetMinSeqs(ctx, conversationIDs) + return db.seq.GetMinSeqs(ctx, conversationIDs) } func (db *commonMsgDatabase) GetMinSeq(ctx context.Context, conversationID string) (int64, error) { - return db.cache.GetMinSeq(ctx, conversationID) + return db.seq.GetMinSeq(ctx, conversationID) } func (db *commonMsgDatabase) GetConversationUserMinSeq(ctx context.Context, conversationID string, userID string) (int64, error) { - return db.cache.GetConversationUserMinSeq(ctx, conversationID, userID) + return db.seq.GetConversationUserMinSeq(ctx, conversationID, userID) } func (db *commonMsgDatabase) GetConversationUserMinSeqs(ctx context.Context, conversationID string, userIDs []string) (map[string]int64, error) { - return db.cache.GetConversationUserMinSeqs(ctx, conversationID, userIDs) + return db.seq.GetConversationUserMinSeqs(ctx, conversationID, userIDs) } func (db *commonMsgDatabase) SetConversationUserMinSeq(ctx context.Context, conversationID string, userID string, minSeq int64) error { - return db.cache.SetConversationUserMinSeq(ctx, conversationID, userID, minSeq) + return db.seq.SetConversationUserMinSeq(ctx, conversationID, userID, minSeq) } func (db *commonMsgDatabase) SetConversationUserMinSeqs(ctx context.Context, conversationID string, seqs map[string]int64) (err error) { - return db.cache.SetConversationUserMinSeqs(ctx, conversationID, seqs) + return db.seq.SetConversationUserMinSeqs(ctx, conversationID, seqs) } func (db *commonMsgDatabase) SetUserConversationsMinSeqs(ctx context.Context, userID string, seqs map[string]int64) error { - return db.cache.SetUserConversationsMinSeqs(ctx, userID, seqs) + return db.seq.SetUserConversationsMinSeqs(ctx, userID, seqs) } func (db *commonMsgDatabase) UserSetHasReadSeqs(ctx context.Context, userID string, hasReadSeqs map[string]int64) error { - return db.cache.UserSetHasReadSeqs(ctx, userID, hasReadSeqs) + return db.seq.UserSetHasReadSeqs(ctx, userID, hasReadSeqs) } func (db *commonMsgDatabase) SetHasReadSeq(ctx context.Context, userID string, conversationID string, hasReadSeq int64) error { - return db.cache.SetHasReadSeq(ctx, userID, conversationID, hasReadSeq) + return db.seq.SetHasReadSeq(ctx, userID, conversationID, hasReadSeq) } func (db *commonMsgDatabase) GetHasReadSeqs(ctx context.Context, userID string, conversationIDs []string) (map[string]int64, error) { - return db.cache.GetHasReadSeqs(ctx, userID, conversationIDs) + return db.seq.GetHasReadSeqs(ctx, userID, conversationIDs) } func (db *commonMsgDatabase) GetHasReadSeq(ctx context.Context, userID string, conversationID string) (int64, error) { - return db.cache.GetHasReadSeq(ctx, userID, conversationID) + return db.seq.GetHasReadSeq(ctx, userID, conversationID) } func (db *commonMsgDatabase) SetSendMsgStatus(ctx context.Context, id string, status int32) error { - return db.cache.SetSendMsgStatus(ctx, id, status) + return db.msg.SetSendMsgStatus(ctx, id, status) } func (db *commonMsgDatabase) GetSendMsgStatus(ctx context.Context, id string) (int32, error) { - return db.cache.GetSendMsgStatus(ctx, id) + return db.msg.GetSendMsgStatus(ctx, id) } func (db *commonMsgDatabase) GetConversationMinMaxSeqInMongoAndCache(ctx context.Context, conversationID string) (minSeqMongo, maxSeqMongo, minSeqCache, maxSeqCache int64, err error) { @@ -1007,11 +962,11 @@ func (db *commonMsgDatabase) GetConversationMinMaxSeqInMongoAndCache(ctx context if err != nil { return } - minSeqCache, err = db.cache.GetMinSeq(ctx, conversationID) + minSeqCache, err = db.seq.GetMinSeq(ctx, conversationID) if err != nil { return } - maxSeqCache, err = db.cache.GetMaxSeq(ctx, conversationID) + maxSeqCache, err = db.seq.GetMaxSeq(ctx, conversationID) if err != nil { return } @@ -1044,7 +999,7 @@ func (db *commonMsgDatabase) RangeUserSendCount( ase bool, pageNumber int32, showNumber int32, -) (msgCount int64, userCount int64, users []*unrelationtb.UserCount, dateCount map[string]int64, err error) { +) (msgCount int64, userCount int64, users []*relation.UserCount, dateCount map[string]int64, err error) { return db.msgDocDatabase.RangeUserSendCount(ctx, start, end, group, ase, pageNumber, showNumber) } @@ -1055,7 +1010,7 @@ func (db *commonMsgDatabase) RangeGroupSendCount( ase bool, pageNumber int32, showNumber int32, -) (msgCount int64, userCount int64, groups []*unrelationtb.GroupCount, dateCount map[string]int64, err error) { +) (msgCount int64, userCount int64, groups []*relation.GroupCount, dateCount map[string]int64, err error) { return db.msgDocDatabase.RangeGroupSendCount(ctx, start, end, ase, pageNumber, showNumber) } @@ -1078,12 +1033,12 @@ func (db *commonMsgDatabase) FindOneByDocIDs(ctx context.Context, conversationID totalMsgs := make(map[string]*sdkws.MsgData) for _, conversationID := range conversationIDs { seq := seqs[conversationID] - docID := db.msg.GetDocID(conversationID, seq) + docID := db.msgTable.GetDocID(conversationID, seq) msgs, err := db.msgDocDatabase.FindOneByDocID(ctx, docID) if err != nil { return nil, err } - index := db.msg.GetMsgIndex(seq) + index := db.msgTable.GetMsgIndex(seq) totalMsgs[conversationID] = convert.MsgDB2Pb(msgs.Msg[index].Msg) } return totalMsgs, nil diff --git a/pkg/common/db/controller/msg_test.go b/pkg/common/db/controller/msg_test.go deleted file mode 100644 index 4c2ab20da3..0000000000 --- a/pkg/common/db/controller/msg_test.go +++ /dev/null @@ -1,250 +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 controller - -import ( - "context" - "fmt" - "math/rand" - "strconv" - "sync" - "testing" - "time" - - "github.com/OpenIMSDK/tools/log" - - "go.mongodb.org/mongo-driver/bson" - - "github.com/openimsdk/open-im-server/v3/pkg/common/config" - unrelationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/unrelation" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/unrelation" -) - -func Test_BatchInsertChat2DB(t *testing.T) { - conf := config.NewGlobalConfig() - conf.Mongo.Address = []string{"192.168.44.128:37017"} - // conf.Mongo.Timeout = 60 - conf.Mongo.Database = "openIM" - // conf.Mongo.Source = "admin" - conf.Mongo.Username = "root" - conf.Mongo.Password = "openIM123" - conf.Mongo.MaxPoolSize = 100 - conf.RetainChatRecords = 3650 - conf.ChatRecordsClearTime = "0 2 * * 3" - - mongo, err := unrelation.NewMongo(conf) - if err != nil { - t.Fatal(err) - } - err = mongo.GetDatabase(conf.Mongo.Database).Client().Ping(context.Background(), nil) - if err != nil { - panic(err) - } - - db := &commonMsgDatabase{ - msgDocDatabase: unrelation.NewMsgMongoDriver(mongo.GetDatabase(conf.Mongo.Database)), - } - - //ctx := context.Background() - //msgs := make([]*sdkws.MsgData, 0, 1) - //for i := 0; i < cap(msgs); i++ { - // msgs = append(msgs, &sdkws.MsgData{ - // Content: []byte(fmt.Sprintf("test-%d", i)), - // SendTime: time.Now().UnixMilli(), - // }) - //} - //err = db.BatchInsertChat2DB(ctx, "test", msgs, 0) - //if err != nil { - // panic(err) - //} - - _ = db.BatchInsertChat2DB - c := mongo.GetDatabase(conf.Mongo.Database).Collection("msg") - - ch := make(chan int) - rand.Seed(time.Now().UnixNano()) - - index := 10 - - var wg sync.WaitGroup - for i := 0; i < 1000; i++ { - wg.Add(1) - go func(channelID int) { - defer wg.Done() - <-ch - var arr []string - for i := 0; i < 500; i++ { - arr = append(arr, strconv.Itoa(i+1)) - } - rand.Shuffle(len(arr), func(i, j int) { - arr[i], arr[j] = arr[j], arr[i] - }) - for j, s := range arr { - if j == 0 { - fmt.Printf("channnelID: %d, arr[0]: %s\n", channelID, arr[j]) - } - filter := bson.M{"doc_id": "test:0"} - update := bson.M{ - "$addToSet": bson.M{ - fmt.Sprintf("msgs.%d.del_list", index): bson.M{"$each": []string{s}}, - }, - } - _, err := c.UpdateOne(context.Background(), filter, update) - if err != nil { - t.Fatal(err) - } - } - }(i) - } - - for i := 0; i < 1000; i++ { - wg.Add(1) - go func() { - defer wg.Done() - <-ch - var arr []string - for i := 0; i < 500; i++ { - arr = append(arr, strconv.Itoa(1001+i)) - } - rand.Shuffle(len(arr), func(i, j int) { - arr[i], arr[j] = arr[j], arr[i] - }) - for _, s := range arr { - filter := bson.M{"doc_id": "test:0"} - update := bson.M{ - "$addToSet": bson.M{ - fmt.Sprintf("msgs.%d.read_list", index): bson.M{"$each": []string{s}}, - }, - } - _, err := c.UpdateOne(context.Background(), filter, update) - if err != nil { - t.Fatal(err) - } - } - }() - } - - time.Sleep(time.Second * 2) - - close(ch) - - wg.Wait() - -} - -func GetDB() *commonMsgDatabase { - conf := config.NewGlobalConfig() - conf.Mongo.Address = []string{"203.56.175.233:37017"} - // conf.Mongo.Timeout = 60 - conf.Mongo.Database = "openim_v3" - // conf.Mongo.Source = "admin" - conf.Mongo.Username = "root" - conf.Mongo.Password = "openIM123" - conf.Mongo.MaxPoolSize = 100 - conf.RetainChatRecords = 3650 - conf.ChatRecordsClearTime = "0 2 * * 3" - - mongo, err := unrelation.NewMongo(conf) - if err != nil { - panic(err) - } - err = mongo.GetDatabase(conf.Mongo.Database).Client().Ping(context.Background(), nil) - if err != nil { - panic(err) - } - return &commonMsgDatabase{ - msgDocDatabase: unrelation.NewMsgMongoDriver(mongo.GetDatabase(conf.Mongo.Database)), - } -} - -func Test_Insert(t *testing.T) { - db := GetDB() - ctx := context.Background() - var arr []any - for i := 0; i < 345; i++ { - if i%2 == 0 { - arr = append(arr, (*unrelationtb.MsgDataModel)(nil)) - continue - } - arr = append(arr, &unrelationtb.MsgDataModel{ - Seq: int64(i), - Content: fmt.Sprintf("test-%d", i), - }) - } - if err := db.BatchInsertBlock(ctx, "test", arr, updateKeyMsg, 1); err != nil { - t.Fatal(err) - } -} - -func Test_Revoke(t *testing.T) { - db := GetDB() - ctx := context.Background() - var arr []any - for i := 0; i < 456; i++ { - arr = append(arr, &unrelationtb.RevokeModel{ - UserID: "uid_" + strconv.Itoa(i), - Nickname: "uname_" + strconv.Itoa(i), - Time: time.Now().UnixMilli(), - }) - } - if err := db.BatchInsertBlock(ctx, "test", arr, updateKeyRevoke, 123); err != nil { - t.Fatal(err) - } -} - -func Test_FindBySeq(t *testing.T) { - if err := log.InitFromConfig("", "", 6, true, false, "", 2, 1); err != nil { - t.Fatal(err) - } - db := GetDB() - ctx := context.Background() - fmt.Println( - db.msgDocDatabase.(*unrelation.MsgMongoDriver).GetMsgBySeqIndexIn1Doc(ctx, "100", "si_100_101:0", []int64{1}), - ) - //res, err := db.msgDocDatabase.GetMsgBySeqIndexIn1Doc(ctx, "123456", "test:0", []int64{1, 2, 3}) - //if err != nil { - // t.Fatal(err) - //} - //db.GetMsgBySeqs(ctx, "100", "si_100_101:0", []int64{6}) - //data, _ := json.Marshal(res) - //fmt.Println(string(data)) -} - -//func Test_Delete(t *testing.T) { -// db := GetDB() -// ctx := context.Background() -// var arr []any -// for i := 0; i < 123; i++ { -// arr = append(arr, []string{"uid_1", "uid_2"}) -// } -// if err := db.BatchInsertBlock(ctx, "test", arr, updateKeyDel, 210); err != nil { -// t.Fatal(err) -// } -//} - -func TestName(t *testing.T) { - db := GetDB() - var seqs []int64 - for i := int64(1); i <= 50; i++ { - seqs = append(seqs, i) - } - msgs, err := db.getMsgBySeqsRange(context.Background(), "4931176757", "si_3866692501_4931176757", seqs, seqs[0], seqs[len(seqs)-1]) - if err != nil { - t.Fatal(err) - } - - t.Log(msgs) - -} diff --git a/pkg/common/db/controller/push.go b/pkg/common/db/controller/push.go index 76d8c3efb9..390d70b7ba 100644 --- a/pkg/common/db/controller/push.go +++ b/pkg/common/db/controller/push.go @@ -25,10 +25,10 @@ type PushDatabase interface { } type pushDataBase struct { - cache cache.MsgModel + cache cache.ThirdCache } -func NewPushDatabase(cache cache.MsgModel) PushDatabase { +func NewPushDatabase(cache cache.ThirdCache) PushDatabase { return &pushDataBase{cache: cache} } diff --git a/pkg/common/db/controller/s3.go b/pkg/common/db/controller/s3.go index e847c9c8ff..eae47c4212 100644 --- a/pkg/common/db/controller/s3.go +++ b/pkg/common/db/controller/s3.go @@ -20,9 +20,9 @@ import ( "time" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/s3" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/s3/cont" "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" + "github.com/openimsdk/tools/s3" + "github.com/openimsdk/tools/s3/cont" "github.com/redis/go-redis/v9" ) diff --git a/pkg/common/db/controller/third.go b/pkg/common/db/controller/third.go index 996d82c452..be618843fd 100644 --- a/pkg/common/db/controller/third.go +++ b/pkg/common/db/controller/third.go @@ -18,9 +18,9 @@ import ( "context" "time" - "github.com/OpenIMSDK/tools/pagination" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" + "github.com/openimsdk/tools/db/pagination" ) type ThirdDatabase interface { @@ -34,7 +34,7 @@ type ThirdDatabase interface { } type thirdDatabase struct { - cache cache.MsgModel + cache cache.ThirdCache logdb relation.LogInterface } @@ -58,7 +58,7 @@ func (t *thirdDatabase) UploadLogs(ctx context.Context, logs []*relation.LogMode return t.logdb.Create(ctx, logs) } -func NewThirdDatabase(cache cache.MsgModel, logdb relation.LogInterface) ThirdDatabase { +func NewThirdDatabase(cache cache.ThirdCache, logdb relation.LogInterface) ThirdDatabase { return &thirdDatabase{cache: cache, logdb: logdb} } diff --git a/pkg/common/db/controller/user.go b/pkg/common/db/controller/user.go index 0e1bdd3147..b2aba41faa 100644 --- a/pkg/common/db/controller/user.go +++ b/pkg/common/db/controller/user.go @@ -16,16 +16,16 @@ package controller import ( "context" + "github.com/openimsdk/tools/db/pagination" + "github.com/openimsdk/tools/db/tx" + "github.com/openimsdk/tools/utils/datautil" "time" - "github.com/OpenIMSDK/protocol/user" - "github.com/OpenIMSDK/tools/errs" - "github.com/OpenIMSDK/tools/pagination" - "github.com/OpenIMSDK/tools/tx" - "github.com/OpenIMSDK/tools/utils" + "github.com/openimsdk/protocol/user" + "github.com/openimsdk/tools/errs" + "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" - unrelationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/unrelation" ) type UserDatabase interface { @@ -39,13 +39,11 @@ type UserDatabase interface { FindNotification(ctx context.Context, level int64) (users []*relation.UserModel, err error) // Create Insert multiple external guarantees that the userID is not repeated and does not exist in the db Create(ctx context.Context, users []*relation.UserModel) (err error) - // Update update (non-zero value) external guarantee userID exists - //Update(ctx context.Context, user *relation.UserModel) (err error) // UpdateByMap update (zero value) external guarantee userID exists UpdateByMap(ctx context.Context, userID string, args map[string]any) (err error) // FindUser PageFindUser(ctx context.Context, level1 int64, level2 int64, pagination pagination.Pagination) (count int64, users []*relation.UserModel, err error) - //FindUser with keyword + // FindUser with keyword PageFindUserWithKeyword(ctx context.Context, level1 int64, level2 int64, userID string, nickName string, pagination pagination.Pagination) (count int64, users []*relation.UserModel, err error) // Page If not found, no error is returned Page(ctx context.Context, pagination pagination.Pagination) (count int64, users []*relation.UserModel, err error) @@ -74,7 +72,7 @@ type UserDatabase interface { // SetUserStatus Set the user status and store the user status in redis SetUserStatus(ctx context.Context, userID string, status, platformID int32) error - //CRUD user command + // CRUD user command AddUserCommand(ctx context.Context, userID string, Type int32, UUID string, value string, ex string) error DeleteUserCommand(ctx context.Context, userID string, Type int32, UUID string) error UpdateUserCommand(ctx context.Context, userID string, Type int32, UUID string, val map[string]any) error @@ -83,19 +81,19 @@ type UserDatabase interface { } type userDatabase struct { - tx tx.CtxTx + tx tx.Tx userDB relation.UserModelInterface cache cache.UserCache - mongoDB unrelationtb.UserModelInterface + mongoDB relation.SubscribeUserModelInterface } -func NewUserDatabase(userDB relation.UserModelInterface, cache cache.UserCache, tx tx.CtxTx, mongoDB unrelationtb.UserModelInterface) UserDatabase { +func NewUserDatabase(userDB relation.UserModelInterface, cache cache.UserCache, tx tx.Tx, mongoDB relation.SubscribeUserModelInterface) UserDatabase { return &userDatabase{userDB: userDB, cache: cache, tx: tx, mongoDB: mongoDB} } func (u *userDatabase) InitOnce(ctx context.Context, users []*relation.UserModel) error { // Extract user IDs from the given user models. - userIDs := utils.Slice(users, func(e *relation.UserModel) string { + userIDs := datautil.Slice(users, func(e *relation.UserModel) string { return e.UserID }) @@ -106,7 +104,7 @@ func (u *userDatabase) InitOnce(ctx context.Context, users []*relation.UserModel } // Determine which users are missing from the database. - missingUsers := utils.SliceAnySub(users, existingUsers, func(e *relation.UserModel) string { + missingUsers := datautil.SliceAnySub(users, existingUsers, func(e *relation.UserModel) string { return e.UserID }) @@ -127,7 +125,7 @@ func (u *userDatabase) FindWithError(ctx context.Context, userIDs []string) (use return } if len(users) != len(userIDs) { - err = errs.ErrRecordNotFound.Wrap("userID not found") + err = errs.ErrRecordNotFound.WrapMsg("userID not found") } return } @@ -137,12 +135,10 @@ func (u *userDatabase) Find(ctx context.Context, userIDs []string) (users []*rel return u.cache.GetUsersInfo(ctx, userIDs) } -// Find userInfo By Nickname. func (u *userDatabase) FindByNickname(ctx context.Context, nickname string) (users []*relation.UserModel, err error) { return u.userDB.TakeByNickname(ctx, nickname) } -// Find notificationAccouts. func (u *userDatabase) FindNotification(ctx context.Context, level int64) (users []*relation.UserModel, err error) { return u.userDB.TakeNotification(ctx, level) } @@ -153,20 +149,12 @@ func (u *userDatabase) Create(ctx context.Context, users []*relation.UserModel) if err = u.userDB.Create(ctx, users); err != nil { return err } - return u.cache.DelUsersInfo(utils.Slice(users, func(e *relation.UserModel) string { + return u.cache.DelUsersInfo(datautil.Slice(users, func(e *relation.UserModel) string { return e.UserID })...).ExecDel(ctx) }) } -//// Update (non-zero value) externally guarantees that userID exists. -//func (u *userDatabase) Update(ctx context.Context, user *relation.UserModel) (err error) { -// if err := u.userDB.Update(ctx, user); err != nil { -// return err -// } -// return u.cache.DelUsersInfo(user.UserID).ExecDel(ctx) -//} - // UpdateByMap update (zero value) externally guarantees that userID exists. func (u *userDatabase) UpdateByMap(ctx context.Context, userID string, args map[string]any) (err error) { return u.tx.Transaction(ctx, func(ctx context.Context) error { @@ -186,13 +174,7 @@ func (u *userDatabase) PageFindUser(ctx context.Context, level1 int64, level2 in return u.userDB.PageFindUser(ctx, level1, level2, pagination) } -func (u *userDatabase) PageFindUserWithKeyword( - ctx context.Context, - level1 int64, - level2 int64, - userID, nickName string, - pagination pagination.Pagination, -) (count int64, users []*relation.UserModel, err error) { +func (u *userDatabase) PageFindUserWithKeyword(ctx context.Context, level1 int64, level2 int64, userID, nickName string, pagination pagination.Pagination) (count int64, users []*relation.UserModel, err error) { return u.userDB.PageFindUserWithKeyword(ctx, level1, level2, userID, nickName, pagination) } @@ -267,19 +249,24 @@ func (u *userDatabase) GetUserStatus(ctx context.Context, userIDs []string) ([]* func (u *userDatabase) SetUserStatus(ctx context.Context, userID string, status, platformID int32) error { return u.cache.SetUserStatus(ctx, userID, status, platformID) } + func (u *userDatabase) AddUserCommand(ctx context.Context, userID string, Type int32, UUID string, value string, ex string) error { return u.userDB.AddUserCommand(ctx, userID, Type, UUID, value, ex) } + func (u *userDatabase) DeleteUserCommand(ctx context.Context, userID string, Type int32, UUID string) error { return u.userDB.DeleteUserCommand(ctx, userID, Type, UUID) } + func (u *userDatabase) UpdateUserCommand(ctx context.Context, userID string, Type int32, UUID string, val map[string]any) error { return u.userDB.UpdateUserCommand(ctx, userID, Type, UUID, val) } + func (u *userDatabase) GetUserCommands(ctx context.Context, userID string, Type int32) ([]*user.CommandInfoResp, error) { commands, err := u.userDB.GetUserCommand(ctx, userID, Type) return commands, err } + func (u *userDatabase) GetAllUserCommands(ctx context.Context, userID string) ([]*user.AllCommandInfoResp, error) { commands, err := u.userDB.GetAllUserCommand(ctx, userID) return commands, err diff --git a/pkg/common/db/mgo/black.go b/pkg/common/db/mgo/black.go index c555e0b776..d588aece6e 100644 --- a/pkg/common/db/mgo/black.go +++ b/pkg/common/db/mgo/black.go @@ -17,9 +17,9 @@ package mgo import ( "context" - "github.com/OpenIMSDK/tools/mgoutil" - "github.com/OpenIMSDK/tools/pagination" "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" + "github.com/openimsdk/tools/db/mongoutil" + "github.com/openimsdk/tools/db/pagination" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo/options" @@ -63,42 +63,42 @@ func (b *BlackMgo) blacksFilter(blacks []*relation.BlackModel) bson.M { } func (b *BlackMgo) Create(ctx context.Context, blacks []*relation.BlackModel) (err error) { - return mgoutil.InsertMany(ctx, b.coll, blacks) + return mongoutil.InsertMany(ctx, b.coll, blacks) } func (b *BlackMgo) Delete(ctx context.Context, blacks []*relation.BlackModel) (err error) { if len(blacks) == 0 { return nil } - return mgoutil.DeleteMany(ctx, b.coll, b.blacksFilter(blacks)) + return mongoutil.DeleteMany(ctx, b.coll, b.blacksFilter(blacks)) } func (b *BlackMgo) UpdateByMap(ctx context.Context, ownerUserID, blockUserID string, args map[string]any) (err error) { if len(args) == 0 { return nil } - return mgoutil.UpdateOne(ctx, b.coll, b.blackFilter(ownerUserID, blockUserID), bson.M{"$set": args}, false) + return mongoutil.UpdateOne(ctx, b.coll, b.blackFilter(ownerUserID, blockUserID), bson.M{"$set": args}, false) } func (b *BlackMgo) Find(ctx context.Context, blacks []*relation.BlackModel) (blackList []*relation.BlackModel, err error) { - return mgoutil.Find[*relation.BlackModel](ctx, b.coll, b.blacksFilter(blacks)) + return mongoutil.Find[*relation.BlackModel](ctx, b.coll, b.blacksFilter(blacks)) } func (b *BlackMgo) Take(ctx context.Context, ownerUserID, blockUserID string) (black *relation.BlackModel, err error) { - return mgoutil.FindOne[*relation.BlackModel](ctx, b.coll, b.blackFilter(ownerUserID, blockUserID)) + return mongoutil.FindOne[*relation.BlackModel](ctx, b.coll, b.blackFilter(ownerUserID, blockUserID)) } func (b *BlackMgo) FindOwnerBlacks(ctx context.Context, ownerUserID string, pagination pagination.Pagination) (total int64, blacks []*relation.BlackModel, err error) { - return mgoutil.FindPage[*relation.BlackModel](ctx, b.coll, bson.M{"owner_user_id": ownerUserID}, pagination) + return mongoutil.FindPage[*relation.BlackModel](ctx, b.coll, bson.M{"owner_user_id": ownerUserID}, pagination) } func (b *BlackMgo) FindOwnerBlackInfos(ctx context.Context, ownerUserID string, userIDs []string) (blacks []*relation.BlackModel, err error) { if len(userIDs) == 0 { - return mgoutil.Find[*relation.BlackModel](ctx, b.coll, bson.M{"owner_user_id": ownerUserID}) + return mongoutil.Find[*relation.BlackModel](ctx, b.coll, bson.M{"owner_user_id": ownerUserID}) } - return mgoutil.Find[*relation.BlackModel](ctx, b.coll, bson.M{"owner_user_id": ownerUserID, "block_user_id": bson.M{"$in": userIDs}}) + return mongoutil.Find[*relation.BlackModel](ctx, b.coll, bson.M{"owner_user_id": ownerUserID, "block_user_id": bson.M{"$in": userIDs}}) } func (b *BlackMgo) FindBlackUserIDs(ctx context.Context, ownerUserID string) (blackUserIDs []string, err error) { - return mgoutil.Find[string](ctx, b.coll, bson.M{"owner_user_id": ownerUserID}, options.Find().SetProjection(bson.M{"_id": 0, "block_user_id": 1})) + return mongoutil.Find[string](ctx, b.coll, bson.M{"owner_user_id": ownerUserID}, options.Find().SetProjection(bson.M{"_id": 0, "block_user_id": 1})) } diff --git a/pkg/common/db/mgo/conversation.go b/pkg/common/db/mgo/conversation.go index bc37ed7591..d10bda39b1 100644 --- a/pkg/common/db/mgo/conversation.go +++ b/pkg/common/db/mgo/conversation.go @@ -18,11 +18,11 @@ import ( "context" "time" - "github.com/OpenIMSDK/protocol/constant" - "github.com/OpenIMSDK/tools/errs" - "github.com/OpenIMSDK/tools/mgoutil" - "github.com/OpenIMSDK/tools/pagination" "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" + "github.com/openimsdk/protocol/constant" + "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" @@ -48,15 +48,15 @@ type ConversationMgo struct { } func (c *ConversationMgo) Create(ctx context.Context, conversations []*relation.ConversationModel) (err error) { - return mgoutil.InsertMany(ctx, c.coll, conversations) + return mongoutil.InsertMany(ctx, c.coll, conversations) } func (c *ConversationMgo) Delete(ctx context.Context, groupIDs []string) (err error) { - return mgoutil.DeleteMany(ctx, c.coll, bson.M{"group_id": bson.M{"$in": groupIDs}}) + return mongoutil.DeleteMany(ctx, c.coll, bson.M{"group_id": bson.M{"$in": groupIDs}}) } func (c *ConversationMgo) UpdateByMap(ctx context.Context, userIDs []string, conversationID string, args map[string]any) (rows int64, err error) { - res, err := mgoutil.UpdateMany(ctx, c.coll, bson.M{"owner_user_id": bson.M{"$in": userIDs}, "conversation_id": conversationID}, bson.M{"$set": args}) + res, err := mongoutil.UpdateMany(ctx, c.coll, bson.M{"owner_user_id": bson.M{"$in": userIDs}, "conversation_id": conversationID}, bson.M{"$set": args}) if err != nil { return 0, err } @@ -64,36 +64,35 @@ func (c *ConversationMgo) UpdateByMap(ctx context.Context, userIDs []string, con } func (c *ConversationMgo) Update(ctx context.Context, conversation *relation.ConversationModel) (err error) { - return mgoutil.UpdateOne(ctx, c.coll, bson.M{"owner_user_id": conversation.OwnerUserID, "conversation_id": conversation.ConversationID}, bson.M{"$set": conversation}, true) + return mongoutil.UpdateOne(ctx, c.coll, bson.M{"owner_user_id": conversation.OwnerUserID, "conversation_id": conversation.ConversationID}, bson.M{"$set": conversation}, true) } func (c *ConversationMgo) Find(ctx context.Context, ownerUserID string, conversationIDs []string) (conversations []*relation.ConversationModel, err error) { - return mgoutil.Find[*relation.ConversationModel](ctx, c.coll, bson.M{"owner_user_id": ownerUserID, "conversation_id": bson.M{"$in": conversationIDs}}) + return mongoutil.Find[*relation.ConversationModel](ctx, c.coll, bson.M{"owner_user_id": ownerUserID, "conversation_id": bson.M{"$in": conversationIDs}}) } func (c *ConversationMgo) FindUserID(ctx context.Context, userIDs []string, conversationIDs []string) ([]string, error) { - return mgoutil.Find[string]( + return mongoutil.Find[string]( ctx, c.coll, bson.M{"owner_user_id": bson.M{"$in": userIDs}, "conversation_id": bson.M{"$in": conversationIDs}}, options.Find().SetProjection(bson.M{"_id": 0, "owner_user_id": 1}), ) } - func (c *ConversationMgo) FindUserIDAllConversationID(ctx context.Context, userID string) ([]string, error) { - return mgoutil.Find[string](ctx, c.coll, bson.M{"owner_user_id": userID}, options.Find().SetProjection(bson.M{"_id": 0, "conversation_id": 1})) + return mongoutil.Find[string](ctx, c.coll, bson.M{"owner_user_id": userID}, options.Find().SetProjection(bson.M{"_id": 0, "conversation_id": 1})) } func (c *ConversationMgo) Take(ctx context.Context, userID, conversationID string) (conversation *relation.ConversationModel, err error) { - return mgoutil.FindOne[*relation.ConversationModel](ctx, c.coll, bson.M{"owner_user_id": userID, "conversation_id": conversationID}) + return mongoutil.FindOne[*relation.ConversationModel](ctx, c.coll, bson.M{"owner_user_id": userID, "conversation_id": conversationID}) } func (c *ConversationMgo) FindConversationID(ctx context.Context, userID string, conversationIDs []string) (existConversationID []string, err error) { - return mgoutil.Find[string](ctx, c.coll, bson.M{"owner_user_id": userID, "conversation_id": bson.M{"$in": conversationIDs}}, options.Find().SetProjection(bson.M{"_id": 0, "conversation_id": 1})) + return mongoutil.Find[string](ctx, c.coll, bson.M{"owner_user_id": userID, "conversation_id": bson.M{"$in": conversationIDs}}, options.Find().SetProjection(bson.M{"_id": 0, "conversation_id": 1})) } func (c *ConversationMgo) FindUserIDAllConversations(ctx context.Context, userID string) (conversations []*relation.ConversationModel, err error) { - return mgoutil.Find[*relation.ConversationModel](ctx, c.coll, bson.M{"owner_user_id": userID}) + return mongoutil.Find[*relation.ConversationModel](ctx, c.coll, bson.M{"owner_user_id": userID}) } func (c *ConversationMgo) FindRecvMsgUserIDs(ctx context.Context, conversationID string, recvOpts []int) ([]string, error) { @@ -103,22 +102,22 @@ func (c *ConversationMgo) FindRecvMsgUserIDs(ctx context.Context, conversationID } else { filter = bson.M{"conversation_id": conversationID, "recv_msg_opt": bson.M{"$in": recvOpts}} } - return mgoutil.Find[string](ctx, c.coll, filter, options.Find().SetProjection(bson.M{"_id": 0, "owner_user_id": 1})) + return mongoutil.Find[string](ctx, c.coll, filter, options.Find().SetProjection(bson.M{"_id": 0, "owner_user_id": 1})) } func (c *ConversationMgo) GetUserRecvMsgOpt(ctx context.Context, ownerUserID, conversationID string) (opt int, err error) { - return mgoutil.FindOne[int](ctx, c.coll, bson.M{"owner_user_id": ownerUserID, "conversation_id": conversationID}, options.FindOne().SetProjection(bson.M{"recv_msg_opt": 1})) + return mongoutil.FindOne[int](ctx, c.coll, bson.M{"owner_user_id": ownerUserID, "conversation_id": conversationID}, options.FindOne().SetProjection(bson.M{"recv_msg_opt": 1})) } func (c *ConversationMgo) GetAllConversationIDs(ctx context.Context) ([]string, error) { - return mgoutil.Aggregate[string](ctx, c.coll, []bson.M{ + return mongoutil.Aggregate[string](ctx, c.coll, []bson.M{ {"$group": bson.M{"_id": "$conversation_id"}}, {"$project": bson.M{"_id": 0, "conversation_id": "$_id"}}, }) } func (c *ConversationMgo) GetAllConversationIDsNumber(ctx context.Context) (int64, error) { - counts, err := mgoutil.Aggregate[int64](ctx, c.coll, []bson.M{ + counts, err := mongoutil.Aggregate[int64](ctx, c.coll, []bson.M{ {"$group": bson.M{"_id": "$conversation_id"}}, {"$group": bson.M{"_id": nil, "count": bson.M{"$sum": 1}}}, {"$project": bson.M{"_id": 0}}, @@ -133,16 +132,16 @@ func (c *ConversationMgo) GetAllConversationIDsNumber(ctx context.Context) (int6 } func (c *ConversationMgo) PageConversationIDs(ctx context.Context, pagination pagination.Pagination) (conversationIDs []string, err error) { - return mgoutil.FindPageOnly[string](ctx, c.coll, bson.M{}, pagination, options.Find().SetProjection(bson.M{"conversation_id": 1})) + return mongoutil.FindPageOnly[string](ctx, c.coll, bson.M{}, pagination, options.Find().SetProjection(bson.M{"conversation_id": 1})) } func (c *ConversationMgo) GetConversationsByConversationID(ctx context.Context, conversationIDs []string) ([]*relation.ConversationModel, error) { - return mgoutil.Find[*relation.ConversationModel](ctx, c.coll, bson.M{"conversation_id": bson.M{"$in": conversationIDs}}) + return mongoutil.Find[*relation.ConversationModel](ctx, c.coll, bson.M{"conversation_id": bson.M{"$in": conversationIDs}}) } func (c *ConversationMgo) GetConversationIDsNeedDestruct(ctx context.Context) ([]*relation.ConversationModel, error) { - //"is_msg_destruct = 1 && msg_destruct_time != 0 && (UNIX_TIMESTAMP(NOW()) > (msg_destruct_time + UNIX_TIMESTAMP(latest_msg_destruct_time)) || latest_msg_destruct_time is NULL)" - return mgoutil.Find[*relation.ConversationModel](ctx, c.coll, bson.M{ + // "is_msg_destruct = 1 && msg_destruct_time != 0 && (UNIX_TIMESTAMP(NOW()) > (msg_destruct_time + UNIX_TIMESTAMP(latest_msg_destruct_time)) || latest_msg_destruct_time is NULL)" + return mongoutil.Find[*relation.ConversationModel](ctx, c.coll, bson.M{ "is_msg_destruct": 1, "msg_destruct_time": bson.M{"$ne": 0}, "$or": []bson.M{ @@ -162,7 +161,7 @@ func (c *ConversationMgo) GetConversationIDsNeedDestruct(ctx context.Context) ([ } func (c *ConversationMgo) GetConversationNotReceiveMessageUserIDs(ctx context.Context, conversationID string) ([]string, error) { - return mgoutil.Find[string]( + return mongoutil.Find[string]( ctx, c.coll, bson.M{"conversation_id": conversationID, "recv_msg_opt": bson.M{"$ne": constant.ReceiveMessage}}, diff --git a/pkg/common/db/s3/doc.go b/pkg/common/db/mgo/doc.go similarity index 81% rename from pkg/common/db/s3/doc.go rename to pkg/common/db/mgo/doc.go index a43710676a..f9d43e8858 100644 --- a/pkg/common/db/s3/doc.go +++ b/pkg/common/db/mgo/doc.go @@ -1,4 +1,4 @@ -// Copyright © 2023 OpenIM. All rights reserved. +// 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. @@ -12,4 +12,4 @@ // See the License for the specific language governing permissions and // limitations under the License. -package s3 // import "github.com/openimsdk/open-im-server/v3/pkg/common/db/s3" +package mgo // import "github.com/openimsdk/open-im-server/v3/pkg/common/db/mgo" diff --git a/pkg/common/db/mgo/friend.go b/pkg/common/db/mgo/friend.go index aa7775ce04..269bb594ab 100644 --- a/pkg/common/db/mgo/friend.go +++ b/pkg/common/db/mgo/friend.go @@ -17,9 +17,9 @@ package mgo import ( "context" - "github.com/OpenIMSDK/tools/mgoutil" - "github.com/OpenIMSDK/tools/pagination" "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" + "github.com/openimsdk/tools/db/mongoutil" + "github.com/openimsdk/tools/db/pagination" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo/options" @@ -48,7 +48,7 @@ func NewFriendMongo(db *mongo.Database) (relation.FriendModelInterface, error) { // Create inserts multiple friend records. func (f *FriendMgo) Create(ctx context.Context, friends []*relation.FriendModel) error { - return mgoutil.InsertMany(ctx, f.coll, friends) + return mongoutil.InsertMany(ctx, f.coll, friends) } // Delete removes specified friends of the owner user. @@ -57,7 +57,7 @@ func (f *FriendMgo) Delete(ctx context.Context, ownerUserID string, friendUserID "owner_user_id": ownerUserID, "friend_user_id": bson.M{"$in": friendUserIDs}, } - return mgoutil.DeleteOne(ctx, f.coll, filter) + return mongoutil.DeleteOne(ctx, f.coll, filter) } // UpdateByMap updates specific fields of a friend document using a map. @@ -69,7 +69,7 @@ func (f *FriendMgo) UpdateByMap(ctx context.Context, ownerUserID string, friendU "owner_user_id": ownerUserID, "friend_user_id": friendUserID, } - return mgoutil.UpdateOne(ctx, f.coll, filter, bson.M{"$set": args}, true) + return mongoutil.UpdateOne(ctx, f.coll, filter, bson.M{"$set": args}, true) } // Update modifies multiple friend documents. @@ -92,7 +92,7 @@ func (f *FriendMgo) Take(ctx context.Context, ownerUserID, friendUserID string) "owner_user_id": ownerUserID, "friend_user_id": friendUserID, } - return mgoutil.FindOne[*relation.FriendModel](ctx, f.coll, filter) + return mongoutil.FindOne[*relation.FriendModel](ctx, f.coll, filter) } // FindUserState finds the friendship status between two users. @@ -103,7 +103,7 @@ func (f *FriendMgo) FindUserState(ctx context.Context, userID1, userID2 string) {"owner_user_id": userID2, "friend_user_id": userID1}, }, } - return mgoutil.Find[*relation.FriendModel](ctx, f.coll, filter) + return mongoutil.Find[*relation.FriendModel](ctx, f.coll, filter) } // FindFriends retrieves a list of friends for a given owner. Missing friends do not cause an error. @@ -112,7 +112,7 @@ func (f *FriendMgo) FindFriends(ctx context.Context, ownerUserID string, friendU "owner_user_id": ownerUserID, "friend_user_id": bson.M{"$in": friendUserIDs}, } - return mgoutil.Find[*relation.FriendModel](ctx, f.coll, filter) + return mongoutil.Find[*relation.FriendModel](ctx, f.coll, filter) } // FindReversalFriends finds users who have added the specified user as a friend. @@ -121,25 +121,25 @@ func (f *FriendMgo) FindReversalFriends(ctx context.Context, friendUserID string "owner_user_id": bson.M{"$in": ownerUserIDs}, "friend_user_id": friendUserID, } - return mgoutil.Find[*relation.FriendModel](ctx, f.coll, filter) + return mongoutil.Find[*relation.FriendModel](ctx, f.coll, filter) } // FindOwnerFriends retrieves a paginated list of friends for a given owner. func (f *FriendMgo) FindOwnerFriends(ctx context.Context, ownerUserID string, pagination pagination.Pagination) (int64, []*relation.FriendModel, error) { filter := bson.M{"owner_user_id": ownerUserID} - return mgoutil.FindPage[*relation.FriendModel](ctx, f.coll, filter, pagination) + return mongoutil.FindPage[*relation.FriendModel](ctx, f.coll, filter, pagination) } // FindInWhoseFriends finds users who have added the specified user as a friend, with pagination. func (f *FriendMgo) FindInWhoseFriends(ctx context.Context, friendUserID string, pagination pagination.Pagination) (int64, []*relation.FriendModel, error) { filter := bson.M{"friend_user_id": friendUserID} - return mgoutil.FindPage[*relation.FriendModel](ctx, f.coll, filter, pagination) + return mongoutil.FindPage[*relation.FriendModel](ctx, f.coll, filter, pagination) } // FindFriendUserIDs retrieves a list of friend user IDs for a given owner. func (f *FriendMgo) FindFriendUserIDs(ctx context.Context, ownerUserID string) ([]string, error) { filter := bson.M{"owner_user_id": ownerUserID} - return mgoutil.Find[string](ctx, f.coll, filter, options.Find().SetProjection(bson.M{"_id": 0, "friend_user_id": 1})) + return mongoutil.Find[string](ctx, f.coll, filter, options.Find().SetProjection(bson.M{"_id": 0, "friend_user_id": 1})) } func (f *FriendMgo) UpdateFriends(ctx context.Context, ownerUserID string, friendUserIDs []string, val map[string]any) error { @@ -158,6 +158,6 @@ func (f *FriendMgo) UpdateFriends(ctx context.Context, ownerUserID string, frien update := bson.M{"$set": val} // Perform the update operation for all matching documents - _, err := mgoutil.UpdateMany(ctx, f.coll, filter, update) + _, err := mongoutil.UpdateMany(ctx, f.coll, filter, update) return err } diff --git a/pkg/common/db/mgo/friend_request.go b/pkg/common/db/mgo/friend_request.go index 3e0588a0b6..704b681267 100644 --- a/pkg/common/db/mgo/friend_request.go +++ b/pkg/common/db/mgo/friend_request.go @@ -17,9 +17,9 @@ package mgo import ( "context" - "github.com/OpenIMSDK/tools/mgoutil" - "github.com/OpenIMSDK/tools/pagination" "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" + "github.com/openimsdk/tools/db/mongoutil" + "github.com/openimsdk/tools/db/pagination" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo/options" @@ -45,11 +45,11 @@ type FriendRequestMgo struct { } func (f *FriendRequestMgo) FindToUserID(ctx context.Context, toUserID string, pagination pagination.Pagination) (total int64, friendRequests []*relation.FriendRequestModel, err error) { - return mgoutil.FindPage[*relation.FriendRequestModel](ctx, f.coll, bson.M{"to_user_id": toUserID}, pagination) + return mongoutil.FindPage[*relation.FriendRequestModel](ctx, f.coll, bson.M{"to_user_id": toUserID}, pagination) } func (f *FriendRequestMgo) FindFromUserID(ctx context.Context, fromUserID string, pagination pagination.Pagination) (total int64, friendRequests []*relation.FriendRequestModel, err error) { - return mgoutil.FindPage[*relation.FriendRequestModel](ctx, f.coll, bson.M{"from_user_id": fromUserID}, pagination) + return mongoutil.FindPage[*relation.FriendRequestModel](ctx, f.coll, bson.M{"from_user_id": fromUserID}, pagination) } func (f *FriendRequestMgo) FindBothFriendRequests(ctx context.Context, fromUserID, toUserID string) (friends []*relation.FriendRequestModel, err error) { @@ -57,22 +57,22 @@ func (f *FriendRequestMgo) FindBothFriendRequests(ctx context.Context, fromUserI {"from_user_id": fromUserID, "to_user_id": toUserID}, {"from_user_id": toUserID, "to_user_id": fromUserID}, }} - return mgoutil.Find[*relation.FriendRequestModel](ctx, f.coll, filter) + return mongoutil.Find[*relation.FriendRequestModel](ctx, f.coll, filter) } func (f *FriendRequestMgo) Create(ctx context.Context, friendRequests []*relation.FriendRequestModel) error { - return mgoutil.InsertMany(ctx, f.coll, friendRequests) + return mongoutil.InsertMany(ctx, f.coll, friendRequests) } func (f *FriendRequestMgo) Delete(ctx context.Context, fromUserID, toUserID string) (err error) { - return mgoutil.DeleteOne(ctx, f.coll, bson.M{"from_user_id": fromUserID, "to_user_id": toUserID}) + return mongoutil.DeleteOne(ctx, f.coll, bson.M{"from_user_id": fromUserID, "to_user_id": toUserID}) } func (f *FriendRequestMgo) UpdateByMap(ctx context.Context, formUserID, toUserID string, args map[string]any) (err error) { if len(args) == 0 { return nil } - return mgoutil.UpdateOne(ctx, f.coll, bson.M{"from_user_id": formUserID, "to_user_id": toUserID}, bson.M{"$set": args}, true) + return mongoutil.UpdateOne(ctx, f.coll, bson.M{"from_user_id": formUserID, "to_user_id": toUserID}, bson.M{"$set": args}, true) } func (f *FriendRequestMgo) Update(ctx context.Context, friendRequest *relation.FriendRequestModel) (err error) { @@ -99,11 +99,11 @@ func (f *FriendRequestMgo) Update(ctx context.Context, friendRequest *relation.F return nil } filter := bson.M{"from_user_id": friendRequest.FromUserID, "to_user_id": friendRequest.ToUserID} - return mgoutil.UpdateOne(ctx, f.coll, filter, bson.M{"$set": updater}, true) + return mongoutil.UpdateOne(ctx, f.coll, filter, bson.M{"$set": updater}, true) } func (f *FriendRequestMgo) Find(ctx context.Context, fromUserID, toUserID string) (friendRequest *relation.FriendRequestModel, err error) { - return mgoutil.FindOne[*relation.FriendRequestModel](ctx, f.coll, bson.M{"from_user_id": fromUserID, "to_user_id": toUserID}) + return mongoutil.FindOne[*relation.FriendRequestModel](ctx, f.coll, bson.M{"from_user_id": fromUserID, "to_user_id": toUserID}) } func (f *FriendRequestMgo) Take(ctx context.Context, fromUserID, toUserID string) (friendRequest *relation.FriendRequestModel, err error) { diff --git a/pkg/common/db/mgo/group.go b/pkg/common/db/mgo/group.go index c63e3c3761..0169c23391 100644 --- a/pkg/common/db/mgo/group.go +++ b/pkg/common/db/mgo/group.go @@ -18,11 +18,11 @@ import ( "context" "time" - "github.com/OpenIMSDK/protocol/constant" - "github.com/OpenIMSDK/tools/errs" - "github.com/OpenIMSDK/tools/mgoutil" - "github.com/OpenIMSDK/tools/pagination" "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" + "github.com/openimsdk/protocol/constant" + "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" @@ -47,7 +47,7 @@ type GroupMgo struct { } func (g *GroupMgo) Create(ctx context.Context, groups []*relation.GroupModel) (err error) { - return mgoutil.InsertMany(ctx, g.coll, groups) + return mongoutil.InsertMany(ctx, g.coll, groups) } func (g *GroupMgo) UpdateStatus(ctx context.Context, groupID string, status int32) (err error) { @@ -58,21 +58,23 @@ func (g *GroupMgo) UpdateMap(ctx context.Context, groupID string, args map[strin if len(args) == 0 { return nil } - return mgoutil.UpdateOne(ctx, g.coll, bson.M{"group_id": groupID}, bson.M{"$set": args}, true) + return mongoutil.UpdateOne(ctx, g.coll, bson.M{"group_id": groupID}, bson.M{"$set": args}, true) } func (g *GroupMgo) Find(ctx context.Context, groupIDs []string) (groups []*relation.GroupModel, err error) { - return mgoutil.Find[*relation.GroupModel](ctx, g.coll, bson.M{"group_id": bson.M{"$in": groupIDs}}) + return mongoutil.Find[*relation.GroupModel](ctx, g.coll, bson.M{"group_id": bson.M{"$in": groupIDs}}) } func (g *GroupMgo) Take(ctx context.Context, groupID string) (group *relation.GroupModel, err error) { - return mgoutil.FindOne[*relation.GroupModel](ctx, g.coll, bson.M{"group_id": groupID}) + return mongoutil.FindOne[*relation.GroupModel](ctx, g.coll, bson.M{"group_id": groupID}) } func (g *GroupMgo) Search(ctx context.Context, keyword string, pagination pagination.Pagination) (total int64, groups []*relation.GroupModel, err error) { + // Define the sorting options opts := options.Find().SetSort(bson.D{{Key: "created_at", Value: -1}}) - return mgoutil.FindPage[*relation.GroupModel](ctx, g.coll, bson.M{ + // Perform the search with pagination and sorting + return mongoutil.FindPage[*relation.GroupModel](ctx, g.coll, bson.M{ "group_name": bson.M{"$regex": keyword}, "status": bson.M{"$ne": constant.GroupStatusDismissed}, }, pagination, opts) @@ -80,9 +82,9 @@ func (g *GroupMgo) Search(ctx context.Context, keyword string, pagination pagina func (g *GroupMgo) CountTotal(ctx context.Context, before *time.Time) (count int64, err error) { if before == nil { - return mgoutil.Count(ctx, g.coll, bson.M{}) + return mongoutil.Count(ctx, g.coll, bson.M{}) } - return mgoutil.Count(ctx, g.coll, bson.M{"create_time": bson.M{"$lt": before}}) + return mongoutil.Count(ctx, g.coll, bson.M{"create_time": bson.M{"$lt": before}}) } func (g *GroupMgo) CountRangeEverydayTotal(ctx context.Context, start time.Time, end time.Time) (map[string]int64, error) { @@ -113,7 +115,7 @@ func (g *GroupMgo) CountRangeEverydayTotal(ctx context.Context, start time.Time, Date string `bson:"_id"` Count int64 `bson:"count"` } - items, err := mgoutil.Aggregate[Item](ctx, g.coll, pipeline) + items, err := mongoutil.Aggregate[Item](ctx, g.coll, pipeline) if err != nil { return nil, err } diff --git a/pkg/common/db/mgo/group_member.go b/pkg/common/db/mgo/group_member.go index e1af34f7c1..29d69d0f0b 100644 --- a/pkg/common/db/mgo/group_member.go +++ b/pkg/common/db/mgo/group_member.go @@ -17,11 +17,11 @@ package mgo import ( "context" - "github.com/OpenIMSDK/protocol/constant" - "github.com/OpenIMSDK/tools/errs" - "github.com/OpenIMSDK/tools/mgoutil" - "github.com/OpenIMSDK/tools/pagination" "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" + "github.com/openimsdk/protocol/constant" + "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" @@ -47,7 +47,7 @@ type GroupMemberMgo struct { } func (g *GroupMemberMgo) Create(ctx context.Context, groupMembers []*relation.GroupMemberModel) (err error) { - return mgoutil.InsertMany(ctx, g.coll, groupMembers) + return mongoutil.InsertMany(ctx, g.coll, groupMembers) } func (g *GroupMemberMgo) Delete(ctx context.Context, groupID string, userIDs []string) (err error) { @@ -55,7 +55,7 @@ func (g *GroupMemberMgo) Delete(ctx context.Context, groupID string, userIDs []s if len(userIDs) > 0 { filter["user_id"] = bson.M{"$in": userIDs} } - return mgoutil.DeleteMany(ctx, g.coll, filter) + return mongoutil.DeleteMany(ctx, g.coll, filter) } func (g *GroupMemberMgo) UpdateRoleLevel(ctx context.Context, groupID string, userID string, roleLevel int32) error { @@ -63,41 +63,41 @@ func (g *GroupMemberMgo) UpdateRoleLevel(ctx context.Context, groupID string, us } func (g *GroupMemberMgo) Update(ctx context.Context, groupID string, userID string, data map[string]any) (err error) { - return mgoutil.UpdateOne(ctx, g.coll, bson.M{"group_id": groupID, "user_id": userID}, bson.M{"$set": data}, true) + return mongoutil.UpdateOne(ctx, g.coll, bson.M{"group_id": groupID, "user_id": userID}, bson.M{"$set": data}, true) } func (g *GroupMemberMgo) Find(ctx context.Context, groupIDs []string, userIDs []string, roleLevels []int32) (groupMembers []*relation.GroupMemberModel, err error) { - //TODO implement me + // TODO implement me panic("implement me") } func (g *GroupMemberMgo) FindMemberUserID(ctx context.Context, groupID string) (userIDs []string, err error) { - return mgoutil.Find[string](ctx, g.coll, bson.M{"group_id": groupID}, options.Find().SetProjection(bson.M{"_id": 0, "user_id": 1})) + return mongoutil.Find[string](ctx, g.coll, bson.M{"group_id": groupID}, options.Find().SetProjection(bson.M{"_id": 0, "user_id": 1})) } func (g *GroupMemberMgo) Take(ctx context.Context, groupID string, userID string) (groupMember *relation.GroupMemberModel, err error) { - return mgoutil.FindOne[*relation.GroupMemberModel](ctx, g.coll, bson.M{"group_id": groupID, "user_id": userID}) + return mongoutil.FindOne[*relation.GroupMemberModel](ctx, g.coll, bson.M{"group_id": groupID, "user_id": userID}) } func (g *GroupMemberMgo) TakeOwner(ctx context.Context, groupID string) (groupMember *relation.GroupMemberModel, err error) { - return mgoutil.FindOne[*relation.GroupMemberModel](ctx, g.coll, bson.M{"group_id": groupID, "role_level": constant.GroupOwner}) + return mongoutil.FindOne[*relation.GroupMemberModel](ctx, g.coll, bson.M{"group_id": groupID, "role_level": constant.GroupOwner}) } func (g *GroupMemberMgo) FindRoleLevelUserIDs(ctx context.Context, groupID string, roleLevel int32) ([]string, error) { - return mgoutil.Find[string](ctx, g.coll, bson.M{"group_id": groupID, "role_level": roleLevel}, options.Find().SetProjection(bson.M{"_id": 0, "user_id": 1})) + return mongoutil.Find[string](ctx, g.coll, bson.M{"group_id": groupID, "role_level": roleLevel}, options.Find().SetProjection(bson.M{"_id": 0, "user_id": 1})) } func (g *GroupMemberMgo) SearchMember(ctx context.Context, keyword string, groupID string, pagination pagination.Pagination) (total int64, groupList []*relation.GroupMemberModel, err error) { filter := bson.M{"group_id": groupID, "nickname": bson.M{"$regex": keyword}} - return mgoutil.FindPage[*relation.GroupMemberModel](ctx, g.coll, filter, pagination) + return mongoutil.FindPage[*relation.GroupMemberModel](ctx, g.coll, filter, pagination) } func (g *GroupMemberMgo) FindUserJoinedGroupID(ctx context.Context, userID string) (groupIDs []string, err error) { - return mgoutil.Find[string](ctx, g.coll, bson.M{"user_id": userID}, options.Find().SetProjection(bson.M{"_id": 0, "group_id": 1})) + return mongoutil.Find[string](ctx, g.coll, bson.M{"user_id": userID}, options.Find().SetProjection(bson.M{"_id": 0, "group_id": 1})) } func (g *GroupMemberMgo) TakeGroupMemberNum(ctx context.Context, groupID string) (count int64, err error) { - return mgoutil.Count(ctx, g.coll, bson.M{"group_id": groupID}) + return mongoutil.Count(ctx, g.coll, bson.M{"group_id": groupID}) } func (g *GroupMemberMgo) FindUserManagedGroupID(ctx context.Context, userID string) (groupIDs []string, err error) { @@ -107,7 +107,7 @@ func (g *GroupMemberMgo) FindUserManagedGroupID(ctx context.Context, userID stri "$in": []int{constant.GroupOwner, constant.GroupAdmin}, }, } - return mgoutil.Find[string](ctx, g.coll, filter, options.Find().SetProjection(bson.M{"_id": 0, "group_id": 1})) + return mongoutil.Find[string](ctx, g.coll, filter, options.Find().SetProjection(bson.M{"_id": 0, "group_id": 1})) } func (g *GroupMemberMgo) IsUpdateRoleLevel(data map[string]any) bool { diff --git a/pkg/common/db/mgo/group_request.go b/pkg/common/db/mgo/group_request.go index 9aee0e9605..17cbeab179 100644 --- a/pkg/common/db/mgo/group_request.go +++ b/pkg/common/db/mgo/group_request.go @@ -17,10 +17,10 @@ package mgo import ( "context" - "github.com/OpenIMSDK/tools/errs" - "github.com/OpenIMSDK/tools/mgoutil" - "github.com/OpenIMSDK/tools/pagination" "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" + "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" @@ -46,29 +46,29 @@ type GroupRequestMgo struct { } func (g *GroupRequestMgo) Create(ctx context.Context, groupRequests []*relation.GroupRequestModel) (err error) { - return mgoutil.InsertMany(ctx, g.coll, groupRequests) + return mongoutil.InsertMany(ctx, g.coll, groupRequests) } func (g *GroupRequestMgo) Delete(ctx context.Context, groupID string, userID string) (err error) { - return mgoutil.DeleteOne(ctx, g.coll, bson.M{"group_id": groupID, "user_id": userID}) + return mongoutil.DeleteOne(ctx, g.coll, bson.M{"group_id": groupID, "user_id": userID}) } func (g *GroupRequestMgo) UpdateHandler(ctx context.Context, groupID string, userID string, handledMsg string, handleResult int32) (err error) { - return mgoutil.UpdateOne(ctx, g.coll, bson.M{"group_id": groupID, "user_id": userID}, bson.M{"$set": bson.M{"handle_msg": handledMsg, "handle_result": handleResult}}, true) + return mongoutil.UpdateOne(ctx, g.coll, bson.M{"group_id": groupID, "user_id": userID}, bson.M{"$set": bson.M{"handle_msg": handledMsg, "handle_result": handleResult}}, true) } func (g *GroupRequestMgo) Take(ctx context.Context, groupID string, userID string) (groupRequest *relation.GroupRequestModel, err error) { - return mgoutil.FindOne[*relation.GroupRequestModel](ctx, g.coll, bson.M{"group_id": groupID, "user_id": userID}) + return mongoutil.FindOne[*relation.GroupRequestModel](ctx, g.coll, bson.M{"group_id": groupID, "user_id": userID}) } func (g *GroupRequestMgo) FindGroupRequests(ctx context.Context, groupID string, userIDs []string) ([]*relation.GroupRequestModel, error) { - return mgoutil.Find[*relation.GroupRequestModel](ctx, g.coll, bson.M{"group_id": groupID, "user_id": bson.M{"$in": userIDs}}) + return mongoutil.Find[*relation.GroupRequestModel](ctx, g.coll, bson.M{"group_id": groupID, "user_id": bson.M{"$in": userIDs}}) } func (g *GroupRequestMgo) Page(ctx context.Context, userID string, pagination pagination.Pagination) (total int64, groups []*relation.GroupRequestModel, err error) { - return mgoutil.FindPage[*relation.GroupRequestModel](ctx, g.coll, bson.M{"user_id": userID}, pagination) + return mongoutil.FindPage[*relation.GroupRequestModel](ctx, g.coll, bson.M{"user_id": userID}, pagination) } func (g *GroupRequestMgo) PageGroup(ctx context.Context, groupIDs []string, pagination pagination.Pagination) (total int64, groups []*relation.GroupRequestModel, err error) { - return mgoutil.FindPage[*relation.GroupRequestModel](ctx, g.coll, bson.M{"group_id": bson.M{"$in": groupIDs}}, pagination) + return mongoutil.FindPage[*relation.GroupRequestModel](ctx, g.coll, bson.M{"group_id": bson.M{"$in": groupIDs}}, pagination) } diff --git a/pkg/common/db/mgo/log.go b/pkg/common/db/mgo/log.go index ca28d5964b..36a0bbbc55 100644 --- a/pkg/common/db/mgo/log.go +++ b/pkg/common/db/mgo/log.go @@ -18,9 +18,9 @@ import ( "context" "time" - "github.com/OpenIMSDK/tools/mgoutil" - "github.com/OpenIMSDK/tools/pagination" "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" + "github.com/openimsdk/tools/db/mongoutil" + "github.com/openimsdk/tools/db/pagination" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo/options" @@ -57,7 +57,7 @@ type LogMgo struct { } func (l *LogMgo) Create(ctx context.Context, log []*relation.LogModel) error { - return mgoutil.InsertMany(ctx, l.coll, log) + return mongoutil.InsertMany(ctx, l.coll, log) } func (l *LogMgo) Search(ctx context.Context, keyword string, start time.Time, end time.Time, pagination pagination.Pagination) (int64, []*relation.LogModel, error) { @@ -65,19 +65,19 @@ func (l *LogMgo) Search(ctx context.Context, keyword string, start time.Time, en if keyword != "" { filter["user_id"] = bson.M{"$regex": keyword} } - return mgoutil.FindPage[*relation.LogModel](ctx, l.coll, filter, pagination, options.Find().SetSort(bson.M{"create_time": -1})) + return mongoutil.FindPage[*relation.LogModel](ctx, l.coll, filter, pagination, options.Find().SetSort(bson.M{"create_time": -1})) } func (l *LogMgo) Delete(ctx context.Context, logID []string, userID string) error { if userID == "" { - return mgoutil.DeleteMany(ctx, l.coll, bson.M{"log_id": bson.M{"$in": logID}}) + return mongoutil.DeleteMany(ctx, l.coll, bson.M{"log_id": bson.M{"$in": logID}}) } - return mgoutil.DeleteMany(ctx, l.coll, bson.M{"log_id": bson.M{"$in": logID}, "user_id": userID}) + return mongoutil.DeleteMany(ctx, l.coll, bson.M{"log_id": bson.M{"$in": logID}, "user_id": userID}) } func (l *LogMgo) Get(ctx context.Context, logIDs []string, userID string) ([]*relation.LogModel, error) { if userID == "" { - return mgoutil.Find[*relation.LogModel](ctx, l.coll, bson.M{"log_id": bson.M{"$in": logIDs}}) + return mongoutil.Find[*relation.LogModel](ctx, l.coll, bson.M{"log_id": bson.M{"$in": logIDs}}) } - return mgoutil.Find[*relation.LogModel](ctx, l.coll, bson.M{"log_id": bson.M{"$in": logIDs}, "user_id": userID}) + return mongoutil.Find[*relation.LogModel](ctx, l.coll, bson.M{"log_id": bson.M{"$in": logIDs}, "user_id": userID}) } diff --git a/pkg/common/db/unrelation/msg.go b/pkg/common/db/mgo/msg.go similarity index 56% rename from pkg/common/db/unrelation/msg.go rename to pkg/common/db/mgo/msg.go index a129f3e996..40ee5e4235 100644 --- a/pkg/common/db/unrelation/msg.go +++ b/pkg/common/db/mgo/msg.go @@ -1,68 +1,54 @@ -// 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 unrelation +package mgo import ( "context" - "encoding/json" - "errors" "fmt" "time" - "github.com/OpenIMSDK/protocol/constant" - "github.com/OpenIMSDK/protocol/msg" - "github.com/OpenIMSDK/protocol/sdkws" - "github.com/OpenIMSDK/tools/errs" - "github.com/OpenIMSDK/tools/log" - table "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/unrelation" + "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" + "github.com/openimsdk/protocol/constant" + "github.com/openimsdk/protocol/msg" + "github.com/openimsdk/protocol/sdkws" + "github.com/openimsdk/tools/db/mongoutil" + "github.com/openimsdk/tools/errs" + "github.com/openimsdk/tools/log" + "github.com/openimsdk/tools/utils/jsonutil" "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" - "google.golang.org/protobuf/proto" ) -var ErrMsgListNotExist = errors.New("user not have msg in mongoDB") - -type MsgMongoDriver struct { - MsgCollection *mongo.Collection - model table.MsgDocModel +func NewMsgMongo(db *mongo.Database) (relation.MsgDocModelInterface, error) { + coll := db.Collection(new(relation.MsgDocModel).TableName()) + _, err := coll.Indexes().CreateOne(context.Background(), mongo.IndexModel{ + Keys: bson.D{ + {Key: "doc_id", Value: 1}, + }, + Options: options.Index().SetUnique(true), + }) + if err != nil { + return nil, errs.Wrap(err) + } + return &MsgMgo{coll: coll}, nil } -func NewMsgMongoDriver(database *mongo.Database) table.MsgDocModelInterface { - collection := database.Collection(table.MsgDocModel{}.TableName()) - return &MsgMongoDriver{MsgCollection: collection} +type MsgMgo struct { + coll *mongo.Collection + model relation.MsgDocModel } -func (m *MsgMongoDriver) PushMsgsToDoc(ctx context.Context, docID string, msgsToMongo []table.MsgInfoModel) error { - return m.MsgCollection.FindOneAndUpdate(ctx, bson.M{"doc_id": docID}, bson.M{"$push": bson.M{"msgs": bson.M{"$each": msgsToMongo}}}). - Err() +func (m *MsgMgo) PushMsgsToDoc(ctx context.Context, docID string, msgsToMongo []relation.MsgInfoModel) error { + filter := bson.M{"doc_id": docID} + update := bson.M{"$push": bson.M{"msgs": bson.M{"$each": msgsToMongo}}} + return mongoutil.UpdateOne(ctx, m.coll, filter, update, false) } -func (m *MsgMongoDriver) Create(ctx context.Context, model *table.MsgDocModel) error { - _, err := m.MsgCollection.InsertOne(ctx, model) - return err +func (m *MsgMgo) Create(ctx context.Context, model *relation.MsgDocModel) error { + return mongoutil.InsertMany(ctx, m.coll, []*relation.MsgDocModel{model}) } -func (m *MsgMongoDriver) UpdateMsg( - ctx context.Context, - docID string, - index int64, - key string, - value any, -) (*mongo.UpdateResult, error) { +func (m *MsgMgo) UpdateMsg(ctx context.Context, docID string, index int64, key string, value any) (*mongo.UpdateResult, error) { var field string if key == "" { field = fmt.Sprintf("msgs.%d", index) @@ -71,21 +57,10 @@ func (m *MsgMongoDriver) UpdateMsg( } filter := bson.M{"doc_id": docID} update := bson.M{"$set": bson.M{field: value}} - res, err := m.MsgCollection.UpdateOne(ctx, filter, update) - if err != nil { - return nil, errs.Wrap(err) - } - return res, nil + return mongoutil.UpdateOneResult(ctx, m.coll, filter, update) } -// PushUnique value must slice. -func (m *MsgMongoDriver) PushUnique( - ctx context.Context, - docID string, - index int64, - key string, - value any, -) (*mongo.UpdateResult, error) { +func (m *MsgMgo) PushUnique(ctx context.Context, docID string, index int64, key string, value any) (*mongo.UpdateResult, error) { var field string if key == "" { field = fmt.Sprintf("msgs.%d", index) @@ -98,138 +73,24 @@ func (m *MsgMongoDriver) PushUnique( field: bson.M{"$each": value}, }, } - res, err := m.MsgCollection.UpdateOne(ctx, filter, update) - if err != nil { - return nil, errs.Wrap(err) - } - return res, nil -} - -func (m *MsgMongoDriver) UpdateMsgContent(ctx context.Context, docID string, index int64, msg []byte) error { - _, err := m.MsgCollection.UpdateOne( - ctx, - bson.M{"doc_id": docID}, - bson.M{"$set": bson.M{fmt.Sprintf("msgs.%d.msg", index): msg}}, - ) - if err != nil { - return errs.Wrap(err) - } - return nil -} - -func (m *MsgMongoDriver) UpdateMsgStatusByIndexInOneDoc(ctx context.Context, docID string, msg *sdkws.MsgData, seqIndex int, status int32) error { - msg.Status = status - bytes, err := proto.Marshal(msg) - if err != nil { - return errs.Wrap(err) - } - _, err = m.MsgCollection.UpdateOne( - ctx, - bson.M{"doc_id": docID}, - bson.M{"$set": bson.M{fmt.Sprintf("msgs.%d.msg", seqIndex): bytes}}, - ) - if err != nil { - return errs.Wrap(err, fmt.Sprintf("docID is %s, seqIndex is %d", docID, seqIndex)) - } - return nil -} - -func (m *MsgMongoDriver) FindOneByDocID(ctx context.Context, docID string) (*table.MsgDocModel, error) { - doc := &table.MsgDocModel{} - err := m.MsgCollection.FindOne(ctx, bson.M{"doc_id": docID}).Decode(doc) - return doc, err -} - -func (m *MsgMongoDriver) GetMsgDocModelByIndex( - ctx context.Context, - conversationID string, - index, sort int64, -) (*table.MsgDocModel, error) { - if sort != 1 && sort != -1 { - return nil, errs.ErrArgs.Wrap("mongo sort must be 1 or -1") - } - findOpts := options.Find().SetLimit(1).SetSkip(index).SetSort(bson.M{"doc_id": sort}) - cursor, err := m.MsgCollection.Find( - ctx, - bson.M{"doc_id": primitive.Regex{Pattern: fmt.Sprintf("^%s:", conversationID)}}, - findOpts, - ) - if err != nil { - return nil, errs.Wrap(err, fmt.Sprintf("conversationID is %s", conversationID)) - } - var msgs []table.MsgDocModel - err = cursor.All(ctx, &msgs) - if err != nil { - return nil, errs.Wrap(err, fmt.Sprintf("cursor is %s", cursor.Current.String())) - } - if len(msgs) > 0 { - return &msgs[0], nil - } - return nil, ErrMsgListNotExist + return mongoutil.UpdateOneResult(ctx, m.coll, filter, update) } -func (m *MsgMongoDriver) GetNewestMsg(ctx context.Context, conversationID string) (*table.MsgInfoModel, error) { - var skip int64 = 0 - for { - msgDocModel, err := m.GetMsgDocModelByIndex(ctx, conversationID, skip, -1) - if err != nil { - return nil, err - } - for i := len(msgDocModel.Msg) - 1; i >= 0; i-- { - if msgDocModel.Msg[i].Msg != nil { - return msgDocModel.Msg[i], nil - } - } - skip++ - } -} - -func (m *MsgMongoDriver) GetOldestMsg(ctx context.Context, conversationID string) (*table.MsgInfoModel, error) { - var skip int64 = 0 - for { - msgDocModel, err := m.GetMsgDocModelByIndex(ctx, conversationID, skip, 1) - if err != nil { - return nil, err - } - for i, v := range msgDocModel.Msg { - if v.Msg != nil { - return msgDocModel.Msg[i], nil - } - } - skip++ - } +func (m *MsgMgo) UpdateMsgContent(ctx context.Context, docID string, index int64, msg []byte) error { + filter := bson.M{"doc_id": docID} + update := bson.M{"$set": bson.M{fmt.Sprintf("msgs.%d.msg", index): msg}} + return mongoutil.UpdateOne(ctx, m.coll, filter, update, false) } -func (m *MsgMongoDriver) DeleteMsgsInOneDocByIndex(ctx context.Context, docID string, indexes []int) error { - updates := bson.M{ - "$set": bson.M{}, - } - for _, index := range indexes { - updates["$set"].(bson.M)[fmt.Sprintf("msgs.%d", index)] = bson.M{ - "msg": nil, - } - } - _, err := m.MsgCollection.UpdateMany(ctx, bson.M{"doc_id": docID}, updates) - if err != nil { - return errs.Wrap(err, fmt.Sprintf("docID is %s, indexes is %v", docID, indexes)) - } - return nil +func (m *MsgMgo) IsExistDocID(ctx context.Context, docID string) (bool, error) { + return mongoutil.Exist(ctx, m.coll, bson.M{"doc_id": docID}) } -func (m *MsgMongoDriver) DeleteDocs(ctx context.Context, docIDs []string) error { - if docIDs == nil { - return nil - } - _, err := m.MsgCollection.DeleteMany(ctx, bson.M{"doc_id": bson.M{"$in": docIDs}}) - return err +func (m *MsgMgo) FindOneByDocID(ctx context.Context, docID string) (*relation.MsgDocModel, error) { + return mongoutil.FindOne[*relation.MsgDocModel](ctx, m.coll, bson.M{"doc_id": docID}) } -func (m *MsgMongoDriver) GetMsgBySeqIndexIn1Doc( - ctx context.Context, - userID string, - docID string, - seqs []int64, -) (msgs []*table.MsgInfoModel, err error) { +func (m *MsgMgo) GetMsgBySeqIndexIn1Doc(ctx context.Context, userID, docID string, seqs []int64) ([]*relation.MsgInfoModel, error) { indexs := make([]int64, 0, len(seqs)) for _, seq := range seqs { indexs = append(indexs, m.model.GetMsgIndex(seq)) @@ -270,20 +131,14 @@ func (m *MsgMongoDriver) GetMsgBySeqIndexIn1Doc( {Key: "msgs.del_list", Value: 0}, }}}, } - - cur, err := m.MsgCollection.Aggregate(ctx, pipeline) + msgDocModel, err := mongoutil.Aggregate[*relation.MsgDocModel](ctx, m.coll, pipeline) if err != nil { - return nil, errs.Wrap(err) - } - defer cur.Close(ctx) - var msgDocModel []table.MsgDocModel - if err := cur.All(ctx, &msgDocModel); err != nil { - return nil, errs.Wrap(err, fmt.Sprintf("docID is %s, seqs is %v", docID, seqs)) + return nil, err } if len(msgDocModel) == 0 { return nil, errs.Wrap(mongo.ErrNoDocuments) } - msgs = make([]*table.MsgInfoModel, 0, len(msgDocModel[0].Msg)) + msgs := make([]*relation.MsgInfoModel, 0, len(msgDocModel[0].Msg)) for i := range msgDocModel[0].Msg { msg := msgDocModel[0].Msg[i] if msg == nil || msg.Msg == nil { @@ -303,16 +158,16 @@ func (m *MsgMongoDriver) GetMsgBySeqIndexIn1Doc( Seq: msg.Msg.Seq, Ex: msg.Msg.Ex, } - data, err := json.Marshal(&revokeContent) + data, err := jsonutil.JsonMarshal(&revokeContent) if err != nil { - return nil, errs.Wrap(err, fmt.Sprintf("docID is %s, seqs is %v", docID, seqs)) + return nil, errs.WrapMsg(err, fmt.Sprintf("docID is %s, seqs is %v", docID, seqs)) } elem := sdkws.NotificationElem{ Detail: string(data), } - content, err := json.Marshal(&elem) + content, err := jsonutil.JsonMarshal(&elem) if err != nil { - return nil, errs.Wrap(err, fmt.Sprintf("docID is %s, seqs is %v", docID, seqs)) + return nil, errs.WrapMsg(err, fmt.Sprintf("docID is %s, seqs is %v", docID, seqs)) } msg.Msg.ContentType = constant.MsgRevokeNotification msg.Msg.Content = string(content) @@ -322,16 +177,72 @@ func (m *MsgMongoDriver) GetMsgBySeqIndexIn1Doc( return msgs, nil } -func (m *MsgMongoDriver) IsExistDocID(ctx context.Context, docID string) (bool, error) { - count, err := m.MsgCollection.CountDocuments(ctx, bson.M{"doc_id": docID}) +func (m *MsgMgo) GetNewestMsg(ctx context.Context, conversationID string) (*relation.MsgInfoModel, error) { + for skip := int64(0); ; skip++ { + msgDocModel, err := m.GetMsgDocModelByIndex(ctx, conversationID, skip, -1) + if err != nil { + return nil, err + } + for i := len(msgDocModel.Msg) - 1; i >= 0; i-- { + if msgDocModel.Msg[i].Msg != nil { + return msgDocModel.Msg[i], nil + } + } + } +} + +func (m *MsgMgo) GetOldestMsg(ctx context.Context, conversationID string) (*relation.MsgInfoModel, error) { + for skip := int64(0); ; skip++ { + msgDocModel, err := m.GetMsgDocModelByIndex(ctx, conversationID, skip, 1) + if err != nil { + return nil, err + } + for i, v := range msgDocModel.Msg { + if v.Msg != nil { + return msgDocModel.Msg[i], nil + } + } + } +} + +func (m *MsgMgo) DeleteDocs(ctx context.Context, docIDs []string) error { + if len(docIDs) == 0 { + return nil + } + return mongoutil.DeleteMany(ctx, m.coll, bson.M{"doc_id": bson.M{"$in": docIDs}}) +} + +func (m *MsgMgo) GetMsgDocModelByIndex(ctx context.Context, conversationID string, index, sort int64) (*relation.MsgDocModel, error) { + if sort != 1 && sort != -1 { + return nil, errs.ErrArgs.WrapMsg("mongo sort must be 1 or -1") + } + opt := options.Find().SetLimit(1).SetSkip(index).SetSort(bson.M{"doc_id": sort}).SetLimit(1) + filter := bson.M{"doc_id": primitive.Regex{Pattern: fmt.Sprintf("^%s:", conversationID)}} + msgs, err := mongoutil.Find[*relation.MsgDocModel](ctx, m.coll, filter, opt) if err != nil { - return false, errs.Wrap(err, fmt.Sprintf("docID is %s", docID)) + return nil, err } - return count > 0, nil + if len(msgs) > 0 { + return msgs[0], nil + } + return nil, errs.Wrap(relation.ErrMsgListNotExist) } -func (m *MsgMongoDriver) MarkSingleChatMsgsAsRead(ctx context.Context, userID string, docID string, indexes []int64) error { - updates := []mongo.WriteModel{} +func (m *MsgMgo) DeleteMsgsInOneDocByIndex(ctx context.Context, docID string, indexes []int) error { + update := bson.M{ + "$set": bson.M{}, + } + for _, index := range indexes { + update["$set"].(bson.M)[fmt.Sprintf("msgs.%d", index)] = bson.M{ + "msg": nil, + } + } + _, err := mongoutil.UpdateMany(ctx, m.coll, bson.M{"doc_id": docID}, update) + return err +} + +func (m *MsgMgo) MarkSingleChatMsgsAsRead(ctx context.Context, userID string, docID string, indexes []int64) error { + var updates []mongo.WriteModel for _, index := range indexes { filter := bson.M{ "doc_id": docID, @@ -349,204 +260,110 @@ func (m *MsgMongoDriver) MarkSingleChatMsgsAsRead(ctx context.Context, userID st SetUpdate(update) updates = append(updates, updateModel) } - _, err := m.MsgCollection.BulkWrite(ctx, updates) - return errs.Wrap(err, fmt.Sprintf("docID is %s, indexes is %v", docID, indexes)) + if _, err := m.coll.BulkWrite(ctx, updates); err != nil { + return errs.WrapMsg(err, fmt.Sprintf("docID is %s, indexes is %v", docID, indexes)) + } + return nil +} + +func (m *MsgMgo) SearchMessage(ctx context.Context, req *msg.SearchMessageReq) (int32, []*relation.MsgInfoModel, error) { + var pipe mongo.Pipeline + condition := bson.A{} + if req.SendTime != "" { + // Changed to keyed fields for bson.M to avoid govet errors + condition = append(condition, bson.M{"$eq": bson.A{bson.M{"$dateToString": bson.M{"format": "%Y-%m-%d", "date": bson.M{"$toDate": "$$item.msg.send_time"}}}, req.SendTime}}) + } + if req.ContentType != 0 { + condition = append(condition, bson.M{"$eq": bson.A{"$$item.msg.content_type", req.ContentType}}) + } + if req.SessionType != 0 { + condition = append(condition, bson.M{"$eq": bson.A{"$$item.msg.session_type", req.SessionType}}) + } + if req.RecvID != "" { + condition = append(condition, bson.M{"$regexFind": bson.M{"input": "$$item.msg.recv_id", "regex": req.RecvID}}) + } + if req.SendID != "" { + condition = append(condition, bson.M{"$regexFind": bson.M{"input": "$$item.msg.send_id", "regex": req.SendID}}) + } + + or := bson.A{ + bson.M{"doc_id": bson.M{"$regex": "^si_", "$options": "i"}}, + bson.M{"doc_id": bson.M{"$regex": "^g_", "$options": "i"}}, + bson.M{"doc_id": bson.M{"$regex": "^sg_", "$options": "i"}}, + } + + // Use bson.D with keyed fields to specify the order explicitly + pipe = mongo.Pipeline{ + {{"$match", bson.D{{Key: "$or", Value: or}}}}, + {{"$project", bson.D{ + {Key: "msgs", Value: bson.D{ + {Key: "$filter", Value: bson.D{ + {Key: "input", Value: "$msgs"}, + {Key: "as", Value: "item"}, + {Key: "cond", Value: bson.D{{Key: "$and", Value: condition}}}, + }}, + }}, + {Key: "doc_id", Value: 1}, + }}}, + {{"$unwind", bson.M{"path": "$msgs"}}}, + {{"$sort", bson.M{"msgs.msg.send_time": -1}}}, + } + type docModel struct { + DocID string `bson:"doc_id"` + Msg *relation.MsgInfoModel `bson:"msgs"` + } + msgsDocs, err := mongoutil.Aggregate[*docModel](ctx, m.coll, pipe) + if err != nil { + return 0, nil, err + } + msgs := make([]*relation.MsgInfoModel, 0) + for _, doc := range msgsDocs { + msgInfo := doc.Msg + if msgInfo == nil || msgInfo.Msg == nil { + continue + } + if msgInfo.Revoke != nil { + revokeContent := sdkws.MessageRevokedContent{ + RevokerID: msgInfo.Revoke.UserID, + RevokerRole: msgInfo.Revoke.Role, + ClientMsgID: msgInfo.Msg.ClientMsgID, + RevokerNickname: msgInfo.Revoke.Nickname, + RevokeTime: msgInfo.Revoke.Time, + SourceMessageSendTime: msgInfo.Msg.SendTime, + SourceMessageSendID: msgInfo.Msg.SendID, + SourceMessageSenderNickname: msgInfo.Msg.SenderNickname, + SessionType: msgInfo.Msg.SessionType, + Seq: msgInfo.Msg.Seq, + Ex: msgInfo.Msg.Ex, + } + data, err := jsonutil.JsonMarshal(&revokeContent) + if err != nil { + return 0, nil, errs.WrapMsg(err, "json.Marshal revokeContent") + } + elem := sdkws.NotificationElem{Detail: string(data)} + content, err := jsonutil.JsonMarshal(&elem) + if err != nil { + return 0, nil, errs.WrapMsg(err, "json.Marshal elem") + } + msgInfo.Msg.ContentType = constant.MsgRevokeNotification + msgInfo.Msg.Content = string(content) + } + msgs = append(msgs, msgInfo) + } + start := (req.Pagination.PageNumber - 1) * req.Pagination.ShowNumber + n := int32(len(msgs)) + if start >= n { + return n, []*relation.MsgInfoModel{}, nil + } + if start+req.Pagination.ShowNumber < n { + msgs = msgs[start : start+req.Pagination.ShowNumber] + } else { + msgs = msgs[start:] + } + return n, msgs, nil } -// RangeUserSendCount -// db.msg.aggregate([ -// -// { -// $match: { -// "msgs.msg.send_time": { -// "$gte": 0, -// "$lt": 1788122092317 -// } -// } -// }, -// { -// "$addFields": { -// "msgs": { -// "$filter": { -// "input": "$msgs", -// "as": "item", -// "cond": { -// "$and": [ -// { -// $gte: ["$$item.msg.send_time", 0] -// }, -// { -// $lt: ["$$item.msg.send_time", 1788122092317] -// } -// ] -// } -// } -// } -// } -// }, -// { -// "$project": { -// "_id": 0, -// -// }, -// -// }, -// { -// "$project": { -// "result": { -// "$map": { -// "input": "$msgs", -// "as": "item", -// "in": { -// user_id: "$$item.msg.send_id", -// send_date: { -// $dateToString: { -// format: "%Y-%m-%d", -// date: { -// $toDate: "$$item.msg.send_time" -// } -// } -// } -// } -// } -// } -// }, -// -// }, -// { -// "$unwind": "$result" -// }, -// { -// "$group": { -// _id: "$result.send_date", -// count: { -// $sum: 1 -// }, -// original: { -// $push: "$$ROOT" -// } -// } -// }, -// { -// "$addFields": { -// "dates": "$$ROOT" -// } -// }, -// { -// "$project": { -// "_id": 0, -// "count": 0, -// "dates.original": 0, -// -// }, -// -// }, -// { -// "$group": { -// _id: null, -// count: { -// $sum: 1 -// }, -// dates: { -// $push: "$dates" -// }, -// original: { -// $push: "$original" -// }, -// -// } -// }, -// { -// "$unwind": "$original" -// }, -// { -// "$unwind": "$original" -// }, -// { -// "$group": { -// _id: "$original.result.user_id", -// count: { -// $sum: 1 -// }, -// original: { -// $push: "$dates" -// }, -// -// } -// }, -// { -// "$addFields": { -// "dates": { -// $arrayElemAt: ["$original", 0] -// } -// } -// }, -// { -// "$project": { -// original: 0 -// } -// }, -// { -// $sort: { -// count: - 1 -// } -// }, -// { -// "$group": { -// _id: null, -// user_count: { -// $sum: 1 -// }, -// users: { -// $push: "$$ROOT" -// }, -// -// } -// }, -// { -// "$addFields": { -// "dates": { -// $arrayElemAt: ["$users", 0] -// } -// } -// }, -// { -// "$addFields": { -// "dates": "$dates.dates" -// } -// }, -// { -// "$project": { -// _id: 0, -// "users.dates": 0, -// -// } -// }, -// { -// "$addFields": { -// "msg_count": { -// $sum: "$users.count" -// } -// } -// }, -// { -// "$addFields": { -// users: { -// $slice: ["$users", 0, 10] -// } -// } -// } -// -// ]). -func (m *MsgMongoDriver) RangeUserSendCount( - ctx context.Context, - start time.Time, - end time.Time, - group bool, - ase bool, - pageNumber int32, - showNumber int32, -) (msgCount int64, userCount int64, users []*table.UserCount, dateCount map[string]int64, err error) { +func (m *MsgMgo) RangeUserSendCount(ctx context.Context, start time.Time, end time.Time, group bool, ase bool, pageNumber int32, showNumber int32) (msgCount int64, userCount int64, users []*relation.UserCount, dateCount map[string]int64, err error) { var sort int if ase { sort = 1 @@ -773,21 +590,16 @@ func (m *MsgMongoDriver) RangeUserSendCount( }, }, } - cur, err := m.MsgCollection.Aggregate(ctx, pipeline, options.Aggregate().SetAllowDiskUse(true)) + result, err := mongoutil.Aggregate[*Result](ctx, m.coll, pipeline, options.Aggregate().SetAllowDiskUse(true)) if err != nil { - return 0, 0, nil, nil, errs.Wrap(err) - } - defer cur.Close(ctx) - var result []Result - if err = cur.All(ctx, &result); err != nil { - return 0, 0, nil, nil, errs.Wrap(err) + return 0, 0, nil, nil, err } if len(result) == 0 { return 0, 0, nil, nil, errs.Wrap(err) } - users = make([]*table.UserCount, len(result[0].Users)) + users = make([]*relation.UserCount, len(result[0].Users)) for i, r := range result[0].Users { - users[i] = &table.UserCount{ + users[i] = &relation.UserCount{ UserID: r.UserID, Count: r.Count, } @@ -799,14 +611,7 @@ func (m *MsgMongoDriver) RangeUserSendCount( return result[0].MsgCount, result[0].UserCount, users, dateCount, nil } -func (m *MsgMongoDriver) RangeGroupSendCount( - ctx context.Context, - start time.Time, - end time.Time, - ase bool, - pageNumber int32, - showNumber int32, -) (msgCount int64, userCount int64, groups []*table.GroupCount, dateCount map[string]int64, err error) { +func (m *MsgMgo) RangeGroupSendCount(ctx context.Context, start time.Time, end time.Time, ase bool, pageNumber int32, showNumber int32) (msgCount int64, userCount int64, groups []*relation.GroupCount, dateCount map[string]int64, err error) { var sort int if ase { sort = 1 @@ -1022,21 +827,16 @@ func (m *MsgMongoDriver) RangeGroupSendCount( }, }, } - cur, err := m.MsgCollection.Aggregate(ctx, pipeline, options.Aggregate().SetAllowDiskUse(true)) + result, err := mongoutil.Aggregate[*Result](ctx, m.coll, pipeline, options.Aggregate().SetAllowDiskUse(true)) if err != nil { - return 0, 0, nil, nil, errs.Wrap(err) - } - defer cur.Close(ctx) - var result []Result - if err = cur.All(ctx, &result); err != nil { - return 0, 0, nil, nil, errs.Wrap(err) + return 0, 0, nil, nil, err } if len(result) == 0 { return 0, 0, nil, nil, errs.Wrap(err) } - groups = make([]*table.GroupCount, len(result[0].Groups)) + groups = make([]*relation.GroupCount, len(result[0].Groups)) for i, r := range result[0].Groups { - groups[i] = &table.GroupCount{ + groups[i] = &relation.GroupCount{ GroupID: r.GroupID, Count: r.Count, } @@ -1048,113 +848,51 @@ func (m *MsgMongoDriver) RangeGroupSendCount( return result[0].MsgCount, result[0].UserCount, groups, dateCount, nil } -func (m *MsgMongoDriver) SearchMessage(ctx context.Context, req *msg.SearchMessageReq) (int32, []*table.MsgInfoModel, error) { - total, msgs, err := m.searchMessage(ctx, req) - if err != nil { - return 0, nil, err - } - return total, msgs, nil -} - -func (m *MsgMongoDriver) searchMessage(ctx context.Context, req *msg.SearchMessageReq) (int32, []*table.MsgInfoModel, error) { - var pipe mongo.Pipeline - condition := bson.A{} - if req.SendTime != "" { - // Changed to keyed fields for bson.M to avoid govet errors - condition = append(condition, bson.M{"$eq": bson.A{bson.M{"$dateToString": bson.M{"format": "%Y-%m-%d", "date": bson.M{"$toDate": "$$item.msg.send_time"}}}, req.SendTime}}) - } - if req.ContentType != 0 { - condition = append(condition, bson.M{"$eq": bson.A{"$$item.msg.content_type", req.ContentType}}) - } - if req.SessionType != 0 { - condition = append(condition, bson.M{"$eq": bson.A{"$$item.msg.session_type", req.SessionType}}) - } - if req.RecvID != "" { - condition = append(condition, bson.M{"$regexFind": bson.M{"input": "$$item.msg.recv_id", "regex": req.RecvID}}) - } - if req.SendID != "" { - condition = append(condition, bson.M{"$regexFind": bson.M{"input": "$$item.msg.send_id", "regex": req.SendID}}) - } - - or := bson.A{ - bson.M{"doc_id": bson.M{"$regex": "^si_", "$options": "i"}}, - bson.M{"doc_id": bson.M{"$regex": "^g_", "$options": "i"}}, - bson.M{"doc_id": bson.M{"$regex": "^sg_", "$options": "i"}}, - } - - // Use bson.D with keyed fields to specify the order explicitly - pipe = mongo.Pipeline{ - {{"$match", bson.D{{Key: "$or", Value: or}}}}, - {{"$project", bson.D{ - {Key: "msgs", Value: bson.D{ - {Key: "$filter", Value: bson.D{ - {Key: "input", Value: "$msgs"}, - {Key: "as", Value: "item"}, - {Key: "cond", Value: bson.D{{Key: "$and", Value: condition}}}, - }}, - }}, - {Key: "doc_id", Value: 1}, - }}}, - {{"$unwind", bson.M{"path": "$msgs"}}}, - {{"$sort", bson.M{"msgs.msg.send_time": -1}}}, - } - cursor, err := m.MsgCollection.Aggregate(ctx, pipe) - if err != nil { - return 0, nil, err - } - type docModel struct { - DocID string `bson:"doc_id"` - Msg *table.MsgInfoModel `bson:"msgs"` - } - var msgsDocs []docModel - err = cursor.All(ctx, &msgsDocs) - if err != nil { - return 0, nil, errs.Wrap(err, "cursor.All msgsDocs") - } - log.ZDebug(ctx, "query mongoDB", "result", msgsDocs) - msgs := make([]*table.MsgInfoModel, 0) - for _, doc := range msgsDocs { - msgInfo := doc.Msg - if msgInfo == nil || msgInfo.Msg == nil { +func (m *MsgMgo) ConvertMsgsDocLen(ctx context.Context, conversationIDs []string) { + for _, conversationID := range conversationIDs { + regex := primitive.Regex{Pattern: fmt.Sprintf("^%s:", conversationID)} + msgDocs, err := mongoutil.Find[*relation.MsgDocModel](ctx, m.coll, bson.M{"doc_id": regex}) + if err != nil { + log.ZError(ctx, "convertAll find msg doc failed", err, "conversationID", conversationID) continue } - if msgInfo.Revoke != nil { - revokeContent := sdkws.MessageRevokedContent{ - RevokerID: msgInfo.Revoke.UserID, - RevokerRole: msgInfo.Revoke.Role, - ClientMsgID: msgInfo.Msg.ClientMsgID, - RevokerNickname: msgInfo.Revoke.Nickname, - RevokeTime: msgInfo.Revoke.Time, - SourceMessageSendTime: msgInfo.Msg.SendTime, - SourceMessageSendID: msgInfo.Msg.SendID, - SourceMessageSenderNickname: msgInfo.Msg.SenderNickname, - SessionType: msgInfo.Msg.SessionType, - Seq: msgInfo.Msg.Seq, - Ex: msgInfo.Msg.Ex, + if len(msgDocs) < 1 { + continue + } + log.ZDebug(ctx, "msg doc convert", "conversationID", conversationID, "len(msgDocs)", len(msgDocs)) + if len(msgDocs[0].Msg) == int(m.model.GetSingleGocMsgNum5000()) { + if err := mongoutil.DeleteMany(ctx, m.coll, bson.M{"doc_id": regex}); err != nil { + log.ZError(ctx, "convertAll delete many failed", err, "conversationID", conversationID) + continue } - data, err := json.Marshal(&revokeContent) - if err != nil { - return 0, nil, errs.Wrap(err, "json.Marshal revokeContent") + var newMsgDocs []any + for _, msgDoc := range msgDocs { + if int64(len(msgDoc.Msg)) == m.model.GetSingleGocMsgNum() { + continue + } + var index int64 + for index < int64(len(msgDoc.Msg)) { + msg := msgDoc.Msg[index] + if msg != nil && msg.Msg != nil { + msgDocModel := relation.MsgDocModel{DocID: m.model.GetDocID(conversationID, msg.Msg.Seq)} + end := index + m.model.GetSingleGocMsgNum() + if int(end) >= len(msgDoc.Msg) { + msgDocModel.Msg = msgDoc.Msg[index:] + } else { + msgDocModel.Msg = msgDoc.Msg[index:end] + } + newMsgDocs = append(newMsgDocs, msgDocModel) + index = end + } else { + break + } + } } - elem := sdkws.NotificationElem{Detail: string(data)} - content, err := json.Marshal(&elem) - if err != nil { - return 0, nil, errs.Wrap(err, "json.Marshal elem") + if err = mongoutil.InsertMany(ctx, m.coll, newMsgDocs); err != nil { + log.ZError(ctx, "convertAll insert many failed", err, "conversationID", conversationID, "len(newMsgDocs)", len(newMsgDocs)) + } else { + log.ZDebug(ctx, "msg doc convert", "conversationID", conversationID, "len(newMsgDocs)", len(newMsgDocs)) } - msgInfo.Msg.ContentType = constant.MsgRevokeNotification - msgInfo.Msg.Content = string(content) } - msgs = append(msgs, msgInfo) - } - start := (req.Pagination.PageNumber - 1) * req.Pagination.ShowNumber - n := int32(len(msgs)) - if start >= n { - return n, []*table.MsgInfoModel{}, nil } - if start+req.Pagination.ShowNumber < n { - msgs = msgs[start : start+req.Pagination.ShowNumber] - } else { - msgs = msgs[start:] - } - return n, msgs, nil } diff --git a/pkg/common/db/mgo/object.go b/pkg/common/db/mgo/object.go index e9d639f198..1c628bb51c 100644 --- a/pkg/common/db/mgo/object.go +++ b/pkg/common/db/mgo/object.go @@ -17,9 +17,9 @@ package mgo import ( "context" - "github.com/OpenIMSDK/tools/errs" - "github.com/OpenIMSDK/tools/mgoutil" "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" + "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" @@ -54,16 +54,16 @@ func (o *S3Mongo) SetObject(ctx context.Context, obj *relation.ObjectModel) erro "group": obj.Group, "create_time": obj.CreateTime, } - return mgoutil.UpdateOne(ctx, o.coll, filter, bson.M{"$set": update}, false, options.Update().SetUpsert(true)) + return mongoutil.UpdateOne(ctx, o.coll, filter, bson.M{"$set": update}, false, options.Update().SetUpsert(true)) } func (o *S3Mongo) Take(ctx context.Context, engine string, name string) (*relation.ObjectModel, error) { if engine == "" { - return mgoutil.FindOne[*relation.ObjectModel](ctx, o.coll, bson.M{"name": name}) + return mongoutil.FindOne[*relation.ObjectModel](ctx, o.coll, bson.M{"name": name}) } - return mgoutil.FindOne[*relation.ObjectModel](ctx, o.coll, bson.M{"name": name, "engine": engine}) + return mongoutil.FindOne[*relation.ObjectModel](ctx, o.coll, bson.M{"name": name, "engine": engine}) } func (o *S3Mongo) Delete(ctx context.Context, engine string, name string) error { - return mgoutil.DeleteOne(ctx, o.coll, bson.M{"name": name, "engine": engine}) + return mongoutil.DeleteOne(ctx, o.coll, bson.M{"name": name, "engine": engine}) } diff --git a/pkg/common/db/unrelation/user.go b/pkg/common/db/mgo/subscribe.go similarity index 92% rename from pkg/common/db/unrelation/user.go rename to pkg/common/db/mgo/subscribe.go index cbf395bf84..f2057dc453 100644 --- a/pkg/common/db/unrelation/user.go +++ b/pkg/common/db/mgo/subscribe.go @@ -12,13 +12,13 @@ // See the License for the specific language governing permissions and // limitations under the License. -package unrelation +package mgo import ( "context" - "github.com/OpenIMSDK/tools/errs" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/unrelation" + "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" + "github.com/openimsdk/tools/errs" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo/options" @@ -35,9 +35,9 @@ const ( MaximumSubscription = 3000 ) -func NewUserMongoDriver(database *mongo.Database) unrelation.UserModelInterface { +func NewUserMongoDriver(database *mongo.Database) relation.SubscribeUserModelInterface { return &UserMongoDriver{ - userCollection: database.Collection(unrelation.SubscribeUser), + userCollection: database.Collection(relation.SubscribeUser), } } @@ -117,7 +117,7 @@ func (u *UserMongoDriver) AddSubscriptionList(ctx context.Context, userID string opts, ) if err != nil { - return errs.Wrap(err, "transaction failed") + return errs.WrapMsg(err, "transaction failed") } } return nil @@ -155,7 +155,7 @@ func (u *UserMongoDriver) RemoveSubscribedListFromUser(ctx context.Context, user // GetAllSubscribeList Get all users subscribed by this user. func (u *UserMongoDriver) GetAllSubscribeList(ctx context.Context, userID string) (userIDList []string, err error) { - var user unrelation.UserModel + var user relation.SubscribeUserModel cursor := u.userCollection.FindOne( ctx, bson.M{"user_id": SubscriptionPrefix + userID}) @@ -172,7 +172,7 @@ func (u *UserMongoDriver) GetAllSubscribeList(ctx context.Context, userID string // GetSubscribedList Get the user subscribed by those users. func (u *UserMongoDriver) GetSubscribedList(ctx context.Context, userID string) (userIDList []string, err error) { - var user unrelation.UserModel + var user relation.SubscribeUserModel cursor := u.userCollection.FindOne( ctx, bson.M{"user_id": SubscribedPrefix + userID}) diff --git a/pkg/common/db/mgo/user.go b/pkg/common/db/mgo/user.go index 9ca2eb1785..696479871e 100644 --- a/pkg/common/db/mgo/user.go +++ b/pkg/common/db/mgo/user.go @@ -18,11 +18,11 @@ import ( "context" "time" - "github.com/OpenIMSDK/protocol/user" - "github.com/OpenIMSDK/tools/errs" - "github.com/OpenIMSDK/tools/mgoutil" - "github.com/OpenIMSDK/tools/pagination" "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" + "github.com/openimsdk/protocol/user" + "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/bson/primitive" "go.mongodb.org/mongo-driver/mongo" @@ -48,34 +48,34 @@ type UserMgo struct { } func (u *UserMgo) Create(ctx context.Context, users []*relation.UserModel) error { - return mgoutil.InsertMany(ctx, u.coll, users) + return mongoutil.InsertMany(ctx, u.coll, users) } func (u *UserMgo) UpdateByMap(ctx context.Context, userID string, args map[string]any) (err error) { if len(args) == 0 { return nil } - return mgoutil.UpdateOne(ctx, u.coll, bson.M{"user_id": userID}, bson.M{"$set": args}, true) + return mongoutil.UpdateOne(ctx, u.coll, bson.M{"user_id": userID}, bson.M{"$set": args}, true) } func (u *UserMgo) Find(ctx context.Context, userIDs []string) (users []*relation.UserModel, err error) { - return mgoutil.Find[*relation.UserModel](ctx, u.coll, bson.M{"user_id": bson.M{"$in": userIDs}}) + return mongoutil.Find[*relation.UserModel](ctx, u.coll, bson.M{"user_id": bson.M{"$in": userIDs}}) } func (u *UserMgo) Take(ctx context.Context, userID string) (user *relation.UserModel, err error) { - return mgoutil.FindOne[*relation.UserModel](ctx, u.coll, bson.M{"user_id": userID}) + return mongoutil.FindOne[*relation.UserModel](ctx, u.coll, bson.M{"user_id": userID}) } func (u *UserMgo) TakeNotification(ctx context.Context, level int64) (user []*relation.UserModel, err error) { - return mgoutil.Find[*relation.UserModel](ctx, u.coll, bson.M{"app_manger_level": level}) + return mongoutil.Find[*relation.UserModel](ctx, u.coll, bson.M{"app_manger_level": level}) } func (u *UserMgo) TakeByNickname(ctx context.Context, nickname string) (user []*relation.UserModel, err error) { - return mgoutil.Find[*relation.UserModel](ctx, u.coll, bson.M{"nickname": nickname}) + return mongoutil.Find[*relation.UserModel](ctx, u.coll, bson.M{"nickname": nickname}) } func (u *UserMgo) Page(ctx context.Context, pagination pagination.Pagination) (count int64, users []*relation.UserModel, err error) { - return mgoutil.FindPage[*relation.UserModel](ctx, u.coll, bson.M{}, pagination) + return mongoutil.FindPage[*relation.UserModel](ctx, u.coll, bson.M{}, pagination) } func (u *UserMgo) PageFindUser(ctx context.Context, level1 int64, level2 int64, pagination pagination.Pagination) (count int64, users []*relation.UserModel, err error) { @@ -86,7 +86,7 @@ func (u *UserMgo) PageFindUser(ctx context.Context, level1 int64, level2 int64, }, } - return mgoutil.FindPage[*relation.UserModel](ctx, u.coll, query, pagination) + return mongoutil.FindPage[*relation.UserModel](ctx, u.coll, query, pagination) } func (u *UserMgo) PageFindUserWithKeyword( @@ -121,26 +121,26 @@ func (u *UserMgo) PageFindUserWithKeyword( } // Perform the paginated search - return mgoutil.FindPage[*relation.UserModel](ctx, u.coll, query, pagination) + return mongoutil.FindPage[*relation.UserModel](ctx, u.coll, query, pagination) } func (u *UserMgo) GetAllUserID(ctx context.Context, pagination pagination.Pagination) (int64, []string, error) { - return mgoutil.FindPage[string](ctx, u.coll, bson.M{}, pagination, options.Find().SetProjection(bson.M{"_id": 0, "user_id": 1})) + return mongoutil.FindPage[string](ctx, u.coll, bson.M{}, pagination, options.Find().SetProjection(bson.M{"_id": 0, "user_id": 1})) } func (u *UserMgo) Exist(ctx context.Context, userID string) (exist bool, err error) { - return mgoutil.Exist(ctx, u.coll, bson.M{"user_id": userID}) + return mongoutil.Exist(ctx, u.coll, bson.M{"user_id": userID}) } func (u *UserMgo) GetUserGlobalRecvMsgOpt(ctx context.Context, userID string) (opt int, err error) { - return mgoutil.FindOne[int](ctx, u.coll, bson.M{"user_id": userID}, options.FindOne().SetProjection(bson.M{"_id": 0, "global_recv_msg_opt": 1})) + return mongoutil.FindOne[int](ctx, u.coll, bson.M{"user_id": userID}, options.FindOne().SetProjection(bson.M{"_id": 0, "global_recv_msg_opt": 1})) } func (u *UserMgo) CountTotal(ctx context.Context, before *time.Time) (count int64, err error) { if before == nil { - return mgoutil.Count(ctx, u.coll, bson.M{}) + return mongoutil.Count(ctx, u.coll, bson.M{}) } - return mgoutil.Count(ctx, u.coll, bson.M{"create_time": bson.M{"$lt": before}}) + return mongoutil.Count(ctx, u.coll, bson.M{"create_time": bson.M{"$lt": before}}) } func (u *UserMgo) AddUserCommand(ctx context.Context, userID string, Type int32, UUID string, value string, ex string) error { @@ -308,7 +308,7 @@ func (u *UserMgo) CountRangeEverydayTotal(ctx context.Context, start time.Time, Date string `bson:"_id"` Count int64 `bson:"count"` } - items, err := mgoutil.Aggregate[Item](ctx, u.coll, pipeline) + items, err := mongoutil.Aggregate[Item](ctx, u.coll, pipeline) if err != nil { return nil, err } diff --git a/pkg/common/db/s3/cont/consts.go b/pkg/common/db/s3/cont/consts.go deleted file mode 100644 index b51878e496..0000000000 --- a/pkg/common/db/s3/cont/consts.go +++ /dev/null @@ -1,38 +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 cont - -const ( - // hashPath defines the storage path for hash data within the 'openim' directory. - hashPath = "openim/data/hash/" - - // tempPath specifies the directory for temporary files in the 'openim' structure. - tempPath = "openim/temp/" - - // DirectPath indicates the directory for direct uploads or access within the 'openim' structure. - DirectPath = "openim/direct" - - // UploadTypeMultipart represents the identifier for multipart uploads, - // allowing large files to be uploaded in chunks. - UploadTypeMultipart = 1 - - // UploadTypePresigned signifies the use of presigned URLs for uploads, - // facilitating secure, authorized file transfers without requiring direct access to the storage credentials. - UploadTypePresigned = 2 - - // partSeparator is used as a delimiter in multipart upload processes, - // separating individual file parts. - partSeparator = "," -) diff --git a/pkg/common/db/s3/cont/controller.go b/pkg/common/db/s3/cont/controller.go deleted file mode 100644 index 915109aa51..0000000000 --- a/pkg/common/db/s3/cont/controller.go +++ /dev/null @@ -1,282 +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 cont - -import ( - "context" - "crypto/md5" - "encoding/hex" - "errors" - "fmt" - "path" - "strings" - "time" - - "github.com/OpenIMSDK/tools/errs" - "github.com/OpenIMSDK/tools/log" - "github.com/google/uuid" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/s3" -) - -func New(cache cache.S3Cache, impl s3.Interface) *Controller { - return &Controller{ - cache: cache, - impl: impl, - } -} - -type Controller struct { - cache cache.S3Cache - impl s3.Interface -} - -func (c *Controller) Engine() string { - return c.impl.Engine() -} - -func (c *Controller) HashPath(md5 string) string { - return path.Join(hashPath, md5) -} - -func (c *Controller) NowPath() string { - now := time.Now() - return path.Join( - fmt.Sprintf("%04d", now.Year()), - fmt.Sprintf("%02d", now.Month()), - fmt.Sprintf("%02d", now.Day()), - fmt.Sprintf("%02d", now.Hour()), - fmt.Sprintf("%02d", now.Minute()), - fmt.Sprintf("%02d", now.Second()), - ) -} - -func (c *Controller) UUID() string { - id := uuid.New() - return hex.EncodeToString(id[:]) -} - -func (c *Controller) PartSize(ctx context.Context, size int64) (int64, error) { - return c.impl.PartSize(ctx, size) -} - -func (c *Controller) PartLimit() *s3.PartLimit { - return c.impl.PartLimit() -} - -func (c *Controller) StatObject(ctx context.Context, name string) (*s3.ObjectInfo, error) { - return c.cache.GetKey(ctx, c.impl.Engine(), name) -} - -func (c *Controller) GetHashObject(ctx context.Context, hash string) (*s3.ObjectInfo, error) { - return c.StatObject(ctx, c.HashPath(hash)) -} - -func (c *Controller) InitiateUpload(ctx context.Context, hash string, size int64, expire time.Duration, maxParts int) (*InitiateUploadResult, error) { - defer log.ZDebug(ctx, "return") - if size < 0 { - return nil, errors.New("invalid size") - } - if hashBytes, err := hex.DecodeString(hash); err != nil { - return nil, err - } else if len(hashBytes) != md5.Size { - return nil, errors.New("invalid md5") - } - partSize, err := c.impl.PartSize(ctx, size) - if err != nil { - return nil, err - } - partNumber := int(size / partSize) - if size%partSize > 0 { - partNumber++ - } - if maxParts > 0 && partNumber > 0 && partNumber < maxParts { - return nil, fmt.Errorf("too many parts: %d", partNumber) - } - if info, err := c.StatObject(ctx, c.HashPath(hash)); err == nil { - return nil, &HashAlreadyExistsError{Object: info} - } else if !c.impl.IsNotFound(err) { - return nil, err - } - if size <= partSize { - // Pre-signed upload - key := path.Join(tempPath, c.NowPath(), fmt.Sprintf("%s_%d_%s.presigned", hash, size, c.UUID())) - rawURL, err := c.impl.PresignedPutObject(ctx, key, expire) - if err != nil { - return nil, err - } - return &InitiateUploadResult{ - UploadID: newMultipartUploadID(multipartUploadID{ - Type: UploadTypePresigned, - ID: "", - Key: key, - Size: size, - Hash: hash, - }), - PartSize: partSize, - Sign: &s3.AuthSignResult{ - Parts: []s3.SignPart{ - { - PartNumber: 1, - URL: rawURL, - }, - }, - }, - }, nil - } else { - // Fragment upload - upload, err := c.impl.InitiateMultipartUpload(ctx, c.HashPath(hash)) - if err != nil { - return nil, err - } - if maxParts < 0 { - maxParts = partNumber - } - var authSign *s3.AuthSignResult - if maxParts > 0 { - partNumbers := make([]int, maxParts) - for i := 0; i < maxParts; i++ { - partNumbers[i] = i + 1 - } - authSign, err = c.impl.AuthSign(ctx, upload.UploadID, upload.Key, time.Hour*24, partNumbers) - if err != nil { - return nil, err - } - } - return &InitiateUploadResult{ - UploadID: newMultipartUploadID(multipartUploadID{ - Type: UploadTypeMultipart, - ID: upload.UploadID, - Key: upload.Key, - Size: size, - Hash: hash, - }), - PartSize: partSize, - Sign: authSign, - }, nil - } -} - -func (c *Controller) CompleteUpload(ctx context.Context, uploadID string, partHashs []string) (*UploadResult, error) { - defer log.ZDebug(ctx, "return") - upload, err := parseMultipartUploadID(uploadID) - if err != nil { - return nil, err - } - if md5Sum := md5.Sum([]byte(strings.Join(partHashs, partSeparator))); hex.EncodeToString(md5Sum[:]) != upload.Hash { - return nil, errors.New("md5 mismatching") - } - if info, err := c.StatObject(ctx, c.HashPath(upload.Hash)); err == nil { - return &UploadResult{ - Key: info.Key, - Size: info.Size, - Hash: info.ETag, - }, nil - } else if !c.IsNotFound(err) { - return nil, err - } - cleanObject := make(map[string]struct{}) - defer func() { - for key := range cleanObject { - _ = c.impl.DeleteObject(ctx, key) - } - }() - var targetKey string - switch upload.Type { - case UploadTypeMultipart: - parts := make([]s3.Part, len(partHashs)) - for i, part := range partHashs { - parts[i] = s3.Part{ - PartNumber: i + 1, - ETag: part, - } - } - // todo: Validation size - result, err := c.impl.CompleteMultipartUpload(ctx, upload.ID, upload.Key, parts) - if err != nil { - return nil, err - } - targetKey = result.Key - case UploadTypePresigned: - uploadInfo, err := c.StatObject(ctx, upload.Key) - if err != nil { - return nil, err - } - cleanObject[uploadInfo.Key] = struct{}{} - if uploadInfo.Size != upload.Size { - return nil, errors.New("upload size mismatching") - } - md5Sum := md5.Sum([]byte(strings.Join([]string{uploadInfo.ETag}, partSeparator))) - if md5val := hex.EncodeToString(md5Sum[:]); md5val != upload.Hash { - return nil, errs.ErrArgs.Wrap(fmt.Sprintf("md5 mismatching %s != %s", md5val, upload.Hash)) - } - // Prevents concurrent operations at this time that cause files to be overwritten - copyInfo, err := c.impl.CopyObject(ctx, uploadInfo.Key, upload.Key+"."+c.UUID()) - if err != nil { - return nil, err - } - cleanObject[copyInfo.Key] = struct{}{} - if copyInfo.ETag != uploadInfo.ETag { - return nil, errors.New("[concurrency]copy md5 mismatching") - } - hashCopyInfo, err := c.impl.CopyObject(ctx, copyInfo.Key, c.HashPath(upload.Hash)) - if err != nil { - return nil, err - } - log.ZInfo(ctx, "hashCopyInfo", "value", fmt.Sprintf("%+v", hashCopyInfo)) - targetKey = hashCopyInfo.Key - default: - return nil, errors.New("invalid upload id type") - } - if err := c.cache.DelS3Key(c.impl.Engine(), targetKey).ExecDel(ctx); err != nil { - return nil, err - } - return &UploadResult{ - Key: targetKey, - Size: upload.Size, - Hash: upload.Hash, - }, nil -} - -func (c *Controller) AuthSign(ctx context.Context, uploadID string, partNumbers []int) (*s3.AuthSignResult, error) { - upload, err := parseMultipartUploadID(uploadID) - if err != nil { - return nil, err - } - switch upload.Type { - case UploadTypeMultipart: - return c.impl.AuthSign(ctx, upload.ID, upload.Key, time.Hour*24, partNumbers) - case UploadTypePresigned: - return nil, errors.New("presigned id not support auth sign") - default: - return nil, errors.New("invalid upload id type") - } -} - -func (c *Controller) IsNotFound(err error) bool { - return c.impl.IsNotFound(err) || errs.ErrRecordNotFound.Is(err) -} - -func (c *Controller) AccessURL(ctx context.Context, name string, expire time.Duration, opt *s3.AccessURLOption) (string, error) { - if opt.Image != nil { - opt.Filename = "" - opt.ContentType = "" - } - return c.impl.AccessURL(ctx, name, expire, opt) -} - -func (c *Controller) FormData(ctx context.Context, name string, size int64, contentType string, duration time.Duration) (*s3.FormData, error) { - return c.impl.FormData(ctx, name, size, contentType, duration) -} diff --git a/pkg/common/db/s3/cont/error.go b/pkg/common/db/s3/cont/error.go deleted file mode 100644 index 8225274d35..0000000000 --- a/pkg/common/db/s3/cont/error.go +++ /dev/null @@ -1,29 +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 cont - -import ( - "fmt" - - "github.com/openimsdk/open-im-server/v3/pkg/common/db/s3" -) - -type HashAlreadyExistsError struct { - Object *s3.ObjectInfo -} - -func (e *HashAlreadyExistsError) Error() string { - return fmt.Sprintf("hash already exists: %s", e.Object.Key) -} diff --git a/pkg/common/db/s3/cont/id.go b/pkg/common/db/s3/cont/id.go deleted file mode 100644 index 47f37d4aa6..0000000000 --- a/pkg/common/db/s3/cont/id.go +++ /dev/null @@ -1,49 +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 cont - -import ( - "encoding/base64" - "encoding/json" - "fmt" -) - -type multipartUploadID struct { - Type int `json:"a,omitempty"` - ID string `json:"b,omitempty"` - Key string `json:"c,omitempty"` - Size int64 `json:"d,omitempty"` - Hash string `json:"e,omitempty"` -} - -func newMultipartUploadID(id multipartUploadID) string { - data, err := json.Marshal(id) - if err != nil { - panic(err) - } - return base64.StdEncoding.EncodeToString(data) -} - -func parseMultipartUploadID(id string) (*multipartUploadID, error) { - data, err := base64.StdEncoding.DecodeString(id) - if err != nil { - return nil, fmt.Errorf("invalid multipart upload id: %w", err) - } - var upload multipartUploadID - if err := json.Unmarshal(data, &upload); err != nil { - return nil, fmt.Errorf("invalid multipart upload id: %w", err) - } - return &upload, nil -} diff --git a/pkg/common/db/s3/cont/structs.go b/pkg/common/db/s3/cont/structs.go deleted file mode 100644 index de484cc5f2..0000000000 --- a/pkg/common/db/s3/cont/structs.go +++ /dev/null @@ -1,34 +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 cont - -import "github.com/openimsdk/open-im-server/v3/pkg/common/db/s3" - -type InitiateUploadResult struct { - // UploadID uniquely identifies the upload session for tracking and management purposes. - UploadID string `json:"uploadID"` - - // PartSize specifies the size of each part in a multipart upload. This is relevant for breaking down large uploads into manageable pieces. - PartSize int64 `json:"partSize"` - - // Sign contains the authentication and signature information necessary for securely uploading each part. This could include signed URLs or tokens. - Sign *s3.AuthSignResult `json:"sign"` -} - -type UploadResult struct { - Hash string `json:"hash"` - Size int64 `json:"size"` - Key string `json:"key"` -} diff --git a/pkg/common/db/s3/cos/cos.go b/pkg/common/db/s3/cos/cos.go deleted file mode 100644 index 9852d2a981..0000000000 --- a/pkg/common/db/s3/cos/cos.go +++ /dev/null @@ -1,400 +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 cos - -import ( - "context" - "crypto/hmac" - "crypto/sha1" - "encoding/base64" - "encoding/hex" - "encoding/json" - "errors" - "fmt" - "net/http" - "net/url" - "strconv" - "strings" - "time" - - "github.com/OpenIMSDK/tools/errs" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/s3" - "github.com/tencentyun/cos-go-sdk-v5" -) - -const ( - minPartSize int64 = 1024 * 1024 * 1 // 1MB - maxPartSize int64 = 1024 * 1024 * 1024 * 5 // 5GB - maxNumSize int64 = 1000 -) - -const ( - imagePng = "png" - imageJpg = "jpg" - imageJpeg = "jpeg" - imageGif = "gif" - imageWebp = "webp" -) - -const successCode = http.StatusOK - -type Config struct { - BucketURL string - SecretID string - SecretKey string - SessionToken string - PublicRead bool -} - -func NewCos(conf Config) (s3.Interface, error) { - u, err := url.Parse(conf.BucketURL) - if err != nil { - panic(err) - } - client := cos.NewClient(&cos.BaseURL{BucketURL: u}, &http.Client{ - Transport: &cos.AuthorizationTransport{ - SecretID: conf.SecretID, - SecretKey: conf.SecretKey, - SessionToken: conf.SessionToken, - }, - }) - return &Cos{ - publicRead: conf.PublicRead, - copyURL: u.Host + "/", - client: client, - credential: client.GetCredential(), - }, nil -} - -type Cos struct { - publicRead bool - copyURL string - client *cos.Client - credential *cos.Credential -} - -func (c *Cos) Engine() string { - return "tencent-cos" -} - -func (c *Cos) PartLimit() *s3.PartLimit { - return &s3.PartLimit{ - MinPartSize: minPartSize, - MaxPartSize: maxPartSize, - MaxNumSize: maxNumSize, - } -} - -func (c *Cos) InitiateMultipartUpload(ctx context.Context, name string) (*s3.InitiateMultipartUploadResult, error) { - result, _, err := c.client.Object.InitiateMultipartUpload(ctx, name, nil) - if err != nil { - return nil, err - } - return &s3.InitiateMultipartUploadResult{ - UploadID: result.UploadID, - Bucket: result.Bucket, - Key: result.Key, - }, nil -} - -func (c *Cos) CompleteMultipartUpload(ctx context.Context, uploadID string, name string, parts []s3.Part) (*s3.CompleteMultipartUploadResult, error) { - opts := &cos.CompleteMultipartUploadOptions{ - Parts: make([]cos.Object, len(parts)), - } - for i, part := range parts { - opts.Parts[i] = cos.Object{ - PartNumber: part.PartNumber, - ETag: strings.ReplaceAll(part.ETag, `"`, ``), - } - } - result, _, err := c.client.Object.CompleteMultipartUpload(ctx, name, uploadID, opts) - if err != nil { - return nil, err - } - return &s3.CompleteMultipartUploadResult{ - Location: result.Location, - Bucket: result.Bucket, - Key: result.Key, - ETag: result.ETag, - }, nil -} - -func (c *Cos) PartSize(ctx context.Context, size int64) (int64, error) { - if size <= 0 { - return 0, errors.New("size must be greater than 0") - } - if size > maxPartSize*maxNumSize { - return 0, fmt.Errorf("COS size must be less than the maximum allowed limit") - } - if size <= minPartSize*maxNumSize { - return minPartSize, nil - } - partSize := size / maxNumSize - if size%maxNumSize != 0 { - partSize++ - } - return partSize, nil -} - -func (c *Cos) AuthSign(ctx context.Context, uploadID string, name string, expire time.Duration, partNumbers []int) (*s3.AuthSignResult, error) { - result := s3.AuthSignResult{ - URL: c.client.BaseURL.BucketURL.String() + "/" + cos.EncodeURIComponent(name), - Query: url.Values{"uploadId": {uploadID}}, - Header: make(http.Header), - Parts: make([]s3.SignPart, len(partNumbers)), - } - req, err := http.NewRequestWithContext(ctx, http.MethodPut, result.URL, nil) - if err != nil { - return nil, err - } - cos.AddAuthorizationHeader(c.credential.SecretID, c.credential.SecretKey, c.credential.SessionToken, req, cos.NewAuthTime(expire)) - result.Header = req.Header - for i, partNumber := range partNumbers { - result.Parts[i] = s3.SignPart{ - PartNumber: partNumber, - Query: url.Values{"partNumber": {strconv.Itoa(partNumber)}}, - } - } - return &result, nil -} - -func (c *Cos) PresignedPutObject(ctx context.Context, name string, expire time.Duration) (string, error) { - rawURL, err := c.client.Object.GetPresignedURL(ctx, http.MethodPut, name, c.credential.SecretID, c.credential.SecretKey, expire, nil) - if err != nil { - return "", err - } - return rawURL.String(), nil -} - -func (c *Cos) DeleteObject(ctx context.Context, name string) error { - _, err := c.client.Object.Delete(ctx, name) - return err -} - -func (c *Cos) StatObject(ctx context.Context, name string) (*s3.ObjectInfo, error) { - if name != "" && name[0] == '/' { - name = name[1:] - } - info, err := c.client.Object.Head(ctx, name, nil) - if err != nil { - return nil, err - } - res := &s3.ObjectInfo{Key: name} - if res.ETag = strings.ToLower(strings.ReplaceAll(info.Header.Get("ETag"), `"`, "")); res.ETag == "" { - return nil, errors.New("StatObject etag not found") - } - if contentLengthStr := info.Header.Get("Content-Length"); contentLengthStr == "" { - return nil, errors.New("StatObject content-length not found") - } else { - res.Size, err = strconv.ParseInt(contentLengthStr, 10, 64) - if err != nil { - return nil, fmt.Errorf("StatObject content-length parse error: %w", err) - } - if res.Size < 0 { - return nil, errors.New("StatObject content-length must be greater than 0") - } - } - if lastModified := info.Header.Get("Last-Modified"); lastModified == "" { - return nil, errors.New("StatObject last-modified not found") - } else { - res.LastModified, err = time.Parse(http.TimeFormat, lastModified) - if err != nil { - return nil, fmt.Errorf("StatObject last-modified parse error: %w", err) - } - } - return res, nil -} - -func (c *Cos) CopyObject(ctx context.Context, src string, dst string) (*s3.CopyObjectInfo, error) { - sourceURL := c.copyURL + src - result, _, err := c.client.Object.Copy(ctx, dst, sourceURL, nil) - if err != nil { - return nil, err - } - return &s3.CopyObjectInfo{ - Key: dst, - ETag: strings.ReplaceAll(result.ETag, `"`, ``), - }, nil -} - -func (c *Cos) IsNotFound(err error) bool { - switch e := errs.Unwrap(err).(type) { - case *cos.ErrorResponse: - return e.Response.StatusCode == http.StatusNotFound || e.Code == "NoSuchKey" - default: - return false - } -} - -func (c *Cos) AbortMultipartUpload(ctx context.Context, uploadID string, name string) error { - _, err := c.client.Object.AbortMultipartUpload(ctx, name, uploadID) - return err -} - -func (c *Cos) ListUploadedParts(ctx context.Context, uploadID string, name string, partNumberMarker int, maxParts int) (*s3.ListUploadedPartsResult, error) { - result, _, err := c.client.Object.ListParts(ctx, name, uploadID, &cos.ObjectListPartsOptions{ - MaxParts: strconv.Itoa(maxParts), - PartNumberMarker: strconv.Itoa(partNumberMarker), - }) - if err != nil { - return nil, err - } - res := &s3.ListUploadedPartsResult{ - Key: result.Key, - UploadID: result.UploadID, - UploadedParts: make([]s3.UploadedPart, len(result.Parts)), - } - res.MaxParts, _ = strconv.Atoi(result.MaxParts) - res.NextPartNumberMarker, _ = strconv.Atoi(result.NextPartNumberMarker) - for i, part := range result.Parts { - lastModified, _ := time.Parse(http.TimeFormat, part.LastModified) - res.UploadedParts[i] = s3.UploadedPart{ - PartNumber: part.PartNumber, - LastModified: lastModified, - ETag: part.ETag, - Size: part.Size, - } - } - return res, nil -} - -func (c *Cos) AccessURL(ctx context.Context, name string, expire time.Duration, opt *s3.AccessURLOption) (string, error) { - var imageMogr string - var option cos.PresignedURLOptions - if opt != nil { - query := make(url.Values) - if opt.Image != nil { - // https://cloud.tencent.com/document/product/436/44880 - style := make([]string, 0, 2) - wh := make([]string, 2) - if opt.Image.Width > 0 { - wh[0] = strconv.Itoa(opt.Image.Width) - } - if opt.Image.Height > 0 { - wh[1] = strconv.Itoa(opt.Image.Height) - } - if opt.Image.Width > 0 || opt.Image.Height > 0 { - style = append(style, strings.Join(wh, "x")) - } - switch opt.Image.Format { - case - imagePng, - imageJpg, - imageJpeg, - imageGif, - imageWebp: - style = append(style, "format/"+opt.Image.Format) - } - if len(style) > 0 { - imageMogr = "imageMogr2/thumbnail/" + strings.Join(style, "/") + "/ignore-error/1" - } - } - if opt.ContentType != "" { - query.Set("response-content-type", opt.ContentType) - } - if opt.Filename != "" { - query.Set("response-content-disposition", `attachment; filename=`+strconv.Quote(opt.Filename)) - } - if len(query) > 0 { - option.Query = &query - } - } - if expire <= 0 { - expire = time.Hour * 24 * 365 * 99 // 99 years - } else if expire < time.Second { - expire = time.Second - } - rawURL, err := c.getPresignedURL(ctx, name, expire, &option) - if err != nil { - return "", err - } - if imageMogr != "" { - if rawURL.RawQuery == "" { - rawURL.RawQuery = imageMogr - } else { - rawURL.RawQuery = rawURL.RawQuery + "&" + imageMogr - } - } - return rawURL.String(), nil -} - -func (c *Cos) getPresignedURL(ctx context.Context, name string, expire time.Duration, opt *cos.PresignedURLOptions) (*url.URL, error) { - if !c.publicRead { - return c.client.Object.GetPresignedURL(ctx, http.MethodGet, name, c.credential.SecretID, c.credential.SecretKey, expire, opt) - } - return c.client.Object.GetObjectURL(name), nil -} - -func (c *Cos) FormData(ctx context.Context, name string, size int64, contentType string, duration time.Duration) (*s3.FormData, error) { - // https://cloud.tencent.com/document/product/436/14690 - now := time.Now() - expiration := now.Add(duration) - keyTime := fmt.Sprintf("%d;%d", now.Unix(), expiration.Unix()) - conditions := []any{ - map[string]string{"q-sign-algorithm": "sha1"}, - map[string]string{"q-ak": c.credential.SecretID}, - map[string]string{"q-sign-time": keyTime}, - map[string]string{"key": name}, - } - if contentType != "" { - conditions = append(conditions, map[string]string{"Content-Type": contentType}) - } - policy := map[string]any{ - "expiration": expiration.Format("2006-01-02T15:04:05.000Z"), - "conditions": conditions, - } - policyJson, err := json.Marshal(policy) - if err != nil { - return nil, err - } - signKey := hmacSha1val(c.credential.SecretKey, keyTime) - strToSign := sha1val(string(policyJson)) - signature := hmacSha1val(signKey, strToSign) - - fd := &s3.FormData{ - URL: c.client.BaseURL.BucketURL.String(), - File: "file", - Expires: expiration, - FormData: map[string]string{ - "policy": base64.StdEncoding.EncodeToString(policyJson), - "q-sign-algorithm": "sha1", - "q-ak": c.credential.SecretID, - "q-key-time": keyTime, - "q-signature": signature, - "key": name, - "success_action_status": strconv.Itoa(successCode), - }, - SuccessCodes: []int{successCode}, - } - if contentType != "" { - fd.FormData["Content-Type"] = contentType - } - if c.credential.SessionToken != "" { - fd.FormData["x-cos-security-token"] = c.credential.SessionToken - } - return fd, nil -} - -func hmacSha1val(key, msg string) string { - v := hmac.New(sha1.New, []byte(key)) - v.Write([]byte(msg)) - return hex.EncodeToString(v.Sum(nil)) -} - -func sha1val(msg string) string { - sha1Hash := sha1.New() - sha1Hash.Write([]byte(msg)) - return hex.EncodeToString(sha1Hash.Sum(nil)) -} diff --git a/pkg/common/db/s3/cos/internal.go b/pkg/common/db/s3/cos/internal.go deleted file mode 100644 index 0645469536..0000000000 --- a/pkg/common/db/s3/cos/internal.go +++ /dev/null @@ -1,27 +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 cos - -import ( - "context" - "net/http" - "net/url" - _ "unsafe" - - "github.com/tencentyun/cos-go-sdk-v5" -) - -//go:linkname newRequest github.com/tencentyun/cos-go-sdk-v5.(*Client).newRequest -func newRequest(c *cos.Client, ctx context.Context, baseURL *url.URL, uri, method string, body any, optQuery any, optHeader any) (req *http.Request, err error) diff --git a/pkg/common/db/s3/minio/image.go b/pkg/common/db/s3/minio/image.go deleted file mode 100644 index 3223993f43..0000000000 --- a/pkg/common/db/s3/minio/image.go +++ /dev/null @@ -1,120 +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 minio - -import ( - "image" - _ "image/gif" - _ "image/jpeg" - _ "image/png" - "io" - - _ "golang.org/x/image/bmp" - _ "golang.org/x/image/tiff" - _ "golang.org/x/image/webp" -) - -const ( - formatPng = "png" - formatJpeg = "jpeg" - formatJpg = "jpg" - formatGif = "gif" -) - -func ImageStat(reader io.Reader) (image.Image, string, error) { - return image.Decode(reader) -} - -func ImageWidthHeight(img image.Image) (int, int) { - bounds := img.Bounds().Max - return bounds.X, bounds.Y -} - -func resizeImage(img image.Image, maxWidth, maxHeight int) image.Image { - bounds := img.Bounds() - imgWidth := bounds.Max.X - imgHeight := bounds.Max.Y - - // Calculating scaling - scaleWidth := float64(maxWidth) / float64(imgWidth) - scaleHeight := float64(maxHeight) / float64(imgHeight) - - // If both are 0, then no scaling is done and the original image is returned - if maxWidth == 0 && maxHeight == 0 { - return img - } - - // If both width and height are greater than 0, select a smaller zoom ratio to maintain the aspect ratio - if maxWidth > 0 && maxHeight > 0 { - scale := scaleWidth - if scaleHeight < scaleWidth { - scale = scaleHeight - } - - // Calculate Thumbnail Size - thumbnailWidth := int(float64(imgWidth) * scale) - thumbnailHeight := int(float64(imgHeight) * scale) - - // Thumbnails are generated using the Resample method of the "image" library. - thumbnail := image.NewRGBA(image.Rect(0, 0, thumbnailWidth, thumbnailHeight)) - for y := 0; y < thumbnailHeight; y++ { - for x := 0; x < thumbnailWidth; x++ { - srcX := int(float64(x) / scale) - srcY := int(float64(y) / scale) - thumbnail.Set(x, y, img.At(srcX, srcY)) - } - } - - return thumbnail - } - - // If only width or height is specified, thumbnails are generated based on the maximum not to exceed rule - if maxWidth > 0 { - thumbnailWidth := maxWidth - thumbnailHeight := int(float64(imgHeight) * scaleWidth) - - // Thumbnails are generated using the Resample method of the "image" library. - thumbnail := image.NewRGBA(image.Rect(0, 0, thumbnailWidth, thumbnailHeight)) - for y := 0; y < thumbnailHeight; y++ { - for x := 0; x < thumbnailWidth; x++ { - srcX := int(float64(x) / scaleWidth) - srcY := int(float64(y) / scaleWidth) - thumbnail.Set(x, y, img.At(srcX, srcY)) - } - } - - return thumbnail - } - - if maxHeight > 0 { - thumbnailWidth := int(float64(imgWidth) * scaleHeight) - thumbnailHeight := maxHeight - - // Thumbnails are generated using the Resample method of the "image" library. - thumbnail := image.NewRGBA(image.Rect(0, 0, thumbnailWidth, thumbnailHeight)) - for y := 0; y < thumbnailHeight; y++ { - for x := 0; x < thumbnailWidth; x++ { - srcX := int(float64(x) / scaleHeight) - srcY := int(float64(y) / scaleHeight) - thumbnail.Set(x, y, img.At(srcX, srcY)) - } - } - - return thumbnail - } - - // By default, the original image is returned - return img -} diff --git a/pkg/common/db/s3/minio/internal.go b/pkg/common/db/s3/minio/internal.go deleted file mode 100644 index 7e9dcd9e49..0000000000 --- a/pkg/common/db/s3/minio/internal.go +++ /dev/null @@ -1,25 +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 minio - -import ( - "net/url" - _ "unsafe" - - "github.com/minio/minio-go/v7" -) - -//go:linkname makeTargetURL github.com/minio/minio-go/v7.(*Client).makeTargetURL -func makeTargetURL(client *minio.Client, bucketName, objectName, bucketLocation string, isVirtualHostStyle bool, queryValues url.Values) (*url.URL, error) diff --git a/pkg/common/db/s3/minio/minio.go b/pkg/common/db/s3/minio/minio.go deleted file mode 100644 index 10526998fb..0000000000 --- a/pkg/common/db/s3/minio/minio.go +++ /dev/null @@ -1,499 +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 minio - -import ( - "context" - "errors" - "fmt" - "io" - "net/http" - "net/url" - "path" - "reflect" - "strconv" - "strings" - "sync" - "time" - "unsafe" - - "github.com/OpenIMSDK/tools/errs" - "github.com/OpenIMSDK/tools/log" - "github.com/minio/minio-go/v7" - "github.com/minio/minio-go/v7/pkg/credentials" - "github.com/minio/minio-go/v7/pkg/signer" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/s3" -) - -const ( - unsignedPayload = "UNSIGNED-PAYLOAD" -) - -const ( - minPartSize int64 = 1024 * 1024 * 5 // 5MB - maxPartSize int64 = 1024 * 1024 * 1024 * 5 // 5GB - maxNumSize int64 = 10000 -) - -const ( - maxImageWidth = 1024 - maxImageHeight = 1024 - maxImageSize = 1024 * 1024 * 50 - imageThumbnailPath = "openim/thumbnail" -) - -const successCode = http.StatusOK - -type Config struct { - Bucket string - Endpoint string - AccessKeyID string - SecretAccessKey string - SessionToken string - SignEndpoint string - PublicRead bool -} - -func NewMinio(cache cache.MinioCache, conf Config) (s3.Interface, error) { - u, err := url.Parse(conf.Endpoint) - if err != nil { - return nil, err - } - opts := &minio.Options{ - Creds: credentials.NewStaticV4(conf.AccessKeyID, conf.SecretAccessKey, conf.SessionToken), - Secure: u.Scheme == "https", - } - client, err := minio.New(u.Host, opts) - if err != nil { - return nil, err - } - m := &Minio{ - conf: conf, - bucket: conf.Bucket, - core: &minio.Core{Client: client}, - lock: &sync.Mutex{}, - init: false, - cache: cache, - } - if conf.SignEndpoint == "" || conf.SignEndpoint == conf.Endpoint { - m.opts = opts - m.sign = m.core.Client - m.prefix = u.Path - u.Path = "" - conf.Endpoint = u.String() - m.signEndpoint = conf.Endpoint - } else { - su, err := url.Parse(conf.SignEndpoint) - if err != nil { - return nil, err - } - m.opts = &minio.Options{ - Creds: credentials.NewStaticV4(conf.AccessKeyID, conf.SecretAccessKey, conf.SessionToken), - Secure: su.Scheme == "https", - } - m.sign, err = minio.New(su.Host, m.opts) - if err != nil { - return nil, err - } - m.prefix = su.Path - su.Path = "" - conf.SignEndpoint = su.String() - m.signEndpoint = conf.SignEndpoint - } - ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) - defer cancel() - if err := m.initMinio(ctx); err != nil { - fmt.Println("init minio error:", err) - } - return m, nil -} - -type Minio struct { - conf Config - bucket string - signEndpoint string - location string - opts *minio.Options - core *minio.Core - sign *minio.Client - lock sync.Locker - init bool - prefix string - cache cache.MinioCache -} - -func (m *Minio) initMinio(ctx context.Context) error { - if m.init { - return nil - } - m.lock.Lock() - defer m.lock.Unlock() - if m.init { - return nil - } - exists, err := m.core.Client.BucketExists(ctx, m.conf.Bucket) - if err != nil { - return fmt.Errorf("check bucket exists error: %w", err) - } - if !exists { - if err = m.core.Client.MakeBucket(ctx, m.conf.Bucket, minio.MakeBucketOptions{}); err != nil { - return fmt.Errorf("make bucket error: %w", err) - } - } - if m.conf.PublicRead { - policy := fmt.Sprintf( - `{"Version": "2012-10-17","Statement": [{"Action": ["s3:GetObject","s3:PutObject"],"Effect": "Allow","Principal": {"AWS": ["*"]},"Resource": ["arn:aws:s3:::%s/*"],"Sid": ""}]}`, - m.conf.Bucket, - ) - if err = m.core.Client.SetBucketPolicy(ctx, m.conf.Bucket, policy); err != nil { - return err - } - } - m.location, err = m.core.Client.GetBucketLocation(ctx, m.conf.Bucket) - if err != nil { - return err - } - func() { - if m.conf.SignEndpoint == "" || m.conf.SignEndpoint == m.conf.Endpoint { - return - } - defer func() { - if r := recover(); r != nil { - m.sign = m.core.Client - log.ZWarn( - context.Background(), - "set sign bucket location cache panic", - errors.New("failed to get private field value"), - "recover", - fmt.Sprintf("%+v", r), - "development version", - "github.com/minio/minio-go/v7 v7.0.61", - ) - } - }() - blc := reflect.ValueOf(m.sign).Elem().FieldByName("bucketLocCache") - vblc := reflect.New(reflect.PtrTo(blc.Type())) - *(*unsafe.Pointer)(vblc.UnsafePointer()) = unsafe.Pointer(blc.UnsafeAddr()) - vblc.Elem().Elem().Interface().(interface{ Set(string, string) }).Set(m.conf.Bucket, m.location) - }() - m.init = true - return nil -} - -func (m *Minio) Engine() string { - return "minio" -} - -func (m *Minio) PartLimit() *s3.PartLimit { - return &s3.PartLimit{ - MinPartSize: minPartSize, - MaxPartSize: maxPartSize, - MaxNumSize: maxNumSize, - } -} - -func (m *Minio) InitiateMultipartUpload(ctx context.Context, name string) (*s3.InitiateMultipartUploadResult, error) { - if err := m.initMinio(ctx); err != nil { - return nil, err - } - uploadID, err := m.core.NewMultipartUpload(ctx, m.bucket, name, minio.PutObjectOptions{}) - if err != nil { - return nil, err - } - return &s3.InitiateMultipartUploadResult{ - Bucket: m.bucket, - Key: name, - UploadID: uploadID, - }, nil -} - -func (m *Minio) CompleteMultipartUpload(ctx context.Context, uploadID string, name string, parts []s3.Part) (*s3.CompleteMultipartUploadResult, error) { - if err := m.initMinio(ctx); err != nil { - return nil, err - } - minioParts := make([]minio.CompletePart, len(parts)) - for i, part := range parts { - minioParts[i] = minio.CompletePart{ - PartNumber: part.PartNumber, - ETag: strings.ToLower(part.ETag), - } - } - upload, err := m.core.CompleteMultipartUpload(ctx, m.bucket, name, uploadID, minioParts, minio.PutObjectOptions{}) - if err != nil { - return nil, err - } - m.delObjectImageInfoKey(ctx, name, upload.Size) - return &s3.CompleteMultipartUploadResult{ - Location: upload.Location, - Bucket: upload.Bucket, - Key: upload.Key, - ETag: strings.ToLower(upload.ETag), - }, nil -} - -func (m *Minio) PartSize(ctx context.Context, size int64) (int64, error) { - if size <= 0 { - return 0, errors.New("size must be greater than 0") - } - if size > maxPartSize*maxNumSize { - return 0, fmt.Errorf("MINIO size must be less than the maximum allowed limit") - } - if size <= minPartSize*maxNumSize { - return minPartSize, nil - } - partSize := size / maxNumSize - if size%maxNumSize != 0 { - partSize++ - } - return partSize, nil -} - -func (m *Minio) AuthSign(ctx context.Context, uploadID string, name string, expire time.Duration, partNumbers []int) (*s3.AuthSignResult, error) { - if err := m.initMinio(ctx); err != nil { - return nil, err - } - creds, err := m.opts.Creds.Get() - if err != nil { - return nil, err - } - result := s3.AuthSignResult{ - URL: m.signEndpoint + "/" + m.bucket + "/" + name, - Query: url.Values{"uploadId": {uploadID}}, - Parts: make([]s3.SignPart, len(partNumbers)), - } - for i, partNumber := range partNumbers { - rawURL := result.URL + "?partNumber=" + strconv.Itoa(partNumber) + "&uploadId=" + uploadID - request, err := http.NewRequestWithContext(ctx, http.MethodPut, rawURL, nil) - if err != nil { - return nil, err - } - request.Header.Set("X-Amz-Content-Sha256", unsignedPayload) - request = signer.SignV4Trailer(*request, creds.AccessKeyID, creds.SecretAccessKey, creds.SessionToken, m.location, nil) - result.Parts[i] = s3.SignPart{ - PartNumber: partNumber, - Query: url.Values{"partNumber": {strconv.Itoa(partNumber)}}, - Header: request.Header, - } - } - if m.prefix != "" { - result.URL = m.signEndpoint + m.prefix + "/" + m.bucket + "/" + name - } - return &result, nil -} - -func (m *Minio) PresignedPutObject(ctx context.Context, name string, expire time.Duration) (string, error) { - if err := m.initMinio(ctx); err != nil { - return "", err - } - rawURL, err := m.sign.PresignedPutObject(ctx, m.bucket, name, expire) - if err != nil { - return "", err - } - if m.prefix != "" { - rawURL.Path = path.Join(m.prefix, rawURL.Path) - } - return rawURL.String(), nil -} - -func (m *Minio) DeleteObject(ctx context.Context, name string) error { - if err := m.initMinio(ctx); err != nil { - return err - } - return m.core.Client.RemoveObject(ctx, m.bucket, name, minio.RemoveObjectOptions{}) -} - -func (m *Minio) StatObject(ctx context.Context, name string) (*s3.ObjectInfo, error) { - if err := m.initMinio(ctx); err != nil { - return nil, err - } - info, err := m.core.Client.StatObject(ctx, m.bucket, name, minio.StatObjectOptions{}) - if err != nil { - return nil, err - } - return &s3.ObjectInfo{ - ETag: strings.ToLower(info.ETag), - Key: info.Key, - Size: info.Size, - LastModified: info.LastModified, - }, nil -} - -func (m *Minio) CopyObject(ctx context.Context, src string, dst string) (*s3.CopyObjectInfo, error) { - if err := m.initMinio(ctx); err != nil { - return nil, err - } - result, err := m.core.Client.CopyObject(ctx, minio.CopyDestOptions{ - Bucket: m.bucket, - Object: dst, - }, minio.CopySrcOptions{ - Bucket: m.bucket, - Object: src, - }) - if err != nil { - return nil, err - } - return &s3.CopyObjectInfo{ - Key: dst, - ETag: strings.ToLower(result.ETag), - }, nil -} - -func (m *Minio) IsNotFound(err error) bool { - switch e := errs.Unwrap(err).(type) { - case minio.ErrorResponse: - return e.StatusCode == http.StatusNotFound || e.Code == "NoSuchKey" - case *minio.ErrorResponse: - return e.StatusCode == http.StatusNotFound || e.Code == "NoSuchKey" - default: - return false - } -} - -func (m *Minio) AbortMultipartUpload(ctx context.Context, uploadID string, name string) error { - if err := m.initMinio(ctx); err != nil { - return err - } - return m.core.AbortMultipartUpload(ctx, m.bucket, name, uploadID) -} - -func (m *Minio) ListUploadedParts(ctx context.Context, uploadID string, name string, partNumberMarker int, maxParts int) (*s3.ListUploadedPartsResult, error) { - if err := m.initMinio(ctx); err != nil { - return nil, err - } - result, err := m.core.ListObjectParts(ctx, m.bucket, name, uploadID, partNumberMarker, maxParts) - if err != nil { - return nil, err - } - res := &s3.ListUploadedPartsResult{ - Key: result.Key, - UploadID: result.UploadID, - MaxParts: result.MaxParts, - NextPartNumberMarker: result.NextPartNumberMarker, - UploadedParts: make([]s3.UploadedPart, len(result.ObjectParts)), - } - for i, part := range result.ObjectParts { - res.UploadedParts[i] = s3.UploadedPart{ - PartNumber: part.PartNumber, - LastModified: part.LastModified, - ETag: part.ETag, - Size: part.Size, - } - } - return res, nil -} - -func (m *Minio) PresignedGetObject(ctx context.Context, name string, expire time.Duration, query url.Values) (string, error) { - if expire <= 0 { - expire = time.Hour * 24 * 365 * 99 // 99 years - } else if expire < time.Second { - expire = time.Second - } - var ( - rawURL *url.URL - err error - ) - if m.conf.PublicRead { - rawURL, err = makeTargetURL(m.sign, m.bucket, name, m.location, false, query) - } else { - rawURL, err = m.sign.PresignedGetObject(ctx, m.bucket, name, expire, query) - } - if err != nil { - return "", err - } - if m.prefix != "" { - rawURL.Path = path.Join(m.prefix, rawURL.Path) - } - return rawURL.String(), nil -} - -func (m *Minio) AccessURL(ctx context.Context, name string, expire time.Duration, opt *s3.AccessURLOption) (string, error) { - if err := m.initMinio(ctx); err != nil { - return "", err - } - reqParams := make(url.Values) - if opt != nil { - if opt.ContentType != "" { - reqParams.Set("response-content-type", opt.ContentType) - } - if opt.Filename != "" { - reqParams.Set("response-content-disposition", `attachment; filename=`+strconv.Quote(opt.Filename)) - } - } - if opt.Image == nil || (opt.Image.Width < 0 && opt.Image.Height < 0 && opt.Image.Format == "") || (opt.Image.Width > maxImageWidth || opt.Image.Height > maxImageHeight) { - return m.PresignedGetObject(ctx, name, expire, reqParams) - } - return m.getImageThumbnailURL(ctx, name, expire, opt.Image) -} - -func (m *Minio) getObjectData(ctx context.Context, name string, limit int64) ([]byte, error) { - object, err := m.core.Client.GetObject(ctx, m.bucket, name, minio.GetObjectOptions{}) - if err != nil { - return nil, err - } - defer object.Close() - if limit < 0 { - return io.ReadAll(object) - } - return io.ReadAll(io.LimitReader(object, limit)) -} - -func (m *Minio) FormData(ctx context.Context, name string, size int64, contentType string, duration time.Duration) (*s3.FormData, error) { - if err := m.initMinio(ctx); err != nil { - return nil, err - } - policy := minio.NewPostPolicy() - if err := policy.SetKey(name); err != nil { - return nil, err - } - expires := time.Now().Add(duration) - if err := policy.SetExpires(expires); err != nil { - return nil, err - } - if size > 0 { - if err := policy.SetContentLengthRange(0, size); err != nil { - return nil, err - } - } - if err := policy.SetSuccessStatusAction(strconv.Itoa(successCode)); err != nil { - return nil, err - } - if contentType != "" { - if err := policy.SetContentType(contentType); err != nil { - return nil, err - } - } - if err := policy.SetBucket(m.bucket); err != nil { - return nil, err - } - u, fd, err := m.core.PresignedPostPolicy(ctx, policy) - if err != nil { - return nil, err - } - sign, err := url.Parse(m.signEndpoint) - if err != nil { - return nil, err - } - u.Scheme = sign.Scheme - u.Host = sign.Host - return &s3.FormData{ - URL: u.String(), - File: "file", - Header: nil, - FormData: fd, - Expires: expires, - SuccessCodes: []int{successCode}, - }, nil -} diff --git a/pkg/common/db/s3/minio/thumbnail.go b/pkg/common/db/s3/minio/thumbnail.go deleted file mode 100644 index 1bf96c27c9..0000000000 --- a/pkg/common/db/s3/minio/thumbnail.go +++ /dev/null @@ -1,150 +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 minio - -import ( - "bytes" - "context" - "errors" - "fmt" - "image" - "image/gif" - "image/jpeg" - "image/png" - "net/url" - "path/filepath" - "strings" - "time" - - "github.com/OpenIMSDK/tools/errs" - "github.com/OpenIMSDK/tools/log" - "github.com/minio/minio-go/v7" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/s3" -) - -func (m *Minio) getImageThumbnailURL(ctx context.Context, name string, expire time.Duration, opt *s3.Image) (string, error) { - var img image.Image - info, err := m.cache.GetImageObjectKeyInfo(ctx, name, func(ctx context.Context) (info *cache.MinioImageInfo, err error) { - info, img, err = m.getObjectImageInfo(ctx, name) - return - }) - if err != nil { - return "", err - } - if !info.IsImg { - return "", errs.ErrData.Wrap("object not image") - } - if opt.Width > info.Width || opt.Width <= 0 { - opt.Width = info.Width - } - if opt.Height > info.Height || opt.Height <= 0 { - opt.Height = info.Height - } - opt.Format = strings.ToLower(opt.Format) - if opt.Format == formatJpg { - opt.Format = formatJpeg - } - switch opt.Format { - case formatPng, formatJpeg, formatGif: - default: - opt.Format = "" - } - reqParams := make(url.Values) - if opt.Width == info.Width && opt.Height == info.Height && (opt.Format == info.Format || opt.Format == "") { - reqParams.Set("response-content-type", "image/"+info.Format) - return m.PresignedGetObject(ctx, name, expire, reqParams) - } - if opt.Format == "" { - switch opt.Format { - case formatGif: - opt.Format = formatGif - case formatJpeg: - opt.Format = formatJpeg - case formatPng: - opt.Format = formatPng - default: - opt.Format = formatPng - } - } - key, err := m.cache.GetThumbnailKey(ctx, name, opt.Format, opt.Width, opt.Height, func(ctx context.Context) (string, error) { - if img == nil { - var reader *minio.Object - reader, err = m.core.Client.GetObject(ctx, m.bucket, name, minio.GetObjectOptions{}) - if err != nil { - return "", err - } - defer reader.Close() - img, _, err = ImageStat(reader) - if err != nil { - return "", err - } - } - thumbnail := resizeImage(img, opt.Width, opt.Height) - buf := bytes.NewBuffer(nil) - switch opt.Format { - case formatPng: - err = png.Encode(buf, thumbnail) - case formatJpeg: - err = jpeg.Encode(buf, thumbnail, nil) - case formatGif: - err = gif.Encode(buf, thumbnail, nil) - } - cacheKey := filepath.Join(imageThumbnailPath, info.Etag, fmt.Sprintf("image_w%d_h%d.%s", opt.Width, opt.Height, opt.Format)) - if _, err = m.core.Client.PutObject(ctx, m.bucket, cacheKey, buf, int64(buf.Len()), minio.PutObjectOptions{}); err != nil { - return "", err - } - return cacheKey, nil - }) - if err != nil { - return "", err - } - reqParams.Set("response-content-type", "image/"+opt.Format) - return m.PresignedGetObject(ctx, key, expire, reqParams) -} - -func (m *Minio) getObjectImageInfo(ctx context.Context, name string) (*cache.MinioImageInfo, image.Image, error) { - fileInfo, err := m.StatObject(ctx, name) - if err != nil { - return nil, nil, err - } - if fileInfo.Size > maxImageSize { - return nil, nil, errors.New("file size too large") - } - imageData, err := m.getObjectData(ctx, name, fileInfo.Size) - if err != nil { - return nil, nil, err - } - var info cache.MinioImageInfo - imageInfo, format, err := ImageStat(bytes.NewReader(imageData)) - if err == nil { - info.IsImg = true - info.Format = format - info.Width, info.Height = ImageWidthHeight(imageInfo) - } else { - info.IsImg = false - } - info.Etag = fileInfo.ETag - return &info, imageInfo, nil -} - -func (m *Minio) delObjectImageInfoKey(ctx context.Context, key string, size int64) { - if size > 0 && size > maxImageSize { - return - } - if err := m.cache.DelObjectImageInfoKey(key).ExecDel(ctx); err != nil { - log.ZError(ctx, "DelObjectImageInfoKey failed", err, "key", key) - } -} diff --git a/pkg/common/db/s3/oss/internal.go b/pkg/common/db/s3/oss/internal.go deleted file mode 100644 index 155708ffd7..0000000000 --- a/pkg/common/db/s3/oss/internal.go +++ /dev/null @@ -1,39 +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 oss - -import ( - "net/http" - "net/url" - _ "unsafe" - - "github.com/aliyun/aliyun-oss-go-sdk/oss" -) - -//go:linkname signHeader github.com/aliyun/aliyun-oss-go-sdk/oss.Conn.signHeader -func signHeader(c oss.Conn, req *http.Request, canonicalizedResource string) - -//go:linkname getURLParams github.com/aliyun/aliyun-oss-go-sdk/oss.Conn.getURLParams -func getURLParams(c oss.Conn, params map[string]any) string - -//go:linkname getURL github.com/aliyun/aliyun-oss-go-sdk/oss.urlMaker.getURL -func getURL(um urlMaker, bucket, object, params string) *url.URL - -type urlMaker struct { - Scheme string - NetLoc string - Type int - IsProxy bool -} diff --git a/pkg/common/db/s3/oss/oss.go b/pkg/common/db/s3/oss/oss.go deleted file mode 100644 index e485db2774..0000000000 --- a/pkg/common/db/s3/oss/oss.go +++ /dev/null @@ -1,382 +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 oss - -import ( - "context" - "crypto/hmac" - "crypto/sha1" - "encoding/base64" - "encoding/json" - "errors" - "fmt" - "io" - "net/http" - "net/url" - "reflect" - "strconv" - "strings" - "time" - - "github.com/OpenIMSDK/tools/errs" - "github.com/aliyun/aliyun-oss-go-sdk/oss" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/s3" -) - -const ( - minPartSize int64 = 1024 * 1024 * 1 // 1MB - maxPartSize int64 = 1024 * 1024 * 1024 * 5 // 5GB - maxNumSize int64 = 10000 -) - -const ( - imagePng = "png" - imageJpg = "jpg" - imageJpeg = "jpeg" - imageGif = "gif" - imageWebp = "webp" -) - -const successCode = http.StatusOK - -type Config struct { - Endpoint string - Bucket string - BucketURL string - AccessKeyID string - AccessKeySecret string - SessionToken string - PublicRead bool -} - -func NewOSS(conf Config) (s3.Interface, error) { - if conf.BucketURL == "" { - return nil, errs.Wrap(errors.New("bucket url is empty")) - } - client, err := oss.New(conf.Endpoint, conf.AccessKeyID, conf.AccessKeySecret) - if err != nil { - return nil, err - } - bucket, err := client.Bucket(conf.Bucket) - if err != nil { - return nil, errs.Wrap(err, "ali-oss bucket error") - } - if conf.BucketURL[len(conf.BucketURL)-1] != '/' { - conf.BucketURL += "/" - } - return &OSS{ - bucketURL: conf.BucketURL, - bucket: bucket, - credentials: client.Config.GetCredentials(), - um: *(*urlMaker)(reflect.ValueOf(bucket.Client.Conn).Elem().FieldByName("url").UnsafePointer()), - publicRead: conf.PublicRead, - }, nil -} - -type OSS struct { - bucketURL string - bucket *oss.Bucket - credentials oss.Credentials - um urlMaker - publicRead bool -} - -func (o *OSS) Engine() string { - return "ali-oss" -} - -func (o *OSS) PartLimit() *s3.PartLimit { - return &s3.PartLimit{ - MinPartSize: minPartSize, - MaxPartSize: maxPartSize, - MaxNumSize: maxNumSize, - } -} - -func (o *OSS) InitiateMultipartUpload(ctx context.Context, name string) (*s3.InitiateMultipartUploadResult, error) { - result, err := o.bucket.InitiateMultipartUpload(name) - if err != nil { - return nil, err - } - return &s3.InitiateMultipartUploadResult{ - UploadID: result.UploadID, - Bucket: result.Bucket, - Key: result.Key, - }, nil -} - -func (o *OSS) CompleteMultipartUpload(ctx context.Context, uploadID string, name string, parts []s3.Part) (*s3.CompleteMultipartUploadResult, error) { - ossParts := make([]oss.UploadPart, len(parts)) - for i, part := range parts { - ossParts[i] = oss.UploadPart{ - PartNumber: part.PartNumber, - ETag: strings.ToUpper(part.ETag), - } - } - result, err := o.bucket.CompleteMultipartUpload(oss.InitiateMultipartUploadResult{ - UploadID: uploadID, - Bucket: o.bucket.BucketName, - Key: name, - }, ossParts) - if err != nil { - return nil, err - } - return &s3.CompleteMultipartUploadResult{ - Location: result.Location, - Bucket: result.Bucket, - Key: result.Key, - ETag: strings.ToLower(strings.ReplaceAll(result.ETag, `"`, ``)), - }, nil -} - -func (o *OSS) PartSize(ctx context.Context, size int64) (int64, error) { - if size <= 0 { - return 0, errs.Wrap(errors.New("size must be greater than 0")) - } - if size > maxPartSize*maxNumSize { - return 0, errs.Wrap(errors.New("size must be less than the maximum allowed limit")) - } - if size <= minPartSize*maxNumSize { - return minPartSize, nil - } - partSize := size / maxNumSize - if size%maxNumSize != 0 { - partSize++ - } - return partSize, nil -} - -func (o *OSS) AuthSign(ctx context.Context, uploadID string, name string, expire time.Duration, partNumbers []int) (*s3.AuthSignResult, error) { - result := s3.AuthSignResult{ - URL: o.bucketURL + name, - Query: url.Values{"uploadId": {uploadID}}, - Header: make(http.Header), - Parts: make([]s3.SignPart, len(partNumbers)), - } - for i, partNumber := range partNumbers { - rawURL := fmt.Sprintf(`%s%s?partNumber=%d&uploadId=%s`, o.bucketURL, name, partNumber, uploadID) - request, err := http.NewRequest(http.MethodPut, rawURL, nil) - if err != nil { - return nil, err - } - if o.credentials.GetSecurityToken() != "" { - request.Header.Set(oss.HTTPHeaderOssSecurityToken, o.credentials.GetSecurityToken()) - } - now := time.Now().UTC().Format(http.TimeFormat) - request.Header.Set(oss.HTTPHeaderHost, request.Host) - request.Header.Set(oss.HTTPHeaderDate, now) - request.Header.Set(oss.HttpHeaderOssDate, now) - signHeader(*o.bucket.Client.Conn, request, fmt.Sprintf(`/%s/%s?partNumber=%d&uploadId=%s`, o.bucket.BucketName, name, partNumber, uploadID)) - delete(request.Header, oss.HTTPHeaderDate) - result.Parts[i] = s3.SignPart{ - PartNumber: partNumber, - Query: url.Values{"partNumber": {strconv.Itoa(partNumber)}}, - URL: request.URL.String(), - Header: request.Header, - } - } - return &result, nil -} - -func (o *OSS) PresignedPutObject(ctx context.Context, name string, expire time.Duration) (string, error) { - return o.bucket.SignURL(name, http.MethodPut, int64(expire/time.Second)) -} - -func (o *OSS) StatObject(ctx context.Context, name string) (*s3.ObjectInfo, error) { - header, err := o.bucket.GetObjectMeta(name) - if err != nil { - return nil, err - } - res := &s3.ObjectInfo{Key: name} - if res.ETag = strings.ToLower(strings.ReplaceAll(header.Get("ETag"), `"`, ``)); res.ETag == "" { - return nil, errs.Wrap(errors.New("StatObject etag not found")) - } - if contentLengthStr := header.Get("Content-Length"); contentLengthStr == "" { - return nil, errors.New("StatObject content-length not found") - } else { - res.Size, err = strconv.ParseInt(contentLengthStr, 10, 64) - if err != nil { - return nil, errs.Wrap(err, "StatObject content-length parse error") - } - if res.Size < 0 { - return nil, errs.Wrap(errors.New("StatObject content-length must be greater than 0")) - } - } - if lastModified := header.Get("Last-Modified"); lastModified == "" { - return nil, errs.Wrap(errors.New("StatObject last-modified not found")) - } else { - res.LastModified, err = time.Parse(http.TimeFormat, lastModified) - if err != nil { - return nil, errs.Wrap(err, "StatObject last-modified parse error") - } - } - return res, nil -} - -func (o *OSS) DeleteObject(ctx context.Context, name string) error { - return o.bucket.DeleteObject(name) -} - -func (o *OSS) CopyObject(ctx context.Context, src string, dst string) (*s3.CopyObjectInfo, error) { - result, err := o.bucket.CopyObject(src, dst) - if err != nil { - return nil, errs.Wrap(err, "CopyObject error") - } - return &s3.CopyObjectInfo{ - Key: dst, - ETag: strings.ToLower(strings.ReplaceAll(result.ETag, `"`, ``)), - }, nil -} - -func (o *OSS) IsNotFound(err error) bool { - switch e := errs.Unwrap(err).(type) { - case oss.ServiceError: - return e.StatusCode == http.StatusNotFound || e.Code == "NoSuchKey" - case *oss.ServiceError: - return e.StatusCode == http.StatusNotFound || e.Code == "NoSuchKey" - default: - return false - } -} - -func (o *OSS) AbortMultipartUpload(ctx context.Context, uploadID string, name string) error { - return o.bucket.AbortMultipartUpload(oss.InitiateMultipartUploadResult{ - UploadID: uploadID, - Key: name, - Bucket: o.bucket.BucketName, - }) -} - -func (o *OSS) ListUploadedParts(ctx context.Context, uploadID string, name string, partNumberMarker int, maxParts int) (*s3.ListUploadedPartsResult, error) { - result, err := o.bucket.ListUploadedParts(oss.InitiateMultipartUploadResult{ - UploadID: uploadID, - Key: name, - Bucket: o.bucket.BucketName, - }, oss.MaxUploads(100), oss.MaxParts(maxParts), oss.PartNumberMarker(partNumberMarker)) - if err != nil { - return nil, errs.Wrap(err, "ListUploadedParts error") - } - res := &s3.ListUploadedPartsResult{ - Key: result.Key, - UploadID: result.UploadID, - MaxParts: result.MaxParts, - UploadedParts: make([]s3.UploadedPart, len(result.UploadedParts)), - } - res.NextPartNumberMarker, _ = strconv.Atoi(result.NextPartNumberMarker) - for i, part := range result.UploadedParts { - res.UploadedParts[i] = s3.UploadedPart{ - PartNumber: part.PartNumber, - LastModified: part.LastModified, - ETag: part.ETag, - Size: int64(part.Size), - } - } - return res, nil -} - -func (o *OSS) AccessURL(ctx context.Context, name string, expire time.Duration, opt *s3.AccessURLOption) (string, error) { - var opts []oss.Option - if opt != nil { - if opt.Image != nil { - // Docs Address: https://help.aliyun.com/zh/oss/user-guide/resize-images-4?spm=a2c4g.11186623.0.0.4b3b1e4fWW6yji - var format string - switch opt.Image.Format { - case - imagePng, - imageJpg, - imageJpeg, - imageGif, - imageWebp: - format = opt.Image.Format - default: - opt.Image.Format = imageJpg - } - // https://oss-console-img-demo-cn-hangzhou.oss-cn-hangzhou.aliyuncs.com/example.jpg?x-oss-process=image/resize,h_100,m_lfit - process := "image/resize,m_lfit" - if opt.Image.Width > 0 { - process += ",w_" + strconv.Itoa(opt.Image.Width) - } - if opt.Image.Height > 0 { - process += ",h_" + strconv.Itoa(opt.Image.Height) - } - process += ",format," + format - opts = append(opts, oss.Process(process)) - } - if !o.publicRead { - if opt.ContentType != "" { - opts = append(opts, oss.ResponseContentType(opt.ContentType)) - } - if opt.Filename != "" { - opts = append(opts, oss.ResponseContentDisposition(`attachment; filename=`+strconv.Quote(opt.Filename))) - } - } - } - if expire <= 0 { - expire = time.Hour * 24 * 365 * 99 // 99 years - } else if expire < time.Second { - expire = time.Second - } - if !o.publicRead { - return o.bucket.SignURL(name, http.MethodGet, int64(expire/time.Second), opts...) - } - rawParams, err := oss.GetRawParams(opts) - if err != nil { - return "", errs.Wrap(err, "AccessURL error") - } - params := getURLParams(*o.bucket.Client.Conn, rawParams) - return getURL(o.um, o.bucket.BucketName, name, params).String(), nil -} - -func (o *OSS) FormData(ctx context.Context, name string, size int64, contentType string, duration time.Duration) (*s3.FormData, error) { - // https://help.aliyun.com/zh/oss/developer-reference/postobject?spm=a2c4g.11186623.0.0.1cb83cebkP55nn - expires := time.Now().Add(duration) - conditions := []any{ - map[string]string{"bucket": o.bucket.BucketName}, - map[string]string{"key": name}, - } - if size > 0 { - conditions = append(conditions, []any{"content-length-range", 0, size}) - } - policy := map[string]any{ - "expiration": expires.Format("2006-01-02T15:04:05.000Z"), - "conditions": conditions, - } - policyJson, err := json.Marshal(policy) - if err != nil { - return nil, errs.Wrap(err, "Marshal json error") - } - policyStr := base64.StdEncoding.EncodeToString(policyJson) - h := hmac.New(sha1.New, []byte(o.credentials.GetAccessKeySecret())) - if _, err := io.WriteString(h, policyStr); err != nil { - return nil, errs.Wrap(err, "WriteString error") - } - fd := &s3.FormData{ - URL: o.bucketURL, - File: "file", - Expires: expires, - FormData: map[string]string{ - "key": name, - "policy": policyStr, - "OSSAccessKeyId": o.credentials.GetAccessKeyID(), - "success_action_status": strconv.Itoa(successCode), - "signature": base64.StdEncoding.EncodeToString(h.Sum(nil)), - }, - SuccessCodes: []int{successCode}, - } - if contentType != "" { - fd.FormData["x-oss-content-type"] = contentType - } - return fd, nil -} diff --git a/pkg/common/db/s3/s3.go b/pkg/common/db/s3/s3.go deleted file mode 100644 index d3dd90ae98..0000000000 --- a/pkg/common/db/s3/s3.go +++ /dev/null @@ -1,166 +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 s3 - -import ( - "context" - "net/http" - "net/url" - "time" -) - -type PartLimit struct { - MinPartSize int64 `json:"minPartSize"` - MaxPartSize int64 `json:"maxPartSize"` - MaxNumSize int64 `json:"maxNumSize"` -} - -type InitiateMultipartUploadResult struct { - Bucket string `json:"bucket"` - Key string `json:"key"` - UploadID string `json:"uploadID"` -} - -type MultipartUploadRequest struct { - UploadID string `json:"uploadId"` - Bucket string `json:"bucket"` - Key string `json:"key"` - Method string `json:"method"` - URL string `json:"url"` - Query url.Values `json:"query"` - Header http.Header `json:"header"` - PartKey string `json:"partKey"` - PartSize int64 `json:"partSize"` - FirstPart int `json:"firstPart"` -} - -type Part struct { - PartNumber int `json:"partNumber"` - ETag string `json:"etag"` -} - -type CompleteMultipartUploadResult struct { - Location string `json:"location"` - Bucket string `json:"bucket"` - Key string `json:"key"` - ETag string `json:"etag"` -} - -type SignResult struct { - Parts []SignPart `json:"parts"` -} - -type ObjectInfo struct { - ETag string `json:"etag"` - Key string `json:"name"` - Size int64 `json:"size"` - LastModified time.Time `json:"lastModified"` -} - -type CopyObjectInfo struct { - Key string `json:"name"` - ETag string `json:"etag"` -} - -type FormData struct { - URL string `json:"url"` - File string `json:"file"` - Header http.Header `json:"header"` - FormData map[string]string `json:"form"` - Expires time.Time `json:"expires"` - SuccessCodes []int `json:"successActionStatus"` -} - -type SignPart struct { - PartNumber int `json:"partNumber"` - URL string `json:"url"` - Query url.Values `json:"query"` - Header http.Header `json:"header"` -} - -type AuthSignResult struct { - URL string `json:"url"` - Query url.Values `json:"query"` - Header http.Header `json:"header"` - Parts []SignPart `json:"parts"` -} - -type InitiateUpload struct { - UploadID string `json:"uploadId"` - Bucket string `json:"bucket"` - Key string `json:"key"` - Method string `json:"method"` - URL string `json:"url"` - Query url.Values `json:"query"` - Header http.Header `json:"header"` - PartKey string `json:"partKey"` - PartSize int64 `json:"partSize"` - FirstPart int `json:"firstPart"` -} - -type UploadedPart struct { - PartNumber int `json:"partNumber"` - LastModified time.Time `json:"lastModified"` - ETag string `json:"etag"` - Size int64 `json:"size"` -} - -type ListUploadedPartsResult struct { - Key string `xml:"Key"` - UploadID string `xml:"UploadId"` - NextPartNumberMarker int `xml:"NextPartNumberMarker"` - MaxParts int `xml:"MaxParts"` - UploadedParts []UploadedPart `xml:"Part"` -} - -type Image struct { - Format string `json:"format"` - Width int `json:"width"` - Height int `json:"height"` -} - -type AccessURLOption struct { - ContentType string `json:"contentType"` - Filename string `json:"filename"` - Image *Image `json:"image"` -} - -type Interface interface { - Engine() string - PartLimit() *PartLimit - - InitiateMultipartUpload(ctx context.Context, name string) (*InitiateMultipartUploadResult, error) - CompleteMultipartUpload(ctx context.Context, uploadID string, name string, parts []Part) (*CompleteMultipartUploadResult, error) - - PartSize(ctx context.Context, size int64) (int64, error) - AuthSign(ctx context.Context, uploadID string, name string, expire time.Duration, partNumbers []int) (*AuthSignResult, error) - - PresignedPutObject(ctx context.Context, name string, expire time.Duration) (string, error) - - DeleteObject(ctx context.Context, name string) error - - CopyObject(ctx context.Context, src string, dst string) (*CopyObjectInfo, error) - - StatObject(ctx context.Context, name string) (*ObjectInfo, error) - - IsNotFound(err error) bool - - AbortMultipartUpload(ctx context.Context, uploadID string, name string) error - ListUploadedParts(ctx context.Context, uploadID string, name string, partNumberMarker int, maxParts int) (*ListUploadedPartsResult, error) - - AccessURL(ctx context.Context, name string, expire time.Duration, opt *AccessURLOption) (string, error) - - FormData(ctx context.Context, name string, size int64, contentType string, duration time.Duration) (*FormData, error) -} diff --git a/pkg/common/db/table/relation/black.go b/pkg/common/db/table/relation/black.go index 50499054cc..f5d1cb2369 100644 --- a/pkg/common/db/table/relation/black.go +++ b/pkg/common/db/table/relation/black.go @@ -18,7 +18,7 @@ import ( "context" "time" - "github.com/OpenIMSDK/tools/pagination" + "github.com/openimsdk/tools/db/pagination" ) type BlackModel struct { @@ -33,8 +33,8 @@ type BlackModel struct { type BlackModelInterface interface { Create(ctx context.Context, blacks []*BlackModel) (err error) Delete(ctx context.Context, blacks []*BlackModel) (err error) - //UpdateByMap(ctx context.Context, ownerUserID, blockUserID string, args map[string]any) (err error) - //Update(ctx context.Context, blacks []*BlackModel) (err error) + // UpdateByMap(ctx context.Context, ownerUserID, blockUserID string, args map[string]any) (err error) + // Update(ctx context.Context, blacks []*BlackModel) (err error) Find(ctx context.Context, blacks []*BlackModel) (blackList []*BlackModel, err error) Take(ctx context.Context, ownerUserID, blockUserID string) (black *BlackModel, err error) FindOwnerBlacks(ctx context.Context, ownerUserID string, pagination pagination.Pagination) (total int64, blacks []*BlackModel, err error) diff --git a/pkg/common/db/table/relation/conversation.go b/pkg/common/db/table/relation/conversation.go index 583e41c0f2..4990c96c60 100644 --- a/pkg/common/db/table/relation/conversation.go +++ b/pkg/common/db/table/relation/conversation.go @@ -18,7 +18,7 @@ import ( "context" "time" - "github.com/OpenIMSDK/tools/pagination" + "github.com/openimsdk/tools/db/pagination" ) type ConversationModel struct { diff --git a/pkg/common/db/unrelation/doc.go b/pkg/common/db/table/relation/doc.go similarity index 79% rename from pkg/common/db/unrelation/doc.go rename to pkg/common/db/table/relation/doc.go index 1a15e42c4b..c711dec705 100644 --- a/pkg/common/db/unrelation/doc.go +++ b/pkg/common/db/table/relation/doc.go @@ -1,4 +1,4 @@ -// Copyright © 2023 OpenIM. All rights reserved. +// 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. @@ -12,4 +12,4 @@ // See the License for the specific language governing permissions and // limitations under the License. -package unrelation // import "github.com/openimsdk/open-im-server/v3/pkg/common/db/unrelation" +package relation // import "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" diff --git a/pkg/common/db/table/relation/friend.go b/pkg/common/db/table/relation/friend.go index 73f7454df1..4c84e773dd 100644 --- a/pkg/common/db/table/relation/friend.go +++ b/pkg/common/db/table/relation/friend.go @@ -18,7 +18,7 @@ import ( "context" "time" - "github.com/OpenIMSDK/tools/pagination" + "github.com/openimsdk/tools/db/pagination" ) // FriendModel represents the data structure for a friend relationship in MongoDB. diff --git a/pkg/common/db/table/relation/friend_request.go b/pkg/common/db/table/relation/friend_request.go index 8dceb0778c..d59e3bb0b5 100644 --- a/pkg/common/db/table/relation/friend_request.go +++ b/pkg/common/db/table/relation/friend_request.go @@ -18,7 +18,7 @@ import ( "context" "time" - "github.com/OpenIMSDK/tools/pagination" + "github.com/openimsdk/tools/db/pagination" ) type FriendRequestModel struct { diff --git a/pkg/common/db/table/relation/group.go b/pkg/common/db/table/relation/group.go index 1f969cd4fb..f479a4745b 100644 --- a/pkg/common/db/table/relation/group.go +++ b/pkg/common/db/table/relation/group.go @@ -18,7 +18,7 @@ import ( "context" "time" - "github.com/OpenIMSDK/tools/pagination" + "github.com/openimsdk/tools/db/pagination" ) type GroupModel struct { diff --git a/pkg/common/db/table/relation/group_member.go b/pkg/common/db/table/relation/group_member.go index 88ab87739d..37f1cfc03e 100644 --- a/pkg/common/db/table/relation/group_member.go +++ b/pkg/common/db/table/relation/group_member.go @@ -18,7 +18,7 @@ import ( "context" "time" - "github.com/OpenIMSDK/tools/pagination" + "github.com/openimsdk/tools/db/pagination" ) type GroupMemberModel struct { @@ -36,10 +36,10 @@ type GroupMemberModel struct { } type GroupMemberModelInterface interface { - //NewTx(tx any) GroupMemberModelInterface + // NewTx(tx any) GroupMemberModelInterface Create(ctx context.Context, groupMembers []*GroupMemberModel) (err error) Delete(ctx context.Context, groupID string, userIDs []string) (err error) - //DeleteGroup(ctx context.Context, groupIDs []string) (err error) + // DeleteGroup(ctx context.Context, groupIDs []string) (err error) Update(ctx context.Context, groupID string, userID string, data map[string]any) (err error) UpdateRoleLevel(ctx context.Context, groupID string, userID string, roleLevel int32) error FindMemberUserID(ctx context.Context, groupID string) (userIDs []string, err error) @@ -47,11 +47,11 @@ type GroupMemberModelInterface interface { TakeOwner(ctx context.Context, groupID string) (groupMember *GroupMemberModel, err error) SearchMember(ctx context.Context, keyword string, groupID string, pagination pagination.Pagination) (total int64, groupList []*GroupMemberModel, err error) FindRoleLevelUserIDs(ctx context.Context, groupID string, roleLevel int32) ([]string, error) - //MapGroupMemberNum(ctx context.Context, groupIDs []string) (count map[string]uint32, err error) - //FindJoinUserID(ctx context.Context, groupIDs []string) (groupUsers map[string][]string, err error) + // MapGroupMemberNum(ctx context.Context, groupIDs []string) (count map[string]uint32, err error) + // FindJoinUserID(ctx context.Context, groupIDs []string) (groupUsers map[string][]string, err error) FindUserJoinedGroupID(ctx context.Context, userID string) (groupIDs []string, err error) TakeGroupMemberNum(ctx context.Context, groupID string) (count int64, err error) - //FindUsersJoinedGroupID(ctx context.Context, userIDs []string) (map[string][]string, error) + // FindUsersJoinedGroupID(ctx context.Context, userIDs []string) (map[string][]string, error) FindUserManagedGroupID(ctx context.Context, userID string) (groupIDs []string, err error) IsUpdateRoleLevel(data map[string]any) bool } diff --git a/pkg/common/db/table/relation/group_request.go b/pkg/common/db/table/relation/group_request.go index 39999d799f..7e9b258de0 100644 --- a/pkg/common/db/table/relation/group_request.go +++ b/pkg/common/db/table/relation/group_request.go @@ -18,7 +18,7 @@ import ( "context" "time" - "github.com/OpenIMSDK/tools/pagination" + "github.com/openimsdk/tools/db/pagination" ) type GroupRequestModel struct { diff --git a/pkg/common/db/table/relation/log.go b/pkg/common/db/table/relation/log.go index ba63c0c2bc..afc32c68e5 100644 --- a/pkg/common/db/table/relation/log.go +++ b/pkg/common/db/table/relation/log.go @@ -18,7 +18,7 @@ import ( "context" "time" - "github.com/OpenIMSDK/tools/pagination" + "github.com/openimsdk/tools/db/pagination" ) type LogModel struct { diff --git a/pkg/common/db/table/unrelation/msg.go b/pkg/common/db/table/relation/msg.go similarity index 88% rename from pkg/common/db/table/unrelation/msg.go rename to pkg/common/db/table/relation/msg.go index 60dd7c260c..14b8dbb30e 100644 --- a/pkg/common/db/table/unrelation/msg.go +++ b/pkg/common/db/table/relation/msg.go @@ -12,15 +12,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -package unrelation +package relation import ( "context" "strconv" "time" - "github.com/OpenIMSDK/protocol/msg" - "github.com/OpenIMSDK/protocol/sdkws" + "github.com/openimsdk/protocol/msg" + "github.com/openimsdk/protocol/sdkws" + "github.com/openimsdk/tools/errs" "go.mongodb.org/mongo-driver/mongo" ) @@ -32,6 +33,8 @@ const ( NewestList = -1 ) +var ErrMsgListNotExist = errs.New("user not have msg in mongoDB") + type MsgDocModel struct { DocID string `bson:"doc_id"` Msg []*MsgInfoModel `bson:"msgs"` @@ -110,23 +113,8 @@ type MsgDocModelInterface interface { DeleteMsgsInOneDocByIndex(ctx context.Context, docID string, indexes []int) error MarkSingleChatMsgsAsRead(ctx context.Context, userID string, docID string, indexes []int64) error SearchMessage(ctx context.Context, req *msg.SearchMessageReq) (int32, []*MsgInfoModel, error) - RangeUserSendCount( - ctx context.Context, - start time.Time, - end time.Time, - group bool, - ase bool, - pageNumber int32, - showNumber int32, - ) (msgCount int64, userCount int64, users []*UserCount, dateCount map[string]int64, err error) - RangeGroupSendCount( - ctx context.Context, - start time.Time, - end time.Time, - ase bool, - pageNumber int32, - showNumber int32, - ) (msgCount int64, userCount int64, groups []*GroupCount, dateCount map[string]int64, err error) + RangeUserSendCount(ctx context.Context, start time.Time, end time.Time, group bool, ase bool, pageNumber int32, showNumber int32) (msgCount int64, userCount int64, users []*UserCount, dateCount map[string]int64, err error) + RangeGroupSendCount(ctx context.Context, start time.Time, end time.Time, ase bool, pageNumber int32, showNumber int32) (msgCount int64, userCount int64, groups []*GroupCount, dateCount map[string]int64, err error) ConvertMsgsDocLen(ctx context.Context, conversationIDs []string) } @@ -165,11 +153,11 @@ func (m MsgDocModel) GetDocIDSeqsMap(conversationID string, seqs []int64) map[st return t } -func (m MsgDocModel) GetMsgIndex(seq int64) int64 { +func (MsgDocModel) GetMsgIndex(seq int64) int64 { return (seq - 1) % singleGocMsgNum } -func (m MsgDocModel) indexGen(conversationID string, seqSuffix int64) string { +func (MsgDocModel) indexGen(conversationID string, seqSuffix int64) string { return conversationID + ":" + strconv.FormatInt(seqSuffix, 10) } diff --git a/pkg/common/db/table/unrelation/user.go b/pkg/common/db/table/relation/subscribe.go similarity index 86% rename from pkg/common/db/table/unrelation/user.go rename to pkg/common/db/table/relation/subscribe.go index 1505829e56..4e184cf384 100644 --- a/pkg/common/db/table/unrelation/user.go +++ b/pkg/common/db/table/relation/subscribe.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package unrelation +package relation import "context" @@ -21,18 +21,18 @@ const ( SubscribeUser = "subscribe_user" ) -// UserModel collection structure. -type UserModel struct { +// SubscribeUserModel collection structure. +type SubscribeUserModel struct { UserID string `bson:"user_id" json:"userID"` UserIDList []string `bson:"user_id_list" json:"userIDList"` } -func (UserModel) TableName() string { +func (SubscribeUserModel) TableName() string { return SubscribeUser } -// UserModelInterface Operation interface of user mongodb. -type UserModelInterface interface { +// SubscribeUserModelInterface Operation interface of user mongodb. +type SubscribeUserModelInterface interface { // AddSubscriptionList Subscriber's handling of thresholds. AddSubscriptionList(ctx context.Context, userID string, userIDList []string) error // UnsubscriptionList Handling of unsubscribe. diff --git a/pkg/common/db/table/relation/user.go b/pkg/common/db/table/relation/user.go index 375930ddf2..938a8a77d7 100644 --- a/pkg/common/db/table/relation/user.go +++ b/pkg/common/db/table/relation/user.go @@ -18,8 +18,8 @@ import ( "context" "time" - "github.com/OpenIMSDK/protocol/user" - "github.com/OpenIMSDK/tools/pagination" + "github.com/openimsdk/protocol/user" + "github.com/openimsdk/tools/db/pagination" ) type UserModel struct { @@ -65,7 +65,7 @@ type UserModelInterface interface { CountTotal(ctx context.Context, before *time.Time) (count int64, err error) // Get user total quantity every day CountRangeEverydayTotal(ctx context.Context, start time.Time, end time.Time) (map[string]int64, error) - //CRUD user command + // CRUD user command AddUserCommand(ctx context.Context, userID string, Type int32, UUID string, value string, ex string) error DeleteUserCommand(ctx context.Context, userID string, Type int32, UUID string) error UpdateUserCommand(ctx context.Context, userID string, Type int32, UUID string, val map[string]any) error diff --git a/pkg/common/db/table/relation/utils.go b/pkg/common/db/table/relation/utils.go index 380f2410ea..006da48083 100644 --- a/pkg/common/db/table/relation/utils.go +++ b/pkg/common/db/table/relation/utils.go @@ -15,7 +15,7 @@ package relation import ( - "github.com/OpenIMSDK/tools/utils" + "github.com/openimsdk/tools/errs" "go.mongodb.org/mongo-driver/mongo" ) @@ -31,5 +31,5 @@ type GroupSimpleUserID struct { } func IsNotFound(err error) bool { - return utils.Unwrap(err) == mongo.ErrNoDocuments + return errs.Unwrap(err) == mongo.ErrNoDocuments } diff --git a/pkg/common/db/table/unrelation/common.go b/pkg/common/db/table/unrelation/common.go deleted file mode 100644 index bd46ccc2ac..0000000000 --- a/pkg/common/db/table/unrelation/common.go +++ /dev/null @@ -1,20 +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 unrelation - -type CommonUserModel struct { - UserID string `bson:"user_id"` - UserName string `bson:"user_name"` -} diff --git a/pkg/common/db/table/unrelation/super_group.go b/pkg/common/db/table/unrelation/super_group.go deleted file mode 100644 index 1fd80c67a7..0000000000 --- a/pkg/common/db/table/unrelation/super_group.go +++ /dev/null @@ -1,53 +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 unrelation - -//import ( -// "context" -//) -// -//const ( -// CSuperGroup = "super_group" -// CUserToSuperGroup = "user_to_super_group" -//) -// -//type SuperGroupModel struct { -// GroupID string `bson:"group_id" json:"groupID"` -// MemberIDs []string `bson:"member_id_list" json:"memberIDList"` -//} -// -//func (SuperGroupModel) TableName() string { -// return CSuperGroup -//} -// -//type UserToSuperGroupModel struct { -// UserID string `bson:"user_id" json:"userID"` -// GroupIDs []string `bson:"group_id_list" json:"groupIDList"` -//} -// -//func (UserToSuperGroupModel) TableName() string { -// return CUserToSuperGroup -//} -// -//type SuperGroupModelInterface interface { -// CreateSuperGroup(ctx context.Context, groupID string, initMemberIDs []string) error -// TakeSuperGroup(ctx context.Context, groupID string) (group *SuperGroupModel, err error) -// FindSuperGroup(ctx context.Context, groupIDs []string) (groups []*SuperGroupModel, err error) -// AddUserToSuperGroup(ctx context.Context, groupID string, userIDs []string) error -// RemoverUserFromSuperGroup(ctx context.Context, groupID string, userIDs []string) error -// GetSuperGroupByUserID(ctx context.Context, userID string) (*UserToSuperGroupModel, error) -// DeleteSuperGroup(ctx context.Context, groupID string) error -// RemoveGroupFromUser(ctx context.Context, groupID string, userIDs []string) error -//} diff --git a/pkg/common/db/unrelation/mongo.go b/pkg/common/db/unrelation/mongo.go deleted file mode 100644 index 834e812375..0000000000 --- a/pkg/common/db/unrelation/mongo.go +++ /dev/null @@ -1,168 +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 unrelation - -import ( - "context" - "fmt" - "os" - "strings" - "time" - - "github.com/OpenIMSDK/tools/errs" - "github.com/OpenIMSDK/tools/mw/specialerror" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/unrelation" - "go.mongodb.org/mongo-driver/bson" - "go.mongodb.org/mongo-driver/mongo" - "go.mongodb.org/mongo-driver/mongo/options" -) - -const ( - maxRetry = 10 // number of retries - mongoConnTimeout = 10 * time.Second -) - -type Mongo struct { - db *mongo.Client - config *config.GlobalConfig -} - -// NewMongo Initialize MongoDB connection. -func NewMongo(config *config.GlobalConfig) (*Mongo, error) { - specialerror.AddReplace(mongo.ErrNoDocuments, errs.ErrRecordNotFound) - uri := buildMongoURI(config) - - var mongoClient *mongo.Client - var err error - - // Retry connecting to MongoDB - for i := 0; i <= maxRetry; i++ { - ctx, cancel := context.WithTimeout(context.Background(), mongoConnTimeout) - defer cancel() - mongoClient, err = mongo.Connect(ctx, options.Client().ApplyURI(uri)) - if err == nil { - if err = mongoClient.Ping(ctx, nil); err != nil { - return nil, errs.Wrap(err, uri) - } - return &Mongo{db: mongoClient, config: config}, nil - } - if shouldRetry(err) { - time.Sleep(time.Second) // exponential backoff could be implemented here - continue - } - } - return nil, errs.Wrap(err, uri) -} - -func buildMongoURI(config *config.GlobalConfig) string { - uri := os.Getenv("MONGO_URI") - if uri != "" { - return uri - } - - if config.Mongo.Uri != "" { - return config.Mongo.Uri - } - - username := os.Getenv("MONGO_OPENIM_USERNAME") - password := os.Getenv("MONGO_OPENIM_PASSWORD") - address := os.Getenv("MONGO_ADDRESS") - port := os.Getenv("MONGO_PORT") - database := os.Getenv("MONGO_DATABASE") - maxPoolSize := os.Getenv("MONGO_MAX_POOL_SIZE") - - if username == "" { - username = config.Mongo.Username - } - if password == "" { - password = config.Mongo.Password - } - if address == "" { - address = strings.Join(config.Mongo.Address, ",") - } else if port != "" { - address = fmt.Sprintf("%s:%s", address, port) - } - if database == "" { - database = config.Mongo.Database - } - if maxPoolSize == "" { - maxPoolSize = fmt.Sprint(config.Mongo.MaxPoolSize) - } - - if username != "" && password != "" { - - return fmt.Sprintf("mongodb://%s:%s@%s/%s?maxPoolSize=%s", username, password, address, database, maxPoolSize) - } - return fmt.Sprintf("mongodb://%s/%s?maxPoolSize=%s", address, database, maxPoolSize) -} - -func shouldRetry(err error) bool { - if cmdErr, ok := err.(mongo.CommandError); ok { - return cmdErr.Code != 13 && cmdErr.Code != 18 - } - return true -} - -// GetClient returns the MongoDB client. -func (m *Mongo) GetClient() *mongo.Client { - return m.db -} - -// GetDatabase returns the specific database from MongoDB. -func (m *Mongo) GetDatabase(database string) *mongo.Database { - return m.db.Database(database) -} - -// CreateMsgIndex creates an index for messages in MongoDB. -func (m *Mongo) CreateMsgIndex() error { - return m.createMongoIndex(unrelation.Msg, true, "doc_id") -} - -// createMongoIndex creates an index in a MongoDB collection. -func (m *Mongo) createMongoIndex(collection string, isUnique bool, keys ...string) error { - db := m.GetDatabase(m.config.Mongo.Database).Collection(collection) - opts := options.CreateIndexes().SetMaxTime(10 * time.Second) - indexView := db.Indexes() - - keysDoc := buildIndexKeys(keys) - - index := mongo.IndexModel{ - Keys: keysDoc, - } - if isUnique { - index.Options = options.Index().SetUnique(true) - } - - _, err := indexView.CreateOne(context.Background(), index, opts) - if err != nil { - return errs.Wrap(err, "CreateIndex") - } - return nil -} - -// buildIndexKeys builds the BSON document for index keys. -func buildIndexKeys(keys []string) bson.D { - keysDoc := bson.D{} - for _, key := range keys { - direction := 1 // default direction is ascending - if strings.HasPrefix(key, "-") { - direction = -1 // descending order for prefixed with "-" - key = strings.TrimLeft(key, "-") - } - keysDoc = append(keysDoc, bson.E{Key: key, Value: direction}) - } - return keysDoc -} diff --git a/pkg/common/db/unrelation/msg_convert.go b/pkg/common/db/unrelation/msg_convert.go deleted file mode 100644 index 30c74e927b..0000000000 --- a/pkg/common/db/unrelation/msg_convert.go +++ /dev/null @@ -1,81 +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 unrelation - -import ( - "context" - "fmt" - - "github.com/OpenIMSDK/tools/log" - table "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/unrelation" - "go.mongodb.org/mongo-driver/bson" - "go.mongodb.org/mongo-driver/bson/primitive" -) - -func (m *MsgMongoDriver) ConvertMsgsDocLen(ctx context.Context, conversationIDs []string) { - for _, conversationID := range conversationIDs { - regex := primitive.Regex{Pattern: fmt.Sprintf("^%s:", conversationID)} - cursor, err := m.MsgCollection.Find(ctx, bson.M{"doc_id": regex}) - if err != nil { - log.ZError(ctx, "convertAll find msg doc failed", err, "conversationID", conversationID) - continue - } - var msgDocs []table.MsgDocModel - err = cursor.All(ctx, &msgDocs) - if err != nil { - log.ZError(ctx, "convertAll cursor all failed", err, "conversationID", conversationID) - continue - } - if len(msgDocs) < 1 { - continue - } - log.ZInfo(ctx, "msg doc convert", "conversationID", conversationID, "len(msgDocs)", len(msgDocs)) - if len(msgDocs[0].Msg) == int(m.model.GetSingleGocMsgNum5000()) { - if _, err := m.MsgCollection.DeleteMany(ctx, bson.M{"doc_id": regex}); err != nil { - log.ZError(ctx, "convertAll delete many failed", err, "conversationID", conversationID) - continue - } - var newMsgDocs []any - for _, msgDoc := range msgDocs { - if int64(len(msgDoc.Msg)) == m.model.GetSingleGocMsgNum() { - continue - } - var index int64 - for index < int64(len(msgDoc.Msg)) { - msg := msgDoc.Msg[index] - if msg != nil && msg.Msg != nil { - msgDocModel := table.MsgDocModel{DocID: m.model.GetDocID(conversationID, msg.Msg.Seq)} - end := index + m.model.GetSingleGocMsgNum() - if int(end) >= len(msgDoc.Msg) { - msgDocModel.Msg = msgDoc.Msg[index:] - } else { - msgDocModel.Msg = msgDoc.Msg[index:end] - } - newMsgDocs = append(newMsgDocs, msgDocModel) - index = end - } else { - break - } - } - } - _, err = m.MsgCollection.InsertMany(ctx, newMsgDocs) - if err != nil { - log.ZError(ctx, "convertAll insert many failed", err, "conversationID", conversationID, "len(newMsgDocs)", len(newMsgDocs)) - } else { - log.ZInfo(ctx, "msg doc convert", "conversationID", conversationID, "len(newMsgDocs)", len(newMsgDocs)) - } - } - } -} diff --git a/pkg/common/db/unrelation/super_group.go b/pkg/common/db/unrelation/super_group.go deleted file mode 100644 index 6c2bb6aafb..0000000000 --- a/pkg/common/db/unrelation/super_group.go +++ /dev/null @@ -1,163 +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 unrelation - -// -//import ( -// "context" -// -// "go.mongodb.org/mongo-driver/bson" -// "go.mongodb.org/mongo-driver/mongo" -// "go.mongodb.org/mongo-driver/mongo/options" -// -// "github.com/OpenIMSDK/tools/utils" -// -// "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/unrelation" -//) -// -//func NewSuperGroupMongoDriver(database *mongo.Database) unrelation.SuperGroupModelInterface { -// return &SuperGroupMongoDriver{ -// superGroupCollection: database.Collection(unrelation.CSuperGroup), -// userToSuperGroupCollection: database.Collection(unrelation.CUserToSuperGroup), -// } -//} -// -//type SuperGroupMongoDriver struct { -// superGroupCollection *mongo.Collection -// userToSuperGroupCollection *mongo.Collection -//} -// -//func (s *SuperGroupMongoDriver) CreateSuperGroup(ctx context.Context, groupID string, initMemberIDs []string) error { -// _, err := s.superGroupCollection.InsertOne(ctx, &unrelation.SuperGroupModel{ -// GroupID: groupID, -// MemberIDs: initMemberIDs, -// }) -// if err != nil { -// return err -// } -// for _, userID := range initMemberIDs { -// _, err = s.userToSuperGroupCollection.UpdateOne( -// ctx, -// bson.M{"user_id": userID}, -// bson.M{"$addToSet": bson.M{"group_id_list": groupID}}, -// &options.UpdateOptions{ -// Upsert: utils.ToPtr(true), -// }, -// ) -// if err != nil { -// return err -// } -// } -// return nil -//} -// -//func (s *SuperGroupMongoDriver) TakeSuperGroup( -// ctx context.Context, -// groupID string, -//) (group *unrelation.SuperGroupModel, err error) { -// if err := s.superGroupCollection.FindOne(ctx, bson.M{"group_id": groupID}).Decode(&group); err != nil { -// return nil, utils.Wrap(err, "") -// } -// return group, nil -//} -// -//func (s *SuperGroupMongoDriver) FindSuperGroup( -// ctx context.Context, -// groupIDs []string, -//) (groups []*unrelation.SuperGroupModel, err error) { -// cursor, err := s.superGroupCollection.Find(ctx, bson.M{"group_id": bson.M{ -// "$in": groupIDs, -// }}) -// if err != nil { -// return nil, err -// } -// defer cursor.Close(ctx) -// if err := cursor.All(ctx, &groups); err != nil { -// return nil, utils.Wrap(err, "") -// } -// return groups, nil -//} -// -//func (s *SuperGroupMongoDriver) AddUserToSuperGroup(ctx context.Context, groupID string, userIDs []string) error { -// _, err := s.superGroupCollection.UpdateOne( -// ctx, -// bson.M{"group_id": groupID}, -// bson.M{"$addToSet": bson.M{"member_id_list": bson.M{"$each": userIDs}}}, -// ) -// if err != nil { -// return err -// } -// upsert := true -// opts := &options.UpdateOptions{ -// Upsert: &upsert, -// } -// for _, userID := range userIDs { -// _, err = s.userToSuperGroupCollection.UpdateOne( -// ctx, -// bson.M{"user_id": userID}, -// bson.M{"$addToSet": bson.M{"group_id_list": groupID}}, -// opts, -// ) -// if err != nil { -// return utils.Wrap(err, "transaction failed") -// } -// } -// return nil -//} -// -//func (s *SuperGroupMongoDriver) RemoverUserFromSuperGroup(ctx context.Context, groupID string, userIDs []string) error { -// _, err := s.superGroupCollection.UpdateOne( -// ctx, -// bson.M{"group_id": groupID}, -// bson.M{"$pull": bson.M{"member_id_list": bson.M{"$in": userIDs}}}, -// ) -// if err != nil { -// return err -// } -// err = s.RemoveGroupFromUser(ctx, groupID, userIDs) -// if err != nil { -// return err -// } -// return nil -//} -// -//func (s *SuperGroupMongoDriver) GetSuperGroupByUserID( -// ctx context.Context, -// userID string, -//) (*unrelation.UserToSuperGroupModel, error) { -// var user unrelation.UserToSuperGroupModel -// err := s.userToSuperGroupCollection.FindOne(ctx, bson.M{"user_id": userID}).Decode(&user) -// return &user, utils.Wrap(err, "") -//} -// -//func (s *SuperGroupMongoDriver) DeleteSuperGroup(ctx context.Context, groupID string) error { -// group, err := s.TakeSuperGroup(ctx, groupID) -// if err != nil { -// return err -// } -// if _, err := s.superGroupCollection.DeleteOne(ctx, bson.M{"group_id": groupID}); err != nil { -// return utils.Wrap(err, "") -// } -// return s.RemoveGroupFromUser(ctx, groupID, group.MemberIDs) -//} -// -//func (s *SuperGroupMongoDriver) RemoveGroupFromUser(ctx context.Context, groupID string, userIDs []string) error { -// _, err := s.userToSuperGroupCollection.UpdateOne( -// ctx, -// bson.M{"user_id": bson.M{"$in": userIDs}}, -// bson.M{"$pull": bson.M{"group_id_list": groupID}}, -// ) -// return utils.Wrap(err, "") -//} diff --git a/pkg/common/discoveryregister/direct/direct_resolver.go b/pkg/common/discoveryregister/direct/direct_resolver.go index a706ce5e4d..8213782772 100644 --- a/pkg/common/discoveryregister/direct/direct_resolver.go +++ b/pkg/common/discoveryregister/direct/direct_resolver.go @@ -19,7 +19,7 @@ import ( "math/rand" "strings" - "github.com/OpenIMSDK/tools/log" + "github.com/openimsdk/tools/log" "google.golang.org/grpc/resolver" ) diff --git a/pkg/common/discoveryregister/direct/directconn.go b/pkg/common/discoveryregister/direct/directconn.go index df03825e51..1cbe56dd52 100644 --- a/pkg/common/discoveryregister/direct/directconn.go +++ b/pkg/common/discoveryregister/direct/directconn.go @@ -14,159 +14,161 @@ package direct -import ( - "context" - "errors" - "fmt" - - "github.com/OpenIMSDK/tools/errs" - config2 "github.com/openimsdk/open-im-server/v3/pkg/common/config" - "google.golang.org/grpc" - "google.golang.org/grpc/credentials/insecure" -) - -type ServiceAddresses map[string][]int - -func getServiceAddresses(config *config2.GlobalConfig) ServiceAddresses { - return ServiceAddresses{ - config.RpcRegisterName.OpenImUserName: config.RpcPort.OpenImUserPort, - config.RpcRegisterName.OpenImFriendName: config.RpcPort.OpenImFriendPort, - config.RpcRegisterName.OpenImMsgName: config.RpcPort.OpenImMessagePort, - config.RpcRegisterName.OpenImMessageGatewayName: config.LongConnSvr.OpenImMessageGatewayPort, - config.RpcRegisterName.OpenImGroupName: config.RpcPort.OpenImGroupPort, - config.RpcRegisterName.OpenImAuthName: config.RpcPort.OpenImAuthPort, - config.RpcRegisterName.OpenImPushName: config.RpcPort.OpenImPushPort, - config.RpcRegisterName.OpenImConversationName: config.RpcPort.OpenImConversationPort, - config.RpcRegisterName.OpenImThirdName: config.RpcPort.OpenImThirdPort, - } -} - -type ConnDirect struct { - additionalOpts []grpc.DialOption - currentServiceAddress string - conns map[string][]*grpc.ClientConn - resolverDirect *ResolverDirect - config *config2.GlobalConfig -} - -func (cd *ConnDirect) GetClientLocalConns() map[string][]*grpc.ClientConn { - return nil -} - -func (cd *ConnDirect) GetUserIdHashGatewayHost(ctx context.Context, userId string) (string, error) { - return "", nil -} - -func (cd *ConnDirect) Register(serviceName, host string, port int, opts ...grpc.DialOption) error { - return nil -} - -func (cd *ConnDirect) UnRegister() error { - return nil -} - -func (cd *ConnDirect) CreateRpcRootNodes(serviceNames []string) error { - return nil -} - -func (cd *ConnDirect) RegisterConf2Registry(key string, conf []byte) error { - return nil -} - -func (cd *ConnDirect) GetConfFromRegistry(key string) ([]byte, error) { - return nil, nil -} - -func (cd *ConnDirect) Close() { - -} - -func NewConnDirect(config *config2.GlobalConfig) (*ConnDirect, error) { - return &ConnDirect{ - conns: make(map[string][]*grpc.ClientConn), - resolverDirect: NewResolverDirect(), - config: config, - }, nil -} - -func (cd *ConnDirect) GetConns(ctx context.Context, - serviceName string, opts ...grpc.DialOption) ([]*grpc.ClientConn, error) { - - if conns, exists := cd.conns[serviceName]; exists { - return conns, nil - } - ports := getServiceAddresses(cd.config)[serviceName] - var connections []*grpc.ClientConn - for _, port := range ports { - conn, err := cd.dialServiceWithoutResolver(ctx, fmt.Sprintf(cd.config.Rpc.ListenIP+":%d", port), append(cd.additionalOpts, opts...)...) - if err != nil { - return nil, errs.Wrap(fmt.Errorf("connect to port %d failed,serviceName %s, IP %s", port, serviceName, cd.config.Rpc.ListenIP)) - } - connections = append(connections, conn) - } - - if len(connections) == 0 { - return nil, errs.Wrap(errors.New("no connections found for service"), "serviceName", serviceName) - } - return connections, nil -} - -func (cd *ConnDirect) GetConn(ctx context.Context, serviceName string, opts ...grpc.DialOption) (*grpc.ClientConn, error) { - // Get service addresses - addresses := getServiceAddresses(cd.config) - address, ok := addresses[serviceName] - if !ok { - return nil, errs.Wrap(errors.New("unknown service name"), "serviceName", serviceName) - } - var result string - for _, addr := range address { - if result != "" { - result = result + "," + fmt.Sprintf(cd.config.Rpc.ListenIP+":%d", addr) - } else { - result = fmt.Sprintf(cd.config.Rpc.ListenIP+":%d", addr) - } - } - // Try to dial a new connection - conn, err := cd.dialService(ctx, result, append(cd.additionalOpts, opts...)...) - if err != nil { - return nil, errs.Wrap(err, "address", result) - } - - // Store the new connection - cd.conns[serviceName] = append(cd.conns[serviceName], conn) - return conn, nil -} - -func (cd *ConnDirect) GetSelfConnTarget() string { - return cd.currentServiceAddress -} - -func (cd *ConnDirect) AddOption(opts ...grpc.DialOption) { - cd.additionalOpts = append(cd.additionalOpts, opts...) -} - -func (cd *ConnDirect) CloseConn(conn *grpc.ClientConn) { - if conn != nil { - conn.Close() - } -} - -func (cd *ConnDirect) dialService(ctx context.Context, address string, opts ...grpc.DialOption) (*grpc.ClientConn, error) { - options := append(opts, grpc.WithTransportCredentials(insecure.NewCredentials())) - conn, err := grpc.DialContext(ctx, cd.resolverDirect.Scheme()+":///"+address, options...) - - if err != nil { - return nil, errs.Wrap(err, "address", address) - } - return conn, nil -} - -func (cd *ConnDirect) dialServiceWithoutResolver(ctx context.Context, address string, opts ...grpc.DialOption) (*grpc.ClientConn, error) { - options := append(opts, grpc.WithTransportCredentials(insecure.NewCredentials())) - conn, err := grpc.DialContext(ctx, address, options...) - - if err != nil { - return nil, errs.Wrap(err) - } - return conn, nil -} +//import ( +// "context" +// "fmt" +// +// config2 "github.com/openimsdk/open-im-server/v3/pkg/common/config" +// "github.com/openimsdk/tools/errs" +// "google.golang.org/grpc" +// "google.golang.org/grpc/credentials/insecure" +//) +// +//type ServiceAddresses map[string][]int +// +//func getServiceAddresses(rpcRegisterName *config2.RpcRegisterName, +// rpcPort *config2.RpcPort, longConnSvrPort []int) ServiceAddresses { +// return ServiceAddresses{ +// rpcRegisterName.OpenImUserName: rpcPort.OpenImUserPort, +// rpcRegisterName.OpenImFriendName: rpcPort.OpenImFriendPort, +// rpcRegisterName.OpenImMsgName: rpcPort.OpenImMessagePort, +// rpcRegisterName.OpenImMessageGatewayName: longConnSvrPort, +// rpcRegisterName.OpenImGroupName: rpcPort.OpenImGroupPort, +// rpcRegisterName.OpenImAuthName: rpcPort.OpenImAuthPort, +// rpcRegisterName.OpenImPushName: rpcPort.OpenImPushPort, +// rpcRegisterName.OpenImConversationName: rpcPort.OpenImConversationPort, +// rpcRegisterName.OpenImThirdName: rpcPort.OpenImThirdPort, +// } +//} +// +//type ConnDirect struct { +// additionalOpts []grpc.DialOption +// currentServiceAddress string +// conns map[string][]*grpc.ClientConn +// resolverDirect *ResolverDirect +// config *config2.GlobalConfig +//} +// +//func (cd *ConnDirect) GetClientLocalConns() map[string][]*grpc.ClientConn { +// return nil +//} +// +//func (cd *ConnDirect) GetUserIdHashGatewayHost(ctx context.Context, userId string) (string, error) { +// return "", nil +//} +// +//func (cd *ConnDirect) Register(serviceName, host string, port int, opts ...grpc.DialOption) error { +// return nil +//} +// +//func (cd *ConnDirect) UnRegister() error { +// return nil +//} +// +//func (cd *ConnDirect) CreateRpcRootNodes(serviceNames []string) error { +// return nil +//} +// +//func (cd *ConnDirect) RegisterConf2Registry(key string, conf []byte) error { +// return nil +//} +// +//func (cd *ConnDirect) GetConfFromRegistry(key string) ([]byte, error) { +// return nil, nil +//} +// +//func (cd *ConnDirect) Close() { +// +//} +// +//func NewConnDirect(config *config2.GlobalConfig) (*ConnDirect, error) { +// return &ConnDirect{ +// conns: make(map[string][]*grpc.ClientConn), +// resolverDirect: NewResolverDirect(), +// config: config, +// }, nil +//} +// +//func (cd *ConnDirect) GetConns(ctx context.Context, +// serviceName string, opts ...grpc.DialOption) ([]*grpc.ClientConn, error) { +// +// if conns, exists := cd.conns[serviceName]; exists { +// return conns, nil +// } +// ports := getServiceAddresses(&cd.config.RpcRegisterName, +// &cd.config.RpcPort, cd.config.LongConnSvr.OpenImMessageGatewayPort)[serviceName] +// var connections []*grpc.ClientConn +// for _, port := range ports { +// conn, err := cd.dialServiceWithoutResolver(ctx, fmt.Sprintf(cd.config.Rpc.ListenIP+":%d", port), append(cd.additionalOpts, opts...)...) +// if err != nil { +// return nil, errs.Wrap(fmt.Errorf("connect to port %d failed,serviceName %s, IP %s", port, serviceName, cd.config.Rpc.ListenIP)) +// } +// connections = append(connections, conn) +// } +// +// if len(connections) == 0 { +// return nil, errs.New("no connections found for service", "serviceName", serviceName).Wrap() +// } +// return connections, nil +//} +// +//func (cd *ConnDirect) GetConn(ctx context.Context, serviceName string, opts ...grpc.DialOption) (*grpc.ClientConn, error) { +// // Get service addresses +// addresses := getServiceAddresses(&cd.config.RpcRegisterName, +// &cd.config.RpcPort, cd.config.LongConnSvr.OpenImMessageGatewayPort) +// address, ok := addresses[serviceName] +// if !ok { +// return nil, errs.New("unknown service name", "serviceName", serviceName).Wrap() +// } +// var result string +// for _, addr := range address { +// if result != "" { +// result = result + "," + fmt.Sprintf(cd.config.Rpc.ListenIP+":%d", addr) +// } else { +// result = fmt.Sprintf(cd.config.Rpc.ListenIP+":%d", addr) +// } +// } +// // Try to dial a new connection +// conn, err := cd.dialService(ctx, result, append(cd.additionalOpts, opts...)...) +// if err != nil { +// return nil, errs.WrapMsg(err, "address", result) +// } +// +// // Store the new connection +// cd.conns[serviceName] = append(cd.conns[serviceName], conn) +// return conn, nil +//} +// +//func (cd *ConnDirect) GetSelfConnTarget() string { +// return cd.currentServiceAddress +//} +// +//func (cd *ConnDirect) AddOption(opts ...grpc.DialOption) { +// cd.additionalOpts = append(cd.additionalOpts, opts...) +//} +// +//func (cd *ConnDirect) CloseConn(conn *grpc.ClientConn) { +// if conn != nil { +// conn.Close() +// } +//} +// +//func (cd *ConnDirect) dialService(ctx context.Context, address string, opts ...grpc.DialOption) (*grpc.ClientConn, error) { +// options := append(opts, grpc.WithTransportCredentials(insecure.NewCredentials())) +// conn, err := grpc.DialContext(ctx, cd.resolverDirect.Scheme()+":///"+address, options...) +// +// if err != nil { +// return nil, errs.WrapMsg(err, "address", address) +// } +// return conn, nil +//} +// +//func (cd *ConnDirect) dialServiceWithoutResolver(ctx context.Context, address string, opts ...grpc.DialOption) (*grpc.ClientConn, error) { +// options := append(opts, grpc.WithTransportCredentials(insecure.NewCredentials())) +// conn, err := grpc.DialContext(ctx, address, options...) +// +// if err != nil { +// return nil, errs.Wrap(err) +// } +// return conn, nil +//} diff --git a/pkg/common/db/table/unrelation/doc.go b/pkg/common/discoveryregister/direct/doc.go similarity index 78% rename from pkg/common/db/table/unrelation/doc.go rename to pkg/common/discoveryregister/direct/doc.go index 7596206a08..b3cd0f804b 100644 --- a/pkg/common/db/table/unrelation/doc.go +++ b/pkg/common/discoveryregister/direct/doc.go @@ -1,4 +1,4 @@ -// Copyright © 2023 OpenIM. All rights reserved. +// 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. @@ -12,4 +12,4 @@ // See the License for the specific language governing permissions and // limitations under the License. -package unrelation // import "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/unrelation" +package direct // import "github.com/openimsdk/open-im-server/v3/pkg/common/discoveryregister/direct" diff --git a/pkg/common/discoveryregister/discoveryregister.go b/pkg/common/discoveryregister/discoveryregister.go index d3acf85f69..b664ee34eb 100644 --- a/pkg/common/discoveryregister/discoveryregister.go +++ b/pkg/common/discoveryregister/discoveryregister.go @@ -15,32 +15,38 @@ package discoveryregister import ( - "errors" - "os" - - "github.com/OpenIMSDK/tools/discoveryregistry" - "github.com/OpenIMSDK/tools/errs" "github.com/openimsdk/open-im-server/v3/pkg/common/config" - "github.com/openimsdk/open-im-server/v3/pkg/common/discoveryregister/direct" "github.com/openimsdk/open-im-server/v3/pkg/common/discoveryregister/kubernetes" - "github.com/openimsdk/open-im-server/v3/pkg/common/discoveryregister/zookeeper" + "github.com/openimsdk/tools/discovery" + "github.com/openimsdk/tools/discovery/zookeeper" + "github.com/openimsdk/tools/errs" + "time" ) -// NewDiscoveryRegister creates a new service discovery and registry client based on the provided environment type. -func NewDiscoveryRegister(config *config.GlobalConfig) (discoveryregistry.SvcDiscoveryRegistry, error) { - - if os.Getenv("ENVS_DISCOVERY") != "" { - config.Envs.Discovery = os.Getenv("ENVS_DISCOVERY") - } +const ( + zookeeperConst = "zookeeper" + kubenetesConst = "k8s" + directConst = "direct" +) - switch config.Envs.Discovery { - case "zookeeper": - return zookeeper.NewZookeeperDiscoveryRegister(config) - case "k8s": - return kubernetes.NewK8sDiscoveryRegister(config.RpcRegisterName.OpenImMessageGatewayName) - case "direct": - return direct.NewConnDirect(config) +// NewDiscoveryRegister creates a new service discovery and registry client based on the provided environment type. +func NewDiscoveryRegister(zookeeperConfig *config.ZooKeeper, share *config.Share) (discovery.SvcDiscoveryRegistry, error) { + switch share.Env { + case zookeeperConst: + return zookeeper.NewZkClient( + zookeeperConfig.Address, + zookeeperConfig.Schema, + zookeeper.WithFreq(time.Hour), + zookeeper.WithUserNameAndPassword(zookeeperConfig.Username, zookeeperConfig.Password), + zookeeper.WithRoundRobin(), + zookeeper.WithTimeout(10), + ) + case kubenetesConst: + return kubernetes.NewK8sDiscoveryRegister(share.RpcRegisterName.MessageGateway) + case directConst: + //return direct.NewConnDirect(config) default: - return nil, errs.Wrap(errors.New("envType not correct")) + return nil, errs.New("unsupported discovery type", "type", share.Env).Wrap() } + return nil, nil } diff --git a/pkg/common/discoveryregister/discoveryregister_test.go b/pkg/common/discoveryregister/discoveryregister_test.go index 08aa5d5d5e..4172266451 100644 --- a/pkg/common/discoveryregister/discoveryregister_test.go +++ b/pkg/common/discoveryregister/discoveryregister_test.go @@ -16,12 +16,6 @@ package discoveryregister import ( "os" - "testing" - - "github.com/openimsdk/open-im-server/v3/pkg/common/config" - - "github.com/OpenIMSDK/tools/discoveryregistry" - "github.com/stretchr/testify/assert" ) func setupTestEnvironment() { @@ -32,35 +26,35 @@ func setupTestEnvironment() { os.Setenv("ZOOKEEPER_PASSWORD", "") } -func TestNewDiscoveryRegister(t *testing.T) { - setupTestEnvironment() - conf := config.NewGlobalConfig() - tests := []struct { - envType string - gatewayName string - expectedError bool - expectedResult bool - }{ - {"zookeeper", "MessageGateway", false, true}, - {"k8s", "MessageGateway", false, true}, - {"direct", "MessageGateway", false, true}, - {"invalid", "MessageGateway", true, false}, - } - - for _, test := range tests { - conf.Envs.Discovery = test.envType - conf.RpcRegisterName.OpenImMessageGatewayName = test.gatewayName - client, err := NewDiscoveryRegister(conf) - - if test.expectedError { - assert.Error(t, err) - } else { - assert.NoError(t, err) - if test.expectedResult { - assert.Implements(t, (*discoveryregistry.SvcDiscoveryRegistry)(nil), client) - } else { - assert.Nil(t, client) - } - } - } -} +//func TestNewDiscoveryRegister(t *testing.T) { +// setupTestEnvironment() +// conf := config.NewGlobalConfig() +// tests := []struct { +// envType string +// gatewayName string +// expectedError bool +// expectedResult bool +// }{ +// {"zookeeper", "MessageGateway", false, true}, +// {"k8s", "MessageGateway", false, true}, +// {"direct", "MessageGateway", false, true}, +// {"invalid", "MessageGateway", true, false}, +// } +// +// for _, test := range tests { +// conf.Envs.Discovery = test.envType +// conf.RpcRegisterName.OpenImMessageGatewayName = test.gatewayName +// client, err := NewDiscoveryRegister(conf) +// +// if test.expectedError { +// assert.Error(t, err) +// } else { +// assert.NoError(t, err) +// if test.expectedResult { +// assert.Implements(t, (*discovery.SvcDiscoveryRegistry)(nil), client) +// } else { +// assert.Nil(t, client) +// } +// } +// } +//} diff --git a/pkg/common/discoveryregister/doc.go b/pkg/common/discoveryregister/doc.go new file mode 100644 index 0000000000..46bbe70012 --- /dev/null +++ b/pkg/common/discoveryregister/doc.go @@ -0,0 +1,15 @@ +// 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 discoveryregister // import "github.com/openimsdk/open-im-server/v3/pkg/common/discoveryregister" diff --git a/pkg/common/discoveryregister/kubernetes/doc.go b/pkg/common/discoveryregister/kubernetes/doc.go new file mode 100644 index 0000000000..8615caa6b6 --- /dev/null +++ b/pkg/common/discoveryregister/kubernetes/doc.go @@ -0,0 +1,15 @@ +// 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 kubernetes // import "github.com/openimsdk/open-im-server/v3/pkg/common/discoveryregister/kubernetes" diff --git a/pkg/common/discoveryregister/kubernetes/kubernetes.go b/pkg/common/discoveryregister/kubernetes/kubernetes.go index 83af53db07..f1ce0bbdce 100644 --- a/pkg/common/discoveryregister/kubernetes/kubernetes.go +++ b/pkg/common/discoveryregister/kubernetes/kubernetes.go @@ -22,8 +22,8 @@ import ( "strconv" "strings" - "github.com/OpenIMSDK/tools/discoveryregistry" - "github.com/OpenIMSDK/tools/log" + "github.com/openimsdk/tools/discovery" + "github.com/openimsdk/tools/log" "github.com/stathat/consistent" "google.golang.org/grpc" ) @@ -36,7 +36,7 @@ type K8sDR struct { gatewayName string } -func NewK8sDiscoveryRegister(gatewayName string) (discoveryregistry.SvcDiscoveryRegistry, error) { +func NewK8sDiscoveryRegister(gatewayName string) (discovery.SvcDiscoveryRegistry, error) { gatewayConsistent := consistent.New() gatewayHosts := getMsgGatewayHost(context.Background(), gatewayName) for _, v := range gatewayHosts { @@ -74,6 +74,7 @@ func (cli *K8sDR) GetConfFromRegistry(key string) ([]byte, error) { return nil, nil } + func (cli *K8sDR) GetUserIdHashGatewayHost(ctx context.Context, userId string) (string, error) { host, err := cli.gatewayHostConsistent.Get(userId) if err != nil { @@ -81,6 +82,7 @@ func (cli *K8sDR) GetUserIdHashGatewayHost(ctx context.Context, userId string) ( } return host, err } + func getSelfHost(ctx context.Context, gatewayName string) string { port := 88 instance := "openimserver" @@ -102,6 +104,7 @@ func getSelfHost(ctx context.Context, gatewayName string) string { } // like openimserver-openim-msggateway-0.openimserver-openim-msggateway-headless.openim-lin.svc.cluster.local:88. +// Replica set in kubernetes environment func getMsgGatewayHost(ctx context.Context, gatewayName string) []string { port := 88 instance := "openimserver" @@ -122,7 +125,7 @@ func getMsgGatewayHost(ctx context.Context, gatewayName string) []string { host := fmt.Sprintf("%s-openim-msggateway-%d.%s-openim-msggateway-headless.%s.svc.cluster.local:%d", instance, i, instance, ns, port) ret = append(ret, host) } - log.ZInfo(ctx, "getMsgGatewayHost", "instance", instance, "selfPodName", selfPodName, "replicas", replicas, "ns", ns, "ret", ret) + log.ZDebug(ctx, "getMsgGatewayHost", "instance", instance, "selfPodName", selfPodName, "replicas", replicas, "ns", ns, "ret", ret) return ret } @@ -187,9 +190,10 @@ func (cli *K8sDR) CloseConn(conn *grpc.ClientConn) { // do not use this method for call rpc. func (cli *K8sDR) GetClientLocalConns() map[string][]*grpc.ClientConn { - fmt.Println("should not call this function!!!!!!!!!!!!!!!!!!!!!!!!!") + log.ZError(context.Background(), "should not call this function!", nil) return nil } + func (cli *K8sDR) Close() { } diff --git a/pkg/common/discoveryregister/zookeeper/doc.go b/pkg/common/discoveryregister/zookeeper/doc.go new file mode 100644 index 0000000000..1c24d77ac9 --- /dev/null +++ b/pkg/common/discoveryregister/zookeeper/doc.go @@ -0,0 +1,15 @@ +// 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/discoveryregister/zookeeper/zookeeper.go b/pkg/common/discoveryregister/zookeeper/zookeeper.go index 0aa40a907c..1d11414b67 100644 --- a/pkg/common/discoveryregister/zookeeper/zookeeper.go +++ b/pkg/common/discoveryregister/zookeeper/zookeeper.go @@ -15,46 +15,10 @@ package zookeeper import ( - "fmt" "os" "strings" - "time" - - "github.com/OpenIMSDK/tools/discoveryregistry" - openkeeper "github.com/OpenIMSDK/tools/discoveryregistry/zookeeper" - "github.com/OpenIMSDK/tools/errs" - "github.com/OpenIMSDK/tools/log" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" ) -// NewZookeeperDiscoveryRegister creates a new instance of ZookeeperDR for Zookeeper service discovery and registration. -func NewZookeeperDiscoveryRegister(config *config.GlobalConfig) (discoveryregistry.SvcDiscoveryRegistry, error) { - schema := getEnv("ZOOKEEPER_SCHEMA", config.Zookeeper.Schema) - zkAddr := getZkAddrFromEnv(config.Zookeeper.ZkAddr) - username := getEnv("ZOOKEEPER_USERNAME", config.Zookeeper.Username) - password := getEnv("ZOOKEEPER_PASSWORD", config.Zookeeper.Password) - - zk, err := openkeeper.NewClient( - zkAddr, - schema, - openkeeper.WithFreq(time.Hour), - openkeeper.WithUserNameAndPassword(username, password), - openkeeper.WithRoundRobin(), - openkeeper.WithTimeout(10), - openkeeper.WithLogger(log.NewZkLogger()), - ) - if err != nil { - uriFormat := "address:%s, username:%s, password:%s, schema:%s." - errInfo := fmt.Sprintf(uriFormat, - config.Zookeeper.ZkAddr, - config.Zookeeper.Username, - config.Zookeeper.Password, - config.Zookeeper.Schema) - return nil, errs.Wrap(err, errInfo) - } - return zk, nil -} - // 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 { diff --git a/pkg/common/ginprometheus/doc.go b/pkg/common/ginprometheus/doc.go new file mode 100644 index 0000000000..7d81b7a8af --- /dev/null +++ b/pkg/common/ginprometheus/doc.go @@ -0,0 +1,15 @@ +// 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 ginprometheus // import "github.com/openimsdk/open-im-server/v3/pkg/common/ginprometheus" diff --git a/pkg/common/http/http_client.go b/pkg/common/http/http_client.go deleted file mode 100644 index 83908b8d33..0000000000 --- a/pkg/common/http/http_client.go +++ /dev/null @@ -1,139 +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 http - -import ( - "bytes" - "context" - "encoding/json" - "io" - "net/http" - "time" - - "github.com/OpenIMSDK/protocol/constant" - "github.com/OpenIMSDK/tools/errs" - "github.com/OpenIMSDK/tools/log" - "github.com/openimsdk/open-im-server/v3/pkg/callbackstruct" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" -) - -var ( - // define http client. - client = &http.Client{ - Timeout: 15 * time.Second, // max timeout is 15s - } -) - -func init() { - // reset http default transport - http.DefaultTransport.(*http.Transport).MaxConnsPerHost = 100 // default: 2 -} - -func Get(url string) (response []byte, err error) { - hclient := http.Client{Timeout: 5 * time.Second} - resp, err := hclient.Get(url) - if err != nil { - return nil, err - } - - defer resp.Body.Close() - body, err := io.ReadAll(resp.Body) - if err != nil { - return nil, err - } - return body, nil -} - -func Post(ctx context.Context, url string, header map[string]string, data any, timeout int) (content []byte, err error) { - if timeout > 0 { - var cancel func() - ctx, cancel = context.WithTimeout(ctx, time.Second*time.Duration(timeout)) - defer cancel() - } - - jsonStr, err := json.Marshal(data) - if err != nil { - return nil, errs.Wrap(err, "Post: JSON marshal failed") - } - - req, err := http.NewRequestWithContext(ctx, http.MethodPost, url, bytes.NewBuffer(jsonStr)) - if err != nil { - return nil, errs.Wrap(err, "Post: NewRequestWithContext failed") - } - - if operationID, _ := ctx.Value(constant.OperationID).(string); operationID != "" { - req.Header.Set(constant.OperationID, operationID) - } - for k, v := range header { - req.Header.Set(k, v) - } - req.Header.Add("content-type", "application/json; charset=utf-8") - - resp, err := client.Do(req) - if err != nil { - return nil, errs.Wrap(err, "Post: client.Do failed") - } - defer resp.Body.Close() - - result, err := io.ReadAll(resp.Body) - if err != nil { - return nil, errs.Wrap(err, "Post: ReadAll failed") - } - - return result, nil -} - -func PostReturn(ctx context.Context, url string, header map[string]string, input, output any, timeOutSecond int) error { - b, err := Post(ctx, url, header, input, timeOutSecond) - if err != nil { - return err - } - err = json.Unmarshal(b, output) - if err != nil { - return errs.Wrap(err, "PostReturn: JSON unmarshal failed") - } - return nil -} - -func callBackPostReturn(ctx context.Context, url, command string, input interface{}, output callbackstruct.CallbackResp, callbackConfig config.CallBackConfig) error { - url = url + "/" + command - log.ZInfo(ctx, "callback", "url", url, "input", input, "config", callbackConfig) - b, err := Post(ctx, url, nil, input, callbackConfig.CallbackTimeOut) - if err != nil { - if callbackConfig.CallbackFailedContinue != nil && *callbackConfig.CallbackFailedContinue { - log.ZInfo(ctx, "callback failed but continue", err, "url", url) - return nil - } - log.ZWarn(ctx, "callback network failed", err, "url", url, "input", input) - return errs.ErrNetwork.Wrap(err.Error()) - } - if err = json.Unmarshal(b, output); err != nil { - if callbackConfig.CallbackFailedContinue != nil && *callbackConfig.CallbackFailedContinue { - log.ZWarn(ctx, "callback failed but continue", err, "url", url) - return nil - } - log.ZWarn(ctx, "callback json unmarshal failed", err, "url", url, "input", input, "response", string(b)) - return errs.ErrData.WithDetail(err.Error() + "response format error") - } - if err := output.Parse(); err != nil { - log.ZWarn(ctx, "callback parse failed", err, "url", url, "input", input, "response", string(b)) - } - log.ZInfo(ctx, "callback success", "url", url, "input", input, "response", string(b)) - return nil -} - -func CallBackPostReturn(ctx context.Context, url string, req callbackstruct.CallbackReq, resp callbackstruct.CallbackResp, callbackConfig config.CallBackConfig) error { - return callBackPostReturn(ctx, url, req.GetCallbackCommand(), req, resp, callbackConfig) -} diff --git a/pkg/common/http/http_client_test.go b/pkg/common/http/http_client_test.go deleted file mode 100644 index 5d25886736..0000000000 --- a/pkg/common/http/http_client_test.go +++ /dev/null @@ -1,154 +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 http - -import ( - "context" - "reflect" - "testing" - - "github.com/openimsdk/open-im-server/v3/pkg/callbackstruct" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" -) - -func TestGet(t *testing.T) { - type args struct { - url string - } - tests := []struct { - name string - args args - wantResponse []byte - wantErr bool - }{ - // TODO: Add test cases. - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - gotResponse, err := Get(tt.args.url) - if (err != nil) != tt.wantErr { - t.Errorf("Get() error = %v, wantErr %v", err, tt.wantErr) - return - } - if !reflect.DeepEqual(gotResponse, tt.wantResponse) { - t.Errorf("Get() = %v, want %v", gotResponse, tt.wantResponse) - } - }) - } -} - -func TestPost(t *testing.T) { - type args struct { - ctx context.Context - url string - header map[string]string - data any - timeout int - } - tests := []struct { - name string - args args - wantContent []byte - wantErr bool - }{ - // TODO: Add test cases. - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - gotContent, err := Post(tt.args.ctx, tt.args.url, tt.args.header, tt.args.data, tt.args.timeout) - if (err != nil) != tt.wantErr { - t.Errorf("Post() error = %v, wantErr %v", err, tt.wantErr) - return - } - if !reflect.DeepEqual(gotContent, tt.wantContent) { - t.Errorf("Post() = %v, want %v", gotContent, tt.wantContent) - } - }) - } -} - -func TestPostReturn(t *testing.T) { - type args struct { - ctx context.Context - url string - header map[string]string - input any - output any - timeOutSecond int - } - tests := []struct { - name string - args args - wantErr bool - }{ - // TODO: Add test cases. - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if err := PostReturn(tt.args.ctx, tt.args.url, tt.args.header, tt.args.input, tt.args.output, tt.args.timeOutSecond); (err != nil) != tt.wantErr { - t.Errorf("PostReturn() error = %v, wantErr %v", err, tt.wantErr) - } - }) - } -} - -func Test_callBackPostReturn(t *testing.T) { - type args struct { - ctx context.Context - url string - command string - input any - output callbackstruct.CallbackResp - callbackConfig config.CallBackConfig - } - tests := []struct { - name string - args args - wantErr bool - }{ - // TODO: Add test cases. - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if err := callBackPostReturn(tt.args.ctx, tt.args.url, tt.args.command, tt.args.input, tt.args.output, tt.args.callbackConfig); (err != nil) != tt.wantErr { - t.Errorf("callBackPostReturn() error = %v, wantErr %v", err, tt.wantErr) - } - }) - } -} - -func TestCallBackPostReturn(t *testing.T) { - type args struct { - ctx context.Context - url string - req callbackstruct.CallbackReq - resp callbackstruct.CallbackResp - callbackConfig config.CallBackConfig - } - tests := []struct { - name string - args args - wantErr bool - }{ - // TODO: Add test cases. - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if err := CallBackPostReturn(tt.args.ctx, tt.args.url, tt.args.req, tt.args.resp, tt.args.callbackConfig); (err != nil) != tt.wantErr { - t.Errorf("CallBackPostReturn() error = %v, wantErr %v", err, tt.wantErr) - } - }) - } -} diff --git a/pkg/common/kafka/consumer.go b/pkg/common/kafka/consumer.go deleted file mode 100644 index 6627c21aea..0000000000 --- a/pkg/common/kafka/consumer.go +++ /dev/null @@ -1,71 +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 kafka - -import ( - "sync" - - "github.com/IBM/sarama" - "github.com/OpenIMSDK/tools/errs" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" -) - -type Consumer struct { - addr []string - WG sync.WaitGroup - Topic string - PartitionList []int32 - Consumer sarama.Consumer -} - -func NewKafkaConsumer(addr []string, topic string, config *config.GlobalConfig) (*Consumer, error) { - p := Consumer{} - p.Topic = topic - p.addr = addr - consumerConfig := sarama.NewConfig() - if config.Kafka.Username != "" && config.Kafka.Password != "" { - consumerConfig.Net.SASL.Enable = true - consumerConfig.Net.SASL.User = config.Kafka.Username - consumerConfig.Net.SASL.Password = config.Kafka.Password - } - var tlsConfig *TLSConfig - if config.Kafka.TLS != nil { - tlsConfig = &TLSConfig{ - CACrt: config.Kafka.TLS.CACrt, - ClientCrt: config.Kafka.TLS.ClientCrt, - ClientKey: config.Kafka.TLS.ClientKey, - ClientKeyPwd: config.Kafka.TLS.ClientKeyPwd, - InsecureSkipVerify: false, - } - } - err := SetupTLSConfig(consumerConfig, tlsConfig) - if err != nil { - return nil, err - } - consumer, err := sarama.NewConsumer(p.addr, consumerConfig) - if err != nil { - return nil, errs.Wrap(err, "NewKafkaConsumer: creating consumer failed") - } - p.Consumer = consumer - - partitionList, err := consumer.Partitions(p.Topic) - if err != nil { - return nil, errs.Wrap(err, "NewKafkaConsumer: getting partitions failed") - } - p.PartitionList = partitionList - - return &p, nil - -} diff --git a/pkg/common/kafka/consumer_group.go b/pkg/common/kafka/consumer_group.go deleted file mode 100644 index 95794aacb7..0000000000 --- a/pkg/common/kafka/consumer_group.go +++ /dev/null @@ -1,87 +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 kafka - -import ( - "context" - "errors" - "strings" - - "github.com/IBM/sarama" - "github.com/OpenIMSDK/tools/errs" - "github.com/OpenIMSDK/tools/log" -) - -type MConsumerGroup struct { - sarama.ConsumerGroup - groupID string - topics []string -} - -type MConsumerGroupConfig struct { - KafkaVersion sarama.KafkaVersion - OffsetsInitial int64 - IsReturnErr bool - UserName string - Password string -} - -func NewMConsumerGroup(consumerConfig *MConsumerGroupConfig, topics, addrs []string, groupID string, tlsConfig *TLSConfig) (*MConsumerGroup, error) { - consumerGroupConfig := sarama.NewConfig() - consumerGroupConfig.Version = consumerConfig.KafkaVersion - consumerGroupConfig.Consumer.Offsets.Initial = consumerConfig.OffsetsInitial - consumerGroupConfig.Consumer.Return.Errors = consumerConfig.IsReturnErr - if consumerConfig.UserName != "" && consumerConfig.Password != "" { - consumerGroupConfig.Net.SASL.Enable = true - consumerGroupConfig.Net.SASL.User = consumerConfig.UserName - consumerGroupConfig.Net.SASL.Password = consumerConfig.Password - } - - SetupTLSConfig(consumerGroupConfig, tlsConfig) - consumerGroup, err := sarama.NewConsumerGroup(addrs, groupID, consumerGroupConfig) - if err != nil { - return nil, errs.Wrap(err, strings.Join(topics, ","), strings.Join(addrs, ","), groupID, consumerConfig.UserName, consumerConfig.Password) - } - - return &MConsumerGroup{ - consumerGroup, - groupID, - topics, - }, nil -} - -func (mc *MConsumerGroup) GetContextFromMsg(cMsg *sarama.ConsumerMessage) context.Context { - return GetContextWithMQHeader(cMsg.Headers) -} - -func (mc *MConsumerGroup) RegisterHandleAndConsumer(ctx context.Context, handler sarama.ConsumerGroupHandler) { - log.ZDebug(ctx, "register consumer group", "groupID", mc.groupID) - for { - err := mc.ConsumerGroup.Consume(ctx, mc.topics, handler) - if errors.Is(err, sarama.ErrClosedConsumerGroup) { - return - } - if errors.Is(err, context.Canceled) { - return - } - if err != nil { - log.ZWarn(ctx, "consume err", err, "topic", mc.topics, "groupID", mc.groupID) - } - } -} - -func (mc *MConsumerGroup) Close() error { - return mc.ConsumerGroup.Close() -} diff --git a/pkg/common/kafka/producer.go b/pkg/common/kafka/producer.go deleted file mode 100644 index 8ee938b515..0000000000 --- a/pkg/common/kafka/producer.go +++ /dev/null @@ -1,197 +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 kafka - -import ( - "bytes" - "context" - "errors" - "fmt" - "strings" - "time" - - "github.com/IBM/sarama" - "github.com/OpenIMSDK/protocol/constant" - "github.com/OpenIMSDK/tools/errs" - "github.com/OpenIMSDK/tools/log" - "github.com/OpenIMSDK/tools/mcontext" - "google.golang.org/protobuf/proto" -) - -const maxRetry = 10 // number of retries - -var errEmptyMsg = errors.New("kafka binary msg is empty") - -// Producer represents a Kafka producer. -type Producer struct { - addr []string - topic string - config *sarama.Config - producer sarama.SyncProducer -} - -type ProducerConfig struct { - ProducerAck string - CompressType string - Username string - Password string -} - -// NewKafkaProducer initializes a new Kafka producer. -func NewKafkaProducer(addr []string, topic string, producerConfig *ProducerConfig, tlsConfig *TLSConfig) (*Producer, error) { - p := Producer{ - addr: addr, - topic: topic, - config: sarama.NewConfig(), - } - - // Set producer return flags - p.config.Producer.Return.Successes = true - p.config.Producer.Return.Errors = true - - // Set partitioner strategy - p.config.Producer.Partitioner = sarama.NewHashPartitioner - - // Configure producer acknowledgement level - configureProducerAck(&p, producerConfig.ProducerAck) - - // Configure message compression - configureCompression(&p, producerConfig.CompressType) - - // Get Kafka configuration from environment variables or fallback to config file - kafkaUsername := getEnvOrConfig("KAFKA_USERNAME", producerConfig.Username) - kafkaPassword := getEnvOrConfig("KAFKA_PASSWORD", producerConfig.Password) - kafkaAddr := getKafkaAddrFromEnv(addr) // Updated to use the new function - - // Configure SASL authentication if credentials are provided - if kafkaUsername != "" && kafkaPassword != "" { - p.config.Net.SASL.Enable = true - p.config.Net.SASL.User = kafkaUsername - p.config.Net.SASL.Password = kafkaPassword - } - - // Set the Kafka address - p.addr = kafkaAddr - - // Set up TLS configuration (if required) - SetupTLSConfig(p.config, tlsConfig) - - // Create the producer with retries - var err error - for i := 0; i <= maxRetry; i++ { - p.producer, err = sarama.NewSyncProducer(p.addr, p.config) - if err == nil { - return &p, errs.Wrap(err) - } - time.Sleep(1 * time.Second) // Wait before retrying - } - // Panic if unable to create producer after retries - if err != nil { - return nil, errs.Wrap(errors.New("failed to create Kafka producer: " + err.Error())) - } - - return &p, nil -} - -// configureProducerAck configures the producer's acknowledgement level. -func configureProducerAck(p *Producer, ackConfig string) { - switch strings.ToLower(ackConfig) { - case "no_response": - p.config.Producer.RequiredAcks = sarama.NoResponse - case "wait_for_local": - p.config.Producer.RequiredAcks = sarama.WaitForLocal - case "wait_for_all": - p.config.Producer.RequiredAcks = sarama.WaitForAll - default: - p.config.Producer.RequiredAcks = sarama.WaitForAll - } -} - -// configureCompression configures the message compression type for the producer. -func configureCompression(p *Producer, compressType string) { - var compress = sarama.CompressionNone - err := compress.UnmarshalText(bytes.ToLower([]byte(compressType))) - if err != nil { - fmt.Printf("Failed to configure compression: %v\n", err) - return - } - p.config.Producer.Compression = compress -} - -// GetMQHeaderWithContext extracts message queue headers from the context. -func GetMQHeaderWithContext(ctx context.Context) ([]sarama.RecordHeader, error) { - operationID, opUserID, platform, connID, err := mcontext.GetCtxInfos(ctx) - if err != nil { - return nil, err - } - return []sarama.RecordHeader{ - {Key: []byte(constant.OperationID), Value: []byte(operationID)}, - {Key: []byte(constant.OpUserID), Value: []byte(opUserID)}, - {Key: []byte(constant.OpUserPlatform), Value: []byte(platform)}, - {Key: []byte(constant.ConnID), Value: []byte(connID)}, - }, nil -} - -// GetContextWithMQHeader creates a context from message queue headers. -func GetContextWithMQHeader(header []*sarama.RecordHeader) context.Context { - var values []string - for _, recordHeader := range header { - values = append(values, string(recordHeader.Value)) - } - return mcontext.WithMustInfoCtx(values) // Attach extracted values to context -} - -// SendMessage sends a message to the Kafka topic configured in the Producer. -func (p *Producer) SendMessage(ctx context.Context, key string, msg proto.Message) (int32, int64, error) { - log.ZDebug(ctx, "SendMessage", "msg", msg, "topic", p.topic, "key", key) - - // Marshal the protobuf message - bMsg, err := proto.Marshal(msg) - if err != nil { - return 0, 0, errs.Wrap(err, "kafka proto Marshal err") - } - if len(bMsg) == 0 { - return 0, 0, errs.Wrap(errEmptyMsg, "") - } - - // Prepare Kafka message - kMsg := &sarama.ProducerMessage{ - Topic: p.topic, - Key: sarama.StringEncoder(key), - Value: sarama.ByteEncoder(bMsg), - } - - // Validate message key and value - if kMsg.Key.Length() == 0 || kMsg.Value.Length() == 0 { - return 0, 0, errs.Wrap(errEmptyMsg) - } - - // Attach context metadata as headers - header, err := GetMQHeaderWithContext(ctx) - if err != nil { - return 0, 0, err - } - kMsg.Headers = header - - // Send the message - partition, offset, err := p.producer.SendMessage(kMsg) - if err != nil { - log.ZWarn(ctx, "p.producer.SendMessage error", err) - return 0, 0, errs.Wrap(err) - } - - log.ZDebug(ctx, "ByteEncoder SendMessage end", "key", kMsg.Key, "key length", kMsg.Value.Length()) - return partition, offset, nil -} diff --git a/pkg/common/kafka/util.go b/pkg/common/kafka/util.go deleted file mode 100644 index 4e2a027143..0000000000 --- a/pkg/common/kafka/util.go +++ /dev/null @@ -1,77 +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 kafka - -import ( - "fmt" - "os" - "strings" - - "github.com/IBM/sarama" - "github.com/openimsdk/open-im-server/v3/pkg/common/tls" -) - -type TLSConfig struct { - CACrt string - ClientCrt string - ClientKey string - ClientKeyPwd string - InsecureSkipVerify bool -} - -// SetupTLSConfig set up the TLS config from config file. -func SetupTLSConfig(cfg *sarama.Config, tlsConfig *TLSConfig) error { - if tlsConfig != nil { - cfg.Net.TLS.Enable = true - tlsConfig, err := tls.NewTLSConfig( - tlsConfig.ClientCrt, - tlsConfig.ClientKey, - tlsConfig.CACrt, - []byte(tlsConfig.ClientKeyPwd), - tlsConfig.InsecureSkipVerify, - ) - if err != nil { - return err - } - cfg.Net.TLS.Config = tlsConfig - } - return nil -} - -// getEnvOrConfig returns the value of the environment variable if it exists, -// otherwise, it returns the value from the configuration file. -func getEnvOrConfig(envName string, configValue string) string { - if value, exists := os.LookupEnv(envName); exists { - return value - } - return configValue -} - -// getKafkaAddrFromEnv returns the Kafka addresses combined from the KAFKA_ADDRESS and KAFKA_PORT environment variables. -// If the environment variables are not set, it returns the fallback value. -func getKafkaAddrFromEnv(fallback []string) []string { - envAddr := os.Getenv("KAFKA_ADDRESS") - envPort := os.Getenv("KAFKA_PORT") - - if envAddr != "" && envPort != "" { - addresses := strings.Split(envAddr, ",") - for i, addr := range addresses { - addresses[i] = fmt.Sprintf("%s:%s", addr, envPort) - } - return addresses - } - - return fallback -} diff --git a/pkg/common/prommetrics/doc.go b/pkg/common/prommetrics/doc.go new file mode 100644 index 0000000000..c5108b4cba --- /dev/null +++ b/pkg/common/prommetrics/doc.go @@ -0,0 +1,15 @@ +// 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 prommetrics // import "github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics" diff --git a/pkg/common/prommetrics/prommetrics.go b/pkg/common/prommetrics/prommetrics.go index 9089e7b5fe..47e5d02b88 100644 --- a/pkg/common/prommetrics/prommetrics.go +++ b/pkg/common/prommetrics/prommetrics.go @@ -31,17 +31,17 @@ func NewGrpcPromObj(cusMetrics []prometheus.Collector) (*prometheus.Registry, *g return reg, grpcMetrics, nil } -func GetGrpcCusMetrics(registerName string, config *config2.GlobalConfig) []prometheus.Collector { +func GetGrpcCusMetrics(registerName string, share *config2.Share) []prometheus.Collector { switch registerName { - case config.RpcRegisterName.OpenImMessageGatewayName: + case share.RpcRegisterName.MessageGateway: return []prometheus.Collector{OnlineUserGauge} - case config.RpcRegisterName.OpenImMsgName: + case share.RpcRegisterName.Msg: return []prometheus.Collector{SingleChatMsgProcessSuccessCounter, SingleChatMsgProcessFailedCounter, GroupChatMsgProcessSuccessCounter, GroupChatMsgProcessFailedCounter} case "Transfer": return []prometheus.Collector{MsgInsertRedisSuccessCounter, MsgInsertRedisFailedCounter, MsgInsertMongoSuccessCounter, MsgInsertMongoFailedCounter, SeqSetFailedCounter} - case config.RpcRegisterName.OpenImPushName: + case share.RpcRegisterName.Push: return []prometheus.Collector{MsgOfflinePushFailedCounter} - case config.RpcRegisterName.OpenImAuthName: + case share.RpcRegisterName.Auth: return []prometheus.Collector{UserLoginCounter} default: return nil diff --git a/pkg/common/prommetrics/prommetrics_test.go b/pkg/common/prommetrics/prommetrics_test.go index eb6f3c7716..65b05652f7 100644 --- a/pkg/common/prommetrics/prommetrics_test.go +++ b/pkg/common/prommetrics/prommetrics_test.go @@ -19,8 +19,6 @@ import ( "github.com/prometheus/client_golang/prometheus" "github.com/stretchr/testify/assert" - - config2 "github.com/openimsdk/open-im-server/v3/pkg/common/config" ) func TestNewGrpcPromObj(t *testing.T) { @@ -57,22 +55,22 @@ func TestNewGrpcPromObj(t *testing.T) { assert.True(t, found, "Custom metric not found in registry") } -func TestGetGrpcCusMetrics(t *testing.T) { - conf := config2.NewGlobalConfig() - - config2.InitConfig(conf, "../../config") - // Test various cases based on the switch statement in the GetGrpcCusMetrics function. - testCases := []struct { - name string - expected int // The expected number of metrics for each case. - }{ - {conf.RpcRegisterName.OpenImMessageGatewayName, 1}, - } - - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - metrics := GetGrpcCusMetrics(tc.name, conf) - assert.Len(t, metrics, tc.expected) - }) - } -} +//func TestGetGrpcCusMetrics(t *testing.T) { +// conf := config2.NewGlobalConfig() +// +// config2.InitConfig(conf, "../../config") +// // Test various cases based on the switch statement in the GetGrpcCusMetrics function. +// testCases := []struct { +// name string +// expected int // The expected number of metrics for each case. +// }{ +// {conf.RpcRegisterName.OpenImMessageGatewayName, 1}, +// } +// +// for _, tc := range testCases { +// t.Run(tc.name, func(t *testing.T) { +// metrics := GetGrpcCusMetrics(tc.name, &conf.RpcRegisterName) +// assert.Len(t, metrics, tc.expected) +// }) +// } +//} diff --git a/pkg/common/redispubsub/doc.go b/pkg/common/redispubsub/doc.go new file mode 100644 index 0000000000..19b2e38f2e --- /dev/null +++ b/pkg/common/redispubsub/doc.go @@ -0,0 +1,15 @@ +// 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 redispubsub // import "github.com/openimsdk/open-im-server/v3/pkg/common/redispubsub" diff --git a/pkg/common/servererrs/code.go b/pkg/common/servererrs/code.go new file mode 100644 index 0000000000..3d0aa4a717 --- /dev/null +++ b/pkg/common/servererrs/code.go @@ -0,0 +1,95 @@ +// 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 servererrs + +// UnknownCode represents the error code when code is not parsed or parsed code equals 0. +const UnknownCode = 1000 + +// Error codes for various error scenarios. +const ( + FormattingError = 10001 // Error in formatting + HasRegistered = 10002 // user has already registered + NotRegistered = 10003 // user is not registered + PasswordErr = 10004 // Password error + GetIMTokenErr = 10005 // Error in getting IM token + RepeatSendCode = 10006 // Repeat sending code + MailSendCodeErr = 10007 // Error in sending code via email + SmsSendCodeErr = 10008 // Error in sending code via SMS + CodeInvalidOrExpired = 10009 // Code is invalid or expired + RegisterFailed = 10010 // Registration failed + ResetPasswordFailed = 10011 // Resetting password failed + RegisterLimit = 10012 // Registration limit exceeded + LoginLimit = 10013 // Login limit exceeded + InvitationError = 10014 // Error in invitation +) + +// General error codes. +const ( + NoError = 0 // No error + DatabaseError = 90002 // Database error (redis/mysql, etc.) + NetworkError = 90004 // Network error + DataError = 90007 // Data error + + CallbackError = 80000 + + // General error codes. + ServerInternalError = 500 // Server internal error + ArgsError = 1001 // Input parameter error + NoPermissionError = 1002 // Insufficient permission + DuplicateKeyError = 1003 + RecordNotFoundError = 1004 // Record does not exist + + // Account error codes. + UserIDNotFoundError = 1101 // UserID does not exist or is not registered + RegisteredAlreadyError = 1102 // user is already registered + + // Group error codes. + GroupIDNotFoundError = 1201 // GroupID does not exist + GroupIDExisted = 1202 // GroupID already exists + NotInGroupYetError = 1203 // Not in the group yet + DismissedAlreadyError = 1204 // Group has already been dismissed + GroupTypeNotSupport = 1205 + GroupRequestHandled = 1206 + + // Relationship error codes. + CanNotAddYourselfError = 1301 // Cannot add yourself as a friend + BlockedByPeer = 1302 // Blocked by the peer + NotPeersFriend = 1303 // Not the peer's friend + RelationshipAlreadyError = 1304 // Already in a friend relationship + + // Message error codes. + MessageHasReadDisable = 1401 + MutedInGroup = 1402 // Member muted in the group + MutedGroup = 1403 // Group is muted + MsgAlreadyRevoke = 1404 // Message already revoked + + // Token error codes. + TokenExpiredError = 1501 + TokenInvalidError = 1502 + TokenMalformedError = 1503 + TokenNotValidYetError = 1504 + TokenUnknownError = 1505 + TokenKickedError = 1506 + TokenNotExistError = 1507 + + // Long connection gateway error codes. + ConnOverMaxNumLimit = 1601 + ConnArgsErr = 1602 + PushMsgErr = 1603 + IOSBackgroundPushErr = 1604 + + // S3 error codes. + FileUploadedExpiredError = 1701 // Upload expired +) diff --git a/pkg/common/servererrs/doc.go b/pkg/common/servererrs/doc.go new file mode 100644 index 0000000000..d408a75146 --- /dev/null +++ b/pkg/common/servererrs/doc.go @@ -0,0 +1 @@ +package servererrs // import "github.com/openimsdk/open-im-server/v3/pkg/common/servererrs" diff --git a/pkg/common/servererrs/predefine.go b/pkg/common/servererrs/predefine.go new file mode 100644 index 0000000000..ab09aa5123 --- /dev/null +++ b/pkg/common/servererrs/predefine.go @@ -0,0 +1,68 @@ +// 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 servererrs + +import "github.com/openimsdk/tools/errs" + +var ( + ErrDatabase = errs.NewCodeError(DatabaseError, "DatabaseError") + ErrNetwork = errs.NewCodeError(NetworkError, "NetworkError") + ErrCallback = errs.NewCodeError(CallbackError, "CallbackError") + ErrCallbackContinue = errs.NewCodeError(CallbackError, "ErrCallbackContinue") + + ErrInternalServer = errs.NewCodeError(ServerInternalError, "ServerInternalError") + ErrArgs = errs.NewCodeError(ArgsError, "ArgsError") + ErrNoPermission = errs.NewCodeError(NoPermissionError, "NoPermissionError") + ErrDuplicateKey = errs.NewCodeError(DuplicateKeyError, "DuplicateKeyError") + ErrRecordNotFound = errs.NewCodeError(RecordNotFoundError, "RecordNotFoundError") + + ErrUserIDNotFound = errs.NewCodeError(UserIDNotFoundError, "UserIDNotFoundError") + ErrGroupIDNotFound = errs.NewCodeError(GroupIDNotFoundError, "GroupIDNotFoundError") + ErrGroupIDExisted = errs.NewCodeError(GroupIDExisted, "GroupIDExisted") + + ErrNotInGroupYet = errs.NewCodeError(NotInGroupYetError, "NotInGroupYetError") + ErrDismissedAlready = errs.NewCodeError(DismissedAlreadyError, "DismissedAlreadyError") + ErrRegisteredAlready = errs.NewCodeError(RegisteredAlreadyError, "RegisteredAlreadyError") + ErrGroupTypeNotSupport = errs.NewCodeError(GroupTypeNotSupport, "") + ErrGroupRequestHandled = errs.NewCodeError(GroupRequestHandled, "GroupRequestHandled") + + ErrData = errs.NewCodeError(DataError, "DataError") + ErrTokenExpired = errs.NewCodeError(TokenExpiredError, "TokenExpiredError") + ErrTokenInvalid = errs.NewCodeError(TokenInvalidError, "TokenInvalidError") // + ErrTokenMalformed = errs.NewCodeError(TokenMalformedError, "TokenMalformedError") // + ErrTokenNotValidYet = errs.NewCodeError(TokenNotValidYetError, "TokenNotValidYetError") // + ErrTokenUnknown = errs.NewCodeError(TokenUnknownError, "TokenUnknownError") // + ErrTokenKicked = errs.NewCodeError(TokenKickedError, "TokenKickedError") + ErrTokenNotExist = errs.NewCodeError(TokenNotExistError, "TokenNotExistError") // + + ErrMessageHasReadDisable = errs.NewCodeError(MessageHasReadDisable, "MessageHasReadDisable") + + ErrCanNotAddYourself = errs.NewCodeError(CanNotAddYourselfError, "CanNotAddYourselfError") + ErrBlockedByPeer = errs.NewCodeError(BlockedByPeer, "BlockedByPeer") + ErrNotPeersFriend = errs.NewCodeError(NotPeersFriend, "NotPeersFriend") + ErrRelationshipAlready = errs.NewCodeError(RelationshipAlreadyError, "RelationshipAlreadyError") + + ErrMutedInGroup = errs.NewCodeError(MutedInGroup, "MutedInGroup") + ErrMutedGroup = errs.NewCodeError(MutedGroup, "MutedGroup") + ErrMsgAlreadyRevoke = errs.NewCodeError(MsgAlreadyRevoke, "MsgAlreadyRevoke") + + ErrConnOverMaxNumLimit = errs.NewCodeError(ConnOverMaxNumLimit, "ConnOverMaxNumLimit") + + ErrConnArgsErr = errs.NewCodeError(ConnArgsErr, "args err, need token, sendID, platformID") + ErrPushMsgErr = errs.NewCodeError(PushMsgErr, "push msg err") + ErrIOSBackgroundPushErr = errs.NewCodeError(IOSBackgroundPushErr, "ios background push err") + + ErrFileUploadedExpired = errs.NewCodeError(FileUploadedExpiredError, "FileUploadedExpiredError") +) diff --git a/pkg/common/servererrs/relation.go b/pkg/common/servererrs/relation.go new file mode 100644 index 0000000000..62b0561471 --- /dev/null +++ b/pkg/common/servererrs/relation.go @@ -0,0 +1,58 @@ +// 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 servererrs + +import "github.com/openimsdk/tools/errs" + +var Relation = &relation{m: make(map[int]map[int]struct{})} + +func init() { + Relation.Add(errs.RecordNotFoundError, UserIDNotFoundError) + Relation.Add(errs.RecordNotFoundError, GroupIDNotFoundError) + Relation.Add(errs.DuplicateKeyError, GroupIDExisted) +} + +type relation struct { + m map[int]map[int]struct{} +} + +func (r *relation) Add(codes ...int) { + if len(codes) < 2 { + panic("codes length must be greater than 2") + } + for i := 1; i < len(codes); i++ { + parent := codes[i-1] + s, ok := r.m[parent] + if !ok { + s = make(map[int]struct{}) + r.m[parent] = s + } + for _, code := range codes[i:] { + s[code] = struct{}{} + } + } +} + +func (r *relation) Is(parent, child int) bool { + if parent == child { + return true + } + s, ok := r.m[parent] + if !ok { + return false + } + _, ok = s[child] + return ok +} diff --git a/pkg/common/startrpc/doc.go b/pkg/common/startrpc/doc.go index 206e7900f7..fce7309f42 100644 --- a/pkg/common/startrpc/doc.go +++ b/pkg/common/startrpc/doc.go @@ -1,4 +1,4 @@ -// Copyright © 2023 OpenIM. All rights reserved. +// 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. @@ -12,5 +12,4 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Package startrpc start rpc server. -package startrpc +package startrpc // import "github.com/openimsdk/open-im-server/v3/pkg/common/startrpc" diff --git a/pkg/common/startrpc/start.go b/pkg/common/startrpc/start.go index bf95509d11..ebcd5aa7cc 100644 --- a/pkg/common/startrpc/start.go +++ b/pkg/common/startrpc/start.go @@ -16,8 +16,10 @@ package startrpc import ( "context" - "errors" "fmt" + config2 "github.com/openimsdk/open-im-server/v3/pkg/common/config" + "github.com/openimsdk/tools/utils/datautil" + "github.com/prometheus/client_golang/prometheus" "net" "net/http" "os" @@ -27,59 +29,61 @@ import ( "syscall" "time" - "github.com/OpenIMSDK/tools/discoveryregistry" - "github.com/OpenIMSDK/tools/errs" - "github.com/OpenIMSDK/tools/mw" - "github.com/OpenIMSDK/tools/network" grpcprometheus "github.com/grpc-ecosystem/go-grpc-prometheus" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" - config2 "github.com/openimsdk/open-im-server/v3/pkg/common/config" kdisc "github.com/openimsdk/open-im-server/v3/pkg/common/discoveryregister" "github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics" - util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" - "github.com/prometheus/client_golang/prometheus" + "github.com/openimsdk/tools/discovery" + "github.com/openimsdk/tools/errs" + "github.com/openimsdk/tools/log" + "github.com/openimsdk/tools/mw" + "github.com/openimsdk/tools/system/program" + "github.com/openimsdk/tools/utils/network" "github.com/prometheus/client_golang/prometheus/promhttp" "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" ) // Start rpc server. -func Start( - rpcPort int, - rpcRegisterName string, - prometheusPort int, - config *config2.GlobalConfig, - rpcFn func(config *config.GlobalConfig, client discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) error, - options ...grpc.ServerOption, -) error { - fmt.Printf("start %s server, port: %d, prometheusPort: %d, OpenIM version: %s\n", - rpcRegisterName, rpcPort, prometheusPort, config2.Version) - rpcTcpAddr := net.JoinHostPort(network.GetListenIP(config.Rpc.ListenIP), strconv.Itoa(rpcPort)) +func Start[T any](ctx context.Context, zookeeperConfig *config2.ZooKeeper, prometheusConfig *config2.Prometheus, listenIP, + registerIP string, rpcPorts []int, index int, rpcRegisterName string, share *config2.Share, config T, rpcFn func(ctx context.Context, + config T, client discovery.SvcDiscoveryRegistry, server *grpc.Server) error, options ...grpc.ServerOption) error { + + rpcPort, err := datautil.GetElemByIndex(rpcPorts, index) + if err != nil { + return err + } + prometheusPort, err := datautil.GetElemByIndex(prometheusConfig.Ports, index) + if err != nil { + return err + } + log.CInfo(ctx, "RPC server is initializing", "rpcRegisterName", rpcRegisterName, "rpcPort", rpcPort, + "prometheusPort", prometheusPort) + rpcTcpAddr := net.JoinHostPort(network.GetListenIP(listenIP), strconv.Itoa(rpcPort)) listener, err := net.Listen( "tcp", rpcTcpAddr, ) if err != nil { - return errs.Wrap(err, "listen err", rpcTcpAddr) + return errs.WrapMsg(err, "listen err", "rpcTcpAddr", rpcTcpAddr) } defer listener.Close() - client, err := kdisc.NewDiscoveryRegister(config) + client, err := kdisc.NewDiscoveryRegister(zookeeperConfig, share) if err != nil { return err } defer client.Close() client.AddOption(mw.GrpcClient(), grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithDefaultServiceConfig(fmt.Sprintf(`{"LoadBalancingPolicy": "%s"}`, "round_robin"))) - registerIP, err := network.GetRpcRegisterIP(config.Rpc.RegisterIP) + registerIP, err = network.GetRpcRegisterIP(registerIP) if err != nil { - return errs.Wrap(err) + return err } var reg *prometheus.Registry var metric *grpcprometheus.ServerMetrics - if config.Prometheus.Enable { - cusMetrics := prommetrics.GetGrpcCusMetrics(rpcRegisterName, config) + if prometheusConfig.Enable { + cusMetrics := prommetrics.GetGrpcCusMetrics(rpcRegisterName, share) reg, metric, _ = prommetrics.NewGrpcPromObj(cusMetrics) options = append(options, mw.GrpcServer(), grpc.StreamInterceptor(metric.StreamServerInterceptor()), grpc.UnaryInterceptor(metric.UnaryServerInterceptor())) @@ -93,10 +97,11 @@ func Start( once.Do(srv.GracefulStop) }() - err = rpcFn(config, client, srv) + err = rpcFn(ctx, config, client, srv) if err != nil { return err } + err = client.Register( rpcRegisterName, registerIP, @@ -104,7 +109,7 @@ func Start( grpc.WithTransportCredentials(insecure.NewCredentials()), ) if err != nil { - return errs.Wrap(err) + return err } var ( @@ -112,13 +117,14 @@ func Start( netErr error httpServer *http.Server ) + go func() { - if config.Prometheus.Enable && prometheusPort != 0 { + if prometheusConfig.Enable && prometheusPort != 0 { metric.InitializeMetrics(srv) // Create a HTTP server for prometheus. httpServer = &http.Server{Handler: promhttp.HandlerFor(reg, promhttp.HandlerOpts{}), Addr: fmt.Sprintf("0.0.0.0:%d", prometheusPort)} if err := httpServer.ListenAndServe(); err != nil && err != http.ErrServerClosed { - netErr = errs.Wrap(err, "prometheus start err", httpServer.Addr) + netErr = errs.WrapMsg(err, "prometheus start err", httpServer.Addr) netDone <- struct{}{} } } @@ -127,7 +133,7 @@ func Start( go func() { err := srv.Serve(listener) if err != nil { - netErr = errs.Wrap(err, "rpc start err: ", rpcTcpAddr) + netErr = errs.WrapMsg(err, "rpc start err: ", rpcTcpAddr) netDone <- struct{}{} } }() @@ -136,7 +142,7 @@ func Start( signal.Notify(sigs, syscall.SIGTERM) select { case <-sigs: - util.SIGTERMExit() + program.SIGTERMExit() ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) defer cancel() if err := gracefulStopWithCtx(ctx, srv.GracefulStop); err != nil { @@ -146,7 +152,7 @@ func Start( defer cancel() err := httpServer.Shutdown(ctx) if err != nil { - return errs.Wrap(err, "shutdown err") + return errs.WrapMsg(err, "shutdown err") } return nil case <-netDone: @@ -163,7 +169,7 @@ func gracefulStopWithCtx(ctx context.Context, f func()) error { }() select { case <-ctx.Done(): - return errs.Wrap(errors.New("timeout, ctx graceful stop")) + return errs.New("timeout, ctx graceful stop") case <-done: return nil } diff --git a/pkg/common/startrpc/start_test.go b/pkg/common/startrpc/start_test.go deleted file mode 100644 index 754fc9c502..0000000000 --- a/pkg/common/startrpc/start_test.go +++ /dev/null @@ -1,69 +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 startrpc - -import ( - "fmt" - "net" - "testing" - "time" - - "github.com/openimsdk/open-im-server/v3/pkg/common/config" - - "github.com/OpenIMSDK/tools/discoveryregistry" - "google.golang.org/grpc" -) - -// mockRpcFn is a mock gRPC function for testing. -func mockRpcFn(config *config.GlobalConfig, client discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) error { - // Implement a mock gRPC service registration logic if needed - return nil -} - -// TestStart tests the Start function for starting the RPC server. -func TestStart(t *testing.T) { - // Use an available port for testing purposes. - testRpcPort := 12345 - testPrometheusPort := 12346 - testRpcRegisterName := "testService" - - doneChan := make(chan error, 1) - - go func() { - err := Start(testRpcPort, testRpcRegisterName, testPrometheusPort, - config.NewGlobalConfig(), mockRpcFn) - doneChan <- err - }() - - // Give some time for the server to start. - time.Sleep(2 * time.Second) - - // Test if the server is listening on the RPC port. - conn, err := net.Dial("tcp", fmt.Sprintf(":%d", testRpcPort)) - if err != nil { - // t.Fatalf("Failed to dial the RPC server: %v", err) - // TODO: Fix this test - t.Skip("Failed to dial the RPC server") - } - conn.Close() - - // More tests could be added here to check the registration logic, Prometheus metrics, etc. - - // Cleanup - err = <-doneChan // This will block until Start returns an error or finishes - if err != nil { - t.Fatalf("Start returned an error: %v", err) - } -} diff --git a/pkg/common/tls/tls.go b/pkg/common/tls/tls.go deleted file mode 100755 index 9666ed9c87..0000000000 --- a/pkg/common/tls/tls.go +++ /dev/null @@ -1,88 +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 tls - -import ( - "crypto/tls" - "crypto/x509" - "encoding/pem" - "errors" - "os" - - "github.com/OpenIMSDK/tools/errs" -) - -// decryptPEM decrypts a PEM block using a password. -func decryptPEM(data []byte, passphrase []byte) ([]byte, error) { - if len(passphrase) == 0 { - return data, nil - } - b, _ := pem.Decode(data) - d, err := x509.DecryptPEMBlock(b, passphrase) - if err != nil { - return nil, err - } - return pem.EncodeToMemory(&pem.Block{ - Type: b.Type, - Bytes: d, - }), nil -} - -func readEncryptablePEMBlock(path string, pwd []byte) ([]byte, error) { - data, err := os.ReadFile(path) - if err != nil { - return nil, err - } - return decryptPEM(data, pwd) -} - -// NewTLSConfig setup the TLS config from general config file. -func NewTLSConfig(clientCertFile, clientKeyFile, caCertFile string, keyPwd []byte, insecureSkipVerify bool) (*tls.Config, error) { - tlsConfig := tls.Config{} - - if clientCertFile != "" && clientKeyFile != "" { - certPEMBlock, err := os.ReadFile(clientCertFile) - if err != nil { - return nil, errs.Wrap(err, "NewTLSConfig: failed to read client cert file") - } - keyPEMBlock, err := readEncryptablePEMBlock(clientKeyFile, keyPwd) - if err != nil { - return nil, err - } - - cert, err := tls.X509KeyPair(certPEMBlock, keyPEMBlock) - if err != nil { - return nil, errs.Wrap(err, "NewTLSConfig: failed to create X509 key pair") - } - tlsConfig.Certificates = []tls.Certificate{cert} - } - - if caCertFile != "" { - caCert, err := os.ReadFile(caCertFile) - if err != nil { - return nil, errs.Wrap(err, "NewTLSConfig: failed to read CA cert file") - } - - caCertPool := x509.NewCertPool() - if ok := caCertPool.AppendCertsFromPEM(caCert); !ok { - return nil, errors.New("NewTLSConfig: not a valid CA cert") - } - tlsConfig.RootCAs = caCertPool - } - - tlsConfig.InsecureSkipVerify = insecureSkipVerify - - return &tlsConfig, nil -} diff --git a/pkg/common/version/base.go b/pkg/common/version/base.go deleted file mode 100644 index 9a656e03a4..0000000000 --- a/pkg/common/version/base.go +++ /dev/null @@ -1,61 +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 version - -// Base version information. -// -// This is the fallback data used when version information from git is not -// provided via go ldflags. It provides an approximation of the Kubernetes -// version for ad-hoc builds (e.g. `go build`) that cannot get the version -// information from git. -// -// If you are looking at these fields in the git tree, they look -// strange. They are modified on the fly by the build process. The -// in-tree values are dummy values used for "git archive", which also -// works for GitHub tar downloads. -// -// When releasing a new Kubernetes version, this file is updated by -// build/mark_new_version.sh to reflect the new version, and then a -// git annotated tag (using format vX.Y where X == Major version and Y -// == Minor version) is created to point to the commit that updates. -var ( - // TODO: Deprecate gitMajor and gitMinor, use only gitVersion - // instead. First step in deprecation, keep the fields but make - // them irrelevant. (Next we'll take it out, which may muck with - // scripts consuming the kubectl version output - but most of - // these should be looking at gitVersion already anyways.) - gitMajor string = "" // major version, always numeric - gitMinor string = "" // minor version, numeric possibly followed by "+" - - // semantic version, derived by build scripts (see - // https://github.com/kubernetes/sig-release/blob/master/release-engineering/versioning.md#kubernetes-release-versioning - // https://kubernetes.io/releases/version-skew-policy/ - // for a detailed discussion of this field) - // - // TODO: This field is still called "gitVersion" for legacy - // reasons. For prerelease versions, the build metadata on the - // semantic version is a git hash, but the version itself is no - // longer the direct output of "git describe", but a slight - // translation to be semver compliant. - - // NOTE: The $Format strings are replaced during 'git archive' thanks to the - // companion .gitattributes file containing 'export-subst' in this same - // directory. See also https://git-scm.com/docs/gitattributes - gitVersion string = "latest" - gitCommit string = "" // sha1 from git, output of $(git rev-parse HEAD) - gitTreeState string = "" // state of git tree, either "clean" or "dirty" - - buildDate string = "1970-01-01T00:00:00Z" // build date in ISO8601 format, output of $(date -u +'%Y-%m-%dT%H:%M:%SZ') -) diff --git a/pkg/common/version/types.go b/pkg/common/version/types.go deleted file mode 100644 index da9c1ed901..0000000000 --- a/pkg/common/version/types.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 version - -// Info contains versioning information. -// TODO: Add []string of api versions supported? It's still unclear -// how we'll want to distribute that information. -type Info struct { - Major string `json:"major,omitempty"` - Minor string `json:"minor,omitempty"` - GitVersion string `json:"gitVersion"` - GitTreeState string `json:"gitTreeState,omitempty"` - GitCommit string `json:"gitCommit,omitempty"` - BuildDate string `json:"buildDate"` - GoVersion string `json:"goVersion"` - Compiler string `json:"compiler"` - Platform string `json:"platform"` -} - -type Output struct { - OpenIMServerVersion Info `json:"OpenIMServerVersion,omitempty" yaml:"OpenIMServerVersion,omitempty"` - OpenIMClientVersion *OpenIMClientVersion `json:"OpenIMClientVersion,omitempty" yaml:"OpenIMClientVersion,omitempty"` -} - -type OpenIMClientVersion struct { - ClientVersion string `json:"clientVersion,omitempty" yaml:"clientVersion,omitempty"` //sdk core version -} - -// String returns info as a human-friendly version string. -func (info Info) String() string { - return info.GitVersion -} diff --git a/pkg/common/version/version.go b/pkg/common/version/version.go deleted file mode 100644 index 3b271b3f60..0000000000 --- a/pkg/common/version/version.go +++ /dev/null @@ -1,72 +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 version - -import ( - "fmt" - "runtime" - - "gopkg.in/src-d/go-git.v4" -) - -// Get returns the overall codebase version. It's for detecting -// what code a binary was built from. -func Get() Info { - // These variables typically come from -ldflags settings and in - // their absence fallback to the settings in ./base.go - return Info{ - Major: gitMajor, - Minor: gitMinor, - GitVersion: gitVersion, - GitTreeState: gitTreeState, - GitCommit: gitCommit, - BuildDate: buildDate, - GoVersion: runtime.Version(), - Compiler: runtime.Compiler, - Platform: fmt.Sprintf("%s/%s", runtime.GOOS, runtime.GOARCH), - } -} - -// GetClientVersion returns the git version of the OpenIM client repository. -func GetClientVersion() (*OpenIMClientVersion, error) { - clientVersion, err := getClientVersion() - if err != nil { - return nil, err - } - return &OpenIMClientVersion{ - ClientVersion: clientVersion, - }, nil -} - -func getClientVersion() (string, error) { - repo, err := git.PlainClone("/tmp/openim-sdk-core", false, &git.CloneOptions{ - URL: "https://github.com/OpenIMSDK/openim-sdk-core", - }) - if err != nil { - return "", fmt.Errorf("error cloning repository: %w", err) - } - - ref, err := repo.Head() - if err != nil { - return "", fmt.Errorf("error getting head reference: %w", err) - } - - return ref.Hash().String(), nil -} - -// GetSingleVersion returns single version of sealer. -func GetSingleVersion() string { - return gitVersion -} diff --git a/pkg/common/webhook/condition.go b/pkg/common/webhook/condition.go new file mode 100644 index 0000000000..2c038f5674 --- /dev/null +++ b/pkg/common/webhook/condition.go @@ -0,0 +1,13 @@ +package webhook + +import ( + "context" + "github.com/openimsdk/open-im-server/v3/pkg/common/config" +) + +func WithCondition(ctx context.Context, before *config.BeforeConfig, callback func(context.Context) error) error { + if !before.Enable { + return nil + } + return callback(ctx) +} diff --git a/pkg/common/db/s3/cont/doc.go b/pkg/common/webhook/doc.go similarity index 80% rename from pkg/common/db/s3/cont/doc.go rename to pkg/common/webhook/doc.go index 45737bc7c9..3a8e3e622c 100644 --- a/pkg/common/db/s3/cont/doc.go +++ b/pkg/common/webhook/doc.go @@ -1,4 +1,4 @@ -// Copyright © 2023 OpenIM. All rights reserved. +// 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. @@ -12,4 +12,4 @@ // See the License for the specific language governing permissions and // limitations under the License. -package cont // import "github.com/openimsdk/open-im-server/v3/pkg/common/db/s3/cont" +package webhook // import "github.com/openimsdk/open-im-server/v3/pkg/common/webhook" diff --git a/pkg/common/webhook/http_client.go b/pkg/common/webhook/http_client.go new file mode 100644 index 0000000000..e46f08806d --- /dev/null +++ b/pkg/common/webhook/http_client.go @@ -0,0 +1,86 @@ +// 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 webhook + +import ( + "context" + "encoding/json" + "github.com/openimsdk/open-im-server/v3/pkg/callbackstruct" + "github.com/openimsdk/open-im-server/v3/pkg/common/config" + "github.com/openimsdk/open-im-server/v3/pkg/common/servererrs" + "github.com/openimsdk/protocol/constant" + "github.com/openimsdk/tools/log" + "github.com/openimsdk/tools/mcontext" + "github.com/openimsdk/tools/mq/memamq" + "github.com/openimsdk/tools/utils/httputil" + "net/http" +) + +type Client struct { + client *httputil.HTTPClient + url string + queue *memamq.MemoryQueue +} + +const ( + webhookWorkerCount = 2 + webhookBufferSize = 100 +) + +func NewWebhookClient(url string, options ...*memamq.MemoryQueue) *Client { + var queue *memamq.MemoryQueue + if len(options) > 0 && options[0] != nil { + queue = options[0] + } else { + queue = memamq.NewMemoryQueue(webhookWorkerCount, webhookBufferSize) + } + + http.DefaultTransport.(*http.Transport).MaxConnsPerHost = 100 // Enhance the default number of max connections per host + + return &Client{ + client: httputil.NewHTTPClient(httputil.NewClientConfig()), + url: url, + queue: queue, + } +} + +func (c *Client) SyncPost(ctx context.Context, command string, req callbackstruct.CallbackReq, resp callbackstruct.CallbackResp, before *config.BeforeConfig) error { + return c.post(ctx, command, req, resp, before.Timeout) +} + +func (c *Client) AsyncPost(ctx context.Context, command string, req callbackstruct.CallbackReq, resp callbackstruct.CallbackResp, after *config.AfterConfig) { + if after.Enable { + c.queue.Push(func() { c.post(ctx, command, req, resp, after.Timeout) }) + } +} + +func (c *Client) post(ctx context.Context, command string, input interface{}, output callbackstruct.CallbackResp, timeout int) error { + ctx = mcontext.WithMustInfoCtx([]string{mcontext.GetOperationID(ctx), mcontext.GetOpUserID(ctx), mcontext.GetOpUserPlatform(ctx), mcontext.GetConnID(ctx)}) + fullURL := c.url + "/" + command + log.ZInfo(ctx, "webhook", "url", fullURL, "input", input, "config", timeout) + operationID, _ := ctx.Value(constant.OperationID).(string) + b, err := c.client.Post(ctx, fullURL, map[string]string{constant.OperationID: operationID}, input, timeout) + if err != nil { + return servererrs.ErrNetwork.WrapMsg(err.Error(), "post url", fullURL) + } + if err = json.Unmarshal(b, output); err != nil { + return servererrs.ErrData.WithDetail(err.Error() + " response format error") + } + if err := output.Parse(); err != nil { + return err + } + log.ZInfo(ctx, "webhook success", "url", fullURL, "input", input, "response", string(b)) + return nil +} diff --git a/internal/rpc/statistics/statistics.go b/pkg/common/webhook/http_client_test.go similarity index 96% rename from internal/rpc/statistics/statistics.go rename to pkg/common/webhook/http_client_test.go index 2f81301a15..3c3aeb809d 100644 --- a/internal/rpc/statistics/statistics.go +++ b/pkg/common/webhook/http_client_test.go @@ -12,4 +12,4 @@ // See the License for the specific language governing permissions and // limitations under the License. -package statistics +package webhook diff --git a/pkg/localcache/doc.go b/pkg/localcache/doc.go new file mode 100644 index 0000000000..24d44b090d --- /dev/null +++ b/pkg/localcache/doc.go @@ -0,0 +1,15 @@ +// 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 localcache // import "github.com/openimsdk/open-im-server/v3/pkg/localcache" diff --git a/pkg/localcache/go.sum b/pkg/localcache/go.sum new file mode 100644 index 0000000000..b1d8cf8c44 --- /dev/null +++ b/pkg/localcache/go.sum @@ -0,0 +1 @@ +github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= diff --git a/pkg/localcache/link/doc.go b/pkg/localcache/link/doc.go new file mode 100644 index 0000000000..e01e7d23dd --- /dev/null +++ b/pkg/localcache/link/doc.go @@ -0,0 +1,15 @@ +// 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 link // import "github.com/openimsdk/open-im-server/v3/pkg/localcache/link" diff --git a/pkg/common/kafka/doc.go b/pkg/localcache/lru/doc.go similarity index 80% rename from pkg/common/kafka/doc.go rename to pkg/localcache/lru/doc.go index 0f0c69a76b..50edcc11b1 100644 --- a/pkg/common/kafka/doc.go +++ b/pkg/localcache/lru/doc.go @@ -1,4 +1,4 @@ -// Copyright © 2023 OpenIM. All rights reserved. +// 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. @@ -12,4 +12,4 @@ // See the License for the specific language governing permissions and // limitations under the License. -package kafka // import "github.com/openimsdk/open-im-server/v3/pkg/common/kafka" +package lru // import "github.com/openimsdk/open-im-server/v3/pkg/localcache/lru" diff --git a/pkg/localcache/lru/lru_lazy_test.go b/pkg/localcache/lru/lru_lazy_test.go index 167dd2135b..ab0fa50a07 100644 --- a/pkg/localcache/lru/lru_lazy_test.go +++ b/pkg/localcache/lru/lru_lazy_test.go @@ -92,12 +92,7 @@ func TestName(t *testing.T) { defer wg.Done() //t.Log(key) fn(key, 10000, func() (string, error) { - //time.Sleep(time.Second * 3) - //t.Log(time.Now(), "key", key, "fetch") - //if rand.Uint32()%5 == 0 { - // return "value_" + key, nil - //} - //return "", errors.New("rand error") + return "value_" + key, nil }) }() diff --git a/pkg/msgprocessor/conversation.go b/pkg/msgprocessor/conversation.go index e3ea89fadd..b369269cc8 100644 --- a/pkg/msgprocessor/conversation.go +++ b/pkg/msgprocessor/conversation.go @@ -18,9 +18,9 @@ import ( "sort" "strings" - "github.com/OpenIMSDK/protocol/constant" - "github.com/OpenIMSDK/protocol/sdkws" - "github.com/OpenIMSDK/tools/errs" + "github.com/openimsdk/protocol/constant" + "github.com/openimsdk/protocol/sdkws" + "github.com/openimsdk/tools/errs" "google.golang.org/protobuf/proto" ) @@ -30,9 +30,9 @@ func GetNotificationConversationIDByMsg(msg *sdkws.MsgData) string { l := []string{msg.SendID, msg.RecvID} sort.Strings(l) return "n_" + strings.Join(l, "_") - case constant.GroupChatType: + case constant.WriteGroupChatType: return "n_" + msg.GroupID - case constant.SuperGroupChatType: + case constant.ReadGroupChatType: return "n_" + msg.GroupID case constant.NotificationChatType: return "n_" + msg.SendID + "_" + msg.RecvID @@ -46,9 +46,9 @@ func GetChatConversationIDByMsg(msg *sdkws.MsgData) string { l := []string{msg.SendID, msg.RecvID} sort.Strings(l) return "si_" + strings.Join(l, "_") - case constant.GroupChatType: + case constant.WriteGroupChatType: return "g_" + msg.GroupID - case constant.SuperGroupChatType: + case constant.ReadGroupChatType: return "sg_" + msg.GroupID case constant.NotificationChatType: return "sn_" + msg.SendID + "_" + msg.RecvID @@ -63,7 +63,7 @@ func GenConversationUniqueKey(msg *sdkws.MsgData) string { l := []string{msg.SendID, msg.RecvID} sort.Strings(l) return strings.Join(l, "_") - case constant.SuperGroupChatType: + case constant.ReadGroupChatType: return msg.GroupID } return "" @@ -79,12 +79,12 @@ func GetConversationIDByMsg(msg *sdkws.MsgData) string { return "n_" + strings.Join(l, "_") } return "si_" + strings.Join(l, "_") // single chat - case constant.GroupChatType: + case constant.WriteGroupChatType: if !options.IsNotNotification() { return "n_" + msg.GroupID // group chat } return "g_" + msg.GroupID // group chat - case constant.SuperGroupChatType: + case constant.ReadGroupChatType: if !options.IsNotNotification() { return "n_" + msg.GroupID // super group chat } @@ -106,9 +106,9 @@ func GetConversationIDBySessionType(sessionType int, ids ...string) string { switch sessionType { case constant.SingleChatType: return "si_" + strings.Join(ids, "_") // single chat - case constant.GroupChatType: + case constant.WriteGroupChatType: return "g_" + ids[0] // group chat - case constant.SuperGroupChatType: + case constant.ReadGroupChatType: return "sg_" + ids[0] // super group chat case constant.NotificationChatType: return "sn_" + ids[0] // server notification chat @@ -134,7 +134,7 @@ func GetNotificationConversationID(sessionType int, ids ...string) string { switch sessionType { case constant.SingleChatType: return "n_" + strings.Join(ids, "_") // single chat - case constant.SuperGroupChatType: + case constant.ReadGroupChatType: return "n_" + ids[0] // super group chat } return "" @@ -158,7 +158,7 @@ func ParseConversationID(msg *sdkws.MsgData) (isNotification bool, conversationI return true, "n_" + strings.Join(l, "_") } return false, "si_" + strings.Join(l, "_") // single chat - case constant.SuperGroupChatType: + case constant.ReadGroupChatType: if !options.IsNotNotification() { return true, "n_" + msg.GroupID // super group chat } diff --git a/pkg/msgprocessor/conversation_test.go b/pkg/msgprocessor/conversation_test.go index c3fdb459d8..32601baec4 100644 --- a/pkg/msgprocessor/conversation_test.go +++ b/pkg/msgprocessor/conversation_test.go @@ -17,7 +17,7 @@ package msgprocessor import ( "testing" - "github.com/OpenIMSDK/protocol/sdkws" + "github.com/openimsdk/protocol/sdkws" "google.golang.org/protobuf/proto" ) diff --git a/pkg/msgprocessor/doc.go b/pkg/msgprocessor/doc.go index d1e24ce305..e8c96befb2 100644 --- a/pkg/msgprocessor/doc.go +++ b/pkg/msgprocessor/doc.go @@ -1,4 +1,4 @@ -// Copyright © 2023 OpenIM. All rights reserved. +// 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. diff --git a/pkg/msgprocessor/options.go b/pkg/msgprocessor/options.go index c6e209b987..406145ef46 100644 --- a/pkg/msgprocessor/options.go +++ b/pkg/msgprocessor/options.go @@ -14,7 +14,7 @@ package msgprocessor -import "github.com/OpenIMSDK/protocol/constant" +import "github.com/openimsdk/protocol/constant" type ( Options map[string]bool diff --git a/pkg/rpccache/conversation.go b/pkg/rpccache/conversation.go index 027ef42fa6..196657b4b3 100644 --- a/pkg/rpccache/conversation.go +++ b/pkg/rpccache/conversation.go @@ -17,18 +17,18 @@ package rpccache import ( "context" - pbconversation "github.com/OpenIMSDK/protocol/conversation" - "github.com/OpenIMSDK/tools/errs" - "github.com/OpenIMSDK/tools/log" "github.com/openimsdk/localcache" "github.com/openimsdk/open-im-server/v3/pkg/common/cachekey" "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" + pbconversation "github.com/openimsdk/protocol/conversation" + "github.com/openimsdk/tools/errs" + "github.com/openimsdk/tools/log" "github.com/redis/go-redis/v9" ) -func NewConversationLocalCache(client rpcclient.ConversationRpcClient, cli redis.UniversalClient) *ConversationLocalCache { - lc := config.Config.LocalCache.Conversation +func NewConversationLocalCache(client rpcclient.ConversationRpcClient, localCache *config.LocalCache, cli redis.UniversalClient) *ConversationLocalCache { + lc := localCache.Conversation log.ZDebug(context.Background(), "ConversationLocalCache", "topic", lc.Topic, "slotNum", lc.SlotNum, "slotSize", lc.SlotSize, "enable", lc.Enable()) x := &ConversationLocalCache{ client: client, diff --git a/pkg/common/http/doc.go b/pkg/rpccache/doc.go similarity index 81% rename from pkg/common/http/doc.go rename to pkg/rpccache/doc.go index e6fd3ec1ee..4244bb239a 100644 --- a/pkg/common/http/doc.go +++ b/pkg/rpccache/doc.go @@ -1,4 +1,4 @@ -// Copyright © 2023 OpenIM. All rights reserved. +// 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. @@ -12,4 +12,4 @@ // See the License for the specific language governing permissions and // limitations under the License. -package http // import "github.com/openimsdk/open-im-server/v3/pkg/common/http" +package rpccache // import "github.com/openimsdk/open-im-server/v3/pkg/rpccache" diff --git a/pkg/rpccache/friend.go b/pkg/rpccache/friend.go index 35122fff5a..557b5cffc0 100644 --- a/pkg/rpccache/friend.go +++ b/pkg/rpccache/friend.go @@ -17,16 +17,16 @@ package rpccache import ( "context" - "github.com/OpenIMSDK/tools/log" "github.com/openimsdk/localcache" "github.com/openimsdk/open-im-server/v3/pkg/common/cachekey" "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" + "github.com/openimsdk/tools/log" "github.com/redis/go-redis/v9" ) -func NewFriendLocalCache(client rpcclient.FriendRpcClient, cli redis.UniversalClient) *FriendLocalCache { - lc := config.Config.LocalCache.Friend +func NewFriendLocalCache(client rpcclient.FriendRpcClient, localCache *config.LocalCache, cli redis.UniversalClient) *FriendLocalCache { + lc := localCache.Friend log.ZDebug(context.Background(), "FriendLocalCache", "topic", lc.Topic, "slotNum", lc.SlotNum, "slotSize", lc.SlotSize, "enable", lc.Enable()) x := &FriendLocalCache{ client: client, diff --git a/pkg/rpccache/group.go b/pkg/rpccache/group.go index 402f63185e..daf76a7a01 100644 --- a/pkg/rpccache/group.go +++ b/pkg/rpccache/group.go @@ -17,18 +17,18 @@ package rpccache import ( "context" - "github.com/OpenIMSDK/protocol/sdkws" - "github.com/OpenIMSDK/tools/errs" - "github.com/OpenIMSDK/tools/log" "github.com/openimsdk/localcache" "github.com/openimsdk/open-im-server/v3/pkg/common/cachekey" "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" + "github.com/openimsdk/protocol/sdkws" + "github.com/openimsdk/tools/errs" + "github.com/openimsdk/tools/log" "github.com/redis/go-redis/v9" ) -func NewGroupLocalCache(client rpcclient.GroupRpcClient, cli redis.UniversalClient) *GroupLocalCache { - lc := config.Config.LocalCache.Group +func NewGroupLocalCache(client rpcclient.GroupRpcClient, localCache *config.LocalCache, cli redis.UniversalClient) *GroupLocalCache { + lc := localCache.Group log.ZDebug(context.Background(), "GroupLocalCache", "topic", lc.Topic, "slotNum", lc.SlotNum, "slotSize", lc.SlotSize, "enable", lc.Enable()) x := &GroupLocalCache{ client: client, diff --git a/pkg/rpccache/subscriber.go b/pkg/rpccache/subscriber.go index cd65094e2b..3046f84b11 100644 --- a/pkg/rpccache/subscriber.go +++ b/pkg/rpccache/subscriber.go @@ -18,7 +18,7 @@ import ( "context" "encoding/json" - "github.com/OpenIMSDK/tools/log" + "github.com/openimsdk/tools/log" "github.com/redis/go-redis/v9" ) diff --git a/pkg/rpccache/user.go b/pkg/rpccache/user.go index c48b058214..b31f187dba 100644 --- a/pkg/rpccache/user.go +++ b/pkg/rpccache/user.go @@ -17,18 +17,18 @@ package rpccache import ( "context" - "github.com/OpenIMSDK/protocol/sdkws" - "github.com/OpenIMSDK/tools/errs" - "github.com/OpenIMSDK/tools/log" "github.com/openimsdk/localcache" "github.com/openimsdk/open-im-server/v3/pkg/common/cachekey" "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" + "github.com/openimsdk/protocol/sdkws" + "github.com/openimsdk/tools/errs" + "github.com/openimsdk/tools/log" "github.com/redis/go-redis/v9" ) -func NewUserLocalCache(client rpcclient.UserRpcClient, cli redis.UniversalClient) *UserLocalCache { - lc := config.Config.LocalCache.User +func NewUserLocalCache(client rpcclient.UserRpcClient, localCache *config.LocalCache, cli redis.UniversalClient) *UserLocalCache { + lc := localCache.User log.ZDebug(context.Background(), "UserLocalCache", "topic", lc.Topic, "slotNum", lc.SlotNum, "slotSize", lc.SlotSize, "enable", lc.Enable()) x := &UserLocalCache{ client: client, diff --git a/pkg/rpcclient/auth.go b/pkg/rpcclient/auth.go index 24597120fd..6665936bdd 100644 --- a/pkg/rpcclient/auth.go +++ b/pkg/rpcclient/auth.go @@ -16,26 +16,48 @@ package rpcclient import ( "context" - - "github.com/OpenIMSDK/protocol/auth" - "github.com/OpenIMSDK/tools/discoveryregistry" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" - util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" + "github.com/openimsdk/protocol/auth" + pbAuth "github.com/openimsdk/protocol/auth" + "github.com/openimsdk/tools/discovery" + "github.com/openimsdk/tools/system/program" "google.golang.org/grpc" ) -func NewAuth(discov discoveryregistry.SvcDiscoveryRegistry, config *config.GlobalConfig) *Auth { - conn, err := discov.GetConn(context.Background(), config.RpcRegisterName.OpenImAuthName) +func NewAuth(discov discovery.SvcDiscoveryRegistry, rpcRegisterName string) *Auth { + conn, err := discov.GetConn(context.Background(), rpcRegisterName) if err != nil { - util.ExitWithError(err) + program.ExitWithError(err) } client := auth.NewAuthClient(conn) - return &Auth{discov: discov, conn: conn, Client: client, Config: config} + return &Auth{discov: discov, conn: conn, Client: client} } type Auth struct { conn grpc.ClientConnInterface Client auth.AuthClient - discov discoveryregistry.SvcDiscoveryRegistry - Config *config.GlobalConfig + discov discovery.SvcDiscoveryRegistry +} + +func (a *Auth) ParseToken(ctx context.Context, token string) (*pbAuth.ParseTokenResp, error) { + req := pbAuth.ParseTokenReq{ + Token: token, + } + resp, err := a.Client.ParseToken(ctx, &req) + if err != nil { + return nil, err + } + return resp, err +} + +func (a *Auth) InvalidateToken(ctx context.Context, preservedToken, userID string, platformID int) (*pbAuth.InvalidateTokenResp, error) { + req := pbAuth.InvalidateTokenReq{ + PreservedToken: preservedToken, + UserID: userID, + PlatformID: int32(platformID), + } + resp, err := a.Client.InvalidateToken(ctx, &req) + if err != nil { + return nil, err + } + return resp, err } diff --git a/pkg/rpcclient/conversation.go b/pkg/rpcclient/conversation.go index 127e029e16..6eb6c94612 100644 --- a/pkg/rpcclient/conversation.go +++ b/pkg/rpcclient/conversation.go @@ -18,34 +18,32 @@ import ( "context" "fmt" - pbconversation "github.com/OpenIMSDK/protocol/conversation" - "github.com/OpenIMSDK/tools/discoveryregistry" - "github.com/OpenIMSDK/tools/errs" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" - util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" + pbconversation "github.com/openimsdk/protocol/conversation" + "github.com/openimsdk/tools/discovery" + "github.com/openimsdk/tools/errs" + "github.com/openimsdk/tools/system/program" "google.golang.org/grpc" ) type Conversation struct { Client pbconversation.ConversationClient conn grpc.ClientConnInterface - discov discoveryregistry.SvcDiscoveryRegistry - Config *config.GlobalConfig + discov discovery.SvcDiscoveryRegistry } -func NewConversation(discov discoveryregistry.SvcDiscoveryRegistry, config *config.GlobalConfig) *Conversation { - conn, err := discov.GetConn(context.Background(), config.RpcRegisterName.OpenImConversationName) +func NewConversation(discov discovery.SvcDiscoveryRegistry, rpcRegisterName string) *Conversation { + conn, err := discov.GetConn(context.Background(), rpcRegisterName) if err != nil { - util.ExitWithError(err) + program.ExitWithError(err) } client := pbconversation.NewConversationClient(conn) - return &Conversation{discov: discov, conn: conn, Client: client, Config: config} + return &Conversation{discov: discov, conn: conn, Client: client} } type ConversationRpcClient Conversation -func NewConversationRpcClient(discov discoveryregistry.SvcDiscoveryRegistry, config *config.GlobalConfig) ConversationRpcClient { - return ConversationRpcClient(*NewConversation(discov, config)) +func NewConversationRpcClient(discov discovery.SvcDiscoveryRegistry, rpcRegisterName string) ConversationRpcClient { + return ConversationRpcClient(*NewConversation(discov, rpcRegisterName)) } func (c *ConversationRpcClient) GetSingleConversationRecvMsgOpt(ctx context.Context, userID, conversationID string) (int32, error) { @@ -109,7 +107,7 @@ func (c *ConversationRpcClient) GetConversationsByConversationID(ctx context.Con return nil, err } if len(resp.Conversations) == 0 { - return nil, errs.ErrRecordNotFound.Wrap(fmt.Sprintf("conversationIDs: %v not found", conversationIDs)) + return nil, errs.ErrRecordNotFound.WrapMsg(fmt.Sprintf("conversationIDs: %v not found", conversationIDs)) } return resp.Conversations, nil } diff --git a/pkg/rpcclient/doc.go b/pkg/rpcclient/doc.go index 0fdfacc60a..66b0aee91d 100644 --- a/pkg/rpcclient/doc.go +++ b/pkg/rpcclient/doc.go @@ -1,4 +1,4 @@ -// Copyright © 2023 OpenIM. All rights reserved. +// 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. diff --git a/pkg/rpcclient/friend.go b/pkg/rpcclient/friend.go index 5a5f38698d..5543afe4f7 100644 --- a/pkg/rpcclient/friend.go +++ b/pkg/rpcclient/friend.go @@ -17,34 +17,32 @@ package rpcclient import ( "context" - "github.com/OpenIMSDK/protocol/friend" - sdkws "github.com/OpenIMSDK/protocol/sdkws" - "github.com/OpenIMSDK/tools/discoveryregistry" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" - util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" + "github.com/openimsdk/protocol/friend" + sdkws "github.com/openimsdk/protocol/sdkws" + "github.com/openimsdk/tools/discovery" + "github.com/openimsdk/tools/system/program" "google.golang.org/grpc" ) type Friend struct { conn grpc.ClientConnInterface Client friend.FriendClient - discov discoveryregistry.SvcDiscoveryRegistry - Config *config.GlobalConfig + discov discovery.SvcDiscoveryRegistry } -func NewFriend(discov discoveryregistry.SvcDiscoveryRegistry, config *config.GlobalConfig) *Friend { - conn, err := discov.GetConn(context.Background(), config.RpcRegisterName.OpenImFriendName) +func NewFriend(discov discovery.SvcDiscoveryRegistry, rpcRegisterName string) *Friend { + conn, err := discov.GetConn(context.Background(), rpcRegisterName) if err != nil { - util.ExitWithError(err) + program.ExitWithError(err) } client := friend.NewFriendClient(conn) - return &Friend{discov: discov, conn: conn, Client: client, Config: config} + return &Friend{discov: discov, conn: conn, Client: client} } type FriendRpcClient Friend -func NewFriendRpcClient(discov discoveryregistry.SvcDiscoveryRegistry, config *config.GlobalConfig) FriendRpcClient { - return FriendRpcClient(*NewFriend(discov, config)) +func NewFriendRpcClient(discov discovery.SvcDiscoveryRegistry, rpcRegisterName string) FriendRpcClient { + return FriendRpcClient(*NewFriend(discov, rpcRegisterName)) } func (f *FriendRpcClient) GetFriendsInfo( diff --git a/pkg/rpcclient/group.go b/pkg/rpcclient/group.go index 3e9c93e7a4..30d0b3288f 100644 --- a/pkg/rpcclient/group.go +++ b/pkg/rpcclient/group.go @@ -18,35 +18,33 @@ import ( "context" "strings" - "github.com/OpenIMSDK/protocol/constant" - "github.com/OpenIMSDK/protocol/group" - "github.com/OpenIMSDK/protocol/sdkws" - "github.com/OpenIMSDK/tools/discoveryregistry" - "github.com/OpenIMSDK/tools/errs" - "github.com/OpenIMSDK/tools/utils" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" - util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" + "github.com/openimsdk/open-im-server/v3/pkg/common/servererrs" + "github.com/openimsdk/protocol/constant" + "github.com/openimsdk/protocol/group" + "github.com/openimsdk/protocol/sdkws" + "github.com/openimsdk/tools/discovery" + "github.com/openimsdk/tools/system/program" + "github.com/openimsdk/tools/utils/datautil" ) type Group struct { Client group.GroupClient - discov discoveryregistry.SvcDiscoveryRegistry - Config *config.GlobalConfig + discov discovery.SvcDiscoveryRegistry } -func NewGroup(discov discoveryregistry.SvcDiscoveryRegistry, config *config.GlobalConfig) *Group { - conn, err := discov.GetConn(context.Background(), config.RpcRegisterName.OpenImGroupName) +func NewGroup(discov discovery.SvcDiscoveryRegistry, rpcRegisterName string) *Group { + conn, err := discov.GetConn(context.Background(), rpcRegisterName) if err != nil { - util.ExitWithError(err) + program.ExitWithError(err) } client := group.NewGroupClient(conn) - return &Group{discov: discov, Client: client, Config: config} + return &Group{discov: discov, Client: client} } type GroupRpcClient Group -func NewGroupRpcClient(discov discoveryregistry.SvcDiscoveryRegistry, config *config.GlobalConfig) GroupRpcClient { - return GroupRpcClient(*NewGroup(discov, config)) +func NewGroupRpcClient(discov discovery.SvcDiscoveryRegistry, rpcRegisterName string) GroupRpcClient { + return GroupRpcClient(*NewGroup(discov, rpcRegisterName)) } func (g *GroupRpcClient) GetGroupInfos(ctx context.Context, groupIDs []string, complete bool) ([]*sdkws.GroupInfo, error) { @@ -57,10 +55,10 @@ func (g *GroupRpcClient) GetGroupInfos(ctx context.Context, groupIDs []string, c return nil, err } if complete { - if ids := utils.Single(groupIDs, utils.Slice(resp.GroupInfos, func(e *sdkws.GroupInfo) string { + if ids := datautil.Single(groupIDs, datautil.Slice(resp.GroupInfos, func(e *sdkws.GroupInfo) string { return e.GroupID })); len(ids) > 0 { - return nil, errs.ErrGroupIDNotFound.Wrap(strings.Join(ids, ",")) + return nil, servererrs.ErrGroupIDNotFound.WrapMsg(strings.Join(ids, ",")) } } return resp.GroupInfos, nil @@ -83,7 +81,7 @@ func (g *GroupRpcClient) GetGroupInfoMap( if err != nil { return nil, err } - return utils.SliceToMap(groups, func(e *sdkws.GroupInfo) string { + return datautil.SliceToMap(groups, func(e *sdkws.GroupInfo) string { return e.GroupID }), nil } @@ -102,10 +100,10 @@ func (g *GroupRpcClient) GetGroupMemberInfos( return nil, err } if complete { - if ids := utils.Single(userIDs, utils.Slice(resp.Members, func(e *sdkws.GroupMemberFullInfo) string { + if ids := datautil.Single(userIDs, datautil.Slice(resp.Members, func(e *sdkws.GroupMemberFullInfo) string { return e.UserID })); len(ids) > 0 { - return nil, errs.ErrNotInGroupYet.Wrap(strings.Join(ids, ",")) + return nil, servererrs.ErrNotInGroupYet.WrapMsg(strings.Join(ids, ",")) } } return resp.Members, nil @@ -133,7 +131,7 @@ func (g *GroupRpcClient) GetGroupMemberInfoMap( if err != nil { return nil, err } - return utils.SliceToMap(members, func(e *sdkws.GroupMemberFullInfo) string { + return datautil.SliceToMap(members, func(e *sdkws.GroupMemberFullInfo) string { return e.UserID }), nil } diff --git a/pkg/rpcclient/grouphash/doc.go b/pkg/rpcclient/grouphash/doc.go new file mode 100644 index 0000000000..c780701d9a --- /dev/null +++ b/pkg/rpcclient/grouphash/doc.go @@ -0,0 +1,15 @@ +// 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 grouphash // import "github.com/openimsdk/open-im-server/v3/pkg/rpcclient/grouphash" diff --git a/pkg/rpcclient/grouphash/grouphash.go b/pkg/rpcclient/grouphash/grouphash.go index dee47ad44e..5015b88c8f 100644 --- a/pkg/rpcclient/grouphash/grouphash.go +++ b/pkg/rpcclient/grouphash/grouphash.go @@ -20,9 +20,9 @@ import ( "encoding/binary" "encoding/json" - "github.com/OpenIMSDK/protocol/group" - "github.com/OpenIMSDK/protocol/sdkws" - "github.com/OpenIMSDK/tools/utils" + "github.com/openimsdk/protocol/group" + "github.com/openimsdk/protocol/sdkws" + "github.com/openimsdk/tools/utils/datautil" ) func NewGroupHashFromGroupClient(x group.GroupClient) *GroupHash { @@ -79,9 +79,9 @@ func (gh *GroupHash) GetGroupHash(ctx context.Context, groupID string) (uint64, if err != nil { return 0, err } - utils.Sort(userIDs, true) + datautil.Sort(userIDs, true) } - memberMap := utils.SliceToMap(members, func(e *sdkws.GroupMemberFullInfo) string { + memberMap := datautil.SliceToMap(members, func(e *sdkws.GroupMemberFullInfo) string { return e.UserID }) res := make([]*sdkws.GroupMemberFullInfo, 0, len(members)) diff --git a/pkg/rpcclient/msg.go b/pkg/rpcclient/msg.go index 54a4671a3d..36daf9f66b 100644 --- a/pkg/rpcclient/msg.go +++ b/pkg/rpcclient/msg.go @@ -17,62 +17,64 @@ package rpcclient import ( "context" "encoding/json" - "fmt" - - "github.com/OpenIMSDK/protocol/constant" - "github.com/OpenIMSDK/protocol/msg" - "github.com/OpenIMSDK/protocol/sdkws" - "github.com/OpenIMSDK/tools/discoveryregistry" - "github.com/OpenIMSDK/tools/errs" - "github.com/OpenIMSDK/tools/log" - "github.com/OpenIMSDK/tools/utils" "github.com/openimsdk/open-im-server/v3/pkg/common/config" - util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" + "github.com/openimsdk/protocol/constant" + "github.com/openimsdk/protocol/msg" + "github.com/openimsdk/protocol/sdkws" + "github.com/openimsdk/tools/discovery" + "github.com/openimsdk/tools/log" + "github.com/openimsdk/tools/mcontext" + "github.com/openimsdk/tools/mq/memamq" + "github.com/openimsdk/tools/system/program" + "github.com/openimsdk/tools/utils/idutil" + "github.com/openimsdk/tools/utils/jsonutil" + "github.com/openimsdk/tools/utils/timeutil" "google.golang.org/grpc" "google.golang.org/protobuf/proto" + "time" ) -func newContentTypeConf(conf *config.GlobalConfig) map[int32]config.NotificationConf { - return map[int32]config.NotificationConf{ +func newContentTypeConf(conf *config.Notification) map[int32]config.NotificationConfig { + return map[int32]config.NotificationConfig{ // group - constant.GroupCreatedNotification: conf.Notification.GroupCreated, - constant.GroupInfoSetNotification: conf.Notification.GroupInfoSet, - constant.JoinGroupApplicationNotification: conf.Notification.JoinGroupApplication, - constant.MemberQuitNotification: conf.Notification.MemberQuit, - constant.GroupApplicationAcceptedNotification: conf.Notification.GroupApplicationAccepted, - constant.GroupApplicationRejectedNotification: conf.Notification.GroupApplicationRejected, - constant.GroupOwnerTransferredNotification: conf.Notification.GroupOwnerTransferred, - constant.MemberKickedNotification: conf.Notification.MemberKicked, - constant.MemberInvitedNotification: conf.Notification.MemberInvited, - constant.MemberEnterNotification: conf.Notification.MemberEnter, - constant.GroupDismissedNotification: conf.Notification.GroupDismissed, - constant.GroupMutedNotification: conf.Notification.GroupMuted, - constant.GroupCancelMutedNotification: conf.Notification.GroupCancelMuted, - constant.GroupMemberMutedNotification: conf.Notification.GroupMemberMuted, - constant.GroupMemberCancelMutedNotification: conf.Notification.GroupMemberCancelMuted, - constant.GroupMemberInfoSetNotification: conf.Notification.GroupMemberInfoSet, - constant.GroupMemberSetToAdminNotification: conf.Notification.GroupMemberSetToAdmin, - constant.GroupMemberSetToOrdinaryUserNotification: conf.Notification.GroupMemberSetToOrdinary, - constant.GroupInfoSetAnnouncementNotification: conf.Notification.GroupInfoSetAnnouncement, - constant.GroupInfoSetNameNotification: conf.Notification.GroupInfoSetName, + constant.GroupCreatedNotification: conf.GroupCreated, + constant.GroupInfoSetNotification: conf.GroupInfoSet, + constant.JoinGroupApplicationNotification: conf.JoinGroupApplication, + constant.MemberQuitNotification: conf.MemberQuit, + constant.GroupApplicationAcceptedNotification: conf.GroupApplicationAccepted, + constant.GroupApplicationRejectedNotification: conf.GroupApplicationRejected, + constant.GroupOwnerTransferredNotification: conf.GroupOwnerTransferred, + constant.MemberKickedNotification: conf.MemberKicked, + constant.MemberInvitedNotification: conf.MemberInvited, + constant.MemberEnterNotification: conf.MemberEnter, + constant.GroupDismissedNotification: conf.GroupDismissed, + constant.GroupMutedNotification: conf.GroupMuted, + constant.GroupCancelMutedNotification: conf.GroupCancelMuted, + constant.GroupMemberMutedNotification: conf.GroupMemberMuted, + constant.GroupMemberCancelMutedNotification: conf.GroupMemberCancelMuted, + constant.GroupMemberInfoSetNotification: conf.GroupMemberInfoSet, + constant.GroupMemberSetToAdminNotification: conf.GroupMemberSetToAdmin, + constant.GroupMemberSetToOrdinaryUserNotification: conf.GroupMemberSetToOrdinary, + constant.GroupInfoSetAnnouncementNotification: conf.GroupInfoSetAnnouncement, + constant.GroupInfoSetNameNotification: conf.GroupInfoSetName, // user - constant.UserInfoUpdatedNotification: conf.Notification.UserInfoUpdated, - constant.UserStatusChangeNotification: conf.Notification.UserStatusChanged, + constant.UserInfoUpdatedNotification: conf.UserInfoUpdated, + constant.UserStatusChangeNotification: conf.UserStatusChanged, // friend - constant.FriendApplicationNotification: conf.Notification.FriendApplicationAdded, - constant.FriendApplicationApprovedNotification: conf.Notification.FriendApplicationApproved, - constant.FriendApplicationRejectedNotification: conf.Notification.FriendApplicationRejected, - constant.FriendAddedNotification: conf.Notification.FriendAdded, - constant.FriendDeletedNotification: conf.Notification.FriendDeleted, - constant.FriendRemarkSetNotification: conf.Notification.FriendRemarkSet, - constant.BlackAddedNotification: conf.Notification.BlackAdded, - constant.BlackDeletedNotification: conf.Notification.BlackDeleted, - constant.FriendInfoUpdatedNotification: conf.Notification.FriendInfoUpdated, - constant.FriendsInfoUpdateNotification: conf.Notification.FriendInfoUpdated, //use the same FriendInfoUpdated + constant.FriendApplicationNotification: conf.FriendApplicationAdded, + constant.FriendApplicationApprovedNotification: conf.FriendApplicationApproved, + constant.FriendApplicationRejectedNotification: conf.FriendApplicationRejected, + constant.FriendAddedNotification: conf.FriendAdded, + constant.FriendDeletedNotification: conf.FriendDeleted, + constant.FriendRemarkSetNotification: conf.FriendRemarkSet, + constant.BlackAddedNotification: conf.BlackAdded, + constant.BlackDeletedNotification: conf.BlackDeleted, + constant.FriendInfoUpdatedNotification: conf.FriendInfoUpdated, + constant.FriendsInfoUpdateNotification: conf.FriendInfoUpdated, // use the same FriendInfoUpdated // conversation - constant.ConversationChangeNotification: conf.Notification.ConversationChanged, - constant.ConversationUnreadNotification: conf.Notification.ConversationChanged, - constant.ConversationPrivateChatNotification: conf.Notification.ConversationSetPrivate, + constant.ConversationChangeNotification: conf.ConversationChanged, + constant.ConversationUnreadNotification: conf.ConversationChanged, + constant.ConversationPrivateChatNotification: conf.ConversationSetPrivate, // msg constant.MsgRevokeNotification: {IsSendMsg: false, ReliabilityLevel: constant.ReliableNotificationNoMsg}, constant.HasReadReceipt: {IsSendMsg: false, ReliabilityLevel: constant.ReliableNotificationNoMsg}, @@ -83,26 +85,26 @@ func newContentTypeConf(conf *config.GlobalConfig) map[int32]config.Notification func newSessionTypeConf() map[int32]int32 { return map[int32]int32{ // group - constant.GroupCreatedNotification: constant.SuperGroupChatType, - constant.GroupInfoSetNotification: constant.SuperGroupChatType, + constant.GroupCreatedNotification: constant.ReadGroupChatType, + constant.GroupInfoSetNotification: constant.ReadGroupChatType, constant.JoinGroupApplicationNotification: constant.SingleChatType, - constant.MemberQuitNotification: constant.SuperGroupChatType, + constant.MemberQuitNotification: constant.ReadGroupChatType, constant.GroupApplicationAcceptedNotification: constant.SingleChatType, constant.GroupApplicationRejectedNotification: constant.SingleChatType, - constant.GroupOwnerTransferredNotification: constant.SuperGroupChatType, - constant.MemberKickedNotification: constant.SuperGroupChatType, - constant.MemberInvitedNotification: constant.SuperGroupChatType, - constant.MemberEnterNotification: constant.SuperGroupChatType, - constant.GroupDismissedNotification: constant.SuperGroupChatType, - constant.GroupMutedNotification: constant.SuperGroupChatType, - constant.GroupCancelMutedNotification: constant.SuperGroupChatType, - constant.GroupMemberMutedNotification: constant.SuperGroupChatType, - constant.GroupMemberCancelMutedNotification: constant.SuperGroupChatType, - constant.GroupMemberInfoSetNotification: constant.SuperGroupChatType, - constant.GroupMemberSetToAdminNotification: constant.SuperGroupChatType, - constant.GroupMemberSetToOrdinaryUserNotification: constant.SuperGroupChatType, - constant.GroupInfoSetAnnouncementNotification: constant.SuperGroupChatType, - constant.GroupInfoSetNameNotification: constant.SuperGroupChatType, + constant.GroupOwnerTransferredNotification: constant.ReadGroupChatType, + constant.MemberKickedNotification: constant.ReadGroupChatType, + constant.MemberInvitedNotification: constant.ReadGroupChatType, + constant.MemberEnterNotification: constant.ReadGroupChatType, + constant.GroupDismissedNotification: constant.ReadGroupChatType, + constant.GroupMutedNotification: constant.ReadGroupChatType, + constant.GroupCancelMutedNotification: constant.ReadGroupChatType, + constant.GroupMemberMutedNotification: constant.ReadGroupChatType, + constant.GroupMemberCancelMutedNotification: constant.ReadGroupChatType, + constant.GroupMemberInfoSetNotification: constant.ReadGroupChatType, + constant.GroupMemberSetToAdminNotification: constant.ReadGroupChatType, + constant.GroupMemberSetToOrdinaryUserNotification: constant.ReadGroupChatType, + constant.GroupInfoSetAnnouncementNotification: constant.ReadGroupChatType, + constant.GroupInfoSetNameNotification: constant.ReadGroupChatType, // user constant.UserInfoUpdatedNotification: constant.SingleChatType, constant.UserStatusChangeNotification: constant.SingleChatType, @@ -129,23 +131,22 @@ func newSessionTypeConf() map[int32]int32 { type Message struct { conn grpc.ClientConnInterface Client msg.MsgClient - discov discoveryregistry.SvcDiscoveryRegistry - Config *config.GlobalConfig + discov discovery.SvcDiscoveryRegistry } -func NewMessage(discov discoveryregistry.SvcDiscoveryRegistry, config *config.GlobalConfig) *Message { - conn, err := discov.GetConn(context.Background(), config.RpcRegisterName.OpenImMsgName) +func NewMessage(discov discovery.SvcDiscoveryRegistry, rpcRegisterName string) *Message { + conn, err := discov.GetConn(context.Background(), rpcRegisterName) if err != nil { - util.ExitWithError(err) + program.ExitWithError(err) } client := msg.NewMsgClient(conn) - return &Message{discov: discov, conn: conn, Client: client, Config: config} + return &Message{discov: discov, conn: conn, Client: client} } type MessageRpcClient Message -func NewMessageRpcClient(discov discoveryregistry.SvcDiscoveryRegistry, config *config.GlobalConfig) MessageRpcClient { - return MessageRpcClient(*NewMessage(discov, config)) +func NewMessageRpcClient(discov discovery.SvcDiscoveryRegistry, rpcRegisterName string) MessageRpcClient { + return MessageRpcClient(*NewMessage(discov, rpcRegisterName)) } // SendMsg sends a message through the gRPC client and returns the response. @@ -212,10 +213,17 @@ func (m *MessageRpcClient) GetConversationMaxSeq(ctx context.Context, conversati } type NotificationSender struct { - contentTypeConf map[int32]config.NotificationConf + contentTypeConf map[int32]config.NotificationConfig sessionTypeConf map[int32]int32 sendMsg func(ctx context.Context, req *msg.SendMsgReq) (*msg.SendMsgResp, error) getUserInfo func(ctx context.Context, userID string) (*sdkws.UserInfo, error) + queue *memamq.MemoryQueue +} + +func WithQueue(queue *memamq.MemoryQueue) NotificationSenderOptions { + return func(s *NotificationSender) { + s.queue = queue + } } type NotificationSenderOptions func(*NotificationSender) @@ -238,11 +246,19 @@ func WithUserRpcClient(userRpcClient *UserRpcClient) NotificationSenderOptions { } } -func NewNotificationSender(config *config.GlobalConfig, opts ...NotificationSenderOptions) *NotificationSender { - notificationSender := &NotificationSender{contentTypeConf: newContentTypeConf(config), sessionTypeConf: newSessionTypeConf()} +const ( + notificationWorkerCount = 2 + notificationBufferSize = 200 +) + +func NewNotificationSender(conf *config.Notification, opts ...NotificationSenderOptions) *NotificationSender { + notificationSender := &NotificationSender{contentTypeConf: newContentTypeConf(conf), sessionTypeConf: newSessionTypeConf()} for _, opt := range opts { opt(notificationSender) } + if notificationSender.queue == nil { + notificationSender.queue = memamq.NewMemoryQueue(notificationWorkerCount, notificationBufferSize) + } return notificationSender } @@ -258,12 +274,15 @@ func WithRpcGetUserName() NotificationOptions { } } -func (s *NotificationSender) NotificationWithSesstionType(ctx context.Context, sendID, recvID string, contentType, sesstionType int32, m proto.Message, opts ...NotificationOptions) (err error) { - n := sdkws.NotificationElem{Detail: utils.StructToJsonString(m)} +func (s *NotificationSender) send(ctx context.Context, sendID, recvID string, contentType, sessionType int32, m proto.Message, opts ...NotificationOptions) { + ctx = mcontext.WithMustInfoCtx([]string{mcontext.GetOperationID(ctx), mcontext.GetOpUserID(ctx), mcontext.GetOpUserPlatform(ctx), mcontext.GetConnID(ctx)}) + ctx, cancel := context.WithTimeout(ctx, time.Second*time.Duration(5)) + defer cancel() + n := sdkws.NotificationElem{Detail: jsonutil.StructToJsonString(m)} content, err := json.Marshal(&n) if err != nil { - errInfo := fmt.Sprintf("MsgClient Notification json.Marshal failed, sendID:%s, recvID:%s, contentType:%d, msg:%s", sendID, recvID, contentType, m) - return errs.Wrap(err, errInfo) + log.ZWarn(ctx, "json.Marshal failed", err, "sendID", sendID, "recvID", recvID, "contentType", contentType, "msg", jsonutil.StructToJsonString(m)) + return } notificationOpt := ¬ificationOpt{} for _, opt := range opts { @@ -275,26 +294,24 @@ func (s *NotificationSender) NotificationWithSesstionType(ctx context.Context, s if notificationOpt.WithRpcGetUsername && s.getUserInfo != nil { userInfo, err = s.getUserInfo(ctx, sendID) if err != nil { - errInfo := fmt.Sprintf("getUserInfo failed, sendID:%s", sendID) - return errs.Wrap(err, errInfo) - } else { - msg.SenderNickname = userInfo.Nickname - msg.SenderFaceURL = userInfo.FaceURL + log.ZWarn(ctx, "getUserInfo failed", err, "sendID", sendID) + return } + msg.SenderNickname = userInfo.Nickname + msg.SenderFaceURL = userInfo.FaceURL } var offlineInfo sdkws.OfflinePushInfo - var title, desc, ex string msg.SendID = sendID msg.RecvID = recvID msg.Content = content msg.MsgFrom = constant.SysMsgType msg.ContentType = contentType - msg.SessionType = sesstionType - if msg.SessionType == constant.SuperGroupChatType { + msg.SessionType = sessionType + if msg.SessionType == constant.ReadGroupChatType { msg.GroupID = recvID } - msg.CreateTime = utils.GetCurrentTimestampByMill() - msg.ClientMsgID = utils.GetMsgID(sendID) + msg.CreateTime = timeutil.GetCurrentTimestampByMill() + msg.ClientMsgID = idutil.GetMsgIDByMD5(sendID) optionsConfig := s.contentTypeConf[contentType] if sendID == recvID && contentType == constant.HasReadReceipt { optionsConfig.ReliabilityLevel = constant.UnreliableNotification @@ -302,21 +319,20 @@ func (s *NotificationSender) NotificationWithSesstionType(ctx context.Context, s options := config.GetOptionsByNotification(optionsConfig) s.SetOptionsByContentType(ctx, options, contentType) msg.Options = options - offlineInfo.Title = title - offlineInfo.Desc = desc - offlineInfo.Ex = ex msg.OfflinePushInfo = &offlineInfo req.MsgData = &msg _, err = s.sendMsg(ctx, &req) if err != nil { - errInfo := fmt.Sprintf("MsgClient Notification SendMsg failed, req:%s", &req) - return errs.Wrap(err, errInfo) + log.ZWarn(ctx, "SendMsg failed", err, "req", req.String()) } - return err } -func (s *NotificationSender) Notification(ctx context.Context, sendID, recvID string, contentType int32, m proto.Message, opts ...NotificationOptions) error { - return s.NotificationWithSesstionType(ctx, sendID, recvID, contentType, s.sessionTypeConf[contentType], m, opts...) +func (s *NotificationSender) NotificationWithSessionType(ctx context.Context, sendID, recvID string, contentType, sessionType int32, m proto.Message, opts ...NotificationOptions) { + s.queue.Push(func() { s.send(ctx, sendID, recvID, contentType, sessionType, m, opts...) }) +} + +func (s *NotificationSender) Notification(ctx context.Context, sendID, recvID string, contentType int32, m proto.Message, opts ...NotificationOptions) { + s.NotificationWithSessionType(ctx, sendID, recvID, contentType, s.sessionTypeConf[contentType], m, opts...) } func (s *NotificationSender) SetOptionsByContentType(_ context.Context, options map[string]bool, contentType int32) { diff --git a/pkg/rpcclient/notification/doc.go b/pkg/rpcclient/notification/doc.go index 2d409bdc94..8ce57ca4e8 100644 --- a/pkg/rpcclient/notification/doc.go +++ b/pkg/rpcclient/notification/doc.go @@ -1,4 +1,4 @@ -// Copyright © 2023 OpenIM. All rights reserved. +// 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. diff --git a/pkg/rpcclient/push.go b/pkg/rpcclient/push.go index c0aa9efa4c..c549e454a7 100644 --- a/pkg/rpcclient/push.go +++ b/pkg/rpcclient/push.go @@ -17,23 +17,22 @@ package rpcclient import ( "context" - "github.com/OpenIMSDK/protocol/push" - "github.com/OpenIMSDK/tools/discoveryregistry" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" - util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" + "github.com/openimsdk/protocol/push" + "github.com/openimsdk/tools/discovery" + "github.com/openimsdk/tools/system/program" "google.golang.org/grpc" ) type Push struct { conn grpc.ClientConnInterface Client push.PushMsgServiceClient - discov discoveryregistry.SvcDiscoveryRegistry + discov discovery.SvcDiscoveryRegistry } -func NewPush(discov discoveryregistry.SvcDiscoveryRegistry, config *config.GlobalConfig) *Push { - conn, err := discov.GetConn(context.Background(), config.RpcRegisterName.OpenImPushName) +func NewPush(discov discovery.SvcDiscoveryRegistry, rpcRegisterName string) *Push { + conn, err := discov.GetConn(context.Background(), rpcRegisterName) if err != nil { - util.ExitWithError(err) + program.ExitWithError(err) } return &Push{ discov: discov, @@ -44,8 +43,8 @@ func NewPush(discov discoveryregistry.SvcDiscoveryRegistry, config *config.Globa type PushRpcClient Push -func NewPushRpcClient(discov discoveryregistry.SvcDiscoveryRegistry, config *config.GlobalConfig) PushRpcClient { - return PushRpcClient(*NewPush(discov, config)) +func NewPushRpcClient(discov discovery.SvcDiscoveryRegistry, rpcRegisterName string) PushRpcClient { + return PushRpcClient(*NewPush(discov, rpcRegisterName)) } func (p *PushRpcClient) DelUserPushToken(ctx context.Context, req *push.DelUserPushTokenReq) (*push.DelUserPushTokenResp, error) { diff --git a/pkg/rpcclient/third.go b/pkg/rpcclient/third.go index a1f8ae180a..4c71dff6ad 100644 --- a/pkg/rpcclient/third.go +++ b/pkg/rpcclient/third.go @@ -16,58 +16,28 @@ package rpcclient import ( "context" - "net/url" - "github.com/OpenIMSDK/protocol/third" - "github.com/OpenIMSDK/tools/discoveryregistry" - "github.com/OpenIMSDK/tools/errs" - "github.com/minio/minio-go/v7" - "github.com/minio/minio-go/v7/pkg/credentials" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" - util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" + "github.com/openimsdk/protocol/third" + "github.com/openimsdk/tools/discovery" + "github.com/openimsdk/tools/system/program" "google.golang.org/grpc" ) type Third struct { - conn grpc.ClientConnInterface - Client third.ThirdClient - discov discoveryregistry.SvcDiscoveryRegistry - MinioClient *minio.Client - Config *config.GlobalConfig + conn grpc.ClientConnInterface + Client third.ThirdClient + discov discovery.SvcDiscoveryRegistry + GrafanaUrl string } -func NewThird(discov discoveryregistry.SvcDiscoveryRegistry, config *config.GlobalConfig) *Third { - conn, err := discov.GetConn(context.Background(), config.RpcRegisterName.OpenImThirdName) +func NewThird(discov discovery.SvcDiscoveryRegistry, rpcRegisterName, grafanaUrl string) *Third { + conn, err := discov.GetConn(context.Background(), rpcRegisterName) if err != nil { - util.ExitWithError(err) + program.ExitWithError(err) } client := third.NewThirdClient(conn) - minioClient, err := minioInit(config) if err != nil { - util.ExitWithError(err) + program.ExitWithError(err) } - return &Third{discov: discov, Client: client, conn: conn, MinioClient: minioClient, Config: config} -} - -func minioInit(config *config.GlobalConfig) (*minio.Client, error) { - minioClient := &minio.Client{} - initUrl := config.Object.Minio.Endpoint - minioUrl, err := url.Parse(initUrl) - if err != nil { - return nil, errs.Wrap(err, "minioInit: failed to parse MinIO endpoint URL") - } - opts := &minio.Options{ - Creds: credentials.NewStaticV4(config.Object.Minio.AccessKeyID, config.Object.Minio.SecretAccessKey, ""), - // Region: config.Credential.Minio.Location, - } - if minioUrl.Scheme == "http" { - opts.Secure = false - } else if minioUrl.Scheme == "https" { - opts.Secure = true - } - minioClient, err = minio.New(minioUrl.Host, opts) - if err != nil { - return nil, errs.Wrap(err, "minioInit: failed to create MinIO client") - } - return minioClient, nil + return &Third{discov: discov, Client: client, conn: conn, GrafanaUrl: grafanaUrl} } diff --git a/pkg/rpcclient/user.go b/pkg/rpcclient/user.go index 08ad41dc1a..aab96603eb 100644 --- a/pkg/rpcclient/user.go +++ b/pkg/rpcclient/user.go @@ -18,33 +18,37 @@ import ( "context" "strings" - "github.com/OpenIMSDK/protocol/sdkws" - "github.com/OpenIMSDK/protocol/user" - "github.com/OpenIMSDK/tools/discoveryregistry" - "github.com/OpenIMSDK/tools/errs" - "github.com/OpenIMSDK/tools/utils" "github.com/openimsdk/open-im-server/v3/pkg/authverify" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" - util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" + "github.com/openimsdk/open-im-server/v3/pkg/common/servererrs" + "github.com/openimsdk/protocol/sdkws" + "github.com/openimsdk/protocol/user" + "github.com/openimsdk/tools/discovery" + "github.com/openimsdk/tools/system/program" + "github.com/openimsdk/tools/utils/datautil" "google.golang.org/grpc" ) // User represents a structure holding connection details for the User RPC client. type User struct { - conn grpc.ClientConnInterface - Client user.UserClient - Discov discoveryregistry.SvcDiscoveryRegistry - Config *config.GlobalConfig + conn grpc.ClientConnInterface + Client user.UserClient + Discov discovery.SvcDiscoveryRegistry + MessageGateWayRpcName string + imAdminUserID []string } // NewUser initializes and returns a User instance based on the provided service discovery registry. -func NewUser(discov discoveryregistry.SvcDiscoveryRegistry, config *config.GlobalConfig) *User { - conn, err := discov.GetConn(context.Background(), config.RpcRegisterName.OpenImUserName) +func NewUser(discov discovery.SvcDiscoveryRegistry, rpcRegisterName, messageGateWayRpcName string, + imAdminUserID []string) *User { + conn, err := discov.GetConn(context.Background(), rpcRegisterName) if err != nil { - util.ExitWithError(err) + program.ExitWithError(err) } client := user.NewUserClient(conn) - return &User{Discov: discov, Client: client, conn: conn, Config: config} + return &User{Discov: discov, Client: client, + conn: conn, + MessageGateWayRpcName: messageGateWayRpcName, + imAdminUserID: imAdminUserID} } // UserRpcClient represents the structure for a User RPC client. @@ -57,8 +61,9 @@ func NewUserRpcClientByUser(user *User) *UserRpcClient { } // NewUserRpcClient initializes a UserRpcClient based on the provided service discovery registry. -func NewUserRpcClient(client discoveryregistry.SvcDiscoveryRegistry, config *config.GlobalConfig) UserRpcClient { - return UserRpcClient(*NewUser(client, config)) +func NewUserRpcClient(client discovery.SvcDiscoveryRegistry, rpcRegisterName string, + imAdminUserID []string) UserRpcClient { + return UserRpcClient(*NewUser(client, rpcRegisterName, "", imAdminUserID)) } // GetUsersInfo retrieves information for multiple users based on their user IDs. @@ -72,10 +77,10 @@ func (u *UserRpcClient) GetUsersInfo(ctx context.Context, userIDs []string) ([]* if err != nil { return nil, err } - if ids := utils.Single(userIDs, utils.Slice(resp.UsersInfo, func(e *sdkws.UserInfo) string { + if ids := datautil.Single(userIDs, datautil.Slice(resp.UsersInfo, func(e *sdkws.UserInfo) string { return e.UserID })); len(ids) > 0 { - return nil, errs.ErrUserIDNotFound.Wrap(strings.Join(ids, ",")) + return nil, servererrs.ErrUserIDNotFound.WrapMsg(strings.Join(ids, ",")) } return resp.UsersInfo, nil } @@ -95,7 +100,7 @@ func (u *UserRpcClient) GetUsersInfoMap(ctx context.Context, userIDs []string) ( if err != nil { return nil, err } - return utils.SliceToMap(users, func(e *sdkws.UserInfo) string { + return datautil.SliceToMap(users, func(e *sdkws.UserInfo) string { return e.UserID }), nil } @@ -110,7 +115,7 @@ func (u *UserRpcClient) GetPublicUserInfos( if err != nil { return nil, err } - return utils.Slice(users, func(e *sdkws.UserInfo) *sdkws.PublicUserInfo { + return datautil.Slice(users, func(e *sdkws.UserInfo) *sdkws.PublicUserInfo { return &sdkws.PublicUserInfo{ UserID: e.UserID, Nickname: e.Nickname, @@ -139,7 +144,7 @@ func (u *UserRpcClient) GetPublicUserInfoMap( if err != nil { return nil, err } - return utils.SliceToMap(users, func(e *sdkws.PublicUserInfo) string { + return datautil.SliceToMap(users, func(e *sdkws.PublicUserInfo) string { return e.UserID }), nil } @@ -161,7 +166,7 @@ func (u *UserRpcClient) Access(ctx context.Context, ownerUserID string) error { if err != nil { return err } - return authverify.CheckAccessV3(ctx, ownerUserID, u.Config) + return authverify.CheckAccessV3(ctx, ownerUserID, u.imAdminUserID) } // GetAllUserIDs retrieves all user IDs with pagination options. diff --git a/pkg/statistics/doc.go b/pkg/statistics/doc.go index 8051c4c719..7b02631dc0 100644 --- a/pkg/statistics/doc.go +++ b/pkg/statistics/doc.go @@ -1,4 +1,4 @@ -// Copyright © 2023 OpenIM. All rights reserved. +// 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. diff --git a/pkg/statistics/statistics.go b/pkg/statistics/statistics.go index 6dfc8155c2..222fd5cbdd 100644 --- a/pkg/statistics/statistics.go +++ b/pkg/statistics/statistics.go @@ -18,7 +18,7 @@ import ( "context" "time" - "github.com/OpenIMSDK/tools/log" + "github.com/openimsdk/tools/log" ) type Statistics struct { diff --git a/pkg/util/conversationutil/conversationutil.go b/pkg/util/conversationutil/conversationutil.go new file mode 100644 index 0000000000..5683d8df89 --- /dev/null +++ b/pkg/util/conversationutil/conversationutil.go @@ -0,0 +1,46 @@ +package conversationutil + +import ( + "sort" + "strings" +) + +func GenConversationIDForSingle(sendID, recvID string) string { + l := []string{sendID, recvID} + sort.Strings(l) + return "si_" + strings.Join(l, "_") +} + +func GenConversationUniqueKeyForGroup(groupID string) string { + return groupID +} + +func GenGroupConversationID(groupID string) string { + return "sg_" + groupID +} + +func GenConversationUniqueKeyForSingle(sendID, recvID string) string { + l := []string{sendID, recvID} + sort.Strings(l) + return strings.Join(l, "_") +} + +func GetNotificationConversationIDByConversationID(conversationID string) string { + l := strings.Split(conversationID, "_") + if len(l) > 1 { + l[0] = "n" + return strings.Join(l, "_") + } + return "" +} + +func GetSelfNotificationConversationID(userID string) string { + return "n_" + userID + "_" + userID +} + +func GetSeqsBeginEnd(seqs []int64) (int64, int64) { + if len(seqs) == 0 { + return 0, 0 + } + return seqs[0], seqs[len(seqs)-1] +} diff --git a/pkg/util/conversationutil/doc.go b/pkg/util/conversationutil/doc.go new file mode 100644 index 0000000000..90325ccb00 --- /dev/null +++ b/pkg/util/conversationutil/doc.go @@ -0,0 +1 @@ +package conversationutil // import "github.com/openimsdk/open-im-server/v3/pkg/util/conversationutil" diff --git a/pkg/util/flag/flag.go b/pkg/util/flag/flag.go deleted file mode 100644 index 0a8e527ab7..0000000000 --- a/pkg/util/flag/flag.go +++ /dev/null @@ -1,54 +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 flag - -import ( - "flag" - "log" - "strings" - - "github.com/spf13/pflag" -) - -// WordSepNormalizeFunc changes all flags that contain "_" separators. -func WordSepNormalizeFunc(f *pflag.FlagSet, name string) pflag.NormalizedName { - if strings.Contains(name, "_") { - return pflag.NormalizedName(strings.ReplaceAll(name, "_", "-")) - } - return pflag.NormalizedName(name) -} - -// WarnWordSepNormalizeFunc changes and warns for flags that contain "_" separators. -func WarnWordSepNormalizeFunc(f *pflag.FlagSet, name string) pflag.NormalizedName { - if strings.Contains(name, "_") { - normalizedName := strings.ReplaceAll(name, "_", "-") - log.Printf("WARNING: flag %s has been deprecated and will be removed in a future version. Use %s instead.", name, normalizedName) - return pflag.NormalizedName(normalizedName) - } - return pflag.NormalizedName(name) -} - -// InitFlags normalizes, parses, then logs the command line flags. -func InitFlags() { - pflag.CommandLine.SetNormalizeFunc(WordSepNormalizeFunc) - pflag.CommandLine.AddGoFlagSet(flag.CommandLine) -} - -// PrintFlags logs the flags in the flagset. -func PrintFlags(flags *pflag.FlagSet) { - flags.VisitAll(func(flag *pflag.Flag) { - log.Printf("FLAG: --%s=%q", flag.Name, flag.Value) - }) -} diff --git a/pkg/util/genutil/genutil.go b/pkg/util/genutil/genutil.go deleted file mode 100644 index 95735485d5..0000000000 --- a/pkg/util/genutil/genutil.go +++ /dev/null @@ -1,54 +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 genutil - -import ( - "fmt" - "os" - "path/filepath" - - "github.com/OpenIMSDK/tools/errs" -) - -// OutDir creates the absolute path name from path and checks path exists. -// Returns absolute path including trailing '/' or error if path does not exist. -func OutDir(path string) (string, error) { - outDir, err := filepath.Abs(path) - if err != nil { - return "", errs.Wrap(err, "output directory %s does not exist", path) - } - - stat, err := os.Stat(outDir) - if err != nil { - return "", errs.Wrap(err, "output directory %s does not exist", outDir) - } - - if !stat.IsDir() { - return "", errs.Wrap(err, "output directory %s is not a directory", outDir) - } - outDir += "/" - return outDir, nil -} - -func ExitWithError(err error) { - progName := filepath.Base(os.Args[0]) - fmt.Fprintf(os.Stderr, "%s exit -1: %+v\n", progName, err) - os.Exit(-1) -} - -func SIGTERMExit() { - progName := filepath.Base(os.Args[0]) - fmt.Fprintf(os.Stderr, "Warning %s receive process terminal SIGTERM exit 0\n", progName) -} diff --git a/pkg/util/genutil/genutil_test.go b/pkg/util/genutil/genutil_test.go deleted file mode 100644 index 050d140407..0000000000 --- a/pkg/util/genutil/genutil_test.go +++ /dev/null @@ -1,40 +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 genutil - -import ( - "testing" -) - -func TestValidDir(t *testing.T) { - _, err := OutDir("./") - if err != nil { - t.Fatal(err) - } -} - -func TestInvalidDir(t *testing.T) { - _, err := OutDir("./nondir") - if err == nil { - t.Fatal("expected an error") - } -} - -func TestNotDir(t *testing.T) { - _, err := OutDir("./genutils_test.go") - if err == nil { - t.Fatal("expected an error") - } -} diff --git a/scripts/check-all.sh b/scripts/check-all.sh index d410233845..54296b22d5 100755 --- a/scripts/check-all.sh +++ b/scripts/check-all.sh @@ -20,9 +20,6 @@ # READ: https://github.com/openimsdk/open-im-server/tree/main/scripts/install/environment.sh - - - OPENIM_ROOT=$(dirname "${BASH_SOURCE[0]}")/.. source "${OPENIM_ROOT}/scripts/install/common.sh" @@ -33,7 +30,7 @@ fi OPENIM_VERBOSE=4 -openim::log::info "\n# Begin to check all openim service" +openim::log::info "\n# Begin to check all OpenIM service" openim::log::status "Check all dependent service ports" # Elegant printing function @@ -65,16 +62,16 @@ print_services_and_ports "${OPENIM_SERVER_NAME_TARGETS[@]}" "${OPENIM_SERVER_POR print_services_and_ports "${OPENIM_DEPENDENCY_TARGETS[@]}" "${OPENIM_DEPENDENCY_PORT_TARGETS[@]}" # OpenIM check -echo "++ The port being checked: ${OPENIM_SERVER_PORT_LISTARIES[@]}" -openim::log::info "\n## Check all dependent service ports" -echo "++ The port being checked: ${OPENIM_DEPENDENCY_PORT_LISTARIES[@]}" +#echo "++ The port being checked: ${OPENIM_SERVER_PORT_LISTARIES[@]}" +openim::log::info "\n## Check all dependent components service ports" +#echo "++ The port being checked: ${OPENIM_DEPENDENCY_PORT_LISTARIES[@]}" # Later, after discarding Docker, the Docker keyword is unreliable, and Kubepods is used if grep -qE 'docker|kubepods' /proc/1/cgroup || [ -f /.dockerenv ]; then openim::color::echo ${COLOR_CYAN} "Environment in the interior of the container" else - openim::color::echo ${COLOR_CYAN} "The environment is outside the container" + openim::color::echo ${COLOR_CYAN}"The environment is outside the container" openim::util::check_ports ${OPENIM_DEPENDENCY_PORT_LISTARIES[@]} fi @@ -82,30 +79,35 @@ if [[ $? -ne 0 ]]; then openim::log::error_exit "The service does not start properly, please check the port, query variable definition!" echo "+++ https://github.com/openimsdk/open-im-server/tree/main/scripts/install/environment.sh +++" else - openim::log::success "All components depended on by openim are running normally! " + openim::log::success "All components depended on by OpenIM are running normally! " fi -openim::log::info "\n## Check openim service name:\n${OPENIM_OUTPUT_HOSTBIN}/openim-msgtransfer" +openim::log::status "Check OpenIM service:" +openim::log::colorless "${OPENIM_OUTPUT_HOSTBIN}/openim-msgtransfer" result=$(. $(dirname ${BASH_SOURCE})/install/openim-msgtransfer.sh openim::msgtransfer::check) if [[ $? -ne 0 ]]; then - echo "+++ cat openim log file >>> ${LOG_FILE}" - openim::log::error "check process failed.\n $result" + #echo "+++ cat openim log file >>> ${LOG_FILE}" + + openim::log::error "The service is not running properly, please check the logs $result" fi -echo "Check openim service name:" +openim::log::status "Check OpenIM service:" for item in "${OPENIM_ALL_SERVICE_LIBRARIES_NO_TRANSFER[@]}"; do - echo "$item" + openim::log::colorless "$item" done + result=$(openim::util::check_process_names ${OPENIM_ALL_SERVICE_LIBRARIES_NO_TRANSFER[@]}) if [[ $? -ne 0 ]]; then - echo "+++ cat openim log file >>> ${LOG_FILE}" - openim::log::error "check process failed.\n " + #echo "+++ cat OpenIM log file >>> ${LOG_FILE}" + openim::log::error "The service is not running properly, please check the logs " echo "$result" exit 1 else - openim::log::success "All openim services are running normally! " + openim::log::status "List the ports listened to by the OpenIM service:" + openim::util::find_ports_for_all_services ${OPENIM_ALL_SERVICE_LIBRARIES_NO_TRANSFER[@]} + openim::util::find_ports_for_all_services ${OPENIM_MSGTRANSFER_BINARY[@]} + openim::log::success "All OpenIM services are running normally! " fi - diff --git a/scripts/cherry-pick.sh b/scripts/cherry-pick.sh index ff303269d8..b95289cd4f 100755 --- a/scripts/cherry-pick.sh +++ b/scripts/cherry-pick.sh @@ -35,8 +35,8 @@ DRY_RUN=${DRY_RUN:-""} REGENERATE_DOCS=${REGENERATE_DOCS:-""} UPSTREAM_REMOTE=${UPSTREAM_REMOTE:-upstream} FORK_REMOTE=${FORK_REMOTE:-origin} -MAIN_REPO_ORG=${MAIN_REPO_ORG:-$(git remote get-url "$UPSTREAM_REMOTE" | awk '{gsub(/http[s]:\/\/|git@/,"")}1' | awk -F'[@:./]' 'NR==1{print $3}')} -MAIN_REPO_NAME=${MAIN_REPO_NAME:-$(git remote get-url "$UPSTREAM_REMOTE" | awk '{gsub(/http[s]:\/\/|git@/,"")}1' | awk -F'[@:./]' 'NR==1{print $4}')} +MAIN_REPO_ORG=${MAIN_REPO_ORG:-$(git remote get-url "$UPSTREAM_REMOTE" | awk '{gsub(/webhook[s]:\/\/|git@/,"")}1' | awk -F'[@:./]' 'NR==1{print $3}')} +MAIN_REPO_NAME=${MAIN_REPO_NAME:-$(git remote get-url "$UPSTREAM_REMOTE" | awk '{gsub(/webhook[s]:\/\/|git@/,"")}1' | awk -F'[@:./]' 'NR==1{print $4}')} if [[ -z ${GITHUB_USER:-} ]]; then openim::log::error_exit "Please export GITHUB_USER= (or GH organization, if that's where your fork lives)" diff --git a/scripts/create-topic.sh b/scripts/create-topic.sh index 5c291ff085..206075fb83 100755 --- a/scripts/create-topic.sh +++ b/scripts/create-topic.sh @@ -14,14 +14,42 @@ # limitations under the License. # Wait for Kafka to be ready -until /opt/bitnami/kafka/bin/kafka-topics.sh --list --bootstrap-server localhost:9092; do - echo "Waiting for Kafka to be ready..." - sleep 2 + +KAFKA_SERVER=localhost:9092 + +MAX_ATTEMPTS=300 +attempt_num=1 + +echo "Waiting for Kafka to be ready..." + +until /opt/bitnami/kafka/bin/kafka-topics.sh --list --bootstrap-server $KAFKA_SERVER; do + echo "Attempt $attempt_num of $MAX_ATTEMPTS: Kafka not ready yet..." + if [ $attempt_num -eq $MAX_ATTEMPTS ]; then + echo "Kafka not ready after $MAX_ATTEMPTS attempts, exiting" + exit 1 + fi + attempt_num=$((attempt_num+1)) + sleep 1 done -# Create topics -/opt/bitnami/kafka/bin/kafka-topics.sh --create --bootstrap-server localhost:9092 --replication-factor 1 --partitions 8 --topic latestMsgToRedis -/opt/bitnami/kafka/bin/kafka-topics.sh --create --bootstrap-server localhost:9092 --replication-factor 1 --partitions 8 --topic msgToPush -/opt/bitnami/kafka/bin/kafka-topics.sh --create --bootstrap-server localhost:9092 --replication-factor 1 --partitions 8 --topic offlineMsgToMongoMysql +echo "Kafka is ready. Creating topics..." + + +topics=("toRedis" "toMongo" "toPush") +partitions=8 +replicationFactor=1 + +for topic in "${topics[@]}"; do + if /opt/bitnami/kafka/bin/kafka-topics.sh --create \ + --bootstrap-server $KAFKA_SERVER \ + --replication-factor $replicationFactor \ + --partitions $partitions \ + --topic $topic + then + echo "Topic $topic created." + else + echo "Failed to create topic $topic." + fi +done -echo "Topics created." \ No newline at end of file +echo "All topics created." diff --git a/scripts/demo.sh b/scripts/demo.sh deleted file mode 100755 index 4b877b9ed3..0000000000 --- a/scripts/demo.sh +++ /dev/null @@ -1,156 +0,0 @@ -#!/usr/bin/env bash -# 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. - -if ! command -v pv &> /dev/null -then - echo "pv not found, installing..." - if [ -e /etc/debian_version ]; then - sudo apt-get update - sudo apt-get install -y pv - elif [ -e /etc/redhat-release ]; then - sudo yum install -y pv - else - echo "Unsupported OS, please install pv manually." - exit 1 - fi -fi - -readonly t_reset=$(tput sgr0) -readonly green=$(tput bold; tput setaf 2) -readonly yellow=$(tput bold; tput setaf 3) -readonly blue=$(tput bold; tput setaf 6) -readonly timeout=$(if [ "$(uname)" == "Darwin" ]; then echo "1"; else echo "0.1"; fi) -readonly ipv6regex='(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))' - -clear -. $(dirname ${BASH_SOURCE})/lib/util.sh - -openim::util::ensure-bash-version - -trap 'openim::util::onCtrlC' INT - -function openim::util::onCtrlC() { - echo -e "\n${t_reset}Ctrl+C Press it. It's exiting openim make init..." - exit 0 -} - -openim::util::desc "========> Welcome to the OpenIM Demo" -openim::util::desc "========> We'll help you get started with OpenIM quickly" -openim::util::desc "========> Press Enter to continue...." -openim::util::run "make advertise" -clear - -openim::util::desc "========> Initialize the project and generate configuration files" -openim::util::run "make init" -clear - -# openim::util::desc "========> You can look git diff" -# openim::util::run "git diff" -# clear - -openim::util::desc "You can learn a lot about automation using make help" -openim::util::run "make help" -clear - -openim::util::desc "You can learn a lot about automation using make help-all" -openim::util::run "make help-all" -clear - -openim::util::desc "First, let's verify and install some necessary tools" -openim::util::run "make tools" -clear - -openim::util::desc "========> Start the basic openim docker components" -openim::util::desc "========> You can use docker-compose ps to check the status of the container" -openim::util::run "docker compose up -d" -clear - -openim::util::desc "========> Use make init-githooks Initialize git hooks " -openim::util::run "make init-githooks" -clear - -openim::util::desc "The specification is pretty high, you need to be bound on your branch name, as well as commit messages" -openim::util::run "git commit -a -s -m 'feta: commit demo against specification'" -openim::util::run "# git commit -a -s -m 'feat: commit demo against specification' --amend" -clear - -openim::util::desc "How did we teach you how to build OpenIM" -openim::util::desc "A full build startup check" -openim::util::run "# make all" -openim::util::desc "Build one OpenIM binary" -openim::util::desc "BINS: openim-api openim-cmdutils openim-crontask openim-msggateway openim-msgtransfer openim-push openim-rpc changelog infra ncpu yamlfmt" -openim::util::run "make build BINS=openim-api" -openim::util::run "make build" - -openim::util::desc "Build binaries for all platforms" -openim::util::run "make multiarch -j BINS=openim-crontask PLATFORMS='linux_arm64 linux_amd64' " - -openim::util::desc "If you wish to use dlv for debugging, either binary or process" -openim::util::desc "You need to enable debug mode" -openim::util::run "make build BINS=openim-cmdutils DEBUG=1" -clear - -openim::util::desc "Next, let's learn how to start the OpenIM service. For starting, we have two ways" -openim::util::desc "The first is Background startup" -openim::util::run "make start" -openim::util::desc "The second way is through the Linux system way" -openim::util::run "./scripts/install/install.sh --help" -clear - -openim::util::desc "Next, let's learn how to check the OpenIM service. For checking, we have two ways" -openim::util::run "make check" -clear - -openim::util::desc "Next, let's learn how to stop the OpenIM service. For stopping, we have two ways" -openim::util::run "make stop" -clear - -openim::util::desc "Run tidy to format and fix imports" -openim::util::run "make tidy" -clear - -openim::util::desc "Vendor go.mod dependencies" -openim::util::run "# make vendor" -clear - -openim::util::desc "Run unit tests" -openim::util::run "# make test" -clear - -openim::util::desc "Run unit tests and get test coverage" -openim::util::run "# make cover" -clear - -openim::util::desc "Check for updates to go.mod dependencies" -openim::util::run "# make updates" -clear - -openim::util::desc "You can learn a lot about automation using make clean, remove all files that are created by building" -openim::util::run "make clean" -clear - -openim::util::desc "Generate all necessary files" -openim::util::run "make gen" -clear - -openim::util::desc "Verify the license headers for all files" -openim::util::run "make verify-copyright" -clear - -openim::util::desc "Add copyright" -openim::util::run "make add-copyright" -clear - -exit 0 diff --git a/scripts/docker-check-service.sh b/scripts/docker-check-service.sh deleted file mode 100755 index 30ca89b5a9..0000000000 --- a/scripts/docker-check-service.sh +++ /dev/null @@ -1,91 +0,0 @@ -#!/usr/bin/env bash - -# 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. - -OPENIM_ROOT=$(dirname "${BASH_SOURCE[0]}")/.. -source "${OPENIM_ROOT}/scripts/install/common.sh" - -cd "$OPENIM_ROOT" - -openim::util::check_docker_and_compose_versions - -progress() { - local _main_pid="$1" - local _length=20 - local _ratio=1 - local _colors=("31" "32" "33" "34" "35" "36" "37") - local _wave=("▁" "▂" "▃" "▄" "▅" "▆" "▇" "█" "▇" "▆" "▅" "▄" "▃" "▂") - - while pgrep -P "$_main_pid" &> /dev/null; do - local _mark='>' - local _progress_bar= - for ((i = 1; i <= _length; i++)); do - if ((i > _ratio)); then - _mark='-' - fi - _progress_bar="${_progress_bar}${_mark}" - done - - local _color_idx=$((_ratio % ${#_colors[@]})) - local _color_prefix="\033[${_colors[_color_idx]}m" - local _reset_suffix="\033[0m" - - local _wave_idx=$((_ratio % ${#_wave[@]})) - local _wave_progress=${_wave[_wave_idx]} - - printf "Progress: ${_color_prefix}${_progress_bar}${_reset_suffix} ${_wave_progress} Countdown: %2ds \r" "$_countdown" - ((_ratio++)) - ((_ratio > _length)) && _ratio=1 - sleep 0.1 - done -} - -countdown() { - local _duration="$1" - - for ((i = _duration; i >= 1; i--)); do - printf "\rCountdown: %2ds \r" "$i" - sleep 1 - done - printf "\rCountdown: %2ds \r" "$_duration" -} - -do_sth() { - echo "++++++++++++++++++++++++" - progress $$ & - local _progress_pid=$! - local _countdown=30 - - countdown "$_countdown" & - local _countdown_pid=$! - - sleep 30 - - kill "$_progress_pid" "$_countdown_pid" - - "${SCRIPTS_ROOT}/check-all.sh" - echo -e "${PURPLE_PREFIX}=========> Check docker-compose status ${COLOR_SUFFIX} \n" -} - -set -e - -do_sth & -do_sth_pid=$(jobs -p | tail -1) - -progress "${do_sth_pid}" & -progress_pid=$(jobs -p | tail -1) - -wait "${do_sth_pid}" -printf "Progress: done \n" diff --git a/scripts/docker-start-all.sh b/scripts/docker-start-all.sh index 4f8747a2a2..8d91cd7715 100755 --- a/scripts/docker-start-all.sh +++ b/scripts/docker-start-all.sh @@ -23,7 +23,7 @@ OPENIM_ROOT=$(dirname "${BASH_SOURCE[0]}")/.. source "${OPENIM_ROOT}/scripts/install/common.sh" -openim::log::info "\n# Use Docker to start all openim service" +openim::log::info "\n# Use Docker to start all OpenIM service" trap 'openim::util::onCtrlC' INT "${OPENIM_ROOT}"/scripts/start-all.sh 2>&1 & tail -f ${DOCKER_LOG_FILE} diff --git a/scripts/gendoc.sh b/scripts/gendoc.sh index ece090190e..43b69c3edd 100755 --- a/scripts/gendoc.sh +++ b/scripts/gendoc.sh @@ -13,66 +13,72 @@ # See the License for the specific language governing permissions and # limitations under the License. -DEFAULT_DIRS=( - "pkg" - "internal/pkg" -) -BASE_URL="github.com/openimsdk/open-im-server" +#!/bin/bash + +DEFAULT_DIRS=("pkg") +BASE_URL="github.com/openimsdk/open-im-server/v3" +REMOVE_DOC=false usage() { echo "Usage: $0 [OPTIONS]" echo - echo "This script iterates over directories and generates doc.go if necessary." - echo "By default, it processes 'pkg' and 'internal/pkg' directories." + echo "This script iterates over directories. By default, it generates doc.go files for 'pkg' and 'internal/pkg'." echo echo "Options:" - echo " -d DIRS, --dirs DIRS Specify the directories to be processed, separated by commas. E.g., 'pkg,internal/pkg'." - echo " -u URL, --url URL Set the base URL for the import path. Default is '$BASE_URL'." - echo " -h, --help Show this help message." + echo " -d DIRS, --dirs DIRS Specify directories to process, separated by commas (e.g., 'pkg,internal/pkg')." + echo " -u URL, --url URL Set the base URL for the import path. Default is '$BASE_URL'." + echo " -r, --remove Remove all doc.go files in the specified directories." + echo " -h, --help Show this help message." echo } process_dir() { - local dir=$1 - local base_url=$2 - - for d in $(find $dir -type d); do - if [ ! -f $d/doc.go ]; then - if ls $d/*.go > /dev/null 2>&1; then - echo $d/doc.go - echo "package $(basename $d) // import \"$base_url/$d\"" > $d/doc.go + local dir="$1" + local base_url="$2" + local remove_doc="$3" + + find "$dir" -type d | while read -r d; do + if [ "$remove_doc" = true ]; then + if [ -f "$d/doc.go" ]; then + echo "Removing $d/doc.go" + rm -f "$d/doc.go" + fi + else + if [ ! -f "$d/doc.go" ] && ls "$d/"*.go &>/dev/null; then + echo "Creating $d/doc.go" + echo "package $(basename "$d") // import \"$base_url/$(echo "$d" | sed "s|^\./||")\"" >"$d/doc.go" fi fi done } while [[ $# -gt 0 ]]; do - key="$1" - - case $key in + case "$1" in -d|--dirs) - IFS=',' read -ra DIRS <<< "$2" - shift # shift past argument - shift # shift past value - ;; - -u|--url) - BASE_URL="$2" - shift # shift past argument - shift # shift past value - ;; - -h|--help) - usage - exit 0 - ;; - *) - usage - exit 1 - ;; - esac + IFS=',' read -ra DIRS <<< "$2" + shift 2 + ;; + -u|--url) + BASE_URL="$2" + shift 2 + ;; + -r|--remove) + REMOVE_DOC=true + shift + ;; + -h|--help) + usage + exit 0 + ;; + *) + usage + exit 1 + ;; + esac done -DIRS=${DIRS:-${DEFAULT_DIRS[@]}} +DIRS=(${DIRS:-"${DEFAULT_DIRS[@]}"}) for dir in "${DIRS[@]}"; do - process_dir $dir $BASE_URL + process_dir "$dir" "$BASE_URL" "$REMOVE_DOC" done diff --git a/scripts/init-config.sh b/scripts/init-config.sh index c5b21d061b..ef2cd0a401 100755 --- a/scripts/init-config.sh +++ b/scripts/init-config.sh @@ -65,6 +65,8 @@ GENERATE_EXAMPLES=false CLEAN_CONFIG=false CLEAN_EXAMPLES=false +FILES_PROCESSED=false + # Function to display help information show_help() { echo "Usage: $(basename "$0") [options]" @@ -126,7 +128,7 @@ process_file() { if [[ "${FORCE_OVERWRITE}" == true ]]; then openim::log::info "Force overwriting ${output_file}." elif [[ "${SKIP_EXISTING}" == true ]]; then - openim::log::info "Skipping generation of ${output_file} as it already exists." + #openim::log::info "Skipping generation of ${output_file} as it already exists." return else echo -n "File ${output_file} already exists. Overwrite? (Y/N): " @@ -173,8 +175,7 @@ process_file() { exit 1 } fi - - sleep 0.5 + FILES_PROCESSED=true } clean_config_files() { @@ -259,4 +260,6 @@ if [[ "${GENERATE_EXAMPLES}" == true ]] && [[ "${CLEAN_EXAMPLES}" == false ]]; t generate_example_files fi -openim::log::success "Configuration and example files operation complete!" +if [[ "${FILES_PROCESSED}" == true ]]; then + openim::log::success "Configuration and example files operation complete!" +fi diff --git a/scripts/install/openim-api.sh b/scripts/install/openim-api.sh index cd3d5eb080..8403382e6a 100755 --- a/scripts/install/openim-api.sh +++ b/scripts/install/openim-api.sh @@ -89,7 +89,7 @@ function openim::api::start_service() { echo "Starting service with command: $cmd" #nohup $cmd >> "${LOG_FILE}" 2> >(tee -a "${STDERR_LOG_FILE}" "$TMP_LOG_FILE" >&2) & - nohup ${cmd} >> "${LOG_FILE}" 2> >(tee -a "$TMP_LOG_FILE" | while read line; do echo -e "\e[31m${line}\e[0m"; done >&2) >/dev/null & + nohup ${cmd} >> "${LOG_FILE}" 2> >(tee -a "$TMP_LOG_FILE" | while read line; do echo -e "\e[31m${line}\e[0m"; done >&2) >> "${LOG_FILE}" 2>&1 & if [ $? -ne 0 ]; then openim::log::error_exit "Failed to start ${binary_name} on port ${service_port}." return 1 diff --git a/scripts/install/openim-crontask.sh b/scripts/install/openim-crontask.sh index 1917010823..d785b37a4e 100755 --- a/scripts/install/openim-crontask.sh +++ b/scripts/install/openim-crontask.sh @@ -53,7 +53,7 @@ function openim::crontask::start() { openim::log::status "start cron_task process, path: ${OPENIM_CRONTASK_BINARY}" #nohup ${OPENIM_CRONTASK_BINARY} -c ${OPENIM_PUSH_CONFIG} >> ${LOG_FILE} 2> >(tee -a "${STDERR_LOG_FILE}" "$TMP_LOG_FILE" >&2) & cmd="${OPENIM_CRONTASK_BINARY} -c ${OPENIM_PUSH_CONFIG}" - nohup ${cmd} >> "${LOG_FILE}" 2> >(tee -a "$TMP_LOG_FILE" | while read line; do echo -e "\e[31m${line}\e[0m"; done >&2) >/dev/null & + nohup ${cmd} >> "${LOG_FILE}" 2> >(tee -a "$TMP_LOG_FILE" | while read line; do echo -e "\e[31m${line}\e[0m"; done >&2) >> "${LOG_FILE}" 2>&1 & return 0 } diff --git a/scripts/install/openim-msggateway.sh b/scripts/install/openim-msggateway.sh index 25051aa6e0..ed79108055 100755 --- a/scripts/install/openim-msggateway.sh +++ b/scripts/install/openim-msggateway.sh @@ -62,7 +62,7 @@ function openim::msggateway::start() { PROMETHEUS_PORT_OPTION="--prometheus_port ${MSG_GATEWAY_PROM_PORTS_ARRAY[$i]}" fi cmd="${OPENIM_MSGGATEWAY_BINARY} --port ${OPENIM_MSGGATEWAY_PORTS_ARRAY[$i]} --ws_port ${OPENIM_WS_PORTS_ARRAY[$i]} $PROMETHEUS_PORT_OPTION -c ${OPENIM_MSGGATEWAY_CONFIG}" - nohup ${cmd} >> "${LOG_FILE}" 2> >(tee -a "$TMP_LOG_FILE" | while read line; do echo -e "\e[31m${line}\e[0m"; done >&2) >/dev/null & + nohup ${cmd} >> "${LOG_FILE}" 2> >(tee -a "$TMP_LOG_FILE" | while read line; do echo -e "\e[31m${line}\e[0m"; done >&2) >> "${LOG_FILE}" 2>&1 & # nohup ${OPENIM_MSGGATEWAY_BINARY} --port ${OPENIM_MSGGATEWAY_PORTS_ARRAY[$i]} --ws_port ${OPENIM_WS_PORTS_ARRAY[$i]} $PROMETHEUS_PORT_OPTION -c ${OPENIM_MSGGATEWAY_CONFIG} >> ${LOG_FILE} 2> >(tee -a "${STDERR_LOG_FILE}" "$TMP_LOG_FILE" >&2) & done diff --git a/scripts/install/openim-msgtransfer.sh b/scripts/install/openim-msgtransfer.sh index 23ce79c36f..8403d1cfcf 100755 --- a/scripts/install/openim-msgtransfer.sh +++ b/scripts/install/openim-msgtransfer.sh @@ -58,7 +58,8 @@ function openim::msgtransfer::start() { PROMETHEUS_PORT_OPTION="--prometheus_port ${PROMETHEUS_MSG_TRANSFER_PORT}" fi cmd="${OPENIM_MSGTRANSFER_BINARY} ${PROMETHEUS_PORT_OPTION} -c ${OPENIM_MSGTRANSFER_CONFIG} -n ${i}" - nohup ${cmd} >> "${LOG_FILE}" 2> >(tee -a "$TMP_LOG_FILE" | while read line; do echo -e "\e[31m${line}\e[0m"; done >&2) >/dev/null & + #nohup ${cmd} >> "${LOG_FILE}" 2> >(tee -a "$TMP_LOG_FILE" | while read line; do echo -e "\e[31m${line}\e[0m"; done >&2) >/dev/null & + nohup ${cmd} >> "${LOG_FILE}" 2> >(tee -a "$TMP_LOG_FILE" | while read line; do echo -e "\e[31m${line}\e[0m"; done >&2) >> "${LOG_FILE}" 2>&1 & #nohup ${OPENIM_MSGTRANSFER_BINARY} ${PROMETHEUS_PORT_OPTION} -c ${OPENIM_MSGTRANSFER_CONFIG} -n ${i} >> ${LOG_FILE} 2> >(tee -a "${STDERR_LOG_FILE}" "$TMP_LOG_FILE" >&2) & done return 0 @@ -82,7 +83,7 @@ function openim::msgtransfer::check() { fi done else - openim::log::error "Expected $OPENIM_MSGGATEWAY_NUM openim msgtransfer processes, but found $NUM_PROCESSES msgtransfer processes." + openim::log::error "Expected $OPENIM_MSGGATEWAY_NUM OpenIM msgtransfer processes, but found $NUM_PROCESSES msgtransfer processes running" return 1 fi return 0 diff --git a/scripts/install/openim-push.sh b/scripts/install/openim-push.sh index 8dea4b1f15..aafb24c7b0 100755 --- a/scripts/install/openim-push.sh +++ b/scripts/install/openim-push.sh @@ -72,7 +72,8 @@ function openim::push::start() { for (( i=0; i<${#OPENIM_PUSH_PORTS_ARRAY[@]}; i++ )); do openim::log::info "start push process, port: ${OPENIM_PUSH_PORTS_ARRAY[$i]}, prometheus port: ${PUSH_PROM_PORTS_ARRAY[$i]}" cmd="${OPENIM_PUSH_BINARY} --port ${OPENIM_PUSH_PORTS_ARRAY[$i]} -c ${OPENIM_PUSH_CONFIG} --prometheus_port ${PUSH_PROM_PORTS_ARRAY[$i]}" - nohup ${cmd} >> "${LOG_FILE}" 2> >(tee -a "$TMP_LOG_FILE" | while read line; do echo -e "\e[31m${line}\e[0m"; done >&2) >/dev/null & + #nohup ${cmd} >> "${LOG_FILE}" 2> >(tee -a "$TMP_LOG_FILE" | while read line; do echo -e "\e[31m${line}\e[0m"; done >&2) >/dev/null & + nohup ${cmd} >> "${LOG_FILE}" 2> >(tee -a "$TMP_LOG_FILE" | while read line; do echo -e "\e[31m${line}\e[0m"; done >&2) >> "${LOG_FILE}" 2>&1 & #nohup ${OPENIM_PUSH_BINARY} --port ${OPENIM_PUSH_PORTS_ARRAY[$i]} -c ${OPENIM_PUSH_CONFIG} --prometheus_port ${PUSH_PROM_PORTS_ARRAY[$i]} >> ${LOG_FILE} 2> >(tee -a "${STDERR_LOG_FILE}" "$TMP_LOG_FILE" >&2) & done return 0 diff --git a/scripts/install/openim-rpc.sh b/scripts/install/openim-rpc.sh index c3ac12449d..1265a11c67 100755 --- a/scripts/install/openim-rpc.sh +++ b/scripts/install/openim-rpc.sh @@ -166,7 +166,8 @@ function openim::rpc::start_service() { cmd="${cmd} --prometheus_port ${prometheus_port}" fi #nohup ${cmd} >> "${LOG_FILE}" 2> >(tee -a "${STDERR_LOG_FILE}" "$TMP_LOG_FILE" >&2) & - nohup ${cmd} >> "${LOG_FILE}" 2> >(tee -a "$TMP_LOG_FILE" | while read line; do echo -e "\e[31m${line}\e[0m"; done >&2) >/dev/null & + #nohup ${cmd} >> "${LOG_FILE}" 2> >(tee -a "$TMP_LOG_FILE" | while read line; do echo -e "\e[31m${line}\e[0m"; done >&2) >/dev/null & + nohup ${cmd} >> "${LOG_FILE}" 2> >(tee -a "$TMP_LOG_FILE" | while read line; do echo -e "\e[31m${line}\e[0m"; done >&2) >> "${LOG_FILE}" 2>&1 & return 0 } diff --git a/scripts/install/openim-tools.sh b/scripts/install/openim-tools.sh index 7f6e1f52b5..57de9772d3 100755 --- a/scripts/install/openim-tools.sh +++ b/scripts/install/openim-tools.sh @@ -83,67 +83,65 @@ function openim::tools::start_service() { local prometheus_port="$4" local cmd="${OPENIM_OUTPUT_HOSTBIN_TOOLS}/${binary_name}" - openim::log::info "Starting PATH: ${OPENIM_OUTPUT_HOSTBIN_TOOLS}/${binary_name}..." + #openim::log::info "Starting PATH: ${OPENIM_OUTPUT_HOSTBIN_TOOLS}/${binary_name}..." if [ -n "${config}" ]; then - printf "Specifying config: %s\n" "${config}" + # printf "Specifying config: %s\n" "${config}" cmd="${cmd} -c ${config}/config.yaml" fi if [ -n "${service_port}" ]; then - printf "Specifying service port: %s\n" "${service_port}" + #printf "Specifying service port: %s\n" "${service_port}" cmd="${cmd} --port ${service_port}" fi if [ -n "${prometheus_port}" ]; then - printf "Specifying prometheus port: %s\n" "${prometheus_port}" + #printf "Specifying prometheus port: %s\n" "${prometheus_port}" cmd="${cmd} --prometheus_port ${prometheus_port}" fi - openim::log::status "Starting binary ${binary_name}..." + #openim::log::status "Starting binary ${binary_name}..." - - ${cmd} - + # openim::log::info "cmd: $cmd" + ${cmd} local status=$? - - if [ $status -eq 0 ]; then - openim::log::info "Service ${binary_name} started successfully." - return 0 - else - openim::log::error "Failed to start service ${binary_name}." - return 1 - fi + if [ $status -eq 0 ]; then + openim::log::colorless "Service ${binary_name} started successfully." + return 0 + else + openim::log::error "Failed to start service ${binary_name}." + return 1 + fi } function openim::tools::start() { openim::log::info "Starting OpenIM Tools..." for tool in "${OPENIM_TOOLS_NAME_LISTARIES[@]}"; do - openim::log::info "Starting tool ${tool}..." + openim::log::colorless "Starting tool ${tool}..." # openim::tools::start_service ${tool} - sleep 0.2 + #sleep 0.2 done } function openim::tools::pre-start() { - openim::log::info "Preparing to start OpenIM Tools..." + #openim::log::info "Preparing to start OpenIM Tools..." for tool in "${OPENIM_TOOLS_PRE_START_NAME_LISTARIES[@]}"; do - openim::log::info "Starting tool ${tool}..." + openim::log::colorless "Starting tool: ${tool}" if ! openim::tools::start_service ${tool} ${OPNEIM_CONFIG}; then openim::log::error "Failed to start ${tool}, aborting..." return 1 fi done - openim::log::info "All tools started successfully." + #openim::log::info "All tools started successfully." } function openim::tools::post-start() { - openim::log::info "Post-start actions for OpenIM Tools..." + #openim::log::info "Post-start actions for OpenIM Tools..." for tool in "${OPENIM_TOOLS_POST_START_NAME_LISTARIES[@]}"; do - openim::log::info "Starting tool ${tool}..." + openim::log::colorless "Starting tool: ${tool}" openim::tools::start_service ${tool} done } diff --git a/scripts/lib/golang.sh b/scripts/lib/golang.sh index f9648cbdba..51db58d891 100755 --- a/scripts/lib/golang.sh +++ b/scripts/lib/golang.sh @@ -149,7 +149,7 @@ openim::golang::start_script_list() { openim-msgtransfer.sh openim-msggateway.sh openim-crontask.sh - openim-tools.sh + #openim-tools.sh ) local result=() for target in "${targets[@]}"; do @@ -181,7 +181,7 @@ openim::golang::check_openim_binaries() { done return 1 else - echo "All binaries have been installed in ${OPENIM_OUTPUT_HOSTBIN}。" + echo -e "All binaries have been installed in: \n${OPENIM_OUTPUT_HOSTBIN}\n${OPENIM_OUTPUT_HOSTBIN_TOOLS}" return 0 fi } @@ -317,8 +317,6 @@ readonly OPENIM_CLIENT_TARGETS=( imctl infra ncpu - openim-web - up35 versionchecker yamlfmt ) diff --git a/scripts/lib/logging.sh b/scripts/lib/logging.sh index fec71b19d9..0d15463eb0 100755 --- a/scripts/lib/logging.sh +++ b/scripts/lib/logging.sh @@ -210,16 +210,26 @@ openim::log::status() { if [[ ${OPENIM_VERBOSE} < ${V} ]]; then return fi - - timestamp=$(date +"[%Y-%m-%d %H:%M:%S %Z]") - echo_log "${timestamp} ${1}" + + local COLOR_BLUE="\033[0;34m" + local COLOR_RESET="\033[0m" + + local timestamp=$(date +"[%Y-%m-%d %H:%M:%S %Z]") + + echo_log() { + echo -e "$@" + } + + + echo_log "${COLOR_BLUE}${timestamp} ${1}${COLOR_RESET}" shift for message; do - echo_log " ${message}" + echo_log "${COLOR_BLUE}${message}${COLOR_RESET}" done } + openim::log::success() { local V="${V:-0}" if [[ ${OPENIM_VERBOSE} < ${V} ]]; then @@ -232,7 +242,6 @@ openim::log::success() { - function openim::log::test_log() { echo_log "test log" openim::log::info "openim::log::info" @@ -249,3 +258,14 @@ function openim::log::print_blue() { echo -e "\033[0;36m$1\033[0m" } + +openim::log::colorless() { + local V="${V:-0}" + if [[ ${OPENIM_VERBOSE} < ${V} ]]; then + return + fi + timestamp=$(date +"[%Y-%m-%d %H:%M:%S %Z]") + echo_log -e "${timestamp} ${1} " +} + + diff --git a/scripts/lib/release.sh b/scripts/lib/release.sh index 05e92377d5..3e6cde103d 100755 --- a/scripts/lib/release.sh +++ b/scripts/lib/release.sh @@ -243,7 +243,7 @@ function openim::release::package_client_tarballs() { local client_bins=("${OPENIM_CLIENT_BINARIES[@]}") - # client_bins: changelog component imctl infra ncpu openim-web up35 versionchecker yamlfmt + # client_bins: changelog component imctl infra ncpu versionchecker yamlfmt # Copy client binclient_bins:aries openim::log::info " Copy client binaries: ${client_bins[@]/#/${LOCAL_OUTPUT_BINTOOLSPATH}/${platform}/}" openim::log::info " Copy client binaries to: ${release_stage}/client/bin" diff --git a/scripts/lib/util.sh b/scripts/lib/util.sh index dcce56c12f..13bd263caf 100755 --- a/scripts/lib/util.sh +++ b/scripts/lib/util.sh @@ -360,8 +360,8 @@ openim::util::check_ports() { # If any of the processes is not running, return a status of 1. if [[ ${#not_started[@]} -ne 0 ]]; then - openim::color::echo $COLOR_RED "OpenIM Stdout Log >> cat ${LOG_FILE}" - openim::color::echo $COLOR_RED "OpenIM Stderr Log >> cat ${STDERR_LOG_FILE}" + #openim::color::echo $COLOR_RED "OpenIM Stdout Log >> cat ${LOG_FILE}" + #openim::color::echo $COLOR_RED "OpenIM Stderr Log >> cat ${STDERR_LOG_FILE}" cat "$TMP_LOG_FILE" | awk '{print "\033[31m" $0 "\033[0m"}' return 1 else @@ -446,8 +446,8 @@ openim::util::check_process_names() { # Return status if [[ ${#not_started[@]} -ne 0 ]]; then - openim::color::echo $COLOR_RED "OpenIM Stdout Log >> cat ${LOG_FILE}" - openim::color::echo $COLOR_RED "OpenIM Stderr Log >> cat ${STDERR_LOG_FILE}" + #openim::color::echo $COLOR_RED "OpenIM Stdout Log >> cat ${LOG_FILE}" + #openim::color::echo $COLOR_RED "OpenIM Stderr Log >> cat ${STDERR_LOG_FILE}" cat "$TMP_LOG_FILE" | awk '{print "\033[31m" $0 "\033[0m"}' return 1 else @@ -599,33 +599,36 @@ openim::util::stop_services_with_name() { # An array to collect information about processes that were stopped. local stopped=() - echo "Stopping services with names: $*" # Iterate over each given service name. for server_name in "$@"; do # Use the `pgrep` command to find process IDs related to the given service name. local pids=$(pgrep -f "$server_name") - # If no process was found with the name, add it to the not_stopped list if [[ -z $pids ]]; then not_stopped+=("$server_name") continue fi local stopped_this_time=false - for pid in $pids; do + for pid in $pids; do - # Exclude the PID of the current script - if [[ "$pid" == "$$" ]]; then - continue - fi + # Exclude the PID of the current script + if [[ "$pid" == "$$" ]]; then + continue + fi + + # If there's a Process ID, it means the service with the name is running. + if [[ -n $pid ]]; then + # Print the binary path for the PID + binary_path=$(readlink -f /proc/$pid/exe) + openim::log::colorless "stop PID $pid full path: $binary_path" + + # Try to stop the service by killing its process. + if kill -15 $pid 2>/dev/null; then + stopped_this_time=true + fi + fi + done - # If there's a Process ID, it means the service with the name is running. - if [[ -n $pid ]]; then - # Try to stop the service by killing its process. - if kill -15 $pid 2>/dev/null; then - stopped_this_time=true - fi - fi - done if $stopped_this_time; then stopped+=("$server_name") @@ -2848,6 +2851,46 @@ function openim::util::check_process_names_for_stop() { +function openim::util::find_process_ports() { + local process_path="$1" + if [[ -z "$process_path" ]]; then + echo "Usage: find_process_ports /path/to/process" + return 1 + fi + + local protocol_ports="" + while read -r line; do + local port_protocol=($line) + local port=${port_protocol[0]##*:} + local protocol=${port_protocol[1]} + protocol_ports="${protocol_ports}${protocol} ${port}, " + + done < <(lsof -nP -iTCP -iUDP | grep LISTEN | grep "$(pgrep -f "$process_path")" | awk '{print $9, $8}') + + protocol_ports=${protocol_ports%, } + + if [[ -z "$protocol_ports" ]]; then + openim::log::colorless "$process_path is not listening on any ports" + else + openim::log::colorless "$process_path is listening on protocol & port: $protocol_ports" + fi +} + + + + + +function openim::util::find_ports_for_all_services() { + local services=("$@") + for service in "${services[@]}"; do + openim::util::find_process_ports "$service" + done +} + + + + + if [[ "$*" =~ openim::util:: ]];then eval $* fi diff --git a/scripts/list-feature-tests.sh b/scripts/list-feature-tests.sh index d6eaa48731..f48a7a7e3c 100755 --- a/scripts/list-feature-tests.sh +++ b/scripts/list-feature-tests.sh @@ -19,8 +19,5 @@ # Usage: `scripts/list-feature-tests.sh`. - - - OPENIM_ROOT=$(dirname "${BASH_SOURCE[0]}")/.. grep "\[Feature:\w+\]" "${OPENIM_ROOT}"/test/e2e/**/*.go -Eoh | LC_ALL=C sort -u \ No newline at end of file diff --git a/scripts/make-rules/gen.mk b/scripts/make-rules/gen.mk index 1671fafffe..fba0132ff5 100644 --- a/scripts/make-rules/gen.mk +++ b/scripts/make-rules/gen.mk @@ -88,11 +88,6 @@ gen.docgo.check: gen.docgo.doc gen.docgo.add: @git ls-files --others '*/doc.go' | $(XARGS) -- git add -## gen.docgo: Generate missing doc.go for go packages ✨ -.PHONY: gen.defaultconfigs -gen.defaultconfigs: - @${ROOT_DIR}/scripts/gen_default_config.sh - ## gen.docgo: Generate missing doc.go for go packages ✨ .PHONY: gen.clean gen.clean: @@ -101,5 +96,5 @@ gen.clean: ## gen.help: show help for gen .PHONY: gen.help -gen.help: scripts/make-rules/gen.mk +gen.help: scripts/make-rules/gen.m $(call smallhelp) \ No newline at end of file diff --git a/scripts/make-rules/golang.mk b/scripts/make-rules/golang.mk index d6de8e3465..cdc5a5fc95 100644 --- a/scripts/make-rules/golang.mk +++ b/scripts/make-rules/golang.mk @@ -104,25 +104,25 @@ go.build: go.build.verify $(addprefix go.build., $(addprefix $(PLATFORM)., $(BIN ## go.start: Start openim .PHONY: go.start go.start: - @echo "===========> Starting openim" + @echo "=========================> Starting OpenIM <=========================" @$(ROOT_DIR)/scripts/start-all.sh ## go.stop: Stop openim .PHONY: go.stop go.stop: - @echo "===========> Stopping openim" + @echo "=========================> Stopping OpenIM <=========================" @$(ROOT_DIR)/scripts/stop-all.sh ## go.check: Check openim .PHONY: go.check go.check: - @echo "===========> Checking openim" + @echo "=========================> Checking OpenIM <=========================" @$(ROOT_DIR)/scripts/check-all.sh ## go.check-component: Check openim component .PHONY: go.check-component go.check-component: - @echo "===========> Checking openim component" + @echo "=========================> Checking OpenIM component <=========================" @$(ROOT_DIR)/scripts/install/openim-tools.sh openim::tools::pre-start ## go.versionchecker: Design, detect some environment variables and versions diff --git a/scripts/mongo-init.sh b/scripts/mongo-init.sh index 41d9ca0aae..01199c4806 100755 --- a/scripts/mongo-init.sh +++ b/scripts/mongo-init.sh @@ -12,19 +12,37 @@ # See the License for the specific language governing permissions and # limitations under the License. -set -e - mongosh <> ${DOCKER_LOG_FILE} 2>&1 fi - - openim::golang::check_openim_binaries if [[ $? -ne 0 ]]; then openim::log::error "OpenIM binaries are not found. Please run 'make build' to build binaries." "${OPENIM_ROOT}"/scripts/build-all-service.sh fi - "${OPENIM_ROOT}"/scripts/init-config.sh --skip #openim::log::print_blue "Execute the following script in sequence: ${OPENIM_SERVER_SCRIPTARIES[@]}" - # TODO Prelaunch tools, simple for now, can abstract functions later TOOLS_START_SCRIPTS_PATH=${START_SCRIPTS_PATH}/openim-tools.sh -openim::log::print_blue "\n## Pre Starting OpenIM services" - - - -if ! ${TOOLS_START_SCRIPTS_PATH} openim::tools::pre-start; then - openim::log::error "Pre Starting OpenIM services failed, aborting..." - exit 1 -fi +openim::log::status "Start the pre-start tools:" +# if ! ${TOOLS_START_SCRIPTS_PATH} openim::tools::pre-start; then +# openim::log::error "Start the pre-start tools, aborting!" +# exit 1 +# fi -openim::log::print_blue "Pre Starting OpenIM services processed successfully" +openim::log::colorless "pre-start has been successfully completed!" result=$("${OPENIM_ROOT}"/scripts/stop-all.sh) if [[ $? -ne 0 ]]; then @@ -102,28 +82,28 @@ if [[ $? -ne 0 ]]; then exit 1 fi - - -openim::log::status "\n## Starting openim scripts: " +openim::log::status "Start the OpenIM startup scripts: " execute_start_scripts +openim::log::status "OpenIM startup scripts have been successfully completed!" sleep 2 result=$(. $(dirname ${BASH_SOURCE})/install/openim-msgtransfer.sh openim::msgtransfer::check) if [[ $? -ne 0 ]]; then - openim::log::error "The program may fail to start.\n $result" + openim::log::error "The OpenIM services may fail to start.\n $result" exit 1 fi - result=$(openim::util::check_process_names ${OPENIM_ALL_SERVICE_LIBRARIES_NO_TRANSFER[@]}) if [[ $? -ne 0 ]]; then - openim::log::error "The program may fail to start.\n $result" + openim::log::error "The OpenIM services may fail to start.\n $result" exit 1 fi +openim::log::status "Start the post-start tools:" +# ${TOOLS_START_SCRIPTS_PATH} openim::tools::post-start +openim::log::status "post-start has been successfully completed!" +openim::util::find_ports_for_all_services ${OPENIM_ALL_SERVICE_LIBRARIES_NO_TRANSFER[@]} +openim::util::find_ports_for_all_services ${OPENIM_MSGTRANSFER_BINARY[@]} -openim::log::info "\n## Post Starting openim services" -${TOOLS_START_SCRIPTS_PATH} openim::tools::post-start - -openim::log::success "All openim services have been successfully started!" \ No newline at end of file +openim::log::success "All OpenIM services have been successfully started!" \ No newline at end of file diff --git a/test/e2e/framework/helpers/chat/chat.go b/test/e2e/framework/helpers/chat/chat.go index aa37c34b55..0613ff5699 100644 --- a/test/e2e/framework/helpers/chat/chat.go +++ b/test/e2e/framework/helpers/chat/chat.go @@ -38,7 +38,6 @@ func main() { // } latestVersion := defaultTemplateVersion - // getLatestVersion // getLatestVersion // Construct the download URL @@ -101,9 +100,8 @@ func main() { select {} } -// getLatestVersion fetches the latest version number from a given URL. /* func getLatestVersion(url string) (string, error) { - resp, err := http.Get(url) + resp, err := webhook.Get(url) if err != nil { return "", err } diff --git a/tools/changelog/go.mod b/tools/changelog/go.mod deleted file mode 100644 index b5a2272a41..0000000000 --- a/tools/changelog/go.mod +++ /dev/null @@ -1,3 +0,0 @@ -module github.com/openimsdk/open-im-server/v3/tools/changelog - -go 1.19 diff --git a/tools/changelog/changelog.go b/tools/changelog/main.go similarity index 100% rename from tools/changelog/changelog.go rename to tools/changelog/main.go diff --git a/tools/check-component/main.go b/tools/check-component/main.go new file mode 100644 index 0000000000..d3225abb8e --- /dev/null +++ b/tools/check-component/main.go @@ -0,0 +1,165 @@ +// 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 main + +import ( + "context" + "flag" + "fmt" + "github.com/openimsdk/open-im-server/v3/pkg/common/cmd" + "github.com/openimsdk/open-im-server/v3/pkg/common/config" + "github.com/openimsdk/tools/db/mongoutil" + "github.com/openimsdk/tools/db/redisutil" + "github.com/openimsdk/tools/discovery/zookeeper" + "github.com/openimsdk/tools/mq/kafka" + "github.com/openimsdk/tools/s3/minio" + "github.com/openimsdk/tools/system/program" + "io/ioutil" + "log" + "os" + "path/filepath" + "time" +) + +const maxRetry = 180 + +func CheckZookeeper(ctx context.Context, config *config.ZooKeeper) error { + // Temporary disable logging + originalLogger := log.Default().Writer() + log.SetOutput(ioutil.Discard) + defer log.SetOutput(originalLogger) // Ensure logging is restored + return zookeeper.Check(ctx, config.Address, config.Schema, zookeeper.WithUserNameAndPassword(config.Username, config.Password)) +} + +func CheckMongo(ctx context.Context, config *config.Mongo) error { + return mongoutil.Check(ctx, config.Build()) +} + +func CheckRedis(ctx context.Context, config *config.Redis) error { + return redisutil.Check(ctx, config.Build()) +} + +func CheckMinIO(ctx context.Context, config *config.Minio) error { + return minio.Check(ctx, config.Build()) +} + +func CheckKafka(ctx context.Context, conf *config.Kafka) error { + return kafka.Check(ctx, conf.Build(), []string{conf.ToMongoTopic, conf.ToRedisTopic, conf.ToPushTopic}) +} + +func initConfig(configDir string) (*config.Mongo, *config.Redis, *config.Kafka, *config.Minio, *config.ZooKeeper, error) { + var ( + mongoConfig = &config.Mongo{} + redisConfig = &config.Redis{} + kafkaConfig = &config.Kafka{} + minioConfig = &config.Minio{} + zookeeperConfig = &config.ZooKeeper{} + ) + err := config.LoadConfig(filepath.Join(configDir, cmd.MongodbConfigFileName), cmd.ConfigEnvPrefixMap[cmd.MongodbConfigFileName], mongoConfig) + if err != nil { + return nil, nil, nil, nil, nil, err + } + + err = config.LoadConfig(filepath.Join(configDir, cmd.RedisConfigFileName), cmd.ConfigEnvPrefixMap[cmd.RedisConfigFileName], redisConfig) + if err != nil { + return nil, nil, nil, nil, nil, err + } + + err = config.LoadConfig(filepath.Join(configDir, cmd.KafkaConfigFileName), cmd.ConfigEnvPrefixMap[cmd.KafkaConfigFileName], kafkaConfig) + if err != nil { + return nil, nil, nil, nil, nil, err + } + + err = config.LoadConfig(filepath.Join(configDir, cmd.MinioConfigFileName), cmd.ConfigEnvPrefixMap[cmd.MinioConfigFileName], minioConfig) + if err != nil { + return nil, nil, nil, nil, nil, err + } + + err = config.LoadConfig(filepath.Join(configDir, cmd.ZookeeperConfigFileName), cmd.ConfigEnvPrefixMap[cmd.ZookeeperConfigFileName], zookeeperConfig) + if err != nil { + return nil, nil, nil, nil, nil, err + } + return mongoConfig, redisConfig, kafkaConfig, minioConfig, zookeeperConfig, nil +} + +func main() { + 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("%s Index: %d, Config Path: %s\n", filepath.Base(os.Args[0]), index, configDir) + + mongoConfig, redisConfig, kafkaConfig, minioConfig, zookeeperConfig, err := initConfig(configDir) + if err != nil { + program.ExitWithError(err) + } + + ctx := context.Background() + err = performChecks(ctx, mongoConfig, redisConfig, kafkaConfig, minioConfig, zookeeperConfig, maxRetry) + if err != nil { + // Assume program.ExitWithError logs the error and exits. + // Replace with your error handling logic as necessary. + program.ExitWithError(err) + } +} + +func performChecks(ctx context.Context, mongoConfig *config.Mongo, redisConfig *config.Redis, kafkaConfig *config.Kafka, minioConfig *config.Minio, zookeeperConfig *config.ZooKeeper, maxRetry int) error { + checksDone := make(map[string]bool) + + checks := map[string]func() error{ + "Zookeeper": func() error { + return CheckZookeeper(ctx, zookeeperConfig) + }, + "Mongo": func() error { + return CheckMongo(ctx, mongoConfig) + }, + "Redis": func() error { + return CheckRedis(ctx, redisConfig) + }, + "MinIO": func() error { + return CheckMinIO(ctx, minioConfig) + }, + "Kafka": func() error { + return CheckKafka(ctx, kafkaConfig) + }, + } + + for i := 0; i < maxRetry; i++ { + allSuccess := true + for name, check := range checks { + if !checksDone[name] { + if err := check(); err != nil { + fmt.Printf("%s check failed: %v\n", name, err) + allSuccess = false + } else { + fmt.Printf("%s check succeeded.\n", name) + checksDone[name] = true + } + } + } + + if allSuccess { + fmt.Println("All components checks passed successfully.") + return nil + } + + time.Sleep(1 * time.Second) + } + + return fmt.Errorf("not all components checks passed successfully after %d attempts", maxRetry) +} diff --git a/tools/check-free-memory/main.go b/tools/check-free-memory/main.go new file mode 100644 index 0000000000..e182a15443 --- /dev/null +++ b/tools/check-free-memory/main.go @@ -0,0 +1,26 @@ +package main + +import ( + "fmt" + "os" + + "github.com/shirou/gopsutil/mem" +) + +func main() { + vMem, err := mem.VirtualMemory() + if err != nil { + fmt.Fprintf(os.Stderr, "Failed to get virtual memory info: %v\n", err) + os.Exit(1) + } + + // Use the Available field to get the available memory + availableMemoryGB := float64(vMem.Available) / float64(1024*1024*1024) + + if availableMemoryGB < 1.0 { + fmt.Fprintf(os.Stderr, "System available memory is less than 1GB: %.2fGB\n", availableMemoryGB) + os.Exit(1) + } else { + fmt.Printf("System available memory is sufficient: %.2fGB\n", availableMemoryGB) + } +} diff --git a/tools/component/component.go b/tools/component/component.go deleted file mode 100644 index e1f86e1207..0000000000 --- a/tools/component/component.go +++ /dev/null @@ -1,400 +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 main - -import ( - "errors" - "flag" - "fmt" - "os" - "strconv" - "strings" - "time" - - "github.com/IBM/sarama" - - "github.com/openimsdk/open-im-server/v3/pkg/common/kafka" - - "github.com/OpenIMSDK/tools/component" - "github.com/OpenIMSDK/tools/errs" - - "gopkg.in/yaml.v3" - - "github.com/openimsdk/open-im-server/v3/pkg/common/config" -) - -const ( - // defaultCfgPath is the default path of the configuration file. - defaultCfgPath = "../../../../../config/config.yaml" - maxRetry = 100 -) - -var ( - cfgPath = flag.String("c", defaultCfgPath, "Path to the configuration file") -) - -func initCfg() (*config.GlobalConfig, error) { - data, err := os.ReadFile(*cfgPath) - if err != nil { - return nil, errs.Wrap(err, "ReadFile unmarshal failed") - } - - conf := config.NewGlobalConfig() - err = yaml.Unmarshal(data, &conf) - if err != nil { - return nil, errs.Wrap(err, "InitConfig unmarshal failed") - } - return conf, nil -} - -type checkFunc struct { - name string - function func(*config.GlobalConfig) error - flag bool - config *config.GlobalConfig -} - -// colorErrPrint prints formatted string in red to stderr -func colorErrPrint(msg string) { - // ANSI escape code for red text - const redColor = "\033[31m" - // ANSI escape code to reset color - const resetColor = "\033[0m" - msg = redColor + msg + resetColor - // Print to stderr in red - fmt.Fprintf(os.Stderr, "%s\n", msg) -} - -func colorSuccessPrint(format string, a ...interface{}) { - // ANSI escape code for green text is \033[32m - // \033[0m resets the color - fmt.Printf("\033[32m"+format+"\033[0m", a...) -} - -func main() { - flag.Parse() - - conf, err := initCfg() - if err != nil { - fmt.Printf("Read config failed: %v\n", err) - return - } - - err = configGetEnv(conf) - if err != nil { - fmt.Printf("configGetEnv failed, err:%v", err) - return - } - - checks := []checkFunc{ - {name: "Mongo", function: checkMongo, config: conf}, - {name: "Redis", function: checkRedis, config: conf}, - {name: "Zookeeper", function: checkZookeeper, config: conf}, - {name: "Kafka", function: checkKafka, config: conf}, - } - if conf.Object.Enable == "minio" { - checks = append(checks, checkFunc{name: "Minio", function: checkMinio, config: conf}) - } - - for i := 0; i < maxRetry; i++ { - if i != 0 { - time.Sleep(1 * time.Second) - } - fmt.Printf("Checking components round %v...\n", i+1) - - var err error - allSuccess := true - for index, check := range checks { - if !check.flag { - err = check.function(check.config) - if err != nil { - allSuccess = false - colorErrPrint(fmt.Sprintf("Check component: %s, failed: %v", check.name, err.Error())) - - if check.name == "Minio" { - if errors.Is(err, errMinioNotEnabled) || - errors.Is(err, errSignEndPoint) || - errors.Is(err, errApiURL) { - checks[index].flag = true - continue - } - break - } - } else { - checks[index].flag = true - component.SuccessPrint(fmt.Sprintf("%s connected successfully", check.name)) - } - } - - } - if allSuccess { - component.SuccessPrint("All components started successfully!") - return - } - } - component.ErrorPrint("Some components checked failed!") - os.Exit(-1) -} - -var errMinioNotEnabled = errors.New("minio.Enable is not configured to use MinIO") - -var errSignEndPoint = errors.New("minio.signEndPoint contains 127.0.0.1, causing issues with image sending") -var errApiURL = errors.New("object.apiURL contains 127.0.0.1, causing issues with image sending") - -// checkMongo checks the MongoDB connection without retries -func checkMongo(config *config.GlobalConfig) error { - mongoStu := &component.Mongo{ - URL: config.Mongo.Uri, - Address: config.Mongo.Address, - Database: config.Mongo.Database, - Username: config.Mongo.Username, - Password: config.Mongo.Password, - MaxPoolSize: config.Mongo.MaxPoolSize, - } - err := component.CheckMongo(mongoStu) - - return err -} - -// checkRedis checks the Redis connection -func checkRedis(config *config.GlobalConfig) error { - redisStu := &component.Redis{ - Address: config.Redis.Address, - Username: config.Redis.Username, - Password: config.Redis.Password, - } - err := component.CheckRedis(redisStu) - return err -} - -// checkMinio checks the MinIO connection -func checkMinio(config *config.GlobalConfig) error { - if strings.Contains(config.Object.ApiURL, "127.0.0.1") { - return errs.Wrap(errApiURL) - } - if config.Object.Enable != "minio" { - return errs.Wrap(errMinioNotEnabled) - } - if strings.Contains(config.Object.Minio.Endpoint, "127.0.0.1") { - return errs.Wrap(errSignEndPoint) - } - - minio := &component.Minio{ - ApiURL: config.Object.ApiURL, - Endpoint: config.Object.Minio.Endpoint, - AccessKeyID: config.Object.Minio.AccessKeyID, - SecretAccessKey: config.Object.Minio.SecretAccessKey, - SignEndpoint: config.Object.Minio.SignEndpoint, - UseSSL: getEnv("MINIO_USE_SSL", "false"), - } - err := component.CheckMinio(minio) - return err -} - -// checkZookeeper checks the Zookeeper connection -func checkZookeeper(config *config.GlobalConfig) error { - zkStu := &component.Zookeeper{ - Schema: config.Zookeeper.Schema, - ZkAddr: config.Zookeeper.ZkAddr, - Username: config.Zookeeper.Username, - Password: config.Zookeeper.Password, - } - err := component.CheckZookeeper(zkStu) - return err -} - -// checkKafka checks the Kafka connection -func checkKafka(config *config.GlobalConfig) error { - // Prioritize environment variables - kafkaStu := &component.Kafka{ - Username: config.Kafka.Username, - Password: config.Kafka.Password, - Addr: config.Kafka.Addr, - } - - kafkaClient, err := component.CheckKafka(kafkaStu) - if err != nil { - return err - } - defer kafkaClient.Close() - - // Verify if necessary topics exist - topics, err := kafkaClient.Topics() - if err != nil { - return errs.Wrap(err) - } - - requiredTopics := []string{ - config.Kafka.MsgToMongo.Topic, - config.Kafka.MsgToPush.Topic, - config.Kafka.LatestMsgToRedis.Topic, - } - - for _, requiredTopic := range requiredTopics { - if !isTopicPresent(requiredTopic, topics) { - return errs.Wrap(err, fmt.Sprintf("Kafka doesn't contain topic: %v", requiredTopic)) - } - } - - var tlsConfig *kafka.TLSConfig - if config.Kafka.TLS != nil { - tlsConfig = &kafka.TLSConfig{ - CACrt: config.Kafka.TLS.CACrt, - ClientCrt: config.Kafka.TLS.ClientCrt, - ClientKey: config.Kafka.TLS.ClientKey, - ClientKeyPwd: config.Kafka.TLS.ClientKeyPwd, - InsecureSkipVerify: config.Kafka.TLS.InsecureSkipVerify, - } - } - - _, err = kafka.NewMConsumerGroup(&kafka.MConsumerGroupConfig{ - KafkaVersion: sarama.V2_0_0_0, - OffsetsInitial: sarama.OffsetNewest, - IsReturnErr: false, - UserName: config.Kafka.Username, - Password: config.Kafka.Password, - }, []string{config.Kafka.LatestMsgToRedis.Topic}, - config.Kafka.Addr, config.Kafka.ConsumerGroupID.MsgToRedis, tlsConfig) - if err != nil { - return err - } - - _, err = kafka.NewMConsumerGroup(&kafka.MConsumerGroupConfig{ - KafkaVersion: sarama.V2_0_0_0, - OffsetsInitial: sarama.OffsetNewest, IsReturnErr: false, - }, []string{config.Kafka.MsgToMongo.Topic}, - config.Kafka.Addr, config.Kafka.ConsumerGroupID.MsgToMongo, tlsConfig) - if err != nil { - return err - } - - _, err = kafka.NewMConsumerGroup(&kafka.MConsumerGroupConfig{ - KafkaVersion: sarama.V2_0_0_0, - OffsetsInitial: sarama.OffsetNewest, IsReturnErr: false, - }, []string{config.Kafka.MsgToPush.Topic}, config.Kafka.Addr, - config.Kafka.ConsumerGroupID.MsgToPush, tlsConfig) - if err != nil { - return err - } - - return nil -} - -// isTopicPresent checks if a topic is present in the list of topics -func isTopicPresent(topic string, topics []string) bool { - for _, t := range topics { - if t == topic { - return true - } - } - return false -} - -func configGetEnv(config *config.GlobalConfig) error { - config.Mongo.Uri = getEnv("MONGO_URI", config.Mongo.Uri) - config.Mongo.Username = getEnv("MONGO_OPENIM_USERNAME", config.Mongo.Username) - config.Mongo.Password = getEnv("MONGO_OPENIM_PASSWORD", config.Mongo.Password) - config.Mongo.Address = getArrEnv("MONGO_ADDRESS", "MONGO_PORT", config.Mongo.Address) - config.Mongo.Database = getEnv("MONGO_DATABASE", config.Mongo.Database) - maxPoolSize, err := getEnvInt("MONGO_MAX_POOL_SIZE", config.Mongo.MaxPoolSize) - if err != nil { - return errs.Wrap(err, "MONGO_MAX_POOL_SIZE") - } - config.Mongo.MaxPoolSize = maxPoolSize - - config.Redis.Username = getEnv("REDIS_USERNAME", config.Redis.Username) - config.Redis.Password = getEnv("REDIS_PASSWORD", config.Redis.Password) - config.Redis.Address = getArrEnv("REDIS_ADDRESS", "REDIS_PORT", config.Redis.Address) - - config.Object.ApiURL = getEnv("OBJECT_APIURL", config.Object.ApiURL) - config.Object.Minio.Endpoint = getEnv("MINIO_ENDPOINT", config.Object.Minio.Endpoint) - config.Object.Minio.AccessKeyID = getEnv("MINIO_ACCESS_KEY_ID", config.Object.Minio.AccessKeyID) - config.Object.Minio.SecretAccessKey = getEnv("MINIO_SECRET_ACCESS_KEY", config.Object.Minio.SecretAccessKey) - config.Object.Minio.SignEndpoint = getEnv("MINIO_SIGN_ENDPOINT", config.Object.Minio.SignEndpoint) - - config.Zookeeper.Schema = getEnv("ZOOKEEPER_SCHEMA", config.Zookeeper.Schema) - config.Zookeeper.ZkAddr = getArrEnv("ZOOKEEPER_ADDRESS", "ZOOKEEPER_PORT", config.Zookeeper.ZkAddr) - config.Zookeeper.Username = getEnv("ZOOKEEPER_USERNAME", config.Zookeeper.Username) - config.Zookeeper.Password = getEnv("ZOOKEEPER_PASSWORD", config.Zookeeper.Password) - - config.Kafka.Username = getEnv("KAFKA_USERNAME", config.Kafka.Username) - config.Kafka.Password = getEnv("KAFKA_PASSWORD", config.Kafka.Password) - config.Kafka.Addr = getArrEnv("KAFKA_ADDRESS", "KAFKA_PORT", config.Kafka.Addr) - config.Object.Minio.Endpoint = getMinioAddr("MINIO_ENDPOINT", "MINIO_ADDRESS", "MINIO_PORT", config.Object.Minio.Endpoint) - return nil -} - -func getMinioAddr(key1, key2, key3, fallback string) string { - // Prioritize environment variables - endpoint := getEnv(key1, fallback) - address, addressExist := os.LookupEnv(key2) - port, portExist := os.LookupEnv(key3) - if portExist && addressExist { - endpoint = "http://" + address + ":" + port - return endpoint - } - return endpoint -} - -// Helper function to get environment variable or default value -func getEnv(key, fallback string) string { - if value, exists := os.LookupEnv(key); exists { - return value - } - return fallback -} - -// Helper function to get environment variable or default value -func getEnvInt(key string, fallback int) (int, error) { - if value, exists := os.LookupEnv(key); exists { - val, err := strconv.Atoi(value) - if err != nil { - return 0, errs.Wrap(err, "string to int failed") - } - return val, nil - } - return fallback, nil -} - -func getArrEnv(key1, key2 string, fallback []string) []string { - address, addrExists := os.LookupEnv(key1) - port, portExists := os.LookupEnv(key2) - - if addrExists && portExists { - addresses := strings.Split(address, ",") - for i, addr := range addresses { - addresses[i] = addr + ":" + port - } - return addresses - } - - if addrExists && !portExists { - addresses := strings.Split(address, ",") - for i, addr := range addresses { - addresses[i] = addr + ":" + "0" - } - return addresses - } - - if !addrExists && portExists { - result := make([]string, len(fallback)) - for i, addr := range fallback { - add := strings.Split(addr, ":") - result[i] = add[0] + ":" + port - } - return result - } - return fallback -} diff --git a/tools/component/component_test.go b/tools/component/component_test.go deleted file mode 100644 index c56361b2c0..0000000000 --- a/tools/component/component_test.go +++ /dev/null @@ -1,65 +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 main - -import ( - "context" - "strconv" - "testing" - "time" - - "github.com/redis/go-redis/v9" -) - -func TestRedis(t *testing.T) { - conf, err := initCfg() - conf.Redis.Address = []string{ - "172.16.8.142:7000", - //"172.16.8.142:7000", "172.16.8.142:7001", "172.16.8.142:7002", "172.16.8.142:7003", "172.16.8.142:7004", "172.16.8.142:7005", - } - - var redisClient redis.UniversalClient - defer func() { - if redisClient != nil { - redisClient.Close() - } - }() - if len(conf.Redis.Address) > 1 { - redisClient = redis.NewClusterClient(&redis.ClusterOptions{ - Addrs: conf.Redis.Address, - Username: conf.Redis.Username, - Password: conf.Redis.Password, - }) - } else { - redisClient = redis.NewClient(&redis.Options{ - Addr: conf.Redis.Address[0], - Username: conf.Redis.Username, - Password: conf.Redis.Password, - }) - } - _, err = redisClient.Ping(context.Background()).Result() - if err != nil { - t.Fatal(err) - } - - for i := 0; i < 1000000; i++ { - val, err := redisClient.Set(context.Background(), "b_"+strconv.Itoa(i), "test", time.Second*10).Result() - t.Log("index", i, "resp", val, "err", err) - if err != nil { - return - } - } - -} diff --git a/tools/component/go.mod b/tools/component/go.mod deleted file mode 100644 index 05a27bcad6..0000000000 --- a/tools/component/go.mod +++ /dev/null @@ -1,3 +0,0 @@ -module github.com/openimsdk/open-im-server/v3/tools/component - -go 1.19 diff --git a/tools/imctl/go.mod b/tools/imctl/go.mod deleted file mode 100644 index e3a720b27f..0000000000 --- a/tools/imctl/go.mod +++ /dev/null @@ -1,18 +0,0 @@ -module github.com/openimsdk/open-im-server/v3/tools/imctl - -go 1.19 - -require ( - github.com/MakeNowJust/heredoc/v2 v2.0.1 - github.com/mitchellh/go-wordwrap v1.0.1 - github.com/moby/term v0.5.0 - github.com/russross/blackfriday v1.6.0 - github.com/spf13/cobra v1.7.0 - github.com/spf13/pflag v1.0.5 -) - -require ( - github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect - github.com/inconshreveable/mousetrap v1.1.0 // indirect - golang.org/x/sys v0.1.0 // indirect -) diff --git a/tools/imctl/go.sum b/tools/imctl/go.sum deleted file mode 100644 index 3d4c613430..0000000000 --- a/tools/imctl/go.sum +++ /dev/null @@ -1,24 +0,0 @@ -github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= -github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= -github.com/MakeNowJust/heredoc/v2 v2.0.1 h1:rlCHh70XXXv7toz95ajQWOWQnN4WNLt0TdpZYIR/J6A= -github.com/MakeNowJust/heredoc/v2 v2.0.1/go.mod h1:6/2Abh5s+hc3g9nbWLe9ObDIOhaRrqsyY9MWy+4JdRM= -github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= -github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= -github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= -github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= -github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0= -github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0= -github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= -github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= -github.com/russross/blackfriday v1.6.0 h1:KqfZb0pUVN2lYqZUYRddxF4OR8ZMURnJIG5Y3VRLtww= -github.com/russross/blackfriday v1.6.0/go.mod h1:ti0ldHuxg49ri4ksnFxlkCfN+hvslNlmVHqNRXXJNAY= -github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I= -github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= -github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= -github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U= -golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/tools/imctl/imctl.go b/tools/imctl/main.go similarity index 100% rename from tools/imctl/imctl.go rename to tools/imctl/main.go diff --git a/tools/infra/go.mod b/tools/infra/go.mod deleted file mode 100644 index 8c66e2654d..0000000000 --- a/tools/infra/go.mod +++ /dev/null @@ -1,11 +0,0 @@ -module github.com/openimsdk/open-im-server/v3/tools/infra - -go 1.19 - -require github.com/fatih/color v1.15.0 - -require ( - github.com/mattn/go-colorable v0.1.13 // indirect - github.com/mattn/go-isatty v0.0.17 // indirect - golang.org/x/sys v0.6.0 // indirect -) diff --git a/tools/infra/go.sum b/tools/infra/go.sum deleted file mode 100644 index 2624c9db06..0000000000 --- a/tools/infra/go.sum +++ /dev/null @@ -1,10 +0,0 @@ -github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= -github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= -github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= -github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= -github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= -github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= -golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= diff --git a/tools/infra/infra.go b/tools/infra/main.go similarity index 90% rename from tools/infra/infra.go rename to tools/infra/main.go index bc01a00eb6..f6225a352e 100644 --- a/tools/infra/infra.go +++ b/tools/infra/main.go @@ -25,13 +25,14 @@ func printLinks() { blue := color.New(color.FgBlue).SprintFunc() fmt.Printf("OpenIM Github: %s\n", blue("https://github.com/OpenIMSDK/Open-IM-Server")) fmt.Printf("Slack Invitation: %s\n", blue("https://openimsdk.slack.com")) + fmt.Printf("Follow Twitter: %s\n", blue("https://twitter.com/founder_im63606")) } func main() { yellow := color.New(color.FgYellow) blue := color.New(color.FgBlue, color.Bold) - yellow.Println("Current module is still under development.") + yellow.Println("Please use the release branch or tag for production environments!") message := ` ____ _____ __ __ diff --git a/tools/ncpu/go.mod b/tools/ncpu/go.mod deleted file mode 100644 index 66697e3501..0000000000 --- a/tools/ncpu/go.mod +++ /dev/null @@ -1,5 +0,0 @@ -module github.com/openimsdk/open-im-server/v3/tools/ncpu - -go 1.19 - -require go.uber.org/automaxprocs v1.5.3 diff --git a/tools/ncpu/go.sum b/tools/ncpu/go.sum deleted file mode 100644 index 804f593b54..0000000000 --- a/tools/ncpu/go.sum +++ /dev/null @@ -1,7 +0,0 @@ -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g= -github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY= -go.uber.org/automaxprocs v1.5.3 h1:kWazyxZUrS3Gs4qUpbwo5kEIMGe/DAvi5Z4tl2NW4j8= -go.uber.org/automaxprocs v1.5.3/go.mod h1:eRbA25aqJrxAbsLO0xy5jVwPt7FQnRgjW+efnwa1WM0= -gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/tools/ncpu/ncpu.go b/tools/ncpu/main.go similarity index 100% rename from tools/ncpu/ncpu.go rename to tools/ncpu/main.go diff --git a/tools/ncpu/ncpu_test.go b/tools/ncpu/main_test.go similarity index 100% rename from tools/ncpu/ncpu_test.go rename to tools/ncpu/main_test.go diff --git a/tools/openim-web/Dockerfile b/tools/openim-web/Dockerfile deleted file mode 100644 index 2e0cd9e8e0..0000000000 --- a/tools/openim-web/Dockerfile +++ /dev/null @@ -1,47 +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. - -# 使用官方Go镜像作为基础镜像 -FROM golang:1.21 AS build-env -ENV CGO_ENABLED=0 -# 设置工作目录 -WORKDIR /app - -# 安装curl和unzip工具 -#RUN apt-get update && apt-get install -y curl unzip - -# 从GitHub下载并解压dist.zip -#RUN curl -LO https://github.com/OpenIMSDK/dist.zip \ - # && unzip dist.zip -d ./ \ - # && rm dist.zip - -# 复制Go代码到容器 -COPY . . - -# 编译Go代码 -RUN go build -o openim-web - -# 使用轻量级的基础镜像 -FROM debian:buster-slim - -# 将编译好的二进制文件和dist资源复制到新的容器 -WORKDIR /app -COPY --from=build-env /app/openim-web /app/openim-web -COPY --from=build-env /app/dist /app/dist - -# 开放容器的20001端口 -EXPOSE 20001 - -# 指定容器启动命令 -ENTRYPOINT ["/app/openim-web"] \ No newline at end of file diff --git a/tools/openim-web/README.md b/tools/openim-web/README.md deleted file mode 100644 index 5794a946de..0000000000 --- a/tools/openim-web/README.md +++ /dev/null @@ -1,78 +0,0 @@ -# OpenIM Web Service - -- [OpenIM Web Service](#openim-web-service) - - [Overview](#overview) - - [User](#user) - - [Docker Deployment](#docker-deployment) - - [Build the Docker Image](#build-the-docker-image) - - [Run the Docker Container](#run-the-docker-container) - - [Configuration](#configuration) - - [Contributions](#contributions) - - -OpenIM Web Service is a lightweight containerized service built with Go. The service serves static files and allows customization via environment variables. - -## Overview - -- Built using Go. -- Deployed as a Docker container. -- Serves static files from a directory which can be set via an environment variable. -- The default port for the service is `20001`, but it can be customized using an environment variable. - -## User - -example: - -```bash -$ ./openim-web -h -Usage of ./openim-web: - -distPath string - Path to the distribution (default "/app/dist") - -port string - Port to run the server on (default "20001") -``` - -Variables can be set as above, Environment variables can also be set - -example: - -```bash -$ export OPENIM_WEB_PPRT="11001" -``` - -Initialize the env configuration file: - -```bash -$ make init -``` - -## Docker Deployment - -### Build the Docker Image - -Even though we've implemented automation, it's to make the developer experience easier: - -To build the Docker image for OpenIM Web Service: - -```bash -$ docker build -t openim-web . -``` - -### Run the Docker Container - -To run the service: - -```bash -$ docker run -e DIST_PATH=/app/dist -e PORT=20001 -p 20001:20001 openim-web -``` - -## Configuration - -You can configure the OpenIM Web Service using the following environment variables: - -- **DIST_PATH**: The path to the directory containing the static files. Default: `/app/dist`. -- **PORT**: The port on which the service listens. Default: `11001`. - -## Contributions - -We welcome contributions from the community. If you find any bugs or have feature suggestions, please create an issue or send a pull request. \ No newline at end of file diff --git a/tools/openim-web/go.mod b/tools/openim-web/go.mod deleted file mode 100644 index deb24f4e5d..0000000000 --- a/tools/openim-web/go.mod +++ /dev/null @@ -1,7 +0,0 @@ -module github.com/openimsdk/open-im-server/v3/tools/openim-web - -go 1.19 - -require gopkg.in/yaml.v2 v2.4.0 - -require github.com/NYTimes/gziphandler v1.1.1 // indirect diff --git a/tools/openim-web/go.sum b/tools/openim-web/go.sum deleted file mode 100644 index 54ca3deb19..0000000000 --- a/tools/openim-web/go.sum +++ /dev/null @@ -1,10 +0,0 @@ -github.com/NYTimes/gziphandler v1.1.1 h1:ZUDjpQae29j0ryrS0u/B8HZfJBtBQHjqw2rQ2cqUQ3I= -github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= -gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= diff --git a/tools/openim-web/openim-web.go b/tools/openim-web/openim-web.go deleted file mode 100644 index c913e35e76..0000000000 --- a/tools/openim-web/openim-web.go +++ /dev/null @@ -1,63 +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 main - -import ( - "flag" - "log" - "net/http" - "os" - - "github.com/NYTimes/gziphandler" -) - -var ( - distPathFlag string - portFlag string -) - -func init() { - flag.StringVar(&distPathFlag, "distPath", "/app/dist", "Path to the distribution") - flag.StringVar(&portFlag, "port", "11001", "Port to run the server on") -} - -func main() { - flag.Parse() - - distPath := getConfigValue("DIST_PATH", distPathFlag, "/app/dist") - fs := http.FileServer(http.Dir(distPath)) - - withGzip := gziphandler.GzipHandler(fs) - - http.Handle("/", withGzip) - - port := getConfigValue("PORT", portFlag, "11001") - log.Printf("Server listening on port %s in %s...", port, distPath) - err := http.ListenAndServe(":"+port, nil) - if err != nil { - log.Fatal(err) - } -} - -func getConfigValue(envKey, flagValue, fallback string) string { - envVal := os.Getenv(envKey) - if envVal != "" { - return envVal - } - if flagValue != "" { - return flagValue - } - return fallback -} diff --git a/tools/openim-web/openim-web_test.go b/tools/openim-web/openim-web_test.go deleted file mode 100644 index dd1c933167..0000000000 --- a/tools/openim-web/openim-web_test.go +++ /dev/null @@ -1,71 +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 main - -import ( - "os" - "testing" -) - -func TestGetConfigValue(t *testing.T) { - tests := []struct { - name string - envKey string - envValue string - flagValue string - fallback string - wantResult string - }{ - { - name: "environment variable set", - envKey: "TEST_KEY", - envValue: "envValue", - flagValue: "", - fallback: "default", - wantResult: "envValue", - }, - { - name: "flag set and environment variable not set", - envKey: "TEST_KEY", - envValue: "", - flagValue: "flagValue", - fallback: "default", - wantResult: "flagValue", - }, - { - name: "nothing set, use fallback", - envKey: "TEST_KEY", - envValue: "", - flagValue: "", - fallback: "default", - wantResult: "default", - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if tt.envValue != "" { - os.Setenv(tt.envKey, tt.envValue) - defer os.Unsetenv(tt.envKey) - } - - got := getConfigValue(tt.envKey, tt.flagValue, tt.fallback) - - if got != tt.wantResult { - t.Errorf("getConfigValue(%s, %s, %s) = %s; want %s", tt.envKey, tt.flagValue, tt.fallback, got, tt.wantResult) - } - }) - } -} diff --git a/tools/url2im/go.mod b/tools/url2im/go.mod deleted file mode 100644 index b6011909db..0000000000 --- a/tools/url2im/go.mod +++ /dev/null @@ -1,20 +0,0 @@ -module github.com/openimsdk/open-im-server/v3/tools/url2im - -go 1.20 - -require ( - github.com/OpenIMSDK/protocol v0.0.21 - github.com/kelindar/bitmap v1.5.1 -) - -require ( - github.com/golang/protobuf v1.5.3 // indirect - github.com/kelindar/simd v1.1.2 // indirect - github.com/klauspost/cpuid/v2 v2.2.4 // indirect - golang.org/x/net v0.17.0 // indirect - golang.org/x/sys v0.13.0 // indirect - golang.org/x/text v0.13.0 // indirect - google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect - google.golang.org/grpc v1.56.3 // indirect - google.golang.org/protobuf v1.31.0 // indirect -) diff --git a/tools/url2im/go.sum b/tools/url2im/go.sum deleted file mode 100644 index 1970dce2c7..0000000000 --- a/tools/url2im/go.sum +++ /dev/null @@ -1,33 +0,0 @@ -github.com/OpenIMSDK/protocol v0.0.21 h1:5H6H+hJ9d/VgRqttvxD/zfK9Asd+4M8Eknk5swSbUVY= -github.com/OpenIMSDK/protocol v0.0.21/go.mod h1:F25dFrwrIx3lkNoiuf6FkCfxuwf8L4Z8UIsdTHP/r0Y= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= -github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= -github.com/kelindar/bitmap v1.5.1 h1:+ZmZdwHbJ+CGE+q/aAJ74KJSnp0vOlGD7KY5x51mVzk= -github.com/kelindar/bitmap v1.5.1/go.mod h1:j3qZjxH9s4OtvsnFTP2bmPkjqil9Y2xQlxPYHexasEA= -github.com/kelindar/simd v1.1.2 h1:KduKb+M9cMY2HIH8S/cdJyD+5n5EGgq+Aeeleos55To= -github.com/kelindar/simd v1.1.2/go.mod h1:inq4DFudC7W8L5fhxoeZflLRNpWSs0GNx6MlWFvuvr0= -github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk= -github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= -golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= -golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= -golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= -golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= -golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 h1:KpwkzHKEF7B9Zxg18WzOa7djJ+Ha5DzthMyZYQfEn2A= -google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU= -google.golang.org/grpc v1.56.3 h1:8I4C0Yq1EjstUzUJzpcRVbuYA2mODtEmpWiQoN/b2nc= -google.golang.org/grpc v1.56.3/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= -google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/tools/url2im/pkg/api.go b/tools/url2im/pkg/api.go index 7575b078aa..5bf48c4ea5 100644 --- a/tools/url2im/pkg/api.go +++ b/tools/url2im/pkg/api.go @@ -18,14 +18,14 @@ import ( "bytes" "context" "encoding/json" - "errors" "fmt" "io" "net/http" - "github.com/OpenIMSDK/protocol/auth" - "github.com/OpenIMSDK/protocol/constant" - "github.com/OpenIMSDK/protocol/third" + "github.com/openimsdk/protocol/auth" + "github.com/openimsdk/protocol/constant" + "github.com/openimsdk/protocol/third" + "github.com/openimsdk/tools/errs" ) type Api struct { @@ -39,7 +39,7 @@ type Api struct { func (a *Api) apiPost(ctx context.Context, path string, req any, resp any) error { operationID, _ := ctx.Value("operationID").(string) if operationID == "" { - return errors.New("call api operationID is empty") + return errs.New("call api operationID is empty") } reqBody, err := json.Marshal(req) if err != nil { diff --git a/tools/url2im/pkg/manage.go b/tools/url2im/pkg/manage.go index 70c6713fcc..5e1626da9f 100644 --- a/tools/url2im/pkg/manage.go +++ b/tools/url2im/pkg/manage.go @@ -20,8 +20,8 @@ import ( "crypto/md5" "encoding/hex" "encoding/json" - "errors" "fmt" + "github.com/openimsdk/tools/errs" "io" "log" "net/http" @@ -34,7 +34,7 @@ import ( "sync/atomic" "time" - "github.com/OpenIMSDK/protocol/third" + "github.com/openimsdk/protocol/third" ) type Upload struct { @@ -256,10 +256,10 @@ func (m *Manage) RunTask(ctx context.Context, task Task) (string, error) { func (m *Manage) partSize(size int64) (int64, error) { if size <= 0 { - return 0, errors.New("size must be greater than 0") + return 0, errs.New("size must be greater than 0") } if size > m.partLimit.MaxPartSize*int64(m.partLimit.MaxNumSize) { - return 0, fmt.Errorf("size must be less than %db", m.partLimit.MaxPartSize*int64(m.partLimit.MaxNumSize)) + return 0, errs.New("size must be less than", "size", m.partLimit.MaxPartSize*int64(m.partLimit.MaxNumSize)) } if size <= m.partLimit.MinPartSize*int64(m.partLimit.MaxNumSize) { return m.partLimit.MinPartSize, nil @@ -392,7 +392,7 @@ func (m *Manage) HttpGet(ctx context.Context, url string) (*http.Response, error } if response.StatusCode != http.StatusOK { _ = response.Body.Close() - return nil, fmt.Errorf("http get %s status %s", url, response.Status) + return nil, fmt.Errorf("webhook get %s status %s", url, response.Status) } return response, nil } diff --git a/tools/versionchecker/go.mod b/tools/versionchecker/go.mod deleted file mode 100644 index 7c274fcf9b..0000000000 --- a/tools/versionchecker/go.mod +++ /dev/null @@ -1,11 +0,0 @@ -module github.com/openimsdk/open-im-server/v3/tools/versionchecker - -go 1.19 - -require github.com/fatih/color v1.15.0 - -require ( - github.com/mattn/go-colorable v0.1.13 // indirect - github.com/mattn/go-isatty v0.0.17 // indirect - golang.org/x/sys v0.6.0 // indirect -) diff --git a/tools/versionchecker/go.sum b/tools/versionchecker/go.sum deleted file mode 100644 index 2624c9db06..0000000000 --- a/tools/versionchecker/go.sum +++ /dev/null @@ -1,10 +0,0 @@ -github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= -github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= -github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= -github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= -github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= -github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= -golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= diff --git a/tools/versionchecker/versionchecker.go b/tools/versionchecker/main.go similarity index 82% rename from tools/versionchecker/versionchecker.go rename to tools/versionchecker/main.go index 12254b58e8..bec7daa799 100644 --- a/tools/versionchecker/versionchecker.go +++ b/tools/versionchecker/main.go @@ -19,10 +19,9 @@ import ( "fmt" "os/exec" "runtime" - "time" "github.com/fatih/color" - //"github.com/openimsdk/open-im-server/v3/pkg/common/version" + "github.com/openimsdk/tools/utils/timeutil" ) func ExecuteCommand(cmdName string, args ...string) (string, error) { @@ -40,8 +39,7 @@ func ExecuteCommand(cmdName string, args ...string) (string, error) { } func printTime() string { - currentTime := time.Now() - formattedTime := currentTime.Format("2006-01-02 15:04:05") + formattedTime := timeutil.GetCurrentTimeFormatted() return fmt.Sprintf("Current Date & Time: %s", formattedTime) } @@ -60,14 +58,6 @@ func getDockerVersion() string { return version } -func getDockerComposeVersion() string { - version, err := ExecuteCommand("docker-compose", "--version") - if err != nil { - return "Docker Compose is not installed. Please install it to get the version." - } - return version -} - func getKubernetesVersion() string { version, err := ExecuteCommand("kubectl", "version", "--client", "--short") if err != nil { @@ -101,20 +91,15 @@ func getGitVersion() string { func main() { // red := color.New(color.FgRed).SprintFunc() - green := color.New(color.FgGreen).SprintFunc() + // green := color.New(color.FgGreen).SprintFunc() blue := color.New(color.FgBlue).SprintFunc() - yellow := color.New(color.FgYellow).SprintFunc() - - fmt.Println(green(printTime())) - fmt.Println(yellow("# Diagnostic Tool Result\n")) + // yellow := color.New(color.FgYellow).SprintFunc() fmt.Println(blue("## Go Version")) fmt.Println(getGoVersion()) fmt.Println(blue("## Branch Type")) fmt.Println(getGitVersion()) fmt.Println(blue("## Docker Version")) fmt.Println(getDockerVersion()) - fmt.Println(blue("## Docker Compose Version")) - fmt.Println(getDockerComposeVersion()) fmt.Println(blue("## Kubernetes Version")) fmt.Println(getKubernetesVersion()) // fmt.Println(blue("## OpenIM Versions")) diff --git a/tools/yamlfmt/go.mod b/tools/yamlfmt/go.mod deleted file mode 100644 index 7c496a5308..0000000000 --- a/tools/yamlfmt/go.mod +++ /dev/null @@ -1,8 +0,0 @@ -module github.com/openimsdk/open-im-server/v3/tools/yamlfmt - -go 1.19 - -require ( - github.com/likexian/gokit v0.25.13 - gopkg.in/yaml.v3 v3.0.1 -) diff --git a/tools/yamlfmt/go.sum b/tools/yamlfmt/go.sum deleted file mode 100644 index 0cf090cc81..0000000000 --- a/tools/yamlfmt/go.sum +++ /dev/null @@ -1,6 +0,0 @@ -github.com/likexian/gokit v0.25.13 h1:p2Uw3+6fGG53CwdU2Dz0T6bOycdb2+bAFAa3ymwWVkM= -github.com/likexian/gokit v0.25.13/go.mod h1:qQhEWFBEfqLCO3/vOEo2EDKd+EycekVtUK4tex+l2H4= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= -gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/tools/yamlfmt/yamlfmt.go b/tools/yamlfmt/main.go similarity index 100% rename from tools/yamlfmt/yamlfmt.go rename to tools/yamlfmt/main.go diff --git a/tools/yamlfmt/yamlfmt_test.go b/tools/yamlfmt/main_test.go similarity index 100% rename from tools/yamlfmt/yamlfmt_test.go rename to tools/yamlfmt/main_test.go From 24a711213630359450bb12c6a0c261af610cc6c9 Mon Sep 17 00:00:00 2001 From: skiffer-git <72860476+skiffer-git@users.noreply.github.com> Date: Sat, 20 Apr 2024 09:17:38 +0800 Subject: [PATCH 133/188] root user for kafka --- docker-compose.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/docker-compose.yml b/docker-compose.yml index 11cc7ff132..4acd00cdd5 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -60,6 +60,7 @@ services: kafka: image: "${KAFKA_IMAGE}" container_name: kafka + user: root restart: always ports: - "19094:9094" From 42332cdd26aab5e0d2e4bc5190503c91b10852f7 Mon Sep 17 00:00:00 2001 From: skiffer-git <72860476+skiffer-git@users.noreply.github.com> Date: Sat, 20 Apr 2024 09:18:27 +0800 Subject: [PATCH 134/188] Add files via upload --- start-config.yml | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 start-config.yml diff --git a/start-config.yml b/start-config.yml new file mode 100644 index 0000000000..cd9663c98b --- /dev/null +++ b/start-config.yml @@ -0,0 +1,19 @@ +serviceBinaries: + openim-api: 1 + openim-crontask: 1 + openim-rpc-user: 1 + openim-msggateway: 1 + openim-push: 1 + openim-msgtransfer: 1 + openim-rpc-conversation: 1 + openim-rpc-auth: 1 + openim-rpc-group: 1 + openim-rpc-friend: 1 + openim-rpc-msg: 1 + openim-rpc-third: 1 +toolBinaries: + - ncpu + - check-free-memory + - versionchecker + - check-component +maxFileDescriptors: 10000 From 843a704c6f041b668cf7c6083d85c231916c9506 Mon Sep 17 00:00:00 2001 From: skiffer-git <44203734@qq.com> Date: Mon, 22 Apr 2024 15:16:42 +0800 Subject: [PATCH 135/188] remove \r --- scripts/create-topic.sh | 10 ---------- scripts/mongo-init.sh | 6 ------ 2 files changed, 16 deletions(-) diff --git a/scripts/create-topic.sh b/scripts/create-topic.sh index 206075fb83..2b0b69c07b 100755 --- a/scripts/create-topic.sh +++ b/scripts/create-topic.sh @@ -12,16 +12,11 @@ # 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. - # Wait for Kafka to be ready - KAFKA_SERVER=localhost:9092 - MAX_ATTEMPTS=300 attempt_num=1 - echo "Waiting for Kafka to be ready..." - until /opt/bitnami/kafka/bin/kafka-topics.sh --list --bootstrap-server $KAFKA_SERVER; do echo "Attempt $attempt_num of $MAX_ATTEMPTS: Kafka not ready yet..." if [ $attempt_num -eq $MAX_ATTEMPTS ]; then @@ -31,14 +26,10 @@ until /opt/bitnami/kafka/bin/kafka-topics.sh --list --bootstrap-server $KAFKA_SE attempt_num=$((attempt_num+1)) sleep 1 done - echo "Kafka is ready. Creating topics..." - - topics=("toRedis" "toMongo" "toPush") partitions=8 replicationFactor=1 - for topic in "${topics[@]}"; do if /opt/bitnami/kafka/bin/kafka-topics.sh --create \ --bootstrap-server $KAFKA_SERVER \ @@ -51,5 +42,4 @@ for topic in "${topics[@]}"; do echo "Failed to create topic $topic." fi done - echo "All topics created." diff --git a/scripts/mongo-init.sh b/scripts/mongo-init.sh index 01199c4806..de3eae5cbc 100755 --- a/scripts/mongo-init.sh +++ b/scripts/mongo-init.sh @@ -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. - mongosh < Date: Mon, 22 Apr 2024 15:26:15 +0800 Subject: [PATCH 136/188] remove \r --- scripts/create-topic.sh | 61 ++++++++++++++++++++--------------------- 1 file changed, 29 insertions(+), 32 deletions(-) diff --git a/scripts/create-topic.sh b/scripts/create-topic.sh index 2b0b69c07b..de3eae5cbc 100755 --- a/scripts/create-topic.sh +++ b/scripts/create-topic.sh @@ -1,4 +1,3 @@ -#!/usr/bin/env bash # Copyright © 2023 OpenIM. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -12,34 +11,32 @@ # 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. -# Wait for Kafka to be ready -KAFKA_SERVER=localhost:9092 -MAX_ATTEMPTS=300 -attempt_num=1 -echo "Waiting for Kafka to be ready..." -until /opt/bitnami/kafka/bin/kafka-topics.sh --list --bootstrap-server $KAFKA_SERVER; do - echo "Attempt $attempt_num of $MAX_ATTEMPTS: Kafka not ready yet..." - if [ $attempt_num -eq $MAX_ATTEMPTS ]; then - echo "Kafka not ready after $MAX_ATTEMPTS attempts, exiting" - exit 1 - fi - attempt_num=$((attempt_num+1)) - sleep 1 -done -echo "Kafka is ready. Creating topics..." -topics=("toRedis" "toMongo" "toPush") -partitions=8 -replicationFactor=1 -for topic in "${topics[@]}"; do - if /opt/bitnami/kafka/bin/kafka-topics.sh --create \ - --bootstrap-server $KAFKA_SERVER \ - --replication-factor $replicationFactor \ - --partitions $partitions \ - --topic $topic - then - echo "Topic $topic created." - else - echo "Failed to create topic $topic." - fi -done -echo "All topics created." +mongosh < Date: Mon, 22 Apr 2024 15:30:14 +0800 Subject: [PATCH 137/188] remove \r --- scripts/create-topic.sh | 71 ++++++++++++++++++++++++----------------- scripts/mongo-init.sh | 6 ++++ 2 files changed, 48 insertions(+), 29 deletions(-) diff --git a/scripts/create-topic.sh b/scripts/create-topic.sh index de3eae5cbc..206075fb83 100755 --- a/scripts/create-topic.sh +++ b/scripts/create-topic.sh @@ -1,3 +1,4 @@ +#!/usr/bin/env bash # Copyright © 2023 OpenIM. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -11,32 +12,44 @@ # 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. -mongosh < Date: Mon, 22 Apr 2024 15:35:55 +0800 Subject: [PATCH 138/188] remove \r --- scripts/create-topic.sh | 1 + scripts/mongo-init.sh | 1 + 2 files changed, 2 insertions(+) diff --git a/scripts/create-topic.sh b/scripts/create-topic.sh index 206075fb83..b6a24a73d7 100755 --- a/scripts/create-topic.sh +++ b/scripts/create-topic.sh @@ -53,3 +53,4 @@ for topic in "${topics[@]}"; do done echo "All topics created." + diff --git a/scripts/mongo-init.sh b/scripts/mongo-init.sh index 01199c4806..3fac5be4e5 100755 --- a/scripts/mongo-init.sh +++ b/scripts/mongo-init.sh @@ -46,3 +46,4 @@ EOF + From 5cfb7c884d774bfb79dc70e9f097e94ad4e5f6f2 Mon Sep 17 00:00:00 2001 From: root Date: Mon, 22 Apr 2024 15:43:25 +0800 Subject: [PATCH 139/188] remove \r --- bootstrap.sh | 0 scripts/create-topic.sh | 1 + scripts/mongo-init.sh | 1 - 3 files changed, 1 insertion(+), 1 deletion(-) mode change 100644 => 100755 bootstrap.sh diff --git a/bootstrap.sh b/bootstrap.sh old mode 100644 new mode 100755 diff --git a/scripts/create-topic.sh b/scripts/create-topic.sh index b6a24a73d7..a719147a28 100755 --- a/scripts/create-topic.sh +++ b/scripts/create-topic.sh @@ -54,3 +54,4 @@ done echo "All topics created." + diff --git a/scripts/mongo-init.sh b/scripts/mongo-init.sh index 3fac5be4e5..01199c4806 100755 --- a/scripts/mongo-init.sh +++ b/scripts/mongo-init.sh @@ -46,4 +46,3 @@ EOF - From cc0c9eb076fd3e7f22352dd6e8df6f532568145d Mon Sep 17 00:00:00 2001 From: root Date: Mon, 22 Apr 2024 15:52:12 +0800 Subject: [PATCH 140/188] remove \r --- scripts/create-topic.sh | 2 -- scripts/mongo-init.sh | 3 --- 2 files changed, 5 deletions(-) diff --git a/scripts/create-topic.sh b/scripts/create-topic.sh index a719147a28..206075fb83 100755 --- a/scripts/create-topic.sh +++ b/scripts/create-topic.sh @@ -53,5 +53,3 @@ for topic in "${topics[@]}"; do done echo "All topics created." - - diff --git a/scripts/mongo-init.sh b/scripts/mongo-init.sh index 01199c4806..f9a86f0d2f 100755 --- a/scripts/mongo-init.sh +++ b/scripts/mongo-init.sh @@ -43,6 +43,3 @@ if (createUserResult.ok == 1) { quit(1); } EOF - - - From 44f928da6798959366d7608fb25690cad2a5e2e2 Mon Sep 17 00:00:00 2001 From: root Date: Mon, 22 Apr 2024 16:03:06 +0800 Subject: [PATCH 141/188] remove \r --- scripts/create-topic.sh | 1 + scripts/mongo-init.sh | 1 + 2 files changed, 2 insertions(+) diff --git a/scripts/create-topic.sh b/scripts/create-topic.sh index 206075fb83..b6a24a73d7 100755 --- a/scripts/create-topic.sh +++ b/scripts/create-topic.sh @@ -53,3 +53,4 @@ for topic in "${topics[@]}"; do done echo "All topics created." + diff --git a/scripts/mongo-init.sh b/scripts/mongo-init.sh index f9a86f0d2f..bc111c2a9b 100755 --- a/scripts/mongo-init.sh +++ b/scripts/mongo-init.sh @@ -43,3 +43,4 @@ if (createUserResult.ok == 1) { quit(1); } EOF + From b2895c49798b9d341cad17dc37b05bb5c8f8ec9a Mon Sep 17 00:00:00 2001 From: skiffer-git <44203734@qq.com> Date: Mon, 22 Apr 2024 16:23:20 +0800 Subject: [PATCH 142/188] remove \r --- scripts/.gitattributes | 1 + 1 file changed, 1 insertion(+) create mode 100644 scripts/.gitattributes diff --git a/scripts/.gitattributes b/scripts/.gitattributes new file mode 100644 index 0000000000..dfdb8b771c --- /dev/null +++ b/scripts/.gitattributes @@ -0,0 +1 @@ +*.sh text eol=lf From 7de5e261f1337679bc7f60d5e57ecc3af6e569d1 Mon Sep 17 00:00:00 2001 From: root Date: Mon, 22 Apr 2024 16:24:37 +0800 Subject: [PATCH 143/188] remove \r --- scripts/create-topic.sh | 1 + scripts/mongo-init.sh | 1 + 2 files changed, 2 insertions(+) diff --git a/scripts/create-topic.sh b/scripts/create-topic.sh index b6a24a73d7..a719147a28 100755 --- a/scripts/create-topic.sh +++ b/scripts/create-topic.sh @@ -54,3 +54,4 @@ done echo "All topics created." + diff --git a/scripts/mongo-init.sh b/scripts/mongo-init.sh index bc111c2a9b..ce2b86d90d 100755 --- a/scripts/mongo-init.sh +++ b/scripts/mongo-init.sh @@ -44,3 +44,4 @@ if (createUserResult.ok == 1) { } EOF + From 77cbadb336fb67d77692bce25837b26c093551d0 Mon Sep 17 00:00:00 2001 From: skiffer-git <44203734@qq.com> Date: Mon, 22 Apr 2024 16:31:11 +0800 Subject: [PATCH 144/188] remove \r --- .gitattributes | 1 + 1 file changed, 1 insertion(+) create mode 100644 .gitattributes diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000000..dfdb8b771c --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +*.sh text eol=lf From 64f4cd103c1b902637ebc28c7969fa0ac8289726 Mon Sep 17 00:00:00 2001 From: skiffer-git <44203734@qq.com> Date: Mon, 22 Apr 2024 17:00:19 +0800 Subject: [PATCH 145/188] fix bug: get localIP --- go.mod | 4 ++-- go.sum | 23 +++++++++++++++++++++-- scripts/.gitattributes | 1 - 3 files changed, 23 insertions(+), 5 deletions(-) delete mode 100644 scripts/.gitattributes diff --git a/go.mod b/go.mod index 8ada8f2e77..b2f922bb26 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/openimsdk/open-im-server/v3 -go 1.20 +go 1.21.2 require ( firebase.google.com/go v3.13.0+incompatible @@ -15,7 +15,7 @@ require ( github.com/mitchellh/mapstructure v1.5.0 github.com/openimsdk/localcache v0.0.1 github.com/openimsdk/protocol v0.0.64 - github.com/openimsdk/tools v0.0.47-alpha.42 + github.com/openimsdk/tools v0.0.47-alpha.43 github.com/pkg/errors v0.9.1 // indirect github.com/prometheus/client_golang v1.18.0 github.com/stretchr/testify v1.9.0 diff --git a/go.sum b/go.sum index 0ef6209fc7..d7a08afa67 100644 --- a/go.sum +++ b/go.sum @@ -22,10 +22,13 @@ github.com/QcloudApi/qcloud_sign_golang v0.0.0-20141224014652-e4130a326409/go.mo github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible h1:8psS8a+wKfiLt1iVDX79F7Y6wUM49Lcha2FMXt4UM8g= github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8= github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= +github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs= +github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c= github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA= +github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0= github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s= github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= @@ -43,6 +46,7 @@ github.com/clbanning/mxj v1.8.4/go.mod h1:BVjHeAH+rl9rs6f+QIpeRl0tfu10SXn1pUSa5P github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/xds/go v0.0.0-20231128003011-0fa0005c9caa h1:jQCWAUqqlij9Pgj2i/PB79y4KOPYVyFYdROxgaCwdTQ= +github.com/cncf/xds/go v0.0.0-20231128003011-0fa0005c9caa/go.mod h1:x/1Gn8zydmfq8dk6e9PdstVsDgu9RuyIIJqAaF//0IM= github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= 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= @@ -66,12 +70,15 @@ github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.m github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/envoyproxy/protoc-gen-validate v1.0.4 h1:gVPz/FMfvh57HdSJQyvBtF00j8JU4zdyUgIUNhlgg0A= +github.com/envoyproxy/protoc-gen-validate v1.0.4/go.mod h1:qys6tmnRsYrQqIhm2bvKZH4Blx/1gTIZ2UKVY1M+Yew= github.com/fatih/color v1.14.1 h1:qfhVLaG5s+nCROl1zJsZRxFeYrHLqWroPOQ8BWiNb4w= github.com/fatih/color v1.14.1/go.mod h1:2oHN61fhTpgcxD3TSWCgKDiH1+x4OiDVVGH8WlgGZGg= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= +github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= 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/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= @@ -90,6 +97,7 @@ github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre 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-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= github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= @@ -137,11 +145,13 @@ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian/v3 v3.3.2 h1:IqNFLAmvJOgVlpdEBiQbDc2EwKW77amAycfTuWKdfvw= +github.com/google/martian/v3 v3.3.2/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o= github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= @@ -194,6 +204,7 @@ github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkr 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/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/kelindar/bitmap v1.5.2 h1:XwX7CTvJtetQZ64zrOkApoZZHBJRkjE23NfqUALA/HE= @@ -209,7 +220,9 @@ github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa02 github.com/klauspost/cpuid/v2 v2.2.6 h1:ndNyv040zDGIDh8thGkXYjnFtiN02M1PVVF+JE/48xc= github.com/klauspost/cpuid/v2 v2.2.6/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= github.com/lestrrat-go/envload v0.0.0-20180220234015-a3eb8ddeffcc h1:RKf14vYWi2ttpEmkA4aQ3j4u9dStX2t4M8UM6qqNsG8= @@ -270,8 +283,8 @@ github.com/openimsdk/gomake v0.0.6 h1:bJmQWDHBj8PQ7oGJ2SL3Gsx0k5CdI/BPfGzlGcV105 github.com/openimsdk/gomake v0.0.6/go.mod h1:PndCozNc2IsQIciyn9mvEblYWZwJmAI+06z94EY+csI= github.com/openimsdk/protocol v0.0.64 h1:OrjSs4CgKN9VLvJvrAsc37O7Ru0E0VllXZQSmG/ab7U= github.com/openimsdk/protocol v0.0.64/go.mod h1:OZQA9FR55lseYoN2Ql1XAHYKHJGu7OMNkUbuekrKCM8= -github.com/openimsdk/tools v0.0.47-alpha.42 h1:wM6t9otTLhXECq8aQcYaZGvBgo/ZAmbNTqVt3g3NHGg= -github.com/openimsdk/tools v0.0.47-alpha.42/go.mod h1:P4oGP1Pd+d4ctbLD5U/XQTgl8yu8Hd3skx640Fr69ko= +github.com/openimsdk/tools v0.0.47-alpha.43 h1:4RfyX+aLBEGOEIfc0CrzETwQUDd3aTsFpA26S/TpgXw= +github.com/openimsdk/tools v0.0.47-alpha.43/go.mod h1:P4oGP1Pd+d4ctbLD5U/XQTgl8yu8Hd3skx640Fr69ko= 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/pierrec/lz4/v4 v4.1.21 h1:yOVMLb6qSIDP67pl/5F7RepeKYu/VmTyEXvuMI5d9mQ= @@ -282,6 +295,7 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g= +github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U= github.com/prometheus/client_golang v1.18.0 h1:HzFfmkOzH5Q8L8G+kSJKUx5dtG87sewO+FoDDqP5Tbk= github.com/prometheus/client_golang v1.18.0/go.mod h1:T+GXkCk5wSJyOqMIzVgvvjFDlkOQntgjkJWKrN5txjA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= @@ -298,6 +312,7 @@ github.com/redis/go-redis/v9 v9.4.0/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0 github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= +github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= github.com/rs/xid v1.5.0 h1:mKX4bl4iPYJtEIxp6CYiUuLQ/8DYMoz0PUdtGgMFRVc= github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= @@ -376,6 +391,7 @@ go.opentelemetry.io/otel v1.23.0/go.mod h1:YCycw9ZeKhcJFrb34iVSkyT0iczq/zYDtZYFu go.opentelemetry.io/otel/metric v1.23.0 h1:pazkx7ss4LFVVYSxYew7L5I6qvLXHA0Ap2pwV+9Cnpo= go.opentelemetry.io/otel/metric v1.23.0/go.mod h1:MqUW2X2a6Q8RN96E2/nqNoT+z9BSms20Jb7Bbp+HiTo= go.opentelemetry.io/otel/sdk v1.21.0 h1:FTt8qirL1EysG6sTQRZ5TokkU8d0ugCj8htOgThZXQ8= +go.opentelemetry.io/otel/sdk v1.21.0/go.mod h1:Nna6Yv7PWTdgJHVRD9hIYywQBRx7pbox6nwBnZIxl/E= go.opentelemetry.io/otel/trace v1.23.0 h1:37Ik5Ib7xfYVb4V1UtnT97T1jI+AoIYkJyPkuL4iJgI= go.opentelemetry.io/otel/trace v1.23.0/go.mod h1:GSGTbIClEsuZrGIzoEHqsVfxgn5UkggkflQwDScNUsk= go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= @@ -383,6 +399,7 @@ go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/automaxprocs v1.5.3 h1:kWazyxZUrS3Gs4qUpbwo5kEIMGe/DAvi5Z4tl2NW4j8= go.uber.org/automaxprocs v1.5.3/go.mod h1:eRbA25aqJrxAbsLO0xy5jVwPt7FQnRgjW+efnwa1WM0= go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= +go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60= @@ -489,6 +506,7 @@ golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8T 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= golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk= +golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= google.golang.org/api v0.165.0 h1:zd5d4JIIIaYYsfVy1HzoXYZ9rWCSBxxAglbczzo7Bgc= google.golang.org/api v0.165.0/go.mod h1:2OatzO7ZDQsoS7IFf3rvsE17/TldiU3F/zxFHeqUB5o= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= @@ -526,6 +544,7 @@ google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGm google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= diff --git a/scripts/.gitattributes b/scripts/.gitattributes deleted file mode 100644 index dfdb8b771c..0000000000 --- a/scripts/.gitattributes +++ /dev/null @@ -1 +0,0 @@ -*.sh text eol=lf From 75a3b9199ae0bcf8713c21825878e04938fd0e0f Mon Sep 17 00:00:00 2001 From: xuan <146319162+wxuanF@users.noreply.github.com> Date: Wed, 24 Apr 2024 12:09:36 +0800 Subject: [PATCH 146/188] update some ci file (#2200) * Update openimci.yml * Update golangci-lint.yml * Update e2e-test.yml --- .github/workflows/e2e-test.yml | 45 ++-- .github/workflows/golangci-lint.yml | 8 +- .github/workflows/openimci.yml | 381 ++++++++++------------------ 3 files changed, 169 insertions(+), 265 deletions(-) diff --git a/.github/workflows/e2e-test.yml b/.github/workflows/e2e-test.yml index f98221e41b..62df69ed5c 100644 --- a/.github/workflows/e2e-test.yml +++ b/.github/workflows/e2e-test.yml @@ -73,14 +73,22 @@ jobs: - name: Docker Operations run: | - sudo make init sudo docker compose up -d + sudo bash bootstrap.sh + sudo mage sudo sleep 20 - name: Module Operations run: | - sudo make tidy - sudo make tools.verify.go-gitlint + sudo go mod tidy + echo "===========> Verifying go-gitlint is installed" + if [ ! -f ./_output/tools/go-gitlint ]; then + export GOBIN=$(pwd)/_output/tools + echo "===========> Installing The default installation path is /home/ubuntu/DF/open-im-server/_output/tools/go-gitlint" + sudo go install github.com/marmotedu/go-gitlint/cmd/go-gitlint@latest + echo "===========> go-gitlint is installed in /home/ubuntu/DF/open-im-server/_output/tools/go-gitlint" + fi + - name: Build, Start(make build && make start) run: | @@ -90,7 +98,8 @@ jobs: run: | sudo ./scripts/install/install.sh -s - - name: Exec OpenIM API test (make test-api) +# - name: Exec OpenIM API test (make test-api) + - name: Exec OpenIM test (make test) run: | mkdir -p ./tmp touch ./tmp/test.md @@ -98,23 +107,27 @@ jobs: echo "## OpenIM API Test" >> ./tmp/test.md echo "

Command Output for OpenIM API Test" >> ./tmp/test.md echo "
" >> ./tmp/test.md
-        sudo make test-api | tee -a ./tmp/test.md
+        echo "===========> Run api test"
+        ./scripts/install/test.sh
+        echo "===========> Run api test" >> ./tmp/test.md
+        ./scripts/install/test.sh >> ./tmp/test.md
         echo "
" >> ./tmp/test.md echo "
" >> ./tmp/test.md - sudo make test-api + echo "===========> Run api test" + ./scripts/install/test.sh - - name: Exec OpenIM E2E Test (make test-e2e) - run: | - echo "" >> ./tmp/test.md - echo "## OpenIM E2E Test" >> ./tmp/test.md - echo "
Command Output for OpenIM E2E Test" >> ./tmp/test.md - echo "
" >> ./tmp/test.md
-        sudo make test-e2e | tee -a ./tmp/test.md
-        echo "
" >> ./tmp/test.md - echo "
" >> ./tmp/test.md + # - name: Exec OpenIM E2E Test (make test-e2e) + # run: | + # echo "" >> ./tmp/test.md + # echo "## OpenIM E2E Test" >> ./tmp/test.md + # echo "
Command Output for OpenIM E2E Test" >> ./tmp/test.md + # echo "
" >> ./tmp/test.md
+ #       sudo make test-e2e | tee -a ./tmp/test.md
+ #       echo "
" >> ./tmp/test.md + # echo "
" >> ./tmp/test.md - sudo make test-e2e + # sudo make test-e2e - name: Comment PR with file uses: thollander/actions-comment-pull-request@v2 diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml index 31e491d6b6..64bd498c54 100644 --- a/.github/workflows/golangci-lint.yml +++ b/.github/workflows/golangci-lint.yml @@ -29,7 +29,13 @@ jobs: go-version: '1.21' cache: false - name: OpenIM Scripts Verification(make verify) - run: sudo make verify + run: | + cd scripts + for script in verify-*; do + if [ -x "$script" ]; then + ./"$script" + fi + done - name: golangci-lint uses: golangci/golangci-lint-action@v4.0.0 with: diff --git a/.github/workflows/openimci.yml b/.github/workflows/openimci.yml index f47283997d..033868a2ed 100644 --- a/.github/workflows/openimci.yml +++ b/.github/workflows/openimci.yml @@ -1,3 +1,4 @@ + # Copyright © 2023 OpenIM open source community. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -11,8 +12,7 @@ # 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 Aotu Build and Install +name: OpenIM CI Auto Build on: push: @@ -37,269 +37,154 @@ on: - "**.md" - "docs/**" -env: - GO_VERSION: "1.19" - GOLANGCI_VERSION: "v1.50.1" - jobs: - openim: - name: Test with go ${{ matrix.go_version }} on ${{ matrix.os }} - runs-on: ${{ matrix.os }} - permissions: - contents: write - pull-requests: write - environment: - name: openim - strategy: - matrix: - go_version: ["1.19","1.20","1.21"] - os: [ubuntu-latest] - steps: - - name: Setup - uses: actions/checkout@v4 - - - name: Set up Go ${{ matrix.go_version }} - uses: actions/setup-go@v5 - with: - go-version: ${{ matrix.go_version }} - id: go - - - name: Install Task - uses: arduino/setup-task@v1 - with: - version: '3.x' # If available, use the latest major version that's compatible - repo-token: ${{ secrets.GITHUB_TOKEN }} - - - name: Code Typecheck Detector - uses: kubecub/typecheck@main - - - name: Conformity Checker for Project - uses: kubecub/standardizer@main - - - name: Module Operations - run: | - sudo make tidy - sudo make tools.verify.go-gitlint - - - name: Format Code - run: sudo make format - continue-on-error: true - - - name: Generate Files - run: make gen - continue-on-error: true - - - name: Build Source - run: sudo make build - - - name: Build multiarch PLATFORMS - if: startsWith(github.ref, 'refs/heads/release-') - run: | - sudo make multiarch - - - name: Cleanup Build - run: sudo make clean - - - name: Set Current Directory - id: set_directory - run: echo "::set-output name=directory::$(pwd)" - continue-on-error: true - - - name: Collect and Display Test Coverage - id: collect_coverage - run: | - cd ${{ steps.set_directory.outputs.directory }} - make cover - echo "::set-output name=coverage_file::./_output/tmp/coverage.out" - echo "Test Coverage:" - cat ${{ steps.collect_coverage.outputs.coverage_file }} - continue-on-error: true - - openim-start: - name: Test OpenIM install/start on ${{ matrix.os }}-${{ matrix.arch }} - runs-on: ${{ matrix.os }} - permissions: - contents: write - pull-requests: write - environment: - name: openim - strategy: - matrix: - go_version: ["1.21"] - os: ["ubuntu-latest"] - steps: - - name: Checkout and Install OpenIM - uses: actions/checkout@v4 - - name: Install Task - uses: arduino/setup-task@v1 - with: - version: '3.x' # If available, use the latest major version that's compatible - repo-token: ${{ secrets.GITHUB_TOKEN }} - - name: Run OpenIM make install start - run: | - sudo make install - - # - name: Check the OpenIM environment and status - # run: | - # sudo docker images - # sudo docker ps - - name: Check the OpenIM environment and status - if: runner.os == 'Linux' && matrix.arch == 'amd64' - id: docker_info - run: | - sleep 30 - echo "images<> $GITHUB_ENV - sudo docker images >> $GITHUB_ENV - echo "EOF" >> $GITHUB_ENV - echo "containers<> $GITHUB_ENV - sudo docker ps >> $GITHUB_ENV - echo "EOF" >> $GITHUB_ENV - - - name: Comment PR - uses: thollander/actions-comment-pull-request@v2 - if: runner.os == 'Linux' && matrix.arch == 'amd64' - with: - message: | - > [!TIP] - > Run make install to check the status - - ### Docker Images: -
Click to expand docker images - ```bash - ${{ env.images }} - ``` -
- - ### Docker Processes: -
Click to expand docker ps - ```bash - ${{ env.containers }} - ``` -
- GITHUB_TOKEN: ${{ secrets.BOT_GITHUB_TOKEN }} - - execute-scripts: - name: Execute OpenIM Script On ${{ matrix.os }}-${{ matrix.arch }} - runs-on: ${{ matrix.os }} + build-linux: + name: Execute OpenIM Script On Linux + runs-on: ubuntu-latest permissions: - contents: write - pull-requests: write + contents: write + pull-requests: write environment: name: openim strategy: matrix: - go_version: ["1.21"] - os: ["ubuntu-latest", "macos-latest"] arch: [arm64, armv7, amd64] + steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Set up Go ${{ matrix.go_version }} - uses: actions/setup-go@v5 - with: - go-version: ${{ matrix.go_version }} - id: go + - uses: actions/checkout@v3 - - name: Install Task - uses: arduino/setup-task@v1 + - name: Set up Go + uses: actions/setup-go@v4 with: - version: '3.x' # If available, use the latest major version that's compatible - repo-token: ${{ secrets.GITHUB_TOKEN }} - - # - name: Install latest Bash (macOS only) - # if: runner.os == 'macOS' && matrix.arch == 'arm64' - # run: | - # /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" - # brew update - - # brew install bash - # brew install gnu-sed - - # echo "/usr/local/bin" >> $GITHUB_PATH - # echo "$(brew --prefix)/opt/gnu-sed/libexec/gnubin" >> $GITHUB_PATH - # continue-on-error: true + go-version: '1.21' - - name: Set up Docker for Ubuntu - if: runner.os == 'Linux' + - name: Set up Docker for Linux run: | - sudo make init sudo docker compose up -d - sudo sleep 20 - - # - name: Set up Docker for macOS - # if: runner.os == 'macOS' && matrix.arch == 'arm64' - # run: | - # brew install --cask docker - # open /Applications/Docker.app - - # sleep 10 - # docker-compose --version || brew install docker-compose + sudo sleep 30 # Increased sleep time for better stability + timeout-minutes: 20 # Increased timeout for Docker setup - # docker-compose up -d - # sleep 20 - - name: Module Operations for Ubuntu - if: runner.os == 'Linux' - run: | - sudo make tidy - sudo make tools.verify.go-gitlint - - # - name: Module Operations for macOS - # if: runner.os == 'macOS' - # run: | - # make tidy - # make tools.verify.go-gitlint - - - name: Build, Start, Check Services and Print Logs for Ubuntu - if: runner.os == 'Linux' - run: | - sudo make build - sudo make start - sudo make check - - - name: Restart Services and Print Logs for Ubuntu - if: runner.os == 'Linux' && matrix.arch == 'amd64' - run: | - sudo make restart - sudo make check - - - name: Build, Start, Check Services and Print Logs for macOS - if: runner.os == 'macOS' && matrix.arch == 'arm64' - run: | - make build - - openim-test-build-image: - name: Build OpenIM Docker Image - runs-on: ubuntu-latest - permissions: - contents: write - pull-requests: write - environment: - name: openim - steps: - - name: Checkout code - uses: actions/checkout@v4 - - name: Set up Go ${{ matrix.go_version }} - uses: actions/setup-go@v5 - with: - go-version: ${{ matrix.go_version }} - id: go - - - name: Install Task - uses: arduino/setup-task@v1 - with: - version: '3.x' # If available, use the latest major version that's compatible - repo-token: ${{ secrets.GITHUB_TOKEN }} + - name: init + run: sudo bash bootstrap.sh + timeout-minutes: 20 - - name: Test Docker Build + - name: Build, Start, Check Services and Print Logs for Linux run: | - sudo make init - sudo make image + sudo mage + sudo mage start + sudo mage check + - - name: Get OpenIM Docker Images Status - id: docker_processes + - name: Restart Services and Print Logs run: | - sudo docker images - sudo docker ps + sudo mage stop + sudo mage start + sudo mage check + + +# build-mac: +# name: Execute OpenIM Script On macOS +# runs-on: macos-latest +# permissions: +# contents: write +# pull-requests: write +# environment: +# name: openim +# strategy: +# matrix: +# arch: [arm64, armv7, amd64] +# +# steps: +# - uses: actions/checkout@v3 + +# - name: Set up Go +# uses: actions/setup-go@v4 +# with: +# go-version: '1.21' + + +# while ! docker system info > /dev/null 2>&1; do +# echo "Waiting for Docker to start..." +# sleep 10 # Increased delay to ensure Docker starts properly +# done + +# - name: Install Docker +# run: | +# brew install docker +# brew install docker-compose +# sleep 10 +# docker-compose up -d +# sleep 30 +# timeout-minutes: 20 +# + +# - name: init +# run: sudo bash bootstrap.sh +# timeout-minutes: 20 + +# - 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 + +# build-windows: +# name: Execute OpenIM Script On Windows +# runs-on: windows-latest +# permissions: +# contents: write +# pull-requests: write +# environment: +# name: openim +# strategy: +# matrix: +# arch: [arm64, armv7, amd64] +# +# steps: +# - uses: actions/checkout@v3 + +# - name: Set up Go +# uses: actions/setup-go@v4 +# with: +# go-version: '1.21' + +# - name: Set up Docker for Windows +# run: | +# $images = @("zookeeper", "redis", "kafka") +# foreach ($image in $images) { +# $tag = "$image:latest" +# docker pull $tag | Out-Null +# if ($LASTEXITCODE -ne 0) { +# Write-Host "Skipping $image as it is not available for Windows" +# } else { +# Write-Host "Successfully pulled $image" +# } +# } +# docker compose up -d +# Start-Sleep -Seconds 30 +# timeout-minutes: 20 +# shell: pwsh + +# - name: init +# run: bootstrap.bat +# timeout-minutes: 20 + +# - name: Build, Start, Check Services and Print Logs for Linux +# run: | +# mage +# mage start +# mage check + +# - name: Restart Services and Print Logs +# run: | +# mage stop +# mage start +# mage check From 653b48479d0387cfaea3117bc195ad5c1c0fbfcc Mon Sep 17 00:00:00 2001 From: OpenIM-Gordon <46924906+FGadvancer@users.noreply.github.com> Date: Wed, 24 Apr 2024 12:11:24 +0800 Subject: [PATCH 147/188] 3.6.1 code conventions (#2202) * refactor: webhooks update. * Adjust configuration settings * Adjust configuration settings * Adjust configuration settings * feat: s3 api addr * refactor: webhooks update. * Adjust configuration settings * Adjust configuration settings * Adjust configuration settings * Adjust configuration settings * Adjust configuration settings * Adjust configuration settings * Adjust configuration settings * refactor: webhooks update. * refactor: kafka update. * Simplify the Docker Compose configuration, remove unnecessary environment variables, and eliminate the gateway service. * refactor: kafka update. * refactor: kafka update. * Simplify the Docker Compose configuration, remove unnecessary environment variables, and eliminate the gateway service. * Simplify the Docker Compose configuration, remove unnecessary environment variables, and eliminate the gateway service. * Windows can compile and run. * Windows can compile and run. * refactor: kafka update. * feat: msg cache split * refactor: webhooks update * refactor: webhooks update * refactor: friends update * refactor: group update * refactor: third update * refactor: api update * refactor: crontab update * refactor: msggateway update * mage * mage * refactor: all module update. * check * refactor: all module update. * load config * load config * load config * load config * refactor: all module update. * refactor: all module update. * refactor: all module update. * refactor: all module update. * refactor: all module update. * Optimize Docker configuration and script. * refactor: all module update. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * refactor: all module update. * Optimize Docker configuration and script. * refactor: all module update. * refactor: all module update. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * update tools * update tools * Optimize Docker configuration and script. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * update protocol * Optimize Docker configuration and script. * Optimize Docker configuration and script. * refactor: all module update. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * refactor: api remove token auth by redis directly. * Code Refactoring * refactor: websocket auth change to call rpc of auth. * refactor: kick online user and remove token change to call auth rpc. * refactor: kick online user and remove token change to call auth rpc. * refactor: remove msggateway redis. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor webhook * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor webhook * refactor: cmd update. * refactor: cmd update. * fix: runtime: goroutine stack exceeds * refactor: cmd update. * refactor notification * refactor notification * refactor * refactor: cmd update. * refactor: cmd update. * refactor * refactor * refactor * protojson * protojson * protojson * go mod * wrapperspb * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: context update. * refactor: websocket update info. * refactor: websocket update info. * refactor: websocket update info. * refactor: websocket update info. * refactor: api name change. * refactor: debug info. * refactor: debug info. * refactor: debug info. * fix: update file * refactor * refactor * refactor: debug info. * refactor: debug info. * refactor: debug info. * refactor: debug info. * refactor: debug info. * refactor: debug info. * fix: callback update. * fix: callback update. * refactor * fix: update message. * fix: msg cache timeout. * refactor * refactor * fix: push update. * fix: push update. * fix: push update. * fix: push update. * fix: push update. * fix: push update. * refactor * refactor * fix: push update. * fix: websocket handle error remove when upgrade error. * fix: priority url * fix: minio config * refactor: add zk logger. * refactor * fix: minio config * refactor * refactor * refactor * refactor * refactor: remove zk logger. * refactor: update tools version. * refactor * refactor: update server version to 3.7.0. * refactor * refactor * refactor * refactor * refactor * refactor * refactor * refactor * refactor * refactor * refactor * refactor * refactor * refactor: zk log debug. * refactor: zk log debug. * refactor: zk log debug. * refactor: zk log debug. * refactor: zk log debug. * refactor * refactor * refactor * refactor: log level change. * refactor: 3.7.0 code conventions. --------- Co-authored-by: skiffer-git <44203734@qq.com> Co-authored-by: withchao <993506633@qq.com> --- .dockerignore | 5 +- Dockerfile | 59 +++++++++++------ bootstrap.sh | 0 config/README.md | 63 +++++++++++++++++++ config/minio.yml | 8 +-- go.mod | 11 ++-- go.sum | 27 ++------ internal/api/init.go | 4 -- internal/msgtransfer/init.go | 5 -- .../msgtransfer/online_history_msg_handler.go | 2 +- internal/push/push_handler.go | 6 +- internal/rpc/third/third.go | 16 ----- pkg/common/config/config.go | 23 ++++--- pkg/common/config/load_config_test.go | 4 +- pkg/common/config/version | 2 +- .../discoveryregister/discoveryregister.go | 1 + pkg/localcache/cache.go | 4 +- pkg/localcache/go.mod | 5 -- pkg/localcache/go.sum | 1 - pkg/localcache/option.go | 2 +- pkg/rpccache/conversation.go | 2 +- pkg/rpccache/friend.go | 2 +- pkg/rpccache/group.go | 2 +- pkg/rpccache/user.go | 2 +- scripts/create-topic.sh | 2 - scripts/docker-start-all.sh | 9 +-- scripts/mongo-init.sh | 1 + 27 files changed, 149 insertions(+), 119 deletions(-) mode change 100755 => 100644 bootstrap.sh create mode 100644 config/README.md delete mode 100644 pkg/localcache/go.mod delete mode 100644 pkg/localcache/go.sum diff --git a/.dockerignore b/.dockerignore index 263798e07e..cf6c3cd596 100644 --- a/.dockerignore +++ b/.dockerignore @@ -5,9 +5,8 @@ .git # Ignore build artifacts -_output/ logs/ - +_output/ # Ignore non-essential documentation README.md README-zh_CN.md @@ -18,8 +17,6 @@ CHANGELOG/ # Ignore testing and linting configuration .golangci.yml -# Ignore deployment-related files -docker-compose.yaml # Ignore assets assets/ diff --git a/Dockerfile b/Dockerfile index 9b10212165..746dddf65a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,30 +1,49 @@ -# Build Stage -FROM golang:1.20 AS builder +# Use Go 1.21 Alpine as the base image for building the application +FROM golang:1.21-alpine as builder -# Set go mod installation source and proxy -ARG GO111MODULE=on +# Define the base directory for the application as an environment variable +ENV SERVER_DIR=/openim-server -ENV GO111MODULE=$GO111MODULE -ENV GOPROXY=$GOPROXY +# Set the working directory inside the container based on the environment variable +WORKDIR $SERVER_DIR -# Set up the working directory -WORKDIR /openim/openim-server +# 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 . . -# Copy all files to the container -ADD . . +RUN go mod download -RUN make clean -RUN make build +# Install Mage to use for building the application +RUN go install github.com/magefile/mage@v1.15.0 -FROM ghcr.io/openim-sigs/openim-ubuntu-image:latest +# Optionally build your application if needed +RUN mage build -WORKDIR ${SERVER_WORKDIR} +# Using Alpine Linux with Go environment for the final image +FROM golang:1.21-alpine -# Copy scripts and binary files to the production image -COPY --from=builder ${OPENIM_SERVER_BINDIR} /openim/openim-server/_output/bin -COPY --from=builder ${OPENIM_SERVER_CMDDIR} /openim/openim-server/scripts -COPY --from=builder ${SERVER_WORKDIR}/config /openim/openim-server/config -COPY --from=builder ${SERVER_WORKDIR}/deployments /openim/openim-server/deployments +# Install necessary packages, such as bash +RUN apk add --no-cache bash -CMD ["/openim/openim-server/scripts/docker-start-all.sh"] +# Set the environment and work directory +ENV SERVER_DIR=/openim-server +WORKDIR $SERVER_DIR + + +# Copy the compiled binaries and mage from the builder image to the final image +COPY --from=builder $SERVER_DIR/_output $SERVER_DIR/_output +COPY --from=builder $SERVER_DIR/config $SERVER_DIR/config +COPY --from=builder /go/bin/mage /usr/local/bin/mage +COPY --from=builder $SERVER_DIR/magefile_windows.go $SERVER_DIR/ +COPY --from=builder $SERVER_DIR/magefile_unix.go $SERVER_DIR/ +COPY --from=builder $SERVER_DIR/magefile.go $SERVER_DIR/ +COPY --from=builder $SERVER_DIR/start-config.yml $SERVER_DIR/ +COPY --from=builder $SERVER_DIR/go.mod $SERVER_DIR/ +COPY --from=builder $SERVER_DIR/go.sum $SERVER_DIR/ + +RUN go get github.com/openimsdk/gomake@v0.0.9 + +# Set the command to run when the container starts +ENTRYPOINT ["sh", "-c", "mage start && tail -f /dev/null"] diff --git a/bootstrap.sh b/bootstrap.sh old mode 100755 new mode 100644 diff --git a/config/README.md b/config/README.md new file mode 100644 index 0000000000..048d7fe362 --- /dev/null +++ b/config/README.md @@ -0,0 +1,63 @@ +--- +title: 'OpenIM Configuration Files and Common Configuration Item Modifications Guide' + +## Configuration Files Explanation + +| Configuration File | Description | +| ------------------------------- | ------------------------------------------------------------ | +| **kafka.yml** | Configurations for Kafka username, password, address, etc. | +| **redis.yml** | Configurations for Redis password, address, etc. | +| **minio.yml** | Configurations for MinIO username, password, address, and external IP/domain; failing to modify external IP or domain may cause image file sending failures | +| **zookeeper.yml** | Configurations for ZooKeeper user, password, address, etc. | +| **mongodb.yml** | Configurations for MongoDB username, password, address, etc. | +| **log.yml** | Configurations for log level and storage directory. | +| **notification.yml** | Configurations for events like adding friends, creating groups, etc. | +| **share.yml** | Common configurations needed by various OpenIM services, such as secret. | +| **webhooks.yml** | Configurations for URLs in Webhook. | +| **local-cache.yml** | Local cache configurations. | +| **openim-rpc-third.yml** | Configurations for listening IP, port, and storage settings for images and videos in openim-rpc-third service. | +| **openim-rpc-user.yml** | Configurations for listening IP and port in openim-rpc-user service. | +| **openim-api.yml** | Configurations for listening IP, port, etc., in openim-api service. | +| **openim-crontask.yml** | Configurations for openim-crontask service. | +| **openim-msggateway.yml** | Configurations for listening IP, port, etc., in openim-msggateway service. | +| **openim-msgtransfer.yml** | Configurations for openim-msgtransfer service. | +| **openim-push.yml** | Configurations for listening IP, port, and offline push settings in openim-push service. | +| **openim-rpc-auth.yml** | Configurations for listening IP, port, and token expiration settings in openim-rpc-auth service. | +| **openim-rpc-conversation.yml** | Configurations for listening IP, port, etc., in openim-rpc-conversation service. | +| **openim-rpc-friend.yml** | Configurations for listening IP, port, etc., in openim-rpc-friend service. | +| **openim-rpc-group.yml** | Configurations for listening IP, port, etc., in openim-rpc-group service. | +| **openim-rpc-msg.yml** | Configurations for listening IP, port, and whether to verify friendship before sending messages in openim-rpc-msg service. | + +## Common Configuration Item Modifications + +| Configuration Item Modification | Configuration File | +| ----------------------------------------------------- | ----------------------- | +| Using MinIO for image and video file object storage | `minio.yml` | +| Adjusting production environment logs | `log.yml` | +| Verifying friendship before sending messages | `openim-rpc-msg.yml` | +| Modifying secret | `share.yml` | +| Using OSS, COS, AWS, Kodo for image and video storage | `openim-rpc-third.yml` | +| Setting multiple login policy | `openim-msggateway.yml` | +| Setting up offline push | `openim-push.yml` | + +## Starting Multiple Instances of an OpenIM Service + +To start multiple instances of an OpenIM service, simply increase the corresponding port numbers and modify the `start-config.yml` file in the project root directory. Restart the service to take effect. For example, the configuration to start 2 instances of `openim-rpc-user` is as follows: + +```yaml +rpc: + registerIP: '' + listenIP: 0.0.0.0 + ports: [ 10110, 10111 ] + +prometheus: + enable: true + ports: [ 20100, 20101 ] +``` + +Modify `start-config.yml`: + +```yaml +serviceBinaries: + openim-rpc-user: 2 +``` diff --git a/config/minio.yml b/config/minio.yml index 0cabb7f36a..0a80bb845c 100644 --- a/config/minio.yml +++ b/config/minio.yml @@ -1,9 +1,7 @@ bucket: "openim" -port: 10005 accessKeyID: "root" secretAccessKey: "openIM123" sessionToken: '' -internalIP: localhost -externalIP: 150.109.93.151 -url: https://image.rentsoft.cn/ -publicRead: false +internalAddress: "minio:9000" +externalAddress: "http://external_ip:10005" +publicRead: false \ No newline at end of file diff --git a/go.mod b/go.mod index b2f922bb26..891125a899 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/openimsdk/open-im-server/v3 -go 1.21.2 +go 1.20 require ( firebase.google.com/go v3.13.0+incompatible @@ -13,9 +13,8 @@ require ( github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible // indirect github.com/mitchellh/mapstructure v1.5.0 - github.com/openimsdk/localcache v0.0.1 github.com/openimsdk/protocol v0.0.64 - github.com/openimsdk/tools v0.0.47-alpha.43 + github.com/openimsdk/tools v0.0.49-alpha.2 github.com/pkg/errors v0.9.1 // indirect github.com/prometheus/client_golang v1.18.0 github.com/stretchr/testify v1.9.0 @@ -32,9 +31,10 @@ require ( github.com/IBM/sarama v1.43.0 github.com/fatih/color v1.14.1 github.com/go-redis/redis v6.15.9+incompatible + github.com/hashicorp/golang-lru/v2 v2.0.7 github.com/kelindar/bitmap v1.5.2 github.com/likexian/gokit v0.25.13 - github.com/openimsdk/gomake v0.0.6 + github.com/openimsdk/gomake v0.0.9 github.com/redis/go-redis/v9 v9.4.0 github.com/robfig/cron/v3 v3.0.1 github.com/shirou/gopsutil v3.21.11+incompatible @@ -83,7 +83,6 @@ require ( github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/hashicorp/go-uuid v1.0.3 // indirect - github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jcmturner/aescts/v2 v2.0.0 // indirect @@ -173,5 +172,3 @@ require ( golang.org/x/crypto v0.21.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect ) - -replace github.com/openimsdk/localcache => ./pkg/localcache diff --git a/go.sum b/go.sum index d7a08afa67..5dc0cc524c 100644 --- a/go.sum +++ b/go.sum @@ -22,13 +22,10 @@ github.com/QcloudApi/qcloud_sign_golang v0.0.0-20141224014652-e4130a326409/go.mo github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible h1:8psS8a+wKfiLt1iVDX79F7Y6wUM49Lcha2FMXt4UM8g= github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8= github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= -github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs= -github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c= github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA= -github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0= github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s= github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= @@ -46,7 +43,6 @@ github.com/clbanning/mxj v1.8.4/go.mod h1:BVjHeAH+rl9rs6f+QIpeRl0tfu10SXn1pUSa5P github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/xds/go v0.0.0-20231128003011-0fa0005c9caa h1:jQCWAUqqlij9Pgj2i/PB79y4KOPYVyFYdROxgaCwdTQ= -github.com/cncf/xds/go v0.0.0-20231128003011-0fa0005c9caa/go.mod h1:x/1Gn8zydmfq8dk6e9PdstVsDgu9RuyIIJqAaF//0IM= github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= 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= @@ -70,15 +66,12 @@ github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.m github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/envoyproxy/protoc-gen-validate v1.0.4 h1:gVPz/FMfvh57HdSJQyvBtF00j8JU4zdyUgIUNhlgg0A= -github.com/envoyproxy/protoc-gen-validate v1.0.4/go.mod h1:qys6tmnRsYrQqIhm2bvKZH4Blx/1gTIZ2UKVY1M+Yew= github.com/fatih/color v1.14.1 h1:qfhVLaG5s+nCROl1zJsZRxFeYrHLqWroPOQ8BWiNb4w= github.com/fatih/color v1.14.1/go.mod h1:2oHN61fhTpgcxD3TSWCgKDiH1+x4OiDVVGH8WlgGZGg= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= -github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= 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/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= @@ -97,7 +90,6 @@ github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre 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-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= github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= @@ -145,13 +137,11 @@ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= -github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian/v3 v3.3.2 h1:IqNFLAmvJOgVlpdEBiQbDc2EwKW77amAycfTuWKdfvw= -github.com/google/martian/v3 v3.3.2/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o= github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= @@ -204,7 +194,6 @@ github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkr 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/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/kelindar/bitmap v1.5.2 h1:XwX7CTvJtetQZ64zrOkApoZZHBJRkjE23NfqUALA/HE= @@ -220,9 +209,7 @@ github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa02 github.com/klauspost/cpuid/v2 v2.2.6 h1:ndNyv040zDGIDh8thGkXYjnFtiN02M1PVVF+JE/48xc= github.com/klauspost/cpuid/v2 v2.2.6/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= -github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= -github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= github.com/lestrrat-go/envload v0.0.0-20180220234015-a3eb8ddeffcc h1:RKf14vYWi2ttpEmkA4aQ3j4u9dStX2t4M8UM6qqNsG8= @@ -279,12 +266,12 @@ github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1y github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE= github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs= -github.com/openimsdk/gomake v0.0.6 h1:bJmQWDHBj8PQ7oGJ2SL3Gsx0k5CdI/BPfGzlGcV105s= -github.com/openimsdk/gomake v0.0.6/go.mod h1:PndCozNc2IsQIciyn9mvEblYWZwJmAI+06z94EY+csI= +github.com/openimsdk/gomake v0.0.9 h1:ouf25ygN2PMQ68Gfgns/EQRPiLPnp+77SIr68GfE+n4= +github.com/openimsdk/gomake v0.0.9/go.mod h1:PndCozNc2IsQIciyn9mvEblYWZwJmAI+06z94EY+csI= github.com/openimsdk/protocol v0.0.64 h1:OrjSs4CgKN9VLvJvrAsc37O7Ru0E0VllXZQSmG/ab7U= github.com/openimsdk/protocol v0.0.64/go.mod h1:OZQA9FR55lseYoN2Ql1XAHYKHJGu7OMNkUbuekrKCM8= -github.com/openimsdk/tools v0.0.47-alpha.43 h1:4RfyX+aLBEGOEIfc0CrzETwQUDd3aTsFpA26S/TpgXw= -github.com/openimsdk/tools v0.0.47-alpha.43/go.mod h1:P4oGP1Pd+d4ctbLD5U/XQTgl8yu8Hd3skx640Fr69ko= +github.com/openimsdk/tools v0.0.49-alpha.2 h1:8IfV6o2ySU7C54sh/MG7ctEp1h3lSNe03OCUDWSk5Ws= +github.com/openimsdk/tools v0.0.49-alpha.2/go.mod h1:P4oGP1Pd+d4ctbLD5U/XQTgl8yu8Hd3skx640Fr69ko= 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/pierrec/lz4/v4 v4.1.21 h1:yOVMLb6qSIDP67pl/5F7RepeKYu/VmTyEXvuMI5d9mQ= @@ -295,7 +282,6 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g= -github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U= github.com/prometheus/client_golang v1.18.0 h1:HzFfmkOzH5Q8L8G+kSJKUx5dtG87sewO+FoDDqP5Tbk= github.com/prometheus/client_golang v1.18.0/go.mod h1:T+GXkCk5wSJyOqMIzVgvvjFDlkOQntgjkJWKrN5txjA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= @@ -312,7 +298,6 @@ github.com/redis/go-redis/v9 v9.4.0/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0 github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= -github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= github.com/rs/xid v1.5.0 h1:mKX4bl4iPYJtEIxp6CYiUuLQ/8DYMoz0PUdtGgMFRVc= github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= @@ -391,7 +376,6 @@ go.opentelemetry.io/otel v1.23.0/go.mod h1:YCycw9ZeKhcJFrb34iVSkyT0iczq/zYDtZYFu go.opentelemetry.io/otel/metric v1.23.0 h1:pazkx7ss4LFVVYSxYew7L5I6qvLXHA0Ap2pwV+9Cnpo= go.opentelemetry.io/otel/metric v1.23.0/go.mod h1:MqUW2X2a6Q8RN96E2/nqNoT+z9BSms20Jb7Bbp+HiTo= go.opentelemetry.io/otel/sdk v1.21.0 h1:FTt8qirL1EysG6sTQRZ5TokkU8d0ugCj8htOgThZXQ8= -go.opentelemetry.io/otel/sdk v1.21.0/go.mod h1:Nna6Yv7PWTdgJHVRD9hIYywQBRx7pbox6nwBnZIxl/E= go.opentelemetry.io/otel/trace v1.23.0 h1:37Ik5Ib7xfYVb4V1UtnT97T1jI+AoIYkJyPkuL4iJgI= go.opentelemetry.io/otel/trace v1.23.0/go.mod h1:GSGTbIClEsuZrGIzoEHqsVfxgn5UkggkflQwDScNUsk= go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= @@ -399,7 +383,6 @@ go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/automaxprocs v1.5.3 h1:kWazyxZUrS3Gs4qUpbwo5kEIMGe/DAvi5Z4tl2NW4j8= go.uber.org/automaxprocs v1.5.3/go.mod h1:eRbA25aqJrxAbsLO0xy5jVwPt7FQnRgjW+efnwa1WM0= go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= -go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60= @@ -506,7 +489,6 @@ golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8T 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= golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk= -golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= google.golang.org/api v0.165.0 h1:zd5d4JIIIaYYsfVy1HzoXYZ9rWCSBxxAglbczzo7Bgc= google.golang.org/api v0.165.0/go.mod h1:2OatzO7ZDQsoS7IFf3rvsE17/TldiU3F/zxFHeqUB5o= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= @@ -544,7 +526,6 @@ google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGm google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= diff --git a/internal/api/init.go b/internal/api/init.go index dcce69a12f..6e784da9a9 100644 --- a/internal/api/init.go +++ b/internal/api/init.go @@ -64,10 +64,6 @@ func Start(ctx context.Context, index int, config *Config) error { return errs.WrapMsg(err, "failed to register discovery service") } - if err = client.CreateRpcRootNodes(config.Share.RpcRegisterName.GetServiceNames()); err != nil { - return errs.WrapMsg(err, "failed to create RPC root nodes") - } - var ( netDone = make(chan struct{}, 1) netErr error diff --git a/internal/msgtransfer/init.go b/internal/msgtransfer/init.go index 685e847b86..68d953e902 100644 --- a/internal/msgtransfer/init.go +++ b/internal/msgtransfer/init.go @@ -80,11 +80,6 @@ func Start(ctx context.Context, index int, config *Config) error { if err != nil { return err } - - if err := client.CreateRpcRootNodes(config.Share.RpcRegisterName.GetServiceNames()); err != nil { - return err - } - client.AddOption(mw.GrpcClient(), grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithDefaultServiceConfig(fmt.Sprintf(`{"LoadBalancingPolicy": "%s"}`, "round_robin"))) //todo MsgCacheTimeout diff --git a/internal/msgtransfer/online_history_msg_handler.go b/internal/msgtransfer/online_history_msg_handler.go index 9960aa5189..8691e92ab6 100644 --- a/internal/msgtransfer/online_history_msg_handler.go +++ b/internal/msgtransfer/online_history_msg_handler.go @@ -394,7 +394,7 @@ func (och *OnlineHistoryRedisConsumerHandler) ConsumeClaim( break } } - log.ZDebug(context.Background(), "online new session msg come", "highWaterMarkOffset", + log.ZInfo(context.Background(), "online new session msg come", "highWaterMarkOffset", claim.HighWaterMarkOffset(), "topic", claim.Topic(), "partition", claim.Partition()) var ( diff --git a/internal/push/push_handler.go b/internal/push/push_handler.go index 2246fb3f68..e09b0b2ec3 100644 --- a/internal/push/push_handler.go +++ b/internal/push/push_handler.go @@ -96,7 +96,7 @@ func (c *ConsumerHandler) handleMs2PsChat(ctx context.Context, msg []byte) { var err error switch msgFromMQ.MsgData.SessionType { case constant.ReadGroupChatType: - err = c.Push2SuperGroup(ctx, pbData.MsgData.GroupID, pbData.MsgData) + err = c.Push2Group(ctx, pbData.MsgData.GroupID, pbData.MsgData) default: var pushUserIDList []string isSenderSync := datautil.GetSwitchFromOptions(pbData.MsgData.Options, constant.IsSenderSync) @@ -108,7 +108,7 @@ func (c *ConsumerHandler) handleMs2PsChat(ctx context.Context, msg []byte) { err = c.Push2User(ctx, pushUserIDList, pbData.MsgData) } if err != nil { - log.ZError(ctx, "push failed", err, "msg", pbData.String()) + log.ZWarn(ctx, "push failed", err, "msg", pbData.String()) } } @@ -179,7 +179,7 @@ func (c *ConsumerHandler) shouldPushOffline(_ context.Context, msg *sdkws.MsgDat return true } -func (c *ConsumerHandler) Push2SuperGroup(ctx context.Context, groupID string, msg *sdkws.MsgData) (err error) { +func (c *ConsumerHandler) Push2Group(ctx context.Context, groupID string, msg *sdkws.MsgData) (err error) { log.ZDebug(ctx, "Get super group msg from msg_transfer and push msg", "msg", msg.String(), "groupID", groupID) var pushToUserIDs []string if err = c.webhookBeforeGroupOnlinePush(ctx, &c.config.WebhooksConfig.BeforeGroupOnlinePush, groupID, msg, diff --git a/internal/rpc/third/third.go b/internal/rpc/third/third.go index ad87fa6f5c..9bf8cafa9e 100644 --- a/internal/rpc/third/third.go +++ b/internal/rpc/third/third.go @@ -18,7 +18,6 @@ import ( "context" "fmt" "github.com/openimsdk/open-im-server/v3/pkg/common/config" - "net/url" "time" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" @@ -29,7 +28,6 @@ import ( "github.com/openimsdk/tools/db/mongoutil" "github.com/openimsdk/tools/db/redisutil" "github.com/openimsdk/tools/discovery" - "github.com/openimsdk/tools/errs" "github.com/openimsdk/tools/s3" "github.com/openimsdk/tools/s3/cos" "github.com/openimsdk/tools/s3/minio" @@ -38,7 +36,6 @@ import ( ) type thirdServer struct { - apiURL string thirdDatabase controller.ThirdDatabase s3dataBase controller.S3Database userRpcClient rpcclient.UserRpcClient @@ -73,18 +70,6 @@ func Start(ctx context.Context, config *Config, client discovery.SvcDiscoveryReg if err != nil { return err } - apiURL := config.MinioConfig.URL - if apiURL == "" { - return errs.Wrap(fmt.Errorf("api is empty")) - } - if _, err := url.Parse(config.MinioConfig.URL); err != nil { - return err - } - if apiURL[len(apiURL)-1] != '/' { - apiURL += "/" - } - apiURL += "object/" - // Select the oss method according to the profile policy enable := config.RpcConfig.Object.Enable var o s3.Interface @@ -103,7 +88,6 @@ func Start(ctx context.Context, config *Config, client discovery.SvcDiscoveryReg } cache.InitLocalCache(&config.LocalCacheConfig) third.RegisterThirdServer(server, &thirdServer{ - apiURL: apiURL, thirdDatabase: controller.NewThirdDatabase(cache.NewThirdCache(rdb), logdb), userRpcClient: rpcclient.NewUserRpcClient(client, config.Share.RpcRegisterName.User, config.Share.IMAdminUserID), s3dataBase: controller.NewS3Database(rdb, o, s3db), diff --git a/pkg/common/config/config.go b/pkg/common/config/config.go index 19edccbab2..df2639cab3 100644 --- a/pkg/common/config/config.go +++ b/pkg/common/config/config.go @@ -22,6 +22,7 @@ import ( "github.com/openimsdk/tools/s3/cos" "github.com/openimsdk/tools/s3/minio" "github.com/openimsdk/tools/s3/oss" + "net" "time" ) @@ -52,13 +53,11 @@ type Log struct { type Minio struct { Bucket string `mapstructure:"bucket"` - Port int `mapstructure:"port"` AccessKeyID string `mapstructure:"accessKeyID"` SecretAccessKey string `mapstructure:"secretAccessKey"` SessionToken string `mapstructure:"sessionToken"` - InternalIP string `mapstructure:"internalIP"` - ExternalIP string `mapstructure:"externalIP"` - URL string `mapstructure:"url"` + InternalAddress string `mapstructure:"internalAddress"` + ExternalAddress string `mapstructure:"externalAddress"` PublicRead bool `mapstructure:"publicRead"` } @@ -477,16 +476,24 @@ func (k *Kafka) Build() *kafka.Config { } } func (m *Minio) Build() *minio.Config { - return &minio.Config{ + conf := minio.Config{ Bucket: m.Bucket, - Endpoint: fmt.Sprintf("http://%s:%d", m.InternalIP, m.Port), AccessKeyID: m.AccessKeyID, SecretAccessKey: m.SecretAccessKey, SessionToken: m.SessionToken, - SignEndpoint: fmt.Sprintf("http://%s:%d", m.ExternalIP, m.Port), PublicRead: m.PublicRead, } - + if _, _, err := net.SplitHostPort(m.InternalAddress); err == nil { + conf.Endpoint = fmt.Sprintf("http://%s", m.InternalAddress) + } else { + conf.Endpoint = m.InternalAddress + } + if _, _, err := net.SplitHostPort(m.ExternalAddress); err == nil { + conf.SignEndpoint = fmt.Sprintf("http://%s", m.ExternalAddress) + } else { + conf.SignEndpoint = m.ExternalAddress + } + return &conf } func (c *Cos) Build() *cos.Config { return &cos.Config{ diff --git a/pkg/common/config/load_config_test.go b/pkg/common/config/load_config_test.go index 575448393f..256214565b 100644 --- a/pkg/common/config/load_config_test.go +++ b/pkg/common/config/load_config_test.go @@ -31,6 +31,8 @@ func TestLoadOpenIMRpcUserConfig(t *testing.T) { var user User err := LoadConfig("../../../config/openim-rpc-user.yml", "IMENV_OPENIM_RPC_USER", &user) assert.Nil(t, err) + //export IMENV_OPENIM_RPC_USER_RPC_LISTENIP="0.0.0.0" assert.Equal(t, "0.0.0.0", user.RPC.ListenIP) - assert.Equal(t, []int{10110}, user.RPC.Ports) + //export IMENV_OPENIM_RPC_USER_RPC_PORTS="10110,10111,10112" + assert.Equal(t, []int{10110, 10111, 10112}, user.RPC.Ports) } diff --git a/pkg/common/config/version b/pkg/common/config/version index 084e244cea..240bba9069 100644 --- a/pkg/common/config/version +++ b/pkg/common/config/version @@ -1 +1 @@ -3.6.0 \ No newline at end of file +3.7.0 \ No newline at end of file diff --git a/pkg/common/discoveryregister/discoveryregister.go b/pkg/common/discoveryregister/discoveryregister.go index b664ee34eb..38d7382fa6 100644 --- a/pkg/common/discoveryregister/discoveryregister.go +++ b/pkg/common/discoveryregister/discoveryregister.go @@ -33,6 +33,7 @@ const ( func NewDiscoveryRegister(zookeeperConfig *config.ZooKeeper, share *config.Share) (discovery.SvcDiscoveryRegistry, error) { switch share.Env { case zookeeperConst: + return zookeeper.NewZkClient( zookeeperConfig.Address, zookeeperConfig.Schema, diff --git a/pkg/localcache/cache.go b/pkg/localcache/cache.go index 91c490922f..0e040ad389 100644 --- a/pkg/localcache/cache.go +++ b/pkg/localcache/cache.go @@ -19,8 +19,8 @@ import ( "hash/fnv" "unsafe" - "github.com/openimsdk/localcache/link" - "github.com/openimsdk/localcache/lru" + "github.com/openimsdk/open-im-server/v3/pkg/localcache/link" + "github.com/openimsdk/open-im-server/v3/pkg/localcache/lru" ) type Cache[V any] interface { diff --git a/pkg/localcache/go.mod b/pkg/localcache/go.mod deleted file mode 100644 index 5f0793042e..0000000000 --- a/pkg/localcache/go.mod +++ /dev/null @@ -1,5 +0,0 @@ -module github.com/openimsdk/localcache - -go 1.19 - -require github.com/hashicorp/golang-lru/v2 v2.0.7 diff --git a/pkg/localcache/go.sum b/pkg/localcache/go.sum deleted file mode 100644 index b1d8cf8c44..0000000000 --- a/pkg/localcache/go.sum +++ /dev/null @@ -1 +0,0 @@ -github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= diff --git a/pkg/localcache/option.go b/pkg/localcache/option.go index e60d5aa07b..00bb9d0441 100644 --- a/pkg/localcache/option.go +++ b/pkg/localcache/option.go @@ -18,7 +18,7 @@ import ( "context" "time" - "github.com/openimsdk/localcache/lru" + "github.com/openimsdk/open-im-server/v3/pkg/localcache/lru" ) func defaultOption() *option { diff --git a/pkg/rpccache/conversation.go b/pkg/rpccache/conversation.go index 196657b4b3..55897a8dae 100644 --- a/pkg/rpccache/conversation.go +++ b/pkg/rpccache/conversation.go @@ -17,9 +17,9 @@ package rpccache import ( "context" - "github.com/openimsdk/localcache" "github.com/openimsdk/open-im-server/v3/pkg/common/cachekey" "github.com/openimsdk/open-im-server/v3/pkg/common/config" + "github.com/openimsdk/open-im-server/v3/pkg/localcache" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" pbconversation "github.com/openimsdk/protocol/conversation" "github.com/openimsdk/tools/errs" diff --git a/pkg/rpccache/friend.go b/pkg/rpccache/friend.go index 557b5cffc0..3e9e7863ab 100644 --- a/pkg/rpccache/friend.go +++ b/pkg/rpccache/friend.go @@ -17,9 +17,9 @@ package rpccache import ( "context" - "github.com/openimsdk/localcache" "github.com/openimsdk/open-im-server/v3/pkg/common/cachekey" "github.com/openimsdk/open-im-server/v3/pkg/common/config" + "github.com/openimsdk/open-im-server/v3/pkg/localcache" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" "github.com/openimsdk/tools/log" "github.com/redis/go-redis/v9" diff --git a/pkg/rpccache/group.go b/pkg/rpccache/group.go index daf76a7a01..7ba22beb82 100644 --- a/pkg/rpccache/group.go +++ b/pkg/rpccache/group.go @@ -17,9 +17,9 @@ package rpccache import ( "context" - "github.com/openimsdk/localcache" "github.com/openimsdk/open-im-server/v3/pkg/common/cachekey" "github.com/openimsdk/open-im-server/v3/pkg/common/config" + "github.com/openimsdk/open-im-server/v3/pkg/localcache" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" "github.com/openimsdk/protocol/sdkws" "github.com/openimsdk/tools/errs" diff --git a/pkg/rpccache/user.go b/pkg/rpccache/user.go index b31f187dba..0a7a4e4b84 100644 --- a/pkg/rpccache/user.go +++ b/pkg/rpccache/user.go @@ -17,9 +17,9 @@ package rpccache import ( "context" - "github.com/openimsdk/localcache" "github.com/openimsdk/open-im-server/v3/pkg/common/cachekey" "github.com/openimsdk/open-im-server/v3/pkg/common/config" + "github.com/openimsdk/open-im-server/v3/pkg/localcache" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" "github.com/openimsdk/protocol/sdkws" "github.com/openimsdk/tools/errs" diff --git a/scripts/create-topic.sh b/scripts/create-topic.sh index a719147a28..206075fb83 100755 --- a/scripts/create-topic.sh +++ b/scripts/create-topic.sh @@ -53,5 +53,3 @@ for topic in "${topics[@]}"; do done echo "All topics created." - - diff --git a/scripts/docker-start-all.sh b/scripts/docker-start-all.sh index 8d91cd7715..116038b536 100755 --- a/scripts/docker-start-all.sh +++ b/scripts/docker-start-all.sh @@ -21,9 +21,6 @@ #fixme This scripts is the total startup scripts #fixme The full name of the shell scripts that needs to be started is placed in the need_to_start_server_shell array -OPENIM_ROOT=$(dirname "${BASH_SOURCE[0]}")/.. -source "${OPENIM_ROOT}/scripts/install/common.sh" -openim::log::info "\n# Use Docker to start all OpenIM service" -trap 'openim::util::onCtrlC' INT -"${OPENIM_ROOT}"/scripts/start-all.sh 2>&1 & -tail -f ${DOCKER_LOG_FILE} +cd /openim/openim-server +mage start +tail -f /dev/null diff --git a/scripts/mongo-init.sh b/scripts/mongo-init.sh index ce2b86d90d..01199c4806 100755 --- a/scripts/mongo-init.sh +++ b/scripts/mongo-init.sh @@ -45,3 +45,4 @@ if (createUserResult.ok == 1) { EOF + From 65b6c3d17f41a185f503badbbb80b39e760a4eb5 Mon Sep 17 00:00:00 2001 From: xuan <146319162+wxuanF@users.noreply.github.com> Date: Wed, 24 Apr 2024 15:16:16 +0800 Subject: [PATCH 148/188] Update action (#2211) * Rename golangci-lint.yml to golangci-lint.bak * Update e2e-test.yml * Update openimci.yml --- .github/workflows/e2e-test.yml | 2 -- .github/workflows/{golangci-lint.yml => golangci-lint.bak} | 0 .github/workflows/openimci.yml | 1 + 3 files changed, 1 insertion(+), 2 deletions(-) rename .github/workflows/{golangci-lint.yml => golangci-lint.bak} (100%) diff --git a/.github/workflows/e2e-test.yml b/.github/workflows/e2e-test.yml index 62df69ed5c..6231697c25 100644 --- a/.github/workflows/e2e-test.yml +++ b/.github/workflows/e2e-test.yml @@ -80,7 +80,6 @@ jobs: - name: Module Operations run: | - sudo go mod tidy echo "===========> Verifying go-gitlint is installed" if [ ! -f ./_output/tools/go-gitlint ]; then export GOBIN=$(pwd)/_output/tools @@ -89,7 +88,6 @@ jobs: echo "===========> go-gitlint is installed in /home/ubuntu/DF/open-im-server/_output/tools/go-gitlint" fi - - name: Build, Start(make build && make start) run: | sudo ./scripts/install/install.sh -i diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.bak similarity index 100% rename from .github/workflows/golangci-lint.yml rename to .github/workflows/golangci-lint.bak diff --git a/.github/workflows/openimci.yml b/.github/workflows/openimci.yml index 033868a2ed..83d495a0e4 100644 --- a/.github/workflows/openimci.yml +++ b/.github/workflows/openimci.yml @@ -36,6 +36,7 @@ on: - "CONTRIBUTING/**" - "**.md" - "docs/**" + workflow_dispatch: jobs: From 38d58b53fac7e740450963a4d3cad1b356fc1845 Mon Sep 17 00:00:00 2001 From: xuan <146319162+wxuanF@users.noreply.github.com> Date: Wed, 24 Apr 2024 15:41:14 +0800 Subject: [PATCH 149/188] Update action (#2213) * Rename golangci-lint.yml to golangci-lint.bak * Update e2e-test.yml * Update openimci.yml * Rename docker-buildx.yml to docker-buildx.bak --- .github/workflows/{docker-buildx.yml => docker-buildx.bak} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .github/workflows/{docker-buildx.yml => docker-buildx.bak} (100%) diff --git a/.github/workflows/docker-buildx.yml b/.github/workflows/docker-buildx.bak similarity index 100% rename from .github/workflows/docker-buildx.yml rename to .github/workflows/docker-buildx.bak From f8d05b7697b19550f7bc776d9dd515842cacf45d Mon Sep 17 00:00:00 2001 From: skiffer-git <72860476+skiffer-git@users.noreply.github.com> Date: Wed, 24 Apr 2024 15:42:43 +0800 Subject: [PATCH 150/188] update go.mod go.sum (#2210) * 3.6.1 code conventions (#2203) * Adjust configuration settings * Adjust configuration settings * Adjust configuration settings * refactor: webhooks update. * refactor: kafka update. * Simplify the Docker Compose configuration, remove unnecessary environment variables, and eliminate the gateway service. * refactor: kafka update. * refactor: kafka update. * Simplify the Docker Compose configuration, remove unnecessary environment variables, and eliminate the gateway service. * Simplify the Docker Compose configuration, remove unnecessary environment variables, and eliminate the gateway service. * Windows can compile and run. * Windows can compile and run. * refactor: kafka update. * feat: msg cache split * refactor: webhooks update * refactor: webhooks update * refactor: friends update * refactor: group update * refactor: third update * refactor: api update * refactor: crontab update * refactor: msggateway update * mage * mage * refactor: all module update. * check * refactor: all module update. * load config * load config * load config * load config * refactor: all module update. * refactor: all module update. * refactor: all module update. * refactor: all module update. * refactor: all module update. * Optimize Docker configuration and script. * refactor: all module update. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * refactor: all module update. * Optimize Docker configuration and script. * refactor: all module update. * refactor: all module update. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * update tools * update tools * Optimize Docker configuration and script. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * update protocol * Optimize Docker configuration and script. * Optimize Docker configuration and script. * refactor: all module update. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * refactor: api remove token auth by redis directly. * Code Refactoring * refactor: websocket auth change to call rpc of auth. * refactor: kick online user and remove token change to call auth rpc. * refactor: kick online user and remove token change to call auth rpc. * refactor: remove msggateway redis. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor webhook * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor webhook * refactor: cmd update. * refactor: cmd update. * fix: runtime: goroutine stack exceeds * refactor: cmd update. * refactor notification * refactor notification * refactor * refactor: cmd update. * refactor: cmd update. * refactor * refactor * refactor * protojson * protojson * protojson * go mod * wrapperspb * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: context update. * refactor: websocket update info. * refactor: websocket update info. * refactor: websocket update info. * refactor: websocket update info. * refactor: api name change. * refactor: debug info. * refactor: debug info. * refactor: debug info. * fix: update file * refactor * refactor * refactor: debug info. * refactor: debug info. * refactor: debug info. * refactor: debug info. * refactor: debug info. * refactor: debug info. * fix: callback update. * fix: callback update. * refactor * fix: update message. * fix: msg cache timeout. * refactor * refactor * fix: push update. * fix: push update. * fix: push update. * fix: push update. * fix: push update. * fix: push update. * refactor * refactor * fix: push update. * fix: websocket handle error remove when upgrade error. * fix: priority url * fix: minio config * refactor: add zk logger. * refactor * fix: minio config * refactor * remove \r * remove \r * remove \r * remove \r * remove \r * remove \r * remove \r * remove \r * remove \r * remove \r * fix bug: get localIP * refactor * refactor * refactor * refactor: remove zk logger. * refactor: update tools version. * refactor * refactor: update server version to 3.7.0. * refactor * refactor * refactor * refactor * refactor * refactor * refactor * refactor * refactor * refactor * refactor * refactor * refactor * refactor: zk log debug. * refactor: zk log debug. * refactor: zk log debug. * refactor: zk log debug. * refactor: zk log debug. * refactor * refactor * refactor * refactor: log level change. * refactor: 3.7.0 code conventions. --------- Co-authored-by: skiffer-git <44203734@qq.com> Co-authored-by: withchao <993506633@qq.com> Co-authored-by: root * update go.mod go.sum * Remove Chinese comments * user localhost for minio * user localhost for minio * Remove Chinese comments * Remove Chinese comments * Remove Chinese comments * Set up 4 instances of transfer * Set up 4 instances of transfer * Add comments to the configuration file * Add comments to the configuration file --------- Co-authored-by: OpenIM-Gordon <46924906+FGadvancer@users.noreply.github.com> Co-authored-by: withchao <993506633@qq.com> Co-authored-by: root --- config/kafka.yml | 18 ++++++++++++++++++ config/minio.yml | 13 +++++++++++-- config/mongodb.yml | 9 ++++++++- config/notification.yml | 9 --------- config/openim-msggateway.yml | 11 +++++++++++ config/openim-msgtransfer.yml | 3 +++ config/openim-push.yml | 9 ++++++++- config/openim-rpc-auth.yml | 7 ++++++- config/openim-rpc-conversation.yml | 8 +++++--- config/openim-rpc-friend.yml | 5 +++++ config/openim-rpc-group.yml | 6 +++++- config/openim-rpc-msg.yml | 8 +++++++- config/openim-rpc-third.yml | 7 +++++++ go.mod | 2 +- go.sum | 19 +++++++++++++++++++ internal/push/offlinepush/offlinepusher.go | 2 +- internal/push/push_handler.go | 2 +- start-config.yml | 4 +--- 18 files changed, 117 insertions(+), 25 deletions(-) diff --git a/config/kafka.yml b/config/kafka.yml index b1773c80a8..d412e1be06 100644 --- a/config/kafka.yml +++ b/config/kafka.yml @@ -1,18 +1,36 @@ +# Username for authentication username: '' +# Password for authentication password: '' +# Producer acknowledgment settings producerAck: "" +# Compression type to use (e.g., none, gzip, snappy) compressType: "none" +# List of Kafka broker addresses address: [ localhost:19094 ] +# Kafka topic for Redis integration toRedisTopic: "toRedis" +# Kafka topic for MongoDB integration toMongoTopic: "toMongo" +# Kafka topic for push notifications toPushTopic: "toPush" +# Consumer group ID for Redis topic toRedisGroupID: redis +# Consumer group ID for MongoDB topic toMongoGroupID: mongo +# Consumer group ID for push notifications topic toPushGroupID: push +# TLS (Transport Layer Security) configuration tls: + # Enable or disable TLS enableTLS: false + # CA certificate file path caCrt: "" + # Client certificate file path clientCrt: "" + # Client key file path clientKey: "" + # Client key password clientKeyPwd: "" + # Whether to skip TLS verification (not recommended for production) insecureSkipVerify: false diff --git a/config/minio.yml b/config/minio.yml index 0a80bb845c..11a9ace354 100644 --- a/config/minio.yml +++ b/config/minio.yml @@ -1,7 +1,16 @@ +# Name of the bucket in MinIO bucket: "openim" +# Access key ID for MinIO authentication accessKeyID: "root" +# Secret access key for MinIO authentication secretAccessKey: "openIM123" +# Session token for MinIO authentication (optional) sessionToken: '' -internalAddress: "minio:9000" +# Internal address of the MinIO server +internalAddress: "localhost:10005" +# External address of the MinIO server, accessible from outside. Supports both HTTP and HTTPS using a domain name externalAddress: "http://external_ip:10005" -publicRead: false \ No newline at end of file +# Flag to enable or disable public read access to the bucket +publicRead: false + + diff --git a/config/mongodb.yml b/config/mongodb.yml index 12f1f66a55..98f5694e45 100644 --- a/config/mongodb.yml +++ b/config/mongodb.yml @@ -1,7 +1,14 @@ +# URI for database connection, leave empty if using address and credential settings directly uri: '' +# List of MongoDB server addresses address: [ localhost:37017 ] +# Name of the database database: openim_v3 +# Username for database authentication username: openIM +# Password for database authentication password: openIM123 +# Maximum number of connections in the connection pool maxPoolSize: 100 -maxRetry: 10 \ No newline at end of file +# Maximum number of retry attempts for a failed database connection +maxRetry: 10 diff --git a/config/notification.yml b/config/notification.yml index 1afb44e467..278376c244 100644 --- a/config/notification.yml +++ b/config/notification.yml @@ -17,32 +17,23 @@ # The options field 'isNotification' indicates if it's a notification. groupCreated: isSendMsg: true - # Reliability level of the message sending. # Set to 1 to send only when online, 2 for guaranteed delivery. reliabilityLevel: 1 - # This setting is effective only when 'isSendMsg' is true. # It controls whether to count unread messages. unreadCount: false - # Configuration for offline push notifications. offlinePush: # Enables or disables offline push notifications. enable: false - # Title for the notification when a group is created. title: "create group title" - # Description for the notification. desc: "create group desc" - # Additional information for the notification. ext: "create group ext" -# Content type is not added here. -# Content should use a JSON structure conforming to the protobuf format. - groupInfoSet: isSendMsg: false reliabilityLevel: 1 diff --git a/config/openim-msggateway.yml b/config/openim-msggateway.yml index ad6e180cca..0c92d83278 100644 --- a/config/openim-msggateway.yml +++ b/config/openim-msggateway.yml @@ -1,19 +1,30 @@ rpc: + # The IP address where this RPC service registers itself; if left blank, it defaults to the internal network IP registerIP: '' + # List of ports that the RPC service listens on; configuring multiple ports will launch multiple instances. These must match the number of configured prometheus ports ports: [ 10140 ] prometheus: + # Enable or disable Prometheus monitoring enable: true + # List of ports that Prometheus listens on; these must match the number of rpc.ports to ensure correct monitoring setup ports: [ 20112 ] +# IP address that the RPC/WebSocket 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 longConnSvr: + # WebSocket listening ports, must match the number of rpc.ports ports: [ 10001 ] + # Maximum number of WebSocket connections websocketMaxConnNum: 100000 + # Maximum length of the entire WebSocket message packet websocketMaxMsgLen: 4096 + # WebSocket connection handshake timeout in seconds websocketTimeout: 10 +# 1: For Android, iOS, Windows, Mac, and web platforms, only one instance can be online at a time multiLoginPolicy: 1 + diff --git a/config/openim-msgtransfer.yml b/config/openim-msgtransfer.yml index 9cb1598b5b..07a7dc1ab1 100644 --- a/config/openim-msgtransfer.yml +++ b/config/openim-msgtransfer.yml @@ -1,3 +1,6 @@ prometheus: + # Enable or disable Prometheus monitoring enable: true + # List of ports that Prometheus listens on; each port corresponds to an instance of monitoring. Ensure these are managed accordingly + # Because four instances have been launched, four ports need to be specified ports: [ 20108, 20109, 20110, 20111 ] diff --git a/config/openim-push.yml b/config/openim-push.yml index 35e1b2c07d..a1abfcf889 100644 --- a/config/openim-push.yml +++ b/config/openim-push.yml @@ -1,14 +1,20 @@ 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. These must match the number of configured prometheus ports ports: [ 10170 ] prometheus: + # Enable or disable Prometheus monitoring enable: true + # List of ports that Prometheus listens on; these must match the number of rpc.ports to ensure correct monitoring setup ports: [ 20107 ] maxConcurrentWorkers: 3 -enable: getui +#"Use geTui for offline push notifications, or choose fcm or jpns; corresponding configuration settings must be specified." +enable: "geTui" geTui: pushUrl: "https://restapi.getui.com/v2/$appId" masterSecret: '' @@ -24,6 +30,7 @@ jpns: pushURL: '' pushIntent: '' +# iOS system push sound and badge count iosPush: pushSound: "xxx" badgeCount: true diff --git a/config/openim-rpc-auth.yml b/config/openim-rpc-auth.yml index a77b5457e8..2d861cd5ab 100644 --- a/config/openim-rpc-auth.yml +++ b/config/openim-rpc-auth.yml @@ -1,13 +1,18 @@ 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. These must match the number of configured prometheus ports ports: [ 10160 ] prometheus: + # Enable or disable Prometheus monitoring enable: true + # List of ports that Prometheus listens on; these must match the number of rpc.ports to ensure correct monitoring setup ports: [ 20106 ] tokenPolicy: - #token有效期,单位(天) + # Token validity period, in days expire: 90 diff --git a/config/openim-rpc-conversation.yml b/config/openim-rpc-conversation.yml index e2d9b6a536..a094bfac10 100644 --- a/config/openim-rpc-conversation.yml +++ b/config/openim-rpc-conversation.yml @@ -1,11 +1,13 @@ 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. These must match the number of configured prometheus ports ports: [ 10180 ] prometheus: + # Enable or disable Prometheus monitoring enable: true + # List of ports that Prometheus listens on; these must match the number of rpc.ports to ensure correct monitoring setup ports: [ 20105 ] - - - diff --git a/config/openim-rpc-friend.yml b/config/openim-rpc-friend.yml index 109e3f658f..7b829f971c 100644 --- a/config/openim-rpc-friend.yml +++ b/config/openim-rpc-friend.yml @@ -1,8 +1,13 @@ 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. These must match the number of configured prometheus ports ports: [ 10120 ] prometheus: + # Enable or disable Prometheus monitoring enable: true + # List of ports that Prometheus listens on; these must match the number of rpc.ports to ensure correct monitoring setup ports: [ 20104 ] diff --git a/config/openim-rpc-group.yml b/config/openim-rpc-group.yml index a70d6f96e2..78b44030e0 100644 --- a/config/openim-rpc-group.yml +++ b/config/openim-rpc-group.yml @@ -1,9 +1,13 @@ 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. These must match the number of configured prometheus ports ports: [ 10150 ] prometheus: + # Enable or disable Prometheus monitoring enable: true + # List of ports that Prometheus listens on; these must match the number of rpc.ports to ensure correct monitoring setup ports: [ 20103 ] - diff --git a/config/openim-rpc-msg.yml b/config/openim-rpc-msg.yml index de5e2324df..17ce26e9b2 100644 --- a/config/openim-rpc-msg.yml +++ b/config/openim-rpc-msg.yml @@ -1,13 +1,19 @@ 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. These must match the number of configured prometheus ports ports: [ 10130 ] prometheus: + # Enable or disable Prometheus monitoring enable: true + # List of ports that Prometheus listens on; these must match the number of rpc.ports to ensure correct monitoring setup ports: [ 20102 ] -#发消息是否需要好友验证 + +# Does sending messages require friend verification friendVerify: false diff --git a/config/openim-rpc-third.yml b/config/openim-rpc-third.yml index e3a847bf2c..bb41c93aee 100644 --- a/config/openim-rpc-third.yml +++ b/config/openim-rpc-third.yml @@ -1,13 +1,20 @@ 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. These must match the number of configured prometheus ports ports: [ 10190 ] prometheus: + # Enable or disable Prometheus monitoring enable: true + # List of ports that Prometheus listens on; these must match the number of rpc.ports to ensure correct monitoring setup ports: [ 20101 ] + object: + # Use MinIO as object storage, or set to "cos", "oss", "kodo", "aws", while also configuring the corresponding settings enable: "minio" cos: bucketURL: https://temp-1252357374.cos.ap-chengdu.myqcloud.com diff --git a/go.mod b/go.mod index 891125a899..1279a12857 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/openimsdk/open-im-server/v3 -go 1.20 +go 1.21.2 require ( firebase.google.com/go v3.13.0+incompatible diff --git a/go.sum b/go.sum index 5dc0cc524c..9b31342d84 100644 --- a/go.sum +++ b/go.sum @@ -22,10 +22,13 @@ github.com/QcloudApi/qcloud_sign_golang v0.0.0-20141224014652-e4130a326409/go.mo github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible h1:8psS8a+wKfiLt1iVDX79F7Y6wUM49Lcha2FMXt4UM8g= github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8= github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= +github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs= +github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c= github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA= +github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0= github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s= github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= @@ -43,6 +46,7 @@ github.com/clbanning/mxj v1.8.4/go.mod h1:BVjHeAH+rl9rs6f+QIpeRl0tfu10SXn1pUSa5P github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/xds/go v0.0.0-20231128003011-0fa0005c9caa h1:jQCWAUqqlij9Pgj2i/PB79y4KOPYVyFYdROxgaCwdTQ= +github.com/cncf/xds/go v0.0.0-20231128003011-0fa0005c9caa/go.mod h1:x/1Gn8zydmfq8dk6e9PdstVsDgu9RuyIIJqAaF//0IM= github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= 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= @@ -66,12 +70,15 @@ github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.m github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/envoyproxy/protoc-gen-validate v1.0.4 h1:gVPz/FMfvh57HdSJQyvBtF00j8JU4zdyUgIUNhlgg0A= +github.com/envoyproxy/protoc-gen-validate v1.0.4/go.mod h1:qys6tmnRsYrQqIhm2bvKZH4Blx/1gTIZ2UKVY1M+Yew= github.com/fatih/color v1.14.1 h1:qfhVLaG5s+nCROl1zJsZRxFeYrHLqWroPOQ8BWiNb4w= github.com/fatih/color v1.14.1/go.mod h1:2oHN61fhTpgcxD3TSWCgKDiH1+x4OiDVVGH8WlgGZGg= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= +github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= 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/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= @@ -90,6 +97,7 @@ github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre 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-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= github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= @@ -137,11 +145,13 @@ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian/v3 v3.3.2 h1:IqNFLAmvJOgVlpdEBiQbDc2EwKW77amAycfTuWKdfvw= +github.com/google/martian/v3 v3.3.2/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o= github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= @@ -194,6 +204,7 @@ github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkr 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/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/kelindar/bitmap v1.5.2 h1:XwX7CTvJtetQZ64zrOkApoZZHBJRkjE23NfqUALA/HE= @@ -209,7 +220,9 @@ github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa02 github.com/klauspost/cpuid/v2 v2.2.6 h1:ndNyv040zDGIDh8thGkXYjnFtiN02M1PVVF+JE/48xc= github.com/klauspost/cpuid/v2 v2.2.6/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= github.com/lestrrat-go/envload v0.0.0-20180220234015-a3eb8ddeffcc h1:RKf14vYWi2ttpEmkA4aQ3j4u9dStX2t4M8UM6qqNsG8= @@ -282,6 +295,7 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g= +github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U= github.com/prometheus/client_golang v1.18.0 h1:HzFfmkOzH5Q8L8G+kSJKUx5dtG87sewO+FoDDqP5Tbk= github.com/prometheus/client_golang v1.18.0/go.mod h1:T+GXkCk5wSJyOqMIzVgvvjFDlkOQntgjkJWKrN5txjA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= @@ -298,6 +312,7 @@ github.com/redis/go-redis/v9 v9.4.0/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0 github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= +github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= github.com/rs/xid v1.5.0 h1:mKX4bl4iPYJtEIxp6CYiUuLQ/8DYMoz0PUdtGgMFRVc= github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= @@ -376,6 +391,7 @@ go.opentelemetry.io/otel v1.23.0/go.mod h1:YCycw9ZeKhcJFrb34iVSkyT0iczq/zYDtZYFu go.opentelemetry.io/otel/metric v1.23.0 h1:pazkx7ss4LFVVYSxYew7L5I6qvLXHA0Ap2pwV+9Cnpo= go.opentelemetry.io/otel/metric v1.23.0/go.mod h1:MqUW2X2a6Q8RN96E2/nqNoT+z9BSms20Jb7Bbp+HiTo= go.opentelemetry.io/otel/sdk v1.21.0 h1:FTt8qirL1EysG6sTQRZ5TokkU8d0ugCj8htOgThZXQ8= +go.opentelemetry.io/otel/sdk v1.21.0/go.mod h1:Nna6Yv7PWTdgJHVRD9hIYywQBRx7pbox6nwBnZIxl/E= go.opentelemetry.io/otel/trace v1.23.0 h1:37Ik5Ib7xfYVb4V1UtnT97T1jI+AoIYkJyPkuL4iJgI= go.opentelemetry.io/otel/trace v1.23.0/go.mod h1:GSGTbIClEsuZrGIzoEHqsVfxgn5UkggkflQwDScNUsk= go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= @@ -383,6 +399,7 @@ go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/automaxprocs v1.5.3 h1:kWazyxZUrS3Gs4qUpbwo5kEIMGe/DAvi5Z4tl2NW4j8= go.uber.org/automaxprocs v1.5.3/go.mod h1:eRbA25aqJrxAbsLO0xy5jVwPt7FQnRgjW+efnwa1WM0= go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= +go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60= @@ -489,6 +506,7 @@ golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8T 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= golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk= +golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= google.golang.org/api v0.165.0 h1:zd5d4JIIIaYYsfVy1HzoXYZ9rWCSBxxAglbczzo7Bgc= google.golang.org/api v0.165.0/go.mod h1:2OatzO7ZDQsoS7IFf3rvsE17/TldiU3F/zxFHeqUB5o= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= @@ -526,6 +544,7 @@ google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGm google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= diff --git a/internal/push/offlinepush/offlinepusher.go b/internal/push/offlinepush/offlinepusher.go index 0706be64a4..d4fcae434a 100644 --- a/internal/push/offlinepush/offlinepusher.go +++ b/internal/push/offlinepush/offlinepusher.go @@ -26,7 +26,7 @@ import ( ) const ( - geTUI = "getui" + geTUI = "geTui" firebase = "fcm" jPush = "jpush" ) diff --git a/internal/push/push_handler.go b/internal/push/push_handler.go index e09b0b2ec3..3a9a696f64 100644 --- a/internal/push/push_handler.go +++ b/internal/push/push_handler.go @@ -259,7 +259,7 @@ func (c *ConsumerHandler) groupMessagesHandler(ctx context.Context, groupID stri *pushToUserIDs = append(*pushToUserIDs, kickedUsers...) case constant.GroupDismissedNotification: - if msgprocessor.IsNotification(msgprocessor.GetConversationIDByMsg(msg)) { // 消息先到,通知后到 + if msgprocessor.IsNotification(msgprocessor.GetConversationIDByMsg(msg)) { var tips sdkws.GroupDismissedTips if unmarshalNotificationElem(msg.Content, &tips) != nil { return err diff --git a/start-config.yml b/start-config.yml index cd9663c98b..a9c412b33f 100644 --- a/start-config.yml +++ b/start-config.yml @@ -4,7 +4,7 @@ serviceBinaries: openim-rpc-user: 1 openim-msggateway: 1 openim-push: 1 - openim-msgtransfer: 1 + openim-msgtransfer: 4 openim-rpc-conversation: 1 openim-rpc-auth: 1 openim-rpc-group: 1 @@ -12,8 +12,6 @@ serviceBinaries: openim-rpc-msg: 1 openim-rpc-third: 1 toolBinaries: - - ncpu - check-free-memory - - versionchecker - check-component maxFileDescriptors: 10000 From 37c0f48055592b6237997e4ecf9c1f8e1173991a Mon Sep 17 00:00:00 2001 From: skiffer-git <72860476+skiffer-git@users.noreply.github.com> Date: Thu, 25 Apr 2024 14:21:32 +0800 Subject: [PATCH 151/188] Update the document (#2219) * 3.6.1 code conventions (#2203) * Adjust configuration settings * Adjust configuration settings * Adjust configuration settings * refactor: webhooks update. * refactor: kafka update. * Simplify the Docker Compose configuration, remove unnecessary environment variables, and eliminate the gateway service. * refactor: kafka update. * refactor: kafka update. * Simplify the Docker Compose configuration, remove unnecessary environment variables, and eliminate the gateway service. * Simplify the Docker Compose configuration, remove unnecessary environment variables, and eliminate the gateway service. * Windows can compile and run. * Windows can compile and run. * refactor: kafka update. * feat: msg cache split * refactor: webhooks update * refactor: webhooks update * refactor: friends update * refactor: group update * refactor: third update * refactor: api update * refactor: crontab update * refactor: msggateway update * mage * mage * refactor: all module update. * check * refactor: all module update. * load config * load config * load config * load config * refactor: all module update. * refactor: all module update. * refactor: all module update. * refactor: all module update. * refactor: all module update. * Optimize Docker configuration and script. * refactor: all module update. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * refactor: all module update. * Optimize Docker configuration and script. * refactor: all module update. * refactor: all module update. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * update tools * update tools * Optimize Docker configuration and script. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * update protocol * Optimize Docker configuration and script. * Optimize Docker configuration and script. * refactor: all module update. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * refactor: api remove token auth by redis directly. * Code Refactoring * refactor: websocket auth change to call rpc of auth. * refactor: kick online user and remove token change to call auth rpc. * refactor: kick online user and remove token change to call auth rpc. * refactor: remove msggateway redis. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor webhook * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor webhook * refactor: cmd update. * refactor: cmd update. * fix: runtime: goroutine stack exceeds * refactor: cmd update. * refactor notification * refactor notification * refactor * refactor: cmd update. * refactor: cmd update. * refactor * refactor * refactor * protojson * protojson * protojson * go mod * wrapperspb * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: context update. * refactor: websocket update info. * refactor: websocket update info. * refactor: websocket update info. * refactor: websocket update info. * refactor: api name change. * refactor: debug info. * refactor: debug info. * refactor: debug info. * fix: update file * refactor * refactor * refactor: debug info. * refactor: debug info. * refactor: debug info. * refactor: debug info. * refactor: debug info. * refactor: debug info. * fix: callback update. * fix: callback update. * refactor * fix: update message. * fix: msg cache timeout. * refactor * refactor * fix: push update. * fix: push update. * fix: push update. * fix: push update. * fix: push update. * fix: push update. * refactor * refactor * fix: push update. * fix: websocket handle error remove when upgrade error. * fix: priority url * fix: minio config * refactor: add zk logger. * refactor * fix: minio config * refactor * remove \r * remove \r * remove \r * remove \r * remove \r * remove \r * remove \r * remove \r * remove \r * remove \r * fix bug: get localIP * refactor * refactor * refactor * refactor: remove zk logger. * refactor: update tools version. * refactor * refactor: update server version to 3.7.0. * refactor * refactor * refactor * refactor * refactor * refactor * refactor * refactor * refactor * refactor * refactor * refactor * refactor * refactor: zk log debug. * refactor: zk log debug. * refactor: zk log debug. * refactor: zk log debug. * refactor: zk log debug. * refactor * refactor * refactor * refactor: log level change. * refactor: 3.7.0 code conventions. --------- Co-authored-by: skiffer-git <44203734@qq.com> Co-authored-by: withchao <993506633@qq.com> Co-authored-by: root * update go.mod go.sum (#2209) * remove \r * remove \r * remove \r * remove \r * remove \r * remove \r * remove \r * remove \r * remove \r * remove \r * fix bug: get localIP * update some ci file (#2200) * Update openimci.yml * Update golangci-lint.yml * Update e2e-test.yml * 3.6.1 code conventions (#2202) * refactor: webhooks update. * Adjust configuration settings * Adjust configuration settings * Adjust configuration settings * feat: s3 api addr * refactor: webhooks update. * Adjust configuration settings * Adjust configuration settings * Adjust configuration settings * Adjust configuration settings * Adjust configuration settings * Adjust configuration settings * Adjust configuration settings * refactor: webhooks update. * refactor: kafka update. * Simplify the Docker Compose configuration, remove unnecessary environment variables, and eliminate the gateway service. * refactor: kafka update. * refactor: kafka update. * Simplify the Docker Compose configuration, remove unnecessary environment variables, and eliminate the gateway service. * Simplify the Docker Compose configuration, remove unnecessary environment variables, and eliminate the gateway service. * Windows can compile and run. * Windows can compile and run. * refactor: kafka update. * feat: msg cache split * refactor: webhooks update * refactor: webhooks update * refactor: friends update * refactor: group update * refactor: third update * refactor: api update * refactor: crontab update * refactor: msggateway update * mage * mage * refactor: all module update. * check * refactor: all module update. * load config * load config * load config * load config * refactor: all module update. * refactor: all module update. * refactor: all module update. * refactor: all module update. * refactor: all module update. * Optimize Docker configuration and script. * refactor: all module update. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * refactor: all module update. * Optimize Docker configuration and script. * refactor: all module update. * refactor: all module update. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * update tools * update tools * Optimize Docker configuration and script. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * update protocol * Optimize Docker configuration and script. * Optimize Docker configuration and script. * refactor: all module update. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * refactor: api remove token auth by redis directly. * Code Refactoring * refactor: websocket auth change to call rpc of auth. * refactor: kick online user and remove token change to call auth rpc. * refactor: kick online user and remove token change to call auth rpc. * refactor: remove msggateway redis. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor webhook * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor webhook * refactor: cmd update. * refactor: cmd update. * fix: runtime: goroutine stack exceeds * refactor: cmd update. * refactor notification * refactor notification * refactor * refactor: cmd update. * refactor: cmd update. * refactor * refactor * refactor * protojson * protojson * protojson * go mod * wrapperspb * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: context update. * refactor: websocket update info. * refactor: websocket update info. * refactor: websocket update info. * refactor: websocket update info. * refactor: api name change. * refactor: debug info. * refactor: debug info. * refactor: debug info. * fix: update file * refactor * refactor * refactor: debug info. * refactor: debug info. * refactor: debug info. * refactor: debug info. * refactor: debug info. * refactor: debug info. * fix: callback update. * fix: callback update. * refactor * fix: update message. * fix: msg cache timeout. * refactor * refactor * fix: push update. * fix: push update. * fix: push update. * fix: push update. * fix: push update. * fix: push update. * refactor * refactor * fix: push update. * fix: websocket handle error remove when upgrade error. * fix: priority url * fix: minio config * refactor: add zk logger. * refactor * fix: minio config * refactor * refactor * refactor * refactor * refactor: remove zk logger. * refactor: update tools version. * refactor * refactor: update server version to 3.7.0. * refactor * refactor * refactor * refactor * refactor * refactor * refactor * refactor * refactor * refactor * refactor * refactor * refactor * refactor: zk log debug. * refactor: zk log debug. * refactor: zk log debug. * refactor: zk log debug. * refactor: zk log debug. * refactor * refactor * refactor * refactor: log level change. * refactor: 3.7.0 code conventions. --------- Co-authored-by: skiffer-git <44203734@qq.com> Co-authored-by: withchao <993506633@qq.com> * update go.mod go.sum * Remove Chinese comments * user localhost for minio * user localhost for minio * Remove Chinese comments * Remove Chinese comments * Remove Chinese comments * Set up 4 instances of transfer * Set up 4 instances of transfer * Add comments to the configuration file * Add comments to the configuration file --------- Co-authored-by: root Co-authored-by: xuan <146319162+wxuanF@users.noreply.github.com> Co-authored-by: OpenIM-Gordon <46924906+FGadvancer@users.noreply.github.com> Co-authored-by: withchao <993506633@qq.com> * Update the document * Update the document --------- Co-authored-by: OpenIM-Gordon <46924906+FGadvancer@users.noreply.github.com> Co-authored-by: withchao <993506633@qq.com> Co-authored-by: root Co-authored-by: xuan <146319162+wxuanF@users.noreply.github.com> --- README.md | 128 +++++++++++++++--------------------------------- README_zh_CN.md | 87 +++++++++++--------------------- docs/CODEOWNERS | 38 +++++++------- 3 files changed, 87 insertions(+), 166 deletions(-) diff --git a/README.md b/README.md index 175db3326b..a80bd14320 100644 --- a/README.md +++ b/README.md @@ -51,137 +51,89 @@

-## :busts_in_silhouette: Community +## :busts_in_silhouette: Join Our Community -+ 💬 [Follow our Twitter account](https://twitter.com/founder_im63606) -+ 👫 [Join our Reddit](https://www.reddit.com/r/OpenIMessaging) -+ 🚀 [Join our Slack community](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q) -+ :eyes: [Join our wechat (微信群)](https://openim-1253691595.cos.ap-nanjing.myqcloud.com/WechatIMG20.jpeg) -+ 📚 [OpenIM Community](https://github.com/OpenIMSDK/community) -+ 💕 [OpenIM Interest Group](https://github.com/Openim-sigs) ++ 💬 [Follow us on Twitter](https://twitter.com/founder_im63606) ++ 🚀 [Join our Slack](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q) ++ :eyes: [Join our WeChat Group](https://openim-1253691595.cos.ap-nanjing.myqcloud.com/WechatIMG20.jpeg) ## Ⓜ️ About OpenIM -OpenIM is a service platform specifically designed for integrating chat, audio-video calls, notifications, and AI chatbots into applications. It provides a range of powerful APIs and Webhooks, enabling developers to easily incorporate these interactive features into their applications. OpenIM is not a standalone chat application, but rather serves as a platform to support other applications in achieving rich communication functionalities. The following diagram illustrates the interaction between AppServer, AppClient, OpenIMServer, and OpenIMSDK to explain in detail. +Unlike standalone chat applications such as Telegram, Signal, and Rocket.Chat, OpenIM offers an open-source instant messaging solution designed specifically for developers rather than as a directly installable standalone chat app. Comprising OpenIM SDK and OpenIM Server, it provides developers with a complete set of tools and services to integrate instant messaging functions into their applications, including message sending and receiving, user management, and group management. Overall, OpenIM aims to provide developers with the necessary tools and framework to implement efficient instant messaging solutions in their applications. ![App-OpenIM Relationship](./docs/images/oepnim-design.png) -## 🚀 About OpenIMSDK +## 🚀 Introduction to OpenIMSDK -**OpenIMSDK** is an IM SDK designed for **OpenIMServer**, created specifically for embedding in client applications. Its main features and modules are as follows: +**OpenIMSDK**, designed for **OpenIMServer**, is an IM SDK created specifically for integration into client applications. It supports various functionalities and modules: + 🌟 Main Features: - - - 📦 Local storage - - 🔔 Listener callbacks - - 🛡️ API wrapping - - 🌐 Connection management + - 📦 Local Storage + - 🔔 Listener Callbacks + - 🛡️ API Wrapping + - 🌐 Connection Management + 📚 Main Modules: - 1. 🚀 Initialization and Login 2. 👤 User Management - 3. 👫 Friend Management + 3. 👫 Friends Management 4. 🤖 Group Functions - 5. 💬 Conversation Handling - -It is built using Golang and supports cross-platform deployment, ensuring a consistent access experience across all platforms. - -👉 **[Explore GO SDK](https://github.com/openimsdk/openim-sdk-core)** - -## 🌐 About OpenIMServer + 5. 💬 Session Handling -+ **OpenIMServer** has the following characteristics: - - 🌐 Microservice architecture: Supports cluster mode, including a gateway and multiple rpc services. - - 🚀 Diverse deployment methods: Supports deployment via source code, Kubernetes, or Docker. - - Support for massive user base: Super large groups with hundreds of thousands of users, tens of millions of users, and billions of messages. +Built with Golang and supports cross-platform deployment to ensure a consistent integration experience across all platforms. -### Enhanced Business Functionality: +👉 **[Explore the GO SDK](https://github.com/openimsdk/openim-sdk-core)** -+ **REST API**: OpenIMServer offers REST APIs for business systems, aimed at empowering businesses with more functionalities, such as creating groups and sending push messages through backend interfaces. -+ **Webhooks**: OpenIMServer provides callback capabilities to extend more business forms. A callback means that OpenIMServer sends a request to the business server before or after a certain event, like callbacks before or after sending a message. +## 🌐 Introduction to OpenIMServer -👉 **[Learn more](https://docs.openim.io/guides/introduction/product)** ++ **OpenIMServer** features include: + - 🌐 Microservices Architecture: Supports cluster mode, including a gateway and multiple rpc services. + - 🚀 Diverse Deployment Options: Supports source code, Kubernetes, or Docker deployment. + - Massive User Support: Supports large-scale groups with hundreds of thousands, millions of users, and billions of messages. -## :building_construction: Overall Architecture +### Enhanced Business Functions: -Delve into the heart of Open-IM-Server's functionality with our architecture diagram. ++ **REST API**: Provides a REST API for business systems to enhance functionality, such as group creation and message pushing through backend interfaces. -![Overall Architecture](./docs/images/architecture-layers.png) ++ **Webhooks**: Expands business forms through callbacks, sending requests to business servers before or after certain events. + ![Overall Architecture](./docs/images/architecture-layers.png) ## :rocket: Quick Start -We support many platforms. Here are the addresses for quick experience on the web side: +Experience online for iOS/Android/H5/PC/Web: -👉 **[OpenIM online web demo](https://web-enterprise.rentsoft.cn/)** +👉 **[OpenIM Online Demo](https://www.openim.io/en/commercial)** -🤲 To facilitate user experience, we offer various deployment solutions. You can choose your deployment method from the list below: +To facilitate user experience, we offer various deployment solutions. You can choose your preferred deployment method from the list below: + **[Source Code Deployment Guide](https://docs.openim.io/guides/gettingStarted/imSourceCodeDeployment)** + **[Docker Deployment Guide](https://docs.openim.io/guides/gettingStarted/dockerCompose)** -+ **[Kubernetes Deployment Guide](https://docs.openim.io/guides/gettingStarted/k8s-deployment)** -+ **[Mac Developer Deployment Guide](https://docs.openim.io/guides/gettingstarted/mac-deployment-guide)** - -## :hammer_and_wrench: To Start Developing OpenIM - -[![Open in Dev Container](https://img.shields.io/static/v1?label=Dev%20Container&message=Open&color=blue&logo=visualstudiocode)](https://vscode.dev/github/openimsdk/open-im-server) - -[![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/openimsdk/open-im-server) - -OpenIM Our goal is to build a top-level open source community. We have a set of standards, in the [Community repository](https://github.com/OpenIMSDK/community). -If you'd like to contribute to this Open-IM-Server repository, please read our [contributor documentation](https://github.com/openimsdk/open-im-server/blob/main/CONTRIBUTING.md). +## System Support -Before you start, please make sure your changes are in demand. The best for that is to create a [new discussion](https://github.com/openimsdk/open-im-server/discussions/new/choose) OR [Slack Communication](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q), or if you find an issue, [report it](https://github.com/openimsdk/open-im-server/issues/new/choose) first. +Supports Linux, Windows, Mac systems, and ARM and AMD CPU architectures. -- [OpenIM API Reference](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/api.md) -- [OpenIM Bash Logging](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/bash-log.md) -- [OpenIM CI/CD Actions](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/cicd-actions.md) -- [OpenIM Code Conventions](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/code-conventions.md) -- [OpenIM Commit Guidelines](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/commit.md) -- [OpenIM Development Guide](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/development.md) -- [OpenIM Directory Structure](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/directory.md) -- [OpenIM Environment Setup](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/environment.md) -- [OpenIM Error Code Reference](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/error-code.md) -- [OpenIM Git Workflow](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/git-workflow.md) -- [OpenIM Git Cherry Pick Guide](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/gitcherry-pick.md) -- [OpenIM GitHub Workflow](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/github-workflow.md) -- [OpenIM Go Code Standards](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/go-code.md) -- [OpenIM Image Guidelines](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/images.md) -- [OpenIM Initial Configuration](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/init-config.md) -- [OpenIM Docker Installation Guide](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/install-docker.md) -- [OpenIM OpenIM Linux System Installation](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/install-openim-linux-system.md) -- [OpenIM Linux Development Guide](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/linux-development.md) -- [OpenIM Local Actions Guide](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/local-actions.md) -- [OpenIM Logging Conventions](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/logging.md) -- [OpenIM Offline Deployment](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/offline-deployment.md) -- [OpenIM Protoc Tools](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/protoc-tools.md) -- [OpenIM Testing Guide](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/test.md) -- [OpenIM Utility Go](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/util-go.md) -- [OpenIM Makefile Utilities](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/util-makefile.md) -- [OpenIM Script Utilities](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/util-scripts.md) -- [OpenIM Versioning](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/version.md) -- [Manage backend and monitor deployment](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/prometheus-grafana.md) -- [Mac Developer Deployment Guide for OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/mac-developer-deployment-guide.md) +## :link: Links -## :calendar: Community Meetings + + **[Developer Manual](https://docs.openim.io/)** + + **[Changelog](https://github.com/openimsdk/open-im-server/blob/main/CHANGELOG.md)** -We want anyone to get involved in our community and contributing code, we offer gifts and rewards, and we welcome you to join us every Thursday night. +## :writing_hand: How to Contribute -Our conference is in the [OpenIM Slack](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q) 🎯, then you can search the Open-IM-Server pipeline to join +We welcome contributions of any kind! Please make sure to read our [Contributor Documentation](https://github.com/openimsdk/open-im-server/blob/main/CONTRIBUTING.md) before submitting a Pull Request. -We take notes of each [biweekly meeting](https://github.com/orgs/OpenIMSDK/discussions/categories/meeting) in [GitHub discussions](https://github.com/openimsdk/open-im-server/discussions/categories/meeting), Our historical meeting notes, as well as replays of the meetings are available at [Google Docs :bookmark_tabs:](https://docs.google.com/document/d/1nx8MDpuG74NASx081JcCpxPgDITNTpIIos0DS6Vr9GU/edit?usp=sharing). + + **[Report a Bug](https://github.com/openimsdk/open-im-server/issues/new?assignees=&labels=bug&template=bug_report.md&title=)** + + **[Suggest a Feature](https://github.com/openimsdk/open-im-server/issues/new?assignees=&labels=enhancement&template=feature_request.md&title=)** + + **[Submit a Pull Request](https://github.com/openimsdk/open-im-server/pulls)** -## :eyes: Who Are Using OpenIM +Thank you for contributing to building a powerful instant messaging solution! -Check out our [user case studies](https://github.com/OpenIMSDK/community/blob/main/ADOPTERS.md) page for a list of the project users. Don't hesitate to leave a [📝comment](https://github.com/openimsdk/open-im-server/issues/379) and share your use case. +## :closed_book: License -## :page_facing_up: License +OpenIMSDK is available under the Apache License 2.0. See the [LICENSE file](https://github.com/openimsdk/open-im-server/blob/main/LICENSE) for more information. -OpenIM is licensed under the Apache 2.0 license. See [LICENSE](https://github.com/openimsdk/open-im-server/tree/main/LICENSE) for the full license text. -The OpenIM logo, including its variations and animated versions, displayed in this repository [OpenIM](https://github.com/openimsdk/open-im-server) under the [assets/logo](./assets/logo) and [assets/logo-gif](assets/logo-gif) directories, are protected by copyright laws. ## 🔮 Thanks to our contributors! diff --git a/README_zh_CN.md b/README_zh_CN.md index f42031165f..e9e56994fb 100644 --- a/README_zh_CN.md +++ b/README_zh_CN.md @@ -51,31 +51,29 @@

-## 🟢 扫描微信进群交流 - +## :busts_in_silhouette: 加入我们的社区 ++ 💬 [关注我们的 Twitter](https://twitter.com/founder_im63606) ++ 🚀 [加入我们的 Slack](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q) ++ :eyes: [加入我们的微信群](https://openim-1253691595.cos.ap-nanjing.myqcloud.com/WechatIMG20.jpeg) ## Ⓜ️ 关于 OpenIM -OpenIM 是一个专门设计用于在应用程序中集成聊天、音视频通话、通知以及AI聊天机器人等通信功能的服务平台。它通过提供一系列强大的API和Webhooks,使开发者可以轻松地在他们的应用中加入这些交互特性。OpenIM 本身并不是一个独立运行的聊天应用,而是作为一个平台,为其他应用提供支持,实现丰富的通信功能。下图展示 AppServer、AppClient、OpenIMServer 和 OpenIMSDK 之间的交互关系来具体说明。 - - +与Telegram、Signal、Rocket.Chat等独立聊天应用不同,OpenIM提供了专为开发者设计的开源即时通讯解决方案,而不是直接安装使用的独立聊天应用。OpenIM由OpenIM SDK和OpenIM Server两大部分组成,为开发者提供了一整套集成即时通讯功能的工具和服务,包括消息发送接收、用户管理和群组管理等。总体来说,OpenIM旨在为开发者提供必要的工具和框架,帮助他们在自己的应用中实现高效的即时通讯解决方案。 ![App-OpenIM 关系](./docs/images/oepnim-design.png) -## 🚀 关于 OpenIMSDK +## 🚀 OpenIMSDK 介绍 -**OpenIMSDK** 是为 **OpenIMServer** 设计的IM SDK,专为嵌入客户端应用而生。其主要功能及模块如下: +**OpenIMSDK** 是为 **OpenIMServer** 设计的IM SDK,专为集成到客户端应用而生。它支持多种功能和模块: + 🌟 主要功能: - - 📦 本地存储 - 🔔 监听器回调 - 🛡️ API封装 - 🌐 连接管理 - ## 📚 主要模块: - ++ 📚 主要模块: 1. 🚀 初始化及登录 2. 👤 用户管理 3. 👫 好友管理 @@ -86,81 +84,52 @@ OpenIM 是一个专门设计用于在应用程序中集成聊天、音视频通 👉 **[探索 GO SDK](https://github.com/openimsdk/openim-sdk-core)** -## 🌐 关于 OpenIMServer +## 🌐 OpenIMServer 介绍 -+ **OpenIMServer** 具有以下特点: ++ **OpenIMServer** 的特点包括: - 🌐 微服务架构:支持集群模式,包括网关(gateway)和多个rpc服务。 - - 🚀 部署方式多样:支持源代码、kubernetes或docker部署。 - - 海量用户支持:十万超级大群,千万用户,及百亿消息 + - 🚀 多样的部署方式:支持源代码、Kubernetes或Docker部署。 + - 海量用户支持:支持十万级超大群组,千万级用户和百亿级消息。 ### 增强的业务功能: -+ **REST API**:OpenIMServer 提供了REST API供业务系统使用,旨在赋予业务更多功能,例如通过后台接口建立群组、发送推送消息等。 -+ **Webhooks**:OpenIMServer提供了回调能力以扩展更多的业务形态,所谓回调,即OpenIMServer会在某一事件发生之前或者之后,向业务服务器发送请求,如发送消息之前或之后的回调。 ++ **REST API**:为业务系统提供REST API,增加群组创建、消息推送等后台接口功能。 + ++ **Webhooks**:通过事件前后的回调,向业务服务器发送请求,扩展更多的业务形态。 -👉 **[了解更多](https://docs.openim.io/guides/introduction/product)** + ![整体架构](./docs/images/architecture-layers.png) -## :rocket: 快速开始 + + +## :rocket: 快速入门 在线体验iOS/Android/H5/PC/Web: -👉 **[OpenIM online demo](https://www.openim.io/zh/commercial)** +👉 **[OpenIM在线演示](https://www.openim.io/en/commercial)** -🤲 为了方便用户体验,我们提供了多种部署解决方案,您可以根据下面的列表选择自己的部署方法: +为了便于用户体验,我们提供了多种部署解决方案,您可以根据以下列表选择适合您的部署方式: + **[源代码部署指南](https://docs.openim.io/guides/gettingStarted/imSourceCodeDeployment)** + **[Docker 部署指南](https://docs.openim.io/guides/gettingStarted/dockerCompose)** -+ **[Kubernetes 部署指南](https://docs.openim.io/guides/gettingStarted/k8s-deployment)** - -## :hammer_and_wrench: 开始开发 OpenIM - -OpenIM 我们的目标是建立一个顶级的开源社区。我们有一套标准,在[社区仓库](https://github.com/OpenIMSDK/community)中。 - -如果你想为这个 Open-IM-Server 仓库做贡献,请阅读我们的[贡献者文档](https://github.com/openimsdk/open-im-server/blob/main/CONTRIBUTING.md)。 - -在开始之前,请确保你的更改是有需求的。最好的方法是创建一个[新的讨论](https://github.com/openimsdk/open-im-server/discussions/new/choose) 或 [Slack 通信](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q),或者如果你发现一个问题,首先[报告它](https://github.com/openimsdk/open-im-server/issues/new/choose)。 -+ [代码标准](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/go-code.md) +## 系统支持 -+ [Docker 镜像标准](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/images.md) +支持 Linux、Windows、Mac 系统以及 ARM 和 AMD CPU 架构。 -+ [目录标准](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/directory.md) +## :link: 相关链接 -+ [提交标准](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/commit.md) - -+ [版本控制标准](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/version.md) - -+ [接口标准](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/interface.md) - -+ [OpenIM配置和环境变量设置](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/environment.md) - -> **Note** -> 针对中国的用户,阅读我们的 [Docker 镜像标准](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/images.md) 以便使用国内 aliyun 的镜像地址。OpenIM 也有针对中国的 gitee 同步仓库,你可以在 [gitee.com](https://gitee.com/openimsdk) 上找到它。 - -## :link: 链接 - - + **[完整文档](https://doc.rentsoft.cn/)** + + **[开发手册](https://docs.openim.io/)** + **[更新日志](https://github.com/openimsdk/open-im-server/blob/main/CHANGELOG.md)** - + **[FAQ](https://github.com/openimsdk/open-im-server/blob/main/FAQ.md)** - + **[代码示例](https://github.com/openimsdk/open-im-server/blob/main/examples)** - -## :handshake: 社区 - - + **[GitHub Discussions](https://github.com/openimsdk/open-im-server/discussions)** - + **[Slack 通信](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q)** - + **[GitHub Issues](https://github.com/openimsdk/open-im-server/issues)** - - 您可以加入这些平台,讨论问题,提出建议,或分享您的成功故事! -## :writing_hand: 贡献 +## :writing_hand: 如何贡献 - 我们欢迎任何形式的贡献!请确保在提交 Pull Request 之前阅读我们的[贡献者文档](https://github.com/openimsdk/open-im-server/blob/main/CONTRIBUTING.md)。 +我们欢迎任何形式的贡献!在提交 Pull Request 之前,请确保阅读我们的[贡献者文档](https://github.com/openimsdk/open-im-server/blob/main/CONTRIBUTING.md) + **[报告 Bug](https://github.com/openimsdk/open-im-server/issues/new?assignees=&labels=bug&template=bug_report.md&title=)** + **[提出新特性](https://github.com/openimsdk/open-im-server/issues/new?assignees=&labels=enhancement&template=feature_request.md&title=)** + **[提交 Pull Request](https://github.com/openimsdk/open-im-server/pulls)** - 感谢您的贡献,我们一起打造一个强大的即时通信解决方案! +感谢您的贡献,一起来打造强大的即时通讯解决方案! ## :closed_book: 许可证 diff --git a/docs/CODEOWNERS b/docs/CODEOWNERS index d1119eb611..68e459f9dd 100644 --- a/docs/CODEOWNERS +++ b/docs/CODEOWNERS @@ -2,28 +2,28 @@ # Each line is a file pattern followed by one or more owners. # README files -README.md @openimsdk/openim @cubxxw @openimsdk/bot @Bloomingg @FGadvancer @skiffer-git @rfyiamcool @withchao +README.md @openimsdk/openim @openimsdk/bot @Bloomingg @FGadvancer @skiffer-git @withchao # Contributing guidelines -CONTRIBUTING.md @cubxxw @openimsdk/bot @Bloomingg @FGadvancer @skiffer-git @rfyiamcool @withchao +CONTRIBUTING.md @openimsdk/bot @Bloomingg @FGadvancer @skiffer-git @withchao # License files -LICENSE @cubxxw @openimsdk/bot @Bloomingg @FGadvancer @skiffer-git @rfyiamcool @withchao +LICENSE @openimsdk/bot @Bloomingg @FGadvancer @skiffer-git @withchao # Makefile -Makefile @cubxxw @openimsdk/bot @Bloomingg @FGadvancer @skiffer-git @rfyiamcool @withchao +Makefile @openimsdk/bot @Bloomingg @FGadvancer @skiffer-git @withchao # These owners will be the default owners for everything in # the repo. Unless a later match takes precedence, -# @cubxxw and @openimsdk/bot will be requested for +# and @openimsdk/bot will be requested for # review when someone opens a pull request. -* @openimsdk/openim @cubxxw @openimsdk/bot @Bloomingg @FGadvancer @skiffer-git @rfyiamcool @withchao +* @openimsdk/openim @openimsdk/bot @Bloomingg @FGadvancer @skiffer-git @withchao # Order is important; the last matching pattern takes the most # precedence. When someone opens a pull request that only # modifies JS files, only @js-owner and not the global # owner(s) will be requested for a review. -*.js @cubxxw @openimsdk/bot @Bloomingg @FGadvancer @skiffer-git @rfyiamcool @withchao +*.js @openimsdk/bot @Bloomingg @FGadvancer @skiffer-git @withchao # You can also use email addresses if you prefer. They'll be # used to look up users just like we do for commit author @@ -35,7 +35,7 @@ Makefile @cubxxw @openimsdk/bot @Bloomingg @FGadvancer @skiffer-git @rfyiam # be identified in the format @org/team-name. Teams must have # explicit write access to the repository. In this example, # the OpenIMSDK team in the github organization owns all .txt files. -*.txt @cubxxw @openimsdk/bot @Bloomingg @FGadvancer @skiffer-git @rfyiamcool @withchao +*.txt @openimsdk/bot @Bloomingg @FGadvancer @skiffer-git @withchao # The `docs/*` pattern will match files like # `docs/getting-started.md` but not further nested files like @@ -44,13 +44,13 @@ docs/* 3293172751nss@gmail.com @openimsdk/bot @skiffer-git # In this example, @octocat owns any file in an apps directory # anywhere in your repository. -api/ @openimsdk/openim @cubxxw @skiffer-git +api/ @openimsdk/openim @skiffer-git # This is a comment. # Each line is a file pattern followed by one or more owners. # CHANGELOG file -CHANGELOG/* @cubxxw @skiffer-git +CHANGELOG/* @skiffer-git # _output directory _output/* @skiffer-git @@ -67,21 +67,21 @@ config/* @skiffer-git # internal directory internal/ @openimsdk/openim @skiffer-git @FGadvancer -tools @openimsdk/openim @openimsdk/bot @cubxxw @skiffer-git @FGadvancer +tools @openimsdk/openim @openimsdk/bot @skiffer-git @FGadvancer # logs directory logs/* @skiffer-git @FGadvancer # pkg directory -pkg/a2r @openimsdk/openim @skiffer-git @cubxxw @openimsdk/bot +pkg/a2r @openimsdk/openim @skiffer-git @openimsdk/bot # scripts directory -scripts/template/* @openimsdk/openim @cubxxw @skiffer-git @FGadvancer -scripts/enterprise/* @openimsdk/openim @FGadvancer @cubxxw @skiffer-git @openimsdk/bot -scripts/githooks/* @openimsdk/openim @cubxxw @skiffer-git @FGadvancer -scripts/lib/* @openimsdk/openim @FGadvancer @cubxxw @skiffer-git @openimsdk/bot -scripts/make-rules/* @openimsdk/openim @FGadvancer @cubxxw @skiffer-git @openimsdk/bot +scripts/template/* @openimsdk/openim @skiffer-git @FGadvancer +scripts/enterprise/* @openimsdk/openim @FGadvancer @skiffer-git @openimsdk/bot +scripts/githooks/* @openimsdk/openim @skiffer-git @FGadvancer +scripts/lib/* @openimsdk/openim @FGadvancer @skiffer-git @openimsdk/bot +scripts/make-rules/* @openimsdk/openim @FGadvancer @skiffer-git @openimsdk/bot # test directory -test/mongo @FGadvancer @cubxxw @skiffer-git @openimsdk/bot -test/mysql @FGadvancer @cubxxw @skiffer-git @openimsdk/bot +test/mongo @FGadvancer @skiffer-git @openimsdk/bot +test/mysql @FGadvancer @skiffer-git @openimsdk/bot From c450f7541952f9bdaa7bc2c13a4e74b909ec1c6b Mon Sep 17 00:00:00 2001 From: xuan <146319162+wxuanF@users.noreply.github.com> Date: Thu, 25 Apr 2024 18:38:22 +0800 Subject: [PATCH 152/188] update action (#2225) * Rename e2e-test.yml to e2e-test.bak * Rename create-branch-on-tag.yml to create-branch-on-tag.bak * Rename pull-request.yml to pull-request.bak --- .../{create-branch-on-tag.yml => create-branch-on-tag.bak} | 0 .github/workflows/{e2e-test.yml => e2e-test.bak} | 0 .github/workflows/{pull-request.yml => pull-request.bak} | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename .github/workflows/{create-branch-on-tag.yml => create-branch-on-tag.bak} (100%) rename .github/workflows/{e2e-test.yml => e2e-test.bak} (100%) rename .github/workflows/{pull-request.yml => pull-request.bak} (100%) diff --git a/.github/workflows/create-branch-on-tag.yml b/.github/workflows/create-branch-on-tag.bak similarity index 100% rename from .github/workflows/create-branch-on-tag.yml rename to .github/workflows/create-branch-on-tag.bak diff --git a/.github/workflows/e2e-test.yml b/.github/workflows/e2e-test.bak similarity index 100% rename from .github/workflows/e2e-test.yml rename to .github/workflows/e2e-test.bak diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.bak similarity index 100% rename from .github/workflows/pull-request.yml rename to .github/workflows/pull-request.bak From 1c505eddd7f743b00b1512d60db02f9f441656b4 Mon Sep 17 00:00:00 2001 From: skiffer-git <72860476+skiffer-git@users.noreply.github.com> Date: Thu, 25 Apr 2024 19:46:36 +0800 Subject: [PATCH 153/188] Update slack invite link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a80bd14320..d0c397a281 100644 --- a/README.md +++ b/README.md @@ -54,7 +54,7 @@ ## :busts_in_silhouette: Join Our Community + 💬 [Follow us on Twitter](https://twitter.com/founder_im63606) -+ 🚀 [Join our Slack](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q) ++ 🚀 [Join our Slack](https://join.slack.com/t/openimsdk/shared_invite/zt-2hljfom5u-9ZuzP3NfEKW~BJKbpLm0Hw) + :eyes: [Join our WeChat Group](https://openim-1253691595.cos.ap-nanjing.myqcloud.com/WechatIMG20.jpeg) ## Ⓜ️ About OpenIM From d65c4ee2ec08179dae62e2058e25a9ef26d21c35 Mon Sep 17 00:00:00 2001 From: skiffer-git <72860476+skiffer-git@users.noreply.github.com> Date: Thu, 25 Apr 2024 19:47:42 +0800 Subject: [PATCH 154/188] Update slack invite link --- README_zh_CN.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README_zh_CN.md b/README_zh_CN.md index e9e56994fb..65aac9ebc6 100644 --- a/README_zh_CN.md +++ b/README_zh_CN.md @@ -54,7 +54,7 @@ ## :busts_in_silhouette: 加入我们的社区 + 💬 [关注我们的 Twitter](https://twitter.com/founder_im63606) -+ 🚀 [加入我们的 Slack](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q) ++ 🚀 [加入我们的 Slack](https://join.slack.com/t/openimsdk/shared_invite/zt-2hljfom5u-9ZuzP3NfEKW~BJKbpLm0Hw) + :eyes: [加入我们的微信群](https://openim-1253691595.cos.ap-nanjing.myqcloud.com/WechatIMG20.jpeg) ## Ⓜ️ 关于 OpenIM From a1e6312c4bc29b5af936e2778e01e7612bed4beb Mon Sep 17 00:00:00 2001 From: xuan <146319162+wxuanF@users.noreply.github.com> Date: Fri, 26 Apr 2024 17:05:54 +0800 Subject: [PATCH 155/188] Update README.md (#2241) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d0c397a281..045d28f470 100644 --- a/README.md +++ b/README.md @@ -84,7 +84,7 @@ Built with Golang and supports cross-platform deployment to ensure a consistent 👉 **[Explore the GO SDK](https://github.com/openimsdk/openim-sdk-core)** -## 🌐 Introduction to OpenIMServer +## 🌐 Introduction to OpenIMServer + **OpenIMServer** features include: - 🌐 Microservices Architecture: Supports cluster mode, including a gateway and multiple rpc services. From 674f5cb3f07b5ab2e7c853029227f343ac776b8e Mon Sep 17 00:00:00 2001 From: skiffer-git <72860476+skiffer-git@users.noreply.github.com> Date: Fri, 26 Apr 2024 19:29:55 +0800 Subject: [PATCH 156/188] Simplify the contribution process 2234 (#2244) * simplify code contribution * simplify code contribution * simplify code contribution * simplify code contribution * update code reviewer --- CONTRIBUTING-zh_CN.md | 55 ++++- CONTRIBUTING.md | 492 ++++-------------------------------------- docs/CODEOWNERS | 89 +------- 3 files changed, 91 insertions(+), 545 deletions(-) diff --git a/CONTRIBUTING-zh_CN.md b/CONTRIBUTING-zh_CN.md index ee3c0b8f85..c10d7337f8 100644 --- a/CONTRIBUTING-zh_CN.md +++ b/CONTRIBUTING-zh_CN.md @@ -1,4 +1,4 @@ -# How do I contribute code to OpenIM +# 如何给OpenIM贡献代码(提交pull request)

Englist · @@ -28,6 +28,55 @@ Türkçe

-
-

+本指南将以 [openimsdk/open-im-server](https://github.com/openimsdk/open-im-server)为例详细说明如何为 OpenIM 项目贡献代码。我们采用“一问题一分支”的策略,确保每个 Issue 都对应一个专门的分支,以便有效管理代码变更。 + +## 1. Fork 仓库 +前往 [openimsdk/open-im-server](https://github.com/openimsdk/open-im-server) GitHub 页面,点击右上角的 "Fork" 按钮,将仓库 Fork 到你的 GitHub 账户下。 + +## 2. 克隆仓库 +将你 Fork 的仓库克隆到本地: +```bash +git clone https://github.com/your-username/open-im-server.git +``` + +## 3. 设置远程上游 +添加原始仓库为远程上游以便跟踪其更新: +```bash +git remote add upstream https://github.com/openimsdk/open-im-server.git +``` + +## 4. 创建 Issue +在原始仓库中创建一个新的 Issue,详细描述你遇到的问题或希望添加的新功能。 + +## 5. 创建新分支 +基于主分支创建一个新分支,并使用描述性的名称与 Issue ID,例如: +```bash +git checkout -b fix-bug-123 +``` + +## 6. 提交更改 +在你的本地分支上进行更改后,提交这些更改: +```bash +git add . +git commit -m "Describe your changes in detail" +``` + +## 7. 推送分支 +将你的分支推送回你的 GitHub Fork: +```bash +git push origin fix-bug-123 +``` + +## 8. 创建 Pull Request +在 GitHub 上转到你的 Fork 仓库,点击 "Pull Request" 按钮。确保 PR 描述清楚,并链接到相关的 Issue。 + +## 9. 签署 CLA +如果这是你第一次提交 PR,你需要在 PR 的评论中回复: +``` +I have read the CLA Document and I hereby sign the CLA +``` +## 其他说明 + +如果需要将同一修改提交到两个不同的分支(例如 `main` 和 `release-v3.7`),应从对应的远程分支分别创建两个新分支。首先在一个分支上完成修改,然后使用 `cherry-pick` 命令将这些更改应用到另一个分支。之后,为每个分支独立提交 Pull Request。 + diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f7d2c07492..a85ba891fc 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -27,475 +27,55 @@ Ελληνικά · Türkçe

+This guide will explain in detail how to contribute code to the OpenIM project, using `openimsdk/open-im-server` as an example. We adopt a "one issue, one branch" strategy to ensure each issue corresponds to a dedicated branch, allowing for effective management of code changes. -
- -

- -So, you want to hack on open-im-server? Yay! - -First of all, thank you for considering contributing to our project! We appreciate your time and effort, and we value any contribution, whether it's reporting a bug, suggesting a new feature, or submitting a pull request. - -![Hello OpenIM Image](assets/demo/hello-openim.png) - -> Use `make demo` start contributing fast. - -This document provides guidelines and best practices to help you contribute effectively. - -## 📇Topics - -- [How do I contribute code to OpenIM](#how-do-i-contribute-code-to-openim) - - [📇Topics](#topics) - - [What we expect of you](#what-we-expect-of-you) - - [Code of ConductCode of Conduct](#code-of-conductcode-of-conduct) - - [Code and doc contribution](#code-and-doc-contribution) - - [Where should I start?](#where-should-i-start) - - [Design documents](#design-documents) - - [Getting Started](#getting-started) - - [Style and Specification](#style-and-specification) - - [Reporting security issues](#reporting-security-issues) - - [Reporting general issues](#reporting-general-issues) - - [Commit Rules](#commit-rules) - - [PR Description](#pr-description) - - [Docs Contribution](#docs-contribution) - - [Engage to help anything](#engage-to-help-anything) - - [Release version](#release-version) - - [Contact Us](#contact-us) - -## What we expect of you - -We hope that anyone can join open-im-server , even if you are a student, writer, translator - -Please meet the minimum version of the Go language published in [go.mod](./go.mod). If you want to manage the Go language version, we provide tools tHow do I contribute code to OpenIMo install [gvm](https://github.com/moovweb/gvm) in our [Makefile](./Makefile) - -You'd better use Linux OR WSL as the development environment, Linux with [Makefile](./Makefile) can help you quickly build and test open-im-server project. - -If you are familiar with [Makefile](./Makefile) , you can easily see the clever design of the open-im-server Makefile. Storing the necessary tools such as golangci in the `/tools` directory can avoid some tool version issues. - -The [Makefile](./Makefile) is for every developer, even if you don't know how to use the Makefile tool, don't worry, we provide two great commands to get you up to speed with the Makefile architecture, `make help` and `make help-all`, it can reduce problems of the developing environment. - -In accordance with the naming conventions adopted by OpenIM and drawing reference from the Google Naming Conventions as per the guidelines available at https://google.github.io/styleguide/go/, the following expectations for naming practices within the project are set forth: - -+ https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/code-conventions.md -+ https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/go-code.md - - -## Code of ConductCode of Conduct - -#### Code and doc contribution - -Every action to make project open-im-server better is encouraged. On GitHub, every improvement for open-im-server could be via a [PR](https://github.com/openimsdk/open-im-server/pulls) (short for pull request). - -+ If you find a typo, try to fix it! -+ If you find a bug, try to fix it! -+ If you find some redundant codes, try to remove them! -+ If you find some test cases missing, try to add them! -+ If you could enhance a feature, please **DO NOT** hesitate! -+ If you find code implicit, try to add comments to make it clear! -+ If you find code ugly, try to refactor that! -+ If you can help to improve documents, it could not be better! -+ If you find document incorrect, just do it and fix that! -+ ... - -#### Where should I start? - -+ If you are new to the project, don't know how to contribute open-im-server, please check out the [good first issue](https://github.com/openimsdk/open-im-server/issues?q=is%3Aopen+label%3A"good+first+issue"+sort%3Aupdated-desc) label. -+ You should be good at filtering the open-im-server issue tags and finding the ones you like, such as [RFC](https://github.com/openimsdk/open-im-server/issues?q=is%3Aissue+is%3Aopen+RFC+label%3ARFC) for big initiatives, features for [feature](https://github.com/openimsdk/open-im-server/issues?q=is%3Aissue+label%3Afeature) proposals, and [bug](https://github.com/openimsdk/open-im-server/issues?q=is%3Aissue+label%3Abug+) fixes. -+ If you are looking for something to work on, check out our [open issues](https://github.com/openimsdk/open-im-server/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc). -+ If you have an idea for a new feature, please [open an issue](https://github.com/openimsdk/open-im-server/issues/new/choose), and we can discuss it. - -#### Design documents - -For any substantial design, there should be a well-crafted design document. This document is not just a simple record, but also a detailed description and manifestation, which can help team members better understand the design thinking and grasp the design direction. In the process of writing the design document, we can choose to use tools such as `Google Docs` or `Notion`, and even mark RFC in [issues](https://github.com/openimsdk/open-im-server/issues?q=is%3Aissue+is%3Aopen+RFC+label%3ARFC) or [discussions](https://github.com/openimsdk/open-im-server/discussions) for better collaboration. Of course, after completing the design document, we should also add it to our [Shared Drive](https://drive.google.com/drive/) and notify the appropriate working group to let everyone know of its existence. Only by doing so can we maximize the effectiveness of the design document and provide strong support for the smooth progress of the project. - -Anybody can access the shared Drive for reading. To get access to comment. Once you've done that, head to the [shared Drive](https://drive.google.com/) and behold all the docs. - -In addition to that, we'd love to invite you to [join our Slack](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q) where you can play with your imagination, tell us what you're working on, and get a quick response. - -When documenting a new design, we recommend a 2-step approach: - -1. Use the short-form RFC template to outline your ideas and get early feedback. -2. Once you have received sufficient feedback and consensus, you may use the longer-form design doc template to specify and discuss your design in more details. - -In order to contribute a feature to open-im-server you'll need to go through the following steps: - -+ Discuss your idea with the appropriate [working groups](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q) on the working group's Slack channel. -+ Once there is general agreement that the feature is useful, create a GitHub issue to track the discussion. The issue should include information about the requirements and use cases that it is trying to address. -+ Include a discussion of the proposed design and technical details of the implementation in the issue. - -But keep in mind that there is no guarantee of it being accepted and so it is usually best to get agreement on the idea/design before time is spent coding it. However, sometimes seeing the exact code change can help focus discussions, so the choice is up to you. - -## Getting Started - -To propose PR for the open-im-server item, we assume you have registered a GitHub ID. Then you could finish the preparation in the following steps: - -1. Fork the repository(open-im-server) - -2. **CLONE** your own repository to main locally. Use `git clone https://github.com//open-im-server.git` to clone repository to your local machine. Then you can create new branches to finish the change you wish to make. - -3. **Initialize Git Hooks with `make init-githooks`** - - After cloning the repository, it's recommended to set up Git hooks to streamline your workflow and ensure your contributions adhere to OpenIM's community standards. Git hooks are scripts that run automatically every time a particular event occurs in a Git repository, such as before a commit or push. To initialize Git hooks for the OpenIM server repository, use the `make init-githooks` command. - - - **Enabling Git Hooks Mode**: By running `make init-githooks` and entering `1` when prompted, you enable Git hooks mode. This action will generate a series of hooks within the `.git/hooks/` directory. These hooks impose certain checks on your commits and pushes, ensuring they meet the quality and standards expected by the OpenIM community. For instance, commit hooks might enforce a specific commit message format, while push hooks could check for code style or linting issues. - - - **Benefits for First-Time Contributors**: This setup is especially beneficial for new contributors. It guides you to make professional, community-standard-compliant Pull Requests (PRs) and PR descriptions right from your first contribution. By automating checks and balances, it reduces the chances of common mistakes and speeds up the review process. - - - **Disabling Git Hooks**: If for any reason you wish to remove the Git hooks, simply run `make init-githooks` again and enter `2` when prompted. This will delete the existing Git hooks, removing the automatic checks and constraints from your Git operations. However, keep in mind that manually ensuring your contributions adhere to community standards without the aid of Git hooks requires diligence. - - > [!NOTE] Utilizing Git hooks through the `make init-githooks` command is a straightforward yet powerful way to ensure your contributions are consistent and high-quality. It's a step towards fostering a professional and efficient development environment in the OpenIM project. - - - -4. **Set Remote** upstream to be `https://github.com/openimsdk/open-im-server.git` using the following two commands: - - ```bash - ❯ git remote add upstream https://github.com/openimsdk/open-im-server.git - ❯ git remote set-url --push upstream no-pushing - ``` - - With this remote setting, you can check your git remote configuration like this: - - ```bash - ❯ git remote -v - origin https://github.com//open-im-server.git (fetch) - origin https://github.com//open-im-server.git (push) - upstream https://github.com/openimsdk/open-im-server.git (fetch) - upstream no-pushing (push) - ``` - - Adding this, we can easily synchronize local branches with upstream branches. - -5. Create a new branch for your changes (use a descriptive name, such as `fix-bug-123` or `add-new-feature`). - - ```bash - ❯ cd open-im-server - ❯ git fetch upstream - ❯ git checkout upstream/main - ``` - - Create a new branch: - - ```bash - ❯ git checkout -b - ``` - - Make any change on the `new-branch` then use [Makefile](./Makefile) build and test your codes. - - -6. **Commit your changes** to your local branch, lint before committing and commit with sign-off - - ```bash - ❯ git rebase upstream/main - ❯ make lint # golangci-lint run -c .golangci.yml - ❯ git add -A # add changes to staging - ❯ git commit -a -s -m "message for your changes" # -s adds a Signed-off-by trailer - ``` - -7. **Push your branch** to your forked repository, it is recommended to have only one commit for a PR. - - ```bash - # sync up with upstream - ❯ git fetch upstream main - ❯ git rebase upstream/main - ❯ - ❯ git rebase -i # rebase with interactive mode to squash your commits into a single one - ❯ git push # push to the remote repository, if it's a first time push, run git push --set-upstream origin # sync up with upstream - ❯ git fetch upstream main - git rebase upstream/main - - ❯ git rebase -i # rebase with interactive mode to squash your commits into a single one - ❯ git push # push to the remote repository, if it's a first time push, run git push --set-upstream origin - ``` - - You can also use `git commit -s --amend && git push -f` to update modifications on the previous commit. - - If you have developed multiple features in the same branch, you should create PR separately by rebasing to the main branch between each push: - - ```bash - # create new branch, for example git checkout -b feature/infra - ❯ git checkout -b - # update some code, feature1 - ❯ git add -A - ❯ git commit -m -s "feat: feature one" - ❯ git push # if it's first time push, run git push --set-upstream origin - # then create pull request, and merge - # update some new feature, feature2, rebase main branch first. - ❯ git rebase upstream/main # rebase the current branch to upstream/main branch - ❯ git add -A - ❯ git commit -m -s "feat: feature two" - ``` - - **Verifying Your Pull Request with `make all` Command** - - Before verifying, you may need to complete the basic deployment of OpenIM to get familiar with the deployment status of OpenIM. Please read [this deployment document](https://docs.openim.io/zh-Hans/guides/gettingStarted/imSourceCodeDeployment), which will tell you how to deploy OpenIM middleware and OpenIM services in detail - - Before submitting your Pull Request (PR), it's crucial to ensure that it passes all the necessary checks and verifications to maintain the quality and integrity of the OpenIM server project. To facilitate this process, we have encapsulated a series of validation steps into the `make all` command. - - - **Purpose of `make all` Command**: The `make all` command serves as a comprehensive pre-PR verification tool. It sequentially executes a variety of tasks designed to scrutinize your changes from multiple angles, ensuring they are ready for submission. - - - **Included Commands**: - - `tidy`: Cleans up the module by removing unused dependencies. - - `gen`: Generates necessary files from templates or specifications, ensuring that your codebase is up-to-date with its dependencies. - - `add-copyright`: Checks for and adds copyright notices to files, ensuring compliance with legal requirements. - - `verify`: Verifies the integrity and consistency of the code, dependencies, and various checks. - - `test-api`: Runs API tests to ensure that your changes do not break any existing functionality and adhere to the expected behaviors. - - `lint`: Analyzes the code for potential stylistic or programming errors, enforcing the project's coding standards. - - `cover`: Measures the code coverage of tests, helping you understand how much of the code is being tested. - - `restart`: (Optionally) restarts services or applications to ensure that changes are correctly applied and functioning in a live environment. - - - **Executing the Command**: To run the `make all` command, simply navigate to the root directory of your cloned repository in your terminal and execute: - ```bash - make all - ``` - This command will sequentially perform all the listed actions, outputting any warnings or errors encountered during the process. It's a vital step to catch any issues early and ensure your contribution meets the quality standards set by the OpenIM community. - - - **Benefits**: By using `make all` for pre-PR verification, you significantly increase the likelihood of your PR being accepted on the first review. It not only demonstrates your commitment to quality but also streamlines the review process by minimizing back-and-forth due to common issues that can be caught automatically. - - - **Troubleshooting Git Push Failures** - - When working with Git, encountering errors during push operations is not uncommon. Two primary reasons you might face push failures are due to firewall restrictions or authentication issues. Here’s how you can troubleshoot and resolve these problems. - - **Firewall Errors** - - If you're behind a corporate firewall or your network restricts certain types of traffic, you might encounter issues when trying to push your changes via HTTPS. This is because firewalls can block the ports used by the HTTPS protocol. To resolve this issue, you can configure Git to use a proxy. - - If you have a local proxy server set up, you can direct Git to use it by setting the `https_proxy` and `http_proxy` environment variables. Open your terminal or command prompt and run the following commands: - - ```bash - export https_proxy="http://127.0.0.1:7890" - export http_proxy="http://127.0.0.1:7890" - ``` - - Replace `127.0.0.1:7890` with the address and port of your proxy server. These commands set the proxy for the current session. If you want to make these changes permanent, add them to your `.bashrc`, `.bash_profile`, or equivalent shell configuration file. - - **Using SSH Instead of HTTPS** - - An alternative to using HTTPS is to set up an SSH connection for Git operations. SSH connections are often not blocked by firewalls and do not require proxy settings. Additionally, SSH provides a secure channel and can simplify the authentication process since it relies on SSH keys rather than username and password credentials. - - To use SSH with Git, you first need to generate an SSH key pair and add the public key to your GitHub account (or another Git hosting service). - - 1. **Generate SSH Key Pair**: Open your terminal and run `ssh-keygen -t rsa -b 4096 -C "your_email@example.com"`, replacing `your_email@example.com` with your email. Press enter to accept the default file location and passphrase prompts. - - 2. **Add SSH Key to SSH-Agent**: Ensure the ssh-agent is running with `eval "$(ssh-agent -s)"` and then add your SSH private key to the ssh-agent using `ssh-add ~/.ssh/id_rsa`. - - 3. **Add SSH Key to GitHub**: Copy your SSH public key to your clipboard with `cat ~/.ssh/id_rsa.pub | clip` (Windows) or `pbcopy < ~/.ssh/id_rsa.pub` (Mac). Go to GitHub, navigate to Settings > SSH and GPG keys, and add a new SSH key, pasting your key into the field provided. - - 4. **Switch to SSH in Your Repository**: Change your repository's remote URL from HTTPS to SSH. You can find the SSH URL in your repository settings on GitHub and use `git remote set-url origin git@github.com:username/repository.git` to switch. - - **Authentication Errors** - - If you're experiencing authentication errors, it might be due to missing or incorrect credentials. Ensure you have added your SSH key to your Git hosting service. You can test your SSH connection with `ssh -T git@github.com` (replace `github.com` with your Git hosting service's domain). If successful, you'll receive a welcome message. - - For HTTPS users, check that your username and password (or personal access token for services like GitHub that no longer accept password authentication for Git operations) are correct. - -8. **Open a pull request** to `openimsdk/open-im-server:main` - - It is recommended to review your changes before filing a pull request. Check if your code doesn't conflict with the main branch and no redundant code is included. - - > [!TIP] There is a [good blog post documenting](https://nsddd.top/posts/participating-in-this-project/) the entire push contribution process. - - -## Style and Specification - -We divide the problem into security and general problems: - -#### Reporting security issues - -Security issues are always treated seriously. As our usual principle, we discourage anyone to spread security issues. If you find a security issue of open-im-server, please do not discuss it in public and even do not open a public issue. - -Instead we encourage you to send us a private email to info@openim.io to report this. - -#### Reporting general issues - -To be honest, we regard every user of open-im-serveras a very kind contributor. After experiencing open-im-server, you may have some feedback for the project. Then feel free to open an issue via [NEW ISSUE](https://github.com/openimsdk/open-im-server/issues/new/choose). - -Since we collaborate project open-im-server in a distributed way, we appreciate **WELL-WRITTEN**, **DETAILED**, **EXPLICIT** issue reports. To make the communication more efficient, we wish everyone could search if your issue is an existing one in the searching list. If you find it existing, please add your details in comments under the existing issue instead of opening a brand new one. - -To make the issue details as standard as possible, we setup an [ISSUE TEMPLATE](https://github.com/OpenIMSDK/.github/tree/main/.github/ISSUE_TEMPLATE) for issue reporters. You can find three kinds of issue templates there: question, bug report and feature request. Please **BE SURE** to follow the instructions to fill fields in template. - -**There are a lot of cases when you could open an issue:** - -+ bug report -+ feature request -+ open-im-server performance issues -+ feature proposal -+ feature design -+ help wanted -+ doc incomplete -+ test improvement -+ any questions on open-im-server project -+ and so on - -Also, we must be reminded when submitting a new question about open-im-server, please remember to remove the sensitive data from your post. Sensitive data could be password, secret key, network locations, private business data and so on. - -#### Commit Rules - -Actually in open-im-server, we take two rules serious when committing: - -**🥇 Commit Message:** - -Commit message could help reviewers better understand what the purpose of submitted PR is. It could help accelerate the code review procedure as well. We encourage contributors to use **EXPLICIT** commit message rather than ambiguous message. In general, we advocate the following commit message type: - -We use [Semantic Commits](https://www.conventionalcommits.org/en/v1.0.0/) to make it easier to understand what a commit does and to build pretty changelogs. Please use the following prefixes for your commits: - -+ `docs: xxxx`. For example, "docs: add docs about storage installation". -+ `feature: xxxx`.For example, "feature: make result show in sorted order". -+ `bugfix: xxxx`. For example, "bugfix: fix panic when input nil parameter". -+ `style: xxxx`. For example, "style: format the code style of Constants.java". -+ `refactor: xxxx.` For example, "refactor: simplify to make codes more readable". -+ `test: xxx`. For example, "test: add unit test case for func InsertIntoArray". -+ `chore: xxx.` For example, "chore: integrate travis-ci". It's the type of mantainance change. -+ other readable and explicit expression ways. - -On the other side, we discourage contributors from committing message like the following ways: - -+ ~~fix bug~~ -+ ~~update~~ -+ ~~add doc~~ - -**🥈 Commit Content:** - -Commit content represents all content changes included in one commit. We had better include things in one single commit which could support reviewer's complete review without any other commits' help. - -In another word, contents in one single commit can pass the CI to avoid code mess. In brief, there are two minor rules for us to keep in mind: - -1. avoid very large change in a commit. -2. complete and reviewable for each commit. -3. words are written in lowercase English, not uppercase English or other languages such as Chinese. - -No matter what the commit message, or commit content is, we do take more emphasis on code review. - -An example for this could be: +### 1. Fork the Repository +Go to the `openimsdk/open-im-server` GitHub page, click the "Fork" button in the upper right corner to fork the repository to your GitHub account. +### 2. Clone the Repository +Clone the forked repository to your local machine: ```bash -❯ git commit -a -s -m "docs: add a new section to the README" +git clone https://github.com/your-username/open-im-server.git ``` -#### PR Description - -PR is the only way to make change to open-im-server project files. To help reviewers better get your purpose, PR description could not be too detailed. We encourage contributors to follow the [PR template](https://github.com/OpenIMSDK/.github/tree/main/.github/PULL_REQUEST_TEMPLATE.md) to finish the pull request. - -You can find some very formal PR in [RFC](https://github.com/openimsdk/open-im-server/issues?q=is%3Aissue+is%3Aopen+RFC+label%3ARFC) issues and learn about them. - -**📖 Opening PRs:** - -+ As long as you are working on your PR, please mark it as a draft -+ Please make sure that your PR is up-to-date with the latest changes in `main` -+ Mention the issue that your PR is addressing (Fix: #{ID_1}, #{ID_2}) -+ Make sure that your PR passes all checks - -**🈴 Reviewing PRs:** - -+ Be respectful and constructive -+ Assign yourself to the PR (comment `/assign`) -+ Check if all checks are passing -+ Suggest changes instead of simply commenting on found issues -+ If you are unsure about something, ask the author -+ If you are not sure if the changes work, try them out -+ Reach out to other reviewers if you are unsure about something -+ If you are happy with the changes, approve the PR -+ Merge the PR once it has all approvals and the checks are passing - -**⚠️ DCO check:** - -We have a DCO check that runs on every pull request to ensure code quality and maintainability. This check verifies that the commit has been signed off, indicating that you have read and agreed to the provisions of the Developer Certificate of Origin. If you have not yet signed off on the commit, you can use the following command to sign off on the last commit you made: - +### 3. Set Upstream Remote +Add the original repository as a remote upstream to track updates: ```bash -❯ git commit --amend --signoff +git remote add upstream https://github.com/openimsdk/open-im-server.git ``` -Please note that signing off on a commit is a commitment that you have read and agreed to the provisions of the Developer Certificate of Origin. If you have not yet read this document, we strongly recommend that you take some time to read it carefully. If you have any questions about the content of this document, or if you need further assistance, please contact an administrator or relevant personnel. - -You can also automate signing off your commits by adding the following to your `.zshrc` or `.bashrc`: +### 4. Create an Issue +Create a new issue in the original repository describing the problem you are facing or the new feature you want to add. For significant feature adjustments, propose an RFC issue to facilitate broad discussion and participation from community members. -```go -git() { - if [ $# -gt 0 ] && [[ "$1" == "commit" ]] ; then - shift - command git commit --signoff "$@" - else - command git "$@" - fi -} +### 5. Create a New Branch +Create a new branch based on the main branch and name it descriptively, including the Issue ID, for example: +```bash +git checkout -b fix-bug-123 ``` +### 6. Commit Changes +After making changes on your local branch, commit them: +```bash +git add . +git commit -m "Describe your changes in detail" +``` -#### Docs Contribution - -The documentation for open-im-server includes: - -+ [README.md](https://github.com/openimsdk/open-im-server/blob/main/README.md): This file includes the basic information and instructions for getting started with open-im-server. -+ [CONTRIBUTING.md](https://github.com/openimsdk/open-im-server/blob/main/CONTRIBUTING.md): This file contains guidelines for contributing to open-im-server's codebase, such as how to submit issues, pull requests, and code reviews. -+ [Official Documentation](https://doc.rentsoft.cn/): This is the official documentation for open-im-server, which includes comprehensive information on all of its features, configuration options, and troubleshooting tips. - -Please obey the following rules to better format the docs, which would greatly improve the reading experience. - -1. Please do not use Chinese punctuations in English docs, and vice versa. -2. Please use upper case letters where applicable, like the first letter of sentences / headings, etc. -3. Please specify a language for each Markdown code blocks, unless there's no associated languages. -4. Please insert a whitespace between Chinese and English words. -5. Please use the correct case for technical terms, such as using `HTTP` instead of http, `MySQL` rather than mysql, `Kubernetes` instead of kubernetes, etc. -6. Please check if there's any typos in the docs before submitting PRs. - -## Engage to help anything - -We choose GitHub as the primary place for open-im-server to collaborate. So the latest updates of open-im-server are always here. Although contributions via PR is an explicit way to help, we still call for any other ways. - -+ reply to other's [issues](https://github.com/openimsdk/open-im-server/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc) if you could; -+ help solve other user's problems; -+ help review other's [PR](https://github.com/openimsdk/open-im-server/pulls?q=is%3Apr+is%3Aopen+sort%3Aupdated-desc) design; -+ discuss about open-im-server to make things clearer; -+ advocate [open-im-server](https://google.com/search?q=open-im-server) technology beyond GitHub; -+ write blogs on open-im-server and so on. - -In a word, **ANY HELP IS CONTRIBUTION.** - -## Release version - -Releases of open-im-server are done using [Release Please](https://github.com/googleapis/release-please) and [GoReleaser](https://goreleaser.com/). The workflow looks like this: - -🎯 A PR is merged to the `main` branch: - -+ Release please is triggered, creates or updates a new release PR -+ This is done with every merge to main, the current release PR is updated every time - -🎯 Merging the 'release please' PR to `main`: - -+ Release please is triggered, creates a new release and updates the changelog based on the commit messages -+ GoReleaser is triggered, builds the binaries and attaches them to the release -+ Containers are created and pushed to the container registry - -With the next relevant merge, a new release PR will be created and the process starts again - -**👀 Manually setting the version:** - -If you want to manually set the version, you can create a PR with an empty commit message that contains the version number in the commit message. For example: - -Such a commit can get produced as follows: - -````bash -❯ git commit --allow-empty -m "chore: release 0.0.3" -m "Release-As: 0.0.3 -```` - -For the complex release process, in fact, and encapsulation as CICD, you only need to tag locally, and then publish the tag to OpenIM github to complete the entire OpenIM release process. - -In addition to CICD, we also do a complex release command locally, which can help you complete the full platform compilation, testing, and release to Minio, just by using the `make release` command. -Please [read the detailed documents](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/release.md) - - -## Contact Us - -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. +### 7. Push the Branch +Push your branch back to your GitHub fork: +```bash +git push origin fix-bug-123 +``` -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. +### 8. Create a Pull Request +Go to your fork on GitHub, click the "Pull Request" button. Make sure the PR description is clear and links to the related Issue. +#### 🅰 Fixed issue #issueID -In addition to Slack, we also offer the following ways to get in touch: +### 9. Sign the CLA +If this is your first time submitting a PR, you need to reply in the PR comments: +``` +I have read the CLA Document and I hereby sign the CLA +``` -+ : 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](info@openim.io). 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. +### Additional Notes +If the same modification needs to be submitted to two different branches (e.g., main and release-v3.7), create two new branches from the corresponding remote branches. First complete the modification in one branch, then use the `cherry-pick` command to apply these changes to the other branch. After that, submit a separate Pull Request for each branch. -Whether you're looking to join our community or have any questions or suggestions, we welcome you to get in touch with us. diff --git a/docs/CODEOWNERS b/docs/CODEOWNERS index 68e459f9dd..5c0d904a46 100644 --- a/docs/CODEOWNERS +++ b/docs/CODEOWNERS @@ -1,87 +1,4 @@ -# This is a comment. -# Each line is a file pattern followed by one or more owners. +# CODEOWNERS file +# This file is used to specify the individuals who are required to review changes in this repository. -# README files -README.md @openimsdk/openim @openimsdk/bot @Bloomingg @FGadvancer @skiffer-git @withchao - -# Contributing guidelines -CONTRIBUTING.md @openimsdk/bot @Bloomingg @FGadvancer @skiffer-git @withchao - -# License files -LICENSE @openimsdk/bot @Bloomingg @FGadvancer @skiffer-git @withchao - -# Makefile -Makefile @openimsdk/bot @Bloomingg @FGadvancer @skiffer-git @withchao - -# These owners will be the default owners for everything in -# the repo. Unless a later match takes precedence, -# and @openimsdk/bot will be requested for -# review when someone opens a pull request. -* @openimsdk/openim @openimsdk/bot @Bloomingg @FGadvancer @skiffer-git @withchao - -# Order is important; the last matching pattern takes the most -# precedence. When someone opens a pull request that only -# modifies JS files, only @js-owner and not the global -# owner(s) will be requested for a review. -*.js @openimsdk/bot @Bloomingg @FGadvancer @skiffer-git @withchao - -# You can also use email addresses if you prefer. They'll be -# used to look up users just like we do for commit author -# emails. -*.go 3293172751nss@gmail.com -*.py 3293172751nss@gmail.com - -# Teams can be specified as code owners as well. Teams should -# be identified in the format @org/team-name. Teams must have -# explicit write access to the repository. In this example, -# the OpenIMSDK team in the github organization owns all .txt files. -*.txt @openimsdk/bot @Bloomingg @FGadvancer @skiffer-git @withchao - -# The `docs/*` pattern will match files like -# `docs/getting-started.md` but not further nested files like -# `docs/build-app/troubleshooting.md`. -docs/* 3293172751nss@gmail.com @openimsdk/bot @skiffer-git - -# In this example, @octocat owns any file in an apps directory -# anywhere in your repository. -api/ @openimsdk/openim @skiffer-git - -# This is a comment. -# Each line is a file pattern followed by one or more owners. - -# CHANGELOG file -CHANGELOG/* @skiffer-git - -# _output directory -_output/* @skiffer-git - -# bin directory -bin/* @skiffer-git @FGadvancer - -# cmd directory -cmd/* - -# config directory -config/* @skiffer-git - -# internal directory -internal/ @openimsdk/openim @skiffer-git @FGadvancer - -tools @openimsdk/openim @openimsdk/bot @skiffer-git @FGadvancer - -# logs directory -logs/* @skiffer-git @FGadvancer - -# pkg directory -pkg/a2r @openimsdk/openim @skiffer-git @openimsdk/bot - -# scripts directory -scripts/template/* @openimsdk/openim @skiffer-git @FGadvancer -scripts/enterprise/* @openimsdk/openim @FGadvancer @skiffer-git @openimsdk/bot -scripts/githooks/* @openimsdk/openim @skiffer-git @FGadvancer -scripts/lib/* @openimsdk/openim @FGadvancer @skiffer-git @openimsdk/bot -scripts/make-rules/* @openimsdk/openim @FGadvancer @skiffer-git @openimsdk/bot - -# test directory -test/mongo @FGadvancer @skiffer-git @openimsdk/bot -test/mysql @FGadvancer @skiffer-git @openimsdk/bot +* @Bloomingg @FGadvancer @skiffer-git @withchao \ No newline at end of file From 6d5e220569dd84b1c5fe5052b020d1125e316062 Mon Sep 17 00:00:00 2001 From: skiffer-git <72860476+skiffer-git@users.noreply.github.com> Date: Fri, 26 Apr 2024 21:04:14 +0800 Subject: [PATCH 157/188] update web/admin front image (#2247) --- .env | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.env b/.env index 92c4d5c416..6c2baa41d8 100644 --- a/.env +++ b/.env @@ -6,8 +6,8 @@ KAFKA_IMAGE=bitnami/kafka:3.5.1 MINIO_IMAGE=minio/minio:RELEASE.2024-01-11T07-46-16Z -OPENIM_WEB_FRONT_IMAGE=ghcr.io/openimsdk/openim-web:v3.5.0-docker -OPENIM_ADMIN_FRONT_IMAGE=ghcr.io/openimsdk/openim-admin:toc-base-open-docker.35 +OPENIM_WEB_FRONT_IMAGE=openim/openim-web-front:release-v3.5.1 +OPENIM_ADMIN_FRONT_IMAGE=openim/openim-admin-front:release-v1.7 DATA_DIR=./ From 25fe09952c12eab630a0d816bf1928e004ed9f16 Mon Sep 17 00:00:00 2001 From: AerisVibe <166510977+AerisVibe@users.noreply.github.com> Date: Sun, 28 Apr 2024 10:52:04 +0800 Subject: [PATCH 158/188] fix bug:invalid go version '1.21.2' : must match format 1.23 (#2249) --- go.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 1279a12857..88be5a3733 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/openimsdk/open-im-server/v3 -go 1.21.2 +go 1.21 require ( firebase.google.com/go v3.13.0+incompatible From 74f4fdb156ab53bde6644c242cd8c295acff0bda Mon Sep 17 00:00:00 2001 From: chao <48119764+withchao@users.noreply.github.com> Date: Sun, 28 Apr 2024 11:47:05 +0800 Subject: [PATCH 159/188] feat: optimize corn tasks (#2237) * fix: GroupApplicationAcceptedNotification * fix: GroupApplicationAcceptedNotification * fix: NotificationUserInfoUpdate * cicd: robot automated Change * fix: component * fix: getConversationInfo * feat: cron task * feat: cron task * feat: cron task * feat: cron task * feat: cron task --------- Co-authored-by: withchao --- config/openim-crontask.yml | 4 +- go.mod | 2 +- go.sum | 4 +- internal/rpc/conversation/conversaion.go | 43 +++++ internal/rpc/msg/clear.go | 77 ++++++++ internal/tools/conversation.go | 149 --------------- internal/tools/cron_task.go | 118 +++++------- internal/tools/cron_task_test.go | 113 ------------ internal/tools/msg.go | 226 ----------------------- internal/tools/msg_doc_convert.go | 46 ----- pkg/authverify/token.go | 1 - pkg/common/cmd/cron_task.go | 3 - pkg/common/cmd/msg_utils.go | 27 +-- pkg/common/config/config.go | 2 - pkg/common/db/controller/msg.go | 75 ++++++++ pkg/common/db/mgo/conversation.go | 11 +- pkg/common/db/mgo/msg.go | 86 +++++++++ pkg/common/db/table/relation/msg.go | 6 + pkg/rpcclient/conversation.go | 5 + pkg/rpcclient/msg.go | 5 + 20 files changed, 355 insertions(+), 648 deletions(-) create mode 100644 internal/rpc/msg/clear.go delete mode 100644 internal/tools/conversation.go delete mode 100644 internal/tools/cron_task_test.go delete mode 100644 internal/tools/msg.go delete mode 100644 internal/tools/msg_doc_convert.go diff --git a/config/openim-crontask.yml b/config/openim-crontask.yml index 39f730112a..9bbccfd252 100644 --- a/config/openim-crontask.yml +++ b/config/openim-crontask.yml @@ -1,4 +1,2 @@ -chatRecordsClearTime: "0 2 * * 3" -msgDestructTime: "0 2 * * *" +chatRecordsClearTime: "0 2 * * *" retainChatRecords: 365 -enableCronLocker: false diff --git a/go.mod b/go.mod index 88be5a3733..21eca956e3 100644 --- a/go.mod +++ b/go.mod @@ -13,7 +13,7 @@ require ( github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible // indirect github.com/mitchellh/mapstructure v1.5.0 - github.com/openimsdk/protocol v0.0.64 + github.com/openimsdk/protocol v0.0.65 github.com/openimsdk/tools v0.0.49-alpha.2 github.com/pkg/errors v0.9.1 // indirect github.com/prometheus/client_golang v1.18.0 diff --git a/go.sum b/go.sum index 9b31342d84..aa851c74b8 100644 --- a/go.sum +++ b/go.sum @@ -281,8 +281,8 @@ github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE= github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs= github.com/openimsdk/gomake v0.0.9 h1:ouf25ygN2PMQ68Gfgns/EQRPiLPnp+77SIr68GfE+n4= github.com/openimsdk/gomake v0.0.9/go.mod h1:PndCozNc2IsQIciyn9mvEblYWZwJmAI+06z94EY+csI= -github.com/openimsdk/protocol v0.0.64 h1:OrjSs4CgKN9VLvJvrAsc37O7Ru0E0VllXZQSmG/ab7U= -github.com/openimsdk/protocol v0.0.64/go.mod h1:OZQA9FR55lseYoN2Ql1XAHYKHJGu7OMNkUbuekrKCM8= +github.com/openimsdk/protocol v0.0.65 h1:SPT9qyUsFRTTKSKb/FjpS+xr6sxz/Kbnu+su1bxYagc= +github.com/openimsdk/protocol v0.0.65/go.mod h1:OZQA9FR55lseYoN2Ql1XAHYKHJGu7OMNkUbuekrKCM8= github.com/openimsdk/tools v0.0.49-alpha.2 h1:8IfV6o2ySU7C54sh/MG7ctEp1h3lSNe03OCUDWSk5Ws= github.com/openimsdk/tools v0.0.49-alpha.2/go.mod h1:P4oGP1Pd+d4ctbLD5U/XQTgl8yu8Hd3skx640Fr69ko= github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4= diff --git a/internal/rpc/conversation/conversaion.go b/internal/rpc/conversation/conversaion.go index 1bf612923c..96d2a403f6 100644 --- a/internal/rpc/conversation/conversaion.go +++ b/internal/rpc/conversation/conversaion.go @@ -536,3 +536,46 @@ func (c *conversationServer) GetConversationNotReceiveMessageUserIDs(ctx context } return &pbconversation.GetConversationNotReceiveMessageUserIDsResp{UserIDs: userIDs}, nil } + +func (c *conversationServer) UpdateConversation(ctx context.Context, req *pbconversation.UpdateConversationReq) (*pbconversation.UpdateConversationResp, error) { + m := make(map[string]any) + if req.RecvMsgOpt != nil { + m["recv_msg_opt"] = req.RecvMsgOpt.Value + } + if req.AttachedInfo != nil { + m["attached_info"] = req.AttachedInfo.Value + } + if req.Ex != nil { + m["ex"] = req.Ex.Value + } + if req.IsPinned != nil { + m["is_pinned"] = req.IsPinned.Value + } + if req.GroupAtType != nil { + m["group_at_type"] = req.GroupAtType.Value + } + if req.MsgDestructTime != nil { + m["msg_destruct_time"] = req.MsgDestructTime.Value + } + if req.IsMsgDestruct != nil { + m["is_msg_destruct"] = req.IsMsgDestruct.Value + } + if req.BurnDuration != nil { + m["burn_duration"] = req.BurnDuration.Value + } + if req.IsPrivateChat != nil { + m["is_private_chat"] = req.IsPrivateChat.Value + } + if req.MinSeq != nil { + m["min_seq"] = req.MinSeq.Value + } + if req.MaxSeq != nil { + m["max_seq"] = req.MaxSeq.Value + } + if len(m) > 0 { + if err := c.conversationDatabase.UpdateUsersConversationField(ctx, req.UserIDs, req.ConversationID, m); err != nil { + return nil, err + } + } + return &pbconversation.UpdateConversationResp{}, nil +} diff --git a/internal/rpc/msg/clear.go b/internal/rpc/msg/clear.go new file mode 100644 index 0000000000..774eae32cd --- /dev/null +++ b/internal/rpc/msg/clear.go @@ -0,0 +1,77 @@ +package msg + +import ( + "context" + "github.com/openimsdk/open-im-server/v3/pkg/authverify" + "github.com/openimsdk/protocol/conversation" + "github.com/openimsdk/protocol/msg" + "github.com/openimsdk/protocol/wrapperspb" + "github.com/openimsdk/tools/errs" + "github.com/openimsdk/tools/log" + "strings" + "time" +) + +func (m *msgServer) ClearMsg(ctx context.Context, req *msg.ClearMsgReq) (_ *msg.ClearMsgResp, err error) { + if err := authverify.CheckAdmin(ctx, m.config.Share.IMAdminUserID); err != nil { + return nil, err + } + if req.Timestamp > time.Now().UnixMilli() { + return nil, errs.ErrArgs.WrapMsg("request millisecond timestamp error") + } + var ( + docNum int + msgNum int + start = time.Now() + ) + clearMsg := func(ctx context.Context) (bool, error) { + conversationSeqs := make(map[string]struct{}) + defer func() { + req := &conversation.UpdateConversationReq{ + MsgDestructTime: wrapperspb.Int64(time.Now().UnixMilli()), + } + for conversationID := range conversationSeqs { + req.ConversationID = conversationID + if err := m.Conversation.UpdateConversations(ctx, req); err != nil { + log.ZError(ctx, "update conversation max seq failed", err, "conversationID", conversationID, "msgDestructTime", req.MsgDestructTime) + } + } + }() + msgs, err := m.MsgDatabase.GetBeforeMsg(ctx, req.Timestamp, 100) + if err != nil { + return false, err + } + if len(msgs) == 0 { + return false, nil + } + for _, msg := range msgs { + index, err := m.MsgDatabase.DeleteDocMsgBefore(ctx, req.Timestamp, msg) + if err != nil { + return false, err + } + if len(index) == 0 { + return false, errs.ErrInternalServer.WrapMsg("delete doc msg failed") + } + docNum++ + msgNum += len(index) + conversationID := msg.DocID[:strings.LastIndex(msg.DocID, ":")] + if _, ok := conversationSeqs[conversationID]; !ok { + conversationSeqs[conversationID] = struct{}{} + } + } + return true, nil + } + for { + keep, err := clearMsg(ctx) + if err != nil { + log.ZError(ctx, "clear msg failed", err, "docNum", docNum, "msgNum", msgNum, "cost", time.Since(start)) + return nil, err + } + if !keep { + log.ZInfo(ctx, "clear msg success", "docNum", docNum, "msgNum", msgNum, "cost", time.Since(start)) + break + } + log.ZInfo(ctx, "clearing message", "docNum", docNum, "msgNum", msgNum, "cost", time.Since(start)) + } + return &msg.ClearMsgResp{}, nil +} diff --git a/internal/tools/conversation.go b/internal/tools/conversation.go deleted file mode 100644 index 3e2a88ffd6..0000000000 --- a/internal/tools/conversation.go +++ /dev/null @@ -1,149 +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 tools - -import ( - "context" - "math/rand" - "time" - - "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" - "github.com/openimsdk/protocol/sdkws" - "github.com/openimsdk/tools/log" - "github.com/openimsdk/tools/mcontext" - "github.com/openimsdk/tools/utils/idutil" - "github.com/openimsdk/tools/utils/stringutil" -) - -// func (c *MsgTool) ConversationsDestructMsgs() { -// log.ZInfo(context.Background(), "start msg destruct cron task") -// ctx := mcontext.NewCtx(utils.GetSelfFuncName()) -// conversations, err := c.conversationDatabase.GetConversationIDsNeedDestruct(ctx) -// if err != nil { -// log.ZError(ctx, "get conversation id need destruct failed", err) -// return -// } -// log.ZDebug(context.Background(), "nums conversations need destruct", "nums", len(conversations)) -// for _, conversation := range conversations { -// ctx = mcontext.NewCtx(utils.GetSelfFuncName() + "-" + utils.OperationIDGenerator() + "-" + conversation.ConversationID + "-" + conversation.OwnerUserID) -// log.ZDebug( -// ctx, -// "UserMsgsDestruct", -// "conversationID", -// conversation.ConversationID, -// "ownerUserID", -// conversation.OwnerUserID, -// "msgDestructTime", -// conversation.MsgDestructTime, -// "lastMsgDestructTime", -// conversation.LatestMsgDestructTime, -// ) -// now := time.Now() -// seqs, err := c.msgDatabase.UserMsgsDestruct(ctx, conversation.OwnerUserID, conversation.ConversationID, conversation.MsgDestructTime, conversation.LatestMsgDestructTime) -// if err != nil { -// log.ZError(ctx, "user msg destruct failed", err, "conversationID", conversation.ConversationID, "ownerUserID", conversation.OwnerUserID) -// continue -// } -// if len(seqs) > 0 { -// if err := c.conversationDatabase.UpdateUsersConversationField(ctx, []string{conversation.OwnerUserID}, conversation.ConversationID, map[string]interface{}{"latest_msg_destruct_time": now}); err -// != nil { -// log.ZError(ctx, "updateUsersConversationField failed", err, "conversationID", conversation.ConversationID, "ownerUserID", conversation.OwnerUserID) -// continue -// } -// if err := c.msgNotificationSender.UserDeleteMsgsNotification(ctx, conversation.OwnerUserID, conversation.ConversationID, seqs); err != nil { -// log.ZError(ctx, "userDeleteMsgsNotification failed", err, "conversationID", conversation.ConversationID, "ownerUserID", conversation.OwnerUserID) -// } -// } -// } -//} - -func (c *MsgTool) ConversationsDestructMsgs() { - log.ZInfo(context.Background(), "start msg destruct cron task") - ctx := mcontext.NewCtx(stringutil.GetSelfFuncName()) - num, err := c.conversationDatabase.GetAllConversationIDsNumber(ctx) - if err != nil { - log.ZError(ctx, "GetAllConversationIDsNumber failed", err) - return - } - const batchNum = 50 - log.ZDebug(ctx, "GetAllConversationIDsNumber", "num", num) - if num == 0 { - return - } - count := int(num/batchNum + num/batchNum/2) - if count < 1 { - count = 1 - } - maxPage := 1 + num/batchNum - if num%batchNum != 0 { - maxPage++ - } - for i := 0; i < count; i++ { - pageNumber := rand.Int63() % maxPage - pagination := &sdkws.RequestPagination{ - PageNumber: int32(pageNumber), - ShowNumber: batchNum, - } - conversationIDs, err := c.conversationDatabase.PageConversationIDs(ctx, pagination) - if err != nil { - log.ZError(ctx, "PageConversationIDs failed", err, "pageNumber", pageNumber) - continue - } - log.ZError(ctx, "PageConversationIDs failed", err, "pageNumber", pageNumber, "conversationIDsNum", len(conversationIDs), "conversationIDs", conversationIDs) - if len(conversationIDs) == 0 { - continue - } - conversations, err := c.conversationDatabase.GetConversationsByConversationID(ctx, conversationIDs) - if err != nil { - log.ZError(ctx, "GetConversationsByConversationID failed", err, "conversationIDs", conversationIDs) - continue - } - temp := make([]*relation.ConversationModel, 0, len(conversations)) - for i, conversation := range conversations { - if conversation.IsMsgDestruct && conversation.MsgDestructTime != 0 && (time.Now().Unix() > (conversation.MsgDestructTime+conversation.LatestMsgDestructTime.Unix()+8*60*60)) || - conversation.LatestMsgDestructTime.IsZero() { - temp = append(temp, conversations[i]) - } - } - for _, conversation := range temp { - ctx = mcontext.NewCtx(stringutil.GetSelfFuncName() + "-" + idutil.OperationIDGenerator() + "-" + conversation.ConversationID + "-" + conversation.OwnerUserID) - log.ZDebug( - ctx, - "UserMsgsDestruct", - "conversationID", - conversation.ConversationID, - "ownerUserID", - conversation.OwnerUserID, - "msgDestructTime", - conversation.MsgDestructTime, - "lastMsgDestructTime", - conversation.LatestMsgDestructTime, - ) - now := time.Now() - seqs, err := c.msgDatabase.UserMsgsDestruct(ctx, conversation.OwnerUserID, conversation.ConversationID, conversation.MsgDestructTime, conversation.LatestMsgDestructTime) - if err != nil { - log.ZError(ctx, "user msg destruct failed", err, "conversationID", conversation.ConversationID, "ownerUserID", conversation.OwnerUserID) - continue - } - if len(seqs) > 0 { - if err := c.conversationDatabase.UpdateUsersConversationField(ctx, []string{conversation.OwnerUserID}, conversation.ConversationID, map[string]any{"latest_msg_destruct_time": now}); err != nil { - log.ZError(ctx, "updateUsersConversationField failed", err, "conversationID", conversation.ConversationID, "ownerUserID", conversation.OwnerUserID) - continue - } - c.msgNotificationSender.UserDeleteMsgsNotification(ctx, conversation.OwnerUserID, conversation.ConversationID, seqs) - } - } - } -} diff --git a/internal/tools/cron_task.go b/internal/tools/cron_task.go index 82ce95eda9..7161f55fc1 100644 --- a/internal/tools/cron_task.go +++ b/internal/tools/cron_task.go @@ -16,8 +16,14 @@ package tools import ( "context" + "fmt" "github.com/openimsdk/open-im-server/v3/pkg/common/config" - "github.com/openimsdk/tools/db/redisutil" + kdisc "github.com/openimsdk/open-im-server/v3/pkg/common/discoveryregister" + "github.com/openimsdk/protocol/msg" + "github.com/openimsdk/tools/mcontext" + "github.com/openimsdk/tools/mw" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" "os" "os/signal" "syscall" @@ -25,96 +31,58 @@ import ( "github.com/openimsdk/tools/errs" "github.com/openimsdk/tools/log" - "github.com/redis/go-redis/v9" "github.com/robfig/cron/v3" ) type CronTaskConfig struct { CronTask config.CronTask - RedisConfig config.Redis - MongodbConfig config.Mongo ZookeeperConfig config.ZooKeeper Share config.Share - KafkaConfig config.Kafka } func Start(ctx context.Context, config *CronTaskConfig) error { - - log.CInfo(ctx, "CRON-TASK server is initializing", "chatRecordsClearTime", - config.CronTask.ChatRecordsClearTime, "msgDestructTime", config.CronTask.MsgDestructTime) - - msgTool, err := InitMsgTool(ctx, config) - if err != nil { - return err - } - - msgTool.convertTools() - - rdb, err := redisutil.NewRedisClient(ctx, config.RedisConfig.Build()) - if err != nil { - return err + log.CInfo(ctx, "CRON-TASK server is initializing", "chatRecordsClearTime", config.CronTask.ChatRecordsClearTime, "msgDestructTime", config.CronTask.RetainChatRecords) + if config.CronTask.RetainChatRecords < 1 { + return errs.New("msg destruct time must be greater than 1").Wrap() } - - // register cron tasks - var crontab = cron.New() - - _, err = crontab.AddFunc(config.CronTask.ChatRecordsClearTime, - cronWrapFunc(config, rdb, "cron_clear_msg_and_fix_seq", msgTool.AllConversationClearMsgAndFixSeq)) + client, err := kdisc.NewDiscoveryRegister(&config.ZookeeperConfig, &config.Share) if err != nil { - return errs.Wrap(err) + return errs.WrapMsg(err, "failed to register discovery service") } - - _, err = crontab.AddFunc(config.CronTask.MsgDestructTime, - cronWrapFunc(config, rdb, "cron_conversations_destruct_msgs", msgTool.ConversationsDestructMsgs)) + client.AddOption(mw.GrpcClient(), grpc.WithTransportCredentials(insecure.NewCredentials())) + ctx, exitBy := context.WithCancelCause(context.Background()) + ctx = mcontext.SetOpUserID(ctx, config.Share.IMAdminUserID[0]) + conn, err := client.GetConn(ctx, config.Share.RpcRegisterName.Msg) if err != nil { - return errs.WrapMsg(err, "cron_conversations_destruct_msgs") - } - - // start crontab - crontab.Start() - - sigs := make(chan os.Signal, 1) - signal.Notify(sigs, syscall.SIGTERM) - <-sigs - - // stop crontab, Wait for the running task to exit. - cronCtx := crontab.Stop() - - select { - case <-cronCtx.Done(): - // graceful exit - - case <-time.After(15 * time.Second): - // forced exit on timeout - } - - return nil -} - -// netlock redis lock. -func netlock(rdb redis.UniversalClient, key string, ttl time.Duration) bool { - value := "used" - ok, err := rdb.SetNX(context.Background(), key, value, ttl).Result() // nolint - if err != nil { - // when err is about redis server, return true. - return false + return err } - - return ok -} - -func cronWrapFunc(config *CronTaskConfig, rdb redis.UniversalClient, key string, fn func()) func() { - enableCronLocker := config.CronTask.EnableCronLocker - return func() { - // if don't enable cron-locker, call fn directly. - if !enableCronLocker { - fn() - return + cli := msg.NewMsgClient(conn) + go func() { + sigs := make(chan os.Signal, 1) + signal.Notify(sigs, syscall.SIGTERM) + select { + case <-ctx.Done(): + case s := <-sigs: + exitBy(fmt.Errorf("exit signal %s", s)) } - - // when acquire redis lock, call fn(). - if netlock(rdb, key, 5*time.Second) { - fn() + }() + crontab := cron.New() + clearFunc := func() { + now := time.Now() + deltime := now.Add(-time.Hour * 24 * time.Duration(config.CronTask.RetainChatRecords)) + ctx := mcontext.SetOperationID(ctx, fmt.Sprintf("cron_%d_%d", os.Getpid(), deltime.UnixMilli())) + log.ZInfo(ctx, "clear chat records", "deltime", deltime, "timestamp", deltime.UnixMilli()) + if _, err := cli.ClearMsg(ctx, &msg.ClearMsgReq{Timestamp: deltime.UnixMilli()}); err != nil { + log.ZError(ctx, "cron clear chat records failed", err, "deltime", deltime, "cont", time.Since(now)) + return } + log.ZInfo(ctx, "cron clear chat records success", "deltime", deltime, "cont", time.Since(now)) + } + if _, err := crontab.AddFunc(config.CronTask.ChatRecordsClearTime, clearFunc); err != nil { + return errs.Wrap(err) } + log.ZInfo(ctx, "start cron task", "chatRecordsClearTime", config.CronTask.ChatRecordsClearTime) + crontab.Start() + <-ctx.Done() + return context.Cause(ctx) } diff --git a/internal/tools/cron_task_test.go b/internal/tools/cron_task_test.go deleted file mode 100644 index 0bea8a4361..0000000000 --- a/internal/tools/cron_task_test.go +++ /dev/null @@ -1,113 +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 tools - -import ( - "testing" - "time" - - "github.com/redis/go-redis/v9" - "github.com/stretchr/testify/assert" -) - -func TestDisLock(t *testing.T) { - rdb := redis.NewClient(&redis.Options{}) - defer rdb.Close() - - assert.Equal(t, true, netlock(rdb, "cron-1", 1*time.Second)) - - // if exists, get false - assert.Equal(t, false, netlock(rdb, "cron-1", 1*time.Second)) - - time.Sleep(2 * time.Second) - - // wait for key on timeout, get true - assert.Equal(t, true, netlock(rdb, "cron-1", 2*time.Second)) - - // set different key - assert.Equal(t, true, netlock(rdb, "cron-2", 2*time.Second)) -} - -//func TestCronWrapFunc(t *testing.T) { -// rdb := redis.NewClient(&redis.Options{}) -// defer rdb.Close() -// -// once := sync.Once{} -// done := make(chan struct{}, 1) -// cb := func() { -// once.Do(func() { -// close(done) -// }) -// } -// -// start := time.Now() -// key := fmt.Sprintf("cron-%v", rand.Int31()) -// crontab := cron.New(cron.WithSeconds()) -// crontab.AddFunc("*/1 * * * * *", cronWrapFunc(config.NewGlobalConfig(), rdb, key, cb)) -// crontab.Start() -// <-done -// -// dur := time.Since(start) -// assert.LessOrEqual(t, dur.Seconds(), float64(2*time.Second)) -// crontab.Stop() -//} -// -//func TestCronWrapFuncWithNetlock(t *testing.T) { -// conf, err := initCfg() -// if err != nil { -// panic(err) -// } -// conf.EnableCronLocker = true -// rdb := redis.NewClient(&redis.Options{}) -// defer rdb.Close() -// -// done := make(chan string, 10) -// -// crontab := cron.New(cron.WithSeconds()) -// -// key := fmt.Sprintf("cron-%v", rand.Int31()) -// crontab.AddFunc("*/1 * * * * *", cronWrapFunc(conf, rdb, key, func() { -// done <- "host1" -// })) -// crontab.AddFunc("*/1 * * * * *", cronWrapFunc(conf, rdb, key, func() { -// done <- "host2" -// })) -// crontab.Start() -// -// time.Sleep(12 * time.Second) -// // the ttl of netlock is 5s, so expected value is 2. -// assert.Equal(t, len(done), 2) -// -// crontab.Stop() -//} -// -//func initCfg() (*config.GlobalConfig, error) { -// const ( -// defaultCfgPath = "../../../../../config/config.yaml" -// ) -// -// cfgPath := flag.String("c", defaultCfgPath, "Path to the configuration file") -// data, err := os.ReadFile(*cfgPath) -// if err != nil { -// return nil, errs.WrapMsg(err, "ReadFile unmarshal failed") -// } -// -// conf := config.NewGlobalConfig() -// err = yaml.Unmarshal(data, &conf) -// if err != nil { -// return nil, errs.WrapMsg(err, "InitConfig unmarshal failed") -// } -// return conf, nil -//} diff --git a/internal/tools/msg.go b/internal/tools/msg.go deleted file mode 100644 index 42af1efdc2..0000000000 --- a/internal/tools/msg.go +++ /dev/null @@ -1,226 +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 tools - -import ( - "context" - "fmt" - "github.com/openimsdk/open-im-server/v3/internal/rpc/msg" - "math" - "math/rand" - - "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" - "github.com/openimsdk/open-im-server/v3/pkg/util/conversationutil" - "github.com/openimsdk/protocol/sdkws" - "github.com/openimsdk/tools/errs" - "github.com/openimsdk/tools/log" - "github.com/openimsdk/tools/mcontext" - "github.com/openimsdk/tools/utils/stringutil" - "github.com/redis/go-redis/v9" -) - -type MsgTool struct { - msgDatabase controller.CommonMsgDatabase - conversationDatabase controller.ConversationDatabase - userDatabase controller.UserDatabase - groupDatabase controller.GroupDatabase - msgNotificationSender *msg.MsgNotificationSender - config *CronTaskConfig -} - -func NewMsgTool(msgDatabase controller.CommonMsgDatabase, userDatabase controller.UserDatabase, - groupDatabase controller.GroupDatabase, conversationDatabase controller.ConversationDatabase, - msgNotificationSender *msg.MsgNotificationSender, config *CronTaskConfig, -) *MsgTool { - return &MsgTool{ - msgDatabase: msgDatabase, - userDatabase: userDatabase, - groupDatabase: groupDatabase, - conversationDatabase: conversationDatabase, - msgNotificationSender: msgNotificationSender, - config: config, - } -} - -func InitMsgTool(ctx context.Context, config *CronTaskConfig) (*MsgTool, error) { - ch := make(chan int) - <-ch - //mgocli, err := mongoutil.NewMongoDB(ctx, config.MongodbConfig.Build()) - //if err != nil { - // return nil, err - //} - //rdb, err := redisutil.NewRedisClient(ctx, config.RedisConfig.Build()) - //if err != nil { - // return nil, err - //} - //discov, err := kdisc.NewDiscoveryRegister(&config.ZookeeperConfig, &config.Share) - //if err != nil { - // return nil, err - //} - //discov.AddOption(mw.GrpcClient(), grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithDefaultServiceConfig(fmt.Sprintf(`{"LoadBalancingPolicy": "%s"}`, "round_robin"))) - //userDB, err := mgo.NewUserMongo(mgocli.GetDB()) - //if err != nil { - // return nil, err - //} - ////msgDatabase, err := controller.InitCommonMsgDatabase(rdb, mgocli.GetDB(), config) - //if err != nil { - // return nil, err - //} - //userMongoDB := mgo.NewUserMongoDriver(mgocli.GetDB()) - //userDatabase := controller.NewUserDatabase( - // userDB, - // cache.NewUserCacheRedis(rdb, userDB, cache.GetDefaultOpt()), - // mgocli.GetTx(), - // userMongoDB, - //) - //groupDB, err := mgo.NewGroupMongo(mgocli.GetDB()) - //if err != nil { - // return nil, err - //} - //groupMemberDB, err := mgo.NewGroupMember(mgocli.GetDB()) - //if err != nil { - // return nil, err - //} - //groupRequestDB, err := mgo.NewGroupRequestMgo(mgocli.GetDB()) - //if err != nil { - // return nil, err - //} - //conversationDB, err := mgo.NewConversationMongo(mgocli.GetDB()) - //if err != nil { - // return nil, err - //} - //groupDatabase := controller.NewGroupDatabase(rdb, groupDB, groupMemberDB, groupRequestDB, mgocli.GetTx(), nil) - //conversationDatabase := controller.NewConversationDatabase( - // conversationDB, - // cache.NewConversationRedis(rdb, cache.GetDefaultOpt(), conversationDB), - // mgocli.GetTx(), - //) - //msgRpcClient := rpcclient.NewMessageRpcClient(discov, config.Share.RpcRegisterName.Msg) - //msgNotificationSender := notification.NewMsgNotificationSender(config, rpcclient.WithRpcClient(&msgRpcClient)) - //msgTool := NewMsgTool(msgDatabase, userDatabase, groupDatabase, conversationDatabase, msgNotificationSender, config) - //return msgTool, nil - return nil, nil -} - -// func (c *MsgTool) AllConversationClearMsgAndFixSeq() { -// ctx := mcontext.NewCtx(utils.GetSelfFuncName()) -// log.ZInfo(ctx, "============================ start del cron task ============================") -// conversationIDs, err := c.conversationDatabase.GetAllConversationIDs(ctx) -// if err != nil { -// log.ZError(ctx, "GetAllConversationIDs failed", err) -// return -// } -// for _, conversationID := range conversationIDs { -// conversationIDs = append(conversationIDs, utils.GetNotificationConversationIDByConversationID(conversationID)) -// } -// c.ClearConversationsMsg(ctx, conversationIDs) -// log.ZInfo(ctx, "============================ start del cron finished ============================") -//} - -func (c *MsgTool) AllConversationClearMsgAndFixSeq() { - ctx := mcontext.NewCtx(stringutil.GetSelfFuncName()) - log.ZInfo(ctx, "============================ start del cron task ============================") - num, err := c.conversationDatabase.GetAllConversationIDsNumber(ctx) - if err != nil { - log.ZError(ctx, "GetAllConversationIDsNumber failed", err) - return - } - const batchNum = 50 - log.ZDebug(ctx, "GetAllConversationIDsNumber", "num", num) - if num == 0 { - return - } - count := int(num/batchNum + num/batchNum/2) - if count < 1 { - count = 1 - } - maxPage := 1 + num/batchNum - if num%batchNum != 0 { - maxPage++ - } - for i := 0; i < count; i++ { - pageNumber := rand.Int63() % maxPage - pagination := &sdkws.RequestPagination{ - PageNumber: int32(pageNumber), - ShowNumber: batchNum, - } - conversationIDs, err := c.conversationDatabase.PageConversationIDs(ctx, pagination) - if err != nil { - log.ZError(ctx, "PageConversationIDs failed", err, "pageNumber", pageNumber) - continue - } - log.ZDebug(ctx, "PageConversationIDs failed", "pageNumber", pageNumber, "conversationIDsNum", len(conversationIDs), "conversationIDs", conversationIDs) - if len(conversationIDs) == 0 { - continue - } - c.ClearConversationsMsg(ctx, conversationIDs) - } - log.ZInfo(ctx, "============================ start del cron finished ============================") -} - -func (c *MsgTool) ClearConversationsMsg(ctx context.Context, conversationIDs []string) { - for _, conversationID := range conversationIDs { - if err := c.msgDatabase.DeleteConversationMsgsAndSetMinSeq(ctx, conversationID, int64(c.config.CronTask.RetainChatRecords*24*60*60)); err != nil { - log.ZError(ctx, "DeleteUserSuperGroupMsgsAndSetMinSeq failed", err, "conversationID", - conversationID, "DBRetainChatRecords", c.config.CronTask.RetainChatRecords) - } - if err := c.checkMaxSeq(ctx, conversationID); err != nil { - log.ZError(ctx, "fixSeq failed", err, "conversationID", conversationID) - } - } -} - -func (c *MsgTool) checkMaxSeqWithMongo(ctx context.Context, conversationID string, maxSeqCache int64) error { - minSeqMongo, maxSeqMongo, err := c.msgDatabase.GetMongoMaxAndMinSeq(ctx, conversationID) - if err != nil { - return err - } - if math.Abs(float64(maxSeqMongo-maxSeqCache)) > 10 { - err = fmt.Errorf("cache max seq and mongo max seq is diff > 10, maxSeqMongo:%d,minSeqMongo:%d,maxSeqCache:%d,conversationID:%s", maxSeqMongo, minSeqMongo, maxSeqCache, conversationID) - return errs.Wrap(err) - } - return nil -} - -func (c *MsgTool) checkMaxSeq(ctx context.Context, conversationID string) error { - maxSeq, err := c.msgDatabase.GetMaxSeq(ctx, conversationID) - if err != nil { - if errs.Unwrap(err) == redis.Nil { - return nil - } - return err - } - if err := c.checkMaxSeqWithMongo(ctx, conversationID, maxSeq); err != nil { - return err - } - return nil -} - -func (c *MsgTool) FixAllSeq(ctx context.Context) error { - conversationIDs, err := c.conversationDatabase.GetAllConversationIDs(ctx) - if err != nil { - return err - } - for _, conversationID := range conversationIDs { - conversationIDs = append(conversationIDs, conversationutil.GetNotificationConversationIDByConversationID(conversationID)) - } - for _, conversationID := range conversationIDs { - if err := c.checkMaxSeq(ctx, conversationID); err != nil { - log.ZWarn(ctx, "fixSeq failed", err, "conversationID", conversationID) - } - } - fmt.Println("fix all seq finished") - return nil -} diff --git a/internal/tools/msg_doc_convert.go b/internal/tools/msg_doc_convert.go deleted file mode 100644 index e7625ce215..0000000000 --- a/internal/tools/msg_doc_convert.go +++ /dev/null @@ -1,46 +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 tools - -import ( - "github.com/openimsdk/open-im-server/v3/pkg/msgprocessor" - "github.com/openimsdk/protocol/constant" - "github.com/openimsdk/tools/log" - "github.com/openimsdk/tools/mcontext" -) - -func (c *MsgTool) convertTools() { - ctx := mcontext.NewCtx("convert") - conversationIDs, err := c.conversationDatabase.GetAllConversationIDs(ctx) - if err != nil { - log.ZError(ctx, "get all conversation ids failed", err) - return - } - for _, conversationID := range conversationIDs { - conversationIDs = append(conversationIDs, msgprocessor.GetNotificationConversationIDByConversationID(conversationID)) - } - _, userIDs, err := c.userDatabase.GetAllUserID(ctx, nil) - if err != nil { - log.ZError(ctx, "get all user ids failed", err) - return - } - log.ZDebug(ctx, "all userIDs", "len userIDs", len(userIDs)) - for _, userID := range userIDs { - conversationIDs = append(conversationIDs, msgprocessor.GetConversationIDBySessionType(constant.SingleChatType, userID, userID)) - conversationIDs = append(conversationIDs, msgprocessor.GetNotificationConversationID(constant.SingleChatType, userID, userID)) - } - log.ZDebug(ctx, "all conversationIDs", "len userIDs", len(conversationIDs)) - c.msgDatabase.ConvertMsgsDocLen(ctx, conversationIDs) -} diff --git a/pkg/authverify/token.go b/pkg/authverify/token.go index a96d6de201..f1b377bad7 100644 --- a/pkg/authverify/token.go +++ b/pkg/authverify/token.go @@ -46,7 +46,6 @@ func IsAppManagerUid(ctx context.Context, imAdminUserID []string) bool { } func CheckAdmin(ctx context.Context, imAdminUserID []string) error { - if datautil.Contain(mcontext.GetOpUserID(ctx), imAdminUserID...) { return nil } diff --git a/pkg/common/cmd/cron_task.go b/pkg/common/cmd/cron_task.go index 0e94cf52ce..be26f5af36 100644 --- a/pkg/common/cmd/cron_task.go +++ b/pkg/common/cmd/cron_task.go @@ -34,11 +34,8 @@ func NewCronTaskCmd() *CronTaskCmd { ret := &CronTaskCmd{cronTaskConfig: &cronTaskConfig} ret.configMap = map[string]any{ OpenIMCronTaskCfgFileName: &cronTaskConfig.CronTask, - RedisConfigFileName: &cronTaskConfig.RedisConfig, - MongodbConfigFileName: &cronTaskConfig.MongodbConfig, ZookeeperConfigFileName: &cronTaskConfig.ZookeeperConfig, ShareFileName: &cronTaskConfig.Share, - KafkaConfigFileName: &cronTaskConfig.KafkaConfig, } ret.RootCmd = NewRootCmd(program.GetProcessName(), WithConfigMap(ret.configMap)) ret.ctx = context.WithValue(context.Background(), "version", config.Version) diff --git a/pkg/common/cmd/msg_utils.go b/pkg/common/cmd/msg_utils.go index fc5eaceae8..a0a9b04101 100644 --- a/pkg/common/cmd/msg_utils.go +++ b/pkg/common/cmd/msg_utils.go @@ -15,16 +15,11 @@ package cmd import ( - "context" - - "github.com/openimsdk/open-im-server/v3/internal/tools" - "github.com/openimsdk/tools/system/program" "github.com/spf13/cobra" ) type MsgUtilsCmd struct { cobra.Command - MsgTool *tools.MsgTool } func (m *MsgUtilsCmd) AddUserIDFlag() { @@ -146,27 +141,7 @@ func NewSeqCmd() *SeqCmd { func (s *SeqCmd) GetSeqCmd() *cobra.Command { s.Command.Run = func(cmdLines *cobra.Command, args []string) { - _, err := tools.InitMsgTool(context.Background(), nil) - if err != nil { - program.ExitWithError(err) - } - userID := s.getUserIDFlag(cmdLines) - superGroupID := s.getSuperGroupIDFlag(cmdLines) - // beginSeq := s.getBeginSeqFlag(cmdLines) - // limit := s.getLimitFlag(cmdLines) - if userID != "" { - // seq, err := msgTool.s(context.Background(), userID) - if err != nil { - panic(err) - } - // println(seq) - } else if superGroupID != "" { - // seq, err := msgTool.GetSuperGroupSeq(context.Background(), superGroupID) - if err != nil { - panic(err) - } - // println(seq) - } + } return &s.Command } diff --git a/pkg/common/config/config.go b/pkg/common/config/config.go index df2639cab3..caf31036cd 100644 --- a/pkg/common/config/config.go +++ b/pkg/common/config/config.go @@ -107,9 +107,7 @@ type API struct { type CronTask struct { ChatRecordsClearTime string `mapstructure:"chatRecordsClearTime"` - MsgDestructTime string `mapstructure:"msgDestructTime"` RetainChatRecords int `mapstructure:"retainChatRecords"` - EnableCronLocker bool `yaml:"enableCronLocker"` } type OfflinePushConfig struct { diff --git a/pkg/common/db/controller/msg.go b/pkg/common/db/controller/msg.go index 130e35d20e..c0a013c175 100644 --- a/pkg/common/db/controller/msg.go +++ b/pkg/common/db/controller/msg.go @@ -17,6 +17,8 @@ package controller import ( "context" "encoding/json" + "errors" + "strings" "time" "github.com/openimsdk/open-im-server/v3/pkg/common/config" @@ -102,6 +104,10 @@ type CommonMsgDatabase interface { RangeUserSendCount(ctx context.Context, start time.Time, end time.Time, group bool, ase bool, pageNumber int32, showNumber int32) (msgCount int64, userCount int64, users []*relation.UserCount, dateCount map[string]int64, err error) RangeGroupSendCount(ctx context.Context, start time.Time, end time.Time, ase bool, pageNumber int32, showNumber int32) (msgCount int64, userCount int64, groups []*relation.GroupCount, dateCount map[string]int64, err error) ConvertMsgsDocLen(ctx context.Context, conversationIDs []string) + + // clear msg + GetBeforeMsg(ctx context.Context, ts int64, limit int) ([]*relation.MsgDocModel, error) + DeleteDocMsgBefore(ctx context.Context, ts int64, doc *relation.MsgDocModel) ([]int, error) } func NewCommonMsgDatabase(msgDocModel relation.MsgDocModelInterface, msg cache.MsgCache, seq cache.SeqCache, kafkaConf *config.Kafka) (CommonMsgDatabase, error) { @@ -1047,3 +1053,72 @@ func (db *commonMsgDatabase) FindOneByDocIDs(ctx context.Context, conversationID func (db *commonMsgDatabase) ConvertMsgsDocLen(ctx context.Context, conversationIDs []string) { db.msgDocDatabase.ConvertMsgsDocLen(ctx, conversationIDs) } + +func (db *commonMsgDatabase) GetBeforeMsg(ctx context.Context, ts int64, limit int) ([]*relation.MsgDocModel, error) { + return db.msgDocDatabase.GetBeforeMsg(ctx, ts, limit) +} + +func (db *commonMsgDatabase) DeleteDocMsgBefore(ctx context.Context, ts int64, doc *relation.MsgDocModel) ([]int, error) { + var notNull int + index := make([]int, 0, len(doc.Msg)) + for i, message := range doc.Msg { + if message.Msg != nil { + notNull++ + if message.Msg.SendTime < ts { + index = append(index, i) + } + } + } + if len(index) == 0 { + return index, nil + } + maxSeq := doc.Msg[index[len(index)-1]].Msg.Seq + conversationID := doc.DocID[:strings.LastIndex(doc.DocID, ":")] + if err := db.setMinSeq(ctx, conversationID, maxSeq+1); err != nil { + return index, err + } + if len(index) == notNull { + return index, db.msgDocDatabase.DeleteDoc(ctx, doc.DocID) + } else { + return index, db.msgDocDatabase.DeleteMsgByIndex(ctx, doc.DocID, index) + } +} + +//func (db *commonMsgDatabase) ClearMsg(ctx context.Context, ts int64) (err error) { +// var ( +// docNum int +// msgNum int +// start = time.Now() +// ) +// for { +// msgs, err := db.msgDocDatabase.GetBeforeMsg(ctx, ts, 100) +// if err != nil { +// return err +// } +// if len(msgs) == 0 { +// return nil +// } +// for _, msg := range msgs { +// num, err := db.deleteOneMsg(ctx, ts, msg) +// if err != nil { +// return err +// } +// docNum++ +// msgNum += num +// } +// } +//} + +func (db *commonMsgDatabase) setMinSeq(ctx context.Context, conversationID string, seq int64) error { + dbSeq, err := db.seq.GetMinSeq(ctx, conversationID) + if err != nil { + if errors.Is(errs.Unwrap(err), redis.Nil) { + return nil + } + return err + } + if dbSeq >= seq { + return nil + } + return db.seq.SetMinSeq(ctx, conversationID, seq) +} diff --git a/pkg/common/db/mgo/conversation.go b/pkg/common/db/mgo/conversation.go index d10bda39b1..5292cb60cf 100644 --- a/pkg/common/db/mgo/conversation.go +++ b/pkg/common/db/mgo/conversation.go @@ -56,7 +56,16 @@ func (c *ConversationMgo) Delete(ctx context.Context, groupIDs []string) (err er } func (c *ConversationMgo) UpdateByMap(ctx context.Context, userIDs []string, conversationID string, args map[string]any) (rows int64, err error) { - res, err := mongoutil.UpdateMany(ctx, c.coll, bson.M{"owner_user_id": bson.M{"$in": userIDs}, "conversation_id": conversationID}, bson.M{"$set": args}) + if len(args) == 0 { + return 0, nil + } + filter := bson.M{ + "conversation_id": conversationID, + } + if len(userIDs) > 0 { + filter["owner_user_id"] = bson.M{"$in": userIDs} + } + res, err := mongoutil.UpdateMany(ctx, c.coll, filter, bson.M{"$set": args}) if err != nil { return 0, err } diff --git a/pkg/common/db/mgo/msg.go b/pkg/common/db/mgo/msg.go index 40ee5e4235..6fe24536bd 100644 --- a/pkg/common/db/mgo/msg.go +++ b/pkg/common/db/mgo/msg.go @@ -896,3 +896,89 @@ func (m *MsgMgo) ConvertMsgsDocLen(ctx context.Context, conversationIDs []string } } } + +func (m *MsgMgo) GetBeforeMsg(ctx context.Context, ts int64, limit int) ([]*relation.MsgDocModel, error) { + return mongoutil.Aggregate[*relation.MsgDocModel](ctx, m.coll, []bson.M{ + { + "$match": bson.M{ + "msgs.msg.send_time": bson.M{ + "$lt": ts, + }, + }, + }, + { + "$project": bson.M{ + "_id": 0, + "doc_id": 1, + "msgs.msg.send_time": 1, + "msgs.msg.seq": 1, + }, + }, + { + "$limit": limit, + }, + }) +} + +func (m *MsgMgo) DeleteMsgByIndex(ctx context.Context, docID string, index []int) error { + if len(index) == 0 { + return nil + } + model := &relation.MsgInfoModel{DelList: []string{}} + set := make(map[string]any) + for i := range index { + set[fmt.Sprintf("msgs.%d", i)] = model + } + return mongoutil.UpdateOne(ctx, m.coll, bson.M{"doc_id": docID}, bson.M{"$set": set}, true) +} + +//func (m *MsgMgo) ClearMsg(ctx context.Context, t time.Time) (int64, error) { +// ts := t.UnixMilli() +// var count int64 +// for { +// msgs, err := m.GetBeforeMsg(ctx, ts, 100) +// if err != nil { +// return count, err +// } +// if len(msgs) == 0 { +// return count, nil +// } +// for _, msg := range msgs { +// num, err := m.deleteOneMsg(ctx, ts, msg) +// count += num +// if err != nil { +// return count, err +// } +// } +// } +//} + +func (m *MsgMgo) DeleteDoc(ctx context.Context, docID string) error { + return mongoutil.DeleteOne(ctx, m.coll, bson.M{"doc_id": docID}) +} + +//func (m *MsgMgo) DeleteDocMsg(ctx context.Context, ts int64, doc *relation.MsgDocModel) (int64, error) { +// var notNull int +// index := make([]int, 0, len(doc.Msg)) +// for i, message := range doc.Msg { +// if message.Msg != nil { +// notNull++ +// if message.Msg.SendTime < ts { +// index = append(index, i) +// } +// } +// } +// if len(index) == 0 { +// return 0, errs.New("no msg to delete").WrapMsg("deleteOneMsg", "docID", doc.DocID) +// } +// if len(index) == notNull { +// if err := m.DeleteDoc(ctx, doc.DocID); err != nil { +// return 0, err +// } +// } else { +// if err := m.setNullMsg(ctx, doc.DocID, index); err != nil { +// return 0, err +// } +// } +// return int64(len(index)), nil +//} diff --git a/pkg/common/db/table/relation/msg.go b/pkg/common/db/table/relation/msg.go index 14b8dbb30e..41a6ede974 100644 --- a/pkg/common/db/table/relation/msg.go +++ b/pkg/common/db/table/relation/msg.go @@ -116,6 +116,12 @@ type MsgDocModelInterface interface { RangeUserSendCount(ctx context.Context, start time.Time, end time.Time, group bool, ase bool, pageNumber int32, showNumber int32) (msgCount int64, userCount int64, users []*UserCount, dateCount map[string]int64, err error) RangeGroupSendCount(ctx context.Context, start time.Time, end time.Time, ase bool, pageNumber int32, showNumber int32) (msgCount int64, userCount int64, groups []*GroupCount, dateCount map[string]int64, err error) ConvertMsgsDocLen(ctx context.Context, conversationIDs []string) + + DeleteDoc(ctx context.Context, docID string) error + DeleteMsgByIndex(ctx context.Context, docID string, index []int) error + GetBeforeMsg(ctx context.Context, ts int64, limit int) ([]*MsgDocModel, error) + + //ClearMsg(ctx context.Context, t time.Time) (int64, error) } func (MsgDocModel) TableName() string { diff --git a/pkg/rpcclient/conversation.go b/pkg/rpcclient/conversation.go index 6eb6c94612..e078f432b3 100644 --- a/pkg/rpcclient/conversation.go +++ b/pkg/rpcclient/conversation.go @@ -82,6 +82,11 @@ func (c *ConversationRpcClient) SetConversations(ctx context.Context, userIDs [] return err } +func (c *ConversationRpcClient) UpdateConversations(ctx context.Context, conversation *pbconversation.UpdateConversationReq) error { + _, err := c.Client.UpdateConversation(ctx, conversation) + return err +} + func (c *ConversationRpcClient) GetConversationIDs(ctx context.Context, ownerUserID string) ([]string, error) { resp, err := c.Client.GetConversationIDs(ctx, &pbconversation.GetConversationIDsReq{UserID: ownerUserID}) if err != nil { diff --git a/pkg/rpcclient/msg.go b/pkg/rpcclient/msg.go index 36daf9f66b..f660c74dd7 100644 --- a/pkg/rpcclient/msg.go +++ b/pkg/rpcclient/msg.go @@ -212,6 +212,11 @@ func (m *MessageRpcClient) GetConversationMaxSeq(ctx context.Context, conversati return resp.MaxSeq, nil } +func (m *MessageRpcClient) ClearMsg(ctx context.Context, ts int64) error { + _, err := m.Client.ClearMsg(ctx, &msg.ClearMsgReq{Timestamp: ts}) + return err +} + type NotificationSender struct { contentTypeConf map[int32]config.NotificationConfig sessionTypeConf map[int32]int32 From f5745b2193808de1f0f16e0fd05a170fa99e5b0b Mon Sep 17 00:00:00 2001 From: skiffer-git <72860476+skiffer-git@users.noreply.github.com> Date: Sun, 28 Apr 2024 12:09:46 +0800 Subject: [PATCH 160/188] Remove redundant scripts (#2254) --- config/templates/alertmanager.yml.template | 47 - config/templates/config.yaml.template | 552 ---- config/templates/email.tmpl.template | 16 - config/templates/env.template | 237 -- .../instance-down-rules.yml.template | 36 - config/templates/notification.yaml.template | 354 -- config/templates/open-im-ng-example.conf | 173 - config/templates/prometheus-dashboard.yaml | 1474 --------- config/templates/prometheus.yml.template | 99 - scripts/.spelling_failures | 31 - scripts/README.md | 311 -- scripts/advertise.sh | 112 - scripts/bash_beautify.py | 173 - scripts/build-all-service.sh | 72 - scripts/check-all.sh | 113 - scripts/cherry-pick.sh | 252 -- scripts/common.sh | 516 --- scripts/coverage.awk | 13 - scripts/coverage.sh | 29 - scripts/docker-start-all.sh | 26 - scripts/ensure-tag.sh | 26 - scripts/gen-swagger-docs.sh | 73 - scripts/genconfig.sh | 56 - scripts/gendoc.sh | 84 - scripts/init-config.sh | 265 -- scripts/init-env.sh | 33 - scripts/init-githooks.sh | 100 - scripts/install-im-server.sh | 86 - scripts/install/README.md | 116 - scripts/install/common.sh | 155 - scripts/install/dependency.sh | 89 - scripts/install/environment.sh | 581 ---- scripts/install/install-protobuf.sh | 118 - scripts/install/install.sh | 155 - scripts/install/openim-api.sh | 169 - scripts/install/openim-crontask.sh | 126 - scripts/install/openim-man.sh | 96 - scripts/install/openim-msggateway.sh | 141 - scripts/install/openim-msgtransfer.sh | 186 -- scripts/install/openim-push.sh | 150 - scripts/install/openim-rpc.sh | 254 -- scripts/install/openim-tools.sh | 179 - scripts/install/test.sh | 1466 --------- scripts/lib/chat.sh | 178 - scripts/lib/color.sh | 139 - scripts/lib/golang.sh | 384 --- scripts/lib/init.sh | 202 -- scripts/lib/logging.sh | 271 -- scripts/lib/release.sh | 670 ---- scripts/lib/util.sh | 2896 ----------------- scripts/lib/version.sh | 145 - scripts/list-feature-tests.sh | 23 - scripts/make-rules/common-versions.mk | 58 - scripts/make-rules/common.mk | 196 -- scripts/make-rules/copyright.mk | 63 - scripts/make-rules/dependencies.mk | 41 - scripts/make-rules/gen.mk | 100 - scripts/make-rules/golang.mk | 272 -- scripts/make-rules/image.mk | 183 -- scripts/make-rules/release.mk | 42 - scripts/make-rules/swagger.mk | 19 - scripts/make-rules/tools.mk | 280 -- scripts/release.sh | 150 - scripts/run-in-gopath.sh | 30 - scripts/start-all.sh | 109 - scripts/stop-all.sh | 60 - scripts/update-generated-docs.sh | 45 - scripts/update-yamlfmt.sh | 38 - scripts/verify-pkg-names.sh | 32 - scripts/verify-shellcheck.sh | 188 -- scripts/verify-spelling.sh | 28 - scripts/verify-standardizer.sh | 33 - scripts/verify-typecheck.sh | 34 - scripts/verify-yamlfmt.sh | 44 - scripts/wait-for-it.sh | 191 -- test/common.sh | 14 - test/wrktest.sh | 276 -- 77 files changed, 16774 deletions(-) delete mode 100644 config/templates/alertmanager.yml.template delete mode 100644 config/templates/config.yaml.template delete mode 100644 config/templates/email.tmpl.template delete mode 100644 config/templates/env.template delete mode 100644 config/templates/instance-down-rules.yml.template delete mode 100644 config/templates/notification.yaml.template delete mode 100644 config/templates/open-im-ng-example.conf delete mode 100644 config/templates/prometheus-dashboard.yaml delete mode 100644 config/templates/prometheus.yml.template delete mode 100644 scripts/.spelling_failures delete mode 100644 scripts/README.md delete mode 100755 scripts/advertise.sh delete mode 100755 scripts/bash_beautify.py delete mode 100755 scripts/build-all-service.sh delete mode 100755 scripts/check-all.sh delete mode 100755 scripts/cherry-pick.sh delete mode 100755 scripts/common.sh delete mode 100755 scripts/coverage.awk delete mode 100755 scripts/coverage.sh delete mode 100755 scripts/docker-start-all.sh delete mode 100755 scripts/ensure-tag.sh delete mode 100755 scripts/gen-swagger-docs.sh delete mode 100755 scripts/genconfig.sh delete mode 100755 scripts/gendoc.sh delete mode 100755 scripts/init-config.sh delete mode 100755 scripts/init-env.sh delete mode 100755 scripts/init-githooks.sh delete mode 100755 scripts/install-im-server.sh delete mode 100644 scripts/install/README.md delete mode 100755 scripts/install/common.sh delete mode 100755 scripts/install/dependency.sh delete mode 100755 scripts/install/environment.sh delete mode 100755 scripts/install/install-protobuf.sh delete mode 100755 scripts/install/install.sh delete mode 100755 scripts/install/openim-api.sh delete mode 100755 scripts/install/openim-crontask.sh delete mode 100755 scripts/install/openim-man.sh delete mode 100755 scripts/install/openim-msggateway.sh delete mode 100755 scripts/install/openim-msgtransfer.sh delete mode 100755 scripts/install/openim-push.sh delete mode 100755 scripts/install/openim-rpc.sh delete mode 100755 scripts/install/openim-tools.sh delete mode 100755 scripts/install/test.sh delete mode 100755 scripts/lib/chat.sh delete mode 100755 scripts/lib/color.sh delete mode 100755 scripts/lib/golang.sh delete mode 100755 scripts/lib/init.sh delete mode 100755 scripts/lib/logging.sh delete mode 100755 scripts/lib/release.sh delete mode 100755 scripts/lib/util.sh delete mode 100755 scripts/lib/version.sh delete mode 100755 scripts/list-feature-tests.sh delete mode 100644 scripts/make-rules/common-versions.mk delete mode 100644 scripts/make-rules/common.mk delete mode 100644 scripts/make-rules/copyright.mk delete mode 100644 scripts/make-rules/dependencies.mk delete mode 100644 scripts/make-rules/gen.mk delete mode 100644 scripts/make-rules/golang.mk delete mode 100644 scripts/make-rules/image.mk delete mode 100644 scripts/make-rules/release.mk delete mode 100644 scripts/make-rules/swagger.mk delete mode 100644 scripts/make-rules/tools.mk delete mode 100755 scripts/release.sh delete mode 100755 scripts/run-in-gopath.sh delete mode 100755 scripts/start-all.sh delete mode 100755 scripts/stop-all.sh delete mode 100755 scripts/update-generated-docs.sh delete mode 100755 scripts/update-yamlfmt.sh delete mode 100755 scripts/verify-pkg-names.sh delete mode 100755 scripts/verify-shellcheck.sh delete mode 100755 scripts/verify-spelling.sh delete mode 100755 scripts/verify-standardizer.sh delete mode 100755 scripts/verify-typecheck.sh delete mode 100755 scripts/verify-yamlfmt.sh delete mode 100755 scripts/wait-for-it.sh delete mode 100644 test/common.sh delete mode 100755 test/wrktest.sh diff --git a/config/templates/alertmanager.yml.template b/config/templates/alertmanager.yml.template deleted file mode 100644 index a0daadfbdf..0000000000 --- a/config/templates/alertmanager.yml.template +++ /dev/null @@ -1,47 +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. - -###################### AlertManager Configuration ###################### -# AlertManager configuration using environment variables -# -# Resolve timeout -# SMTP configuration for sending alerts -# Templates for email notifications -# Routing configurations for alerts -# Receiver configurations -global: - resolve_timeout: 5m - smtp_from: alert@openim.io - smtp_smarthost: smtp.163.com:465 - smtp_auth_username: alert@openim.io - smtp_auth_password: YOURAUTHPASSWORD - smtp_require_tls: false - smtp_hello: xxx监控告警 - -templates: - - /etc/alertmanager/email.tmpl - -route: - group_by: ['alertname'] - group_wait: 5s - group_interval: 5s - repeat_interval: 5m - receiver: email -receivers: - - name: email - email_configs: - - to: 'alert@example.com' - html: '{{ template "email.to.html" . }}' - headers: { Subject: "[OPENIM-SERVER]Alarm" } - send_resolved: true diff --git a/config/templates/config.yaml.template b/config/templates/config.yaml.template deleted file mode 100644 index 5c5cfda787..0000000000 --- a/config/templates/config.yaml.template +++ /dev/null @@ -1,552 +0,0 @@ -envs: - discovery: zookeeper - -###################### Zookeeper ###################### -# Zookeeper configuration -# It's not recommended to modify the schema -# -# Zookeeper address -# Zookeeper username -# Zookeeper password -zookeeper: - schema: openim - address: [ 172.28.0.1:12181 ] - username: '' - password: '' - -###################### Mongo ###################### -# 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 - -###################### Redis configuration information ###################### -# Redis configuration -# -# Username is required only for Redis version 6.0+ -redis: - address: [ 172.28.0.1:16379 ] - username: '' - password: openIM123 - -###################### Kafka configuration information ###################### -# Kafka configuration -# -# Kafka username -# Kafka password -# It's not recommended to modify this topic name -# Consumer group ID, it's not recommended to modify -kafka: - username: '' - password: '' - addr: [ 172.28.0.1:19094 ] - latestMsgToRedis: - topic: "latestMsgToRedis" - offlineMsgToMongo: - topic: "offlineMsgToMongoMysql" - msgToPush: - topic: "msgToPush" - consumerGroupID: - msgToRedis: redis - msgToMongo: mongo - msgToMySql: mysql - msgToPush: push - -###################### RPC configuration information ###################### -# RPC configuration -# -# IP address to register with zookeeper when starting RPC, the IP and corresponding rpcPort should be accessible by api/gateway -# Default listen IP is 0.0.0.0 -rpc: - registerIP: '' - listenIP: 0.0.0.0 - -###################### API configuration information ###################### -# API configuration -# -# API service port -# Default listen IP is 0.0.0.0 -api: - openImApiPort: [ 10002 ] - listenIP: 0.0.0.0 - -###################### Object configuration information ###################### -# Object storage configuration -# -# Use minio for object storage -# API URL should be accessible by the app -# It's not recommended to modify the bucket name -# Endpoint should be accessible by the app -# Session token -# Configuration for Tencent COS -# Configuration for Aliyun OSS -# apiURL is the address of the api, the access address of the app, use s3 must be configured -# minio.endpoint can be configured as an intranet address, -# minio.signEndpoint is minio public network address -object: - enable: "minio" - apiURL: "http://127.0.0.1:10002" - minio: - bucket: "openim" - endpoint: "http://172.28.0.1:10005" - accessKeyID: "root" - secretAccessKey: "openIM123" - sessionToken: '' - signEndpoint: "http://127.0.0.1:10005" - publicRead: false - cos: - bucketURL: https://temp-1252357374.cos.ap-chengdu.myqcloud.com - secretID: '' - secretKey: '' - sessionToken: '' - publicRead: false - oss: - endpoint: "https://oss-cn-chengdu.aliyuncs.com" - bucket: "demo-9999999" - bucketURL: "https://demo-9999999.oss-cn-chengdu.aliyuncs.com" - accessKeyID: '' - accessKeySecret: '' - sessionToken: '' - publicRead: false - kodo: - endpoint: "http://s3.cn-east-1.qiniucs.com" - bucket: "demo-9999999" - bucketURL: "http://your.domain.com" - accessKeyID: '' - accessKeySecret: '' - sessionToken: '' - publicRead: false - aws: - endpoint: "''" # This might not be necessary unless you're using a custom endpoint - region: "us-east-1" - bucket: "demo-9999999" - accessKeyID: '' - accessKeySecret: '' - publicRead: false - -###################### RPC Port Configuration ###################### -# RPC service ports -# These ports are passed into the program by the script and are not recommended to modify -# For launching multiple programs, just fill in multiple ports separated by commas -# For example, [10110, 10111] -rpcPort: - openImUserPort: [ 10110 ] - openImFriendPort: [ 10120 ] - openImMessagePort: [ 10130 ] - openImGroupPort: [ 10150 ] - openImAuthPort: [ 10160 ] - openImPushPort: [ 10170 ] - openImConversationPort: [ 10180 ] - openImThirdPort: [ 10190 ] - -###################### RPC Register Name Configuration ###################### -# RPC service names for registration, it's not recommended to modify these -rpcRegisterName: - openImUserName: User - openImFriendName: Friend - openImMsgName: Msg - openImPushName: Push - openImMessageGatewayName: MessageGateway - openImGroupName: Group - openImAuthName: Auth - openImConversationName: Conversation - openImThirdName: Third - -###################### Log Configuration ###################### -# Log configuration -# -# Storage directory -# Log rotation time -# Maximum number of logs to retain -# Log level, 6 means all levels -# Whether to output to stdout -# Whether to output in json format -# Whether to include stack trace in logs -log: - storageLocation: /data/workspaces/open-im-server/_output/logs/ - rotationTime: 24 - remainRotationCount: 2 - remainLogLevel: 6 - isStdout: false - isJson: false - withStack: false - -###################### Variables definition ###################### -# Long connection server configuration -# -# Websocket port for msg_gateway -# Maximum number of websocket connections -# Maximum length of websocket request package -# Websocket connection handshake timeout -longConnSvr: - openImWsPort: [ 10001 ] - websocketMaxConnNum: 100000 - openImMessageGatewayPort: [ 10140 ] - websocketMaxMsgLen: 4096 - websocketTimeout: 10 - -# Push notification service configuration -# -# Use GeTui for push notifications -# GeTui offline push configuration -# FCM offline push configuration -# Account file, place it in the config directory -# JPush configuration, modify these after applying in JPush backend -push: - enable: getui - geTui: - pushUrl: "https://restapi.getui.com/v2/$appId" - masterSecret: '' - appKey: '' - intent: '' - channelID: '' - channelName: '' - fcm: - serviceAccount: "x.json" - jpns: - appKey: '' - masterSecret: '' - pushUrl: '' - pushIntent: '' - -# App manager configuration -# -# Built-in app manager user IDs -# Built-in app manager nicknames -# Attention, this configure is discarded. If you have used him before, configure your own -manager: - userID: - nickname: - -# chatAdmin, use for send notification -# -# Built-in app system notification account ID -# Built-in app system notification account nickname -im-admin: - userID: [ "imAdmin" ] - nickname: [ "imAdmin" ] - -# Multi-platform login policy -# For each platform(Android, iOS, Windows, Mac, web), only one can be online at a time -multiLoginPolicy: 1 - -# Whether to store messages in MySQL, messages in MySQL are only used for management background -chatPersistenceMysql: true - -# Message cache timeout in seconds, it's not recommended to modify -msgCacheTimeout: 86400 - -# Whether to enable read receipts for group chat -groupMessageHasReadReceiptEnable: true - -# Whether to enable read receipts for single chat -singleMessageHasReadReceiptEnable: true - -# MongoDB offline message retention period in days -retainChatRecords: 365 - -# Schedule to clear expired messages(older than retainChatRecords days) in MongoDB every Wednesday at 2am -# This deletion is just for cleaning up disk usage according to previous configuration retainChatRecords, no notification will be sent -chatRecordsClearTime: "0 2 * * 3" - -# Schedule to auto delete messages every day at 2am -# This deletion is for messages that have been retained for more than msg_destruct_time (seconds) in the conversation field -msgDestructTime: "0 2 * * *" - -# Secret key -secret: openIM123 - -# Token policy -# -# Token expiration period in days -tokenPolicy: - expire: 90 - -# Message verification policy -# -# Whether to verify friendship when sending messages -messageVerify: - friendVerify: false - -# iOS push notification configuration -# -# iOS push notification sound -# Whether to count badge -# Whether it's production environment -iosPush: - pushSound: "xxx" - badgeCount: true - production: false - -###################### Third-party service configuration ###################### -# Callback configuration -# -# Callback URL -# Whether to enable this callback event -# Timeout in seconds -# Whether to continue execution if callback fails -callback: - url: "http://127.0.0.1:10008/callbackExample" - beforeSendSingleMsg: - enable: false - timeout: 5 - failedContinue: true - beforeUpdateUserInfoEx: - enable: false - timeout: 5 - failedContinue: true - afterUpdateUserInfoEx: - enable: false - timeout: 5 - failedContinue: true - afterSendSingleMsg: - enable: false - timeout: 5 - failedContinue: true - beforeSendGroupMsg: - enable: false - timeout: 5 - failedContinue: true - afterSendGroupMsg: - enable: false - timeout: 5 - failedContinue: true - msgModify: - enable: false - timeout: 5 - failedContinue: true - userOnline: - enable: false - timeout: 5 - failedContinue: true - userOffline: - enable: false - timeout: 5 - failedContinue: true - userKickOff: - enable: false - timeout: 5 - failedContinue: true - offlinePush: - enable: false - timeout: 5 - failedContinue: true - onlinePush: - enable: false - timeout: 5 - failedContinue: true - superGroupOnlinePush: - enable: false - timeout: 5 - failedContinue: true - beforeAddFriend: - enable: false - timeout: 5 - failedContinue: true - beforeUpdateUserInfo: - enable: false - timeout: 5 - failedContinue: true - beforeCreateGroup: - enable: false - timeout: 5 - failedContinue: true - afterCreateGroup: - enable: false - timeout: 5 - failedContinue: true - beforeMemberJoinGroup: - enable: false - timeout: 5 - failedContinue: true - beforeSetGroupMemberInfo: - enable: false - timeout: 5 - failedContinue: true - afterSetGroupMemberInfo: - enable: false - timeout: 5 - failedContinue: true - setMessageReactionExtensions: - enable: false - timeout: 5 - failedContinue: true - quitGroup: - enable: false - timeout: 5 - failedContinue: true - killGroupMember: - enable: false - timeout: 5 - failedContinue: true - dismissGroup: - enable: false - timeout: 5 - failedContinue: true - joinGroup: - enable: false - timeout: 5 - failedContinue: true - groupMsgRead: - enable: false - timeout: 5 - failedContinue: true - singleMsgRead: - enable: false - timeout: 5 - failedContinue: true - updateUserInfo: - enable: false - timeout: 5 - failedContinue: true - beforeUserRegister: - enable: false - timeout: 5 - failedContinue: true - afterUserRegister: - enable: false - timeout: 5 - failedContinue: true - transferGroupOwner: - enable: false - timeout: 5 - failedContinue: true - beforeSetFriendRemark: - enable: false - timeout: 5 - failedContinue: true - afterSetFriendRemark: - enable: false - timeout: 5 - failedContinue: true - afterGroupMsgRead: - enable: false - timeout: 5 - failedContinue: true - afterGroupMsgRevoke: - enable: false - timeout: 5 - failedContinue: true - afterJoinGroup: - enable: false - timeout: 5 - failedContinue: true - beforeInviteUserToGroup: - enable: false - timeout: 5 - failedContinue: true - joinGroupAfter: - enable: false - timeout: 5 - failedContinue: true - setGroupInfoAfter: - enable: false - timeout: 5 - failedContinue: true - setGroupInfoBefore: - enable: false - timeout: 5 - failedContinue: true - revokeMsgAfter: - enable: false - timeout: 5 - failedContinue: true - addBlackBefore: - enable: false - timeout: 5 - failedContinue: true - addFriendAfter: - enable: false - timeout: 5 - failedContinue: true - addFriendAgreeBefore: - enable: false - timeout: 5 - failedContinue: true - deleteFriendAfter: - enable: false - timeout: 5 - failedContinue: true - importFriendsBefore: - enable: false - timeout: 5 - failedContinue: true - importFriendsAfter: - enable: false - timeout: 5 - failedContinue: true - removeBlackAfter: - enable: false - timeout: 5 - failedContinue: true -###################### Prometheus ###################### -# Prometheus configuration for various services -# The number of Prometheus ports per service needs to correspond to rpcPort -# The number of ports needs to be consistent with msg_transfer_service_num in script/path_info.sh -prometheus: - enable: true - grafanaUrl: http://127.0.0.1:13000/ - apiPrometheusPort: [20100] - userPrometheusPort: [ 20110 ] - friendPrometheusPort: [ 20120 ] - messagePrometheusPort: [ 20130 ] - messageGatewayPrometheusPort: [ 20140 ] - groupPrometheusPort: [ 20150 ] - authPrometheusPort: [ 20160 ] - pushPrometheusPort: [ 20170 ] - conversationPrometheusPort: [ 20230 ] - rtcPrometheusPort: [ 21300 ] - thirdPrometheusPort: [ 21301 ] - messageTransferPrometheusPort: [ 21400, 21401, 21402, 21403 ] # List of ports - -###################### LocalCache configuration information ###################### -# topic: redis subscriber channel -# slotNum: number of slots, multiple slots can prevent too many keys from competing for a lock -# slotSize: number of slots, the number of cached keys per slot, the overall cache quantity is slotNum * slotSize -# successExpire: successful cache time seconds -# failedExpire: failed cache time seconds -# disable local caching and annotate topic, slotNum, and slotSize -localCache: - user: - topic: DELETE_CACHE_USER - slotNum: 100 - slotSize: 2000 - successExpire: 300 - failedExpire: 5 - - group: - topic: DELETE_CACHE_GROUP - slotNum: 100 - slotSize: 2000 - successExpire: 300 - failedExpire: 5 - - friend: - topic: DELETE_CACHE_FRIEND - slotNum: 100 - slotSize: 2000 - successExpire: 300 - failedExpire: 5 - - conversation: - topic: DELETE_CACHE_CONVERSATION - slotNum: 100 - slotSize: 2000 - successExpire: 300 - failedExpire: 5 diff --git a/config/templates/email.tmpl.template b/config/templates/email.tmpl.template deleted file mode 100644 index 0385601d00..0000000000 --- a/config/templates/email.tmpl.template +++ /dev/null @@ -1,16 +0,0 @@ -{{ define "email.to.html" }} -{{ range .Alerts }} - -
-

OpenIM Alert

-

Alert Program: Prometheus Alert

-

Severity Level: {{ .Labels.severity }}

-

Alert Type: {{ .Labels.alertname }}

-

Affected Host: {{ .Labels.instance }}

-

Affected Service: {{ .Labels.job }}

-

Alert Subject: {{ .Annotations.summary }}

-

Trigger Time: {{ .StartsAt.Format "2006-01-02 15:04:05" }}

-
- -{{ end }} -{{ end }} diff --git a/config/templates/env.template b/config/templates/env.template deleted file mode 100644 index 1178e0f7df..0000000000 --- a/config/templates/env.template +++ /dev/null @@ -1,237 +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. - -# ----------------------------------------------------------------------------- -# General Configuration -# This section contains general configuration options for the entire environment. -# These options can be set via environment variables. If both environment variables -# and settings in this .env file exist, the environment variables take precedence. -# ----------------------------------------------------------------------------- -# ========================== -# General Configuration -# ========================== -# These settings apply to the overall environment. - -# Data storage directory for persistent data. -# Example: DATA_DIR=/path/to/data -DATA_DIR=/data/workspaces/open-im-server - -# Docker image registry. Uncomment the preferred one. -# Options: ghcr.io/openimsdk, openim, registry.cn-hangzhou.aliyuncs.com/openimsdk -# IMAGE_REGISTRY="ghcr.io/openimsdk" -# IMAGE_REGISTRY="openim" -# IMAGE_REGISTRY="registry.cn-hangzhou.aliyuncs.com/openimsdk" -IMAGE_REGISTRY=ghcr.io/openimsdk - -# ====================================== -# ========= Network Configuration ====== -# ====================================== - -# Subnet for the Docker network. -# Default: DOCKER_BRIDGE_SUBNET=172.28.0.0/16 -DOCKER_BRIDGE_SUBNET=172.28.0.0/16 - -# Set and specify the IP addresses of some containers. Generally speaking, -# you do not need to modify these configurations to facilitate debugging -DOCKER_BRIDGE_GATEWAY=172.28.0.1 -MONGO_NETWORK_ADDRESS=172.28.0.2 -REDIS_NETWORK_ADDRESS=172.28.0.3 -KAFKA_NETWORK_ADDRESS=172.28.0.4 -ZOOKEEPER_NETWORK_ADDRESS=172.28.0.5 -MINIO_NETWORK_ADDRESS=172.28.0.6 -OPENIM_WEB_NETWORK_ADDRESS=172.28.0.7 -OPENIM_SERVER_NETWORK_ADDRESS=172.28.0.8 -OPENIM_CHAT_NETWORK_ADDRESS=172.28.0.9 -PROMETHEUS_NETWORK_ADDRESS=172.28.0.10 -GRAFANA_NETWORK_ADDRESS=172.28.0.11 -NODE_EXPORTER_NETWORK_ADDRESS=172.28.0.12 -OPENIM_ADMIN_FRONT_NETWORK_ADDRESS=172.28.0.13 -ALERT_MANAGER_NETWORK_ADDRESS=172.28.0.14 - -# ============================================================================== -# Configuration Update Instructions -# ============================================================================== -# This header outlines the methods to update common variables in config.yaml and .env files. -# These instructions are vital for maintaining the OpenIM environment's configuration. -# -# METHOD 1: Regenerate All Configurations -# ---------------------------------------- -# Use this method to regenerate all configurations. -# Steps: -# 1. Delete existing config files: -# - openim-server/config/config.yaml -# - openim-chat/config/config.yaml -# 2. Modify the .env file as required. -# 3. Run 'docker compose up -d'. This will regenerate: -# - config/config.yaml -# -# METHOD 2: Modify Individual Configuration Files -# ----------------------------------------------- -# Use this method to update specific configuration files. -# Steps: -# 1. Modify the .env file as necessary. -# 2. Update the corresponding entries in: -# - config/config.yaml -# 3. Restart the services with 'docker compose up -d'. -# 4. Special Note: If you modify OPENIM_IP, API_OPENIM_PORT, or MINIO_PORT in .env, -# ensure to update the corresponding services and configurations accordingly. -# -# It is essential to follow these methods to ensure consistent and correct application behavior. -# ============================================================================== -# Local IP address of the service. Modify if necessary. -# Example: OPENIM_IP=172.28.0.1, -OPENIM_IP=127.0.0.1 - -# ----- ZooKeeper Configuration ----- -# Port for ZooKeeper service. -# Default: ZOOKEEPER_PORT=12181 -ZOOKEEPER_PORT=12181 - -# MongoDB service port configuration. -# Default: MONGO_PORT=37017 -MONGO_PORT=37017 - -# Password for MongoDB admin user. Used for service authentication. -# Default: MONGO_PASSWORD=openIM123 -MONGO_PASSWORD=openIM123 - -# Username for a regular OpenIM user in MongoDB. -# Default: MONGO_OPENIM_USERNAME=openIM -MONGO_OPENIM_USERNAME=openIM - -# Password for a regular OpenIM user in MongoDB. -# Default: MONGO_OPENIM_PASSWORD=openIM123456 -MONGO_OPENIM_PASSWORD=openIM123 - -# Specifies the database name to be used within MongoDB. -# Default: MONGO_DATABASE=openim_v3 -MONGO_DATABASE=openim_v3 - -MONGO_MAX_POOL_SIZE=100 -# ----- Redis Configuration ----- - -# Port on which Redis in-memory data structure store is running. -# Default: REDIS_PORT=16379 -REDIS_PORT=16379 - -# Password to authenticate with the Redis service. -# Default: REDIS_PASSWORD=openIM123 -REDIS_PASSWORD=openIM123 - -# Kakfa username to authenticate with the Kafka service. -# KAFKA_USERNAME='' - -# Port on which Kafka distributed streaming platform is running. -# Default: KAFKA_PORT=19092 -KAFKA_PORT=19094 - -# Topic in Kafka for storing the latest messages in Redis. -# Default: KAFKA_LATESTMSG_REDIS_TOPIC=latestMsgToRedis -KAFKA_LATESTMSG_REDIS_TOPIC=latestMsgToRedis - -# MINIO_PORT -# ---------- -# MINIO_PORT sets the port for the MinIO object storage service. -# Upon changing this port, the MinIO endpoint URLs in the config/config.yaml file must be updated -# to reflect this change. The endpoints include both the 'endpoint' and 'signEndpoint' -# under the MinIO configuration. -# -# Default: MINIO_PORT=10005 -MINIO_PORT=10005 - -# Access key to authenticate with the MinIO service. -# Default: MINIO_ACCESS_KEY=root -# MINIO_ACCESS_KEY=root - -# Secret key corresponding to the access key for MinIO authentication. -# Default: MINIO_SECRET_KEY=openIM123 -MINIO_SECRET_KEY=openIM123 - -# ----- Prometheus Configuration ----- -# Port on which Prometheus service is running. -# Default: PROMETHEUS_PORT=19090 -PROMETHEUS_PORT=19090 - -# ----- Grafana Configuration ----- -# Port on which Grafana service is running. -# Default: GRAFANA_PORT=13000 -GRAFANA_PORT=13000 - -# ====================================== -# ============ OpenIM Web =============== -# ====================================== - -# Port on which OpenIM web service is running. -# Default: OPENIM_WEB_PORT=11001 -OPENIM_WEB_PORT=11001 - -# ====================================== -# ========= OpenIM Server ============== -# ====================================== -# Port for the OpenIM WebSockets. -# Default: OPENIM_WS_PORT=10001 -OPENIM_WS_PORT=10001 - -# API_OPENIM_PORT -# --------------- -# This variable defines the port on which the OpenIM API service will listen. -# When changing this port, it's essential to update the apiURL in the config.yaml file -# to ensure the API service is accessible at the new port. -# -# Default: API_OPENIM_PORT=10002 -API_OPENIM_PORT=10002 - -# ====================================== -# ========== OpenIM Chat =============== -# ====================================== - -# Branch name for OpenIM chat. -# Default: CHAT_IMAGE_VERSION=main -CHAT_IMAGE_VERSION=main - -# Port for the OpenIM chat API. -# Default: OPENIM_CHAT_API_PORT=10008 -OPENIM_CHAT_API_PORT=10008 - -# Port for the OpenIM admin API. -# Default: OPENIM_ADMIN_API_PORT=10009 -OPENIM_ADMIN_API_PORT=10009 - -# ====================================== -# ========== OpenIM Admin ============== -# ====================================== - -# Branch name for OpenIM server. -# Default: SERVER_IMAGE_VERSION=main -SERVER_IMAGE_VERSION=main - -# Port for the node exporter. -# Default: NODE_EXPORTER_PORT=19100 -NODE_EXPORTER_PORT=19100 - -# Port for the prometheus. -# Default: PROMETHEUS_PORT=19090 -PROMETHEUS_PORT=19090 - -# Port for the grafana. -# Default: GRAFANA_PORT=13000 -GRAFANA_PORT=13000 - -# Port for the admin front. -# Default: OPENIM_ADMIN_FRONT_PORT=11002 -OPENIM_ADMIN_FRONT_PORT=11002 - -# Port for the alertmanager. -# Default: ALERT_MANAGER_PORT=19093 -ALERT_MANAGER_PORT=19093 diff --git a/config/templates/instance-down-rules.yml.template b/config/templates/instance-down-rules.yml.template deleted file mode 100644 index 7a6e9fda9f..0000000000 --- a/config/templates/instance-down-rules.yml.template +++ /dev/null @@ -1,36 +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. - -groups: - - name: instance_down - rules: - - alert: InstanceDown - expr: up == 0 - for: 1m - labels: - severity: critical - annotations: - summary: "Instance {{ $labels.instance }} down" - description: "{{ $labels.instance }} of job {{ $labels.job }} has been down for more than 1 minutes." - - - name: database_insert_failure_alerts - rules: - - alert: DatabaseInsertFailed - expr: (increase(msg_insert_redis_failed_total[5m]) > 0) or (increase(msg_insert_mongo_failed_total[5m]) > 0) - for: 1m - labels: - severity: critical - annotations: - summary: "Increase in MsgInsertRedisFailedCounter or MsgInsertMongoFailedCounter detected" - description: "Either MsgInsertRedisFailedCounter or MsgInsertMongoFailedCounter has increased in the last 5 minutes, indicating failures in message insert operations to Redis or MongoDB,maybe the redis or mongodb is crash." diff --git a/config/templates/notification.yaml.template b/config/templates/notification.yaml.template deleted file mode 100644 index 665c212611..0000000000 --- a/config/templates/notification.yaml.template +++ /dev/null @@ -1,354 +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. - -# Determines if a message should be sent. If set to false, it triggers a silent sync without a message. If true, it requires triggering a conversation. -# For rpc notification, send twice: once as a message and once as a notification. -# The options field 'isNotification' indicates if it's a notification. -groupCreated: - isSendMsg: true - -# Reliability level of the message sending. -# Set to 1 to send only when online, 2 for guaranteed delivery. - reliabilityLevel: 1 - -# This setting is effective only when 'isSendMsg' is true. -# It controls whether to count unread messages. - unreadCount: false - -# Configuration for offline push notifications. - offlinePush: - # Enables or disables offline push notifications. - enable: false - - # Title for the notification when a group is created. - title: "create group title" - - # Description for the notification. - desc: "create group desc" - - # Additional information for the notification. - ext: "create group ext" - -# Content type is not added here. -# Content should use a JSON structure conforming to the protobuf format. - -groupInfoSet: - isSendMsg: false - reliabilityLevel: 1 - unreadCount: false - offlinePush: - enable: false - title: "groupInfoSet title" - desc: "groupInfoSet desc" - ext: "groupInfoSet ext" - - -joinGroupApplication: - isSendMsg: false - reliabilityLevel: 1 - unreadCount: false - offlinePush: - enable: false - title: "joinGroupApplication title" - desc: "joinGroupApplication desc" - ext: "joinGroupApplication ext" - -memberQuit: - isSendMsg: true - reliabilityLevel: 1 - unreadCount: false - offlinePush: - enable: false - title: "memberQuit title" - desc: "memberQuit desc" - ext: "memberQuit ext" - -groupApplicationAccepted: - isSendMsg: false - reliabilityLevel: 1 - unreadCount: false - offlinePush: - enable: false - title: "groupApplicationAccepted title" - desc: "groupApplicationAccepted desc" - ext: "groupApplicationAccepted ext" - -groupApplicationRejected: - isSendMsg: false - reliabilityLevel: 1 - unreadCount: false - offlinePush: - enable: false - title: " title" - desc: " desc" - ext: " ext" - - -groupOwnerTransferred: - isSendMsg: true - reliabilityLevel: 1 - unreadCount: false - offlinePush: - enable: false - title: "groupOwnerTransferred title" - desc: "groupOwnerTransferred desc" - ext: "groupOwnerTransferred ext" - -memberKicked: - isSendMsg: true - reliabilityLevel: 1 - unreadCount: false - offlinePush: - enable: false - title: "memberKicked title" - desc: "memberKicked desc" - ext: "memberKicked ext" - -memberInvited: - isSendMsg: true - reliabilityLevel: 1 - unreadCount: false - offlinePush: - enable: false - title: "memberInvited title" - desc: "memberInvited desc" - ext: "memberInvited ext" - -memberEnter: - isSendMsg: true - reliabilityLevel: 1 - unreadCount: false - offlinePush: - enable: false - title: "memberEnter title" - desc: "memberEnter desc" - ext: "memberEnter ext" - -groupDismissed: - isSendMsg: true - reliabilityLevel: 1 - unreadCount: false - offlinePush: - enable: false - title: "groupDismissed title" - desc: "groupDismissed desc" - ext: "groupDismissed ext" - -groupMuted: - isSendMsg: true - reliabilityLevel: 1 - unreadCount: false - offlinePush: - enable: false - title: "groupMuted title" - desc: "groupMuted desc" - ext: "groupMuted ext" - -groupCancelMuted: - isSendMsg: true - reliabilityLevel: 1 - unreadCount: false - offlinePush: - enable: false - title: "groupCancelMuted title" - desc: "groupCancelMuted desc" - ext: "groupCancelMuted ext" - defaultTips: - tips: "group Cancel Muted" - - -groupMemberMuted: - isSendMsg: true - reliabilityLevel: 1 - unreadCount: false - offlinePush: - enable: false - title: "groupMemberMuted title" - desc: "groupMemberMuted desc" - ext: "groupMemberMuted ext" - -groupMemberCancelMuted: - isSendMsg: true - reliabilityLevel: 1 - unreadCount: false - offlinePush: - enable: false - title: "groupMemberCancelMuted title" - desc: "groupMemberCancelMuted desc" - ext: "groupMemberCancelMuted ext" - -groupMemberInfoSet: - isSendMsg: false - reliabilityLevel: 1 - unreadCount: false - offlinePush: - enable: false - title: "groupMemberInfoSet title" - desc: "groupMemberInfoSet desc" - ext: "groupMemberInfoSet ext" - -groupInfoSetAnnouncement: - isSendMsg: true - reliabilityLevel: 1 - unreadCount: false - offlinePush: - enable: false - title: "groupInfoSetAnnouncement title" - desc: "groupInfoSetAnnouncement desc" - ext: "groupInfoSetAnnouncement ext" - - -groupInfoSetName: - isSendMsg: true - reliabilityLevel: 1 - unreadCount: false - offlinePush: - enable: false - title: "groupInfoSetName title" - desc: "groupInfoSetName desc" - ext: "groupInfoSetName ext" - - -#############################friend################################# -friendApplicationAdded: - isSendMsg: false - reliabilityLevel: 1 - unreadCount: false - offlinePush: - enable: false - title: "Somebody applies to add you as a friend" - desc: "Somebody applies to add you as a friend" - ext: "Somebody applies to add you as a friend" - -friendApplicationApproved: - isSendMsg: true - reliabilityLevel: 1 - unreadCount: false - offlinePush: - enable: true - title: "Someone applies to add your friend application" - desc: "Someone applies to add your friend application" - ext: "Someone applies to add your friend application" - -friendApplicationRejected: - isSendMsg: false - reliabilityLevel: 1 - unreadCount: false - offlinePush: - enable: true - title: "Someone rejected your friend application" - desc: "Someone rejected your friend application" - ext: "Someone rejected your friend application" - -friendAdded: - isSendMsg: false - reliabilityLevel: 1 - unreadCount: false - offlinePush: - enable: true - title: "We have become friends" - desc: "We have become friends" - ext: "We have become friends" - -friendDeleted: - isSendMsg: false - reliabilityLevel: 1 - unreadCount: false - offlinePush: - enable: true - title: "deleted a friend" - desc: "deleted a friend" - ext: "deleted a friend" - -friendRemarkSet: - isSendMsg: false - reliabilityLevel: 1 - unreadCount: false - offlinePush: - enable: true - title: "Your friend's profile has been changed" - desc: "Your friend's profile has been changed" - ext: "Your friend's profile has been changed" - -blackAdded: - isSendMsg: false - reliabilityLevel: 1 - unreadCount: false - offlinePush: - enable: true - title: "blocked a user" - desc: "blocked a user" - ext: "blocked a user" - -blackDeleted: - isSendMsg: false - reliabilityLevel: 1 - unreadCount: false - offlinePush: - enable: true - title: "Remove a blocked user" - desc: "Remove a blocked user" - ext: "Remove a blocked user" - -friendInfoUpdated: - isSendMsg: false - reliabilityLevel: 1 - unreadCount: false - offlinePush: - enable: true - title: "friend info updated" - desc: "friend info updated" - ext: "friend info updated" - -#####################user######################### -userInfoUpdated: - isSendMsg: false - reliabilityLevel: 1 - unreadCount: false - offlinePush: - enable: true - title: "Remove a blocked user" - desc: "Remove a blocked user" - ext: "Remove a blocked user" - -userStatusChanged: - isSendMsg: false - reliabilityLevel: 1 - unreadCount: false - offlinePush: - enable: false - title: "user status changed" - desc: "user status changed" - ext: "user status changed" - -#####################conversation######################### -conversationChanged: - isSendMsg: false - reliabilityLevel: 1 - unreadCount: false - offlinePush: - enable: true - title: "conversation changed" - desc: "conversation changed" - ext: "conversation changed" - -conversationSetPrivate: - isSendMsg: true - reliabilityLevel: 1 - unreadCount: false - offlinePush: - enable: true - title: "burn after reading" - desc: "burn after reading" - ext: "burn after reading" diff --git a/config/templates/open-im-ng-example.conf b/config/templates/open-im-ng-example.conf deleted file mode 100644 index 2598347773..0000000000 --- a/config/templates/open-im-ng-example.conf +++ /dev/null @@ -1,173 +0,0 @@ -upstream im_msg_gateway{ - server 127.0.0.1:10001; #IM Message server address Multiple can be specified according to the deployment - } -upstream im_api{ - server 127.0.0.1:10002; #IM Group user api server address Multiple can be specified according to the deployment - } -upstream im_grafana{ - server 127.0.0.1:10007; #IM Statistical server address The machine where docker-compose starts - } -upstream im_chat_api{ - server 127.0.0.1:10008; #IM Business version login registration server address Multiple can be specified according to the deployment - } -upstream im_admin_api{ - server 127.0.0.1:10009; #IM The admin address of the commercial version can specify multiple units according to the deployment situation - } -upstream im_open_rtc{ - server 127.0.0.1:7880; #rtc Audio and video call server address Multiple devices can be specified according to the deployment - } -upstream minio_s3_2 { - least_conn; - server 127.0.0.1:10005; -} - -upstream minio_console_2 { - least_conn; - server 127.0.0.1:9090; -} -server { - listen 443; - server_name your-domain.com; #your-domain.com - - ssl on; - ssl_certificate /etc/nginx/conf.d/ssl/your-domain.com.crt; #2 Certificate - ssl_certificate_key /etc/nginx/conf.d/ssl/your-domain.com.key; #3 Certificate - ssl_session_timeout 5m; - gzip on; - gzip_min_length 1k; - gzip_buffers 4 16k; - gzip_comp_level 2; - gzip_types text/plain application/javascript application/x-javascript text/css application/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png application/wasm; - gzip_vary off; - gzip_disable "MSIE [1-6]\."; - error_page 405 =200 $uri; - - default_type application/wasm; - location /{ #web demo - proxy_set_header Host $host; - proxy_set_header X-Real-Ip $remote_addr; - proxy_set_header X-Forwarded-For $remote_addr; - proxy_set_header X-NginX-Proxy true; - root /data1/online/Pc-Web-Demo/build/; # web im static resource storage path - index index.html; - try_files $uri $uri/ /index.html; - } - location /msg_gateway { #10001 ws - proxy_http_version 1.1; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection "Upgrade"; - proxy_set_header X-real-ip $remote_addr; - proxy_set_header X-Forwarded-For $remote_addr; - proxy_pass http://im_msg_gateway/; - } - location ^~/api/ { #10002 api - proxy_http_version 1.1; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection "Upgrade"; - proxy_set_header X-real-ip $remote_addr; - proxy_set_header X-Forwarded-For $remote_addr; - proxy_set_header X-Request-Api $scheme://$host/api; - proxy_pass http://im_api/; - } - location ^~/grafana/ { #10007 prometheus - proxy_http_version 1.1; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection "Upgrade"; - proxy_set_header X-real-ip $remote_addr; - proxy_set_header X-Forwarded-For $remote_addr; - proxy_pass http://im_grafana/; - } - location ^~/chat/ { #10008 im_chat_api - proxy_http_version 1.1; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection "Upgrade"; - proxy_set_header X-real-ip $remote_addr; - proxy_set_header X-Forwarded-For $remote_addr; - proxy_pass http://im_chat_api/; - } - location ^~/complete_admin/ { #10009 admin - proxy_http_version 1.1; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection "Upgrade"; - proxy_set_header X-real-ip $remote_addr; - proxy_set_header X-Forwarded-For $remote_addr; - proxy_pass http://im_admin_api/; - } - location ^~/open_rtc/ { #7880 rtc - proxy_http_version 1.1; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection "Upgrade"; - proxy_set_header X-real-ip $remote_addr; - proxy_set_header X-Forwarded-For $remote_addr; - proxy_pass http://im_open_rtc/; - } -} - -server { - listen 80; - server_name test-web.rentsoft.cn ; #1 web im end domain name - rewrite ^(.*)$ https://${server_name}$1 permanent; -} - - -server { - listen 443; - - server_name your-domain.com; #your-domain.com - ssl on; - ssl_certificate /etc/nginx/conf.d/ssl/your-domain.com.crt; #Certificate - ssl_certificate_key /etc/nginx/conf.d/ssl/your-domain.com.key; #Certificate - gzip on; - gzip_min_length 1k; - gzip_buffers 4 16k; - gzip_comp_level 2; - gzip_types text/plain application/javascript application/x-javascript text/css application/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png application/wasm; - gzip_vary off; - gzip_disable "MSIE [1-6]\."; - # Allow special characters in headers - ignore_invalid_headers off; - # Allow any size file to be uploaded. - # Set to a value such as 1000m; to restrict file size to a specific value - client_max_body_size 0; - # Disable buffering - proxy_buffering off; - proxy_request_buffering off; - - location / { - proxy_set_header Host $http_host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-Proto $scheme; - - proxy_connect_timeout 300; - # Default is HTTP/1, keepalive is only enabled in HTTP/1.1 - proxy_http_version 1.1; - proxy_set_header Connection ""; - chunked_transfer_encoding off; - - proxy_pass http://minio_s3_2; # This uses the upstream directive definition to load balance - } - - location /minio/ui { - rewrite ^/minio/ui/(.*) /$1 break; - proxy_set_header Host $http_host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-Proto $scheme; - proxy_set_header X-NginX-Proxy true; - - # This is necessary to pass the correct IP to be hashed - real_ip_header X-Real-IP; - - proxy_connect_timeout 300; - - # To support websockets in MinIO versions released after January 2023 - proxy_http_version 1.1; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection "upgrade"; - - chunked_transfer_encoding off; - - proxy_pass http://minio_console_2; # This uses the upstream directive definition to load balance - } -} \ No newline at end of file diff --git a/config/templates/prometheus-dashboard.yaml b/config/templates/prometheus-dashboard.yaml deleted file mode 100644 index 1dccbd6921..0000000000 --- a/config/templates/prometheus-dashboard.yaml +++ /dev/null @@ -1,1474 +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. - -{ - "annotations": { - "list": [ - { - "builtIn": 1, - "datasource": { - "type": "grafana", - "uid": "-- Grafana --" - }, - "enable": true, - "hide": true, - "iconColor": "rgba(0, 211, 255, 1)", - "name": "Annotations & Alerts", - "target": { - "limit": 100, - "matchAny": false, - "tags": [], - "type": "dashboard" - }, - "type": "dashboard" - } - ] - }, - "editable": true, - "fiscalYearStartMonth": 0, - "graphTooltip": 1, - "id": 3, - "iteration": 1699530082761, - "links": [], - "liveNow": false, - "panels": [ - { - "collapsed": false, - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 0 - }, - "id": 16, - "panels": [], - "title": "openim Custom Metrics", - "type": "row" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${datasource}" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 10, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 2, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "never", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 0, - "y": 1 - }, - "id": 12, - "options": { - "legend": { - "calcs": [], - "displayMode": "table", - "placement": "right", - "showLegend": true - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${datasource}" - }, - "editorMode": "code", - "expr": "sum(online_user_num{job=~\"^($job)$\"})", - "instant": false, - "legendFormat": "online_user_num", - "range": true, - "refId": "A" - } - ], - "title": "Online population", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${datasource}" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 10, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 2, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "never", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 12, - "y": 1 - }, - "id": 15, - "options": { - "legend": { - "calcs": [], - "displayMode": "table", - "placement": "right", - "showLegend": true - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${datasource}" - }, - "editorMode": "code", - "expr": "sum(user_login_total{job=~\"^($job)$\"})", - "instant": false, - "legendFormat": "user_login_total", - "range": true, - "refId": "A" - } - ], - "title": "Login/registration numbers", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${datasource}" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 10, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 2, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "never", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 0, - "y": 9 - }, - "id": 13, - "options": { - "legend": { - "calcs": [], - "displayMode": "table", - "placement": "bottom", - "showLegend": true - }, - "tooltip": { - "mode": "multi", - "sort": "none" - } - }, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${datasource}" - }, - "editorMode": "code", - "expr": "sum(rate(single_chat_msg_process_failed_total{job=~\"^($job)$\"}[$interval])) by (job)", - "instant": false, - "legendFormat": "{{job}}-single_chat_msg_process_failed", - "range": true, - "refId": "A" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${datasource}" - }, - "editorMode": "code", - "expr": "sum(rate(group_chat_msg_process_failed_total{job=~\"^($job)$\"}[$interval])) by (job)", - "hide": false, - "instant": false, - "legendFormat": "{{job}}-group_chat_msg_process_failed", - "range": true, - "refId": "B" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${datasource}" - }, - "editorMode": "code", - "expr": "sum(rate(msg_offline_push_failed_total{job=~\"^($job)$\"}[$interval])) by (job)", - "hide": false, - "instant": false, - "legendFormat": "{{job}}-msg_offline_push_failed", - "range": true, - "refId": "C" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${datasource}" - }, - "editorMode": "code", - "expr": "sum(rate(msg_insert_redis_failed_total{job=~\"^($job)$\"}[$interval])) by (job)", - "hide": false, - "instant": false, - "legendFormat": "{{job}}-msg_insert_redis_failed", - "range": true, - "refId": "D" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${datasource}" - }, - "editorMode": "code", - "expr": "sum(rate(msg_insert_mongo_failed_total{job=~\"^($job)$\"}[$interval])) by (job)", - "hide": false, - "instant": false, - "legendFormat": "{{job}}-msg_insert_mongo_failed", - "range": true, - "refId": "E" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${datasource}" - }, - "editorMode": "code", - "expr": "sum(rate(seq_set_failed_total{job=~\"^($job)$\"}[$interval])) by (job)", - "hide": false, - "instant": false, - "legendFormat": "{{job}}-seq_set_failed", - "range": true, - "refId": "F" - } - ], - "title": "failues/s", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${datasource}" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 10, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 2, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "never", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 12, - "y": 9 - }, - "id": 14, - "options": { - "legend": { - "calcs": [], - "displayMode": "table", - "placement": "bottom", - "showLegend": true - }, - "tooltip": { - "mode": "multi", - "sort": "none" - } - }, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${datasource}" - }, - "editorMode": "code", - "expr": "sum(rate(single_chat_msg_process_success_total{job=~\"^($job)$\"}[$interval])) by (job)", - "instant": false, - "legendFormat": "{{job}}-single_chat_msg_process_success", - "range": true, - "refId": "A" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${datasource}" - }, - "editorMode": "code", - "expr": "sum(rate(group_chat_msg_process_success_total{job=~\"^($job)$\"}[$interval])) by (job)", - "hide": false, - "instant": false, - "legendFormat": "{{job}}-group_chat_msg_process_success", - "range": true, - "refId": "B" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${datasource}" - }, - "editorMode": "code", - "expr": "sum(rate(msg_insert_redis_success_total{job=~\"^($job)$\"}[$interval])) by (job)", - "hide": false, - "instant": false, - "legendFormat": "{{job}}-msg_insert_redis_success", - "range": true, - "refId": "C" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${datasource}" - }, - "editorMode": "code", - "expr": "sum(rate(msg_insert_mongo_success_total{job=~\"^($job)$\"}[$interval])) by (job)", - "hide": false, - "instant": false, - "legendFormat": "{{job}}-msg_insert_mongo_success", - "range": true, - "refId": "D" - } - ], - "title": "messages/s", - "type": "timeseries" - }, - { - "collapsed": false, - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 17 - }, - "id": 11, - "panels": [], - "title": "Go Stats", - "type": "row" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${datasource}" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 10, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineStyle": { - "fill": "solid" - }, - "lineWidth": 2, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "never", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 0, - "y": 18 - }, - "id": 10, - "options": { - "legend": { - "calcs": [], - "displayMode": "table", - "placement": "bottom", - "showLegend": true - }, - "tooltip": { - "mode": "multi", - "sort": "none" - } - }, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${datasource}" - }, - "editorMode": "code", - "expr": "avg(go_goroutines{job=~\"^($job)$\"}) by (job)", - "instant": false, - "legendFormat": "{{job}}", - "range": true, - "refId": "A" - } - ], - "title": "Goroutines", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${datasource}" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 10, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineStyle": { - "fill": "solid" - }, - "lineWidth": 2, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "never", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 12, - "y": 18 - }, - "id": 7, - "options": { - "legend": { - "calcs": [ - "mean", - "lastNotNull", - "max" - ], - "displayMode": "table", - "placement": "bottom", - "showLegend": true - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${datasource}" - }, - "editorMode": "code", - "exemplar": false, - "expr": "go_gc_duration_seconds{job=~\"^($job)$\",quantile=\"1\"}", - "instant": false, - "legendFormat": "{{pod}}: {{quantile}}", - "range": true, - "refId": "A" - } - ], - "title": "GC duration quantiles", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${datasource}" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 10, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 2, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "never", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "bytes" - }, - "overrides": [] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 0, - "y": 26 - }, - "id": 9, - "options": { - "legend": { - "calcs": [], - "displayMode": "table", - "placement": "bottom", - "showLegend": true - }, - "tooltip": { - "mode": "multi", - "sort": "none" - } - }, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${datasource}" - }, - "editorMode": "code", - "expr": "avg(go_memstats_alloc_bytes{job=~\"^($job)$\"}) by (job)", - "instant": false, - "legendFormat": "{{job}}", - "range": true, - "refId": "A" - } - ], - "title": "process memory", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${datasource}" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 10, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 2, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "never", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 12, - "y": 26 - }, - "id": 8, - "options": { - "legend": { - "calcs": [ - "mean", - "lastNotNull", - "max" - ], - "displayMode": "table", - "placement": "bottom", - "showLegend": true - }, - "tooltip": { - "mode": "multi", - "sort": "none" - } - }, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${datasource}" - }, - "editorMode": "code", - "expr": "sum(process_open_fds{job=~\"^($job)$\"})by (job)", - "instant": false, - "legendFormat": "{{job}}", - "range": true, - "refId": "A" - } - ], - "title": "open fds", - "type": "timeseries" - }, - { - "collapsed": true, - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 34 - }, - "id": 6, - "panels": [ - { - "datasource": { - "type": "prometheus", - "uid": "${datasource}" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 10, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "never", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 0, - "y": 3 - }, - "id": 2, - "options": { - "legend": { - "calcs": [], - "displayMode": "table", - "placement": "right", - "showLegend": true - }, - "tooltip": { - "mode": "multi", - "sort": "none" - } - }, - "pluginVersion": "10.1.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${datasource}" - }, - "disableTextWrap": false, - "editorMode": "code", - "exemplar": false, - "expr": "sum(up{job=~\"^($job)$\"})by(job)", - "fullMetaSearch": false, - "includeNullMetadata": true, - "instant": false, - "legendFormat": "{{job}}-up", - "range": true, - "refId": "A", - "useBackend": false - } - ], - "title": "Up", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${datasource}" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "never", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "none" - }, - "overrides": [] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 12, - "y": 3 - }, - "id": 3, - "options": { - "legend": { - "calcs": [], - "displayMode": "table", - "placement": "right", - "showLegend": true - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "10.1.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${datasource}" - }, - "editorMode": "code", - "exemplar": true, - "expr": "sum(rate(app_requests_total{job=~\"^($job)$\", code!~\"200\"}[$interval])) by (job)", - "instant": false, - "legendFormat": "{{job}}", - "range": true, - "refId": "A" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${datasource}" - }, - "editorMode": "code", - "expr": "sum(rate(grpc_server_handled_total{job=~\"^($job)$\",grpc_code!~\"OK\"}[$interval])) by (job)", - "hide": false, - "instant": false, - "legendFormat": "__auto", - "range": true, - "refId": "B" - } - ], - "title": "failures/s", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${datasource}" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 10, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "never", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "req/s" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 12, - "x": 0, - "y": 11 - }, - "id": 4, - "options": { - "legend": { - "calcs": [], - "displayMode": "table", - "placement": "right", - "showLegend": true - }, - "tooltip": { - "mode": "multi", - "sort": "none" - } - }, - "pluginVersion": "10.1.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${datasource}" - }, - "editorMode": "code", - "expr": "sum(rate(app_requests_total{job=~\"^($job)$\"}[$interval])) by (job)", - "instant": false, - "legendFormat": "{{job}}-webhook", - "range": true, - "refId": "A" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${datasource}" - }, - "editorMode": "code", - "expr": "sum(rate(grpc_server_started_total{job=~\"^($job)$\"}[$interval])) by (job)", - "hide": false, - "instant": false, - "legendFormat": "{{job}}-grpc", - "range": true, - "refId": "B" - } - ], - "title": "qps", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${datasource}" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 10, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineStyle": { - "fill": "solid" - }, - "lineWidth": 2, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "never", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "s" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 12, - "x": 12, - "y": 11 - }, - "id": 5, - "maxDataPoints": 100, - "options": { - "legend": { - "calcs": [], - "displayMode": "table", - "placement": "right", - "showLegend": true - }, - "tooltip": { - "mode": "multi", - "sort": "none" - } - }, - "pluginVersion": "10.1.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${datasource}" - }, - "editorMode": "code", - "exemplar": false, - "expr": "histogram_quantile(0.95, \r\n sum(rate(app_request_duration_seconds_bucket{job=~\"^($job)$\"}[$interval])) \r\n by (le, job)\r\n)", - "instant": false, - "legendFormat": "{{job}}", - "range": true, - "refId": "A" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${datasource}" - }, - "editorMode": "code", - "expr": "histogram_quantile(0.95, \r\n sum(rate(grpc_server_handling_seconds_bucket{job=~\"^($job)$\"}[$interval])) \r\n by (le, job)\r\n)", - "hide": false, - "instant": false, - "legendFormat": "{{job}}", - "range": true, - "refId": "B" - } - ], - "title": "Latency", - "type": "timeseries" - } - ], - "title": "Traffic indicators of the application server", - "type": "row" - } - ], - "refresh": "", - "schemaVersion": 34, - "style": "dark", - "tags": [], - "templating": { - "list": [ - { - "current": { - "selected": false, - "text": "Prometheus", - "value": "Prometheus" - }, - "hide": 0, - "includeAll": false, - "label": "Data Source", - "multi": false, - "name": "datasource", - "options": [], - "query": "prometheus", - "queryValue": "", - "refresh": 1, - "regex": "", - "skipUrlSync": false, - "type": "datasource" - }, - { - "current": { - "selected": true, - "text": [ - "All" - ], - "value": [ - "$__all" - ] - }, - "datasource": { - "type": "prometheus", - "uid": "${datasource}" - }, - "definition": "label_values(go_memstats_alloc_bytes,job) ", - "hide": 0, - "includeAll": true, - "label": "job", - "multi": true, - "name": "job", - "options": [], - "query": { - "query": "label_values(go_memstats_alloc_bytes,job) ", - "refId": "StandardVariableQuery" - }, - "refresh": 2, - "regex": "", - "skipUrlSync": false, - "sort": 0, - "type": "query" - }, - { - "auto": false, - "auto_count": 30, - "auto_min": "10s", - "current": { - "selected": false, - "text": "1m", - "value": "1m" - }, - "hide": 0, - "name": "interval", - "options": [ - { - "selected": true, - "text": "1m", - "value": "1m" - }, - { - "selected": false, - "text": "10m", - "value": "10m" - }, - { - "selected": false, - "text": "30m", - "value": "30m" - }, - { - "selected": false, - "text": "1h", - "value": "1h" - }, - { - "selected": false, - "text": "6h", - "value": "6h" - }, - { - "selected": false, - "text": "12h", - "value": "12h" - }, - { - "selected": false, - "text": "1d", - "value": "1d" - } - ], - "query": "1m,10m,30m,1h,6h,12h,1d", - "queryValue": "", - "refresh": 2, - "skipUrlSync": false, - "type": "interval" - } - ] - }, - "time": { - "from": "now-24h", - "to": "now" - }, - "timepicker": {}, - "timezone": "", - "title": "docker-openim-custom1", - "uid": "f5f5de9a-6ec5-499a-841e-6e901c33b1f7", - "version": 16, - "weekStart": "" -} diff --git a/config/templates/prometheus.yml.template b/config/templates/prometheus.yml.template deleted file mode 100644 index 709fe9754a..0000000000 --- a/config/templates/prometheus.yml.template +++ /dev/null @@ -1,99 +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. - -# my global config -global: - scrape_interval: 15s # Set the scrape interval to every 15 seconds. Default is every 1 minute. - evaluation_interval: 15s # Evaluate rules every 15 seconds. The default is every 1 minute. - # scrape_timeout is set to the global default (10s). - -# Alertmanager configuration -alerting: - alertmanagers: - - static_configs: - - targets: ['172.28.0.1:19093'] - -# Load rules once and periodically evaluate them according to the global 'evaluation_interval'. -rule_files: - - "instance-down-rules.yml" -# - "first_rules.yml" -# - "second_rules.yml" - -# A scrape configuration containing exactly one endpoint to scrape: -# Here it's Prometheus itself. -scrape_configs: - # The job name is added as a label "job='job_name'"" to any timeseries scraped from this config. - # Monitored information captured by prometheus - - job_name: 'node-exporter' - static_configs: - - targets: [ '172.28.0.1:19100' ] - labels: - namespace: 'default' - - # prometheus fetches application services - - job_name: 'openimserver-openim-api' - static_configs: - - targets: [ '172.28.0.1:20100' ] - labels: - namespace: 'default' - - job_name: 'openimserver-openim-msggateway' - static_configs: - - targets: [ '172.28.0.1:20140' ] - labels: - namespace: 'default' - - job_name: 'openimserver-openim-msgtransfer' - static_configs: - - targets: [ 172.28.0.1:21400, 172.28.0.1:21401, 172.28.0.1:21402, 172.28.0.1:21403 ] - labels: - namespace: 'default' - - job_name: 'openimserver-openim-push' - static_configs: - - targets: [ '172.28.0.1:20170' ] - labels: - namespace: 'default' - - job_name: 'openimserver-openim-rpc-auth' - static_configs: - - targets: [ '172.28.0.1:20160' ] - labels: - namespace: 'default' - - job_name: 'openimserver-openim-rpc-conversation' - static_configs: - - targets: [ '172.28.0.1:20230' ] - labels: - namespace: 'default' - - job_name: 'openimserver-openim-rpc-friend' - static_configs: - - targets: [ '172.28.0.1:20120' ] - labels: - namespace: 'default' - - job_name: 'openimserver-openim-rpc-group' - static_configs: - - targets: [ '172.28.0.1:20150' ] - labels: - namespace: 'default' - - job_name: 'openimserver-openim-rpc-msg' - static_configs: - - targets: [ '172.28.0.1:20130' ] - labels: - namespace: 'default' - - job_name: 'openimserver-openim-rpc-third' - static_configs: - - targets: [ '172.28.0.1:21301' ] - labels: - namespace: 'default' - - job_name: 'openimserver-openim-rpc-user' - static_configs: - - targets: [ '172.28.0.1:20110' ] - labels: - namespace: 'default' diff --git a/scripts/.spelling_failures b/scripts/.spelling_failures deleted file mode 100644 index 347246f2e0..0000000000 --- a/scripts/.spelling_failures +++ /dev/null @@ -1,31 +0,0 @@ -CHANGELOG -go.mod -go.sum -third_party/ -translations/ -logs -.git -.golangci.yml -docs/readme/README_uk.md -docs/readme/README_cs.md -docs/readme/README_hu.md -docs/readme/README_es.md -docs/readme/README_fa.md -docs/readme/README_fr.md -docs/readme/README_de.md -docs/readme/README_pl.md -docs/readme/README_id.md -docs/readme/README_fi.md -docs/readme/README_ml.md -docs/readme/README_ja.md -docs/readme/README_nl.md -docs/readme/README_it.md -docs/readme/README_ru.md -docs/readme/README_pt_BR -docs/readme/README_eo.md -docs/readme/README_ko.md -docs/readme/README_ar.md -docs/readme/README_vi.md -docs/readme/README_da.md -docs/readme/README_el.md -docs/readme/README_tr.md diff --git a/scripts/README.md b/scripts/README.md deleted file mode 100644 index b55049a7b5..0000000000 --- a/scripts/README.md +++ /dev/null @@ -1,311 +0,0 @@ -# OpenIM Scripts Directory Structure - -- [OpenIM Scripts Directory Structure](#openim-scripts-directory-structure) - - [log directory](#log-directory) - - [Supported platforms](#supported-platforms) - - [Get started quickly - demo.sh](#get-started-quickly---demosh) - - [Guide: Using and Understanding OpenIM Utility Functions](#guide-using-and-understanding-openim-utility-functions) - - [Table of Contents](#table-of-contents) - - [1. Checking the Status of Services by Ports](#1-checking-the-status-of-services-by-ports) - - [Function: `openim::util::check_ports`](#function-openimutilcheck_ports) - - [Example:](#example) - - [2. Checking the Status of Services by Process Names](#2-checking-the-status-of-services-by-process-names) - - [Function: `openim::util::check_process_names`](#function-openimutilcheck_process_names) - - [Example:](#example-1) - - [3. Stopping Services by Ports](#3-stopping-services-by-ports) - - [Function: `openim::util::stop_services_on_ports`](#function-openimutilstop_services_on_ports) - - [Example:](#example-2) - - [4. Stopping Services by Process Names](#4-stopping-services-by-process-names) - - [Function: `openim::util::stop_services_with_name`](#function-openimutilstop_services_with_name) - - [Example:](#example-3) - - [system management and installation of openim via Linux system](#system-management-and-installation-of-openim-via-linux-system) - - [examples](#examples) - - -This document outlines the directory structure for scripts in the OpenIM Server project. These scripts play a critical role in various areas like building, deploying, running and managing the services of OpenIM. - -```bash -scripts/ -├── README.md # Documentation for the scripts directory. -├── advertise.sh # Script to advertise or broadcast services. -├── batch_start_all.sh # Batch script to start all services. -├── build-all-service.sh # Script to build all services. -├── build.cmd # Command script for building (usually for Windows). -├── check-all.sh # Check script for all components or services. -├── cherry-pick.sh # Helper script for git cherry-pick operations. -├── common.sh # Common utilities and shared functions. -├── coverage.awk # AWK script for processing code coverage data. -├── coverage.sh # Script to gather and report code coverage. -├── demo.sh # Demonstration or example script. -├── docker-check-service.sh # Docker script to check services' status. -├── docker-start-all.sh # Docker script to start all containers/services. -├── ensure-tag.sh # Ensure correct tags or labeling. -├── env_check.sh # Environment verification and checking. -├── gen-swagger-docs.sh # Script to generate Swagger documentation. -├── genconfig.sh # Generate configuration files. -├── gendoc.sh # General documentation generation script. -├── githooks # Directory containing git hooks. -│ ├── commit-msg # Git hook for commit messages. -│ ├── pre-commit # Pre-commit git hook. -│ └── pre-push # Pre-push git hook. -├── golangci.yml # Configuration for GolangCI linting. -├── init-config.sh # Initialize configurations. -├── init-env.sh # Initialize the environment. -├── init-pwd.sh # Initialize or set password. -├── install # Installation scripts directory. -│ ├── README.md # Installation documentation. -│ ├── common.sh # Common utilities for installation. -│ ├── dependency.sh # Script to install dependencies. -│ ├── environment.sh # Set up the environment during installation. -│ ├── install-protobuf.sh # Install Protocol Buffers. -│ ├── install.sh # Main installation script. -│ ├── openim-api.sh # Install OpenIM API. -│ ├── openim-crontask.sh # Install OpenIM crontask. -│ ├── openim-man.sh # Install OpenIM management tool. -│ ├── openim-msggateway.sh # Install OpenIM message gateway. -│ ├── openim-msgtransfer.sh # Install OpenIM message transfer. -│ ├── openim-push.sh # Install OpenIM push service. -│ ├── openim-rpc.sh # Install OpenIM RPC. -│ ├── openim-tools.sh # Install OpenIM tools. -│ ├── test.sh # Installation testing script. -│ └── vimrc # Vim configuration file. -├── install-im-server.sh # Script to install the OpenIM server. -├── install_im_compose.sh # Install OpenIM using Docker Compose. -├── lib # Library or utility scripts directory. -│ ├── chat.sh # Utilities related to chat. -│ ├── color.sh # Color-related utilities. -│ ├── golang.sh # Golang utilities. -│ ├── init.sh # Initialization utilities. -│ ├── logging.sh # Logging utilities. -│ ├── release.sh # Release related utilities. -│ ├── util.sh # General utility functions. -│ └── version.sh # Version management utilities. -├── list-feature-tests.sh # Script to list feature tests. -├── make-rules # Makefile rule templates. -│ ├── common.mk # Common make rules. -│ ├── copyright.mk # Copyright related make rules. -│ ├── dependencies.mk # Dependency management rules. -│ ├── gen.mk # Generic or general rules. -│ ├── golang.mk # Golang-specific make rules. -│ ├── image.mk # Image or container-related rules. -│ ├── release.mk # Release specific rules. -│ ├── swagger.mk # Swagger documentation rules. -│ └── tools.mk # Tooling-related make rules. -├── mongo-init.sh # MongoDB initialization script. -├── release.sh # Script for releasing or deployment. -├── run-in-gopath.sh # Script to run commands within GOPATH. -├── start-all.sh # Script to start all services. -├── start.bat # Batch file to start services (usually for Windows). -├── stop-all.sh # Script to stop all services. -├── template # Directory containing template files. -│ ├── LICENSE # License template. -│ ├── LICENSE_TEMPLATES # Collection of license templates. -│ ├── boilerplate.txt # Boilerplate template. -│ ├── footer.md.tmpl # Footer template for markdown. -│ ├── head.md.tmpl # Header template for markdown. -│ └── project_README.md # Project README template. -├── update-generated-docs.sh # Update generated documentation. -├── update-yamlfmt.sh # Update YAML formatting. -├── verify-pkg-names.sh # Verify package names. -├── verify-shellcheck.sh # Shell script linting verification. -├── verify-spelling.sh # Spelling verification script. -├── verify-typecheck.sh # Type checking verification. -├── verify-yamlfmt.sh # Verify YAML format. -└── wait-for-it.sh # Script to wait for a condition or service to be ready. -``` - -The purpose of having a structured scripts directory like this is to make the operations of OpenIM Server clear and easy to manage. Each script has its own responsibility, making it easier to maintain and update. It's also helpful for newcomers who can easily understand what each part of the system is doing by just looking at this directory structure. - -Each directory and script in the structure should be understood as a part of a larger whole. All scripts work together to ensure the smooth operation and maintenance of the OpenIM Server. - - -## log directory - -**PATH:** `scripts/lib/logging.sh` - -+ [log details](../docs/contrib/bash-log.md) - -## Supported platforms - -- Linux x86_64 (linux_amd64) : 64-bit Linux for most desktop and server systems. - -- Windows x86_64 (windows_amd64) : 64-bit version for most Windows operating systems. - -- macOS x86_64 (darwin_amd64) : 64-bit version for Apple Macintosh computers. - -- Linux ARM64 (linux_arm64) : For ARM-based 64-bit Linux systems such as Raspberry Pi 4 and Jetson Nano. - -- Linux s390x (linux_s390x) : 64-bit Linux for IBM System z hosts. - -- Linux MIPS64 (linux_mips64) : 64-bit Linux for MIPS architecture. - -- Linux MIPS64LE (linux_mips64le) : Suitable for 64-bit Linux systems with little endian MIPS architecture. - -## Get started quickly - demo.sh - -Is the `demo.sh` script teaching you how to quickly get started with OpenIM development and use - - -Steps to run demo: - -```sh -$ make demo -``` - -More about `make` read: - -+ [makefile](../docs/contrib/go-code.md) - -Instructions for producing the demo movie: - -```bash -# Create temporary directory -mkdir /tmp/kb-demo -cd /tmp/kb-demo - -asciinema rec -/scripts/demo/run.sh - - to terminate the script - to terminate the asciinema recording - to save the recording locally - -# Edit the recorded file by editing the controller-gen path -# Once you are happy with the recording, use svg-term program to generate the svg - -svg-term --cast= --out _output/demo.svg --window -``` - -Here you will learn how to test a script, We take the four functions for starting and checking a service as an example. - -## Guide: Using and Understanding OpenIM Utility Functions - -This document provides an overview of the four utility functions designed for managing processes and services. These functions can check the status of services based on ports and process names, as well as stop services based on the same criteria. - -### Table of Contents -- [1. Checking the Status of Services by Ports](#checking-the-status-of-services-by-ports) -- [2. Checking the Status of Services by Process Names](#checking-the-status-of-services-by-process-names) -- [3. Stopping Services by Ports](#stopping-services-by-ports) -- [4. Stopping Services by Process Names](#stopping-services-by-process-names) - -### 1. Checking the Status of Services by Ports - -#### Function: `openim::util::check_ports` - -This function checks the status of services running on specified ports. - -**Usage**: - -```bash -$ openim::util::check_ports ... -``` - -**Design**: - -- The function iterates through each provided port. -- It uses the `lsof` command to identify if there is a service running on the specified port. -- If a service is running, it logs the command, PID, and start time of the service. -- If a service is not running, it logs that the port is not started. -- If any service is not running, the function returns a status of 1. - -#### Example: - -```bash -$ openim::util::check_ports 8080 8081 8082 -``` - -### 2. Checking the Status of Services by Process Names - -#### Function: `openim::util::check_process_names` - -This function checks the status of services based on their process names. - -**Usage**: - -```bash -$ openim::util::check_process_names ... -``` - -**Design**: - -- The function uses `pgrep` to find process IDs associated with the given process names. -- If processes are found, it logs the command, PID, associated port, and start time. -- If no processes are found for a name, it logs that the process is not started. -- If any process is not running, the function returns a status of 1. - -#### Example: - -```bash -$ openim::util::check_process_names nginx mysql redis -``` - -### 3. Stopping Services by Ports - -#### Function: `openim::util::stop_services_on_ports` - -This function attempts to stop services running on the specified ports. - -**Usage**: - -```bash -$ openim::util::stop_services_on_ports ... -``` - -**Design**: - -- The function uses the `lsof` command to identify services running on the specified ports. -- If a service is running on a port, it tries to terminate the associated process using the `kill` command. -- It logs successful terminations and any failures. -- If any service couldn't be stopped, the function returns a status of 1. - -#### Example: - -```bash -$ openim::util::stop_services_on_ports 8080 8081 8082 -``` - -### 4. Stopping Services by Process Names - -#### Function: `openim::util::stop_services_with_name` - -This function attempts to stop services based on their process names. - -**Usage**: - -```bash -$ openim::util::stop_services_with_name ... -``` - -**Design**: - -- The function uses `pgrep` to identify processes associated with the specified names. -- If processes are found, it tries to terminate them using the `kill` command. -- It logs successful terminations and any failures. -- If any service couldn't be stopped, the function returns a status of 1. - -#### Example: - -```bash -$ openim::util::stop_services_with_name nginx apache -``` - -### system management and installation of openim via Linux system - -```bash -$ ./scripts/install/install.sh -``` - -## examples -Scripts to perform various build, install, analysis, etc operations. - -The script directory design of OpenIM and the writing of scripts and tools refer to many excellent open source projects, such as helm, iam, kubernetes, docker, etc. - -Maybe they'll give you inspiration for later maintenance... - -These scripts keep the root level Makefile small and simple. - -Examples: - -* https://github.com/kubernetes/helm/tree/master/scripts -* https://github.com/cockroachdb/cockroach/tree/master/scripts -* https://github.com/hashicorp/terraform/tree/master/scripts \ No newline at end of file diff --git a/scripts/advertise.sh b/scripts/advertise.sh deleted file mode 100755 index 958b4e3ae6..0000000000 --- a/scripts/advertise.sh +++ /dev/null @@ -1,112 +0,0 @@ -#!/usr/bin/env bash -# 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. - -set -e - - -. $(dirname ${BASH_SOURCE})/lib/init.sh - -trap 'openim::util::onCtrlC' INT - -print_with_delay() { - text="$1" - delay="$2" - - for i in $(seq 0 $((${#text}-1))); do - printf "${text:$i:1}" - sleep $delay - done - printf "\n" -} - -print_progress() { - total="$1" - delay="$2" - - printf "[" - for i in $(seq 1 $total); do - printf "#" - sleep $delay - done - printf "]\n" -} - -function openim_logo() { - # Set text color to cyan for header and URL - echo -e "\033[0;36m" - - # Display fancy ASCII Art logo - # look http://patorjk.com/software/taag/#p=display&h=1&v=1&f=Doh&t=OpenIM - print_with_delay ' - - - OOOOOOOOO IIIIIIIIIIMMMMMMMM MMMMMMMM - OO:::::::::OO I::::::::IM:::::::M M:::::::M - OO:::::::::::::OO I::::::::IM::::::::M M::::::::M -O:::::::OOO:::::::O II::::::IIM:::::::::M M:::::::::M -O::::::O O::::::Oppppp ppppppppp eeeeeeeeeeee nnnn nnnnnnnn I::::I M::::::::::M M::::::::::M -O:::::O O:::::Op::::ppp:::::::::p ee::::::::::::ee n:::nn::::::::nn I::::I M:::::::::::M M:::::::::::M -O:::::O O:::::Op:::::::::::::::::p e::::::eeeee:::::een::::::::::::::nn I::::I M:::::::M::::M M::::M:::::::M -O:::::O O:::::Opp::::::ppppp::::::pe::::::e e:::::enn:::::::::::::::n I::::I M::::::M M::::M M::::M M::::::M -O:::::O O:::::O p:::::p p:::::pe:::::::eeeee::::::e n:::::nnnn:::::n I::::I M::::::M M::::M::::M M::::::M -O:::::O O:::::O p:::::p p:::::pe:::::::::::::::::e n::::n n::::n I::::I M::::::M M:::::::M M::::::M -O:::::O O:::::O p:::::p p:::::pe::::::eeeeeeeeeee n::::n n::::n I::::I M::::::M M:::::M M::::::M -O::::::O O::::::O p:::::p p::::::pe:::::::e n::::n n::::n I::::I M::::::M MMMMM M::::::M -O:::::::OOO:::::::O p:::::ppppp:::::::pe::::::::e n::::n n::::nII::::::IIM::::::M M::::::M - OO:::::::::::::OO p::::::::::::::::p e::::::::eeeeeeee n::::n n::::nI::::::::IM::::::M M::::::M - OO:::::::::OO p::::::::::::::pp ee:::::::::::::e n::::n n::::nI::::::::IM::::::M M::::::M - OOOOOOOOO p::::::pppppppp eeeeeeeeeeeeee nnnnnn nnnnnnIIIIIIIIIIMMMMMMMM MMMMMMMM - p:::::p - p:::::p - p:::::::p - p:::::::p - p:::::::p - ppppppppp - - ' 0.0001 - - # Display product URL - print_with_delay "Discover more and contribute at: https://github.com/openimsdk/open-im-server" 0.01 - - # Reset text color back to normal - echo -e "\033[0m" - - # Set text color to green for product description - echo -e "\033[1;32m" - - print_with_delay "Open-IM-Server: Reinventing Instant Messaging" 0.01 - print_progress 50 0.02 - - print_with_delay "Open-IM-Server is not just a product; it's a revolution. It's about bringing the power of seamless," 0.01 - print_with_delay "real-time messaging to your fingertips. And it's about joining a global community of developers, dedicated to pushing the boundaries of what's possible." 0.01 - - print_progress 50 0.02 - - # Reset text color back to normal - echo -e "\033[0m" - - # Set text color to yellow for the Slack link - echo -e "\033[1;33m" - - print_with_delay "Join our developer community on Slack: https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q" 0.01 - - # Reset text color back to normal - echo -e "\033[0m" -} - -function main() { - openim_logo -} -main "$@" diff --git a/scripts/bash_beautify.py b/scripts/bash_beautify.py deleted file mode 100755 index 54c6fa0add..0000000000 --- a/scripts/bash_beautify.py +++ /dev/null @@ -1,173 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -#************************************************************************** -# Copyright (C) 2011, Paul Lutus * -# * -# This program is free software; you can redistribute it and/or modify * -# it under the terms of the GNU General Public License as published by * -# the Free Software Foundation; either version 2 of the License, or * -# (at your option) any later version. * -# * -# This program is distributed in the hope that it will be useful, * -# but WITHOUT ANY WARRANTY; without even the implied warranty of * -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * -# GNU General Public License for more details. * -# * -# You should have received a copy of the GNU General Public License * -# along with this program; if not, write to the * -# Free Software Foundation, Inc., * -# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * -#************************************************************************** - -import re -import sys - -PVERSION = '1.0' - - -class BeautifyBash: - - def __init__(self): - self.tab_str = ' ' - self.tab_size = 2 - - def read_file(self, fp): - with open(fp) as f: - return f.read() - - def write_file(self, fp, data): - with open(fp, 'w') as f: - f.write(data) - - def beautify_string(self, data, path=''): - tab = 0 - case_stack = [] - in_here_doc = False - defer_ext_quote = False - in_ext_quote = False - ext_quote_string = '' - here_string = '' - output = [] - line = 1 - for record in re.split('\n', data): - record = record.rstrip() - stripped_record = record.strip() - - # collapse multiple quotes between ' ... ' - test_record = re.sub(r'\'.*?\'', '', stripped_record) - # collapse multiple quotes between " ... " - test_record = re.sub(r'".*?"', '', test_record) - # collapse multiple quotes between ` ... ` - test_record = re.sub(r'`.*?`', '', test_record) - # collapse multiple quotes between \` ... ' (weird case) - test_record = re.sub(r'\\`.*?\'', '', test_record) - # strip out any escaped single characters - test_record = re.sub(r'\\.', '', test_record) - # remove '#' comments - test_record = re.sub(r'(\A|\s)(#.*)', '', test_record, 1) - if(not in_here_doc): - if(re.search('<<-?', test_record)): - here_string = re.sub( - '.*<<-?\s*[\'|"]?([_|\w]+)[\'|"]?.*', '\\1', stripped_record, 1) - in_here_doc = (len(here_string) > 0) - if(in_here_doc): # pass on with no changes - output.append(record) - # now test for here-doc termination string - if(re.search(here_string, test_record) and not re.search('<<', test_record)): - in_here_doc = False - else: # not in here doc - if(in_ext_quote): - if(re.search(ext_quote_string, test_record)): - # provide line after quotes - test_record = re.sub( - '.*%s(.*)' % ext_quote_string, '\\1', test_record, 1) - in_ext_quote = False - else: # not in ext quote - if(re.search(r'(\A|\s)(\'|")', test_record)): - # apply only after this line has been processed - defer_ext_quote = True - ext_quote_string = re.sub( - '.*([\'"]).*', '\\1', test_record, 1) - # provide line before quote - test_record = re.sub( - '(.*)%s.*' % ext_quote_string, '\\1', test_record, 1) - if(in_ext_quote): - # pass on unchanged - output.append(record) - else: # not in ext quote - inc = len(re.findall( - '(\s|\A|;)(case|then|do)(;|\Z|\s)', test_record)) - inc += len(re.findall('(\{|\(|\[)', test_record)) - outc = len(re.findall( - '(\s|\A|;)(esac|fi|done|elif)(;|\)|\||\Z|\s)', test_record)) - outc += len(re.findall('(\}|\)|\])', test_record)) - if(re.search(r'\besac\b', test_record)): - if(len(case_stack) == 0): - sys.stderr.write( - 'File %s: error: "esac" before "case" in line %d.\n' % ( - path, line) - ) - else: - outc += case_stack.pop() - # sepcial handling for bad syntax within case ... esac - if(len(case_stack) > 0): - if(re.search('\A[^(]*\)', test_record)): - # avoid overcount - outc -= 2 - case_stack[-1] += 1 - if(re.search(';;', test_record)): - outc += 1 - case_stack[-1] -= 1 - # an ad-hoc solution for the "else" keyword - else_case = ( - 0, -1)[re.search('^(else)', test_record) != None] - net = inc - outc - tab += min(net, 0) - extab = tab + else_case - extab = max(0, extab) - output.append( - (self.tab_str * self.tab_size * extab) + stripped_record) - tab += max(net, 0) - if(defer_ext_quote): - in_ext_quote = True - defer_ext_quote = False - if(re.search(r'\bcase\b', test_record)): - case_stack.append(0) - line += 1 - error = (tab != 0) - if(error): - sys.stderr.write( - 'File %s: error: indent/outdent mismatch: %d.\n' % (path, tab)) - return '\n'.join(output), error - - def beautify_file(self, path): - error = False - if(path == '-'): - data = sys.stdin.read() - result, error = self.beautify_string(data, '(stdin)') - sys.stdout.write(result) - else: # named file - data = self.read_file(path) - result, error = self.beautify_string(data, path) - if(data != result): - # make a backup copy - self.write_file(path + '~', data) - self.write_file(path, result) - return error - - def main(self): - error = False - sys.argv.pop(0) - if(len(sys.argv) < 1): - sys.stderr.write( - 'usage: shell script filenames or \"-\" for stdin.\n') - else: - for path in sys.argv: - error |= self.beautify_file(path) - sys.exit((0, 1)[error]) - -# if not called as a module -if(__name__ == '__main__'): - BeautifyBash().main() - diff --git a/scripts/build-all-service.sh b/scripts/build-all-service.sh deleted file mode 100755 index eea380b4fd..0000000000 --- a/scripts/build-all-service.sh +++ /dev/null @@ -1,72 +0,0 @@ -#!/usr/bin/env bash -# 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. -# -# This script runs `make build` command. -# The command compiles all Makefile configs. -# Args: -# WHAT: Directory names to build. If any of these directories has a 'main' -# package, the build will produce executable files under $(OUT_DIR)/bin/platforms OR $(OUT_DIR)/bin—tools/platforms. -# If not specified, "everything" will be built. -# Usage: `scripts/build-all-service.sh`. -# Example: `scripts/build-go.sh WHAT=cmd/kubelet`. - - -OPENIM_ROOT=$(dirname "${BASH_SOURCE[0]}")/.. -source "${OPENIM_ROOT}/scripts/lib/init.sh" - -# CPU core number -pushd "${OPENIM_ROOT}/tools/ncpu" >/dev/null -cpu_count=$(go run .) -popd >/dev/null - -openim::color::echo ${GREEN_PREFIX} "======> cpu_count=$cpu_count" - -openim::log::info "Building OpenIM, Parallel compilation compile=$cpu_count" -compile_count=$((cpu_count / 2)) - -# For help output -ARGHELP="" -if [[ "$#" -gt 0 ]]; then - ARGHELP="'$*'" -fi - -openim::color::echo $COLOR_CYAN "NOTE: $0 has been replaced by 'make multiarch' or 'make build'" -echo -echo "The equivalent of this invocation is: " -echo " make build ${ARGHELP}" -echo " ./scripts/build-all-service.sh ${ARGHELP}" -echo -echo " Example: " -echo " Print a single binary:" -echo " make build BINS=openim-api" -echo " ./scripts/build-all-service.sh BINS=openim-api" -echo " Print : Enable debugging and logging" -echo " make build BINS=openim-api V=1 DEBUG=1" -echo " ./scripts/build-all-service.sh BINS=openim-api V=1 DEBUG=1" -echo - -if [ -z "$*" ]; then - openim::log::info "no args, build all service" - make --no-print-directory -C "${OPENIM_ROOT}" -j$compile_count build -else - openim::log::info "build service: $*" - make --no-print-directory -C "${OPENIM_ROOT}" -j$compile_count build "$*" -fi - -if [ $? -eq 0 ]; then - openim::log::success "all service build success, run 'make start' or './scripts/start-all.sh'" -else - openim::log::error "make build Error, script exits" -fi diff --git a/scripts/check-all.sh b/scripts/check-all.sh deleted file mode 100755 index 54296b22d5..0000000000 --- a/scripts/check-all.sh +++ /dev/null @@ -1,113 +0,0 @@ -#!/usr/bin/env bash -# 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. - -# This script is check openim service is running normally -# -# Usage: `scripts/check-all.sh`. -# Encapsulated as: `make check`. -# READ: https://github.com/openimsdk/open-im-server/tree/main/scripts/install/environment.sh - - -OPENIM_ROOT=$(dirname "${BASH_SOURCE[0]}")/.. -source "${OPENIM_ROOT}/scripts/install/common.sh" - -if openim::util::is_running_in_container; then - exec >> ${DOCKER_LOG_FILE} 2>&1 -fi - - -OPENIM_VERBOSE=4 - -openim::log::info "\n# Begin to check all OpenIM service" - -openim::log::status "Check all dependent service ports" -# Elegant printing function -# Elegant printing function -print_services_and_ports() { - local service_names=("$@") - local half_length=$((${#service_names[@]} / 2)) - local service_ports=("${service_names[@]:half_length}") - - echo "+-------------------------+----------+" - echo "| Service Name | Port |" - echo "+-------------------------+----------+" - - for ((index=0; index < half_length; index++)); do - printf "| %-23s | %-8s |\n" "${service_names[$index]}" "${service_ports[$index]}" - done - - echo "+-------------------------+----------+" -} - - -# Assuming OPENIM_SERVER_NAME_TARGETS and OPENIM_SERVER_PORT_TARGETS are defined -# Similarly for OPENIM_DEPENDENCY_TARGETS and OPENIM_DEPENDENCY_PORT_TARGETS - -# Print out services and their ports -print_services_and_ports "${OPENIM_SERVER_NAME_TARGETS[@]}" "${OPENIM_SERVER_PORT_TARGETS[@]}" - -# Print out dependencies and their ports -print_services_and_ports "${OPENIM_DEPENDENCY_TARGETS[@]}" "${OPENIM_DEPENDENCY_PORT_TARGETS[@]}" - -# OpenIM check -#echo "++ The port being checked: ${OPENIM_SERVER_PORT_LISTARIES[@]}" -openim::log::info "\n## Check all dependent components service ports" -#echo "++ The port being checked: ${OPENIM_DEPENDENCY_PORT_LISTARIES[@]}" - - -# Later, after discarding Docker, the Docker keyword is unreliable, and Kubepods is used -if grep -qE 'docker|kubepods' /proc/1/cgroup || [ -f /.dockerenv ]; then - openim::color::echo ${COLOR_CYAN} "Environment in the interior of the container" -else - openim::color::echo ${COLOR_CYAN}"The environment is outside the container" - openim::util::check_ports ${OPENIM_DEPENDENCY_PORT_LISTARIES[@]} -fi - -if [[ $? -ne 0 ]]; then - openim::log::error_exit "The service does not start properly, please check the port, query variable definition!" - echo "+++ https://github.com/openimsdk/open-im-server/tree/main/scripts/install/environment.sh +++" -else - openim::log::success "All components depended on by OpenIM are running normally! " -fi - - -openim::log::status "Check OpenIM service:" -openim::log::colorless "${OPENIM_OUTPUT_HOSTBIN}/openim-msgtransfer" -result=$(. $(dirname ${BASH_SOURCE})/install/openim-msgtransfer.sh openim::msgtransfer::check) -if [[ $? -ne 0 ]]; then - #echo "+++ cat openim log file >>> ${LOG_FILE}" - - openim::log::error "The service is not running properly, please check the logs $result" -fi - - -openim::log::status "Check OpenIM service:" -for item in "${OPENIM_ALL_SERVICE_LIBRARIES_NO_TRANSFER[@]}"; do - openim::log::colorless "$item" -done - - -result=$(openim::util::check_process_names ${OPENIM_ALL_SERVICE_LIBRARIES_NO_TRANSFER[@]}) -if [[ $? -ne 0 ]]; then - #echo "+++ cat OpenIM log file >>> ${LOG_FILE}" - openim::log::error "The service is not running properly, please check the logs " - echo "$result" - exit 1 -else - openim::log::status "List the ports listened to by the OpenIM service:" - openim::util::find_ports_for_all_services ${OPENIM_ALL_SERVICE_LIBRARIES_NO_TRANSFER[@]} - openim::util::find_ports_for_all_services ${OPENIM_MSGTRANSFER_BINARY[@]} - openim::log::success "All OpenIM services are running normally! " -fi diff --git a/scripts/cherry-pick.sh b/scripts/cherry-pick.sh deleted file mode 100755 index b95289cd4f..0000000000 --- a/scripts/cherry-pick.sh +++ /dev/null @@ -1,252 +0,0 @@ -#!/usr/bin/env bash -# 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. - - -# Usage Instructions: https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/gitcherry-pick.md - -# Checkout a PR from GitHub. (Yes, this is sitting in a Git tree. How -# meta.) Assumes you care about pulls from remote "upstream" and -# checks them out to a branch named: -# automated-cherry-pick-of--- - -OPENIM_ROOT=$(dirname "${BASH_SOURCE[0]}")/.. -source "${OPENIM_ROOT}/scripts/lib/init.sh" - -REPO_ROOT="$(git rev-parse --show-toplevel)" -declare -r REPO_ROOT -cd "${REPO_ROOT}" - -STARTINGBRANCH=$(git symbolic-ref --short HEAD) -declare -r STARTINGBRANCH -declare -r REBASEMAGIC="${REPO_ROOT}/.git/rebase-apply" -DRY_RUN=${DRY_RUN:-""} -REGENERATE_DOCS=${REGENERATE_DOCS:-""} -UPSTREAM_REMOTE=${UPSTREAM_REMOTE:-upstream} -FORK_REMOTE=${FORK_REMOTE:-origin} -MAIN_REPO_ORG=${MAIN_REPO_ORG:-$(git remote get-url "$UPSTREAM_REMOTE" | awk '{gsub(/webhook[s]:\/\/|git@/,"")}1' | awk -F'[@:./]' 'NR==1{print $3}')} -MAIN_REPO_NAME=${MAIN_REPO_NAME:-$(git remote get-url "$UPSTREAM_REMOTE" | awk '{gsub(/webhook[s]:\/\/|git@/,"")}1' | awk -F'[@:./]' 'NR==1{print $4}')} - -if [[ -z ${GITHUB_USER:-} ]]; then - openim::log::error_exit "Please export GITHUB_USER= (or GH organization, if that's where your fork lives)" -fi - -if ! command -v gh > /dev/null; then - openim::log::error_exit "Can't find 'gh' tool in PATH, please install from https://github.com/cli/cli" -fi - -if [[ "$#" -lt 2 ]]; then - echo "${0} ...: cherry pick one or more onto and leave instructions for proposing pull request" - echo - echo " Checks out and handles the cherry-pick of (possibly multiple) for you." - echo " Examples:" - echo " $0 upstream/release-v3.1 12345 # Cherry-picks PR 12345 onto upstream/release-v3.1 and proposes that as a PR." - echo " $0 upstream/release-v3.1 12345 56789 # Cherry-picks PR 12345, then 56789 and proposes the combination as a single PR." - echo - echo " Set the DRY_RUN environment var to skip git push and creating PR." - echo " This is useful for creating patches to a release branch without making a PR." - echo " When DRY_RUN is set the script will leave you in a branch containing the commits you cherry-picked." - echo - echo " Set the REGENERATE_DOCS environment var to regenerate documentation for the target branch after picking the specified commits." - echo " This is useful when picking commits containing changes to API documentation." - echo - echo " Set UPSTREAM_REMOTE (default: upstream) and FORK_REMOTE (default: origin)" - echo " to override the default remote names to what you have locally." - echo - echo " For merge process info, see https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/gitcherry-pick.md" - exit 2 -fi - -# Checks if you are logged in. Will error/bail if you are not. -gh auth status - -if git_status=$(git status --porcelain --untracked=no 2>/dev/null) && [[ -n "${git_status}" ]]; then - openim::log::error_exit "!!! Dirty tree. Clean up and try again." -fi - -if [[ -e "${REBASEMAGIC}" ]]; then - openim::log::error_exit "!!! 'git rebase' or 'git am' in progress. Clean up and try again." -fi - -declare -r BRANCH="$1" -shift 1 -declare -r PULLS=( "$@" ) - -function join { local IFS="$1"; shift; echo "$*"; } -PULLDASH=$(join - "${PULLS[@]/#/#}") # Generates something like "#12345-#56789" -declare -r PULLDASH -PULLSUBJ=$(join " " "${PULLS[@]/#/#}") # Generates something like "#12345 #56789" -declare -r PULLSUBJ - -openim::log::status "Updating remotes..." -git remote update "${UPSTREAM_REMOTE}" "${FORK_REMOTE}" - -if ! git log -n1 --format=%H "${BRANCH}" >/dev/null 2>&1; then - openim::log::error " '${BRANCH}' not found. The second argument should be something like ${UPSTREAM_REMOTE}/release-0.21." - openim::log::error " (In particular, it needs to be a valid, existing remote branch that I can 'git checkout'.)" - exit 1 -fi - -NEWBRANCHREQ="automated-cherry-pick-of-${PULLDASH}" # "Required" portion for tools. -declare -r NEWBRANCHREQ -NEWBRANCH="$(echo "${NEWBRANCHREQ}-${BRANCH}" | sed 's/\//-/g')" -declare -r NEWBRANCH -NEWBRANCHUNIQ="${NEWBRANCH}-$(date +%s)" -declare -r NEWBRANCHUNIQ -openim::log::info "+++ Creating local branch ${NEWBRANCHUNIQ}" - -cleanbranch="" -gitamcleanup=false -function return_to_kansas { - if [[ "${gitamcleanup}" == "true" ]]; then - echo - openim::log::status "Aborting in-progress git am." - git am --abort >/dev/null 2>&1 || true - fi - - # return to the starting branch and delete the PR text file - if [[ -z "${DRY_RUN}" ]]; then - echo - openim::log::status "Returning you to the ${STARTINGBRANCH} branch and cleaning up." - git checkout -f "${STARTINGBRANCH}" >/dev/null 2>&1 || true - if [[ -n "${cleanbranch}" ]]; then - git branch -D "${cleanbranch}" >/dev/null 2>&1 || true - fi - fi -} -trap return_to_kansas EXIT - -SUBJECTS=() -function make-a-pr() { - local rel - rel="$(basename "${BRANCH}")" - echo - openim::log::status "Creating a pull request on GitHub at ${GITHUB_USER}:${NEWBRANCH}" - - local numandtitle - numandtitle=$(printf '%s\n' "${SUBJECTS[@]}") - prtext=$(cat <&2 - exit 1 - fi - done - - if [[ "${conflicts}" != "true" ]]; then - echo "!!! git am failed, likely because of an in-progress 'git am' or 'git rebase'" - exit 1 - fi -} - -# set the subject -subject=$(grep -m 1 "^Subject" "/tmp/${pull}.patch" | sed -e 's/Subject: \[PATCH//g' | sed 's/.*] //') -SUBJECTS+=("#${pull}: ${subject}") - -# remove the patch file from /tmp -rm -f "/tmp/${pull}.patch" -done -gitamcleanup=false - -# Re-generate docs (if needed) -if [[ -n "${REGENERATE_DOCS}" ]]; then -echo -echo "Regenerating docs..." -if ! scripts/generate-docs.sh; then - echo - echo "scripts/gendoc.sh FAILED to complete." - exit 1 -fi -fi - -if [[ -n "${DRY_RUN}" ]]; then -openim::log::error "!!! Skipping git push and PR creation because you set DRY_RUN." -echo "To return to the branch you were in when you invoked this script:" -echo -echo " git checkout ${STARTINGBRANCH}" -echo -echo "To delete this branch:" -echo -echo " git branch -D ${NEWBRANCHUNIQ}" -exit 0 -fi - -if git remote -v | grep ^"${FORK_REMOTE}" | grep "${MAIN_REPO_ORG}/${MAIN_REPO_NAME}.git"; then -echo "!!! You have ${FORK_REMOTE} configured as your ${MAIN_REPO_ORG}/${MAIN_REPO_NAME}.git" -echo "This isn't normal. Leaving you with push instructions:" -echo -openim::log::status "First manually push the branch this script created:" -echo -echo " git push REMOTE ${NEWBRANCHUNIQ}:${NEWBRANCH}" -echo -echo "where REMOTE is your personal fork (maybe ${UPSTREAM_REMOTE}? Consider swapping those.)." -echo "OR consider setting UPSTREAM_REMOTE and FORK_REMOTE to different values." -echo -make-a-pr -cleanbranch="" -exit 0 -fi - -echo -openim::log::status "I'm about to do the following to push to GitHub (and I'm assuming ${FORK_REMOTE} is your personal fork):" -echo -echo " git push ${FORK_REMOTE} ${NEWBRANCHUNIQ}:${NEWBRANCH}" -echo -read -p "+++ Proceed (anything other than 'y' aborts the cherry-pick)? [y/n] " -r -if ! [[ "${REPLY}" =~ ^[yY]$ ]]; then -echo "Aborting." >&2 -exit 1 -fi - -git push "${FORK_REMOTE}" -f "${NEWBRANCHUNIQ}:${NEWBRANCH}" -make-a-pr \ No newline at end of file diff --git a/scripts/common.sh b/scripts/common.sh deleted file mode 100755 index f7155fca2a..0000000000 --- a/scripts/common.sh +++ /dev/null @@ -1,516 +0,0 @@ -#!/usr/bin/env bash - -# 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. - - -# shellcheck disable=SC2034 # Variables sourced in other scripts. - -# Common utilities, variables and checks for all build scripts. - -# Unset CDPATH, having it set messes up with script import paths -unset CDPATH - -USER_ID=$(id -u) -GROUP_ID=$(id -g) - -DOCKER_OPTS=${DOCKER_OPTS:-""} -IFS=" " read -r -a DOCKER <<< "docker ${DOCKER_OPTS}" -DOCKER_HOST=${DOCKER_HOST:-""} -DOCKER_MACHINE_NAME=${DOCKER_MACHINE_NAME:-"openim-dev"} -readonly DOCKER_MACHINE_DRIVER=${DOCKER_MACHINE_DRIVER:-"virtualbox --virtualbox-cpu-count -1"} - -# This will canonicalize the path -OPENIM_ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")"/.. && pwd -P) - -# Please do not refer to lib after referring to common -. $(dirname ${BASH_SOURCE})/lib/init.sh - -# Constants -readonly OPENIM_BUILD_IMAGE_REPO=openim-build -#readonly OPENIM_BUILD_IMAGE_CROSS_TAG="$(cat "${OPENIM_ROOT}/build/build-image/cross/VERSION")" - -readonly OPENIM_DOCKER_REGISTRY="${OPENIM_DOCKER_REGISTRY:-k8s.gcr.io}" -readonly OPENIM_BASE_IMAGE_REGISTRY="${OPENIM_BASE_IMAGE_REGISTRY:-us.gcr.io/k8s-artifacts-prod/build-image}" - -# This version number is used to cause everyone to rebuild their data containers -# and build image. This is especially useful for automated build systems like -# Jenkins. -# -# Increment/change this number if you change the build image (anything under -# build/build-image) or change the set of volumes in the data container. -#readonly OPENIM_BUILD_IMAGE_VERSION_BASE="$(cat "${OPENIM_ROOT}/build/build-image/VERSION")" -#readonly OPENIM_BUILD_IMAGE_VERSION="${OPENIM_BUILD_IMAGE_VERSION_BASE}-${OPENIM_BUILD_IMAGE_CROSS_TAG}" - -# Here we map the output directories across both the local and remote _output -# directories: -# -# *_OUTPUT_ROOT - the base of all output in that environment. -# *_OUTPUT_SUBPATH - location where golang stuff is built/cached. Also -# persisted across docker runs with a volume mount. -# *_OUTPUT_BINPATH - location where final binaries are placed. If the remote -# is really remote, this is the stuff that has to be copied -# back. -# OUT_DIR can come in from the Makefile, so honor it. -readonly LOCAL_OUTPUT_ROOT="${OPENIM_ROOT}/${OUT_DIR:-_output}" -readonly LOCAL_OUTPUT_SUBPATH="${LOCAL_OUTPUT_ROOT}/bin" -readonly LOCAL_OUTPUT_BINPATH="${LOCAL_OUTPUT_SUBPATH}/platforms" -readonly LOCAL_OUTPUT_BINTOOLSPATH="${LOCAL_OUTPUT_SUBPATH}/tools" -readonly LOCAL_OUTPUT_GOPATH="${LOCAL_OUTPUT_SUBPATH}/go" -readonly LOCAL_OUTPUT_IMAGE_STAGING="${LOCAL_OUTPUT_ROOT}/images" - -# This is the port on the workstation host to expose RSYNC on. Set this if you -# are doing something fancy with ssh tunneling. -readonly OPENIM_RSYNC_PORT="${OPENIM_RSYNC_PORT:-}" - -# This is the port that rsync is running on *inside* the container. This may be -# mapped to OPENIM_RSYNC_PORT via docker networking. -readonly OPENIM_CONTAINER_RSYNC_PORT=8730 - -# Get the set of master binaries that run in Docker (on Linux) -# Entry format is ",". -# Binaries are placed in /usr/local/bin inside the image. -# -# $1 - server architecture -openim::build::get_docker_wrapped_binaries() { -local arch=$1 -local debian_base_version=v2.1.0 -local debian_iptables_version=v12.1.0 -### If you change any of these lists, please also update DOCKERIZED_BINARIES -### in build/BUILD. And openim::golang::server_image_targets - -local targets=( - "openim-api,${OPENIM_BASE_IMAGE_REGISTRY}/debian-base-${arch}:${debian_base_version}" - "openim-cmdutils,${OPENIM_BASE_IMAGE_REGISTRY}/debian-base-${arch}:${debian_base_version}" - "openim-crontask,${OPENIM_BASE_IMAGE_REGISTRY}/debian-base-${arch}:${debian_base_version}" - "openim-msggateway,${OPENIM_BASE_IMAGE_REGISTRY}/debian-base-${arch}:${debian_base_version}" - "openim-msgtransfer,${OPENIM_BASE_IMAGE_REGISTRY}/debian-base-${arch}:${debian_base_version}" - "openim-push,${OPENIM_BASE_IMAGE_REGISTRY}/debian-base-${arch}:${debian_base_version}" - "openim-rpc-auth,${OPENIM_BASE_IMAGE_REGISTRY}/debian-base-${arch}:${debian_base_version}" - "openim-rpc-conversation,${OPENIM_BASE_IMAGE_REGISTRY}/debian-base-${arch}:${debian_base_version}" - "openim-rpc-friend,${OPENIM_BASE_IMAGE_REGISTRY}/debian-base-${arch}:${debian_base_version}" - "openim-rpc-group,${OPENIM_BASE_IMAGE_REGISTRY}/debian-base-${arch}:${debian_base_version}" - "openim-rpc-msg,${OPENIM_BASE_IMAGE_REGISTRY}/debian-base-${arch}:${debian_base_version}" - "openim-rpc-third,${OPENIM_BASE_IMAGE_REGISTRY}/debian-base-${arch}:${debian_base_version}" - "openim-rpc-user,${OPENIM_BASE_IMAGE_REGISTRY}/debian-base-${arch}:${debian_base_version}" -) -echo "${targets[@]}" -} - -# --------------------------------------------------------------------------- -# Basic setup functions - -# Verify that the right utilities and such are installed for building openim. Set -# up some dynamic constants. -# Args: -# $1 - boolean of whether to require functioning docker (default true) -# -# Vars set: -# OPENIM_ROOT_HASH -# OPENIM_BUILD_IMAGE_TAG_BASE -# OPENIM_BUILD_IMAGE_TAG -# OPENIM_BUILD_IMAGE -# OPENIM_BUILD_CONTAINER_NAME_BASE -# OPENIM_BUILD_CONTAINER_NAME -# OPENIM_DATA_CONTAINER_NAME_BASE -# OPENIM_DATA_CONTAINER_NAME -# OPENIM_RSYNC_CONTAINER_NAME_BASE -# OPENIM_RSYNC_CONTAINER_NAME -# DOCKER_MOUNT_ARGS -# LOCAL_OUTPUT_BUILD_CONTEXT -function openim::build::verify_prereqs() { -local -r require_docker=${1:-true} -openim::log::status "Verifying Prerequisites...." -openim::build::ensure_tar || return 1 -openim::build::ensure_rsync || return 1 -if ${require_docker}; then - openim::build::ensure_docker_in_path || return 1 - openim::util::ensure_docker_daemon_connectivity || return 1 - - if (( OPENIM_VERBOSE > 6 )); then - openim::log::status "Docker Version:" - "${DOCKER[@]}" version | openim::log::info_from_stdin - fi -fi - -OPENIM_GIT_BRANCH=$(git symbolic-ref --short -q HEAD 2>/dev/null || true) -OPENIM_ROOT_HASH=$(openim::build::short_hash "${HOSTNAME:-}:${OPENIM_ROOT}:${OPENIM_GIT_BRANCH}") -OPENIM_BUILD_IMAGE_TAG_BASE="build-${OPENIM_ROOT_HASH}" -#OPENIM_BUILD_IMAGE_TAG="${OPENIM_BUILD_IMAGE_TAG_BASE}-${OPENIM_BUILD_IMAGE_VERSION}" -#OPENIM_BUILD_IMAGE="${OPENIM_BUILD_IMAGE_REPO}:${OPENIM_BUILD_IMAGE_TAG}" -OPENIM_BUILD_CONTAINER_NAME_BASE="openim-build-${OPENIM_ROOT_HASH}" -#OPENIM_BUILD_CONTAINER_NAME="${OPENIM_BUILD_CONTAINER_NAME_BASE}-${OPENIM_BUILD_IMAGE_VERSION}" -OPENIM_RSYNC_CONTAINER_NAME_BASE="openim-rsync-${OPENIM_ROOT_HASH}" -#OPENIM_RSYNC_CONTAINER_NAME="${OPENIM_RSYNC_CONTAINER_NAME_BASE}-${OPENIM_BUILD_IMAGE_VERSION}" -OPENIM_DATA_CONTAINER_NAME_BASE="openim-build-data-${OPENIM_ROOT_HASH}" -#OPENIM_DATA_CONTAINER_NAME="${OPENIM_DATA_CONTAINER_NAME_BASE}-${OPENIM_BUILD_IMAGE_VERSION}" -#DOCKER_MOUNT_ARGS=(--volumes-from "${OPENIM_DATA_CONTAINER_NAME}") -#LOCAL_OUTPUT_BUILD_CONTEXT="${LOCAL_OUTPUT_IMAGE_STAGING}/${OPENIM_BUILD_IMAGE}" - -openim::version::get_version_vars -#openim::version::save_version_vars "${OPENIM_ROOT}/.dockerized-openim-version-defs" -} - -# --------------------------------------------------------------------------- -# Utility functions - -function openim::build::docker_available_on_osx() { -if [[ -z "${DOCKER_HOST}" ]]; then - if [[ -S "/var/run/docker.sock" ]]; then - openim::log::status "Using Docker for MacOS" - return 0 - fi - - openim::log::status "No docker host is set. Checking options for setting one..." - if [[ -z "$(which docker-machine)" ]]; then - openim::log::status "It looks like you're running Mac OS X, yet neither Docker for Mac nor docker-machine can be found." - openim::log::status "See: https://docs.docker.com/engine/installation/mac/ for installation instructions." - return 1 - elif [[ -n "$(which docker-machine)" ]]; then - openim::build::prepare_docker_machine - fi -fi -} - -function openim::build::prepare_docker_machine() { -openim::log::status "docker-machine was found." - -local available_memory_bytes -available_memory_bytes=$(sysctl -n hw.memsize 2>/dev/null) - -local bytes_in_mb=1048576 - -# Give virtualbox 1/2 the system memory. Its necessary to divide by 2, instead -# of multiple by .5, because bash can only multiply by ints. -local memory_divisor=2 - -local virtualbox_memory_mb=$(( available_memory_bytes / (bytes_in_mb * memory_divisor) )) - -docker-machine inspect "${DOCKER_MACHINE_NAME}" &> /dev/null || { - openim::log::status "Creating a machine to build OPENIM" - docker-machine create --driver "${DOCKER_MACHINE_DRIVER}" \ - --virtualbox-memory "${virtualbox_memory_mb}" \ - --engine-env HTTP_PROXY="${OPENIMRNETES_HTTP_PROXY:-}" \ - --engine-env HTTPS_PROXY="${OPENIMRNETES_HTTPS_PROXY:-}" \ - --engine-env NO_PROXY="${OPENIMRNETES_NO_PROXY:-127.0.0.1}" \ - "${DOCKER_MACHINE_NAME}" > /dev/null || { - openim::log::error "Something went wrong creating a machine." - openim::log::error "Try the following: " - openim::log::error "docker-machine create -d ${DOCKER_MACHINE_DRIVER} --virtualbox-memory ${virtualbox_memory_mb} ${DOCKER_MACHINE_NAME}" - return 1 - } -} -docker-machine start "${DOCKER_MACHINE_NAME}" &> /dev/null -# it takes `docker-machine env` a few seconds to work if the machine was just started -local docker_machine_out -while ! docker_machine_out=$(docker-machine env "${DOCKER_MACHINE_NAME}" 2>&1); do - if [[ ${docker_machine_out} =~ "Error checking TLS connection" ]]; then - echo "${docker_machine_out}" - docker-machine regenerate-certs "${DOCKER_MACHINE_NAME}" - else - sleep 1 - fi -done -eval "$(docker-machine env "${DOCKER_MACHINE_NAME}")" -openim::log::status "A Docker host using docker-machine named '${DOCKER_MACHINE_NAME}' is ready to go!" -return 0 -} - -function openim::build::is_gnu_sed() { -[[ $(sed --version 2>&1) == *GNU* ]] -} - -function openim::build::ensure_rsync() { -if [[ -z "$(which rsync)" ]]; then - openim::log::error "Can't find 'rsync' in PATH, please fix and retry." - return 1 -fi -} - -function openim::build::update_dockerfile() { -if openim::build::is_gnu_sed; then - sed_opts=(-i) -else - sed_opts=(-i '') -fi -sed "${sed_opts[@]}" "s/OPENIM_BUILD_IMAGE_CROSS_TAG/${OPENIM_BUILD_IMAGE_CROSS_TAG}/" "${LOCAL_OUTPUT_BUILD_CONTEXT}/Dockerfile" -} - -function openim::build::set_proxy() { -if [[ -n "${OPENIMRNETES_HTTPS_PROXY:-}" ]]; then - echo "ENV https_proxy $OPENIMRNETES_HTTPS_PROXY" >> "${LOCAL_OUTPUT_BUILD_CONTEXT}/Dockerfile" -fi -if [[ -n "${OPENIMRNETES_HTTP_PROXY:-}" ]]; then - echo "ENV http_proxy $OPENIMRNETES_HTTP_PROXY" >> "${LOCAL_OUTPUT_BUILD_CONTEXT}/Dockerfile" -fi -if [[ -n "${OPENIMRNETES_NO_PROXY:-}" ]]; then - echo "ENV no_proxy $OPENIMRNETES_NO_PROXY" >> "${LOCAL_OUTPUT_BUILD_CONTEXT}/Dockerfile" -fi -} - -function openim::build::ensure_docker_in_path() { -if [[ -z "$(which docker)" ]]; then - openim::log::error "Can't find 'docker' in PATH, please fix and retry." - openim::log::error "See https://docs.docker.com/installation/#installation for installation instructions." - return 1 -fi -} - -function openim::build::ensure_tar() { -if [[ -n "${TAR:-}" ]]; then - return -fi - -# Find gnu tar if it is available, bomb out if not. -TAR=tar -if which gtar &>/dev/null; then - TAR=gtar -else - if which gnutar &>/dev/null; then - TAR=gnutar - fi -fi -if ! "${TAR}" --version | grep -q GNU; then - echo " !!! Cannot find GNU tar. Build on Linux or install GNU tar" - echo " on Mac OS X (brew install gnu-tar)." - return 1 -fi -} - -function openim::build::has_docker() { -which docker &> /dev/null -} - -function openim::build::has_ip() { -which ip &> /dev/null && ip -Version | grep 'iproute2' &> /dev/null -} - -# Detect if a specific image exists -# -# $1 - image repo name -# $2 - image tag -function openim::build::docker_image_exists() { -[[ -n $1 && -n $2 ]] || { - openim::log::error "Internal error. Image not specified in docker_image_exists." - exit 2 -} - -[[ $("${DOCKER[@]}" images -q "${1}:${2}") ]] -} - -# Delete all images that match a tag prefix except for the "current" version -# -# $1: The image repo/name -# $2: The tag base. We consider any image that matches $2* -# $3: The current image not to delete if provided -function openim::build::docker_delete_old_images() { -# In Docker 1.12, we can replace this with -# docker images "$1" --format "{{.Tag}}" -for tag in $("${DOCKER[@]}" images "${1}" | tail -n +2 | awk '{print $2}') ; do - if [[ "${tag}" != "${2}"* ]] ; then - V=3 openim::log::status "Keeping image ${1}:${tag}" - continue - fi - - if [[ -z "${3:-}" || "${tag}" != "${3}" ]] ; then - V=2 openim::log::status "Deleting image ${1}:${tag}" - "${DOCKER[@]}" rmi "${1}:${tag}" >/dev/null - else - V=3 openim::log::status "Keeping image ${1}:${tag}" - fi -done -} - -# Stop and delete all containers that match a pattern -# -# $1: The base container prefix -# $2: The current container to keep, if provided -function openim::build::docker_delete_old_containers() { -# In Docker 1.12 we can replace this line with -# docker ps -a --format="{{.Names}}" -for container in $("${DOCKER[@]}" ps -a | tail -n +2 | awk '{print $NF}') ; do - if [[ "${container}" != "${1}"* ]] ; then - V=3 openim::log::status "Keeping container ${container}" - continue - fi - if [[ -z "${2:-}" || "${container}" != "${2}" ]] ; then - V=2 openim::log::status "Deleting container ${container}" - openim::build::destroy_container "${container}" - else - V=3 openim::log::status "Keeping container ${container}" - fi -done -} - -# Takes $1 and computes a short has for it. Useful for unique tag generation -function openim::build::short_hash() { -[[ $# -eq 1 ]] || { - openim::log::error "Internal error. No data based to short_hash." - exit 2 -} - -local short_hash -if which md5 >/dev/null 2>&1; then - short_hash=$(md5 -q -s "$1") -else - short_hash=$(echo -n "$1" | md5sum) -fi -echo "${short_hash:0:10}" -} - -# Pedantically kill, wait-on and remove a container. The -f -v options -# to rm don't actually seem to get the job done, so force kill the -# container, wait to ensure it's stopped, then try the remove. This is -# a workaround for bug https://github.com/docker/docker/issues/3968. -function openim::build::destroy_container() { -"${DOCKER[@]}" kill "$1" >/dev/null 2>&1 || true -if [[ $("${DOCKER[@]}" version --format '{{.Server.Version}}') = 17.06.0* ]]; then - # Workaround https://github.com/moby/moby/issues/33948. - # TODO: remove when 17.06.0 is not relevant anymore - DOCKER_API_VERSION=v1.29 "${DOCKER[@]}" wait "$1" >/dev/null 2>&1 || true -else - "${DOCKER[@]}" wait "$1" >/dev/null 2>&1 || true -fi -"${DOCKER[@]}" rm -f -v "$1" >/dev/null 2>&1 || true -} - -# --------------------------------------------------------------------------- -# Building - - -function openim::build::clean() { -if openim::build::has_docker ; then - openim::build::docker_delete_old_containers "${OPENIM_BUILD_CONTAINER_NAME_BASE}" - openim::build::docker_delete_old_containers "${OPENIM_RSYNC_CONTAINER_NAME_BASE}" - openim::build::docker_delete_old_containers "${OPENIM_DATA_CONTAINER_NAME_BASE}" - openim::build::docker_delete_old_images "${OPENIM_BUILD_IMAGE_REPO}" "${OPENIM_BUILD_IMAGE_TAG_BASE}" - - V=2 openim::log::status "Cleaning all untagged docker images" - "${DOCKER[@]}" rmi "$("${DOCKER[@]}" images -q --filter 'dangling=true')" 2> /dev/null || true -fi - -if [[ -d "${LOCAL_OUTPUT_ROOT}" ]]; then - openim::log::status "Removing _output directory" - rm -rf "${LOCAL_OUTPUT_ROOT}" -fi -} - -# Set up the context directory for the openim-build image and build it. -function openim::build::build_image() { -mkdir -p "${LOCAL_OUTPUT_BUILD_CONTEXT}" -# Make sure the context directory owned by the right user for syncing sources to container. -chown -R "${USER_ID}":"${GROUP_ID}" "${LOCAL_OUTPUT_BUILD_CONTEXT}" - -cp /etc/localtime "${LOCAL_OUTPUT_BUILD_CONTEXT}/" - -cp "${OPENIM_ROOT}/build/build-image/Dockerfile" "${LOCAL_OUTPUT_BUILD_CONTEXT}/Dockerfile" -cp "${OPENIM_ROOT}/build/build-image/rsyncd.sh" "${LOCAL_OUTPUT_BUILD_CONTEXT}/" -dd if=/dev/urandom bs=512 count=1 2>/dev/null | LC_ALL=C tr -dc 'A-Za-z0-9' | dd bs=32 count=1 2>/dev/null > "${LOCAL_OUTPUT_BUILD_CONTEXT}/rsyncd.password" -chmod go= "${LOCAL_OUTPUT_BUILD_CONTEXT}/rsyncd.password" - -openim::build::update_dockerfile -openim::build::set_proxy -openim::build::docker_build "${OPENIM_BUILD_IMAGE}" "${LOCAL_OUTPUT_BUILD_CONTEXT}" 'false' - -# Clean up old versions of everything -openim::build::docker_delete_old_containers "${OPENIM_BUILD_CONTAINER_NAME_BASE}" "${OPENIM_BUILD_CONTAINER_NAME}" -openim::build::docker_delete_old_containers "${OPENIM_RSYNC_CONTAINER_NAME_BASE}" "${OPENIM_RSYNC_CONTAINER_NAME}" -openim::build::docker_delete_old_containers "${OPENIM_DATA_CONTAINER_NAME_BASE}" "${OPENIM_DATA_CONTAINER_NAME}" -openim::build::docker_delete_old_images "${OPENIM_BUILD_IMAGE_REPO}" "${OPENIM_BUILD_IMAGE_TAG_BASE}" "${OPENIM_BUILD_IMAGE_TAG}" - -openim::build::ensure_data_container -openim::build::sync_to_container -} - -# Build a docker image from a Dockerfile. -# $1 is the name of the image to build -# $2 is the location of the "context" directory, with the Dockerfile at the root. -# $3 is the value to set the --pull flag for docker build; true by default -function openim::build::docker_build() { -local -r image=$1 -local -r context_dir=$2 -local -r pull="${3:-true}" -local -ra build_cmd=("${DOCKER[@]}" build -t "${image}" "--pull=${pull}" "${context_dir}") - -openim::log::status "Building Docker image ${image}" -local docker_output -docker_output=$("${build_cmd[@]}" 2>&1) || { - cat <&2 -+++ Docker build command failed for ${image} - -${docker_output} - -To retry manually, run: - -${build_cmd[*]} - -EOF - return 1 -} -} - -function openim::build::ensure_data_container() { -# If the data container exists AND exited successfully, we can use it. -# Otherwise nuke it and start over. -local ret=0 -local code=0 - -code=$(docker inspect \ - -f '{{.State.ExitCode}}' \ -"${OPENIM_DATA_CONTAINER_NAME}" 2>/dev/null) || ret=$? -if [[ "${ret}" == 0 && "${code}" != 0 ]]; then - openim::build::destroy_container "${OPENIM_DATA_CONTAINER_NAME}" - ret=1 -fi -if [[ "${ret}" != 0 ]]; then - openim::log::status "Creating data container ${OPENIM_DATA_CONTAINER_NAME}" - # We have to ensure the directory exists, or else the docker run will - # create it as root. - mkdir -p "${LOCAL_OUTPUT_GOPATH}" - # We want this to run as root to be able to chown, so non-root users can - # later use the result as a data container. This run both creates the data - # container and chowns the GOPATH. - # - # The data container creates volumes for all of the directories that store - # intermediates for the Go build. This enables incremental builds across - # Docker sessions. The *_cgo paths are re-compiled versions of the go std - # libraries for true static building. - local -ra docker_cmd=( - "${DOCKER[@]}" run - --volume "${REMOTE_ROOT}" # white-out the whole output dir - --volume /usr/local/go/pkg/linux_386_cgo - --volume /usr/local/go/pkg/linux_amd64_cgo - --volume /usr/local/go/pkg/linux_arm_cgo - --volume /usr/local/go/pkg/linux_arm64_cgo - --volume /usr/local/go/pkg/linux_ppc64le_cgo - --volume /usr/local/go/pkg/darwin_amd64_cgo - --volume /usr/local/go/pkg/darwin_386_cgo - --volume /usr/local/go/pkg/windows_amd64_cgo - --volume /usr/local/go/pkg/windows_386_cgo - --name "${OPENIM_DATA_CONTAINER_NAME}" - --hostname "${HOSTNAME}" - "${OPENIM_BUILD_IMAGE}" - chown -R "${USER_ID}":"${GROUP_ID}" - "${REMOTE_ROOT}" - /usr/local/go/pkg/ - ) - "${docker_cmd[@]}" -fi -} - -# Build all openim commands. -function openim::build::build_command() { -openim::log::status "Running build command..." -make -C "${OPENIM_ROOT}" multiarch -} diff --git a/scripts/coverage.awk b/scripts/coverage.awk deleted file mode 100755 index 49389054e2..0000000000 --- a/scripts/coverage.awk +++ /dev/null @@ -1,13 +0,0 @@ -#!/usr/bin/env awk - -{ - print $0 - if (match($0, /^total:/)) { - sub(/%/, "", $NF); - printf("test coverage is %s%(quality gate is %s%)\n", $NF, target) - if (strtonum($NF) < target) { - printf("test coverage does not meet expectations: %d%, please add test cases!\n", target) - exit 1; - } - } -} diff --git a/scripts/coverage.sh b/scripts/coverage.sh deleted file mode 100755 index e5cef0b5dd..0000000000 --- a/scripts/coverage.sh +++ /dev/null @@ -1,29 +0,0 @@ -#!/usr/bin/env bash - -# 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. - -# http://stackoverflow.com/a/21142256/2055281 - -echo "mode: atomic" > coverage.txt - -for d in $(find ./* -maxdepth 10 -type d); do - if ls $d/*.go &> /dev/null; then - go test -coverprofile=profile.out -covermode=atomic $d - if [ -f profile.out ]; then - cat profile.out | grep -v "mode: " >> /tmp/coverage.txt - rm profile.out - fi - fi -done diff --git a/scripts/docker-start-all.sh b/scripts/docker-start-all.sh deleted file mode 100755 index 116038b536..0000000000 --- a/scripts/docker-start-all.sh +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env bash - -# 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. - - - - - -#fixme This scripts is the total startup scripts -#fixme The full name of the shell scripts that needs to be started is placed in the need_to_start_server_shell array - -cd /openim/openim-server -mage start -tail -f /dev/null diff --git a/scripts/ensure-tag.sh b/scripts/ensure-tag.sh deleted file mode 100755 index 5fedf70192..0000000000 --- a/scripts/ensure-tag.sh +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env bash - -# 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. - -OPENIM_ROOT=$(dirname "${BASH_SOURCE[0]}")/.. - -version="${VERSION}" -if [ "${version}" == "" ];then - version=v$(${OPENIM_ROOT}/_output/tools/gsemver bump) -fi - -if [ -z "$(git tag -l ${version})" ];then - git tag -a -m "release version ${version}" ${version} -fi diff --git a/scripts/gen-swagger-docs.sh b/scripts/gen-swagger-docs.sh deleted file mode 100755 index e768f9106c..0000000000 --- a/scripts/gen-swagger-docs.sh +++ /dev/null @@ -1,73 +0,0 @@ -#!/usr/bin/env bash -# 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. - -# Script to generate docs from the latest swagger spec. - - - - - -# The root of the build/dist directory -OPENIM_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd -P)" -source "${OPENIM_ROOT}"/scripts/lib/util.sh - -mkdir -p ${OPENIM_OUTPUT_TMP} -cd ${OPENIM_OUTPUT_TMP} - -# gendocs takes "input.json" as the input swagger spec. -# $1 is expected to be _ -cp ${OPENIM_OUTPUT_TMP}/swagger-source/"$1".json ${OPENIM_OUTPUT_TMP}/input.json - -./gradle-2.5/bin/gradle gendocs --info - -#insert a TOC for top level API objects -buf="== Top Level API Objects\n\n" -top_level_models=$(grep '&[A-Za-z]*{},' /register.go | sed 's/.*&//;s/{},//') - -# check if the top level models exist in the definitions.adoc. If they exist, -# their name will be . -VERSION="${1#*_}" -for m in ${top_level_models} -do - if grep -xq "=== ${VERSION}.${m}" ./definitions.adoc - then - buf+="* <<${VERSION}.${m}>>\n" - fi -done -sed -i "1i ${buf}" ./definitions.adoc - -# fix the links in .adoc, replace <> with link:definitions.html#_x_y[x.y], and lowercase the _x_y part -sed -i -e 's|<<\(.*\)\.\(.*\)>>|link:#_\L\1_\2\E[\1.\2]|g' ./definitions.adoc -sed -i -e 's|<<\(.*\)\.\(.*\)>>|link:../definitions#_\L\1_\2\E[\1.\2]|g' ./paths.adoc - -# fix the link to <> -sed -i -e 's|<>|link:#_any[any]|g' ./definitions.adoc -sed -i -e 's|<>|link:../definitions#_any[any]|g' ./paths.adoc - -# change the title of paths.adoc from "paths" to "operations" -sed -i 's|== Paths|== Operations|g' ./paths.adoc - -# $$ has special meaning in asciidoc, we need to escape it -sed -i 's|\$\$|+++$$+++|g' ./definitions.adoc - -echo -e "=== any\nRepresents an untyped JSON map - see the description of the field for more info about the structure of this object." >> ./definitions.adoc - -asciidoctor definitions.adoc -asciidoctor paths.adoc - -cp "$OPENIM_OUTPUT_TMP/definitions.html" "$OPENIM_OUTPUT_TMP/_output/" -cp "$OPENIM_OUTPUT_TMP/paths.html" "$OPENIM_OUTPUT_TMP/_output/operations.html" - -success "SUCCESS" \ No newline at end of file diff --git a/scripts/genconfig.sh b/scripts/genconfig.sh deleted file mode 100755 index 498b0b9089..0000000000 --- a/scripts/genconfig.sh +++ /dev/null @@ -1,56 +0,0 @@ -#!/usr/bin/env bash -# 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. - -# Function of this script: Generate the OPENIM component YAML configuration file according to the scripts/environment.sh configuration. -# eg:./scripts/genconfig.sh scripts/install/environment.sh scripts/template/config.yaml -# Read: https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/init-config.md - -env_file="$1" -template_file="$2" - -OPENIM_ROOT=$(dirname "${BASH_SOURCE[0]}")/.. - -source "${OPENIM_ROOT}/scripts/lib/init.sh" - -if [ $# -ne 2 ];then - openim::log::error "Usage: scripts/genconfig.sh scripts/environment.sh configs/config.yaml" - exit 1 -fi - -if [ -z "${OPENIM_IP}" ]; then - openim::util::require-dig -fi - -source "${env_file}" - -declare -A envs - -set +u -for env in $(sed -n 's/^[^#].*${\(.*\)}.*/\1/p' ${template_file}) -do - if [ -z "$(eval echo \$${env})" ];then - openim::log::error "environment variable '${env}' not set" - missing=true - fi -done - -if [ "${missing}" ];then - openim::log::error "You may run 'source scripts/environment.sh' to set these environment" - exit 1 -fi - -eval "cat << EOF -$(cat ${template_file}) -EOF" \ No newline at end of file diff --git a/scripts/gendoc.sh b/scripts/gendoc.sh deleted file mode 100755 index 43b69c3edd..0000000000 --- a/scripts/gendoc.sh +++ /dev/null @@ -1,84 +0,0 @@ -#!/usr/bin/env bash -# 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. - -#!/bin/bash - -DEFAULT_DIRS=("pkg") -BASE_URL="github.com/openimsdk/open-im-server/v3" -REMOVE_DOC=false - -usage() { - echo "Usage: $0 [OPTIONS]" - echo - echo "This script iterates over directories. By default, it generates doc.go files for 'pkg' and 'internal/pkg'." - echo - echo "Options:" - echo " -d DIRS, --dirs DIRS Specify directories to process, separated by commas (e.g., 'pkg,internal/pkg')." - echo " -u URL, --url URL Set the base URL for the import path. Default is '$BASE_URL'." - echo " -r, --remove Remove all doc.go files in the specified directories." - echo " -h, --help Show this help message." - echo -} - -process_dir() { - local dir="$1" - local base_url="$2" - local remove_doc="$3" - - find "$dir" -type d | while read -r d; do - if [ "$remove_doc" = true ]; then - if [ -f "$d/doc.go" ]; then - echo "Removing $d/doc.go" - rm -f "$d/doc.go" - fi - else - if [ ! -f "$d/doc.go" ] && ls "$d/"*.go &>/dev/null; then - echo "Creating $d/doc.go" - echo "package $(basename "$d") // import \"$base_url/$(echo "$d" | sed "s|^\./||")\"" >"$d/doc.go" - fi - fi - done -} - -while [[ $# -gt 0 ]]; do - case "$1" in - -d|--dirs) - IFS=',' read -ra DIRS <<< "$2" - shift 2 - ;; - -u|--url) - BASE_URL="$2" - shift 2 - ;; - -r|--remove) - REMOVE_DOC=true - shift - ;; - -h|--help) - usage - exit 0 - ;; - *) - usage - exit 1 - ;; - esac -done - -DIRS=(${DIRS:-"${DEFAULT_DIRS[@]}"}) - -for dir in "${DIRS[@]}"; do - process_dir "$dir" "$BASE_URL" "$REMOVE_DOC" -done diff --git a/scripts/init-config.sh b/scripts/init-config.sh deleted file mode 100755 index ef2cd0a401..0000000000 --- a/scripts/init-config.sh +++ /dev/null @@ -1,265 +0,0 @@ -#!/usr/bin/env bash -# 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. - -# This script automatically initializes various configuration files and can generate example files. - - - - - -# Root directory of the OpenIM project -OPENIM_ROOT=$(dirname "${BASH_SOURCE[0]}")/.. - -# Source initialization script -source "${OPENIM_ROOT}/scripts/lib/init.sh" - -# Default environment file -readonly ENV_FILE=${ENV_FILE:-"${OPENIM_ROOT}/scripts/install/environment.sh"} - -# Templates for configuration files -declare -A TEMPLATES=( - ["${OPENIM_ROOT}/deployments/templates/env-template.yaml"]="${OPENIM_ROOT}/.env" - ["${OPENIM_ROOT}/deployments/templates/config.yaml"]="${OPENIM_ROOT}/config/config.yaml" - ["${OPENIM_ROOT}/deployments/templates/prometheus.yml"]="${OPENIM_ROOT}/config/prometheus.yml" - ["${OPENIM_ROOT}/deployments/templates/alertmanager.yml"]="${OPENIM_ROOT}/config/alertmanager.yml" -) - -# Templates for example files -declare -A EXAMPLES=( - ["${OPENIM_ROOT}/deployments/templates/env-template.yaml"]="${OPENIM_ROOT}/config/templates/env.template" - ["${OPENIM_ROOT}/deployments/templates/config.yaml"]="${OPENIM_ROOT}/config/templates/config.yaml.template" - ["${OPENIM_ROOT}/deployments/templates/prometheus.yml"]="${OPENIM_ROOT}/config/templates/prometheus.yml.template" - ["${OPENIM_ROOT}/deployments/templates/alertmanager.yml"]="${OPENIM_ROOT}/config/templates/alertmanager.yml.template" -) - -# Templates for config Copy file -declare -A COPY_TEMPLATES=( - ["${OPENIM_ROOT}/deployments/templates/email.tmpl"]="${OPENIM_ROOT}/config/email.tmpl" - ["${OPENIM_ROOT}/deployments/templates/instance-down-rules.yml"]="${OPENIM_ROOT}/config/instance-down-rules.yml" - ["${OPENIM_ROOT}/deployments/templates/notification.yaml"]="${OPENIM_ROOT}/config/notification.yaml" -) - -# Templates for config Copy file -declare -A COPY_EXAMPLES=( - ["${OPENIM_ROOT}/deployments/templates/email.tmpl"]="${OPENIM_ROOT}/config/templates/email.tmpl.template" - ["${OPENIM_ROOT}/deployments/templates/instance-down-rules.yml"]="${OPENIM_ROOT}/config/templates/instance-down-rules.yml.template" - ["${OPENIM_ROOT}/deployments/templates/notification.yaml"]="${OPENIM_ROOT}/config/templates/notification.yaml.template" -) - -# Command-line options -FORCE_OVERWRITE=false -SKIP_EXISTING=false -GENERATE_EXAMPLES=false -CLEAN_CONFIG=false -CLEAN_EXAMPLES=false - -FILES_PROCESSED=false - -# Function to display help information -show_help() { - echo "Usage: $(basename "$0") [options]" - echo "Options:" - echo " -h, --help Show this help message" - echo " --force Overwrite existing files without prompt" - echo " --skip Skip generation if file exists" - echo " --examples Generate example files" - echo " --clean-config Clean all configuration files" - echo " --clean-examples Clean all example files" -} - -# Function to generate and copy configuration files -generate_config_files() { - # Handle TEMPLATES array - for template in "${!TEMPLATES[@]}"; do - local output_file="${TEMPLATES[$template]}" - process_file "$template" "$output_file" true - done - - # Handle COPY_TEMPLATES array - for template in "${!COPY_TEMPLATES[@]}"; do - local output_file="${COPY_TEMPLATES[$template]}" - process_file "$template" "$output_file" false - done -} - -# Function to generate example files -generate_example_files() { - env_cmd="env -i" - - env_vars["OPENIM_IP"]="127.0.0.1" - env_vars["LOG_STORAGE_LOCATION"]="../../" - - for var in "${!env_vars[@]}"; do - env_cmd+=" $var='${env_vars[$var]}'" - done - - # Processing EXAMPLES array - for template in "${!EXAMPLES[@]}"; do - local example_file="${EXAMPLES[$template]}" - process_file "$template" "$example_file" true - done - - # Processing COPY_EXAMPLES array - for template in "${!COPY_EXAMPLES[@]}"; do - local example_file="${COPY_EXAMPLES[$template]}" - process_file "$template" "$example_file" false - done -} - -# Function to process a single file, either by generating or copying -process_file() { - local template=$1 - local output_file=$2 - local use_genconfig=$3 - - if [[ -f "${output_file}" ]]; then - if [[ "${FORCE_OVERWRITE}" == true ]]; then - openim::log::info "Force overwriting ${output_file}." - elif [[ "${SKIP_EXISTING}" == true ]]; then - #openim::log::info "Skipping generation of ${output_file} as it already exists." - return - else - echo -n "File ${output_file} already exists. Overwrite? (Y/N): " - read -r -n 1 REPLY - echo - if [[ ! $REPLY =~ ^[Yy]$ ]]; then - openim::log::info "Skipping generation of ${output_file}." - return - fi - fi - else - if [[ "${SKIP_EXISTING}" == true ]]; then - openim::log::info "Generating ${output_file} as it does not exist." - fi - fi - - if [[ "$use_genconfig" == true ]]; then - openim::log::info "⌚ Working with template file: ${template} to generate ${output_file}..." - if [[ ! -f "${OPENIM_ROOT}/scripts/genconfig.sh" ]]; then - openim::log::error "genconfig.sh script not found" - exit 1 - fi - if [[ -n "${env_cmd}" ]]; then - - { - printf "debugggggggggggggggggggg file: %s template: %s\n" "${ENV_FILE}" "${template}" - } | tee /tmp/debug.log - - - eval "$env_cmd ${OPENIM_ROOT}/scripts/genconfig.sh '${ENV_FILE}' '${template}' > '${output_file}'" || { - openim::log::error "Error processing template file ${template}" - exit 1 - } - else - "${OPENIM_ROOT}/scripts/genconfig.sh" "${ENV_FILE}" "${template}" > "${output_file}" || { - openim::log::error "Error processing template file ${template}" - exit 1 - } - fi - else - openim::log::info "📋 Copying ${template} to ${output_file}..." - cp "${template}" "${output_file}" || { - openim::log::error "Error copying template file ${template}" - exit 1 - } - fi - FILES_PROCESSED=true -} - -clean_config_files() { - local all_templates=("${TEMPLATES[@]}" "${COPY_TEMPLATES[@]}") - - for output_file in "${all_templates[@]}"; do - if [[ -f "${output_file}" ]]; then - rm -f "${output_file}" - openim::log::info "Removed configuration file: ${output_file}" - fi - done -} - -# Function to clean example files -clean_example_files() { - local all_examples=("${EXAMPLES[@]}" "${COPY_EXAMPLES[@]}") - - for example_file in "${all_examples[@]}"; do - if [[ -f "${example_file}" ]]; then - rm -f "${example_file}" - openim::log::info "Removed example file: ${example_file}" - fi - done -} - -while [[ $# -gt 0 ]]; do - case "$1" in - -h|--help) - show_help - exit 0 - ;; - --force) - FORCE_OVERWRITE=true - shift - ;; - --skip) - SKIP_EXISTING=true - shift - ;; - --examples) - GENERATE_EXAMPLES=true - shift - ;; - --clean-config) - CLEAN_CONFIG=true - shift - ;; - --clean-examples) - CLEAN_EXAMPLES=true - shift - ;; - *) - echo "Unknown option: $1" - show_help - exit 1 - ;; - esac -done - -# Clean configuration files if --clean-config option is provided -if [[ "${CLEAN_CONFIG}" == true ]]; then - clean_config_files -fi - -# Clean example files if --clean-examples option is provided -if [[ "${CLEAN_EXAMPLES}" == true ]]; then - clean_example_files -fi - -# Generate configuration files if requested -if [[ "${FORCE_OVERWRITE}" == true || "${SKIP_EXISTING}" == false ]] && [[ "${CLEAN_CONFIG}" == false ]]; then - generate_config_files -fi - -# Generate configuration files if requested -if [[ "${SKIP_EXISTING}" == true ]]; then - generate_config_files -fi - -# Generate example files if --examples option is provided -if [[ "${GENERATE_EXAMPLES}" == true ]] && [[ "${CLEAN_EXAMPLES}" == false ]]; then - generate_example_files -fi - -if [[ "${FILES_PROCESSED}" == true ]]; then - openim::log::success "Configuration and example files operation complete!" -fi diff --git a/scripts/init-env.sh b/scripts/init-env.sh deleted file mode 100755 index 1e802c3be4..0000000000 --- a/scripts/init-env.sh +++ /dev/null @@ -1,33 +0,0 @@ -#!/usr/bin/env bash -# 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. - -#FIXME This script is the startup script for multiple servers. -#FIXME The full names of the shell scripts that need to be started are placed in the `need_to_start_server_shell` array. - - - - -OPENIM_ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")"/.. && pwd -P) -source "${OPENIM_ROOT}/scripts/install/common.sh" - -openim::log::info "\n# Begin Install OpenIM Config" - -for file in "${OPENIM_SERVER_TARGETS[@]}"; do - VARNAME="$(echo $file | tr '[:lower:]' '[:upper:]' | tr '.' '_' | tr '-' '_')" - VARVALUE="$OPENIM_OUTPUT_HOSTBIN/$file" - # /etc/profile.d/openim-env.sh - echo "export $VARNAME=$VARVALUE" > /etc/profile.d/openim-env.sh - source /etc/profile.d/openim-env.sh -done diff --git a/scripts/init-githooks.sh b/scripts/init-githooks.sh deleted file mode 100755 index 4ee470742e..0000000000 --- a/scripts/init-githooks.sh +++ /dev/null @@ -1,100 +0,0 @@ -#!/usr/bin/env bash -# 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. -# -# ----------------------------------------------------------------------------- -# init-githooks.sh -# -# This script assists in managing Git hooks for the OpenIM project. -# When executed: -# 1. It prompts the user to enable git hooks. -# 2. If the user accepts, it copies predefined hook scripts to the appropriate -# Git directory, making them executable. -# 3. If requested, it can delete the added hooks. -# -# This script equal runs `make init-githooks` command. -# Usage: -# ./init-githooks.sh Prompt to enable git hooks. -# ./init-githooks.sh --delete Delete previously added git hooks. -# ./init-githooks.sh --help Show the help message. -# -# Example: `scripts/build-go.sh --help`. -# Documentation & related context can be found at: -# https://gist.github.com/cubxxw/126b72104ac0b0ca484c9db09c3e5694 -# -# ----------------------------------------------------------------------------- - -OPENIM_ROOT=$(dirname "${BASH_SOURCE[0]}")/.. -HOOKS_DIR="${OPENIM_ROOT}/.git/hooks" - -help_info() { - echo "Usage: $0 [options]" - echo - echo "This script helps to manage git hooks." - echo - echo "Options:" - echo " -h, --help Show this help message and exit." - echo " -d, --delete Delete the hooks that have been added." - echo " By default, it will prompt to enable git hooks." -} - -delete_hooks() { - for file in "${OPENIM_ROOT}"/scripts/githooks/*.sh; do - hook_name=$(basename "$file" .sh) # This removes the .sh extension - rm -f "$HOOKS_DIR/$hook_name" - done - echo "Git hooks have been deleted." -} - -enable_hooks() { - echo "Would you like to:" - echo "1) Enable git hooks mode" - echo "2) Delete existing git hooks" - echo "Please select a number (or any other key to exit):" - read -r choice - - case "$choice" in - 1) - for file in ${OPENIM_ROOT}/scripts/githooks/*.sh; do - hook_name=$(basename "$file" .sh) # This removes the .sh extension - cp -f "$file" "$HOOKS_DIR/$hook_name" - done - - chmod +x $HOOKS_DIR/* - - echo "Git hooks mode has been enabled." - echo "With git hooks enabled, every time you perform a git action (e.g. git commit), the corresponding hooks script will be triggered automatically." - echo "This means that if the size of the file you're committing exceeds the set limit (e.g. 42MB), the commit will be rejected." - ;; - 2) - delete_hooks - ;; - *) - echo "Exiting without making changes." - ;; - esac -} - - -case "$1" in - -h|--help) - help_info - ;; - -d|--delete) - delete_hooks - ;; - *) - enable_hooks - ;; -esac diff --git a/scripts/install-im-server.sh b/scripts/install-im-server.sh deleted file mode 100755 index d11a49dc8d..0000000000 --- a/scripts/install-im-server.sh +++ /dev/null @@ -1,86 +0,0 @@ -#!/usr/bin/env bash -# 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. - -# -# OpenIM Docker Deployment Script -# -# This script automates the process of building the OpenIM server image -# and deploying it using Docker Compose. -# -# Variables: -# - SERVER_IMAGE_VERSION: Version of the server image (default: test) -# - IMAGE_REGISTRY: Docker image registry (default: openim) -# - DOCKER_COMPOSE_FILE_URL: URL to the docker-compose.yml file -# -# Usage: -# SERVER_IMAGE_VERSION=latest IMAGE_REGISTRY=myregistry ./this_script.sh - - - - - -OPENIM_ROOT=$(dirname "${BASH_SOURCE[0]}")/.. -source "${OPENIM_ROOT}/scripts/lib/init.sh" - -trap 'openim::util::onCtrlC' INT - -chmod +x "${OPENIM_ROOT}"/scripts/*.sh - -openim::util::ensure_docker_daemon_connectivity - -# Default values for variables -: ${SERVER_IMAGE_VERSION:=test} -: ${IMAGE_REGISTRY:=openim} -: ${DOCKER_COMPOSE_FILE_URL:="https://raw.githubusercontent.com/openimsdk/openim-docker/main/docker-compose.yaml"} - -DOCKER_COMPOSE_COMMAND= -# Check if docker-compose command is available -openim::util::check_docker_and_compose_versions -if command -v docker compose &> /dev/null; then - openim::log::info "docker compose command is available" - DOCKER_COMPOSE_COMMAND="docker compose" -else - DOCKER_COMPOSE_COMMAND="docker-compose" -fi - -export SERVER_IMAGE_VERSION -export IMAGE_REGISTRY -"${OPENIM_ROOT}"/scripts/init-config.sh - -pushd "${OPENIM_ROOT}" -docker build -t "${IMAGE_REGISTRY}/openim-server:${SERVER_IMAGE_VERSION}" . -${DOCKER_COMPOSE_COMMAND} stop -curl "${DOCKER_COMPOSE_FILE_URL}" -o docker-compose.yml -${DOCKER_COMPOSE_COMMAND} up -d - -# Function to check container status -check_containers() { - if ! ${DOCKER_COMPOSE_COMMAND} ps | grep -q 'Up'; then - echo "Error: One or more docker containers failed to start." - ${DOCKER_COMPOSE_COMMAND} logs openim-server - ${DOCKER_COMPOSE_COMMAND} logs openim-chat - return 1 - fi - return 0 -} - -# Wait for a short period to allow containers to initialize -sleep 100 - -${DOCKER_COMPOSE_COMMAND} ps - -check_containers - -popd \ No newline at end of file diff --git a/scripts/install/README.md b/scripts/install/README.md deleted file mode 100644 index 8e710add8d..0000000000 --- a/scripts/install/README.md +++ /dev/null @@ -1,116 +0,0 @@ -# OpenIM Suite Scripts - -The OpenIM Suite represents a comprehensive collection of scripts, each tailored to manage and operate specific services within the OpenIM ecosystem. These scripts offer consistent, reliable, and efficient tools for initializing, controlling, and managing various OpenIM services on a Linux platform. - -## Features - -- **Robustness:** Built with Bash's error handling mechanisms (`errexit`, `nounset`, and `pipefail`), ensuring scripts fail fast and provide relevant error messages. -- **Modularity:** Each script is dedicated to a particular service, promoting clarity and ease of maintenance. -- **Comprehensive Logging:** Integrated logging utilities offer real-time insights into operations, enhancing transparency and debuggability. -- **Systemd Integration:** Where applicable, scripts integrate with the systemd service manager, offering standardized service controls like start, stop, restart, and status checks. - -## Scripts Overview - -1. **openim-api:** Control interface for the OpenIM API service. -2. **openim-cmdutils:** Utility toolkit for common OpenIM command-line operations. -3. **openim-crontask:** Manages the OpenIM CronTask service, with both direct and systemctl installation methods. -4. **openim-msggateway:** Script to operate the OpenIM Message Gateway service. -5. **openim-msgtransfer:** Manages the OpenIM Message Transfer functionalities. -6. **openim-push:** Interface for controlling the OpenIM Push Notification service. -7. **openim-rpc-auth:** Script dedicated to the OpenIM RPC Authentication service. -8. **openim-rpc-conversation:** Manages operations related to the OpenIM RPC Conversation service. -9. **openim-rpc-friend:** Control interface for the OpenIM RPC Friend functionalities. -10. **openim-rpc-group:** Script for managing the OpenIM RPC Group service. -11. **openim-rpc-msg:** Operates the OpenIM RPC Messaging service. -12. **openim-rpc-third:** Script dedicated to third-party integrations with OpenIM RPC. -13. **openim-rpc-user:** Control interface for OpenIM RPC User operations. - -## OpenIM Server Installation Script Usage - -The scripts within the OpenIM Suite generally adhere to two primary execution methodologies. To illustrate these methodologies, we'll use `openim-crontask` as a representative example. - -1. **Direct Script Execution:** Running the script directly, typically for straightforward start/stop operations. - - ```bash - ./[script-name].sh - ``` - -2. **Function-based Execution:** Invoking specific functions within the script for more specialized operations (e.g., install, uninstall). - - ```bash - ./scripts/install/install.sh [options] - ``` - -**Description:** -This script is designed to handle the installation, uninstallation, and status checking of OpenIM components on the server. OpenIM is a presumed communication or messaging platform. - -### Commands: -- **-i, --install**: - Initiate the installation of all OpenIM components. - -- **-u, --uninstall**: - Uninstall or remove all OpenIM components from the server. - -- **-s, --status**: - Check and report the current operational status of the installed OpenIM components. - -- **-h, --help**: - Display the help menu for available commands. - -### Example Usage: -To install all OpenIM components: -```bash -./scripts/install/install.sh -i -``` -or -```bash -./scripts/install/install.sh --install -``` -> **Note**: -> Ensure you have the necessary privileges to execute installation or uninstallation operations. It's generally recommended to take a backup before making major changes. - - -### 1. Direct Script Execution - -This method involves invoking the script directly, initiating its default behavior. For instance, with `openim-crontask`, direct execution will start the OpenIM CronTask as a background process. - -**Example:** - -```bash -./openim-crontask.sh -``` - -Upon execution, the script will source any necessary configurations, log the start of the CronTask, and finally run the CronTask in the background. The log messages will provide feedback about the process, ensuring the user is informed of the task's progress. - -### 2. Function-based Execution - -This approach is more specialized, enabling users to call specific functions defined within the script. This is particularly useful for tasks like installation, uninstallation, and status checks. - -For the `openim-crontask` script: - -- **Installation**: It includes building the service, generating configuration files, setting up systemd services, and starting the service. - - ```bash - ./openim-crontask.sh openim::crontask::install - ``` - -- **Uninstallation**: Stops the service, removes associated binaries, configuration files, and systemd service files. - - ```bash - ./openim-crontask.sh openim::crontask::uninstall - ``` - -- **Status Check**: Verifies the running status of the service, checking for active processes and listening ports. - - ```bash - ./openim-crontask.sh openim::crontask::status - ``` - -It's crucial to familiarize oneself with the available functions within each script. This ensures optimal utilization of the provided tools and a deeper understanding of the underlying operations. - - - -## Notes - -- Always ensure you have the correct permissions before executing any script. -- Environment variables may need to be set or sourced depending on your installation and configuration. \ No newline at end of file diff --git a/scripts/install/common.sh b/scripts/install/common.sh deleted file mode 100755 index ed1ba1a4bb..0000000000 --- a/scripts/install/common.sh +++ /dev/null @@ -1,155 +0,0 @@ -#!/usr/bin/env bash -# 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. - - -# Common utilities, variables and checks for all build scripts. - - - - -# Sourced flag -COMMON_SOURCED=true -# The root of the build/dist directory -OPENIM_ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")"/../.. && pwd -P) -source "${OPENIM_ROOT}/scripts/lib/init.sh" -# Make sure the environment is only called via common to avoid too much nesting -source "${OPENIM_ROOT}/scripts/install/environment.sh" - -# This function returns a list of Prometheus ports for various services -# based on the provided configuration. Each service has its own dedicated -# port for monitoring purposes. -openim::common::prometheus_port() { - # Declare an array to hold all the Prometheus ports for different services - local targets=( - ${USER_PROM_PORT} # Prometheus port for user service - ${FRIEND_PROM_PORT} # Prometheus port for friend service - ${MESSAGE_PROM_PORT} # Prometheus port for message service - ${MSG_GATEWAY_PROM_PORT} # Prometheus port for message gateway service - ${GROUP_PROM_PORT} # Prometheus port for group service - ${AUTH_PROM_PORT} # Prometheus port for authentication service - ${PUSH_PROM_PORT} # Prometheus port for push notification service - ${CONVERSATION_PROM_PORT} # Prometheus port for conversation service - ${RTC_PROM_PORT} # Prometheus port for real-time communication service - ${THIRD_PROM_PORT} # Prometheus port for third-party integrations service - ${MSG_TRANSFER_PROM_PORT} # Prometheus port for message transfer service - ) - # Print the list of ports - echo "${targets[@]}" -} -IFS=" " read -ra OPENIM_PROM_PORT_TARGETS <<< "$(openim::common::prometheus_port)" -readonly OPENIM_PROM_PORT_TARGETS -readonly OPENIM_PROM_PORT_LISTARIES=("${OPENIM_PROM_PORT_TARGETS[@]##*/}") - -openim::common::service_name() { - local targets=( - openim-user - openim-friend - openim-msg - openim-msg-gateway - openim-group - openim-auth - openim-push - openim-conversation - openim-third - # openim-msg-transfer - - # api - openim-api - openim-ws - ) - echo "${targets[@]}" -} - -IFS=" " read -ra OPENIM_SERVER_NAME_TARGETS <<< "$(openim::common::service_name)" -readonly OPENIM_SERVER_NAME_TARGETS - -# Storing all the defined ports in an array for easy management and access. -# This array consolidates the port numbers for all the services defined above. -openim::common::service_port() { - local targets=( - ${OPENIM_USER_PORT} # User service - ${OPENIM_FRIEND_PORT} # Friend service - ${OPENIM_MESSAGE_PORT} # Message service - ${OPENIM_MESSAGE_GATEWAY_PORT} # Message gateway - ${OPENIM_GROUP_PORT} # Group service - ${OPENIM_AUTH_PORT} # Authorization service - ${OPENIM_PUSH_PORT} # Push service - ${OPENIM_CONVERSATION_PORT} # Conversation service - ${OPENIM_THIRD_PORT} # Third-party service - - # API PORT - ${API_OPENIM_PORT} # API service - ${OPENIM_WS_PORT} # WebSocket service - ) - echo "${targets[@]}" -} -IFS=" " read -ra OPENIM_SERVER_PORT_TARGETS <<< "$(openim::common::service_port)" -readonly OPENIM_SERVER_PORT_TARGETS -readonly OPENIM_SERVER_PORT_LISTARIES=("${OPENIM_SERVER_PORT_TARGETS[@]##*/}") - - -OPENIM_ALL_SERVICE_LIBRARIES_NO_TRANSFER=() - -for target in "${OPENIM_SERVER_BINARIES_NO_TRANSFER[@]}"; do - OPENIM_ALL_SERVICE_LIBRARIES_NO_TRANSFER+=("${OPENIM_OUTPUT_HOSTBIN}/${target}") -done -readonly OPENIM_ALL_SERVICE_LIBRARIES_NO_TRANSFER - - - -OPENIM_ALL_SERVICE_LIBRARIES=() -for target in "${OPENIM_SERVER_BINARIES_NO_CMDUTILS[@]}"; do - OPENIM_ALL_SERVICE_LIBRARIES+=("${OPENIM_OUTPUT_HOSTBIN}/${target}") -done -readonly OPENIM_ALL_SERVICE_LIBRARIES - -openim::common::dependency_name() { - local targets=( - redis - zookeeper - kafka - mongodb - minio - ) - echo "${targets[@]}" -} - -IFS=" " read -ra OPENIM_DEPENDENCY_TARGETS <<< "$(openim::common::dependency_name)" -readonly OPENIM_DEPENDENCY_TARGETS - -# This function returns a list of ports for various services -# - zookeeper -# - kafka -# - mongodb -# - redis -# - minio -openim::common::dependency_port() { - local targets=( - ${REDIS_PORT} # Redis port - ${ZOOKEEPER_PORT} # Zookeeper port - ${KAFKA_PORT} # Kafka port - ${MONGO_PORT} # MongoDB port - ${MINIO_PORT} # MinIO port - ) - echo "${targets[@]}" -} -IFS=" " read -ra OPENIM_DEPENDENCY_PORT_TARGETS <<< "$(openim::common::dependency_port)" -readonly OPENIM_DEPENDENCY_PORT_TARGETS -readonly OPENIM_DEPENDENCY_PORT_LISTARIES=("${OPENIM_DEPENDENCY_PORT_TARGETS[@]##*/}") - -# Execute commands that require root permission without entering a password -function openim::common::sudo { - echo ${LINUX_PASSWORD} | sudo -S $1 -} diff --git a/scripts/install/dependency.sh b/scripts/install/dependency.sh deleted file mode 100755 index bad1cb6f92..0000000000 --- a/scripts/install/dependency.sh +++ /dev/null @@ -1,89 +0,0 @@ -#!/usr/bin/env bash -# 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. - -# This script will install the dependencies required for openim - - - - - -OPENIM_ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")"/../.. && pwd -P) -[[ -z ${COMMON_SOURCED} ]] && source "${OPENIM_ROOT}"/scripts/install/common.sh - -# Start MongoDB service -docker run -d \ ---name mongo \ --p 37017:27017 \ --v "${DATA_DIR}/components/mongodb/data/db:/data/db" \ --v "${DATA_DIR}/components/mongodb/data/logs:/data/logs" \ --v "${DATA_DIR}/components/mongodb/data/conf:/etc/mongo" \ --v "./scripts/mongo-init.sh:/docker-entrypoint-initdb.d/mongo-init.sh:ro" \ --e TZ=Asia/Shanghai \ --e wiredTigerCacheSizeGB=1 \ --e MONGO_INITDB_ROOT_USERNAME=${OPENIM_USER} \ --e MONGO_INITDB_ROOT_PASSWORD=${PASSWORD} \ --e MONGO_INITDB_DATABASE=openim_v3 \ --e MONGO_OPENIM_USERNAME=${OPENIM_USER} \ --e MONGO_OPENIM_PASSWORD=${PASSWORD} \ ---restart always \ -mongo:6.0.2 --wiredTigerCacheSizeGB 1 --auth - -# Start Redis service -docker run -d \ ---name redis \ --p 16379:6379 \ --v "${DATA_DIR}/components/redis/data:/data" \ --v "${DATA_DIR}/components/redis/config/redis.conf:/usr/local/redis/config/redis.conf" \ --e TZ=Asia/Shanghai \ ---sysctl net.core.somaxconn=1024 \ ---restart always \ -redis:7.0.0 redis-server --requirepass ${PASSWORD} --appendonly yes - -# Start Zookeeper service -docker run -d \ ---name zookeeper \ --p 2181:2181 \ --v "/etc/localtime:/etc/localtime" \ --e TZ=Asia/Shanghai \ ---restart always \ -wurstmeister/zookeeper - -# Start Kafka service -docker run -d \ ---name kafka \ --p 9092:9092 \ --e TZ=Asia/Shanghai \ --e KAFKA_BROKER_ID=0 \ --e KAFKA_ZOOKEEPER_CONNECT=zookeeper:2181 \ --e KAFKA_CREATE_TOPICS="latestMsgToRedis:8:1,msgToPush:8:1,offlineMsgToMongoMysql:8:1" \ --e KAFKA_ADVERTISED_LISTENERS="INSIDE://127.0.0.1:9092,OUTSIDE://103.116.45.174:9092" \ --e KAFKA_LISTENERS="INSIDE://:9092,OUTSIDE://:9093" \ --e KAFKA_LISTENER_SECURITY_PROTOCOL_MAP="INSIDE:PLAINTEXT,OUTSIDE:PLAINTEXT" \ --e KAFKA_INTER_BROKER_LISTENER_NAME=INSIDE \ ---restart always \ ---link zookeeper \ -wurstmeister/kafka - -# Start MinIO service -docker run -d \ ---name minio \ --p 10005:9000 \ --p 9090:9090 \ --v "/mnt/data:/data" \ --v "/mnt/config:/root/.minio" \ --e MINIO_ROOT_USER=${OPENIM_USER} \ --e MINIO_ROOT_PASSWORD=${PASSWORD} \ ---restart always \ -minio/minio server /data --console-address ':9090' diff --git a/scripts/install/environment.sh b/scripts/install/environment.sh deleted file mode 100755 index 64e76853d6..0000000000 --- a/scripts/install/environment.sh +++ /dev/null @@ -1,581 +0,0 @@ -#!/usr/bin/env bash -# 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. - -# This is a file that initializes variables for the automation script that initializes the config file -# You need to supplement the script according to the specification. -# Read: https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/init-config.md -# 格式化 bash 注释:https://tool.lu/shell/ -# 配置中心文档:https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/environment.md - -OPENIM_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd -P)" - -# 生成文件存放目录 -LOCAL_OUTPUT_ROOT="${OPENIM_ROOT}/${OUT_DIR:-_output}" -source "${OPENIM_ROOT}/scripts/lib/init.sh" - -#TODO: Access to the OPENIM_IP networks outside, or you want to use the OPENIM_IP network -# OPENIM_IP=127.0.0.1 -if [ -z "${OPENIM_IP}" ]; then - OPENIM_IP=$(openim::util::get_server_ip) -fi - -# config.gateway custom bridge modes -# if [ -z "{IP_GATEWAY}" ] then -# IP_GATEWAY=$(openim::util::get_local_ip) -# fi - -function def() { - local var_name="$1" - local default_value="${2:-}" - eval "readonly $var_name=\"\${$var_name:-$(printf '%q' "$default_value")}\"" -} - -# OpenIM Docker Compose 数据存储的默认路径 -def "DATA_DIR" "${OPENIM_ROOT}" - -# 设置统一的用户名,方便记忆 -def "OPENIM_USER" "root" - -# 设置统一的密码,方便记忆 -readonly PASSWORD=${PASSWORD:-'openIM123'} - -# 设置统一的数据库名称,方便管理 -def "DATABASE_NAME" "openim_v3" - -# Linux系统 openim 用户 -def "LINUX_USERNAME" "openim" -readonly LINUX_PASSWORD=${LINUX_PASSWORD:-"${PASSWORD}"} - -# 设置安装目录 -def "INSTALL_DIR" "${LOCAL_OUTPUT_ROOT}/installs" -mkdir -p ${INSTALL_DIR} - -def "ENV_FILE" "${OPENIM_ROOT}/scripts/install/environment.sh" - -###################### Docker compose ################### -# OPENIM AND CHAT -def "CHAT_IMAGE_VERSION" "main" -def "SERVER_IMAGE_VERSION" "main" - -# Choose the appropriate image address, the default is GITHUB image, -# you can choose docker hub, for Chinese users can choose Ali Cloud -# export IMAGE_REGISTRY="ghcr.io/openimsdk" -# export IMAGE_REGISTRY="openim" -# export IMAGE_REGISTRY="registry.cn-hangzhou.aliyuncs.com/openimsdk" -def "IMAGE_REGISTRY" "ghcr.io/openimsdk" -# def "IMAGE_REGISTRY" "openim" -# def "IMAGE_REGISTRY" "registry.cn-hangzhou.aliyuncs.com/openimsdk" - -# Choose the appropriate image tag, the default is the latest version -def "SERVER_IMAGE_TAG" "latest" - -###################### OpenIM Docker Network ###################### -# 设置 Docker 网络的网段 -readonly DOCKER_BRIDGE_SUBNET=${DOCKER_BRIDGE_SUBNET:-'172.28.0.0/16'} -IP_PREFIX=$(echo $DOCKER_BRIDGE_SUBNET | cut -d '/' -f 1) -SUBNET=$(echo $DOCKER_BRIDGE_SUBNET | cut -d '/' -f 2) -LAST_OCTET=$(echo $IP_PREFIX | cut -d '.' -f 4) - -generate_ip() { - local NEW_IP="$(echo $IP_PREFIX | cut -d '.' -f 1-3).$((LAST_OCTET++))" - echo $NEW_IP -} -LAST_OCTET=$((LAST_OCTET + 1)) -DOCKER_BRIDGE_GATEWAY=$(generate_ip) -LAST_OCTET=$((LAST_OCTET + 1)) -MONGO_NETWORK_ADDRESS=$(generate_ip) -LAST_OCTET=$((LAST_OCTET + 1)) -REDIS_NETWORK_ADDRESS=$(generate_ip) -LAST_OCTET=$((LAST_OCTET + 1)) -KAFKA_NETWORK_ADDRESS=$(generate_ip) -LAST_OCTET=$((LAST_OCTET + 1)) -ZOOKEEPER_NETWORK_ADDRESS=$(generate_ip) -LAST_OCTET=$((LAST_OCTET + 1)) -MINIO_NETWORK_ADDRESS=$(generate_ip) -LAST_OCTET=$((LAST_OCTET + 1)) -OPENIM_WEB_NETWORK_ADDRESS=$(generate_ip) -LAST_OCTET=$((LAST_OCTET + 1)) -OPENIM_SERVER_NETWORK_ADDRESS=$(generate_ip) -LAST_OCTET=$((LAST_OCTET + 1)) -OPENIM_CHAT_NETWORK_ADDRESS=$(generate_ip) -LAST_OCTET=$((LAST_OCTET + 1)) -PROMETHEUS_NETWORK_ADDRESS=$(generate_ip) -LAST_OCTET=$((LAST_OCTET + 1)) -GRAFANA_NETWORK_ADDRESS=$(generate_ip) -LAST_OCTET=$((LAST_OCTET + 1)) -NODE_EXPORTER_NETWORK_ADDRESS=$(generate_ip) -LAST_OCTET=$((LAST_OCTET + 1)) -OPENIM_ADMIN_FRONT_NETWORK_ADDRESS=$(generate_ip) -LAST_OCTET=$((LAST_OCTET + 1)) -ALERT_MANAGER_NETWORK_ADDRESS=$(generate_ip) -###################### openim 配置 ###################### -# read: https://github.com/openimsdk/open-im-server/blob/main/deployment/README.md -def "OPENIM_DATA_DIR" "/data/openim" -def "OPENIM_INSTALL_DIR" "/opt/openim" -def "OPENIM_CONFIG_DIR" "/etc/openim/config" -def "OPENIM_LOG_DIR" "/var/log/openim" -def "CA_FILE" "${OPENIM_CONFIG_DIR}/cert/ca.pem" - -def "OPNEIM_CONFIG" "${OPENIM_ROOT}/config" -def "OPENIM_SERVER_ADDRESS" "${DOCKER_BRIDGE_GATEWAY}" # OpenIM服务地址 - -# OpenIM Websocket端口 -readonly OPENIM_WS_PORT=${OPENIM_WS_PORT:-'10001'} - -# OpenIM API端口 -readonly API_OPENIM_PORT=${API_OPENIM_PORT:-'10002'} -def "API_LISTEN_IP" "0.0.0.0" # API的监听IP - -###################### openim-chat 配置信息 ###################### -def "OPENIM_CHAT_DATA_DIR" "./openim-chat/${CHAT_IMAGE_VERSION}" -def "OPENIM_CHAT_ADDRESS" "${DOCKER_BRIDGE_GATEWAY}" # OpenIM服务地址 -def "OPENIM_CHAT_API_PORT" "10008" # OpenIM API端口 -def "CHAT_API_LISTEN_IP" "" # OpenIM API的监听IP - -def "OPENIM_ADMIN_API_PORT" "10009" # OpenIM Admin API端口 -def "ADMIN_API_LISTEN_IP" "" # OpenIM Admin API的监听IP - -def "OPENIM_ADMIN_PORT" "30200" # OpenIM chat Admin端口 -def "OPENIM_CHAT_PORT" "30300" # OpenIM chat Admin的监听IP - -def "OPENIM_ADMIN_NAME" "admin" # openim-chat Admin用户名 -def "OPENIM_CHAT_NAME" "chat" # openim-chat chat用户名 - -# TODO 注意: 一般的配置都可以使用 def 函数来定义,如果是包含特殊字符,比如说: -# TODO readonly MSG_DESTRUCT_TIME=${MSG_DESTRUCT_TIME:-'0 2 * * *'} -# TODO 使用 readonly 来定义合适,负责无法正常解析, 并且 yaml 模板需要加 "" 来包裹 -###################### Env 配置信息 ###################### -def "ENVS_DISCOVERY" "zookeeper" - -###################### Zookeeper 配置信息 ###################### -def "ZOOKEEPER_SCHEMA" "openim" # Zookeeper的模式 -def "ZOOKEEPER_PORT" "12181" # Zookeeper的端口 -def "ZOOKEEPER_ADDRESS" "${DOCKER_BRIDGE_GATEWAY}" # Zookeeper的地址 -def "ZOOKEEPER_USERNAME" "" # Zookeeper的用户名 -def "ZOOKEEPER_PASSWORD" "" # Zookeeper的密码 - -###################### MongoDB 配置信息 ###################### -def "MONGO_URI" # MongoDB的URI -def "MONGO_PORT" "37017" # MongoDB的端口 -def "MONGO_ADDRESS" "${DOCKER_BRIDGE_GATEWAY}" # MongoDB的地址 -def "MONGO_DATABASE" "${DATABASE_NAME}" # MongoDB的数据库名 -def "MONGO_USERNAME" "root" # MongoDB的管理员身份用户名 -# MongoDB的管理员身份密码 -readonly MONGO_PASSWORD=${MONGO_PASSWORD:-"${PASSWORD}"} -# Mongo OpenIM 身份用户名 -def "MONGO_OPENIM_USERNAME" "openIM" -# Mongo OpenIM 身份密码 -readonly MONGO_OPENIM_PASSWORD=${MONGO_OPENIM_PASSWORD:-"${PASSWORD}"} - -def "MONGO_MAX_POOL_SIZE" "100" # 最大连接池大小 - -###################### Object 配置信息 ###################### -# app要能访问到此ip和端口或域名 -readonly API_URL=${API_URL:-"http://${OPENIM_IP}:${API_OPENIM_PORT}"} - -def "OBJECT_ENABLE" "minio" # 对象是否启用 -# 对象的API地址 -readonly OBJECT_APIURL=${OBJECT_APIURL:-"${API_URL}"} -def "MINIO_BUCKET" "openim" # MinIO的存储桶名称 -def "MINIO_PORT" "10005" # MinIO的端口 -# MinIO的端点URL -def MINIO_ADDRESS "${DOCKER_BRIDGE_GATEWAY}" -readonly MINIO_ENDPOINT=${MINIO_ENDPOINT:-"http://${MINIO_ADDRESS}:${MINIO_PORT}"} -def "MINIO_ACCESS_KEY" "${OPENIM_USER}" # MinIO的访问密钥ID -readonly MINIO_SECRET_KEY=${MINIO_SECRET_KEY:-"${PASSWORD}"} -def "MINIO_SESSION_TOKEN" # MinIO的会话令牌 -readonly MINIO_SIGN_ENDPOINT=${MINIO_SIGN_ENDPOINT:-"http://${OPENIM_IP}:${MINIO_PORT}"} # signEndpoint为minio公网地址 -def "MINIO_PUBLIC_READ" "false" # 公有读 - -# 腾讯云COS的存储桶URL -def "COS_BUCKET_URL" "https://temp-1252357374.cos.ap-chengdu.myqcloud.com" -def "COS_SECRET_ID" # 腾讯云COS的密钥ID -def "COS_SECRET_KEY" # 腾讯云COS的密钥 -def "COS_SESSION_TOKEN" # 腾讯云COS的会话令牌 -def "COS_PUBLIC_READ" "false" # 公有读 -def "OSS_ENDPOINT" "https://oss-cn-chengdu.aliyuncs.com" # 阿里云OSS的端点URL -def "OSS_BUCKET" "demo-9999999" # 阿里云OSS的存储桶名称 -def "OSS_BUCKET_URL" "https://demo-9999999.oss-cn-chengdu.aliyuncs.com" # 阿里云OSS的存储桶URL -def "OSS_ACCESS_KEY_ID" # 阿里云OSS的访问密钥ID -def "OSS_ACCESS_KEY_SECRET" # 阿里云OSS的密钥 -def "OSS_SESSION_TOKEN" # 阿里云OSS的会话令牌 -def "OSS_PUBLIC_READ" "false" # 公有读 - -#七牛云配置信息 -def "KODO_ENDPOINT" "http://s3.cn-east-1.qiniucs.com" # 七牛云OSS的端点URL -def "KODO_BUCKET" "demo-9999999" # 七牛云OSS的存储桶名称 -def "KODO_BUCKET_URL" "http://your.domain.com" # 七牛云OSS的存储桶URL -def "KODO_ACCESS_KEY_ID" # 七牛云OSS的访问密钥ID -def "KODO_ACCESS_KEY_SECRET" # 七牛云OSS的密钥 -def "KODO_SESSION_TOKEN" # 七牛云OSS的会话令牌 -def "KODO_PUBLIC_READ" "false" # 公有读 - -# AWS Configuration Information -def "AWS_ENDPOINT" "" # AWS endpoint, generally not needed unless using a specific service -def "AWS_REGION" "us-east-1" # AWS Region -def "AWS_BUCKET" "demo-9999999" # AWS S3 Bucket Name -def "AWS_ACCESS_KEY_ID" # AWS Access Key ID -def "AWS_SECRET_ACCESS_KEY" # AWS Secret Access Key -def "AWS_PUBLIC_READ" "false" # Public read access - -###################### Redis 配置信息 ###################### -def "REDIS_PORT" "16379" # Redis的端口 -def "REDIS_ADDRESS" "${DOCKER_BRIDGE_GATEWAY}" # Redis的地址 -def "REDIS_USERNAME" # Redis的用户名 -readonly REDIS_PASSWORD=${REDIS_PASSWORD:-"${PASSWORD}"} - -###################### Kafka 配置信息 ###################### -def "KAFKA_USERNAME" # `Kafka` 的用户名 -def "KAFKA_PASSWORD" # `Kafka` 的密码 -def "KAFKA_PORT" "19094" # `Kafka` 的端口 -def "KAFKA_ADDRESS" "${DOCKER_BRIDGE_GATEWAY}" # `Kafka` 的地址 -def "KAFKA_LATESTMSG_REDIS_TOPIC" "latestMsgToRedis" # `Kafka` 的最新消息到Redis的主题 -def "KAFKA_OFFLINEMSG_MONGO_TOPIC" "offlineMsgToMongoMysql" # `Kafka` 的离线消息到Mongo的主题 -def "KAFKA_MSG_PUSH_TOPIC" "msgToPush" # `Kafka` 的消息到推送的主题 -def "KAFKA_CONSUMERGROUPID_REDIS" "redis" # `Kafka` 的消费组ID到Redis -def "KAFKA_CONSUMERGROUPID_MONGO" "mongo" # `Kafka` 的消费组ID到Mongo -def "KAFKA_CONSUMERGROUPID_MYSQL" "mysql" # `Kafka` 的消费组ID到MySql -def "KAFKA_CONSUMERGROUPID_PUSH" "push" # `Kafka` 的消费组ID到推送 - -###################### openim-web 配置信息 ###################### -def "OPENIM_WEB_PORT" "11001" # openim-web的端口 - -###################### openim-admin-front 配置信息 ###################### -def "OPENIM_ADMIN_FRONT_PORT" "11002" # openim-admin-front的端口 - -###################### RPC 配置信息 ###################### -def "RPC_REGISTER_IP" # RPC的注册IP -def "RPC_LISTEN_IP" "0.0.0.0" # RPC的监听IP - -###################### prometheus 配置 ###################### -def "PROMETHEUS_PORT" "19090" # Prometheus的端口 -def "PROMETHEUS_ADDRESS" "${DOCKER_BRIDGE_GATEWAY}" # Prometheus的地址 - -###################### node-exporter 配置 ###################### -def "NODE_EXPORTER_PORT" "19100" # node-exporter的端口 -def "NODE_EXPORTER_ADDRESS" "${DOCKER_BRIDGE_GATEWAY}" # node-exporter的地址 - -###################### alertmanagerS 配置 ###################### -def "ALERT_MANAGER_PORT" "19093" # node-exporter的端口 -def "ALERT_MANAGER_ADDRESS" "${DOCKER_BRIDGE_GATEWAY}" # node-exporter的地址 - -###################### AlertManager Configuration Script ###################### -# 解析超时 -readonly ALERTMANAGER_RESOLVE_TIMEOUT=${ALERTMANAGER_RESOLVE_TIMEOUT:-'5m'} -# 发件人邮箱 -readonly ALERTMANAGER_SMTP_FROM=${ALERTMANAGER_SMTP_FROM:-'alert@openim.io'} -# SMTP服务器地址和端口 -readonly ALERTMANAGER_SMTP_SMARTHOST=${ALERTMANAGER_SMTP_SMARTHOST:-'smtp.163.com:465'} -# SMTP认证用户名 -readonly ALERTMANAGER_SMTP_AUTH_USERNAME=${SMTP_USERNAME:-"alert@openim.io"} -# SMTP认证密码 -readonly ALERTMANAGER_SMTP_AUTH_PASSWORD=${SMTP_PASSWORD:-"YOURAUTHPASSWORD"} -# SMTP是否需要TLS -readonly ALERTMANAGER_SMTP_REQUIRE_TLS=${ALERTMANAGER_SMTP_REQUIRE_TLS:-"false"} -# SMTP HELO/EHLO标识符 -readonly ALERTMANAGER_SMTP_HELLO=${ALERTMANAGER_SMTP_HELLO:-"xxx监控告警"} -# 邮箱接收人 -readonly ALERTMANAGER_EMAIL_TO=${ALERTMANAGER_EMAIL_TO:-"alert@example.com"} -# 邮箱主题 -readonly ALERTMANAGER_EMAIL_SUBJECT=${ALERTMANAGER_EMAIL_SUBJECT:-"{EMAIL_SUBJECT:-'[Alert] Notification'}"} -# 是否发送已解决的告警 -readonly ALERTMANAGER_SEND_RESOLVED=${ALERTMANAGER_SEND_RESOLVED:-"{SEND_RESOLVED:-'true'}"} - -###################### Grafana 配置信息 ###################### -def "GRAFANA_PORT" "13000" # Grafana的端口 -def "GRAFANA_ADDRESS" "${DOCKER_BRIDGE_GATEWAY}" # Grafana的地址 -###################### RPC Port Configuration Variables ###################### -# For launching multiple programs, just fill in multiple ports separated by commas -# For example: -# readonly OPENIM_USER_PORT=${OPENIM_USER_PORT:-'10110, 10111, 10112'} #Try not to have Spaces - -# OpenIM用户服务端口 -readonly OPENIM_USER_PORT=${OPENIM_USER_PORT:-'10110'} -# OpenIM朋友服务端口 -readonly OPENIM_FRIEND_PORT=${OPENIM_FRIEND_PORT:-'10120'} -# OpenIM消息服务端口 -readonly OPENIM_MESSAGE_PORT=${OPENIM_MESSAGE_PORT:-'10130'} -# OpenIM消息网关服务端口 -readonly OPENIM_MESSAGE_GATEWAY_PORT=${OPENIM_MESSAGE_GATEWAY_PORT:-'10140'} -# OpenIM组服务端口 -readonly OPENIM_GROUP_PORT=${OPENIM_GROUP_PORT:-'10150'} -# OpenIM授权服务端口 -readonly OPENIM_AUTH_PORT=${OPENIM_AUTH_PORT:-'10160'} -# OpenIM推送服务端口 -readonly OPENIM_PUSH_PORT=${OPENIM_PUSH_PORT:-'10170'} -# OpenIM对话服务端口 -readonly OPENIM_CONVERSATION_PORT=${OPENIM_CONVERSATION_PORT:-'10180'} -# OpenIM第三方服务端口 -readonly OPENIM_THIRD_PORT=${OPENIM_THIRD_PORT:-'10190'} - -###################### RPC Register Name Variables ###################### -def "OPENIM_USER_NAME" "User" # OpenIM用户服务名称 -def "OPENIM_FRIEND_NAME" "Friend" # OpenIM朋友服务名称 -def "OPENIM_MSG_NAME" "Msg" # OpenIM消息服务名称 -def "OPENIM_PUSH_NAME" "Push" # OpenIM推送服务名称 -def "OPENIM_MESSAGE_GATEWAY_NAME" "MessageGateway" # OpenIM消息网关服务名称 -def "OPENIM_GROUP_NAME" "Group" # OpenIM组服务名称 -def "OPENIM_AUTH_NAME" "Auth" # OpenIM授权服务名称 -def "OPENIM_CONVERSATION_NAME" "Conversation" # OpenIM对话服务名称 -def "OPENIM_THIRD_NAME" "Third" # OpenIM第三方服务名称 - -###################### Log Configuration Variables ###################### -def "LOG_STORAGE_LOCATION" "${OPENIM_ROOT}/_output/logs/" # 日志存储位置 -def "LOG_ROTATION_TIME" "24" # 日志轮替时间 -def "LOG_REMAIN_ROTATION_COUNT" "2" # 保留的日志轮替数量 -def "LOG_REMAIN_LOG_LEVEL" "6" # 保留的日志级别 -def "LOG_IS_STDOUT" "false" # 是否将日志输出到标准输出 -def "LOG_IS_JSON" "false" # 日志是否为JSON格式 -def "LOG_WITH_STACK" "false" # 日志是否带有堆栈信息 - -###################### Variables definition ###################### -def "WEBSOCKET_MAX_CONN_NUM" "100000" # Websocket最大连接数 -def "WEBSOCKET_MAX_MSG_LEN" "4096" # Websocket最大消息长度 -def "WEBSOCKET_TIMEOUT" "10" # Websocket超时 -def "PUSH_ENABLE" "getui" # 推送是否启用 -# GeTui推送URL -readonly GETUI_PUSH_URL=${GETUI_PUSH_URL:-'https://restapi.getui.com/v2/$appId'} -def "GETUI_MASTER_SECRET" "" # GeTui主密钥 -def "GETUI_APP_KEY" "" # GeTui应用密钥 -def "GETUI_INTENT" "" # GeTui推送意图 -def "GETUI_CHANNEL_ID" "" # GeTui渠道ID -def "GETUI_CHANNEL_NAME" "" # GeTui渠道名称 -def "FCM_SERVICE_ACCOUNT" "x.json" # FCM服务账户 -def "JPNS_APP_KEY" "" # JPNS应用密钥 -def "JPNS_MASTER_SECRET" "" # JPNS主密钥 -def "JPNS_PUSH_URL" "" # JPNS推送URL -def "JPNS_PUSH_INTENT" "" # JPNS推送意图 -def "IM_ADMIN_USERID" "imAdmin" # IM管理员ID -def "IM_ADMIN_NAME" "imAdmin" # IM管理员昵称 -def "MULTILOGIN_POLICY" "1" # 多登录策略 -def "CHAT_PERSISTENCE_MYSQL" "true" # 聊天持久化MySQL -def "MSG_CACHE_TIMEOUT" "86400" # 消息缓存超时 -def "GROUP_MSG_READ_RECEIPT" "true" # 群消息已读回执启用 -def "SINGLE_MSG_READ_RECEIPT" "true" # 单一消息已读回执启用 -def "RETAIN_CHAT_RECORDS" "365" # 保留聊天记录 -# 聊天记录清理时间 -readonly CHAT_RECORDS_CLEAR_TIME=${CHAT_RECORDS_CLEAR_TIME:-'0 2 * * 3'} -# 消息销毁时间 -readonly MSG_DESTRUCT_TIME=${MSG_DESTRUCT_TIME:-'0 2 * * *'} -# 密钥 -readonly SECRET=${SECRET:-"${PASSWORD}"} -def "TOKEN_EXPIRE" "90" # Token到期时间 -def "FRIEND_VERIFY" "false" # 朋友验证 -def "IOS_PUSH_SOUND" "xxx" # IOS推送声音 -def "IOS_BADGE_COUNT" "true" # IOS徽章计数 -def "IOS_PRODUCTION" "false" # IOS生产 -# callback 配置 -def "CALLBACK_ENABLE" "false" # 是否开启 Callback -def "CALLBACK_TIMEOUT" "5" # 最长超时时间 -def "CALLBACK_FAILED_CONTINUE" "true" # 失败后是否继续 -###################### Prometheus 配置信息 ###################### -# 是否启用 Prometheus -readonly PROMETHEUS_ENABLE=${PROMETHEUS_ENABLE:-'true'} -readonly GRAFANA_URL=${GRAFANA_URL:-"http://${OPENIM_IP}:${GRAFANA_PORT}/"} -# Api 服务的 Prometheus 端口 -readonly API_PROM_PORT=${API_PROM_PORT:-'20100'} -# User 服务的 Prometheus 端口 -readonly USER_PROM_PORT=${USER_PROM_PORT:-'20110'} -# Friend 服务的 Prometheus 端口 -readonly FRIEND_PROM_PORT=${FRIEND_PROM_PORT:-'20120'} -# Message 服务的 Prometheus 端口 -readonly MESSAGE_PROM_PORT=${MESSAGE_PROM_PORT:-'20130'} -# Message Gateway 服务的 Prometheus 端口 -readonly MSG_GATEWAY_PROM_PORT=${MSG_GATEWAY_PROM_PORT:-'20140'} -# Group 服务的 Prometheus 端口 -readonly GROUP_PROM_PORT=${GROUP_PROM_PORT:-'20150'} -# Auth 服务的 Prometheus 端口 -readonly AUTH_PROM_PORT=${AUTH_PROM_PORT:-'20160'} -# Push 服务的 Prometheus 端口 -readonly PUSH_PROM_PORT=${PUSH_PROM_PORT:-'20170'} -# Conversation 服务的 Prometheus 端口 -readonly CONVERSATION_PROM_PORT=${CONVERSATION_PROM_PORT:-'20230'} -# RTC 服务的 Prometheus 端口 -readonly RTC_PROM_PORT=${RTC_PROM_PORT:-'21300'} -# Third 服务的 Prometheus 端口 -readonly THIRD_PROM_PORT=${THIRD_PROM_PORT:-'21301'} - -# Message Transfer 服务的 Prometheus 端口列表 -readonly MSG_TRANSFER_PROM_PORT=${MSG_TRANSFER_PROM_PORT:-'21400, 21401, 21402, 21403'} -readonly MSG_TRANSFER_PROM_ADDRESS_PORT=${MSG_TRANSFER_PROM_ADDRESS_PORT:-"${DOCKER_BRIDGE_GATEWAY}:21400, ${DOCKER_BRIDGE_GATEWAY}:21401, ${DOCKER_BRIDGE_GATEWAY}:21402, ${DOCKER_BRIDGE_GATEWAY}:21403"} - -###################### OpenIM openim-api ###################### -def "OPENIM_API_HOST" "127.0.0.1" -def "OPENIM_API_BINARY" "${OPENIM_OUTPUT_HOSTBIN}/openim-api" # OpenIM openim-api 二进制文件路径 -def "OPENIM_API_CONFIG" "${OPENIM_ROOT}/config/" # OpenIM openim-api 配置文件路径 -def "OPENIM_API_LOG_DIR" "${LOG_STORAGE_LOCATION}/openim-api" # OpenIM openim-api 日志存储路径 -def "OPENIM_API_LOG_LEVEL" "info" # OpenIM openim-api 日志级别 -def "OPENIM_API_LOG_MAX_SIZE" "100" # OpenIM openim-api 日志最大大小(MB) -def "OPENIM_API_LOG_MAX_BACKUPS" "7" # OpenIM openim-api 日志最大备份数 -def "OPENIM_API_LOG_MAX_AGE" "7" # OpenIM openim-api 日志最大保存时间(天) -def "OPENIM_API_LOG_COMPRESS" "false" # OpenIM openim-api 日志是否压缩 -def "OPENIM_API_LOG_WITH_STACK" "${LOG_WITH_STACK}" # OpenIM openim-api 日志是否带有堆栈信息 - -###################### OpenIM openim-cmdutils ###################### -def "OPENIM_CMDUTILS_HOST" "127.0.0.1" -def "OPENIM_CMDUTILS_BINARY" "${OPENIM_OUTPUT_HOSTBIN}/openim-cmdutils" # OpenIM openim-cmdutils 二进制文件路径 -def "OPENIM_CMDUTILS_CONFIG" "${OPENIM_ROOT}/config/" # OpenIM openim-cmdutils 配置文件路径 -def "OPENIM_CMDUTILS_LOG_DIR" "${LOG_STORAGE_LOCATION}/openim-cmdutils" # OpenIM openim-cmdutils 日志存储路径 -def "OPENIM_CMDUTILS_LOG_LEVEL" "info" # OpenIM openim-cmdutils 日志级别 -def "OPENIM_CMDUTILS_LOG_MAX_SIZE" "100" # OpenIM openim-cmdutils 日志最大大小(MB) -def "OPENIM_CMDUTILS_LOG_MAX_BACKUPS" "7" # OpenIM openim-cmdutils 日志最大备份数 -def "OPENIM_CMDUTILS_LOG_MAX_AGE" "7" # OpenIM openim-cmdutils 日志最大保存时间(天) -def "OPENIM_CMDUTILS_LOG_COMPRESS" "false" # OpenIM openim-cmdutils 日志是否压缩 -def "OPENIM_CMDUTILS_LOG_WITH_STACK" "${LOG_WITH_STACK}" # OpenIM openim-cmdutils 日志是否带有堆栈信息 - -###################### OpenIM openim-crontask ###################### -def "OPENIM_CRONTASK_HOST" "127.0.0.1" -def "OPENIM_CRONTASK_BINARY" "${OPENIM_OUTPUT_HOSTBIN}/openim-crontask" # OpenIM openim-crontask 二进制文件路径 -def "OPENIM_CRONTASK_CONFIG" "${OPENIM_ROOT}/config/" # OpenIM openim-crontask 配置文件路径 -def "OPENIM_CRONTASK_LOG_DIR" "${LOG_STORAGE_LOCATION}/openim-crontask" # OpenIM openim-crontask 日志存储路径 -def "OPENIM_CRONTASK_LOG_LEVEL" "info" # OpenIM openim-crontask 日志级别 -def "OPENIM_CRONTASK_LOG_MAX_SIZE" "100" # OpenIM openim-crontask 日志最大大小(MB) -def "OPENIM_CRONTASK_LOG_MAX_BACKUPS" "7" # OpenIM openim-crontask 日志最大备份数 -def "OPENIM_CRONTASK_LOG_MAX_AGE" "7" # OpenIM openim-crontask 日志最大保存时间(天) -def "OPENIM_CRONTASK_LOG_COMPRESS" "false" # OpenIM openim-crontask 日志是否压缩 -def "OPENIM_CRONTASK_LOG_WITH_STACK" "${LOG_WITH_STACK}" # OpenIM openim-crontask 日志是否带有堆栈信息 - -###################### OpenIM openim-msggateway ###################### -def "OPENIM_MSGGATEWAY_HOST" "127.0.0.1" -def "OPENIM_MSGGATEWAY_BINARY" "${OPENIM_OUTPUT_HOSTBIN}/openim-msggateway" -def "OPENIM_MSGGATEWAY_CONFIG" "${OPENIM_ROOT}/config/" -def "OPENIM_MSGGATEWAY_LOG_DIR" "${LOG_STORAGE_LOCATION}/openim-msggateway" -def "OPENIM_MSGGATEWAY_LOG_LEVEL" "info" -def "OPENIM_MSGGATEWAY_LOG_MAX_SIZE" "100" -def "OPENIM_MSGGATEWAY_LOG_MAX_BACKUPS" "7" -def "OPENIM_MSGGATEWAY_LOG_MAX_AGE" "7" -def "OPENIM_MSGGATEWAY_LOG_COMPRESS" "false" -def "OPENIM_MSGGATEWAY_LOG_WITH_STACK" "${LOG_WITH_STACK}" - -# 定义 openim-msggateway 的数量, 默认为 4 -readonly OPENIM_MSGGATEWAY_NUM=${OPENIM_MSGGATEWAY_NUM:-'4'} - -###################### OpenIM openim-msgtransfer ###################### -def "OPENIM_MSGTRANSFER_HOST" "127.0.0.1" -def "OPENIM_MSGTRANSFER_BINARY" "${OPENIM_OUTPUT_HOSTBIN}/openim-msgtransfer" # OpenIM openim-msgtransfer 二进制文件路径 -def "OPENIM_MSGTRANSFER_CONFIG" "${OPENIM_ROOT}/config/" # OpenIM openim-msgtransfer 配置文件路径 -def "OPENIM_MSGTRANSFER_LOG_DIR" "${LOG_STORAGE_LOCATION}/openim-msgtransfer" # OpenIM openim-msgtransfer 日志存储路径 -def "OPENIM_MSGTRANSFER_LOG_LEVEL" "info" # OpenIM openim-msgtransfer 日志级别 -def "OPENIM_MSGTRANSFER_LOG_MAX_SIZE" "100" # OpenIM openim-msgtransfer 日志最大大小(MB) -def "OPENIM_MSGTRANSFER_LOG_MAX_BACKUPS" "7" # OpenIM openim-msgtransfer 日志最大备份数 -def "OPENIM_MSGTRANSFER_LOG_MAX_AGE" "7" # OpenIM openim-msgtransfer 日志最大保存时间(天) -def "OPENIM_MSGTRANSFER_LOG_COMPRESS" "false" # OpenIM openim-msgtransfer 日志是否压缩 -def "OPENIM_MSGTRANSFER_LOG_WITH_STACK" "${LOG_WITH_STACK}" # OpenIM openim-msgtransfer 日志是否带有堆栈信息 - -###################### OpenIM openim-push ###################### -def "OPENIM_PUSH_HOST" "127.0.0.1" -def "OPENIM_PUSH_BINARY" "${OPENIM_OUTPUT_HOSTBIN}/openim-push" # OpenIM openim-push 二进制文件路径 -def "OPENIM_PUSH_CONFIG" "${OPENIM_ROOT}/config/" # OpenIM openim-push 配置文件路径 -def "OPENIM_PUSH_LOG_DIR" "${LOG_STORAGE_LOCATION}/openim-push" # OpenIM openim-push 日志存储路径 -def "OPENIM_PUSH_LOG_LEVEL" "info" # OpenIM openim-push 日志级别 -def "OPENIM_PUSH_LOG_MAX_SIZE" "100" # OpenIM openim-push 日志最大大小(MB) -def "OPENIM_PUSH_LOG_MAX_BACKUPS" "7" # OpenIM openim-push 日志最大备份数 -def "OPENIM_PUSH_LOG_MAX_AGE" "7" # OpenIM openim-push 日志最大保存时间(天) -def "OPENIM_PUSH_LOG_COMPRESS" "false" # OpenIM openim-push 日志是否压缩 -def "OPENIM_PUSH_LOG_WITH_STACK" "${LOG_WITH_STACK}" # OpenIM openim-push 日志是否带有堆栈信息 - -###################### OpenIM openim-rpc-auth ###################### -def "OPENIM_RPC_AUTH_HOST" "127.0.0.1" -def "OPENIM_RPC_AUTH_BINARY" "${OPENIM_OUTPUT_HOSTBIN}/openim-rpc-auth" # OpenIM openim-rpc-auth 二进制文件路径 -def "OPENIM_RPC_AUTH_CONFIG" "${OPENIM_ROOT}/config/" # OpenIM openim-rpc-auth 配置文件路径 -def "OPENIM_RPC_AUTH_LOG_DIR" "${LOG_STORAGE_LOCATION}/openim-rpc-auth" # OpenIM openim-rpc-auth 日志存储路径 -def "OPENIM_RPC_AUTH_LOG_LEVEL" "info" # OpenIM openim-rpc-auth 日志级别 -def "OPENIM_RPC_AUTH_LOG_MAX_SIZE" "100" # OpenIM openim-rpc-auth 日志最大大小(MB) -def "OPENIM_RPC_AUTH_LOG_MAX_BACKUPS" "7" # OpenIM openim-rpc-auth 日志最大备份数 -def "OPENIM_RPC_AUTH_LOG_MAX_AGE" "7" # OpenIM openim-rpc-auth 日志最大保存时间(天) -def "OPENIM_RPC_AUTH_LOG_COMPRESS" "false" # OpenIM openim-rpc-auth 日志是否压缩 -def "OPENIM_RPC_AUTH_LOG_WITH_STACK" "${LOG_WITH_STACK}" # OpenIM openim-rpc-auth 日志是否带有堆栈信息 - -###################### OpenIM openim-rpc-conversation ###################### -def "OPENIM_RPC_CONVERSATION_HOST" "127.0.0.1" -def "OPENIM_RPC_CONVERSATION_BINARY" "${OPENIM_OUTPUT_HOSTBIN}/openim-rpc-conversation" # OpenIM openim-rpc-conversation 二进制文件路径 -def "OPENIM_RPC_CONVERSATION_CONFIG" "${OPENIM_ROOT}/config/" # OpenIM openim-rpc-conversation 配置文件路径 -def "OPENIM_RPC_CONVERSATION_LOG_DIR" "${LOG_STORAGE_LOCATION}/openim-rpc-conversation" # OpenIM openim-rpc-conversation 日志存储路径 -def "OPENIM_RPC_CONVERSATION_LOG_LEVEL" "info" # OpenIM openim-rpc-conversation 日志级别 -def "OPENIM_RPC_CONVERSATION_LOG_MAX_SIZE" "100" # OpenIM openim-rpc-conversation 日志最大大小(MB) -def "OPENIM_RPC_CONVERSATION_LOG_MAX_BACKUPS" "7" # OpenIM openim-rpc-conversation 日志最大备份数 -def "OPENIM_RPC_CONVERSATION_LOG_MAX_AGE" "7" # OpenIM openim-rpc-conversation 日志最大保存时间(天) -def "OPENIM_RPC_CONVERSATION_LOG_COMPRESS" "false" # OpenIM openim-rpc-conversation 日志是否压缩 -def "OPENIM_RPC_CONVERSATION_LOG_WITH_STACK" "${LOG_WITH_STACK}" # OpenIM openim-rpc-conversation 日志是否带有堆栈信息 - -###################### OpenIM openim-rpc-friend ###################### -def "OPENIM_RPC_FRIEND_HOST" "127.0.0.1" -def "OPENIM_RPC_FRIEND_BINARY" "${OPENIM_OUTPUT_HOSTBIN}/openim-rpc-friend" # OpenIM openim-rpc-friend 二进制文件路径 -def "OPENIM_RPC_FRIEND_CONFIG" "${OPENIM_ROOT}/config/" # OpenIM openim-rpc-friend 配置文件路径 -def "OPENIM_RPC_FRIEND_LOG_DIR" "${LOG_STORAGE_LOCATION}/openim-rpc-friend" # OpenIM openim-rpc-friend 日志存储路径 -def "OPENIM_RPC_FRIEND_LOG_LEVEL" "info" # OpenIM openim-rpc-friend 日志级别 -def "OPENIM_RPC_FRIEND_LOG_MAX_SIZE" "100" # OpenIM openim-rpc-friend 日志最大大小(MB) -def "OPENIM_RPC_FRIEND_LOG_MAX_BACKUPS" "7" # OpenIM openim-rpc-friend 日志最大备份数 -def "OPENIM_RPC_FRIEND_LOG_MAX_AGE" "7" # OpenIM openim-rpc-friend 日志最大保存时间(天) -def "OPENIM_RPC_FRIEND_LOG_COMPRESS" "false" # OpenIM openim-rpc-friend 日志是否压缩 -def "OPENIM_RPC_FRIEND_LOG_WITH_STACK" "${LOG_WITH_STACK}" # OpenIM openim-rpc-friend 日志是否带有堆栈信息 - -###################### OpenIM openim-rpc-group ###################### -def "OPENIM_RPC_GROUP_HOST" "127.0.0.1" -def "OPENIM_RPC_GROUP_BINARY" "${OPENIM_OUTPUT_HOSTBIN}/openim-rpc-group" # OpenIM openim-rpc-group 二进制文件路径 -def "OPENIM_RPC_GROUP_CONFIG" "${OPENIM_ROOT}/config/" # OpenIM openim-rpc-group 配置文件路径 -def "OPENIM_RPC_GROUP_LOG_DIR" "${LOG_STORAGE_LOCATION}/openim-rpc-group" # OpenIM openim-rpc-group 日志存储路径 -def "OPENIM_RPC_GROUP_LOG_LEVEL" "info" # OpenIM openim-rpc-group 日志级别 -def "OPENIM_RPC_GROUP_LOG_MAX_SIZE" "100" # OpenIM openim-rpc-group 日志最大大小(MB) -def "OPENIM_RPC_GROUP_LOG_MAX_BACKUPS" "7" # OpenIM openim-rpc-group 日志最大备份数 -def "OPENIM_RPC_GROUP_LOG_MAX_AGE" "7" # OpenIM openim-rpc-group 日志最大保存时间(天) -def "OPENIM_RPC_GROUP_LOG_COMPRESS" "false" # OpenIM openim-rpc-group 日志是否压缩 -def "OPENIM_RPC_GROUP_LOG_WITH_STACK" "${LOG_WITH_STACK}" # OpenIM openim-rpc-group 日志是否带有堆栈信息 - -###################### OpenIM openim-rpc-msg ###################### -def "OPENIM_RPC_MSG_HOST" "127.0.0.1" -def "OPENIM_RPC_MSG_BINARY" "${OPENIM_OUTPUT_HOSTBIN}/openim-rpc-msg" # OpenIM openim-rpc-msg 二进制文件路径 -def "OPENIM_RPC_MSG_CONFIG" "${OPENIM_ROOT}/config/" # OpenIM openim-rpc-msg 配置文件路径 -def "OPENIM_RPC_MSG_LOG_DIR" "${LOG_STORAGE_LOCATION}/openim-rpc-msg" # OpenIM openim-rpc-msg 日志存储路径 -def "OPENIM_RPC_MSG_LOG_LEVEL" "info" # OpenIM openim-rpc-msg 日志级别 -def "OPENIM_RPC_MSG_LOG_MAX_SIZE" "100" # OpenIM openim-rpc-msg 日志最大大小(MB) -def "OPENIM_RPC_MSG_LOG_MAX_BACKUPS" "7" # OpenIM openim-rpc-msg 日志最大备份数 -def "OPENIM_RPC_MSG_LOG_MAX_AGE" "7" # OpenIM openim-rpc-msg 日志最大保存时间(天) -def "OPENIM_RPC_MSG_LOG_COMPRESS" "false" # OpenIM openim-rpc-msg 日志是否压缩 -def "OPENIM_RPC_MSG_LOG_WITH_STACK" "${LOG_WITH_STACK}" # OpenIM openim-rpc-msg 日志是否带有堆栈信息 - -###################### OpenIM openim-rpc-third ###################### -def "OPENIM_RPC_THIRD_HOST" "127.0.0.1" -def "OPENIM_RPC_THIRD_BINARY" "${OPENIM_OUTPUT_HOSTBIN}/openim-rpc-third" # OpenIM openim-rpc-third 二进制文件路径 -def "OPENIM_RPC_THIRD_CONFIG" "${OPENIM_ROOT}/config/" # OpenIM openim-rpc-third 配置文件路径 -def "OPENIM_RPC_THIRD_LOG_DIR" "${LOG_STORAGE_LOCATION}/openim-rpc-third" # OpenIM openim-rpc-third 日志存储路径 -def "OPENIM_RPC_THIRD_LOG_LEVEL" "info" # OpenIM openim-rpc-third 日志级别 -def "OPENIM_RPC_THIRD_LOG_MAX_SIZE" "100" # OpenIM openim-rpc-third 日志最大大小(MB) -def "OPENIM_RPC_THIRD_LOG_MAX_BACKUPS" "7" # OpenIM openim-rpc-third 日志最大备份数 -def "OPENIM_RPC_THIRD_LOG_MAX_AGE" "7" # OpenIM openim-rpc-third 日志最大保存时间(天) -def "OPENIM_RPC_THIRD_LOG_COMPRESS" "false" # OpenIM openim-rpc-third 日志是否压缩 -def "OPENIM_RPC_THIRD_LOG_WITH_STACK" "${LOG_WITH_STACK}" # OpenIM openim-rpc-third 日志是否带有堆栈信息 - -###################### OpenIM openim-rpc-user ###################### -def "OPENIM_RPC_USER_HOST" "127.0.0.1" -def "OPENIM_RPC_USER_BINARY" "${OPENIM_OUTPUT_HOSTBIN}/openim-rpc-user" # OpenIM openim-rpc-user 二进制文件路径 -def "OPENIM_RPC_USER_CONFIG" "${OPENIM_ROOT}/config/" # OpenIM openim-rpc-user 配置文件路径 -def "OPENIM_RPC_USER_LOG_DIR" "${LOG_STORAGE_LOCATION}/openim-rpc-user" # OpenIM openim-rpc-user 日志存储路径 -def "OPENIM_RPC_USER_LOG_LEVEL" "info" # OpenIM openim-rpc-user 日志级别 -def "OPENIM_RPC_USER_LOG_MAX_SIZE" "100" # OpenIM openim-rpc-user 日志最大大小(MB) -def "OPENIM_RPC_USER_LOG_MAX_BACKUPS" "7" # OpenIM openim-rpc-user 日志最大备份数 -def "OPENIM_RPC_USER_LOG_MAX_AGE" "7" # OpenIM openim-rpc-user 日志最大保存时间(天) -def "OPENIM_RPC_USER_LOG_COMPRESS" "false" # OpenIM openim-rpc-user 日志是否压缩 -def "OPENIM_RPC_USER_LOG_WITH_STACK" "${LOG_WITH_STACK}" # OpenIM openim-rpc-user 日志是否带有堆栈信息 - -###################### 设计中...暂时不需要###################### - -# openimctl 配置 -def "CONFIG_USER_USERNAME" "admin" -def "CONFIG_USER_PASSWORD" "Admin@2021" -def "CONFIG_USER_CLIENT_CERTIFICATE" "${HOME}/.openim/cert/admin.pem" -def "CONFIG_USER_CLIENT_KEY" "${HOME}/.openim/cert/admin-key.pem" -def "CONFIG_SERVER_ADDRESS" "${OPENIM_APISERVER_HOST}:${OPENIM_APISERVER_SECURE_BIND_PORT}" -def "CONFIG_SERVER_CERTIFICATE_AUTHORITY" "${CA_FILE}" diff --git a/scripts/install/install-protobuf.sh b/scripts/install/install-protobuf.sh deleted file mode 100755 index 838b390b50..0000000000 --- a/scripts/install/install-protobuf.sh +++ /dev/null @@ -1,118 +0,0 @@ -#!/usr/bin/env bash -# 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. - - -# -------------------------------------------------------------- -# OpenIM Protoc Tool v1.0.0 -# -------------------------------------------------------------- -# OpenIM has released its custom Protoc tool version v1.0.0. -# This tool is customized to meet the specific needs of OpenIM and resides in its separate repository. -# It can be downloaded from the following link: -# https://github.com/OpenIMSDK/Open-IM-Protoc/releases/tag/v1.0.0 -# -# About the tool: -# https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/protoc-tools.md -# Download link (Windows): https://github.com/OpenIMSDK/Open-IM-Protoc/releases/download/v1.0.0/windows.zip -# Download link (Linux): https://github.com/OpenIMSDK/Open-IM-Protoc/releases/download/v1.0.0/linux.zip -# -# Installation steps (taking Windows as an example): -# 1. Visit the above link and download the version suitable for Windows. -# 2. Extract the downloaded file. -# 3. Add the extracted tool to your PATH environment variable so that it can be run directly from the command line. -# -# Note: The specific installation and usage instructions may vary based on the tool's actual implementation. It's advised to refer to official documentation. -# -------------------------------------------------------------- - -PROTOC_DOWNLOAD_URL="https://github.com/OpenIMSDK/Open-IM-Protoc/releases/download/v1.0.0/linux.zip" -DOWNLOAD_DIR="/tmp/openim-protoc" -INSTALL_DIR="/usr/local/bin" - -function help_message { - echo "Usage: ./install-protobuf.sh [option]" - echo "Options:" - echo "-i, --install Install the OpenIM Protoc tool." - echo "-u, --uninstall Uninstall the OpenIM Protoc tool." - echo "-r, --reinstall Reinstall the OpenIM Protoc tool." - echo "-c, --check Check if the OpenIM Protoc tool is installed." - echo "-h, --help Display this help message." -} - -function install_protobuf { - echo "Installing OpenIM Protoc tool..." - - # Create temporary directory and download the zip file - mkdir -p $DOWNLOAD_DIR - wget $PROTOC_DOWNLOAD_URL -O $DOWNLOAD_DIR/linux.zip - - # Unzip the file - unzip -o $DOWNLOAD_DIR/linux.zip -d $DOWNLOAD_DIR - - # Move binaries to the install directory and make them executable - sudo cp $DOWNLOAD_DIR/linux/protoc $INSTALL_DIR/ - sudo cp $DOWNLOAD_DIR/linux/protoc-gen-go $INSTALL_DIR/ - sudo chmod +x $INSTALL_DIR/protoc - sudo chmod +x $INSTALL_DIR/protoc-gen-go - - # Clean up - rm -rf $DOWNLOAD_DIR - - echo "OpenIM Protoc tool installed successfully!" -} - -function uninstall_protobuf { - echo "Uninstalling OpenIM Protoc tool..." - - # Removing binaries from the install directory - sudo rm -f $INSTALL_DIR/protoc - sudo rm -f $INSTALL_DIR/protoc-gen-go - - echo "OpenIM Protoc tool uninstalled successfully!" -} - -function reinstall_protobuf { - echo "Reinstalling OpenIM Protoc tool..." - uninstall_protobuf - install_protobuf -} - -function check_protobuf { - echo "Checking for OpenIM Protoc tool installation..." - - which protoc > /dev/null 2>&1 - if [ $? -eq 0 ]; then - echo "OpenIM Protoc tool is installed." - else - echo "OpenIM Protoc tool is not installed." - fi -} - -while [ "$1" != "" ]; do - case $1 in - -i | --install ) install_protobuf - ;; - -u | --uninstall ) uninstall_protobuf - ;; - -r | --reinstall ) reinstall_protobuf - ;; - -c | --check ) check_protobuf - ;; - -h | --help ) help_message - exit - ;; - * ) help_message - exit 1 - esac - shift -done diff --git a/scripts/install/install.sh b/scripts/install/install.sh deleted file mode 100755 index bb09675bfd..0000000000 --- a/scripts/install/install.sh +++ /dev/null @@ -1,155 +0,0 @@ -#!/usr/bin/env bash -# 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. -# -# OpenIM Server Installation Script -# -# Description: -# This script is designed to handle the installation, Is a deployment solution -# that uses the Linux systen extension. uninstallation, and -# status checking of OpenIM components on the server. OpenIM is a presumed -# communication or messaging platform based on the context. -# -# Usage: -# To utilize this script, you need to invoke it with specific commands -# and options as detailed below. -# -# Commands: -# -i, --install : Use this command to initiate the installation of all -# OpenIM components. -# -u, --uninstall : Use this command to uninstall or remove all -# OpenIM components from the server. -# -s, --status : This command can be used to check and report the -# current operational status of the installed OpenIM components. -# -h, --help : For any assistance or to view the available commands, -# use this command to display the help menu. -# -# Example Usage: -# To install all OpenIM components: -# ./scripts/install/install.sh -i -# or -# ./scripts/install/install.sh --install -# -# Note: -# Ensure you have the necessary privileges to execute installation or -# uninstallation operations. It's generally recommended to take a backup -# before making major changes. -# -############################################################################### - -OPENIM_ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")"/../.. && pwd -P) -[[ -z ${COMMON_SOURCED} ]] && source "${OPENIM_ROOT}"/scripts/install/common.sh - -${OPENIM_ROOT}/scripts/install/openim-man.sh -${OPENIM_ROOT}/scripts/install/openim-tools.sh -${OPENIM_ROOT}/scripts/install/test.sh - -# Detailed help function -function openim::install::show_help() { - echo "OpenIM Installer" - echo "Usage: $0 [options]" - echo "" - echo "Commands:" - echo " -i, --install Install all OpenIM components." - echo " -u, --uninstall Remove all OpenIM components." - echo " -s, --status Check the current status of OpenIM components." - echo " -h, --help Show this help menu." - echo "" - echo "Example: " - echo " $0 -i Will install all OpenIM components." - echo " $0 --install Same as above." -} - -function openim::install::install_openim() { - openim::common::sudo "mkdir -p ${OPENIM_DATA_DIR} ${OPENIM_INSTALL_DIR} ${OPENIM_CONFIG_DIR} ${OPENIM_LOG_DIR}" - openim::log::info "check openim dependency" - openim::common::sudo "cp -r ${OPENIM_ROOT}/config/* ${OPENIM_CONFIG_DIR}/" - - ${OPENIM_ROOT}/scripts/genconfig.sh ${ENV_FILE} ${OPENIM_ROOT}/deployments/templates/config.yaml > ${OPENIM_CONFIG_DIR}/config.yaml - ${OPENIM_ROOT}/scripts/genconfig.sh ${ENV_FILE} ${OPENIM_ROOT}/deployments/templates/prometheus.yml > ${OPENIM_CONFIG_DIR}/prometheus.yml - - openim::util::check_ports ${OPENIM_DEPENDENCY_PORT_LISTARIES[@]} - - ${OPENIM_ROOT}/scripts/install/openim-msggateway.sh openim::msggateway::install || return 1 - ${OPENIM_ROOT}/scripts/install/openim-msgtransfer.sh openim::msgtransfer::install || return 1 - ${OPENIM_ROOT}/scripts/install/openim-push.sh openim::push::install || return 1 - ${OPENIM_ROOT}/scripts/install/openim-crontask.sh openim::crontask::install || return 1 - ${OPENIM_ROOT}/scripts/install/openim-rpc.sh openim::rpc::install || return 1 - ${OPENIM_ROOT}/scripts/install/openim-api.sh openim::api::install || return 1 - - openim::common::sudo "cp -r ${OPENIM_ROOT}/deployments/templates/openim.target /etc/systemd/system/openim.target" - openim::common::sudo "systemctl daemon-reload" - openim::common::sudo "systemctl restart openim.target" - openim::common::sudo "systemctl enable openim.target" - openim::log::success "openim install success" -} - -function openim::uninstall::uninstall_openim() { - openim::log::info "uninstall openim" - - ${OPENIM_ROOT}/scripts/install/openim-msggateway.sh openim::msggateway::uninstall || return 1 - ${OPENIM_ROOT}/scripts/install/openim-msgtransfer.sh openim::msgtransfer::uninstall || return 1 - ${OPENIM_ROOT}/scripts/install/openim-push.sh openim::push::uninstall || return 1 - ${OPENIM_ROOT}/scripts/install/openim-crontask.sh openim::crontask::uninstall || return 1 - ${OPENIM_ROOT}/scripts/install/openim-rpc.sh openim::rpc::uninstall || return 1 - ${OPENIM_ROOT}/scripts/install/openim-api.sh openim::api::uninstall || return 1 - - set +o errexit - openim::common::sudo "systemctl stop openim.target" - openim::common::sudo "systemctl disable openim.target" - openim::common::sudo "rm -f /etc/systemd/system/openim.target" - - openim::log::success "openim uninstall success" -} - -function openim::install::status() { - openim::log::info "check openim status" - - ${OPENIM_ROOT}/scripts/install/openim-msggateway.sh openim::msggateway::status || return 1 - ${OPENIM_ROOT}/scripts/install/openim-msgtransfer.sh openim::msgtransfer::status || return 1 - ${OPENIM_ROOT}/scripts/install/openim-push.sh openim::push::status || return 1 - ${OPENIM_ROOT}/scripts/install/openim-crontask.sh openim::crontask::status || return 1 - ${OPENIM_ROOT}/scripts/install/openim-rpc.sh openim::rpc::status || return 1 - ${OPENIM_ROOT}/scripts/install/openim-api.sh openim::api::status || return 1 - - openim::log::success "openim status success" -} - -# If no arguments are provided, show help -if [[ $# -eq 0 ]]; then - openim::install::show_help - exit 0 -fi - -# Argument parsing to call functions based on user input -while (( "$#" )); do - case "$1" in - -i|--install) - openim::install::install_openim - shift - ;; - -u|--uninstall) - openim::uninstall::uninstall_openim - shift - ;; - -s|--status) - openim::install::status - shift - ;; - -h|--help|*) - openim::install::show_help - exit 0 - ;; - esac -done \ No newline at end of file diff --git a/scripts/install/openim-api.sh b/scripts/install/openim-api.sh deleted file mode 100755 index 8403382e6a..0000000000 --- a/scripts/install/openim-api.sh +++ /dev/null @@ -1,169 +0,0 @@ -#!/usr/bin/env bash - -# 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. - - - - - -OPENIM_ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")"/../.. && pwd -P) -[[ -z ${COMMON_SOURCED} ]] && source "${OPENIM_ROOT}"/scripts/install/common.sh - -SERVER_NAME="openim-api" - -readonly OPENIM_API_PORT_TARGETS=( - ${API_OPENIM_PORT} -) -readonly OPENIM_API_PORT_LISTARIES=("${OPENIM_API_PORT_TARGETS[@]##*/}") - -readonly OPENIM_API_SERVICE_TARGETS=( - openim-api -) -readonly OPENIM_API_SERVICE_LISTARIES=("${OPENIM_API_SERVICE_TARGETS[@]##*/}") - -readonly OPENIM_API_PROMETHEUS_PORT_TARGETS=( - ${API_PROM_PORT} -) -readonly OPENIM_API_PROMETHEUS_PORT_LISTARIES=("${OPENIM_API_PROMETHEUS_PORT_TARGETS[@]##*/}") - -function openim::api::start() { - rm -rf "$TMP_LOG_FILE" - - echo "++ OPENIM_API_SERVICE_LISTARIES: ${OPENIM_API_SERVICE_LISTARIES[@]}" - echo "++ OPENIM_API_PORT_LISTARIES: ${OPENIM_API_PORT_LISTARIES[@]}" - echo "++ OpenIM API config path: ${OPENIM_API_CONFIG}" - - openim::log::info "Starting ${SERVER_NAME} ..." - - readonly OPENIM_API_SERVER_LIBRARIES="${OPENIM_OUTPUT_HOSTBIN}/${SERVER_NAME}" - - - printf "+------------------------+--------------+\n" - printf "| Service Name | Port |\n" - printf "+------------------------+--------------+\n" - - - local length=${#OPENIM_API_SERVICE_LISTARIES[@]} - for ((i=0; i> "${LOG_FILE}" 2> >(tee -a "${STDERR_LOG_FILE}" "$TMP_LOG_FILE" >&2) & - nohup ${cmd} >> "${LOG_FILE}" 2> >(tee -a "$TMP_LOG_FILE" | while read line; do echo -e "\e[31m${line}\e[0m"; done >&2) >> "${LOG_FILE}" 2>&1 & - if [ $? -ne 0 ]; then - openim::log::error_exit "Failed to start ${binary_name} on port ${service_port}." - return 1 - fi - return 0 -} - -###################################### Linux Systemd ###################################### -SYSTEM_FILE_PATH="/etc/systemd/system/${SERVER_NAME}.service" - -# Print the necessary information after installation -function openim::api::info() { -cat << EOF -openim-api listen on: ${OPENIM_API_HOST}:${API_OPENIM_PORT} -EOF -} - -# install openim-api -function openim::api::install() { - openim::log::info "Installing ${SERVER_NAME} ..." - - pushd "${OPENIM_ROOT}" - - # 1. Build openim-api - make build BINS=${SERVER_NAME} - openim::common::sudo "cp -r ${OPENIM_OUTPUT_HOSTBIN}/${SERVER_NAME} ${OPENIM_INSTALL_DIR}/${SERVER_NAME}" - openim::log::status "${SERVER_NAME} binary: ${OPENIM_INSTALL_DIR}/${SERVER_NAME}/${SERVER_NAME}" - - # 2. Generate and install the openim-api configuration file (config) - openim::log::status "${SERVER_NAME} config file: ${OPENIM_CONFIG_DIR}/config.yaml" - - # 3. Create and install the ${SERVER_NAME} systemd unit file - echo ${LINUX_PASSWORD} | sudo -S bash -c \ - "SERVER_NAME=${SERVER_NAME} ./scripts/genconfig.sh ${ENV_FILE} deployments/templates/openim.service > ${SYSTEM_FILE_PATH}" - openim::log::status "${SERVER_NAME} systemd file: ${SYSTEM_FILE_PATH}" - - # 4. Start the openim-api service - openim::common::sudo "systemctl daemon-reload" - openim::common::sudo "systemctl restart ${SERVER_NAME}" - openim::common::sudo "systemctl enable ${SERVER_NAME}" - openim::api::status || return 1 - openim::api::info - - openim::log::info "install ${SERVER_NAME} successfully" - popd -} - -# Unload -function openim::api::uninstall() { - openim::log::info "Uninstalling ${SERVER_NAME} ..." - - set +o errexit - openim::common::sudo "systemctl stop ${SERVER_NAME}" - openim::common::sudo "systemctl disable ${SERVER_NAME}" - openim::common::sudo "rm -f ${OPENIM_INSTALL_DIR}/${SERVER_NAME}" - openim::common::sudo "rm -f ${OPENIM_CONFIG_DIR}/${SERVER_NAME}.yaml" - openim::common::sudo "rm -f /etc/systemd/system/${SERVER_NAME}.service" - - openim::log::info "uninstall ${SERVER_NAME} successfully" -} - -# Status Check -function openim::api::status() { - openim::log::info "Checking ${SERVER_NAME} status ..." - - # Check the running status of the ${SERVER_NAME}. If active (running) is displayed, the ${SERVER_NAME} is started successfully. - systemctl status ${SERVER_NAME}|grep -q 'active' || { - openim::log::error "${SERVER_NAME} failed to start, maybe not installed properly" - return 1 - } - - openim::util::check_ports ${OPENIM_API_PORT_LISTARIES[@]} -} - -if [[ "$*" =~ openim::api:: ]];then - eval $* -fi diff --git a/scripts/install/openim-crontask.sh b/scripts/install/openim-crontask.sh deleted file mode 100755 index d785b37a4e..0000000000 --- a/scripts/install/openim-crontask.sh +++ /dev/null @@ -1,126 +0,0 @@ -#!/usr/bin/env bash - -# 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. -# -# OpenIM CronTask Control Script -# -# Description: -# This script provides a control interface for the OpenIM CronTask service within a Linux environment. It supports two installation methods: installation via function calls to systemctl, and direct installation through background processes. -# -# Features: -# 1. Robust error handling leveraging Bash built-ins such as 'errexit', 'nounset', and 'pipefail'. -# 2. Capability to source common utility functions and configurations, ensuring environmental consistency. -# 3. Comprehensive logging tools, offering clear operational insights. -# 4. Support for creating, managing, and interacting with Linux systemd services. -# 5. Mechanisms to verify the successful running of the service. -# -# Usage: -# 1. Direct Script Execution: -# This will start the OpenIM CronTask directly through a background process. -# Example: ./openim-crontask.sh openim::crontask::start -# -# 2. Controlling through Functions for systemctl operations: -# Specific operations like installation, uninstallation, and status check can be executed by passing the respective function name as an argument to the script. -# Example: ./openim-crontask.sh openim::crontask::install -# -# Note: Ensure that the appropriate permissions and environmental variables are set prior to script execution. -# - -OPENIM_ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")"/../.. && pwd -P) -[[ -z ${COMMON_SOURCED} ]] && source "${OPENIM_ROOT}"/scripts/install/common.sh - -SERVER_NAME="openim-crontask" - -function openim::crontask::start() { - - rm -rf "$TMP_LOG_FILE" - - openim::log::info "Start OpenIM Cron, binary root: ${SERVER_NAME}" - openim::log::status "Start OpenIM Cron, path: ${OPENIM_CRONTASK_BINARY}" - - openim::log::status "start cron_task process, path: ${OPENIM_CRONTASK_BINARY}" - #nohup ${OPENIM_CRONTASK_BINARY} -c ${OPENIM_PUSH_CONFIG} >> ${LOG_FILE} 2> >(tee -a "${STDERR_LOG_FILE}" "$TMP_LOG_FILE" >&2) & - cmd="${OPENIM_CRONTASK_BINARY} -c ${OPENIM_PUSH_CONFIG}" - nohup ${cmd} >> "${LOG_FILE}" 2> >(tee -a "$TMP_LOG_FILE" | while read line; do echo -e "\e[31m${line}\e[0m"; done >&2) >> "${LOG_FILE}" 2>&1 & - return 0 - -} - -###################################### Linux Systemd ###################################### -SYSTEM_FILE_PATH="/etc/systemd/system/${SERVER_NAME}.service" - -# Print the necessary information after installation -function openim::crontask::info() { -cat << EOF -openim-crontask listen on: ${OPENIM_CRONTASK_HOST} -EOF -} - -# install openim-crontask -function openim::crontask::install() { - pushd "${OPENIM_ROOT}" - - # 1. Build openim-crontask - make build BINS=${SERVER_NAME} - - openim::common::sudo "cp -r ${OPENIM_OUTPUT_HOSTBIN}/${SERVER_NAME} ${OPENIM_INSTALL_DIR}/${SERVER_NAME}" - openim::log::status "${SERVER_NAME} binary: ${OPENIM_INSTALL_DIR}/${SERVER_NAME}/${SERVER_NAME}" - - # 2. Generate and install the openim-crontask configuration file (openim-crontask.yaml) - openim::log::status "${SERVER_NAME} config file: ${OPENIM_CONFIG_DIR}/config.yaml" - - # 3. Create and install the ${SERVER_NAME} systemd unit file - echo ${LINUX_PASSWORD} | sudo -S bash -c \ - "SERVER_NAME=${SERVER_NAME} ./scripts/genconfig.sh ${ENV_FILE} deployments/templates/openim.service > ${SYSTEM_FILE_PATH}" - openim::log::status "${SERVER_NAME} systemd file: ${SYSTEM_FILE_PATH}" - - # 4. Start the openim-crontask service - openim::common::sudo "systemctl daemon-reload" - openim::common::sudo "systemctl restart ${SERVER_NAME}" - openim::common::sudo "systemctl enable ${SERVER_NAME}" - openim::crontask::status || return 1 - openim::crontask::info - - openim::log::info "install ${SERVER_NAME} successfully" - popd -} - - -# Unload -function openim::crontask::uninstall() { - set +o errexit - openim::common::sudo "systemctl stop ${SERVER_NAME}" - openim::common::sudo "systemctl disable ${SERVER_NAME}" - openim::common::sudo "rm -f ${OPENIM_INSTALL_DIR}/${SERVER_NAME}" - openim::common::sudo "rm -f ${OPENIM_CONFIG_DIR}/${SERVER_NAME}.yaml" - openim::common::sudo "rm -f /etc/systemd/system/${SERVER_NAME}.service" - - openim::log::info "uninstall ${SERVER_NAME} successfully" -} - -# Status Check -function openim::crontask::status() { - # Check the running status of the ${SERVER_NAME}. If active (running) is displayed, the ${SERVER_NAME} is started successfully. - if systemctl is-active --quiet "${SERVER_NAME}"; then - openim::log::info "${SERVER_NAME} is running successfully." - else - openim::log::error "${SERVER_NAME} failed to start, maybe not installed properly" - return 1 - fi -} - -if [[ "$*" =~ openim::crontask:: ]];then - eval $* -fi diff --git a/scripts/install/openim-man.sh b/scripts/install/openim-man.sh deleted file mode 100755 index 642588a287..0000000000 --- a/scripts/install/openim-man.sh +++ /dev/null @@ -1,96 +0,0 @@ -#!/usr/bin/env bash -# 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. - -# openim-man.sh Script to manage man pages for openim -# -# Description: -# This script manages the man pages for the OpenIM software suite. -# It provides facilities to install, uninstall, and verify the -# installation status of the man pages related to OpenIM components. -# -# Usage: -# ./openim-man.sh openim::man::install - Install man pages -# ./openim-man.sh openim::man::uninstall - Uninstall man pages -# ./openim-man.sh openim::man::status - Check installation status -# -# Dependencies: -# - Assumes there's a common.sh in "${OPENIM_ROOT}/scripts/install/" -# containing shared functions and variables. -# - Relies on the script "${OPENIM_ROOT}/scripts/update-generated-docs.sh" -# to generate the man pages. -# -# Notes: -# - This script must be run with appropriate permissions to modify the -# system man directories. -# - Always ensure you're in the script's directory or provide the correct -# path when executing. -################################################################################ - -# Define the root of the build/dist directory -OPENIM_ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd) - -# Ensure the common script is sourced -[[ -z ${COMMON_SOURCED} ]] && source "${OPENIM_ROOT}/scripts/install/common.sh" - -# Print usage information after installation -function openim::man::info() { -cat <<- EOF -Usage: - man openim-server to see openim-server help # Display the man page for openim-server -EOF -} - -# Install the man pages for openim -function openim::man::install() { - # Navigate to the openim root directory - pushd "${OPENIM_ROOT}" > /dev/null - - # Generate man pages for each component - "${OPENIM_ROOT}/scripts/update-generated-docs.sh" - openim::common::sudo "cp docs/man/man1/* /usr/share/man/man1/" - - # Verify installation status - if openim::man::status; then - openim::log::info "Installed openim-server man page successfully" - openim::man::info - fi - - # Return to the original directory - popd > /dev/null -} - -# Uninstall the man pages for openim -function openim::man::uninstall() { - # Turn off exit-on-error temporarily to handle non-existing files gracefully - set +o errexit - openim::common::sudo "rm -f /usr/share/man/man1/openim-*" - - - openim::log::info "Uninstalled openim man pages successfully" -} - -# Check the installation status of the man pages -function openim::man::status() { - if ! ls /usr/share/man/man1/openim-* &> /dev/null; then - openim::log::error "OpenIM man files not found. Perhaps they were not installed correctly." - return 1 - fi - return 0 -} - -# Execute the appropriate function based on the given arguments -if [[ "$*" =~ openim::man:: ]]; then - eval "$*" -fi diff --git a/scripts/install/openim-msggateway.sh b/scripts/install/openim-msggateway.sh deleted file mode 100755 index ed79108055..0000000000 --- a/scripts/install/openim-msggateway.sh +++ /dev/null @@ -1,141 +0,0 @@ -#!/usr/bin/env bash -# 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. - -# Common utilities, variables and checks for all build scripts. - - - - -OPENIM_ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")"/../.. && pwd -P) -[[ -z ${COMMON_SOURCED} ]] && source "${OPENIM_ROOT}"/scripts/install/common.sh - - -SERVER_NAME="openim-msggateway" - -function openim::msggateway::start() { - - rm -rf "$TMP_LOG_FILE" - - openim::log::info "Start OpenIM Msggateway, binary root: ${SERVER_NAME}" - openim::log::status "Start OpenIM Msggateway, path: ${OPENIM_MSGGATEWAY_BINARY}" - - - # OpenIM message gateway service port - OPENIM_MESSAGE_GATEWAY_PORTS=$(openim::util::list-to-string ${OPENIM_MESSAGE_GATEWAY_PORT} ) - read -a OPENIM_MSGGATEWAY_PORTS_ARRAY <<< ${OPENIM_MESSAGE_GATEWAY_PORTS} - openim::util::stop_services_on_ports ${OPENIM_MSGGATEWAY_PORTS_ARRAY[*]} - # OpenIM WS port - OPENIM_WS_PORTS=$(openim::util::list-to-string ${OPENIM_WS_PORT} ) - read -a OPENIM_WS_PORTS_ARRAY <<< ${OPENIM_WS_PORTS} - - # Message Gateway Prometheus port of the service - MSG_GATEWAY_PROM_PORTS=$(openim::util::list-to-string ${MSG_GATEWAY_PROM_PORT} ) - read -a MSG_GATEWAY_PROM_PORTS_ARRAY <<< ${MSG_GATEWAY_PROM_PORTS} - - openim::log::status "OpenIM Mssage Getway ports: ${OPENIM_MESSAGE_GATEWAY_PORTS[*]}" - openim::log::status "OpenIM WS ports: ${OPENIM_WS_PORTS[*]}" - openim::log::status "OpenIM Prometheus ports: ${MSG_GATEWAY_PROM_PORTS[*]}" - - openim::log::status "OpenIM Msggateway config path: ${OPENIM_MSGGATEWAY_CONFIG}" - - if [ ${#OPENIM_MSGGATEWAY_PORTS_ARRAY[@]} -ne ${#OPENIM_WS_PORTS_ARRAY[@]} ]; then - openim::log::error_exit "ws_ports does not match push_rpc_ports or prome_ports in quantity!!!" - fi - - for ((i = 0; i < ${#OPENIM_WS_PORTS_ARRAY[@]}; i++)); do - openim::log::info "start push process, port: ${OPENIM_MSGGATEWAY_PORTS_ARRAY[$i]}, prometheus port: ${MSG_GATEWAY_PROM_PORTS_ARRAY[$i]}" - - PROMETHEUS_PORT_OPTION="" - if [[ -n "${MSG_GATEWAY_PROM_PORTS_ARRAY[$i]}" ]]; then - PROMETHEUS_PORT_OPTION="--prometheus_port ${MSG_GATEWAY_PROM_PORTS_ARRAY[$i]}" - fi - cmd="${OPENIM_MSGGATEWAY_BINARY} --port ${OPENIM_MSGGATEWAY_PORTS_ARRAY[$i]} --ws_port ${OPENIM_WS_PORTS_ARRAY[$i]} $PROMETHEUS_PORT_OPTION -c ${OPENIM_MSGGATEWAY_CONFIG}" - nohup ${cmd} >> "${LOG_FILE}" 2> >(tee -a "$TMP_LOG_FILE" | while read line; do echo -e "\e[31m${line}\e[0m"; done >&2) >> "${LOG_FILE}" 2>&1 & - # nohup ${OPENIM_MSGGATEWAY_BINARY} --port ${OPENIM_MSGGATEWAY_PORTS_ARRAY[$i]} --ws_port ${OPENIM_WS_PORTS_ARRAY[$i]} $PROMETHEUS_PORT_OPTION -c ${OPENIM_MSGGATEWAY_CONFIG} >> ${LOG_FILE} 2> >(tee -a "${STDERR_LOG_FILE}" "$TMP_LOG_FILE" >&2) & - - done - return 0 -} - -###################################### Linux Systemd ###################################### -SYSTEM_FILE_PATH="/etc/systemd/system/${SERVER_NAME}.service" - -# Print the necessary information after installation -function openim::msggateway::info() { -cat << EOF -openim-msggateway listen on: ${OPENIM_MSGGATEWAY_HOST}:${OPENIM_MESSAGE_GATEWAY_PORT} -EOF -} - -# install openim-msggateway -function openim::msggateway::install() { - pushd "${OPENIM_ROOT}" - - # 1. Build openim-msggateway - make build BINS=${SERVER_NAME} - openim::common::sudo "cp -r ${OPENIM_OUTPUT_HOSTBIN}/${SERVER_NAME} ${OPENIM_INSTALL_DIR}/${SERVER_NAME}" - openim::log::status "${SERVER_NAME} binary: ${OPENIM_INSTALL_DIR}/${SERVER_NAME}" - - # 2. Generate and install the openim-msggateway configuration file (openim-msggateway.yaml) - # nono - - # 3. Create and install the ${SERVER_NAME} systemd unit file - echo ${LINUX_PASSWORD} | sudo -S bash -c \ - "SERVER_NAME=${SERVER_NAME} ./scripts/genconfig.sh ${ENV_FILE} deployments/templates/openim.service > ${SYSTEM_FILE_PATH}" - openim::log::status "${SERVER_NAME} systemd file: ${SYSTEM_FILE_PATH}" - - # 4. Start the openim-msggateway service - openim::common::sudo "systemctl daemon-reload" - openim::common::sudo "systemctl restart ${SERVER_NAME}" - openim::common::sudo "systemctl enable ${SERVER_NAME}" - openim::msggateway::status || return 1 - openim::msggateway::info - - openim::log::info "install ${SERVER_NAME} successfully" - popd -} - - -# Unload -function openim::msggateway::uninstall() { - set +o errexit - openim::common::sudo "systemctl stop ${SERVER_NAME}" - openim::common::sudo "systemctl disable ${SERVER_NAME}" - openim::common::sudo "rm -f ${OPENIM_INSTALL_DIR}/${SERVER_NAME}" - openim::common::sudo "rm -f ${OPENIM_CONFIG_DIR}/${SERVER_NAME}.yaml" - openim::common::sudo "rm -f /etc/systemd/system/${SERVER_NAME}.service" - - openim::log::info "uninstall ${SERVER_NAME} successfully" -} - -# Status Check -function openim::msggateway::status() { - # Check the running status of the ${SERVER_NAME}. If active (running) is displayed, the ${SERVER_NAME} is started successfully. - systemctl status ${SERVER_NAME}|grep -q 'active' || { - openim::log::error "${SERVER_NAME} failed to start, maybe not installed properly" - - return 1 - } - - # The listening port is hardcode in the configuration file - if echo | telnet ${OPENIM_MSGGATEWAY_HOST} ${OPENIM_MESSAGE_GATEWAY_PORT} 2>&1|grep refused &>/dev/null;then - openim::log::error "cannot access health check port, ${SERVER_NAME} maybe not startup" - return 1 - fi -} - -if [[ "$*" =~ openim::msggateway:: ]];then - eval $* -fi diff --git a/scripts/install/openim-msgtransfer.sh b/scripts/install/openim-msgtransfer.sh deleted file mode 100755 index 8403d1cfcf..0000000000 --- a/scripts/install/openim-msgtransfer.sh +++ /dev/null @@ -1,186 +0,0 @@ -#!/usr/bin/env bash -# 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. -# Use: -# ./scripts/install/openim-msgtransfer.sh openim::msgtransfer::start - -# Common utilities, variables and checks for all build scripts. - - - - -OPENIM_ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")"/../.. && pwd -P) -[[ -z ${COMMON_SOURCED} ]] && source "${OPENIM_ROOT}"/scripts/install/common.sh - -SERVER_NAME="openim-msgtransfer" - -function openim::msgtransfer::start() { - - rm -rf "$TMP_LOG_FILE" - - openim::log::info "Start OpenIM Msggateway, binary root: ${SERVER_NAME}" - openim::log::status "Start OpenIM Msggateway, path: ${OPENIM_MSGTRANSFER_BINARY}" - - # Message Transfer Prometheus port list - MSG_TRANSFER_PROM_PORTS=(openim::util::list-to-string ${MSG_TRANSFER_PROM_PORT} ) - - openim::log::status "OpenIM Prometheus ports: ${MSG_TRANSFER_PROM_PORTS[*]}" - - openim::log::status "OpenIM Msggateway config path: ${OPENIM_MSGTRANSFER_CONFIG}" - - openim::log::info "openim maggateway num: ${OPENIM_MSGGATEWAY_NUM}" - - if [ "${OPENIM_MSGGATEWAY_NUM}" -lt 1 ]; then - opeim::log::error "OPENIM_MSGGATEWAY_NUM must be greater than 0" - fi - - if [ ${OPENIM_MSGGATEWAY_NUM} -ne $((${#MSG_TRANSFER_PROM_PORTS[@]} - 1)) ]; then - openim::log::error "OPENIM_MSGGATEWAY_NUM must be equal to the number of MSG_TRANSFER_PROM_PORTS" - fi - - for (( i=0; i<$OPENIM_MSGGATEWAY_NUM; i++ )) do - openim::log::info "prometheus port: ${MSG_TRANSFER_PROM_PORTS[$i]}" - PROMETHEUS_PORT_OPTION="" - if [[ -n "${MSG_TRANSFER_PROM_PORTS[$i+1]}" ]]; then - PROMETHEUS_MSG_TRANSFER_PORT="${MSG_TRANSFER_PROM_PORTS[$i+1]%,}" - openim::util::stop_services_on_ports ${PROMETHEUS_MSG_TRANSFER_PORT} - PROMETHEUS_PORT_OPTION="--prometheus_port ${PROMETHEUS_MSG_TRANSFER_PORT}" - fi - cmd="${OPENIM_MSGTRANSFER_BINARY} ${PROMETHEUS_PORT_OPTION} -c ${OPENIM_MSGTRANSFER_CONFIG} -n ${i}" - #nohup ${cmd} >> "${LOG_FILE}" 2> >(tee -a "$TMP_LOG_FILE" | while read line; do echo -e "\e[31m${line}\e[0m"; done >&2) >/dev/null & - nohup ${cmd} >> "${LOG_FILE}" 2> >(tee -a "$TMP_LOG_FILE" | while read line; do echo -e "\e[31m${line}\e[0m"; done >&2) >> "${LOG_FILE}" 2>&1 & - #nohup ${OPENIM_MSGTRANSFER_BINARY} ${PROMETHEUS_PORT_OPTION} -c ${OPENIM_MSGTRANSFER_CONFIG} -n ${i} >> ${LOG_FILE} 2> >(tee -a "${STDERR_LOG_FILE}" "$TMP_LOG_FILE" >&2) & - done - return 0 -} - -function openim::msgtransfer::check() { - PIDS=$(pgrep -f "${OPENIM_OUTPUT_HOSTBIN}/openim-msgtransfer") - if [ -z "$PIDS" ]; then - NUM_PROCESSES=0 - else - NUM_PROCESSES=$(echo "$PIDS" | wc -l) - fi - if [ "$NUM_PROCESSES" -eq "$OPENIM_MSGGATEWAY_NUM" ]; then - for PID in $PIDS; do - if [[ "$OSTYPE" == "linux-gnu"* ]]; then - ps -p $PID -o pid,cmd - elif [[ "$OSTYPE" == "darwin"* ]]; then - ps -p $PID -o pid,comm - else - openim::log::error "Unsupported OS type: $OSTYPE" - fi - done - else - openim::log::error "Expected $OPENIM_MSGGATEWAY_NUM OpenIM msgtransfer processes, but found $NUM_PROCESSES msgtransfer processes running" - return 1 - fi - return 0 -} - -function openim::msgtransfer::check_for_stop() { - PIDS=$(pgrep -f "${OPENIM_OUTPUT_HOSTBIN}/openim-msgtransfer") || PIDS="0" - if [ "$PIDS" = "0" ]; then - return 0 - fi - - NUM_PROCESSES=$(echo "$PIDS" | wc -l | xargs) - - if [ "$NUM_PROCESSES" -gt 0 ]; then - openim::log::error "Found $NUM_PROCESSES processes for $OPENIM_OUTPUT_HOSTBIN/openim-msgtransfer" - for PID in $PIDS; do - if [[ "$OSTYPE" == "linux-gnu"* ]]; then - echo -e "\033[31m$(ps -p $PID -o pid,cmd)\033[0m" - elif [[ "$OSTYPE" == "darwin"* ]]; then - echo -e "\033[31m$(ps -p $PID -o pid,comm)\033[0m" - else - openim::log::error "Unsupported OS type: $OSTYPE" - fi - done - openim::log::error "Processes have not been stopped properly." - else - openim::log::success "All openim-msgtransfer processes have been stopped properly." - fi - return 0 -} - - -###################################### Linux Systemd ###################################### -SYSTEM_FILE_PATH="/etc/systemd/system/${SERVER_NAME}.service" - -# Print the necessary information after installation -function openim::msgtransfer::info() { -cat << EOF -openim-msgtransfer listen on: ${OPENIM_MSGTRANSFER_HOST} -EOF -} - -# install openim-msgtransfer -function openim::msgtransfer::install() { - pushd "${OPENIM_ROOT}" - - # 1. Build openim-msgtransfer - make build BINS=${SERVER_NAME} - - openim::common::sudo "cp -r ${OPENIM_OUTPUT_HOSTBIN}/${SERVER_NAME} ${OPENIM_INSTALL_DIR}/${SERVER_NAME}" - openim::log::status "${SERVER_NAME} binary: ${OPENIM_INSTALL_DIR}/${SERVER_NAME}/${SERVER_NAME}" - - openim::log::status "${SERVER_NAME} binary: ${OPENIM_INSTALL_DIR}/bin/${SERVER_NAME}" - - # 2. Generate and install the openim-msgtransfer configuration file (openim-msgtransfer.yaml) - # nono - - # 3. Create and install the ${SERVER_NAME} systemd unit file - echo ${LINUX_PASSWORD} | sudo -S bash -c \ - "SERVER_NAME=${SERVER_NAME} ./scripts/genconfig.sh ${ENV_FILE} deployments/templates/openim.service > ${SYSTEM_FILE_PATH}" - openim::log::status "${SERVER_NAME} systemd file: ${SYSTEM_FILE_PATH}" - - # 4. Start the openim-msgtransfer service - openim::common::sudo "systemctl daemon-reload" - openim::common::sudo "systemctl restart ${SERVER_NAME}" - openim::common::sudo "systemctl enable ${SERVER_NAME}" - openim::msgtransfer::status || return 1 - openim::msgtransfer::info - - openim::log::info "install ${SERVER_NAME} successfully" - popd -} - - -# Unload -function openim::msgtransfer::uninstall() { - set +o errexit - openim::common::sudo "systemctl stop ${SERVER_NAME}" - openim::common::sudo "systemctl disable ${SERVER_NAME}" - openim::common::sudo "rm -f ${OPENIM_INSTALL_DIR}/${SERVER_NAME}" - openim::common::sudo "rm -f ${OPENIM_CONFIG_DIR}/${SERVER_NAME}.yaml" - openim::common::sudo "rm -f /etc/systemd/system/${SERVER_NAME}.service" - - openim::log::info "uninstall ${SERVER_NAME} successfully" -} - -# Status Check -function openim::msgtransfer::status() { - # Check the running status of the ${SERVER_NAME}. If active (running) is displayed, the ${SERVER_NAME} is started successfully. - if systemctl is-active --quiet "${SERVER_NAME}"; then - openim::log::info "${SERVER_NAME} is running successfully." - else - openim::log::error "${SERVER_NAME} failed to start, maybe not installed properly" - return 1 - fi -} - -if [[ "$*" =~ openim::msgtransfer:: ]];then - eval $* -fi diff --git a/scripts/install/openim-push.sh b/scripts/install/openim-push.sh deleted file mode 100755 index aafb24c7b0..0000000000 --- a/scripts/install/openim-push.sh +++ /dev/null @@ -1,150 +0,0 @@ -#!/usr/bin/env bash -# 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. -# -# OpenIM Push Control Script -# -# Description: -# This script provides a control interface for the OpenIM Push service within a Linux environment. It supports two installation methods: installation via function calls to systemctl, and direct installation through background processes. -# -# Features: -# 1. Robust error handling leveraging Bash built-ins such as 'errexit', 'nounset', and 'pipefail'. -# 2. Capability to source common utility functions and configurations, ensuring environmental consistency. -# 3. Comprehensive logging tools, offering clear operational insights. -# 4. Support for creating, managing, and interacting with Linux systemd services. -# 5. Mechanisms to verify the successful running of the service. -# -# Usage: -# 1. Direct Script Execution: -# This will start the OpenIM push directly through a background process. -# Example: ./openim-push.sh -# -# 2. Controlling through Functions for systemctl operations: -# Specific operations like installation, uninstallation, and status check can be executed by passing the respective function name as an argument to the script. -# Example: ./openim-push.sh openim::push::install -# -# ENVIRONMENT VARIABLES: -# export OPENIM_PUSH_BINARY="8080 8081 8082" -# export OPENIM_PUSH_PORT="9090 9091 9092" -# -# Note: Ensure that the appropriate permissions and environmental variables are set prior to script execution. -# - - - - -OPENIM_ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")"/../.. && pwd -P) -[[ -z ${COMMON_SOURCED} ]] && source "${OPENIM_ROOT}"/scripts/install/common.sh - -SERVER_NAME="openim-push" - -function openim::push::start() { - - rm -rf "$TMP_LOG_FILE" - - openim::log::status "Start OpenIM Push, binary root: ${SERVER_NAME}" - openim::log::info "Start OpenIM Push, path: ${OPENIM_PUSH_BINARY}" - - openim::log::status "prepare start push process, path: ${OPENIM_PUSH_BINARY}" - openim::log::status "prepare start push process, port: ${OPENIM_PUSH_PORT}, prometheus port: ${PUSH_PROM_PORT}" - - OPENIM_PUSH_PORTS_ARRAY=$(openim::util::list-to-string ${OPENIM_PUSH_PORT} ) - PUSH_PROM_PORTS_ARRAY=$(openim::util::list-to-string ${PUSH_PROM_PORT} ) - - openim::log::status "push port list: ${OPENIM_PUSH_PORTS_ARRAY[@]}" - openim::log::status "prometheus port list: ${PUSH_PROM_PORTS_ARRAY[@]}" - - if [ ${#OPENIM_PUSH_PORTS_ARRAY[@]} -ne ${#PUSH_PROM_PORTS_ARRAY[@]} ]; then - openim::log::error "The length of the two port lists is different!" - fi - - for (( i=0; i<${#OPENIM_PUSH_PORTS_ARRAY[@]}; i++ )); do - openim::log::info "start push process, port: ${OPENIM_PUSH_PORTS_ARRAY[$i]}, prometheus port: ${PUSH_PROM_PORTS_ARRAY[$i]}" - cmd="${OPENIM_PUSH_BINARY} --port ${OPENIM_PUSH_PORTS_ARRAY[$i]} -c ${OPENIM_PUSH_CONFIG} --prometheus_port ${PUSH_PROM_PORTS_ARRAY[$i]}" - #nohup ${cmd} >> "${LOG_FILE}" 2> >(tee -a "$TMP_LOG_FILE" | while read line; do echo -e "\e[31m${line}\e[0m"; done >&2) >/dev/null & - nohup ${cmd} >> "${LOG_FILE}" 2> >(tee -a "$TMP_LOG_FILE" | while read line; do echo -e "\e[31m${line}\e[0m"; done >&2) >> "${LOG_FILE}" 2>&1 & - #nohup ${OPENIM_PUSH_BINARY} --port ${OPENIM_PUSH_PORTS_ARRAY[$i]} -c ${OPENIM_PUSH_CONFIG} --prometheus_port ${PUSH_PROM_PORTS_ARRAY[$i]} >> ${LOG_FILE} 2> >(tee -a "${STDERR_LOG_FILE}" "$TMP_LOG_FILE" >&2) & - done - return 0 - -} - -###################################### Linux Systemd ###################################### -SYSTEM_FILE_PATH="/etc/systemd/system/${SERVER_NAME}.service" - -# Print the necessary information after installation -function openim::push::info() { -cat << EOF -openim-push listen on: ${OPENIM_PUSH_HOST}:${OPENIM_PUSH_PORT} -EOF -} - -# install openim-push -function openim::push::install() { - pushd "${OPENIM_ROOT}" - - # 1. Build openim-push - make build BINS=${SERVER_NAME} - openim::common::sudo "cp -r ${OPENIM_OUTPUT_HOSTBIN}/${SERVER_NAME} ${OPENIM_INSTALL_DIR}/${SERVER_NAME}" - openim::log::status "${SERVER_NAME} binary: ${OPENIM_INSTALL_DIR}/${SERVER_NAME}/${SERVER_NAME}" - - # 2. Generate and install the openim-push configuration file (config) - openim::log::status "${SERVER_NAME} config file: ${OPENIM_CONFIG_DIR}/config.yaml" - - # 3. Create and install the ${SERVER_NAME} systemd unit file - echo ${LINUX_PASSWORD} | sudo -S bash -c \ - "SERVER_NAME=${SERVER_NAME} ./scripts/genconfig.sh ${ENV_FILE} deployments/templates/openim.service > ${SYSTEM_FILE_PATH}" - openim::log::status "${SERVER_NAME} systemd file: ${SYSTEM_FILE_PATH}" - - # 4. Start the openim-push service - openim::common::sudo "systemctl daemon-reload" - openim::common::sudo "systemctl restart ${SERVER_NAME}" - openim::common::sudo "systemctl enable ${SERVER_NAME}" - openim::push::status || return 1 - openim::push::info - - openim::log::info "install ${SERVER_NAME} successfully" - popd -} - -# Unload -function openim::push::uninstall() { - set +o errexit - openim::common::sudo "systemctl stop ${SERVER_NAME}" - openim::common::sudo "systemctl disable ${SERVER_NAME}" - openim::common::sudo "rm -f ${OPENIM_INSTALL_DIR}/${SERVER_NAME}" - openim::common::sudo "rm -f ${OPENIM_CONFIG_DIR}/${SERVER_NAME}.yaml" - openim::common::sudo "rm -f /etc/systemd/system/${SERVER_NAME}.service" - - openim::log::info "uninstall ${SERVER_NAME} successfully" -} - -# Status Check -function openim::push::status() { - # Check the running status of the ${SERVER_NAME}. If active (running) is displayed, the ${SERVER_NAME} is started successfully. - systemctl status ${SERVER_NAME}|grep -q 'active' || { - openim::log::error "${SERVER_NAME} failed to start, maybe not installed properly" - return 1 - } - - # The listening port is hardcode in the configuration file - if echo | telnet ${OPENIM_MSGGATEWAY_HOST} ${OPENIM_PUSH_PORT} 2>&1|grep refused &>/dev/null;then # Assuming a different port for push - openim::log::error "cannot access health check port, ${SERVER_NAME} maybe not startup" - return 1 - fi -} - -if [[ "$*" =~ openim::push:: ]];then - eval $* -fi diff --git a/scripts/install/openim-rpc.sh b/scripts/install/openim-rpc.sh deleted file mode 100755 index 1265a11c67..0000000000 --- a/scripts/install/openim-rpc.sh +++ /dev/null @@ -1,254 +0,0 @@ -#!/usr/bin/env bash - -# 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. -# -# OpenIM RPC Service Control Script -# -# Description: -# This script provides a control interface for the OpenIM RPC service within a Linux environment. It offers functionalities to start multiple RPC services, each denoted by their respective names under openim::rpc::service_name. -# -# Features: -# 1. Robust error handling using Bash built-ins like 'errexit', 'nounset', and 'pipefail'. -# 2. The capability to source common utility functions and configurations to ensure uniform environmental settings. -# 3. Comprehensive logging functionalities, providing a detailed understanding of operational processes. -# 4. Provision for declaring and managing a set of RPC services, each associated with its unique name and corresponding ports. -# 5. The ability to define and associate Prometheus ports for service monitoring purposes. -# 6. Functionalities to start each RPC service, along with its designated ports, in a sequence. -# -# Usage: -# 1. Direct Script Execution: -# This initiates all the RPC services declared under the function openim::rpc::service_name. -# Example: ./openim-rpc-{rpc-name}.sh openim::rpc::start -# 2. Controlling through Functions for systemctl operations: -# Specific operations like installation, uninstallation, and status check can be executed by passing the respective function name as an argument to the script. -# Example: ./openim-rpc-{rpc-name}.sh openim::rpc::install -# -# Note: Before executing this script, ensure that the necessary permissions are granted and relevant environmental variables are set. -# - -OPENIM_ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")"/../.. && pwd -P) -[[ -z ${COMMON_SOURCED} ]] && source "${OPENIM_ROOT}"/scripts/install/common.sh - -SERVER_NAME="openim-rpc" -readonly OPENIM_RPC_CONFIG="${OPENIM_ROOT}"/config - -openim::rpc::service_name() { - local targets=( - openim-rpc-user - openim-rpc-friend - openim-rpc-msg - openim-rpc-group - openim-rpc-auth - openim-rpc-conversation - openim-rpc-third - ) - echo "${targets[@]}" -} -IFS=" " read -ra OPENIM_RPC_SERVICE_TARGETS <<< "$(openim::rpc::service_name)" -readonly OPENIM_RPC_SERVICE_TARGETS -readonly OPENIM_RPC_SERVICE_LISTARIES=("${OPENIM_RPC_SERVICE_TARGETS[@]##*/}") - - -OPENIM_ALL_RPC_FULL_PATH=() -for target in openim::rpc::service_name; do - OPENIM_ALL_RPC_FULL_PATH+=("${OPENIM_OUTPUT_HOSTBIN}/${target}") -done -readonly OPENIM_ALL_RPC_FULL_PATH - - - - -# Make sure the environment is only called via common to avoid too much nesting -openim::rpc::service_port() { - local targets=( - ${OPENIM_USER_PORT} # User service 10110 - ${OPENIM_FRIEND_PORT} # Friend service 10120 - ${OPENIM_MESSAGE_PORT} # Message service 10130 - # ${OPENIM_MESSAGE_GATEWAY_PORT} # Message gateway 10140 - ${OPENIM_GROUP_PORT} # Group service 10150 - ${OPENIM_AUTH_PORT} # Authorization service 10160 - # ${OPENIM_PUSH_PORT} # Push service 10170 - ${OPENIM_CONVERSATION_PORT} # Conversation service 10180 - ${OPENIM_THIRD_PORT} # Third-party service 10190 - ) - echo "${targets[@]}" -} -IFS=" " read -ra OPENIM_RPC_PORT_TARGETS <<< "$(openim::rpc::service_port)" -readonly OPENIM_RPC_PORT_TARGETS -readonly OPENIM_RPC_PORT_LISTARIES=("${OPENIM_RPC_PORT_TARGETS[@]##*/}") - -openim::rpc::prometheus_port() { - # Declare an array to hold all the Prometheus ports for different services - local targets=( - ${USER_PROM_PORT} # Prometheus port for user service - ${FRIEND_PROM_PORT} # Prometheus port for friend service - ${MESSAGE_PROM_PORT} # Prometheus port for message service - ${GROUP_PROM_PORT} # Prometheus port for group service - ${AUTH_PROM_PORT} # Prometheus port for authentication service - ${CONVERSATION_PROM_PORT} # Prometheus port for conversation service - ${THIRD_PROM_PORT} # Prometheus port for third-party integrations service - ) - # Print the list of ports - echo "${targets[@]}" -} -IFS=" " read -ra OPENIM_RPC_PROM_PORT_TARGETS <<< "$(openim::rpc::prometheus_port)" -readonly OPENIM_RPC_PROM_PORT_TARGETS -readonly OPENIM_RPC_PROM_PORT_LISTARIES=("${OPENIM_RPC_PROM_PORT_TARGETS[@]##*/}") - -function openim::rpc::start() { - rm -rf "$TMP_LOG_FILE" - - echo "OPENIM_RPC_SERVICE_LISTARIES: ${OPENIM_RPC_SERVICE_LISTARIES[@]}" - echo "OPENIM_RPC_PROM_PORT_LISTARIES: ${OPENIM_RPC_PROM_PORT_LISTARIES[@]}" - echo "OPENIM_RPC_PORT_LISTARIES: ${OPENIM_RPC_PORT_LISTARIES[@]}" - - openim::log::info "Starting ${SERVER_NAME} ..." - - printf "+------------------------+-------+-----------------+\n" - printf "| Service Name | Port | Prometheus Port |\n" - printf "+------------------------+-------+-----------------+\n" - - length=${#OPENIM_RPC_SERVICE_LISTARIES[@]} - - for ((i=0; i<$length; i++)); do - printf "| %-22s | %-5s | %-15s |\n" "${OPENIM_RPC_SERVICE_LISTARIES[$i]}" "${OPENIM_RPC_PORT_LISTARIES[$i]}" "${OPENIM_RPC_PROM_PORT_LISTARIES[$i]}" - printf "+------------------------+-------+-----------------+\n" - done - - - # start all rpc services - for ((i = 0; i < ${#OPENIM_RPC_SERVICE_LISTARIES[*]}; i++)); do - - openim::log::info "OpenIM ${OPENIM_RPC_SERVICE_LISTARIES[$i]} config path: ${OPENIM_RPC_CONFIG}" - # Get the service and Prometheus ports. - OPENIM_RPC_SERVICE_PORTS=( $(openim::util::list-to-string ${OPENIM_RPC_PORT_LISTARIES[$i]}) ) - read -a OPENIM_RPC_SERVICE_PORTS_ARRAY <<< ${OPENIM_RPC_SERVICE_PORTS} - - OPENIM_RPC_PROM_PORTS=( $(openim::util::list-to-string ${OPENIM_RPC_PROM_PORT_LISTARIES[$i]}) ) - read -a OPENIM_RPC_PROM_PORTS_ARRAY <<< ${OPENIM_RPC_PROM_PORTS} - - for ((j = 0; j < ${#OPENIM_RPC_SERVICE_PORTS_ARRAY[@]}; j++)); do - openim::log::info "Starting ${OPENIM_RPC_SERVICE_LISTARIES[$i]} service, port: ${OPENIM_RPC_SERVICE_PORTS[j]}, prometheus port: ${OPENIM_RPC_PROM_PORTS[j]}, binary root: ${OPENIM_OUTPUT_HOSTBIN}/${OPENIM_RPC_SERVICE_LISTARIES[$i]}" - result=$(openim::rpc::start_service "${OPENIM_RPC_SERVICE_LISTARIES[$i]}" "${OPENIM_RPC_SERVICE_PORTS[j]}" "${OPENIM_RPC_PROM_PORTS[j]}") - if [[ $? -ne 0 ]]; then - openim::log::error "start ${SERVER_NAME} failed" - else - openim::log::info "$result" - fi - done - done - - - return 0 -} - -function openim::rpc::start_service() { - local binary_name="$1" - local service_port="$2" - local prometheus_port="$3" - - local cmd="${OPENIM_OUTPUT_HOSTBIN}/${binary_name} --port ${service_port} -c ${OPENIM_RPC_CONFIG}" - - if [ -n "${prometheus_port}" ]; then - printf "Specifying prometheus port: %s\n" "${prometheus_port}" - cmd="${cmd} --prometheus_port ${prometheus_port}" - fi - #nohup ${cmd} >> "${LOG_FILE}" 2> >(tee -a "${STDERR_LOG_FILE}" "$TMP_LOG_FILE" >&2) & - #nohup ${cmd} >> "${LOG_FILE}" 2> >(tee -a "$TMP_LOG_FILE" | while read line; do echo -e "\e[31m${line}\e[0m"; done >&2) >/dev/null & - nohup ${cmd} >> "${LOG_FILE}" 2> >(tee -a "$TMP_LOG_FILE" | while read line; do echo -e "\e[31m${line}\e[0m"; done >&2) >> "${LOG_FILE}" 2>&1 & - return 0 -} - -###################################### Linux Systemd ###################################### -declare -A SYSTEM_FILE_PATHS -for service in "${OPENIM_RPC_SERVICE_LISTARIES[@]}"; do - SYSTEM_FILE_PATHS["$service"]="/etc/systemd/system/${service}.service" -done - -# Print the necessary information after installation -function openim::rpc::info() { - for service in "${OPENIM_RPC_SERVICE_LISTARIES[@]}"; do - echo "${service} listen on: ${OPENIM_RPC_PORT_LISTARIES[@]}" - done -} - -# install openim-rpc -function openim::rpc::install() { - pushd "${OPENIM_ROOT}" - - # 1. Build openim-rpc - for service in "${OPENIM_RPC_SERVICE_LISTARIES[@]}"; do - make build BINS=${service} - openim::common::sudo "cp -r ${OPENIM_OUTPUT_HOSTBIN}/${service} ${OPENIM_INSTALL_DIR}/${service}" - openim::log::status "${service} binary: ${OPENIM_INSTALL_DIR}/${service}/${service}" - done - - # 2. Generate and install the openim-rpc configuration file (config) - openim::log::status "openim-rpc config file: ${OPENIM_CONFIG_DIR}/config.yaml" - - # 3. Create and install the systemd unit files - for service in "${OPENIM_RPC_SERVICE_LISTARIES[@]}"; do - echo ${LINUX_PASSWORD} | sudo -S bash -c \ - "SERVER_NAME=${service} ./scripts/genconfig.sh ${ENV_FILE} deployments/templates/openim.service > ${SYSTEM_FILE_PATHS[$service]}" - openim::log::status "${service} systemd file: ${SYSTEM_FILE_PATHS[$service]}" - done - - # 4. Start the openim-rpc services - openim::common::sudo "systemctl daemon-reload" - for service in "${OPENIM_RPC_SERVICE_LISTARIES[@]}"; do - openim::common::sudo "systemctl restart ${service}" - openim::common::sudo "systemctl enable ${service}" - done - openim::rpc::status || return 1 - openim::rpc::info - - openim::log::info "install openim-rpc successfully" - popd -} - -# Unload -function openim::rpc::uninstall() { - set +o errexit - for service in "${OPENIM_RPC_SERVICE_LISTARIES[@]}"; do - openim::common::sudo "systemctl stop ${service}" - openim::common::sudo "systemctl disable ${service}" - openim::common::sudo "rm -f ${OPENIM_INSTALL_DIR}/${service}" - openim::common::sudo "rm -f ${OPENIM_CONFIG_DIR}/${service}.yaml" - openim::common::sudo "rm -f ${SYSTEM_FILE_PATHS[$service]}" - done - - openim::log::info "uninstall openim-rpc successfully" -} - -# Status Check -function openim::rpc::status() { - for service in "${OPENIM_RPC_SERVICE_LISTARIES[@]}"; do - # Check the running status of the ${service}. If active (running) is displayed, the ${service} is started successfully. - systemctl status ${service}|grep -q 'active' || { - openim::log::error "${service} failed to start, maybe not installed properly" - return 1 - } - - # The listening port is hardcoded in the configuration file - if echo | telnet ${OPENIM_MSGGATEWAY_HOST} ${OPENIM_RPC_PORT_LISTARIES[@]} 2>&1|grep refused &>/dev/null;then - openim::log::error "cannot access health check port, ${service} maybe not startup" - return 1 - fi - done -} - -if [[ "$*" =~ openim::rpc:: ]];then - eval $* -fi diff --git a/scripts/install/openim-tools.sh b/scripts/install/openim-tools.sh deleted file mode 100755 index 57de9772d3..0000000000 --- a/scripts/install/openim-tools.sh +++ /dev/null @@ -1,179 +0,0 @@ -#!/usr/bin/env bash - -# 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. -# -# OpenIM Tools Control Script -# -# Description: -# This script is responsible for managing the lifecycle of OpenIM tools, which include starting, stopping, -# and handling pre and post operations. It's designed to be modular and extensible, ensuring that the -# individual operations can be managed separately, and integrated seamlessly with Linux systemd. -# -# Features: -# 1. Robust error handling using Bash built-ins like 'errexit', 'nounset', and 'pipefail'. -# 2. The capability to source common utility functions and configurations to ensure uniform environmental settings. -# 3. Comprehensive logging functionalities, providing a detailed understanding of operational processes. -# 4. Provision for declaring and managing a set of OpenIM tools, each associated with its unique name and corresponding ports. -# 5. The ability to define and associate Prometheus ports for service monitoring purposes. -# 6. Functionalities to start each OpenIM tool, along with its designated ports, in a sequence. -# -# Usage: -# 1. Direct Script Execution: -# This initiates all the OpenIM tools declared under the function openim::tools::service_name. -# Example: ./openim-tools.sh openim::tools::start -# 2. Controlling through Functions for systemctl operations: -# Specific operations like installation, uninstallation, and status check can be executed by passing the respective function name as an argument to the script. -# Example: ./openim-tools.sh openim::tools::install -# - - -OPENIM_ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")"/../.. && pwd -P) -[[ -z ${COMMON_SOURCED} ]] && source "${OPENIM_ROOT}"/scripts/install/common.sh - -SERVER_NAME="openim-tools" - -openim::tools::start_name() { - local targets=( - imctl - ) - echo "${targets[@]}" -} -IFS=" " read -ra OPENIM_TOOLS_NAME_TARGETS <<< "$(openim::tools::start_name)" -readonly OPENIM_TOOLS_NAME_TARGETS -readonly OPENIM_TOOLS_NAME_LISTARIES=("${OPENIM_TOOLS_NAME_TARGETS[@]##*/}") - -openim::tools::pre_start_name() { - local targets=( - ncpu - component - ) - echo "${targets[@]}" -} -IFS=" " read -ra OPENIM_TOOLS_PRE_START_NAME_TARGETS <<< "$(openim::tools::pre_start_name)" -readonly OPENIM_TOOLS_PRE_START_NAME_TARGETS -readonly OPENIM_TOOLS_PRE_START_NAME_LISTARIES=("${OPENIM_TOOLS_PRE_START_NAME_TARGETS[@]##*/}") - -openim::tools::post_start_name() { - local targets=( - infra - versionchecker - ) - echo "${targets[@]}" -} -IFS=" " read -ra OPENIM_TOOLS_POST_START_NAME_TARGETS <<< "$(openim::tools::post_start_name)" -readonly OPENIM_TOOLS_POST_START_NAME_TARGETS -readonly OPENIM_TOOLS_POST_START_NAME_LISTARIES=("${OPENIM_TOOLS_POST_START_NAME_TARGETS[@]##*/}") - -function openim::tools::start_service() { - local binary_name="$1" - local config="$2" - local service_port="$3" - local prometheus_port="$4" - - local cmd="${OPENIM_OUTPUT_HOSTBIN_TOOLS}/${binary_name}" - #openim::log::info "Starting PATH: ${OPENIM_OUTPUT_HOSTBIN_TOOLS}/${binary_name}..." - - if [ -n "${config}" ]; then - # printf "Specifying config: %s\n" "${config}" - cmd="${cmd} -c ${config}/config.yaml" - fi - - if [ -n "${service_port}" ]; then - #printf "Specifying service port: %s\n" "${service_port}" - cmd="${cmd} --port ${service_port}" - fi - - if [ -n "${prometheus_port}" ]; then - #printf "Specifying prometheus port: %s\n" "${prometheus_port}" - cmd="${cmd} --prometheus_port ${prometheus_port}" - fi - #openim::log::status "Starting binary ${binary_name}..." - - - # openim::log::info "cmd: $cmd" - ${cmd} - - - local status=$? - if [ $status -eq 0 ]; then - openim::log::colorless "Service ${binary_name} started successfully." - return 0 - else - openim::log::error "Failed to start service ${binary_name}." - return 1 - fi -} - -function openim::tools::start() { - openim::log::info "Starting OpenIM Tools..." - for tool in "${OPENIM_TOOLS_NAME_LISTARIES[@]}"; do - openim::log::colorless "Starting tool ${tool}..." - # openim::tools::start_service ${tool} - #sleep 0.2 - done -} - - -function openim::tools::pre-start() { - #openim::log::info "Preparing to start OpenIM Tools..." - for tool in "${OPENIM_TOOLS_PRE_START_NAME_LISTARIES[@]}"; do - openim::log::colorless "Starting tool: ${tool}" - if ! openim::tools::start_service ${tool} ${OPNEIM_CONFIG}; then - openim::log::error "Failed to start ${tool}, aborting..." - return 1 - fi - done - #openim::log::info "All tools started successfully." -} - -function openim::tools::post-start() { - #openim::log::info "Post-start actions for OpenIM Tools..." - for tool in "${OPENIM_TOOLS_POST_START_NAME_LISTARIES[@]}"; do - openim::log::colorless "Starting tool: ${tool}" - openim::tools::start_service ${tool} - done -} - -function openim::tools::stop() { - openim::log::info "Stopping OpenIM Tools..." - for tool in "${OPENIM_TOOLS_NAME_LISTARIES[@]}"; do - openim::log::info "Stopping ${tool}..." - # Similarly, place the actual command to stop the tool here. - echo "Stopping service for ${tool}" - sleep 0.2 - done -} - -function openim::tools::pre-stop() { - openim::log::info "Preparing to stop OpenIM Tools..." - for tool in "${OPENIM_TOOLS_PRE_START_NAME_LISTARIES[@]}"; do - openim::log::info "Setting up pre-stop for ${tool}..." - echo "Pre-stop actions for ${tool}" - sleep 0.2 - done -} - -function openim::tools::post-stop() { - openim::log::info "Post-stop actions for OpenIM Tools..." - for tool in "${OPENIM_TOOLS_POST_START_NAME_LISTARIES[@]}"; do - openim::log::info "Executing post-stop for ${tool}..." - echo "Post-stop cleanup for ${tool}" - sleep 0.2 - done -} - -if [[ "$*" =~ openim::tools:: ]];then - eval $* -fi diff --git a/scripts/install/test.sh b/scripts/install/test.sh deleted file mode 100755 index 51d541ecea..0000000000 --- a/scripts/install/test.sh +++ /dev/null @@ -1,1466 +0,0 @@ -#!/usr/bin/env bash - -# 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. -# -# OpenIM RPC Service Test Control Script -# -# This control script is designed to conduct various tests on the OpenIM RPC services. -# It includes functions to perform smoke tests, API tests, and comprehensive service tests. -# The script is intended to be used in a Linux environment with appropriate permissions and -# environmental variables set. -# -# It provides robust error handling and logging to facilitate debugging and service monitoring. -# Functions within the script can be called directly or passed as arguments to perform -# systematic testing, ensuring the integrity of the RPC services. -# -# Test Functions: -# - openim::test::smoke: Runs basic tests to ensure the fundamental functionality of the service. -# - openim::test::api: Executes a series of API tests covering authentication, user, friend, -# group, and message functionalities. -# - openim::test::test: Performs a complete test suite, invoking utility checks and all defined -# test cases, and reports on their success. -# - -# The root of the build/dist directory -OPENIM_ROOT=$(dirname "${BASH_SOURCE[0]}")/../.. -[[ -z ${COMMON_SOURCED} ]] && source ${OPENIM_ROOT}/scripts/install/common.sh - -# API Server API Address:Port -INSECURE_OPENIMAPI="http://${OPENIM_API_HOST}:${API_OPENIM_PORT}" -INSECURE_OPENIMAUTO=${OPENIM_RPC_AUTH_HOST}:${OPENIM_AUTH_PORT} -CCURL="curl -f -s -XPOST" # Create -UCURL="curl -f -s -XPUT" # Update -RCURL="curl -f -s -XGET" # Retrieve -DCURL="curl -f -s -XDELETE" # Delete - -openim::test::check_error() { - local response=$1 - local err_code=$(echo "$response" | jq '.errCode') - openim::log::status "Response from user registration: $response" - if [[ "$err_code" != "0" ]]; then - openim::log::error_exit "Error occurred: $response, You can read the error code in the API documentation https://docs.openim.io/restapi/errcode" - else - openim::log::success "Operation was successful." - fi -} - -# The `openim::test::auth` function serves as a test suite for authentication-related operations. -function openim::test::auth() { - # 1. Retrieve and set the authentication token. - openim::test::get_token - - # 2. Force logout the test user from a specific platform. - openim::test::force_logout - - # Log the completion of the auth test suite. - openim::log::success "Auth test suite completed successfully." -} - -#################################### Auth Module #################################### - -# Define a function to get a token for a specific user -openim::test::get_token() { - local user_id="${1:-imAdmin}" # Default user ID if not provided - token_response=$( - ${CCURL} "${OperationID}" "${Header}" ${INSECURE_OPENIMAPI}/auth/user_token \ - -d'{"secret": "'"$SECRET"'","platformID": 1,"userID": "'$user_id'"}' - ) - token=$(echo $token_response | grep -Po 'token[" :]+\K[^"]+') - echo "$token" -} - -Header="-HContent-Type: application/json" -OperationID="-HoperationID: 1646445464564" -Token="-Htoken: $(openim::test::get_token)" - -# Forces a user to log out from the specified platform by user ID. -openim::test::force_logout() { - local request_body=$( - cat </dev/null || { - openim::log::usage "chat must be in your PATH" - openim::log::info "You can use 'scripts/install-chat.sh' to install a copy in third_party/." - exit 1 - } - - # validate chat port is free - local port_check_command - if command -v ss &> /dev/null && ss -Version | grep 'iproute2' &> /dev/null; then - port_check_command="ss" - elif command -v netstat &>/dev/null; then - port_check_command="netstat" - else - openim::log::usage "unable to identify if chat is bound to port ${CHAT_PORT}. unable to find ss or netstat utilities." - exit 1 - fi - if ${port_check_command} -nat | grep "LISTEN" | grep "[\.:]${CHAT_PORT:?}" >/dev/null 2>&1; then - openim::log::usage "unable to start chat as port ${CHAT_PORT} is in use. please stop the process listening on this port and retry." - openim::log::usage "$(${port_check_command} -nat | grep "LISTEN" | grep "[\.:]${CHAT_PORT:?}")" - exit 1 - fi - - # need set the env of "CHAT_UNSUPPORTED_ARCH" on unstable arch. - arch=$(uname -m) - if [[ $arch =~ arm* ]]; then - export CHAT_UNSUPPORTED_ARCH=arm - fi - # validate installed version is at least equal to minimum - version=$(chat --version | grep Version | head -n 1 | cut -d " " -f 3) - if [[ $(openim::chat::version "${CHAT_VERSION}") -gt $(openim::chat::version "${version}") ]]; then - export PATH="${OPENIM_ROOT}"/third_party/chat:${PATH} - hash chat - echo "${PATH}" - version=$(chat --version | grep Version | head -n 1 | cut -d " " -f 3) - if [[ $(openim::chat::version "${CHAT_VERSION}") -gt $(openim::chat::version "${version}") ]]; then - openim::log::usage "chat version ${CHAT_VERSION} or greater required." - openim::log::info "You can use 'scripts/install-chat.sh' to install a copy in third_party/." - exit 1 - fi - fi -} - -openim::chat::version() { - printf '%s\n' "${@}" | awk -F . '{ printf("%d%03d%03d\n", $1, $2, $3) }' -} - -openim::chat::start() { - # validate before running - openim::chat::validate - - # Start chat - CHAT_DIR=${CHAT_DIR:-$(mktemp -d 2>/dev/null || mktemp -d -t test-chat.XXXXXX)} - if [[ -d "${ARTIFACTS:-}" ]]; then - CHAT_LOGFILE="${ARTIFACTS}/chat.$(uname -n).$(id -un).log.DEBUG.$(date +%Y%m%d-%H%M%S).$$" - else - CHAT_LOGFILE=${CHAT_LOGFILE:-"/dev/null"} - fi - openim::log::info "chat --advertise-client-urls ${OPENIM_INTEGRATION_CHAT_URL} --data-dir ${CHAT_DIR} --listen-client-urls http://${CHAT_HOST}:${CHAT_PORT} --log-level=${CHAT_LOGLEVEL} 2> \"${CHAT_LOGFILE}\" >/dev/null" - chat --advertise-client-urls "${OPENIM_INTEGRATION_CHAT_URL}" --data-dir "${CHAT_DIR}" --listen-client-urls "${OPENIM_INTEGRATION_CHAT_URL}" --log-level="${CHAT_LOGLEVEL}" 2> "${CHAT_LOGFILE}" >/dev/null & - CHAT_PID=$! - - echo "Waiting for chat to come up." - openim::util::wait_for_url "${OPENIM_INTEGRATION_CHAT_URL}/health" "chat: " 0.25 80 - curl -fs -X POST "${OPENIM_INTEGRATION_CHAT_URL}/v3/kv/put" -d '{"key": "X3Rlc3Q=", "value": ""}' -} - -openim::chat::start_scraping() { - if [[ -d "${ARTIFACTS:-}" ]]; then - CHAT_SCRAPE_DIR="${ARTIFACTS}/chat-scrapes" - else - CHAT_SCRAPE_DIR=$(mktemp -d -t test.XXXXXX)/chat-scrapes - fi - openim::log::info "Periodically scraping chat to ${CHAT_SCRAPE_DIR} ." - mkdir -p "${CHAT_SCRAPE_DIR}" - ( - while sleep 30; do - openim::chat::scrape - done - ) & - CHAT_SCRAPE_PID=$! -} - -openim::chat::scrape() { - curl -s -S "${OPENIM_INTEGRATION_CHAT_URL}/metrics" > "${CHAT_SCRAPE_DIR}/next" && mv "${CHAT_SCRAPE_DIR}/next" "${CHAT_SCRAPE_DIR}/$(date +%s).scrape" -} - -openim::chat::stop() { - if [[ -n "${CHAT_SCRAPE_PID:-}" ]] && [[ -n "${CHAT_SCRAPE_DIR:-}" ]] ; then - kill "${CHAT_SCRAPE_PID}" &>/dev/null || : - wait "${CHAT_SCRAPE_PID}" &>/dev/null || : - openim::chat::scrape || : - ( - # shellcheck disable=SC2015 - cd "${CHAT_SCRAPE_DIR}"/.. && \ - tar czf chat-scrapes.tgz chat-scrapes && \ - rm -rf chat-scrapes || : - ) - fi - if [[ -n "${CHAT_PID-}" ]]; then - kill "${CHAT_PID}" &>/dev/null || : - wait "${CHAT_PID}" &>/dev/null || : - fi -} - -openim::chat::clean_chat_dir() { - if [[ -n "${CHAT_DIR-}" ]]; then - rm -rf "${CHAT_DIR}" - fi -} - -openim::chat::cleanup() { - openim::chat::stop - openim::chat::clean_chat_dir -} - -openim::chat::install() { - ( - local os - local arch - - os=$(openim::util::host_os) - arch=$(openim::util::host_arch) - - cd "${OPENIM_ROOT}/third_party" || return 1 - if [[ $(readlink chat) == chat-v${CHAT_VERSION}-${os}-* ]]; then - openim::log::info "chat v${CHAT_VERSION} already installed. To use:" - openim::log::info "export PATH=\"$(pwd)/chat:\${PATH}\"" - return #already installed - fi - - if [[ ${os} == "darwin" ]]; then - download_file="chat-v${CHAT_VERSION}-${os}-${arch}.zip" - url="https://github.com/chat-io/chat/releases/download/v${CHAT_VERSION}/${download_file}" - openim::util::download_file "${url}" "${download_file}" - unzip -o "${download_file}" - ln -fns "chat-v${CHAT_VERSION}-${os}-${arch}" chat - rm "${download_file}" - elif [[ ${os} == "linux" ]]; then - url="https://github.com/coreos/chat/releases/download/v${CHAT_VERSION}/chat-v${CHAT_VERSION}-${os}-${arch}.tar.gz" - download_file="chat-v${CHAT_VERSION}-${os}-${arch}.tar.gz" - openim::util::download_file "${url}" "${download_file}" - tar xzf "${download_file}" - ln -fns "chat-v${CHAT_VERSION}-${os}-${arch}" chat - rm "${download_file}" - else - openim::log::info "${os} is NOT supported." - fi - openim::log::info "chat v${CHAT_VERSION} installed. To use:" - openim::log::info "export PATH=\"$(pwd)/chat:\${PATH}\"" - ) -} \ No newline at end of file diff --git a/scripts/lib/color.sh b/scripts/lib/color.sh deleted file mode 100755 index 744fccf5ad..0000000000 --- a/scripts/lib/color.sh +++ /dev/null @@ -1,139 +0,0 @@ -#!/usr/bin/env bash - -# 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. - -# this script is used to install the dependencies of the project -# -# Usage: `scripts/color.sh`. -################################################################################ - -# shellcheck disable=SC2034 -if [ -z "${COLOR_OPEN+x}" ]; then - COLOR_OPEN=1 -fi - -# Function for colored echo -openim::color::echo() { - COLOR=$1 - [ $COLOR_OPEN -eq 1 ] && echo -e "${COLOR} $(date '+%Y-%m-%d %H:%M:%S') $@ ${COLOR_SUFFIX}" - shift -} - -# Define color variables -# --- Feature --- -COLOR_NORMAL='\033[0m';COLOR_BOLD='\033[1m';COLOR_DIM='\033[2m';COLOR_UNDER='\033[4m'; -COLOR_ITALIC='\033[3m';COLOR_NOITALIC='\033[23m';COLOR_BLINK='\033[5m'; -COLOR_REVERSE='\033[7m';COLOR_CONCEAL='\033[8m';COLOR_NOBOLD='\033[22m'; -COLOR_NOUNDER='\033[24m';COLOR_NOBLINK='\033[25m'; - -# --- Front color --- -COLOR_BLACK='\033[30m'; -COLOR_RED='\033[31m'; -COLOR_GREEN='\033[32m'; -COLOR_YELLOW='\033[33m'; -COLOR_BLUE='\033[34m'; -COLOR_MAGENTA='\033[35m'; -COLOR_CYAN='\033[36m'; -COLOR_WHITE='\033[37m'; - -# --- background color --- -COLOR_BBLACK='\033[40m';COLOR_BRED='\033[41m'; -COLOR_BGREEN='\033[42m';COLOR_BYELLOW='\033[43m'; -COLOR_BBLUE='\033[44m';COLOR_BMAGENTA='\033[45m'; -COLOR_BCYAN='\033[46m';COLOR_BWHITE='\033[47m'; - -# --- Color definitions --- -# Color definitions -COLOR_SUFFIX="\033[0m" # End all colors and special effects -BLACK_PREFIX="\033[30m" # Black prefix -RED_PREFIX="\033[31m" # Red prefix -GREEN_PREFIX="\033[32m" # Green prefix -YELLOW_PREFIX="\033[33m" # Yellow prefix -BLUE_PREFIX="\033[34m" # Blue prefix -SKY_BLUE_PREFIX="\033[36m" # Sky blue prefix -WHITE_PREFIX="\033[37m" # White prefix -BOLD_PREFIX="\033[1m" # Bold prefix -UNDERLINE_PREFIX="\033[4m" # Underline prefix -ITALIC_PREFIX="\033[3m" # Italic prefix -CYAN_PREFIX="\033[0;36m" # Cyan prefix - -# Print colors you can use -openim::color::print_color() { - echo - echo -e ${bmagenta}--back-color:${normal} - echo "bblack; bgreen; bblue; bcyan; bred; byellow; bmagenta; bwhite" - echo - echo -e ${red}--font-color:${normal} - echo "black; red; green; yellow; blue; magenta; cyan; white" - echo - echo -e ${bold}--font:${normal} - echo "normal; italic; reverse; nounder; bold; noitalic; conceal; noblink; - dim; blink; nobold; under" - echo -} - -# test functions -openim::color::test() { - echo "Starting the color tests..." - - echo "Testing normal echo without color" - openim::color::echo $COLOR_NORMAL "This is a normal text" - - echo "Testing bold echo" - openim::color::echo $COLOR_BOLD "This is bold text" - - echo "Testing dim echo" - openim::color::echo $COLOR_DIM "This is dim text" - - echo "Testing underlined echo" - openim::color::echo $COLOR_UNDER "This is underlined text" - - echo "Testing italic echo" - openim::color::echo $COLOR_ITALIC "This is italic text" - - echo "Testing red color" - openim::color::echo $COLOR_RED "This is red text" - - echo "Testing green color" - openim::color::echo $COLOR_GREEN "This is green text" - - echo "Testing yellow color" - openim::color::echo $COLOR_YELLOW "This is yellow text" - - echo "Testing blue color" - openim::color::echo $COLOR_BLUE "This is blue text" - - echo "Testing magenta color" - openim::color::echo $COLOR_MAGENTA "This is magenta text" - - echo "Testing cyan color" - openim::color::echo $COLOR_CYAN "This is cyan text" - - echo "Testing black background" - openim::color::echo $COLOR_BBLACK "This is text with black background" - - echo "Testing red background" - openim::color::echo $COLOR_BRED "This is text with red background" - - echo "Testing green background" - openim::color::echo $COLOR_BGREEN "This is text with green background" - - echo "Testing blue background" - openim::color::echo $COLOR_BBLUE "This is text with blue background" - - echo "All tests completed!" -} - -# openim::color::test diff --git a/scripts/lib/golang.sh b/scripts/lib/golang.sh deleted file mode 100755 index 51db58d891..0000000000 --- a/scripts/lib/golang.sh +++ /dev/null @@ -1,384 +0,0 @@ -#!/usr/bin/env bash -# 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. - -# The golang package that we are building. -OPENIM_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd -P)" -readonly OPENIM_GO_PACKAGE=github.com/openimsdk/open-im-server - -# The server platform we are building on. -readonly OPENIM_SUPPORTED_SERVER_PLATFORMS=( - linux/amd64 - linux/arm64 - linux/s390x - linux_mips64 - linux_mips64le - darwin_amd64 - windows_amd64 - linux_amd64 - linux_arm64 - linux_ppc64le -) - -# If we update this we should also update the set of platforms whose standard -readonly OPENIM_SUPPORTED_CLIENT_PLATFORMS=( - linux/amd64 - linux/arm64 - linux/s390x - linux/ppc64le - windows/amd64 -) - -# openim chat -readonly OPENIM_CHAT_SUPPORTED_PLATFORMS=( - linux/amd64 - linux/arm64 - linux/s390x - linux/ppc64le - windows/amd64 -) - -# Which platforms we should compile test targets for. -# Not all client platforms need these tests -readonly KUBE_SUPPORTED_TEST_PLATFORMS=( - linux/amd64 - linux/arm64 - linux/s390x - linux/ppc64le - darwin/amd64 - darwin/arm64 - windows/amd64 - windows/arm64 -) - -# The set of server targets that we are only building for Linux -# If you update this list, please also update build/BUILD. -# TODO: Label -openim::golang::server_targets() { - local targets=( - openim-api - openim-cmdutils - openim-crontask - openim-msggateway - openim-msgtransfer - openim-push - openim-rpc-auth - openim-rpc-conversation - openim-rpc-friend - openim-rpc-group - openim-rpc-msg - openim-rpc-third - openim-rpc-user - ) - echo "${targets[@]}" -} - -openim::golang::server_targets_no_transfer() { - local targets=( - openim-api - openim-crontask - openim-msggateway - openim-push - openim-rpc-auth - openim-rpc-conversation - openim-rpc-friend - openim-rpc-group - openim-rpc-msg - openim-rpc-third - openim-rpc-user - ) - echo "${targets[@]}" -} - -openim::golang::server_targets_no_cmdutils() { - local targets=( - openim-api - openim-crontask - openim-msggateway - openim-msgtransfer - openim-push - openim-rpc-auth - openim-rpc-conversation - openim-rpc-friend - openim-rpc-group - openim-rpc-msg - openim-rpc-third - openim-rpc-user - ) - echo "${targets[@]}" -} - - -IFS=" " read -ra OPENIM_SERVER_TARGETS_NO_CMDUTILS <<< "$(openim::golang::server_targets_no_cmdutils)" -readonly OPENIM_SERVER_TARGETS_NO_CMDUTILS -readonly OPENIM_SERVER_BINARIES_NO_CMDUTILS=("${OPENIM_SERVER_TARGETS_NO_CMDUTILS[@]##*/}") - - - - - -IFS=" " read -ra OPENIM_SERVER_TARGETS_NO_TRANSFER <<< "$(openim::golang::server_targets_no_transfer)" -readonly OPENIM_SERVER_TARGETS_NO_TRANSFER -readonly OPENIM_SERVER_BINARIES_NO_TRANSFER=("${OPENIM_SERVER_TARGETS_NO_TRANSFER[@]##*/}") - - - - -IFS=" " read -ra OPENIM_SERVER_TARGETS <<< "$(openim::golang::server_targets)" -readonly OPENIM_SERVER_TARGETS -readonly OPENIM_SERVER_BINARIES=("${OPENIM_SERVER_TARGETS[@]##*/}") - -# TODO: Label -START_SCRIPTS_PATH="${OPENIM_ROOT}/scripts/install/" -openim::golang::start_script_list() { - local targets=( - openim-api.sh - openim-rpc.sh - openim-push.sh - openim-msgtransfer.sh - openim-msggateway.sh - openim-crontask.sh - #openim-tools.sh - ) - local result=() - for target in "${targets[@]}"; do - result+=("${START_SCRIPTS_PATH}${target}") - done - - echo "${result[@]}" -} - -# Populate the OPENIM_SERVER_SCRIPT_START_LIST with the full path names of the scripts. -IFS=" " read -ra OPENIM_SERVER_SCRIPT_START_LIST <<< "$(openim::golang::start_script_list)" -readonly OPENIM_SERVER_SCRIPT_START_LIST - -# Extract just the script names from the full paths. -readonly OPENIM_SERVER_SCRIPTARIES=("${OPENIM_SERVER_SCRIPT_START_LIST[@]##*/}") - -openim::golang::check_openim_binaries() { - local missing_binaries=() - for binary in "${OPENIM_SERVER_BINARIES[@]}"; do - if [[ ! -x "${OPENIM_OUTPUT_HOSTBIN}/${binary}" ]]; then - missing_binaries+=("${binary}") - fi - done - - if [[ ${#missing_binaries[@]} -ne 0 ]]; then - echo "The following binaries were not found in ${OPENIM_OUTPUT_HOSTBIN}:" - for missing in "${missing_binaries[@]}"; do - echo " - ${missing}" - done - return 1 - else - echo -e "All binaries have been installed in: \n${OPENIM_OUTPUT_HOSTBIN}\n${OPENIM_OUTPUT_HOSTBIN_TOOLS}" - return 0 - fi -} - -openim::golang::tools_targets() { - local targets=( - yamlfmt - changelog - infra - ncpu - ) - echo "${targets[@]}" -} - -IFS=" " read -ra OPENIM_TOOLS_TARGETS <<< "$(openim::golang::tools_targets)" -readonly OPENIM_TOOLS_TARGETS -readonly OPENIM_TOOLS_BINARIES=("${OPENIM_TOOLS_TARGETS[@]##*/}") - -# The set of server targets we build docker images for -openim::golang::server_image_targets() { - # NOTE: this contains cmd targets for openim::build::get_docker_wrapped_binaries - local targets=( - cmd/openim-api - cmd/openim-cmdutils - cmd/openim-crontask - cmd/openim-msggateway - cmd/openim-msgtransfer - cmd/openim-push - cmd/openim-rpc-auth - cmd/openim-rpc-conversation - cmd/openim-rpc-friend - cmd/openim-rpc-group - cmd/openim-rpc-msg - cmd/openim-rpc-third - cmd/openim-rpc-user - ) - echo "${targets[@]}" -} - -IFS=" " read -ra OPENIM_SERVER_IMAGE_TARGETS <<< "$(openim::golang::server_image_targets)" -readonly OPENIM_SERVER_IMAGE_TARGETS -readonly OPENIM_SERVER_IMAGE_BINARIES=("${OPENIM_SERVER_IMAGE_TARGETS[@]##*/}") - -# shellcheck disable=SC2034 # Variables sourced in other scripts. - -# ------------ -# NOTE: All functions that return lists should use newlines. -# bash functions can't return arrays, and spaces are tricky, so newline -# separators are the preferred pattern. -# To transform a string of newline-separated items to an array, use openim::util::read-array: -# openim::util::read-array FOO < <(openim::golang::dups a b c a) -# -# ALWAYS remember to quote your subshells. Not doing so will break in -# bash 4.3, and potentially cause other issues. -# ------------ - -# Returns a sorted newline-separated list containing only duplicated items. -openim::golang::dups() { - # We use printf to insert newlines, which are required by sort. - printf "%s\n" "$@" | sort | uniq -d -} - -# echo "aa: $OPENIM_SERVER_IMAGE_TARGETS" -# echo "aa: $OPENIM_SERVER_IMAGE_BINARIES" - -openim::golang::dups $OPENIM_SERVER_IMAGE_TARGETS -openim::golang::dups $OPENIM_SERVER_IMAGE_BINARIES - -# Returns a sorted newline-separated list with duplicated items removed. -openim::golang::dedup() { - # We use printf to insert newlines, which are required by sort. - printf "%s\n" "$@" | sort -u -} - -# openim::golang::dedup $OPENIM_SERVER_IMAGE_TARGETS -# openim::golang::dedup $OPENIM_SERVER_IMAGE_BINARIES - -# Depends on values of user-facing OPENIM_BUILD_PLATFORMS, OPENIM_FASTBUILD, -# and OPENIM_BUILDER_OS. -# Configures OPENIM_SERVER_PLATFORMS and OPENIM_CLIENT_PLATFORMS, then sets them -# to readonly. -# The configured vars will only contain platforms allowed by the -# OPENIM_SUPPORTED* vars at the top of this file. -declare -a OPENIM_SERVER_PLATFORMS -declare -a OPENIM_CLIENT_PLATFORMS -openim::golang::setup_platforms() { - if [[ -n "${OPENIM_BUILD_PLATFORMS:-}" ]]; then - # OPENIM_BUILD_PLATFORMS needs to be read into an array before the next - # step, or quoting treats it all as one element. - local -a platforms - IFS=" " read -ra platforms <<< "${OPENIM_BUILD_PLATFORMS}" - - # Deduplicate to ensure the intersection trick with openim::golang::dups - # is not defeated by duplicates in user input. - openim::util::read-array platforms < <(openim::golang::dedup "${platforms[@]}") - - # Use openim::golang::dups to restrict the builds to the platforms in - # OPENIM_SUPPORTED_*_PLATFORMS. Items should only appear at most once in each - # set, so if they appear twice after the merge they are in the intersection. - openim::util::read-array OPENIM_SERVER_PLATFORMS < <(openim::golang::dups \ - "${platforms[@]}" \ - "${OPENIM_SUPPORTED_SERVER_PLATFORMS[@]}" \ - ) - readonly OPENIM_SERVER_PLATFORMS - - openim::util::read-array OPENIM_CLIENT_PLATFORMS < <(openim::golang::dups \ - "${platforms[@]}" \ - "${OPENIM_SUPPORTED_CLIENT_PLATFORMS[@]}" \ - ) - readonly OPENIM_CLIENT_PLATFORMS - - elif [[ "${OPENIM_FASTBUILD:-}" == "true" ]]; then - OPENIM_SERVER_PLATFORMS=(linux/amd64) - readonly OPENIM_SERVER_PLATFORMS - OPENIM_CLIENT_PLATFORMS=(linux/amd64) - readonly OPENIM_CLIENT_PLATFORMS - else - OPENIM_SERVER_PLATFORMS=("${OPENIM_SUPPORTED_SERVER_PLATFORMS[@]}") - readonly OPENIM_SERVER_PLATFORMS - - OPENIM_CLIENT_PLATFORMS=("${OPENIM_SUPPORTED_CLIENT_PLATFORMS[@]}") - readonly OPENIM_CLIENT_PLATFORMS - fi -} - -openim::golang::setup_platforms - -# The set of client targets that we are building for all platforms -# If you update this list, please also update build/BUILD. -readonly OPENIM_CLIENT_TARGETS=( - changelog - component - imctl - infra - ncpu - versionchecker - yamlfmt -) -readonly OPENIM_CLIENT_BINARIES=("${OPENIM_CLIENT_TARGETS[@]##*/}") - -readonly OPENIM_ALL_TARGETS=( - "${OPENIM_SERVER_TARGETS[@]}" - "${OPENIM_CLIENT_TARGETS[@]}" -) -readonly OPENIM_ALL_BINARIES=("${OPENIM_ALL_TARGETS[@]##*/}") - -# Asks golang what it thinks the host platform is. The go tool chain does some -# slightly different things when the target platform matches the host platform. -openim::golang::host_platform() { - echo "$(go env GOHOSTOS)/$(go env GOHOSTARCH)" -} - -# Ensure the go tool exists and is a viable version. -openim::golang::verify_go_version() { - if [[ -z "$(command -v go)" ]]; then - openim::log::usage_from_stdin < 0 to enable rsync -# compression for build container -OPENIM_RSYNC_COMPRESS="${KUBE_RSYNC_COMPRESS:-0}" - -# Set no_proxy for localhost if behind a proxy, otherwise, -# the connections to localhost in scripts will time out -export no_proxy="127.0.0.1,localhost${no_proxy:+,${no_proxy}}" - -# This is a symlink to binaries for "this platform", e.g. build tools. -export THIS_PLATFORM_BIN="${OPENIM_ROOT}/_output/bin/platforms" -export THIS_PLATFORM_BIN_TOOLS="${OPENIM_ROOT}/_output/bin/tools" - -. $(dirname ${BASH_SOURCE})/color.sh -. $(dirname ${BASH_SOURCE})/util.sh -. $(dirname ${BASH_SOURCE})/logging.sh - -openim::log::install_errexit -openim::util::ensure-bash-version - -. $(dirname ${BASH_SOURCE})/version.sh -. $(dirname ${BASH_SOURCE})/golang.sh -. $(dirname ${BASH_SOURCE})/chat.sh - -OPENIM_OUTPUT_HOSTBIN="${OPENIM_OUTPUT_BINPATH}/$(openim::util::host_platform)" -export OPENIM_OUTPUT_HOSTBIN -OPENIM_OUTPUT_HOSTBIN_TOOLS="${OPENIM_OUTPUT_BINTOOLPATH}/$(openim::util::host_platform)" -export OPENIM_OUTPUT_HOSTBIN_TOOLS - -export OPENIM_NONSERVER_GROUP_VERSIONS - - -# This emulates "readlink -f" which is not available on MacOS X. -# Test: -# T=/tmp/$$.$RANDOM -# mkdir $T -# touch $T/file -# mkdir $T/dir -# ln -s $T/file $T/linkfile -# ln -s $T/dir $T/linkdir -# function testone() { -# X=$(readlink -f $1 2>&1) -# Y=$(kube::readlinkdashf $1 2>&1) -# if [ "$X" != "$Y" ]; then -# echo readlinkdashf $1: expected "$X", got "$Y" -# fi -# } -# testone / -# testone /tmp -# testone $T -# testone $T/file -# testone $T/dir -# testone $T/linkfile -# testone $T/linkdir -# testone $T/nonexistant -# testone $T/linkdir/file -# testone $T/linkdir/dir -# testone $T/linkdir/linkfile -# testone $T/linkdir/linkdir -function openim::readlinkdashf { - # run in a subshell for simpler 'cd' - ( - if [[ -d "${1}" ]]; then # This also catch symlinks to dirs. - cd "${1}" - pwd -P - else - cd "$(dirname "${1}")" - local f - f=$(basename "${1}") - if [[ -L "${f}" ]]; then - readlink "${f}" - else - echo "$(pwd -P)/${f}" - fi - fi - ) -} - -# This emulates "readlink -f" which is not available on MacOS X. -# Test: -# T=/tmp/$$.$RANDOM -# mkdir $T -# touch $T/file -# mkdir $T/dir -# ln -s $T/file $T/linkfile -# ln -s $T/dir $T/linkdir -# function testone() { -# X=$(readlink -f $1 2>&1) -# Y=$(kube::readlinkdashf $1 2>&1) -# if [ "$X" != "$Y" ]; then -# echo readlinkdashf $1: expected "$X", got "$Y" -# fi -# } -# testone / -# testone /tmp -# testone $T -# testone $T/file -# testone $T/dir -# testone $T/linkfile -# testone $T/linkdir -# testone $T/nonexistant -# testone $T/linkdir/file -# testone $T/linkdir/dir -# testone $T/linkdir/linkfile -# testone $T/linkdir/linkdir -function openim::readlinkdashf { - # run in a subshell for simpler 'cd' - ( - if [[ -d "${1}" ]]; then # This also catch symlinks to dirs. - cd "${1}" - pwd -P - else - cd "$(dirname "${1}")" - local f - f=$(basename "${1}") - if [[ -L "${f}" ]]; then - readlink "${f}" - else - echo "$(pwd -P)/${f}" - fi - fi - ) -} - -# This emulates "realpath" which is not available on MacOS X -# Test: -# T=/tmp/$$.$RANDOM -# mkdir $T -# touch $T/file -# mkdir $T/dir -# ln -s $T/file $T/linkfile -# ln -s $T/dir $T/linkdir -# function testone() { -# X=$(realpath $1 2>&1) -# Y=$(kube::realpath $1 2>&1) -# if [ "$X" != "$Y" ]; then -# echo realpath $1: expected "$X", got "$Y" -# fi -# } -# testone / -# testone /tmp -# testone $T -# testone $T/file -# testone $T/dir -# testone $T/linkfile -# testone $T/linkdir -# testone $T/nonexistant -# testone $T/linkdir/file -# testone $T/linkdir/dir -# testone $T/linkdir/linkfile -# testone $T/linkdir/linkdir -openim::realpath() { - if [[ ! -e "${1}" ]]; then - echo "${1}: No such file or directory" >&2 - return 1 - fi - openim::readlinkdashf "${1}" -} - -# Marker function to indicate init.sh has been fully sourced -openim::init::loaded() { - return 0 -} \ No newline at end of file diff --git a/scripts/lib/logging.sh b/scripts/lib/logging.sh deleted file mode 100755 index 0d15463eb0..0000000000 --- a/scripts/lib/logging.sh +++ /dev/null @@ -1,271 +0,0 @@ -#!/usr/bin/env bash -# 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. - -# Controls verbosity of the script output and logging. -OPENIM_VERBOSE="${OPENIM_VERBOSE:-5}" - -# Enable logging by default. Set to false to disable. -ENABLE_LOGGING="${ENABLE_LOGGING:-true}" - -# If OPENIM_OUTPUT is not set, set it to the default value -if [ -z "${OPENIM_OUTPUT+x}" ]; then - OPENIM_OUTPUT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../../_output" && pwd -P)" -fi - -# Set the log file path -LOG_FILE="${OPENIM_OUTPUT}/logs/openim-$(date '+%Y%m%d').log" -STDERR_LOG_FILE="${OPENIM_OUTPUT}/logs/openim-error-$(date '+%Y%m%d').log" -TMP_LOG_FILE="${OPENIM_OUTPUT}/logs/openim-tmp-$(date '+%Y%m%d').log" -DOCKER_LOG_FILE="${OPENIM_OUTPUT}/logs/openim-docker.log" -if [[ ! -d "${OPENIM_OUTPUT}/logs" ]]; then - mkdir -p "${OPENIM_OUTPUT}/logs" - touch "$LOG_FILE" - touch "$STDERR_LOG_FILE" - touch "$TMP_LOG_FILE" -fi - -if [[ ! -f "$DOCKER_LOG_FILE" ]]; then - touch "$DOCKER_LOG_FILE" -fi - - - -# Define the logging function -function echo_log() { - if $ENABLE_LOGGING; then - echo -e "$@" | tee -a "${LOG_FILE}" - else - echo -e "$@" - fi -} - -# MAX_LOG_SIZE=10485760 # 10MB - -# Clear logs from 5 days ago -# find $OPENIM_OUTPUT_LOGS -type f -name "*.log" -mtime +5 -exec rm -f {} \; - -# Handler for when we exit automatically on an error. -# Borrowed from https://gist.github.com/ahendrix/7030300 -openim::log::errexit() { - local err="${PIPESTATUS[*]}" - - # If the shell we are in doesn't have errexit set (common in subshells) then - # don't dump stacks. - set +o | grep -qe "-o errexit" || return - - set +o xtrace - local code="${1:-1}" - # Print out the stack trace described by $function_stack - if [ ${#FUNCNAME[@]} -gt 2 ] - then - openim::log::error "Call tree:" - for ((i=1;i<${#FUNCNAME[@]}-1;i++)) - do - openim::log::error " ${i}: ${BASH_SOURCE[${i}+1]}:${BASH_LINENO[${i}]} ${FUNCNAME[${i}]}(...)" - done - fi - openim::log::error_exit "Error in ${BASH_SOURCE[1]}:${BASH_LINENO[0]}. '${BASH_COMMAND}' exited with status ${err}" "${1:-1}" 1 -} - -openim::log::install_errexit() { - # trap ERR to provide an error handler whenever a command exits nonzero this - # is a more verbose version of - # trap 'openim::log::errexit' ERR - - # setting errtrace allows our ERR trap handler to be propagated to functions, - # expansions and subshells - #set -o errtrace - return 0 -} - -# Print out the stack trace -# -# Args: -# $1 The number of stack frames to skip when printing. -openim::log::stack() { - local stack_skip=${1:-0} - stack_skip=$((stack_skip + 1)) - if [[ ${#FUNCNAME[@]} -gt ${stack_skip} ]]; then - echo_log "Call stack:" >&2 - local i - for ((i=1 ; i <= ${#FUNCNAME[@]} - stack_skip ; i++)) - do - local frame_no=$((i - 1 + stack_skip)) - local source_file=${BASH_SOURCE[${frame_no}]} - local source_lineno=${BASH_LINENO[$((frame_no - 1))]} - local funcname=${FUNCNAME[${frame_no}]} - echo_log " ${i}: ${source_file}:${source_lineno} ${funcname}(...)" >&2 - done - fi -} - -# Log an error and exit. -# Args: -# $1 Message to log with the error -# $2 The error code to return -# $3 The number of stack frames to skip when printing. -openim::log::error_exit() { - local message="${1:-}" - local code="${2:-1}" - local stack_skip="${3:-0}" - stack_skip=$((stack_skip + 1)) - - if [[ ${OPENIM_VERBOSE} -ge 4 ]]; then - local source_file=${BASH_SOURCE[${stack_skip}]} - local source_line=${BASH_LINENO[$((stack_skip - 1))]} - echo_log -e "${COLOR_RED}!!! Error in ${source_file}:${source_line} ${COLOR_SUFFIX}" >&2 - [[ -z ${1-} ]] || { - echo_log " ${1}" >&2 - } - - openim::log::stack ${stack_skip} - - echo_log "Exiting with status ${code}" >&2 - fi - - exit "${code}" -} - -# Log an error but keep going. Don't dump the stack or exit. -openim::log::error() { - # Define red color - red='\033[0;31m' - # No color (reset) - nc='\033[0m' # No Color - - timestamp=$(date +"[%Y-%m-%d %H:%M:%S %Z]") - # Apply red color for error message - echo_log "${red}!!! ${timestamp} ${1-}${nc}" >&2 - shift - for message; do - # Apply red color for subsequent lines of the error message - echo_log "${red} ${message}${nc}" >&2 - done -} - - -# Print an usage message to stderr. The arguments are printed directly. -openim::log::usage() { - echo_log >&2 - local message - for message; do - echo_log "${message}" >&2 - done - echo_log >&2 -} - -openim::log::usage_from_stdin() { - local messages=() - while read -r line; do - messages+=("${line}") - done - - openim::log::usage "${messages[@]}" -} - -# Print out some info that isn't a top level status line -openim::log::info() { - local V="${V:-0}" - if [[ ${OPENIM_VERBOSE} < ${V} ]]; then - return - fi - - for message; do - echo_log "${message}" - done -} - -# Just like openim::log::info, but no \n, so you can make a progress bar -openim::log::progress() { - for message; do - echo_log -e -n "${message}" - done -} - -# Print out some info that isn't a top level status line -openim::log::info_from_stdin() { - local messages=() - while read -r line; do - messages+=("${line}") - done - - openim::log::info "${messages[@]}" -} - -# Print a status line. Formatted to show up in a stream of output. -openim::log::status() { - local V="${V:-0}" - if [[ ${OPENIM_VERBOSE} < ${V} ]]; then - return - fi - - local COLOR_BLUE="\033[0;34m" - local COLOR_RESET="\033[0m" - - local timestamp=$(date +"[%Y-%m-%d %H:%M:%S %Z]") - - echo_log() { - echo -e "$@" - } - - - echo_log "${COLOR_BLUE}${timestamp} ${1}${COLOR_RESET}" - shift - for message; do - echo_log "${COLOR_BLUE}${message}${COLOR_RESET}" - done -} - - - -openim::log::success() { - local V="${V:-0}" - if [[ ${OPENIM_VERBOSE} < ${V} ]]; then - return - fi - local timestamp=$(date +"%m%d %H:%M:%S") - local reset_color='\033[0m' - echo_log -e "${COLOR_GREEN}[success ${timestamp}]${COLOR_SUFFIX}==> ${COLOR_GREEN}$@${reset_color}" -} - - - -function openim::log::test_log() { - echo_log "test log" - openim::log::info "openim::log::info" - openim::log::progress "openim::log::progress" - openim::log::status "openim::log::status" - openim::log::success "openim::log::success" - openim::log::error "openim::log::error" - openim::log::error_exit "openim::log::error_exit" -} - -# openim::log::test_log - -function openim::log::print_blue() { - echo -e "\033[0;36m$1\033[0m" -} - - -openim::log::colorless() { - local V="${V:-0}" - if [[ ${OPENIM_VERBOSE} < ${V} ]]; then - return - fi - timestamp=$(date +"[%Y-%m-%d %H:%M:%S %Z]") - echo_log -e "${timestamp} ${1} " -} - - diff --git a/scripts/lib/release.sh b/scripts/lib/release.sh deleted file mode 100755 index 3e6cde103d..0000000000 --- a/scripts/lib/release.sh +++ /dev/null @@ -1,670 +0,0 @@ -#!/usr/bin/env bash -# 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. - - -############################################################################### -# Most of the ::release:: namespace functions have been moved to -# github.com/openim/release. Have a look in that repo and specifically in -# lib/releaselib.sh for ::release::-related functionality. -############################################################################### -# example: ./coscli cp/sync -r /home/off-line/docker-off-line/ cos://openim-1306374445/openim/image/amd/off-line/off-line/ -e cos.ap-guangzhou.myqcloud.com -# https://cloud.tencent.com/document/product/436/71763 - -readonly BUCKET="openim-1306374445" -readonly REGION="ap-guangzhou" -readonly COS_RELEASE_DIR="openim-release" -# readonly COS_RELEASE_DIR="openim-advanced-release" # !pro - -# default cos command tool coscli or coscmd -readonly COSTOOL="coscli" - -# This is where the final release artifacts are created locally -readonly RELEASE_STAGE="${LOCAL_OUTPUT_ROOT}/release-stage" -readonly RELEASE_TARS="${LOCAL_OUTPUT_ROOT}/release-tars" -readonly RELEASE_IMAGES="${LOCAL_OUTPUT_ROOT}/release-images" - -# OpenIM github account info -readonly OPENIM_GITHUB_ORG=openimsdk -readonly OPENIM_GITHUB_REPO=open-im-server -# readonly OPENIM_GITHUB_REPO=open-im-server-enterprise # !pro - -readonly ARTIFACT=openim.tar.gz -# readonly ARTIFACT=openim-enterprise.tar.gz # !pro - -readonly CHECKSUM=${ARTIFACT}.sha1sum - -OPENIM_BUILD_CONFORMANCE=${OPENIM_BUILD_CONFORMANCE:-y} -OPENIM_BUILD_PULL_LATEST_IMAGES=${OPENIM_BUILD_PULL_LATEST_IMAGES:-y} - -if [ -z "${OPENIM_ROOT}" ]; then - OPENIM_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd -P)" -fi - -if [ -z "${TOOLS_DIR}" ]; then - TOOLS_DIR="${OPENIM_ROOT}/_output/tools" -fi - -# Validate a ci version -# -# Globals: -# None -# Arguments: -# version -# Returns: -# If version is a valid ci version -# Sets: (e.g. for '1.2.3-alpha.4.56+abcdef12345678') -# VERSION_MAJOR (e.g. '1') -# VERSION_MINOR (e.g. '2') -# VERSION_PATCH (e.g. '3') -# VERSION_PRERELEASE (e.g. 'alpha') -# VERSION_PRERELEASE_REV (e.g. '4') -# VERSION_BUILD_INFO (e.g. '.56+abcdef12345678') -# VERSION_COMMITS (e.g. '56') -function openim::release::parse_and_validate_ci_version() { - # Accept things like "v1.2.3-alpha.4.56+abcdef12345678" or "v1.2.3-beta.4" - local -r version_regex="^v(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)-([a-zA-Z0-9]+)\\.(0|[1-9][0-9]*)(\\.(0|[1-9][0-9]*)\\+[0-9a-f]{7,40})?$" - local -r version="${1-}" - [[ "${version}" =~ ${version_regex} ]] || { - openim::log::error "Invalid ci version: '${version}', must match regex ${version_regex}" - return 1 - } - - # The VERSION variables are used when this file is sourced, hence - # the shellcheck SC2034 'appears unused' warning is to be ignored. - - # shellcheck disable=SC2034 - VERSION_MAJOR="${BASH_REMATCH[1]}" - # shellcheck disable=SC2034 - VERSION_MINOR="${BASH_REMATCH[2]}" - # shellcheck disable=SC2034 - VERSION_PATCH="${BASH_REMATCH[3]}" - # shellcheck disable=SC2034 - VERSION_PRERELEASE="${BASH_REMATCH[4]}" - # shellcheck disable=SC2034 - VERSION_PRERELEASE_REV="${BASH_REMATCH[5]}" - # shellcheck disable=SC2034 - VERSION_BUILD_INFO="${BASH_REMATCH[6]}" - # shellcheck disable=SC2034 - VERSION_COMMITS="${BASH_REMATCH[7]}" -} - -# --------------------------------------------------------------------------- -# Build final release artifacts -function openim::release::clean_cruft() { - # Clean out cruft - find "${RELEASE_STAGE}" -name '*~' -exec rm {} \; - find "${RELEASE_STAGE}" -name '#*#' -exec rm {} \; - find "${RELEASE_STAGE}" -name '.DS*' -exec rm {} \; -} - -function openim::release::package_tarballs() { - # Clean out any old releases - rm -rf "${RELEASE_STAGE}" "${RELEASE_TARS}" "${RELEASE_IMAGES}" - mkdir -p "${RELEASE_TARS}" - openim::release::package_src_tarball & - openim::release::package_client_tarballs & - openim::release::package_openim_manifests_tarball & - openim::release::package_server_tarballs & - openim::util::wait-for-jobs || { openim::log::error "previous tarball phase failed"; return 1; } - - openim::release::package_final_tarball & # _final depends on some of the previous phases - openim::util::wait-for-jobs || { openim::log::error "previous tarball phase failed"; return 1; } -} - -function openim::release::upload_tarballs() { - openim::log::info "upload ${RELEASE_TARS}/* to cos bucket ${BUCKET}." - for file in $(ls ${RELEASE_TARS}/*) - do - if [ "${COSTOOL}" == "coscli" ];then - echo "++++ ${TOOLS_DIR}/coscli cp ${file} cos://${BUCKET}/${COS_RELEASE_DIR}/${OPENIM_GIT_VERSION}/${file##*/}" - ${TOOLS_DIR}/coscli cp "${file}" "cos://${BUCKET}/${COS_RELEASE_DIR}/${OPENIM_GIT_VERSION}/${file##*/}" - ${TOOLS_DIR}/coscli cp "${file}" "cos://${BUCKET}/${COS_RELEASE_DIR}/latest/${file##*/}" - else - coscmd upload "${file}" "${COS_RELEASE_DIR}/${OPENIM_GIT_VERSION}/" - coscmd upload "${file}" "${COS_RELEASE_DIR}/latest/" - fi - done -} - -# Package the source code we built, for compliance/licensing/audit/yadda. -function openim::release::package_src_tarball() { - local -r src_tarball="${RELEASE_TARS}/openim-src.tar.gz" - openim::log::status "Building tarball: src" - if [[ "${OPENIM_GIT_TREE_STATE-}" = 'clean' ]]; then - git archive -o "${src_tarball}" HEAD - else - find "${OPENIM_ROOT}" -mindepth 1 -maxdepth 1 \ - ! \( \ - \( -path "${OPENIM_ROOT}"/_\* -o \ - -path "${OPENIM_ROOT}"/.git\* -o \ - -path "${OPENIM_ROOT}"/.github\* -o \ - -path "${OPENIM_ROOT}"/components\* -o \ - -path "${OPENIM_ROOT}"/logs\* -o \ - -path "${OPENIM_ROOT}"/_output\* -o \ - -path "${OPENIM_ROOT}"/.gitignore\* -o \ - -path "${OPENIM_ROOT}"/.gsemver.yml\* -o \ - -path "${OPENIM_ROOT}"/.config\* -o \ - -path "${OPENIM_ROOT}"/.chglog\* -o \ - -path "${OPENIM_ROOT}"/.gitlint -o \ - -path "${OPENIM_ROOT}"/.golangci.yml -o \ - -path "${OPENIM_ROOT}"/build/goreleaser.yaml -o \ - -path "${OPENIM_ROOT}"/.note.md -o \ - -path "${OPENIM_ROOT}"/.todo.md \ - \) -prune \ - \) -print0 \ - | "${TAR}" czf "${src_tarball}" --transform "s|${OPENIM_ROOT#/*}|openim|" --null -T - - fi -} - -# Package up all of the server binaries -function openim::release::package_server_tarballs() { - # Find all of the built client binaries - local long_platforms=("${LOCAL_OUTPUT_BINPATH}"/*/*) - - if [[ -n ${OPENIM_BUILD_PLATFORMS-} ]]; then - read -ra long_platforms <<< "${OPENIM_BUILD_PLATFORMS}" - fi - - for platform_long in "${long_platforms[@]}"; do - local platform - local platform_tag - platform=${platform_long##${LOCAL_OUTPUT_BINPATH}/} # Strip LOCAL_OUTPUT_BINPATH - platform_tag=${platform/\//-} # Replace a "/" for a "-" - - openim::log::status "Starting tarball: server $platform_tag" - - ( - local release_stage="${RELEASE_STAGE}/server/${platform_tag}/openim" - openim::log::info "release_stage: ${release_stage}" - - rm -rf "${release_stage}" - mkdir -p "${release_stage}/server/bin" - - local server_bins=("${OPENIM_SERVER_BINARIES[@]}") - - openim::log::info " Copy client binaries: ${client_bins[@]/#/${LOCAL_OUTPUT_BINPATH}/${platform}/}" - openim::log::info " Copy client binaries to: ${release_stage}/server/bin" - - # Copy server binaries - cp "${server_bins[@]/#/${LOCAL_OUTPUT_BINPATH}/${platform}/}" \ - "${release_stage}/server/bin/" - - openim::release::clean_cruft - - local package_name="${RELEASE_TARS}/openim-server-${platform_tag}.tar.gz" - openim::release::create_tarball "${package_name}" "${release_stage}/.." - ) & - done - openim::log::status "Waiting on tarballs" - openim::util::wait-for-jobs || { openim::log::error "server tarball creation failed"; exit 1; } -} - -# Package up all of the cross compiled clients. Over time this should grow into -# a full SDK -# Package up all of the cross compiled clients. Over time this should grow into -# a full SDK -function openim::release::package_client_tarballs() { - # Find all of the built client binaries - local long_platforms=("${LOCAL_OUTPUT_BINTOOLSPATH}"/*/*) - if [[ -n ${OPENIM_BUILD_PLATFORMS-} ]]; then - read -ra long_platforms <<< "${OPENIM_BUILD_PLATFORMS}" - fi - # echo "++++ LOCAL_OUTPUT_BINTOOLSPATH: ${LOCAL_OUTPUT_BINTOOLSPATH}" - # LOCAL_OUTPUT_BINTOOLSPATH: /data/workspaces/open-im-server/_output/bin/tools - # echo "++++ long_platforms: ${long_platforms[@]}" - # long_platforms: /data/workspaces/open-im-server/_output/bin/tools/darwin/amd64 /data/workspaces/open-im-server/_output/bin/tools/darwin/arm64 /data/workspaces/open-im-server/_output/bin/tools/linux/amd64 /data/workspaces/open-im-server/_output/bin/tools/linux/arm64 /data/workspaces/open-im-server/_output/bin/tools/linux/mips64 /data/workspaces/open-im-server/_output/bin/tools/linux/mips64le /data/workspaces/open-im-server/_output/bin/tools/linux/ppc64le /data/workspaces/open-im-server/_output/bin/tools/linux/s390x /data/workspaces/open-im-server/_output/bin/tools/windows/amd64 - - for platform_long in "${long_platforms[@]}"; do - local platform - local platform_tag - platform=${platform_long##${LOCAL_OUTPUT_BINTOOLSPATH}/} # Strip LOCAL_OUTPUT_BINTOOLSPATH - platform_tag=${platform/\//-} # Replace a "/" for a "-" - openim::log::status "Starting tarball: client $platform_tag" # darwin-amd64 - - ( - local release_stage="${RELEASE_STAGE}/client/${platform_tag}/openim" - - openim::log::info "release_stage: ${release_stage}" - # ++++ release_stage: /data/workspaces/open-im-server/_output/release-stage/client/darwin-amd64/openim - rm -rf "${release_stage}" - mkdir -p "${release_stage}/client/bin" - - local client_bins=("${OPENIM_CLIENT_BINARIES[@]}") - - # client_bins: changelog component imctl infra ncpu versionchecker yamlfmt - # Copy client binclient_bins:aries - openim::log::info " Copy client binaries: ${client_bins[@]/#/${LOCAL_OUTPUT_BINTOOLSPATH}/${platform}/}" - openim::log::info " Copy client binaries to: ${release_stage}/client/bin" - - cp "${client_bins[@]/#/${LOCAL_OUTPUT_BINTOOLSPATH}/${platform}/}" \ - "${release_stage}/client/bin/" - - openim::release::clean_cruft - - local package_name="${RELEASE_TARS}/openim-client-${platform_tag}.tar.gz" - openim::release::create_tarball "${package_name}" "${release_stage}/.." - ) & - done - openim::log::status "Waiting on tarballs" - openim::util::wait-for-jobs || { openim::log::error "client tarball creation failed"; exit 1; } -} - -# Package up all of the server binaries in docker images -function openim::release::build_server_images() { - # Clean out any old images - rm -rf "${RELEASE_IMAGES}" - local platform - for platform in "${OPENIM_SERVER_PLATFORMS[@]}"; do - local platform_tag - local arch - platform_tag=${platform/\//-} # Replace a "/" for a "-" - arch=$(basename "${platform}") - openim::log::status "Building images: $platform_tag" - - local release_stage - release_stage="${RELEASE_STAGE}/server/${platform_tag}/openim" - rm -rf "${release_stage}" - mkdir -p "${release_stage}/server/bin" - - # This fancy expression will expand to prepend a path - # (${LOCAL_OUTPUT_BINPATH}/${platform}/) to every item in the - # OPENIM_SERVER_IMAGE_BINARIES array. - cp "${OPENIM_SERVER_IMAGE_BINARIES[@]/bin/#/${LOCAL_OUTPUT_BINPATH}/${platform}/}" \ - "${release_stage}/server/bin/" - - openim::release::create_docker_images_for_server "${release_stage}/server/bin" "${arch}" - done -} - -function openim::release::md5() { - if which md5 >/dev/null 2>&1; then - md5 -q "$1" - else - md5sum "$1" | awk '{ print $1 }' - fi -} - -function openim::release::sha1() { - if which sha1sum >/dev/null 2>&1; then - sha1sum "$1" | awk '{ print $1 }' - else - shasum -a1 "$1" | awk '{ print $1 }' - fi -} - -function openim::release::sha256() { - if which sha256sum >/dev/null 2>&1; then - sha256sum "$1" | awk '{ print $1 }' - else - shasum -a256 "$1" | awk '{ print $1 }' - fi -} - - -function openim::release::build_conformance_image() { - local -r arch="$1" - local -r registry="$2" - local -r version="$3" - local -r save_dir="${4-}" - openim::log::status "Building conformance image for arch: ${arch}" - ARCH="${arch}" REGISTRY="${registry}" VERSION="${version}" \ - make -C cluster/images/conformance/ build >/dev/null - - local conformance_tag - conformance_tag="${registry}/conformance-${arch}:${version}" - if [[ -n "${save_dir}" ]]; then - "${DOCKER[@]}" save "${conformance_tag}" > "${save_dir}/conformance-${arch}.tar" - fi - openim::log::status "Deleting conformance image ${conformance_tag}" - "${DOCKER[@]}" rmi "${conformance_tag}" &>/dev/null || true -} - -# This builds all the release docker images (One docker image per binary) -# Args: -# $1 - binary_dir, the directory to save the tared images to. -# $2 - arch, architecture for which we are building docker images. -function openim::release::create_docker_images_for_server() { - # Create a sub-shell so that we don't pollute the outer environment - ( - local binary_dir - local arch - local binaries - local images_dir - binary_dir="$1" - arch="$2" - binaries=$(openim::build::get_docker_wrapped_binaries "${arch}") - images_dir="${RELEASE_IMAGES}/${arch}" - mkdir -p "${images_dir}" - - # k8s.gcr.io is the constant tag in the docker archives, this is also the default for config scripts in GKE. - # We can use OPENIM_DOCKER_REGISTRY to include and extra registry in the docker archive. - # If we use OPENIM_DOCKER_REGISTRY="k8s.gcr.io", then the extra tag (same) is ignored, see release_docker_image_tag below. - local -r docker_registry="k8s.gcr.io" - # Docker tags cannot contain '+' - local docker_tag="${OPENIM_GIT_VERSION/+/_}" - if [[ -z "${docker_tag}" ]]; then - openim::log::error "git version information missing; cannot create Docker tag" - return 1 - fi - - # provide `--pull` argument to `docker build` if `OPENIM_BUILD_PULL_LATEST_IMAGES` - # is set to y or Y; otherwise try to build the image without forcefully - # pulling the latest base image. - local docker_build_opts - docker_build_opts= - if [[ "${OPENIM_BUILD_PULL_LATEST_IMAGES}" =~ [yY] ]]; then - docker_build_opts='--pull' - fi - - for wrappable in $binaries; do - - local binary_name=${wrappable%%,*} - local base_image=${wrappable##*,} - local binary_file_path="${binary_dir}/${binary_name}" - local docker_build_path="${binary_file_path}.dockerbuild" - local docker_file_path="${docker_build_path}/Dockerfile" - local docker_image_tag="${docker_registry}/${binary_name}-${arch}:${docker_tag}" - - openim::log::status "Starting docker build for image: ${binary_name}-${arch}" - ( - rm -rf "${docker_build_path}" - mkdir -p "${docker_build_path}" - ln "${binary_file_path}" "${docker_build_path}/${binary_name}" - ln "${OPENIM_ROOT}/build/nsswitch.conf" "${docker_build_path}/nsswitch.conf" - chmod 0644 "${docker_build_path}/nsswitch.conf" - cat < "${docker_file_path}" -FROM ${base_image} -COPY ${binary_name} /usr/local/bin/${binary_name} -EOF - # ensure /etc/nsswitch.conf exists so go's resolver respects /etc/hosts - if [[ "${base_image}" =~ busybox ]]; then - echo "COPY nsswitch.conf /etc/" >> "${docker_file_path}" - fi - - "${DOCKER[@]}" build ${docker_build_opts:+"${docker_build_opts}"} -q -t "${docker_image_tag}" "${docker_build_path}" >/dev/null - # If we are building an official/alpha/beta release we want to keep - # docker images and tag them appropriately. - local -r release_docker_image_tag="${OPENIM_DOCKER_REGISTRY-$docker_registry}/${binary_name}-${arch}:${OPENIM_DOCKER_IMAGE_TAG-$docker_tag}" - if [[ "${release_docker_image_tag}" != "${docker_image_tag}" ]]; then - openim::log::status "Tagging docker image ${docker_image_tag} as ${release_docker_image_tag}" - "${DOCKER[@]}" rmi "${release_docker_image_tag}" 2>/dev/null || true - "${DOCKER[@]}" tag "${docker_image_tag}" "${release_docker_image_tag}" 2>/dev/null - fi - "${DOCKER[@]}" save -o "${binary_file_path}.tar" "${docker_image_tag}" "${release_docker_image_tag}" - echo "${docker_tag}" > "${binary_file_path}.docker_tag" - rm -rf "${docker_build_path}" - ln "${binary_file_path}.tar" "${images_dir}/" - - openim::log::status "Deleting docker image ${docker_image_tag}" - "${DOCKER[@]}" rmi "${docker_image_tag}" &>/dev/null || true - ) & - done - - if [[ "${OPENIM_BUILD_CONFORMANCE}" =~ [yY] ]]; then - openim::release::build_conformance_image "${arch}" "${docker_registry}" \ - "${docker_tag}" "${images_dir}" & - fi - - openim::util::wait-for-jobs || { openim::log::error "previous Docker build failed"; return 1; } - openim::log::status "Docker builds done" - ) - -} - -# This will pack openim-system manifests files for distros such as COS. -function openim::release::package_openim_manifests_tarball() { - openim::log::status "Building tarball: manifests" - - local src_dir="${OPENIM_ROOT}/deployments" - - local release_stage="${RELEASE_STAGE}/manifests/openim" - rm -rf "${release_stage}" - - local dst_dir="${release_stage}" - mkdir -p "${dst_dir}" - cp -r ${src_dir}/* "${dst_dir}" - #cp "${src_dir}/openim-api.yaml" "${dst_dir}" - #cp "${src_dir}/openim-cmdutils.yaml" "${dst_dir}" - #cp "${src_dir}/openim-crontask.yaml" "${dst_dir}" - #cp "${src_dir}/openim-msggateway.yaml" "${dst_dir}" - #cp "${src_dir}/openim-msgtransfer.yaml" "${dst_dir}" - #cp "${src_dir}/openim-push.yaml" "${dst_dir}" - #cp "${src_dir}/openim-rpc-auth.yaml" "${dst_dir}" - #cp "${src_dir}/openim-rpc-conversation.yaml" "${dst_dir}" - #cp "${src_dir}/openim-rpc-friend.yaml" "${dst_dir}" - #cp "${src_dir}/openim-rpc-group.yaml" "${dst_dir}" - #cp "${src_dir}/openim-rpc-msg.yaml" "${dst_dir}" - #cp "${src_dir}/openim-rpc-third.yaml" "${dst_dir}" - #cp "${src_dir}/openim-rpc-user.yaml" "${dst_dir}" - #cp "${OPENIM_ROOT}/cluster/gce/gci/health-monitor.sh" "${dst_dir}/health-monitor.sh" - - openim::release::clean_cruft - - local package_name="${RELEASE_TARS}/openim-manifests.tar.gz" - openim::release::create_tarball "${package_name}" "${release_stage}/.." -} - -# This is all the platform-independent stuff you need to run/install openim. -# Arch-specific binaries will need to be downloaded separately (possibly by -# using the bundled cluster/get-openim-binaries.sh script). -# Included in this tarball: -# - Cluster spin up/down scripts and configs for various cloud providers -# - Tarballs for manifest configs that are ready to be uploaded -# - Examples (which may or may not still work) -# - The remnants of the docs/ directory -function openim::release::package_final_tarball() { - openim::log::status "Building tarball: final" - - # This isn't a "full" tarball anymore, but the release lib still expects - # artifacts under "full/openim/" - local release_stage="${RELEASE_STAGE}/full/openim" - openim::log::info "release_stage(final): ${release_stage}" - rm -rf "${release_stage}" - mkdir -p "${release_stage}" - - mkdir -p "${release_stage}/client" - cat < "${release_stage}/client/README" -Client binaries are no longer included in the OpenIM final tarball. - -Run release/get-openim-binaries.sh to download client and server binaries. -EOF - - # We want everything in /scripts. - mkdir -p "${release_stage}/release" - mkdir -p "${OPENIM_ROOT}/scripts/release" - cp -R "${OPENIM_ROOT}/scripts/release" "${release_stage}/" - cat < "${release_stage}/release/get-openim-binaries.sh" -#!/usr/bin/env bash -# This file download openim client and server binaries from tencent cos bucket. - -os=linux arch=amd64 version=${OPENIM_GIT_VERSION} && wget https://${BUCKET}.cos.${REGION}.myqcloud.com/${COS_RELEASE_DIR}/\$version/{openim-client-\$os-\$arch.tar.gz,openim-server-\$os-\$arch.tar.gz} -EOF - chmod +x ${release_stage}/release/get-openim-binaries.sh - - mkdir -p "${release_stage}/server" - cp "${RELEASE_TARS}/openim-manifests.tar.gz" "${release_stage}/server/" - cat < "${release_stage}/server/README" -Server binary tarballs are no longer included in the OpenIM final tarball. - -Run release/get-openim-binaries.sh to download client and server binaries. -EOF - - # Include scripts/lib as a dependency for the cluster/ scripts - #mkdir -p "${release_stage}/hack" - #cp -R "${OPENIM_ROOT}/scripts/lib" "${release_stage}/scripts/" - - cp -R "${OPENIM_ROOT}"/{docs,config,scripts,deployments,README.md,LICENSE} "${release_stage}/" - - echo "${OPENIM_GIT_VERSION}" > "${release_stage}/version" - - openim::release::clean_cruft - - local package_name="${RELEASE_TARS}/${ARTIFACT}" - openim::release::create_tarball "${package_name}" "${release_stage}/.." -} - -# Build a release tarball. $1 is the output tar name. $2 is the base directory -# of the files to be packaged. This assumes that ${2}/iamis what is -# being packaged. -function openim::release::create_tarball() { - openim::build::ensure_tar - - local tarfile=$1 - local stagingdir=$2 - - "${TAR}" czf "${tarfile}" -C "${stagingdir}" openim --owner=0 --group=0 -} - -function openim::release::install_github_release(){ - GO111MODULE=on go install github.com/github-release/github-release@latest -} - -# Require the following tools: -# - github-release -# - gsemver -# - git-chglog -# - coscmd or coscli -function openim::release::verify_prereqs(){ - if [ -z "$(which ${TOOLS_DIR}/github-release 2>/dev/null)" ]; then - openim::log::info "'github-release' tool not installed, try to install it." - - if ! openim::release::install_github_release; then - openim::log::error "failed to install 'github-release'" - return 1 - fi - fi - - if [ -z "$(which ${TOOLS_DIR}/git-chglog 2>/dev/null)" ]; then - openim::log::info "'git-chglog' tool not installed, try to install it." - - if ! go install github.com/git-chglog/git-chglog/cmd/git-chglog@latest &>/dev/null; then - openim::log::error "failed to install 'git-chglog'" - return 1 - fi - fi - - if [ -z "$(which ${TOOLS_DIR}/gsemver 2>/dev/null)" ]; then - openim::log::info "'gsemver' tool not installed, try to install it." - - if ! go install github.com/arnaud-deprez/gsemver@latest &>/dev/null; then - openim::log::error "failed to install 'gsemver'" - return 1 - fi - fi - - if [ -z "$(which ${TOOLS_DIR}/${COSTOOL} 2>/dev/null)" ]; then - openim::log::info "${COSTOOL} tool not installed, try to install it." - - if ! make -C "${OPENIM_ROOT}" tools.install.${COSTOOL}; then - openim::log::error "failed to install ${COSTOOL}" - return 1 - fi - fi - - if [ -z "${TENCENT_SECRET_ID}" -o -z "${TENCENT_SECRET_KEY}" ];then - openim::log::info "You need set env: TENCENT_SECRET_ID(cos secretid) and TENCENT_SECRET_KEY(cos secretkey)" - openim::log::error "can not find env: TENCENT_SECRET_ID and TENCENT_SECRET_KEY" - return 1 - fi - - if [ "${COSTOOL}" == "coscli" ];then - if [ ! -f "${HOME}/.cos.yaml" ];then - cat << EOF > "${HOME}/.cos.yaml" -cos: - base: - secretid: ${TENCENT_SECRET_ID} - secretkey: ${TENCENT_SECRET_KEY} - sessiontoken: "" - buckets: - - name: ${BUCKET} - alias: ${BUCKET} - region: ${REGION} -EOF - fi - else - if [ ! -f "${HOME}/.cos.conf" ];then - cat << EOF > "${HOME}/.cos.conf" -[common] -secret_id = ${TENCENT_SECRET_ID} -secret_key = ${TENCENT_SECRET_KEY} -bucket = ${BUCKET} -region =${REGION} -max_thread = 5 -part_size = 1 -schema = https -EOF - fi - fi -} - -# Create a github release with specified tarballs. -# NOTICE: Must export 'GITHUB_TOKEN' env in the shell, details: -# https://github.com/github-release/github-release -function openim::release::github_release() { - # create a github release - if [ -z "${GITHUB_TOKEN}" ];then - openim::log::error "can not find env: GITHUB_TOKEN" - return 1 - fi - openim::log::info "create a new github release with tag ${OPENIM_GIT_VERSION}" - ${TOOLS_DIR}/github-release release \ - --user ${OPENIM_GITHUB_ORG} \ - --repo ${OPENIM_GITHUB_REPO} \ - --tag ${OPENIM_GIT_VERSION} \ - --description "" \ - --pre-release \ - --draft - - # update openim tarballs - openim::log::info "upload ${ARTIFACT} to release ${OPENIM_GIT_VERSION}" - ${TOOLS_DIR}/github-release upload \ - --user ${OPENIM_GITHUB_ORG} \ - --repo ${OPENIM_GITHUB_REPO} \ - --tag ${OPENIM_GIT_VERSION} \ - --name ${ARTIFACT} \ - --label "openim-${OPENIM_GIT_VERSION}" \ - --file ${RELEASE_TARS}/${ARTIFACT} - - for file in ${RELEASE_TARS}/*.tar.gz; do - if [[ -f "$file" ]]; then - filename=$(basename "$file") - openim::log::info "Update file ${filename} to release vertion ${OPENIM_GIT_VERSION}" - ${TOOLS_DIR}/github-release upload \ - --user ${OPENIM_GITHUB_ORG} \ - --repo ${OPENIM_GITHUB_REPO} \ - --tag ${OPENIM_GIT_VERSION} \ - --name "${filename}" \ - --file "${file}" - fi - done -} - -function openim::release::generate_changelog() { - openim::log::info "generate CHANGELOG-${OPENIM_GIT_VERSION#v}.md and commit it" - - local major_version=$(echo ${OPENIM_GIT_VERSION} | cut -d '+' -f 1) - - ${TOOLS_DIR}/git-chglog --config ${OPENIM_ROOT}/CHANGELOG/.chglog/config.yml ${OPENIM_GIT_VERSION} > ${OPENIM_ROOT}/CHANGELOG/CHANGELOG-${major_version#v}.md - - set +o errexit - git add "${OPENIM_ROOT}"/CHANGELOG/CHANGELOG-${major_version#v}.md - git commit -a -m "docs(changelog): add CHANGELOG-${major_version#v}.md" - echo "" - echo "##########################################################################" - echo "git commit -a -m \"docs(changelog): add CHANGELOG-${major_version#v}.md\"" - openim::log::info "You need git push CHANGELOG-${major_version#v}.md to remote" - echo "##########################################################################" - echo "" -} diff --git a/scripts/lib/util.sh b/scripts/lib/util.sh deleted file mode 100755 index 13bd263caf..0000000000 --- a/scripts/lib/util.sh +++ /dev/null @@ -1,2896 +0,0 @@ -#!/usr/bin/env bash -# 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. - -# this script is used to check whether the code is formatted by gofmt or not -# -# Usage: source scripts/lib/util.sh -################################################################################ - -# TODO Debug: Just for testing, please comment out -# OPENIM_ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")"/../.. && pwd -P) -# source "${OPENIM_ROOT}/scripts/lib/logging.sh" - -#1、将IP写在一个文件里,比如文件名为hosts_file,一行一个IP地址。 -#2、修改ssh-mutual-trust.sh里面的用户名及密码,默认为root用户及密码123。 -# hosts_file_path="path/to/your/hosts/file" -# openim:util::setup_ssh_key_copy "$hosts_file_path" "root" "123" -function openim:util::setup_ssh_key_copy() { - local hosts_file="$1" - local username="${2:-root}" - local password="${3:-123}" - - local sshkey_file=~/.ssh/id_rsa.pub - - # check sshkey file - if [[ ! -e $sshkey_file ]]; then - expect -c " - spawn ssh-keygen -t rsa - expect \"Enter*\" { send \"\n\"; exp_continue; } - " - fi - - # get hosts list - local hosts=$(awk '/^[^#]/ {print $1}' "${hosts_file}") - - ssh_key_copy() { - local target=$1 - - # delete history - sed -i "/$target/d" ~/.ssh/known_hosts - - # copy key - expect -c " - set timeout 100 - spawn ssh-copy-id $username@$target - expect { - \"yes/no\" { send \"yes\n\"; exp_continue; } - \"*assword\" { send \"$password\n\"; } - \"already exist on the remote system\" { exit 1; } - } - expect eof - " - } - - # auto sshkey pair - for host in $hosts; do - if ! ping -i 0.2 -c 3 -W 1 "$host" > /dev/null 2>&1; then - echo "[ERROR]: Can't connect $host" - continue - fi - - local host_entry=$(awk "/$host/"'{print $1, $2}' /etc/hosts) - if [[ $host_entry ]]; then - local hostaddr=$(echo "$host_entry" | awk '{print $1}') - local hostname=$(echo "$host_entry" | awk '{print $2}') - ssh_key_copy "$hostaddr" - ssh_key_copy "$hostname" - else - ssh_key_copy "$host" - fi - done -} - -function openim::util::sourced_variable { - # Call this function to tell shellcheck that a variable is supposed to - # be used from other calling context. This helps quiet an "unused - # variable" warning from shellcheck and also document your code. - true -} - -openim::util::sortable_date() { - date "+%Y%m%d-%H%M%S" -} - -# arguments: target, item1, item2, item3, ... -# returns 0 if target is in the given items, 1 otherwise. -openim::util::array_contains() { - local search="$1" - local element - shift - for element; do - if [[ "${element}" == "${search}" ]]; then - return 0 - fi - done - return 1 -} - -openim::util::wait_for_url() { - local url=$1 - local prefix=${2:-} - local wait=${3:-1} - local times=${4:-30} - local maxtime=${5:-1} - - command -v curl >/dev/null || { - openim::log::usage "curl must be installed" - exit 1 - } - - local i - for i in $(seq 1 "${times}"); do - local out - if out=$(curl --max-time "${maxtime}" -gkfs "${url}" 2>/dev/null); then - openim::log::status "On try ${i}, ${prefix}: ${out}" - return 0 - fi - sleep "${wait}" - done - openim::log::error "Timed out waiting for ${prefix} to answer at ${url}; tried ${times} waiting ${wait} between each" - return 1 -} - -# Example: openim::util::wait_for_success 120 5 "openimctl get nodes|grep localhost" -# arguments: wait time, sleep time, shell command -# returns 0 if the shell command get output, 1 otherwise. -openim::util::wait_for_success(){ - local wait_time="$1" - local sleep_time="$2" - local cmd="$3" - while [ "$wait_time" -gt 0 ]; do - if eval "$cmd"; then - return 0 - else - sleep "$sleep_time" - wait_time=$((wait_time-sleep_time)) - fi - done - return 1 -} - -# Example: openim::util::trap_add 'echo "in trap DEBUG"' DEBUG -# See: http://stackoverflow.com/questions/3338030/multiple-bash-traps-for-the-same-signal -openim::util::trap_add() { - local trap_add_cmd - trap_add_cmd=$1 - shift - - for trap_add_name in "$@"; do - local existing_cmd - local new_cmd - - # Grab the currently defined trap commands for this trap - existing_cmd=$(trap -p "${trap_add_name}" | awk -F"'" '{print $2}') - - if [[ -z "${existing_cmd}" ]]; then - new_cmd="${trap_add_cmd}" - else - new_cmd="${trap_add_cmd};${existing_cmd}" - fi - - # Assign the test. Disable the shellcheck warning telling that trap - # commands should be single quoted to avoid evaluating them at this - # point instead evaluating them at run time. The logic of adding new - # commands to a single trap requires them to be evaluated right away. - # shellcheck disable=SC2064 - trap "${new_cmd}" "${trap_add_name}" - done -} - -# Opposite of openim::util::ensure-temp-dir() -openim::util::cleanup-temp-dir() { - rm -rf "${OPENIM_TEMP}" -} - -# Create a temp dir that'll be deleted at the end of this bash session. -# -# Vars set: -# OPENIM_TEMP -openim::util::ensure-temp-dir() { - if [[ -z ${OPENIM_TEMP-} ]]; then - OPENIM_TEMP=$(mktemp -d 2>/dev/null || mktemp -d -t openimrnetes.XXXXXX) - openim::util::trap_add openim::util::cleanup-temp-dir EXIT - fi -} - -openim::util::host_os() { - local host_os - case "$(uname -s)" in - Darwin) - host_os=darwin - ;; - Linux) - host_os=linux - ;; - *) - openim::log::error "Unsupported host OS. Must be Linux or Mac OS X." - exit 1 - ;; - esac - echo "${host_os}" -} - -openim::util::host_arch() { - local host_arch - case "$(uname -m)" in - x86_64*) - host_arch=amd64 - ;; - i?86_64*) - host_arch=amd64 - ;; - amd64*) - host_arch=amd64 - ;; - aarch64*) - host_arch=arm64 - ;; - arm64*) - host_arch=arm64 - ;; - arm*) - host_arch=arm - ;; - i?86*) - host_arch=x86 - ;; - s390x*) - host_arch=s390x - ;; - ppc64le*) - host_arch=ppc64le - ;; - *) - openim::log::error "Unsupported host arch. Must be x86_64, 386, arm, arm64, s390x or ppc64le." - exit 1 - ;; - esac - echo "${host_arch}" -} - -# Define a bash function to check the versions of Docker and Docker Compose -openim::util::check_docker_and_compose_versions() { - # Define the required versions of Docker and Docker Compose - required_docker_version="20.10.0" - required_compose_version="2.0" - - # Get the currently installed Docker version - installed_docker_version=$(docker --version | awk '{print $3}' | sed 's/,//') - - # Check if the installed Docker version matches the required version - if [[ "$installed_docker_version" < "$required_docker_version" ]]; then - echo "Docker version mismatch. Installed: $installed_docker_version, Required: $required_docker_version" - return 1 - fi - - # Check if the docker compose sub-command is available - if ! docker compose version &> /dev/null; then - echo "Docker does not support the docker compose sub-command" - echo "You need to upgrade Docker to the right version" - return 1 - fi - - # Get the currently installed Docker Compose version - installed_compose_version=$(docker compose version --short) - - # Check if the installed Docker Compose version matches the required version - if [[ "$installed_compose_version" < "$required_compose_version" ]]; then - echo "Docker Compose version mismatch. Installed: $installed_compose_version, Required: $required_compose_version" - return 1 - fi - -} - - -# The `openim::util::check_ports` function analyzes the state of processes based on given ports. -# It accepts multiple ports as arguments and prints: -# 1. The state of the process (whether it's running or not). -# 2. The start time of the process if it's running. -# User: -# openim::util::check_ports 8080 8081 8082 -# The function returns a status of 1 if any of the processes is not running. -openim::util::check_ports() { - # An array to collect ports of processes that are not running. - local not_started=() - - # An array to collect information about processes that are running. - local started=() - - echo "Checking ports: $*" - # Iterate over each given port. - for port in "$@"; do - # Initialize variables - # Check the OS and use the appropriate command - if [[ "$OSTYPE" == "linux-gnu"* ]]; then - if command -v ss > /dev/null 2>&1; then - info=$(ss -ltnp | grep ":$port" || true) - else - info=$(netstat -ltnp | grep ":$port" || true) - fi - elif [[ "$OSTYPE" == "darwin"* ]]; then - # For macOS, use lsof - info=$(lsof -P -i:"$port" | grep "LISTEN" || true) - fi - - # Check if any process is using the port - if [[ -z $info ]]; then - not_started+=($port) - else - if [[ "$OSTYPE" == "linux-gnu"* ]]; then - # Extract relevant details for Linux: Process Name, PID, and FD. - details=$(echo $info | sed -n 's/.*users:(("\([^"]*\)",pid=\([^,]*\),fd=\([^)]*\))).*/\1 \2 \3/p') - command=$(echo $details | awk '{print $1}') - pid=$(echo $details | awk '{print $2}') - fd=$(echo $details | awk '{print $3}') - elif [[ "$OSTYPE" == "darwin"* ]]; then - # Handle extraction for macOS - pid=$(echo $info | awk '{print $2}' | cut -d'/' -f1) - command=$(ps -p $pid -o comm= | xargs basename) - fd=$(echo $info | awk '{print $4}' | cut -d'/' -f1) - fi - - # Get the start time of the process using the PID - if [[ -z $pid ]]; then - start_time="N/A" - else - start_time=$(ps -p $pid -o lstart=) - fi - - started+=("Port $port - Command: $command, PID: $pid, FD: $fd, Started: $start_time") - fi - done - - # Print information about ports whose processes are not running. - if [[ ${#not_started[@]} -ne 0 ]]; then - echo "### Not started ports:" - for port in "${not_started[@]}"; do - openim::log::error "Port $port is not started." - done - fi - - # Print information about ports whose processes are running. - if [[ ${#started[@]} -ne 0 ]]; then - echo "### Started ports:" - for info in "${started[@]}"; do - echo "$info" - done - fi - - # If any of the processes is not running, return a status of 1. - if [[ ${#not_started[@]} -ne 0 ]]; then - #openim::color::echo $COLOR_RED "OpenIM Stdout Log >> cat ${LOG_FILE}" - #openim::color::echo $COLOR_RED "OpenIM Stderr Log >> cat ${STDERR_LOG_FILE}" - cat "$TMP_LOG_FILE" | awk '{print "\033[31m" $0 "\033[0m"}' - return 1 - else - #openim::log::success "All specified ports are running." - return 0 - fi -} - -# set +o errexit -# Sample call for testing: -# openim::util::check_ports 10002 1004 12345 13306 -# - -# The `openim::util::check_process_names` function analyzes the state of processes based on given names. -# It accepts multiple process names as arguments and prints: -# 1. The state of the process (whether it's running or not). -# 2. The start time of the process if it's running. -# User: -# openim::util::check_process_names nginx mysql redis -# The function returns a status of 1 if any of the processes is not running. -openim::util::check_process_names() { - # Function to get the port of a process - get_port() { - local pid=$1 - if [[ "$OSTYPE" == "linux-gnu"* ]]; then - # Linux - ss -ltnp 2>/dev/null | grep $pid | awk '{print $4}' | cut -d ':' -f2 - elif [[ "$OSTYPE" == "darwin"* ]]; then - # macOS - lsof -nP -iTCP -sTCP:LISTEN -a -p $pid | awk 'NR>1 {print $9}' | sed 's/.*://' - else - echo "Unsupported OS" - return 1 - fi - } - - # Arrays to collect details of processes - local not_started=() - local started=() - - # Iterate over each given process name - for process_name in "$@"; do - # Use `pgrep` to find process IDs related to the given process name - local pids=($(pgrep -f $process_name)) - - # Check if any process IDs were found - if [[ ${#pids[@]} -eq 0 ]]; then - not_started+=($process_name) - else - # If there are PIDs, loop through each one - for pid in "${pids[@]}"; do - local command=$(ps -p $pid -o comm=) - local start_time=$(ps -p $pid -o lstart=) - local port=$(get_port $pid) - - # Check if port information was found for the PID - if [[ -z $port ]]; then - port="N/A" - fi - - started+=("Process $process_name - Command: $command, PID: $pid, Port: $port, Start time: $start_time") - done - fi - done - - - # Print information - if [[ ${#not_started[@]} -ne 0 ]]; then - echo "Not started processes:" - for process_name in "${not_started[@]}"; do - echo "Process $process_name is not started." - done - fi - - if [[ ${#started[@]} -ne 0 ]]; then - echo - echo "Started processes:" - for info in "${started[@]}"; do - echo "$info" - done - fi - - # Return status - if [[ ${#not_started[@]} -ne 0 ]]; then - #openim::color::echo $COLOR_RED "OpenIM Stdout Log >> cat ${LOG_FILE}" - #openim::color::echo $COLOR_RED "OpenIM Stderr Log >> cat ${STDERR_LOG_FILE}" - cat "$TMP_LOG_FILE" | awk '{print "\033[31m" $0 "\033[0m"}' - return 1 - else - echo "" - openim::log::success "All processes are running." - return 0 - fi -} - -openim::util::check_process_names_for_stop() { - # Function to get the port of a process - get_port() { - local pid=$1 - if [[ "$OSTYPE" == "linux-gnu"* ]]; then - # Linux - ss -ltnp 2>/dev/null | grep $pid | awk '{print $4}' | cut -d ':' -f2 - elif [[ "$OSTYPE" == "darwin"* ]]; then - # macOS - lsof -nP -iTCP -sTCP:LISTEN -a -p $pid | awk 'NR>1 {print $9}' | sed 's/.*://' - else - echo "Unsupported OS" - return 1 - fi - } - - # Arrays to collect details of processes - local not_started=() - local started=() - - - # Iterate over each given process name - for process_name in "$@"; do - # Use `pgrep` to find process IDs related to the given process name - local pids=($(pgrep -f $process_name)) - - # Check if any process IDs were found - if [[ ${#pids[@]} -eq 0 ]]; then - not_started+=($process_name) - else - # If there are PIDs, loop through each one - for pid in "${pids[@]}"; do - local command=$(ps -p $pid -o comm=) - local start_time=$(ps -p $pid -o lstart=) - local port=$(get_port $pid) - - # Check if port information was found for the PID - if [[ -z $port ]]; then - port="N/A" - fi - - started+=("Process $process_name - Command: $command, PID: $pid, Port: $port, Start time: $start_time") - done - fi - done - - - if [[ ${#started[@]} -ne 0 ]]; then - echo - echo "The programs that have not exited are:" - for info in "${started[@]}"; do - echo "$info " - done - return 1 - fi - - return 0 - -} - -# openim::util::check_process_names docker-pr - -# The `openim::util::stop_services_on_ports` function stops services running on specified ports. -# It accepts multiple ports as arguments and performs the following: -# 1. Attempts to stop any services running on the specified ports. -# 2. Prints details of services successfully stopped and those that failed to stop. -# Usage: -# openim::util::stop_services_on_ports 8080 8081 8082 -# The function returns a status of 1 if any service couldn't be stopped. -openim::util::stop_services_on_ports() { - # An array to collect ports of processes that couldn't be stopped. - local not_stopped=() - - # An array to collect information about processes that were stopped. - local stopped=() - - echo "Stopping services on ports: $*" - # Iterate over each given port. - for port in "$@"; do - # Use the `lsof` command to find process information related to the given port. - info=$(lsof -i :$port -n -P | grep LISTEN || true) - - # If there's process information, it means the process associated with the port is running. - if [[ -n $info ]]; then - # Extract the Process ID. - while read -r line; do - local pid=$(echo $line | awk '{print $2}') - - # Try to stop the service by killing its process. - if kill -15 $pid; then - stopped+=($port) - else - not_stopped+=($port) - fi - done <<< "$info" - fi - done - - # Print information about ports whose processes couldn't be stopped. - if [[ ${#not_stopped[@]} -ne 0 ]]; then - echo "Ports that couldn't be stopped:" - for port in "${not_stopped[@]}"; do - openim::log::status "Failed to stop service on port $port." - done - fi - - # Print information about ports whose processes were successfully stopped. - if [[ ${#stopped[@]} -ne 0 ]]; then - for port in "${stopped[@]}"; do - echo "Successfully stopped service on port $port." - done - fi - - # If any of the processes couldn't be stopped, return a status of 1. - if [[ ${#not_stopped[@]} -ne 0 ]]; then - return 1 - else - openim::log::success "All specified services were stopped." - echo "" - return 0 - fi -} -# nc -l -p 12345 -# nc -l -p 123456 -# ps -ef | grep "nc -l" -# openim::util::stop_services_on_ports 1234 12345 - - -# The `openim::util::stop_services_with_name` function stops services with specified names. -# It accepts multiple service names as arguments and performs the following: -# 1. Attempts to stop any services with the specified names. -# 2. Prints details of services successfully stopped and those that failed to stop. -# Usage: -# openim::util::stop_services_with_name nginx apache -# The function returns a status of 1 if any service couldn't be stopped. -openim::util::stop_services_with_name() { - # An array to collect names of processes that couldn't be stopped. - local not_stopped=() - - # An array to collect information about processes that were stopped. - local stopped=() - - # Iterate over each given service name. - for server_name in "$@"; do - # Use the `pgrep` command to find process IDs related to the given service name. - local pids=$(pgrep -f "$server_name") - # If no process was found with the name, add it to the not_stopped list - if [[ -z $pids ]]; then - not_stopped+=("$server_name") - continue - fi - local stopped_this_time=false - for pid in $pids; do - - # Exclude the PID of the current script - if [[ "$pid" == "$$" ]]; then - continue - fi - - # If there's a Process ID, it means the service with the name is running. - if [[ -n $pid ]]; then - # Print the binary path for the PID - binary_path=$(readlink -f /proc/$pid/exe) - openim::log::colorless "stop PID $pid full path: $binary_path" - - # Try to stop the service by killing its process. - if kill -15 $pid 2>/dev/null; then - stopped_this_time=true - fi - fi - done - - - if $stopped_this_time; then - stopped+=("$server_name") - else - not_stopped+=("$server_name") - fi - done - return 0 - -} -# sleep 333333& -# sleep 444444& -# ps -ef | grep "sleep" -# openim::util::stop_services_with_name "sleep 333333" "sleep 444444" - -# This figures out the host platform without relying on golang. We need this as -# we don't want a golang install to be a prerequisite to building yet we need -# this info to figure out where the final binaries are placed. -openim::util::host_platform() { - echo "$(openim::util::host_os)/$(openim::util::host_arch)" -} - -# looks for $1 in well-known output locations for the platform ($2) -# $OPENIM_ROOT must be set -openim::util::find-binary-for-platform() { - local -r lookfor="$1" - local -r platform="$2" - local locations=( - "${OPENIM_ROOT}/_output/bin/${lookfor}" - "${OPENIM_ROOT}/_output/${platform}/${lookfor}" - "${OPENIM_ROOT}/_output/local/bin/${platform}/${lookfor}" - "${OPENIM_ROOT}/_output/platforms/${platform}/${lookfor}" - "${OPENIM_ROOT}/_output/platforms/bin/${platform}/${lookfor}" - ) - - # List most recently-updated location. - local -r bin=$( (ls -t "${locations[@]}" 2>/dev/null || true) | head -1 ) - echo -n "${bin}" -} - -# looks for $1 in well-known output locations for the host platform -# $OPENIM_ROOT must be set -openim::util::find-binary() { - openim::util::find-binary-for-platform "$1" "$(openim::util::host_platform)" -} - -# Run all known doc generators (today gendocs and genman for openimctl) -# $1 is the directory to put those generated documents -openim::util::gen-docs() { - local dest="$1" - - # Find binary - gendocs=$(openim::util::find-binary "gendocs") - genopenimdocs=$(openim::util::find-binary "genopenimdocs") - genman=$(openim::util::find-binary "genman") - genyaml=$(openim::util::find-binary "genyaml") - genfeddocs=$(openim::util::find-binary "genfeddocs") - - # TODO: If ${genfeddocs} is not used from anywhere (it isn't used at - # least from k/k tree), remove it completely. - openim::util::sourced_variable "${genfeddocs}" - - mkdir -p "${dest}/docs/guide/en-US/cmd/openimctl/" - "${gendocs}" "${dest}/docs/guide/en-US/cmd/openimctl/" - - mkdir -p "${dest}/docs/guide/en-US/cmd/" - "${genopenimdocs}" "${dest}/docs/guide/en-US/cmd/" "openim-api" - "${genopenimdocs}" "${dest}/docs/guide/en-US/cmd/" "openim-cmdutils" - "${genopenimdocs}" "${dest}/docs/guide/en-US/cmd/" "openim-crontask" - "${genopenimdocs}" "${dest}/docs/guide/en-US/cmd/" "openim-msggateway" - "${genopenimdocs}" "${dest}/docs/guide/en-US/cmd/" "openim-msgtransfer" - "${genopenimdocs}" "${dest}/docs/guide/en-US/cmd/" "openim-push" - "${genopenimdocs}" "${dest}/docs/guide/en-US/cmd/" "openim-rpc-auth" - "${genopenimdocs}" "${dest}/docs/guide/en-US/cmd/" "openim-rpc-conversation" - "${genopenimdocs}" "${dest}/docs/guide/en-US/cmd/" "openim-rpc-friend" - "${genopenimdocs}" "${dest}/docs/guide/en-US/cmd/" "openim-rpc-group" - "${genopenimdocs}" "${dest}/docs/guide/en-US/cmd/" "openim-rpc-msg" - "${genopenimdocs}" "${dest}/docs/guide/en-US/cmd/" "openim-rpc-third" - "${genopenimdocs}" "${dest}/docs/guide/en-US/cmd/" "openim-rpc-user" - "${genopenimdocs}" "${dest}/docs/guide/en-US/cmd/openimctl" "openimctl" - - mkdir -p "${dest}/docs/man/man1/" -"${genman}" "${dest}/docs/man/man1/" "openim-api" -"${genman}" "${dest}/docs/man/man1/" "openim-cmdutils" -"${genman}" "${dest}/docs/man/man1/" "openim-crontask" -"${genman}" "${dest}/docs/man/man1/" "openim-msggateway" -"${genman}" "${dest}/docs/man/man1/" "openim-msgtransfer" -"${genman}" "${dest}/docs/man/man1/" "openim-push" -"${genman}" "${dest}/docs/man/man1/" "openim-rpc-auth" -"${genman}" "${dest}/docs/man/man1/" "openim-rpc-conversation" -"${genman}" "${dest}/docs/man/man1/" "openim-rpc-friend" -"${genman}" "${dest}/docs/man/man1/" "openim-rpc-group" -"${genman}" "${dest}/docs/man/man1/" "openim-rpc-msg" -"${genman}" "${dest}/docs/man/man1/" "openim-rpc-third" -"${genman}" "${dest}/docs/man/man1/" "openim-rpc-user" - - mkdir -p "${dest}/docs/guide/en-US/yaml/openimctl/" - "${genyaml}" "${dest}/docs/guide/en-US/yaml/openimctl/" - - # create the list of generated files - pushd "${dest}" > /dev/null || return 1 - touch docs/.generated_docs - find . -type f | cut -sd / -f 2- | LC_ALL=C sort > docs/.generated_docs - popd > /dev/null || return 1 -} - -# Removes previously generated docs-- we don't want to check them in. $OPENIM_ROOT -# must be set. -openim::util::remove-gen-docs() { - if [ -e "${OPENIM_ROOT}/docs/.generated_docs" ]; then - # remove all of the old docs; we don't want to check them in. - while read -r file; do - rm "${OPENIM_ROOT}/${file}" 2>/dev/null || true - done <"${OPENIM_ROOT}/docs/.generated_docs" - # The docs/.generated_docs file lists itself, so we don't need to explicitly - # delete it. - fi -} - -# Returns the name of the upstream remote repository name for the local git -# repo, e.g. "upstream" or "origin". -openim::util::git_upstream_remote_name() { - git remote -v | grep fetch |\ - grep -E 'github.com[/:]openimsdk/open-im-server|openim.cc/server' |\ - head -n 1 | awk '{print $1}' -} - -# Exits script if working directory is dirty. If it's run interactively in the terminal -# the user can commit changes in a second terminal. This script will wait. -openim::util::ensure_clean_working_dir() { - while ! git diff HEAD --exit-code &>/dev/null; do - echo -e "\nUnexpected dirty working directory:\n" - if tty -s; then - git status -s - else - git diff -a # be more verbose in log files without tty - exit 1 - fi | sed 's/^/ /' - echo -e "\nCommit your changes in another terminal and then continue here by pressing enter." - read -r - done 1>&2 -} - -# Find the base commit using: -# $PULL_BASE_SHA if set (from Prow) -# current ref from the remote upstream branch -openim::util::base_ref() { - local -r git_branch=$1 - - if [[ -n ${PULL_BASE_SHA:-} ]]; then - echo "${PULL_BASE_SHA}" - return - fi - - full_branch="$(openim::util::git_upstream_remote_name)/${git_branch}" - - # make sure the branch is valid, otherwise the check will pass erroneously. - if ! git describe "${full_branch}" >/dev/null; then - # abort! - exit 1 - fi - - echo "${full_branch}" -} - -# Checks whether there are any files matching pattern $2 changed between the -# current branch and upstream branch named by $1. -# Returns 1 (false) if there are no changes -# 0 (true) if there are changes detected. -openim::util::has_changes() { - local -r git_branch=$1 - local -r pattern=$2 - local -r not_pattern=${3:-totallyimpossiblepattern} - - local base_ref - base_ref=$(openim::util::base_ref "${git_branch}") - echo "Checking for '${pattern}' changes against '${base_ref}'" - - # notice this uses ... to find the first shared ancestor - if git diff --name-only "${base_ref}...HEAD" | grep -v -E "${not_pattern}" | grep "${pattern}" > /dev/null; then - return 0 - fi - # also check for pending changes - if git status --porcelain | grep -v -E "${not_pattern}" | grep "${pattern}" > /dev/null; then - echo "Detected '${pattern}' uncommitted changes." - return 0 - fi - echo "No '${pattern}' changes detected." - return 1 -} - -openim::util::download_file() { - local -r url=$1 - local -r destination_file=$2 - - rm "${destination_file}" 2&> /dev/null || true - - for i in $(seq 5) - do - if ! curl -fsSL --retry 3 --keepalive-time 2 "${url}" -o "${destination_file}"; then - echo "Downloading ${url} failed. $((5-i)) retries left." - sleep 1 - else - echo "Downloading ${url} succeed" - return 0 - fi - done - return 1 -} - -# Test whether openssl is installed. -# Sets: -# OPENSSL_BIN: The path to the openssl binary to use -function openim::util::test_openssl_installed { - if ! openssl version >& /dev/null; then - echo "Failed to run openssl. Please ensure openssl is installed" - exit 1 - fi - - OPENSSL_BIN=$(command -v openssl) -} - -# creates a client CA, args are sudo, dest-dir, ca-id, purpose -# purpose is dropped in after "key encipherment", you usually want -# '"client auth"' -# '"server auth"' -# '"client auth","server auth"' -function openim::util::create_signing_certkey { - local sudo=$1 - local dest_dir=$2 - local id=$3 - local purpose=$4 - # Create client ca - ${sudo} /usr/bin/env bash -e < "${dest_dir}/${id}-ca-config.json" -EOF -} - -# signs a client certificate: args are sudo, dest-dir, CA, filename (roughly), username, groups... -function openim::util::create_client_certkey { - local sudo=$1 - local dest_dir=$2 - local ca=$3 - local id=$4 - local cn=${5:-$4} - local groups="" - local SEP="" - shift 5 - while [ -n "${1:-}" ]; do - groups+="${SEP}{\"O\":\"$1\"}" - SEP="," - shift 1 - done - ${sudo} /usr/bin/env bash -e < /dev/null -apiVersion: v1 -kind: Config -clusters: - - cluster: - certificate-authority: ${ca_file} - server: https://${api_host}:${api_port}/ - name: local-up-cluster -users: - - user: - token: ${token} - client-certificate: ${dest_dir}/client-${client_id}.crt - client-key: ${dest_dir}/client-${client_id}.key - name: local-up-cluster -contexts: - - context: - cluster: local-up-cluster - user: local-up-cluster - name: local-up-cluster -current-context: local-up-cluster -EOF - - # flatten the openimconfig files to make them self contained - username=$(whoami) - ${sudo} /usr/bin/env bash -e < "/tmp/${client_id}.openimconfig" - mv -f "/tmp/${client_id}.openimconfig" "${dest_dir}/${client_id}.openimconfig" - chown ${username} "${dest_dir}/${client_id}.openimconfig" -EOF -} - -# Determines if docker can be run, failures may simply require that the user be added to the docker group. -function openim::util::ensure_docker_daemon_connectivity { - IFS=" " read -ra DOCKER <<< "${DOCKER_OPTS}" - # Expand ${DOCKER[@]} only if it's not unset. This is to work around - # Bash 3 issue with unbound variable. - DOCKER=(docker ${DOCKER[@]:+"${DOCKER[@]}"}) - if ! "${DOCKER[@]}" info > /dev/null 2>&1 ; then - cat <<'EOF' >&2 -Can't connect to 'docker' daemon. please fix and retry. - -Possible causes: - - Docker Daemon not started - - Linux: confirm via your init system - - macOS w/ docker-machine: run `docker-machine ls` and `docker-machine start ` - - macOS w/ Docker for Mac: Check the menu bar and start the Docker application - - DOCKER_HOST hasn't been set or is set incorrectly - - Linux: domain socket is used, DOCKER_* should be unset. In Bash run `unset ${!DOCKER_*}` - - macOS w/ docker-machine: run `eval "$(docker-machine env )"` - - macOS w/ Docker for Mac: domain socket is used, DOCKER_* should be unset. In Bash run `unset ${!DOCKER_*}` - - Other things to check: - - Linux: User isn't in 'docker' group. Add and relogin. - - Something like 'sudo usermod -a -G docker ${USER}' - - RHEL7 bug and workaround: https://bugzilla.redhat.com/show_bug.cgi?id=1119282#c8 -EOF - return 1 - fi -} - -# Wait for background jobs to finish. Return with -# an error status if any of the jobs failed. -openim::util::wait-for-jobs() { - local fail=0 - local job - for job in $(jobs -p); do - wait "${job}" || fail=$((fail + 1)) - done - return ${fail} -} - -# openim::util::join -# Concatenates the list elements with the delimiter passed as first parameter -# -# Ex: openim::util::join , a b c -# -> a,b,c -function openim::util::join { - local IFS="$1" - shift - echo "$*" -} - -# Function: openim::util::list-to-string -# Description: Converts a list to a string, removing spaces, brackets, and commas. -# Example input: [1002 3 , 2 32 3 , 3 434 ,] -# Example output: 10023 2323 3434 -# Example usage: -# result=$(openim::util::list-to-string "[10023, 2323, 3434]") -# echo $result -function openim::util::list-to-string() { - # Capture all arguments into a single string - ports_list="$*" - - # Use sed for transformations: - # 1. Remove spaces - # 2. Replace commas with spaces - # 3. Remove opening and closing brackets - ports_array=$(echo "$ports_list" | sed 's/ //g; s/,/ /g; s/^\[\(.*\)\]$/\1/') - # For external use, we might want to echo the result so that it can be captured by callers - echo "$ports_array" -} -# MSG_GATEWAY_PROM_PORTS=$(openim::util::list-to-string "10023, 2323, 34 34") -# read -a MSG_GATEWAY_PROM_PORTS <<< $(openim::util::list-to-string "10023, 2323, 34 34") -# echo ${MSG_GATEWAY_PROM_PORTS} -# echo "${#MSG_GATEWAY_PROM_PORTS[@]}" -# Downloads cfssl/cfssljson/cfssl-certinfo into $1 directory if they do not already exist in PATH -# -# Assumed vars: -# $1 (cfssl directory) (optional) -# -# Sets: -# CFSSL_BIN: The path of the installed cfssl binary -# CFSSLJSON_BIN: The path of the installed cfssljson binary -# CFSSLCERTINFO_BIN: The path of the installed cfssl-certinfo binary -# -function openim::util::ensure-cfssl { - if command -v cfssl &>/dev/null && command -v cfssljson &>/dev/null && command -v cfssl-certinfo &>/dev/null; then - CFSSL_BIN=$(command -v cfssl) - CFSSLJSON_BIN=$(command -v cfssljson) - CFSSLCERTINFO_BIN=$(command -v cfssl-certinfo) - return 0 - fi - - host_arch=$(openim::util::host_arch) - - if [[ "${host_arch}" != "amd64" ]]; then - echo "Cannot download cfssl on non-amd64 hosts and cfssl does not appear to be installed." - echo "Please install cfssl, cfssljson and cfssl-certinfo and verify they are in \$PATH." - echo "Hint: export PATH=\$PATH:\$GOPATH/bin; go get -u github.com/cloudflare/cfssl/cmd/..." - exit 1 - fi - - # Create a temp dir for cfssl if no directory was given - local cfssldir=${1:-} - if [[ -z "${cfssldir}" ]]; then - cfssldir="$HOME/bin" - fi - - mkdir -p "${cfssldir}" - pushd "${cfssldir}" > /dev/null || return 1 - - echo "Unable to successfully run 'cfssl' from ${PATH}; downloading instead..." - kernel=$(uname -s) - case "${kernel}" in - Linux) - curl --retry 10 -L -o cfssl https://pkg.cfssl.org/R1.2/cfssl_linux-amd64 - curl --retry 10 -L -o cfssljson https://pkg.cfssl.org/R1.2/cfssljson_linux-amd64 - curl --retry 10 -L -o cfssl-certinfo https://pkg.cfssl.org/R1.2/cfssl-certinfo_linux-amd64 - ;; - Darwin) - curl --retry 10 -L -o cfssl https://pkg.cfssl.org/R1.2/cfssl_darwin-amd64 - curl --retry 10 -L -o cfssljson https://pkg.cfssl.org/R1.2/cfssljson_darwin-amd64 - curl --retry 10 -L -o cfssl-certinfo https://pkg.cfssl.org/R1.2/cfssl-certinfo_darwin-amd64 - ;; - *) - echo "Unknown, unsupported platform: ${kernel}." >&2 - echo "Supported platforms: Linux, Darwin." >&2 - exit 2 - esac - - chmod +x cfssl || true - chmod +x cfssljson || true - chmod +x cfssl-certinfo || true - - CFSSL_BIN="${cfssldir}/cfssl" - CFSSLJSON_BIN="${cfssldir}/cfssljson" - CFSSLCERTINFO_BIN="${cfssldir}/cfssl-certinfo" - if [[ ! -x ${CFSSL_BIN} || ! -x ${CFSSLJSON_BIN} || ! -x ${CFSSLCERTINFO_BIN} ]]; then - echo "Failed to download 'cfssl'." - echo "Please install cfssl, cfssljson and cfssl-certinfo and verify they are in \$PATH." - echo "Hint: export PATH=\$PATH:\$GOPATH/bin; go get -u github.com/cloudflare/cfssl/cmd/..." - exit 1 - fi - popd > /dev/null || return 1 -} - -function openim::util::ensure-docker-buildx { - # podman returns 0 on `docker buildx version`, docker on `docker buildx`. One of them must succeed. - if docker buildx version >/dev/null 2>&1 || docker buildx >/dev/null 2>&1; then - return 0 - else - echo "ERROR: docker buildx not available. Docker 19.03 or higher is required with experimental features enabled" - exit 1 - fi -} - -# openim::util::ensure-bash-version -# Check if we are using a supported bash version -# -function openim::util::ensure-bash-version { - # shellcheck disable=SC2004 - if ((${BASH_VERSINFO[0]}<4)) || ( ((${BASH_VERSINFO[0]}==4)) && ((${BASH_VERSINFO[1]}<2)) ); then - echo "ERROR: This script requires a minimum bash version of 4.2, but got version of ${BASH_VERSINFO[0]}.${BASH_VERSINFO[1]}" - if [ "$(uname)" = 'Darwin' ]; then - echo "On macOS with homebrew 'brew install bash' is sufficient." - fi - exit 1 - fi -} - -# openim::util::ensure-install-nginx -# Check if nginx is installed -# -function openim::util::ensure-install-nginx { - if ! command -v nginx &>/dev/null; then - echo "ERROR: nginx not found. Please install nginx." - exit 1 - fi - - for port in "80" - do - if echo |telnet 127.0.0.1 $port 2>&1|grep refused &>/dev/null;then - exit 1 - fi - done -} - -# openim::util::ensure-gnu-sed -# Determines which sed binary is gnu-sed on linux/darwin -# -# Sets: -# SED: The name of the gnu-sed binary -# -function openim::util::ensure-gnu-sed { - # NOTE: the echo below is a workaround to ensure sed is executed before the grep. - # see: https://github.com/openimrnetes/openimrnetes/issues/87251 - sed_help="$(LANG=C sed --help 2>&1 || true)" - if echo "${sed_help}" | grep -q "GNU\|BusyBox"; then - SED="sed" - elif command -v gsed &>/dev/null; then - SED="gsed" - else - openim::log::error "Failed to find GNU sed as sed or gsed. If you are on Mac: brew install gnu-sed." >&2 - return 1 - fi - openim::util::sourced_variable "${SED}" -} - -# openim::util::ensure-gnu-date -# Determines which date binary is gnu-date on linux/darwin -# -# Sets: -# DATE: The name of the gnu-date binary -# -function openim::util::ensure-gnu-date { - # NOTE: the echo below is a workaround to ensure date is executed before the grep. - date_help="$(LANG=C date --help 2>&1 || true)" - if echo "${date_help}" | grep -q "GNU\|BusyBox"; then - DATE="date" - elif command -v gdate &>/dev/null; then - DATE="gdate" - else - openim::log::error "Failed to find GNU date as date or gdate. If you are on Mac: brew install coreutils." >&2 - return 1 - fi - openim::util::sourced_variable "${DATE}" -} - -# openim::util::check-file-in-alphabetical-order -# Check that the file is in alphabetical order -# -function openim::util::check-file-in-alphabetical-order { - local failure_file="$1" - if ! diff -u "${failure_file}" <(LC_ALL=C sort "${failure_file}"); then - { - echo - echo "${failure_file} is not in alphabetical order. Please sort it:" - echo - echo " LC_ALL=C sort -o ${failure_file} ${failure_file}" - echo - } >&2 - false - fi -} - -# openim::util::require-jq -# Checks whether jq is installed. -function openim::util::require-jq { - if ! command -v jq &>/dev/null; then - openim::log::errexit "jq not found. Please install." 1>&2 - fi -} - -# openim::util::require-dig -# Checks whether dig is installed and provides installation instructions if it is not. -function openim::util::require-dig { - if ! command -v dig &>/dev/null; then - openim::log::error "Please install 'dig' to use this feature. OR Set the environment variable for OPENIM_IP" - openim::log::error "Installation instructions:" - openim::log::error " For Ubuntu/Debian: sudo apt-get install dnsutils" - openim::log::error " For CentOS/RedHat: sudo yum install bind-utils" - openim::log::error " For macOS: 'dig' should be preinstalled. If missing, try: brew install bind" - openim::log::error " For Windows: Install BIND9 tools from https://www.isc.org/download/" - openim::log::error_exit "dig command not found." - fi - return 0 -} - -# outputs md5 hash of $1, works on macOS and Linux -function openim::util::md5() { - if which md5 >/dev/null 2>&1; then - md5 -q "$1" - else - md5sum "$1" | awk '{ print $1 }' - fi -} - -# openim::util::read-array -# Reads in stdin and adds it line by line to the array provided. This can be -# used instead of "mapfile -t", and is bash 3 compatible. -# -# Assumed vars: -# $1 (name of array to create/modify) -# -# Example usage: -# openim::util::read-array files < <(ls -1) -# -function openim::util::read-array { - local i=0 - unset -v "$1" - while IFS= read -r "$1[i++]"; do :; done - eval "[[ \${$1[--i]} ]]" || unset "$1[i]" # ensures last element isn't empty -} - -# Some useful colors. -if [[ -z "${color_start-}" ]]; then - declare -r color_start="\033[" - declare -r color_red="${color_start}0;31m" - declare -r color_yellow="${color_start}0;33m" - declare -r color_green="${color_start}0;32m" - declare -r color_blue="${color_start}1;34m" - declare -r color_cyan="${color_start}1;36m" - declare -r color_norm="${color_start}0m" - - openim::util::sourced_variable "${color_start}" - openim::util::sourced_variable "${color_red}" - openim::util::sourced_variable "${color_yellow}" - openim::util::sourced_variable "${color_green}" - openim::util::sourced_variable "${color_blue}" - openim::util::sourced_variable "${color_cyan}" - openim::util::sourced_variable "${color_norm}" -fi - -# ex: ts=2 sw=2 et filetype=sh - -function openim::util::desc() { - openim::util:run::maybe_first_prompt - rate=25 - if [ -n "$DEMO_RUN_FAST" ]; then - rate=1000 - fi - echo "$blue# $@$reset" | pv -qL $rate#!/usr/bin/env bash -# 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. - -# this script is used to check whether the code is formatted by gofmt or not -# -# Usage: source scripts/lib/util.sh -################################################################################ - -# TODO Debug: Just for testing, please comment out -# OPENIM_ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")"/../.. && pwd -P) -# source "${OPENIM_ROOT}/scripts/lib/logging.sh" - -#1、将IP写在一个文件里,比如文件名为hosts_file,一行一个IP地址。 -#2、修改ssh-mutual-trust.sh里面的用户名及密码,默认为root用户及密码123。 -# hosts_file_path="path/to/your/hosts/file" -# openim:util::setup_ssh_key_copy "$hosts_file_path" "root" "123" -function openim:util::setup_ssh_key_copy() { - local hosts_file="$1" - local username="${2:-root}" - local password="${3:-123}" - - local sshkey_file=~/.ssh/id_rsa.pub - - # check sshkey file - if [[ ! -e $sshkey_file ]]; then - expect -c " - spawn ssh-keygen -t rsa - expect \"Enter*\" { send \"\n\"; exp_continue; } - " - fi - - # get hosts list - local hosts=$(awk '/^[^#]/ {print $1}' "${hosts_file}") - - ssh_key_copy() { - local target=$1 - - # delete history - sed -i "/$target/d" ~/.ssh/known_hosts - - # copy key - expect -c " - set timeout 100 - spawn ssh-copy-id $username@$target - expect { - \"yes/no\" { send \"yes\n\"; exp_continue; } - \"*assword\" { send \"$password\n\"; } - \"already exist on the remote system\" { exit 1; } - } - expect eof - " - } - - # auto sshkey pair - for host in $hosts; do - if ! ping -i 0.2 -c 3 -W 1 "$host" > /dev/null 2>&1; then - echo "[ERROR]: Can't connect $host" - continue - fi - - local host_entry=$(awk "/$host/"'{print $1, $2}' /etc/hosts) - if [[ $host_entry ]]; then - local hostaddr=$(echo "$host_entry" | awk '{print $1}') - local hostname=$(echo "$host_entry" | awk '{print $2}') - ssh_key_copy "$hostaddr" - ssh_key_copy "$hostname" - else - ssh_key_copy "$host" - fi - done -} - -function openim::util::sourced_variable { - # Call this function to tell shellcheck that a variable is supposed to - # be used from other calling context. This helps quiet an "unused - # variable" warning from shellcheck and also document your code. - true -} - -openim::util::sortable_date() { - date "+%Y%m%d-%H%M%S" -} - -# arguments: target, item1, item2, item3, ... -# returns 0 if target is in the given items, 1 otherwise. -openim::util::array_contains() { - local search="$1" - local element - shift - for element; do - if [[ "${element}" == "${search}" ]]; then - return 0 - fi - done - return 1 -} - -openim::util::wait_for_url() { - local url=$1 - local prefix=${2:-} - local wait=${3:-1} - local times=${4:-30} - local maxtime=${5:-1} - - command -v curl >/dev/null || { - openim::log::usage "curl must be installed" - exit 1 - } - - local i - for i in $(seq 1 "${times}"); do - local out - if out=$(curl --max-time "${maxtime}" -gkfs "${url}" 2>/dev/null); then - openim::log::status "On try ${i}, ${prefix}: ${out}" - return 0 - fi - sleep "${wait}" - done - openim::log::error "Timed out waiting for ${prefix} to answer at ${url}; tried ${times} waiting ${wait} between each" - return 1 -} - -# Example: openim::util::wait_for_success 120 5 "openimctl get nodes|grep localhost" -# arguments: wait time, sleep time, shell command -# returns 0 if the shell command get output, 1 otherwise. -openim::util::wait_for_success(){ - local wait_time="$1" - local sleep_time="$2" - local cmd="$3" - while [ "$wait_time" -gt 0 ]; do - if eval "$cmd"; then - return 0 - else - sleep "$sleep_time" - wait_time=$((wait_time-sleep_time)) - fi - done - return 1 -} - -# Example: openim::util::trap_add 'echo "in trap DEBUG"' DEBUG -# See: http://stackoverflow.com/questions/3338030/multiple-bash-traps-for-the-same-signal -openim::util::trap_add() { - local trap_add_cmd - trap_add_cmd=$1 - shift - - for trap_add_name in "$@"; do - local existing_cmd - local new_cmd - - # Grab the currently defined trap commands for this trap - existing_cmd=$(trap -p "${trap_add_name}" | awk -F"'" '{print $2}') - - if [[ -z "${existing_cmd}" ]]; then - new_cmd="${trap_add_cmd}" - else - new_cmd="${trap_add_cmd};${existing_cmd}" - fi - - # Assign the test. Disable the shellcheck warning telling that trap - # commands should be single quoted to avoid evaluating them at this - # point instead evaluating them at run time. The logic of adding new - # commands to a single trap requires them to be evaluated right away. - # shellcheck disable=SC2064 - trap "${new_cmd}" "${trap_add_name}" - done -} - -# Opposite of openim::util::ensure-temp-dir() -openim::util::cleanup-temp-dir() { - rm -rf "${OPENIM_TEMP}" -} - -# Create a temp dir that'll be deleted at the end of this bash session. -# -# Vars set: -# OPENIM_TEMP -openim::util::ensure-temp-dir() { - if [[ -z ${OPENIM_TEMP-} ]]; then - OPENIM_TEMP=$(mktemp -d 2>/dev/null || mktemp -d -t openimrnetes.XXXXXX) - openim::util::trap_add openim::util::cleanup-temp-dir EXIT - fi -} - -openim::util::host_os() { - local host_os - case "$(uname -s)" in - Darwin) - host_os=darwin - ;; - Linux) - host_os=linux - ;; - *) - openim::log::error "Unsupported host OS. Must be Linux or Mac OS X." - exit 1 - ;; - esac - echo "${host_os}" -} - -openim::util::host_arch() { - local host_arch - case "$(uname -m)" in - x86_64*) - host_arch=amd64 - ;; - i?86_64*) - host_arch=amd64 - ;; - amd64*) - host_arch=amd64 - ;; - aarch64*) - host_arch=arm64 - ;; - arm64*) - host_arch=arm64 - ;; - arm*) - host_arch=arm - ;; - i?86*) - host_arch=x86 - ;; - s390x*) - host_arch=s390x - ;; - ppc64le*) - host_arch=ppc64le - ;; - *) - openim::log::error "Unsupported host arch. Must be x86_64, 386, arm, arm64, s390x or ppc64le." - exit 1 - ;; - esac - echo "${host_arch}" -} - -# Define a bash function to check the versions of Docker and Docker Compose -openim::util::check_docker_and_compose_versions() { - # Define the required versions of Docker and Docker Compose - required_docker_version="20.10.0" - required_compose_version="2.0" - - # Get the currently installed Docker version - installed_docker_version=$(docker --version | awk '{print $3}' | sed 's/,//') - - # Check if the installed Docker version matches the required version - if [[ "$installed_docker_version" < "$required_docker_version" ]]; then - echo "Docker version mismatch. Installed: $installed_docker_version, Required: $required_docker_version" - return 1 - fi - - # Check if the docker compose sub-command is available - if ! docker compose version &> /dev/null; then - echo "Docker does not support the docker compose sub-command" - echo "You need to upgrade Docker to the right version" - return 1 - fi - - # Get the currently installed Docker Compose version - installed_compose_version=$(docker compose version --short) - - # Check if the installed Docker Compose version matches the required version - if [[ "$installed_compose_version" < "$required_compose_version" ]]; then - echo "Docker Compose version mismatch. Installed: $installed_compose_version, Required: $required_compose_version" - return 1 - fi - -} - - -# The `openim::util::check_ports` function analyzes the state of processes based on given ports. -# It accepts multiple ports as arguments and prints: -# 1. The state of the process (whether it's running or not). -# 2. The start time of the process if it's running. -# User: -# openim::util::check_ports 8080 8081 8082 -# The function returns a status of 1 if any of the processes is not running. -openim::util::check_ports() { - # An array to collect ports of processes that are not running. - local not_started=() - - # An array to collect information about processes that are running. - local started=() - - echo "Checking ports: $*" - # Iterate over each given port. - for port in "$@"; do - # Initialize variables - # Check the OS and use the appropriate command - if [[ "$OSTYPE" == "linux-gnu"* ]]; then - if command -v ss > /dev/null 2>&1; then - info=$(ss -ltnp | grep ":$port" || true) - else - info=$(netstat -ltnp | grep ":$port" || true) - fi - elif [[ "$OSTYPE" == "darwin"* ]]; then - # For macOS, use lsof - info=$(lsof -i:"$port" | grep "\*:$port" || true) - fi - - # Check if any process is using the port - if [[ -z $info ]]; then - not_started+=($port) - else - if [[ "$OSTYPE" == "linux-gnu"* ]]; then - # Extract relevant details for Linux: Process Name, PID, and FD. - details=$(echo $info | sed -n 's/.*users:(("\([^"]*\)",pid=\([^,]*\),fd=\([^)]*\))).*/\1 \2 \3/p') - command=$(echo $details | awk '{print $1}') - pid=$(echo $details | awk '{print $2}') - fd=$(echo $details | awk '{print $3}') - elif [[ "$OSTYPE" == "darwin"* ]]; then - # Handle extraction for macOS - pid=$(echo $info | awk '{print $2}' | cut -d'/' -f1) - command=$(ps -p $pid -o comm= | xargs basename) - fd=$(echo $info | awk '{print $4}' | cut -d'/' -f1) - fi - - # Get the start time of the process using the PID - if [[ -z $pid ]]; then - start_time="N/A" - else - start_time=$(ps -p $pid -o lstart=) - fi - - started+=("Port $port - Command: $command, PID: $pid, FD: $fd, Started: $start_time") - fi - done - - # Print information about ports whose processes are not running. - if [[ ${#not_started[@]} -ne 0 ]]; then - printf "\n### Not started ports:" - for port in "${not_started[@]}"; do - openim::log::error "Port $port is not started." - done - fi - - # Print information about ports whose processes are running. - if [[ ${#started[@]} -ne 0 ]]; then - printf "\n### Started ports:" - for info in "${started[@]}"; do - echo "$info" - done - fi - - # If any of the processes is not running, return a status of 1. - if [[ ${#not_started[@]} -ne 0 ]]; then - openim::color::echo $COLOR_RED "OpenIM Stdout Log >> cat ${LOG_FILE}" - openim::color::echo $COLOR_RED "OpenIM Stderr Log >> cat ${STDERR_LOG_FILE}" - echo "" - cat "$TMP_LOG_FILE" | awk '{print "\033[31m" $0 "\033[0m"}' - return 1 - else - openim::log::success "All specified processes are running." - return 0 - fi -} - -# set +o errexit -# Sample call for testing: -# openim::util::check_ports 10002 1004 12345 13306 -# - -# The `openim::util::check_process_names` function analyzes the state of processes based on given names. -# It accepts multiple process names as arguments and prints: -# 1. The state of the process (whether it's running or not). -# 2. The start time of the process if it's running. -# User: -# openim::util::check_process_names nginx mysql redis -# The function returns a status of 1 if any of the processes is not running. -openim::util::check_process_names() { - # Function to get the port of a process - get_port() { - local pid=$1 - if [[ "$OSTYPE" == "linux-gnu"* ]]; then - # Linux - ss -ltnp 2>/dev/null | grep $pid | awk '{print $4}' | cut -d ':' -f2 - elif [[ "$OSTYPE" == "darwin"* ]]; then - # macOS - lsof -nP -iTCP -sTCP:LISTEN -a -p $pid | awk 'NR>1 {print $9}' | sed 's/.*://' - else - echo "Unsupported OS" - return 1 - fi - } - - # Arrays to collect details of processes - local not_started=() - local started=() - - echo "Checking processes: $*" - # Iterate over each given process name - for process_name in "$@"; do - # Use `pgrep` to find process IDs related to the given process name - local pids=($(pgrep -f $process_name)) - - # Check if any process IDs were found - if [[ ${#pids[@]} -eq 0 ]]; then - not_started+=($process_name) - else - # If there are PIDs, loop through each one - for pid in "${pids[@]}"; do - local command=$(ps -p $pid -o cmd=) - local start_time=$(ps -p $pid -o lstart=) - local port=$(get_port $pid) - - # Check if port information was found for the PID - if [[ -z $port ]]; then - port="N/A" - fi - - started+=("Process $process_name - Command: $command, PID: $pid, Port: $port, Start time: $start_time") - done - fi - done - - # Print information - if [[ ${#not_started[@]} -ne 0 ]]; then - echo "Not started processes:" - for process_name in "${not_started[@]}"; do - openim::log::error "Process $process_name is not started." - done - fi - - if [[ ${#started[@]} -ne 0 ]]; then - echo - echo "Started processes:" - for info in "${started[@]}"; do - echo "$info" - done - fi - - # Return status - if [[ ${#not_started[@]} -ne 0 ]]; then - openim::color::echo $COLOR_RED " OpenIM Stdout Log >> cat ${LOG_FILE}" - openim::color::echo $COLOR_RED " OpenIM Stderr Log >> cat ${STDERR_LOG_FILE}" - cat "$TMP_LOG_FILE" | awk '{print "\033[31m" $0 "\033[0m"}' - return 1 - else - echo "" - openim::log::success "All processes are running." - return 0 - fi -} - -# openim::util::check_process_names docker-pr - -# The `openim::util::stop_services_on_ports` function stops services running on specified ports. -# It accepts multiple ports as arguments and performs the following: -# 1. Attempts to stop any services running on the specified ports. -# 2. Prints details of services successfully stopped and those that failed to stop. -# Usage: -# openim::util::stop_services_on_ports 8080 8081 8082 -# The function returns a status of 1 if any service couldn't be stopped. -openim::util::stop_services_on_ports() { - # An array to collect ports of processes that couldn't be stopped. - local not_stopped=() - - # An array to collect information about processes that were stopped. - local stopped=() - - echo "Stopping services on ports: $*" - # Iterate over each given port. - for port in "$@"; do - # Use the `lsof` command to find process information related to the given port. - info=$(lsof -i :$port -n -P | grep LISTEN || true) - - # If there's process information, it means the process associated with the port is running. - if [[ -n $info ]]; then - # Extract the Process ID. - while read -r line; do - local pid=$(echo $line | awk '{print $2}') - - # Try to stop the service by killing its process. - if kill -10 $pid; then - stopped+=($port) - else - not_stopped+=($port) - fi - done <<< "$info" - fi - done - - # Print information about ports whose processes couldn't be stopped. - if [[ ${#not_stopped[@]} -ne 0 ]]; then - echo "Ports that couldn't be stopped:" - for port in "${not_stopped[@]}"; do - openim::log::status "Failed to stop service on port $port." - done - fi - - # Print information about ports whose processes were successfully stopped. - if [[ ${#stopped[@]} -ne 0 ]]; then - for port in "${stopped[@]}"; do - echo "Successfully stopped service on port $port." - done - fi - - # If any of the processes couldn't be stopped, return a status of 1. - if [[ ${#not_stopped[@]} -ne 0 ]]; then - return 1 - else - openim::log::success "All specified services were stopped." - echo "" - return 0 - fi -} - - -# The `openim::util::stop_services_with_name` function stops services with specified names. -# It accepts multiple service names as arguments and performs the following: -# 1. Attempts to stop any services with the specified names. -# 2. Prints details of services successfully stopped and those that failed to stop. -# Usage: -# openim::util::stop_services_with_name nginx apache -# The function returns a status of 1 if any service couldn't be stopped. - -# sleep 333333& -# sleep 444444& -# ps -ef | grep "sleep" -# openim::util::stop_services_with_name "sleep 333333" "sleep 444444" - -# This figures out the host platform without relying on golang. We need this as -# we don't want a golang install to be a prerequisite to building yet we need -# this info to figure out where the final binaries are placed. -openim::util::host_platform() { - echo "$(openim::util::host_os)/$(openim::util::host_arch)" -} - -# looks for $1 in well-known output locations for the platform ($2) -# $OPENIM_ROOT must be set -openim::util::find-binary-for-platform() { - local -r lookfor="$1" - local -r platform="$2" - local locations=( - "${OPENIM_ROOT}/_output/bin/${lookfor}" - "${OPENIM_ROOT}/_output/${platform}/${lookfor}" - "${OPENIM_ROOT}/_output/local/bin/${platform}/${lookfor}" - "${OPENIM_ROOT}/_output/platforms/${platform}/${lookfor}" - "${OPENIM_ROOT}/_output/platforms/bin/${platform}/${lookfor}" - ) - - # List most recently-updated location. - local -r bin=$( (ls -t "${locations[@]}" 2>/dev/null || true) | head -1 ) - echo -n "${bin}" -} - -# looks for $1 in well-known output locations for the host platform -# $OPENIM_ROOT must be set -openim::util::find-binary() { - openim::util::find-binary-for-platform "$1" "$(openim::util::host_platform)" -} - -# Run all known doc generators (today gendocs and genman for openimctl) -# $1 is the directory to put those generated documents -openim::util::gen-docs() { - local dest="$1" - - # Find binary - gendocs=$(openim::util::find-binary "gendocs") - genopenimdocs=$(openim::util::find-binary "genopenimdocs") - genman=$(openim::util::find-binary "genman") - genyaml=$(openim::util::find-binary "genyaml") - genfeddocs=$(openim::util::find-binary "genfeddocs") - - # TODO: If ${genfeddocs} is not used from anywhere (it isn't used at - # least from k/k tree), remove it completely. - openim::util::sourced_variable "${genfeddocs}" - - mkdir -p "${dest}/docs/guide/en-US/cmd/openimctl/" - "${gendocs}" "${dest}/docs/guide/en-US/cmd/openimctl/" - - mkdir -p "${dest}/docs/guide/en-US/cmd/" - "${genopenimdocs}" "${dest}/docs/guide/en-US/cmd/" "openim-api" - "${genopenimdocs}" "${dest}/docs/guide/en-US/cmd/" "openim-cmdutils" - "${genopenimdocs}" "${dest}/docs/guide/en-US/cmd/" "openim-crontask" - "${genopenimdocs}" "${dest}/docs/guide/en-US/cmd/" "openim-msggateway" - "${genopenimdocs}" "${dest}/docs/guide/en-US/cmd/" "openim-msgtransfer" - "${genopenimdocs}" "${dest}/docs/guide/en-US/cmd/" "openim-push" - "${genopenimdocs}" "${dest}/docs/guide/en-US/cmd/" "openim-rpc-auth" - "${genopenimdocs}" "${dest}/docs/guide/en-US/cmd/" "openim-rpc-conversation" - "${genopenimdocs}" "${dest}/docs/guide/en-US/cmd/" "openim-rpc-friend" - "${genopenimdocs}" "${dest}/docs/guide/en-US/cmd/" "openim-rpc-group" - "${genopenimdocs}" "${dest}/docs/guide/en-US/cmd/" "openim-rpc-msg" - "${genopenimdocs}" "${dest}/docs/guide/en-US/cmd/" "openim-rpc-third" - "${genopenimdocs}" "${dest}/docs/guide/en-US/cmd/" "openim-rpc-user" - "${genopenimdocs}" "${dest}/docs/guide/en-US/cmd/openimctl" "openimctl" - - mkdir -p "${dest}/docs/man/man1/" -"${genman}" "${dest}/docs/man/man1/" "openim-api" -"${genman}" "${dest}/docs/man/man1/" "openim-cmdutils" -"${genman}" "${dest}/docs/man/man1/" "openim-crontask" -"${genman}" "${dest}/docs/man/man1/" "openim-msggateway" -"${genman}" "${dest}/docs/man/man1/" "openim-msgtransfer" -"${genman}" "${dest}/docs/man/man1/" "openim-push" -"${genman}" "${dest}/docs/man/man1/" "openim-rpc-auth" -"${genman}" "${dest}/docs/man/man1/" "openim-rpc-conversation" -"${genman}" "${dest}/docs/man/man1/" "openim-rpc-friend" -"${genman}" "${dest}/docs/man/man1/" "openim-rpc-group" -"${genman}" "${dest}/docs/man/man1/" "openim-rpc-msg" -"${genman}" "${dest}/docs/man/man1/" "openim-rpc-third" -"${genman}" "${dest}/docs/man/man1/" "openim-rpc-user" - - mkdir -p "${dest}/docs/guide/en-US/yaml/openimctl/" - "${genyaml}" "${dest}/docs/guide/en-US/yaml/openimctl/" - - # create the list of generated files - pushd "${dest}" > /dev/null || return 1 - touch docs/.generated_docs - find . -type f | cut -sd / -f 2- | LC_ALL=C sort > docs/.generated_docs - popd > /dev/null || return 1 -} - -# Removes previously generated docs-- we don't want to check them in. $OPENIM_ROOT -# must be set. -openim::util::remove-gen-docs() { - if [ -e "${OPENIM_ROOT}/docs/.generated_docs" ]; then - # remove all of the old docs; we don't want to check them in. - while read -r file; do - rm "${OPENIM_ROOT}/${file}" 2>/dev/null || true - done <"${OPENIM_ROOT}/docs/.generated_docs" - # The docs/.generated_docs file lists itself, so we don't need to explicitly - # delete it. - fi -} - -# Returns the name of the upstream remote repository name for the local git -# repo, e.g. "upstream" or "origin". -openim::util::git_upstream_remote_name() { - git remote -v | grep fetch |\ - grep -E 'github.com[/:]openimsdk/open-im-server|openim.cc/server' |\ - head -n 1 | awk '{print $1}' -} - -# Exits script if working directory is dirty. If it's run interactively in the terminal -# the user can commit changes in a second terminal. This script will wait. -openim::util::ensure_clean_working_dir() { - while ! git diff HEAD --exit-code &>/dev/null; do - echo -e "\nUnexpected dirty working directory:\n" - if tty -s; then - git status -s - else - git diff -a # be more verbose in log files without tty - exit 1 - fi | sed 's/^/ /' - echo -e "\nCommit your changes in another terminal and then continue here by pressing enter." - read -r - done 1>&2 -} - -# Find the base commit using: -# $PULL_BASE_SHA if set (from Prow) -# current ref from the remote upstream branch -openim::util::base_ref() { - local -r git_branch=$1 - - if [[ -n ${PULL_BASE_SHA:-} ]]; then - echo "${PULL_BASE_SHA}" - return - fi - - full_branch="$(openim::util::git_upstream_remote_name)/${git_branch}" - - # make sure the branch is valid, otherwise the check will pass erroneously. - if ! git describe "${full_branch}" >/dev/null; then - # abort! - exit 1 - fi - - echo "${full_branch}" -} - -# Checks whether there are any files matching pattern $2 changed between the -# current branch and upstream branch named by $1. -# Returns 1 (false) if there are no changes -# 0 (true) if there are changes detected. -openim::util::has_changes() { - local -r git_branch=$1 - local -r pattern=$2 - local -r not_pattern=${3:-totallyimpossiblepattern} - - local base_ref - base_ref=$(openim::util::base_ref "${git_branch}") - echo "Checking for '${pattern}' changes against '${base_ref}'" - - # notice this uses ... to find the first shared ancestor - if git diff --name-only "${base_ref}...HEAD" | grep -v -E "${not_pattern}" | grep "${pattern}" > /dev/null; then - return 0 - fi - # also check for pending changes - if git status --porcelain | grep -v -E "${not_pattern}" | grep "${pattern}" > /dev/null; then - echo "Detected '${pattern}' uncommitted changes." - return 0 - fi - echo "No '${pattern}' changes detected." - return 1 -} - -openim::util::download_file() { - local -r url=$1 - local -r destination_file=$2 - - rm "${destination_file}" 2&> /dev/null || true - - for i in $(seq 5) - do - if ! curl -fsSL --retry 3 --keepalive-time 2 "${url}" -o "${destination_file}"; then - echo "Downloading ${url} failed. $((5-i)) retries left." - sleep 1 - else - echo "Downloading ${url} succeed" - return 0 - fi - done - return 1 -} - -# Test whether openssl is installed. -# Sets: -# OPENSSL_BIN: The path to the openssl binary to use -function openim::util::test_openssl_installed { - if ! openssl version >& /dev/null; then - echo "Failed to run openssl. Please ensure openssl is installed" - exit 1 - fi - - OPENSSL_BIN=$(command -v openssl) -} - -# creates a client CA, args are sudo, dest-dir, ca-id, purpose -# purpose is dropped in after "key encipherment", you usually want -# '"client auth"' -# '"server auth"' -# '"client auth","server auth"' -function openim::util::create_signing_certkey { - local sudo=$1 - local dest_dir=$2 - local id=$3 - local purpose=$4 - # Create client ca - ${sudo} /usr/bin/env bash -e < "${dest_dir}/${id}-ca-config.json" -EOF -} - -# signs a client certificate: args are sudo, dest-dir, CA, filename (roughly), username, groups... -function openim::util::create_client_certkey { - local sudo=$1 - local dest_dir=$2 - local ca=$3 - local id=$4 - local cn=${5:-$4} - local groups="" - local SEP="" - shift 5 - while [ -n "${1:-}" ]; do - groups+="${SEP}{\"O\":\"$1\"}" - SEP="," - shift 1 - done - ${sudo} /usr/bin/env bash -e < /dev/null -apiVersion: v1 -kind: Config -clusters: - - cluster: - certificate-authority: ${ca_file} - server: https://${api_host}:${api_port}/ - name: local-up-cluster -users: - - user: - token: ${token} - client-certificate: ${dest_dir}/client-${client_id}.crt - client-key: ${dest_dir}/client-${client_id}.key - name: local-up-cluster -contexts: - - context: - cluster: local-up-cluster - user: local-up-cluster - name: local-up-cluster -current-context: local-up-cluster -EOF - - # flatten the openimconfig files to make them self contained - username=$(whoami) - ${sudo} /usr/bin/env bash -e < "/tmp/${client_id}.openimconfig" - mv -f "/tmp/${client_id}.openimconfig" "${dest_dir}/${client_id}.openimconfig" - chown ${username} "${dest_dir}/${client_id}.openimconfig" -EOF -} - -# Determines if docker can be run, failures may simply require that the user be added to the docker group. -function openim::util::ensure_docker_daemon_connectivity { - IFS=" " read -ra DOCKER <<< "${DOCKER_OPTS}" - # Expand ${DOCKER[@]} only if it's not unset. This is to work around - # Bash 3 issue with unbound variable. - DOCKER=(docker ${DOCKER[@]:+"${DOCKER[@]}"}) - if ! "${DOCKER[@]}" info > /dev/null 2>&1 ; then - cat <<'EOF' >&2 -Can't connect to 'docker' daemon. please fix and retry. - -Possible causes: - - Docker Daemon not started - - Linux: confirm via your init system - - macOS w/ docker-machine: run `docker-machine ls` and `docker-machine start ` - - macOS w/ Docker for Mac: Check the menu bar and start the Docker application - - DOCKER_HOST hasn't been set or is set incorrectly - - Linux: domain socket is used, DOCKER_* should be unset. In Bash run `unset ${!DOCKER_*}` - - macOS w/ docker-machine: run `eval "$(docker-machine env )"` - - macOS w/ Docker for Mac: domain socket is used, DOCKER_* should be unset. In Bash run `unset ${!DOCKER_*}` - - Other things to check: - - Linux: User isn't in 'docker' group. Add and relogin. - - Something like 'sudo usermod -a -G docker ${USER}' - - RHEL7 bug and workaround: https://bugzilla.redhat.com/show_bug.cgi?id=1119282#c8 -EOF - return 1 - fi -} - -# Wait for background jobs to finish. Return with -# an error status if any of the jobs failed. -openim::util::wait-for-jobs() { - local fail=0 - local job - for job in $(jobs -p); do - wait "${job}" || fail=$((fail + 1)) - done - return ${fail} -} - -# openim::util::join -# Concatenates the list elements with the delimiter passed as first parameter -# -# Ex: openim::util::join , a b c -# -> a,b,c -function openim::util::join { - local IFS="$1" - shift - echo "$*" -} - -# Function: openim::util::list-to-string -# Description: Converts a list to a string, removing spaces, brackets, and commas. -# Example input: [1002 3 , 2 32 3 , 3 434 ,] -# Example output: 10023 2323 3434 -# Example usage: -# result=$(openim::util::list-to-string "[10023, 2323, 3434]") -# echo $result -function openim::util::list-to-string() { - # Capture all arguments into a single string - ports_list="$*" - - # Use sed for transformations: - # 1. Remove spaces - # 2. Replace commas with spaces - # 3. Remove opening and closing brackets - ports_array=$(echo "$ports_list" | sed 's/ //g; s/,/ /g; s/^\[\(.*\)\]$/\1/') - # For external use, we might want to echo the result so that it can be captured by callers - echo "$ports_array" -} -# MSG_GATEWAY_PROM_PORTS=$(openim::util::list-to-string "10023, 2323, 34 34") -# read -a MSG_GATEWAY_PROM_PORTS <<< $(openim::util::list-to-string "10023, 2323, 34 34") -# echo ${MSG_GATEWAY_PROM_PORTS} -# echo "${#MSG_GATEWAY_PROM_PORTS[@]}" -# Downloads cfssl/cfssljson/cfssl-certinfo into $1 directory if they do not already exist in PATH -# -# Assumed vars: -# $1 (cfssl directory) (optional) -# -# Sets: -# CFSSL_BIN: The path of the installed cfssl binary -# CFSSLJSON_BIN: The path of the installed cfssljson binary -# CFSSLCERTINFO_BIN: The path of the installed cfssl-certinfo binary -# -function openim::util::ensure-cfssl { - if command -v cfssl &>/dev/null && command -v cfssljson &>/dev/null && command -v cfssl-certinfo &>/dev/null; then - CFSSL_BIN=$(command -v cfssl) - CFSSLJSON_BIN=$(command -v cfssljson) - CFSSLCERTINFO_BIN=$(command -v cfssl-certinfo) - return 0 - fi - - host_arch=$(openim::util::host_arch) - - if [[ "${host_arch}" != "amd64" ]]; then - echo "Cannot download cfssl on non-amd64 hosts and cfssl does not appear to be installed." - echo "Please install cfssl, cfssljson and cfssl-certinfo and verify they are in \$PATH." - echo "Hint: export PATH=\$PATH:\$GOPATH/bin; go get -u github.com/cloudflare/cfssl/cmd/..." - exit 1 - fi - - # Create a temp dir for cfssl if no directory was given - local cfssldir=${1:-} - if [[ -z "${cfssldir}" ]]; then - cfssldir="$HOME/bin" - fi - - mkdir -p "${cfssldir}" - pushd "${cfssldir}" > /dev/null || return 1 - - echo "Unable to successfully run 'cfssl' from ${PATH}; downloading instead..." - kernel=$(uname -s) - case "${kernel}" in - Linux) - curl --retry 10 -L -o cfssl https://pkg.cfssl.org/R1.2/cfssl_linux-amd64 - curl --retry 10 -L -o cfssljson https://pkg.cfssl.org/R1.2/cfssljson_linux-amd64 - curl --retry 10 -L -o cfssl-certinfo https://pkg.cfssl.org/R1.2/cfssl-certinfo_linux-amd64 - ;; - Darwin) - curl --retry 10 -L -o cfssl https://pkg.cfssl.org/R1.2/cfssl_darwin-amd64 - curl --retry 10 -L -o cfssljson https://pkg.cfssl.org/R1.2/cfssljson_darwin-amd64 - curl --retry 10 -L -o cfssl-certinfo https://pkg.cfssl.org/R1.2/cfssl-certinfo_darwin-amd64 - ;; - *) - echo "Unknown, unsupported platform: ${kernel}." >&2 - echo "Supported platforms: Linux, Darwin." >&2 - exit 2 - esac - - chmod +x cfssl || true - chmod +x cfssljson || true - chmod +x cfssl-certinfo || true - - CFSSL_BIN="${cfssldir}/cfssl" - CFSSLJSON_BIN="${cfssldir}/cfssljson" - CFSSLCERTINFO_BIN="${cfssldir}/cfssl-certinfo" - if [[ ! -x ${CFSSL_BIN} || ! -x ${CFSSLJSON_BIN} || ! -x ${CFSSLCERTINFO_BIN} ]]; then - echo "Failed to download 'cfssl'." - echo "Please install cfssl, cfssljson and cfssl-certinfo and verify they are in \$PATH." - echo "Hint: export PATH=\$PATH:\$GOPATH/bin; go get -u github.com/cloudflare/cfssl/cmd/..." - exit 1 - fi - popd > /dev/null || return 1 -} - -function openim::util::ensure-docker-buildx { - # podman returns 0 on `docker buildx version`, docker on `docker buildx`. One of them must succeed. - if docker buildx version >/dev/null 2>&1 || docker buildx >/dev/null 2>&1; then - return 0 - else - echo "ERROR: docker buildx not available. Docker 19.03 or higher is required with experimental features enabled" - exit 1 - fi -} - -# openim::util::ensure-bash-version -# Check if we are using a supported bash version -# -function openim::util::ensure-bash-version { - # shellcheck disable=SC2004 - if ((${BASH_VERSINFO[0]}<4)) || ( ((${BASH_VERSINFO[0]}==4)) && ((${BASH_VERSINFO[1]}<2)) ); then - echo "ERROR: This script requires a minimum bash version of 4.2, but got version of ${BASH_VERSINFO[0]}.${BASH_VERSINFO[1]}" - if [ "$(uname)" = 'Darwin' ]; then - echo "On macOS with homebrew 'brew install bash' is sufficient." - fi - exit 1 - fi -} - -# openim::util::ensure-install-nginx -# Check if nginx is installed -# -function openim::util::ensure-install-nginx { - if ! command -v nginx &>/dev/null; then - echo "ERROR: nginx not found. Please install nginx." - exit 1 - fi - - for port in "80" - do - if echo |telnet 127.0.0.1 $port 2>&1|grep refused &>/dev/null;then - exit 1 - fi - done -} - -# openim::util::ensure-gnu-sed -# Determines which sed binary is gnu-sed on linux/darwin -# -# Sets: -# SED: The name of the gnu-sed binary -# -function openim::util::ensure-gnu-sed { - # NOTE: the echo below is a workaround to ensure sed is executed before the grep. - # see: https://github.com/openimrnetes/openimrnetes/issues/87251 - sed_help="$(LANG=C sed --help 2>&1 || true)" - if echo "${sed_help}" | grep -q "GNU\|BusyBox"; then - SED="sed" - elif command -v gsed &>/dev/null; then - SED="gsed" - else - openim::log::error "Failed to find GNU sed as sed or gsed. If you are on Mac: brew install gnu-sed." >&2 - return 1 - fi - openim::util::sourced_variable "${SED}" -} - -# openim::util::ensure-gnu-date -# Determines which date binary is gnu-date on linux/darwin -# -# Sets: -# DATE: The name of the gnu-date binary -# -function openim::util::ensure-gnu-date { - # NOTE: the echo below is a workaround to ensure date is executed before the grep. - date_help="$(LANG=C date --help 2>&1 || true)" - if echo "${date_help}" | grep -q "GNU\|BusyBox"; then - DATE="date" - elif command -v gdate &>/dev/null; then - DATE="gdate" - else - openim::log::error "Failed to find GNU date as date or gdate. If you are on Mac: brew install coreutils." >&2 - return 1 - fi - openim::util::sourced_variable "${DATE}" -} - -# openim::util::check-file-in-alphabetical-order -# Check that the file is in alphabetical order -# -function openim::util::check-file-in-alphabetical-order { - local failure_file="$1" - if ! diff -u "${failure_file}" <(LC_ALL=C sort "${failure_file}"); then - { - echo - echo "${failure_file} is not in alphabetical order. Please sort it:" - echo - echo " LC_ALL=C sort -o ${failure_file} ${failure_file}" - echo - } >&2 - false - fi -} - -# openim::util::require-jq -# Checks whether jq is installed. -function openim::util::require-jq { - if ! command -v jq &>/dev/null; then - openim::log::errexit "jq not found. Please install." 1>&2 - fi -} - -# openim::util::require-dig -# Checks whether dig is installed and provides installation instructions if it is not. -function openim::util::require-dig { - if ! command -v dig &>/dev/null; then - openim::log::error "Please install 'dig' to use this feature. OR Set the environment variable for OPENIM_IP" - openim::log::error "Installation instructions:" - openim::log::error " For Ubuntu/Debian: sudo apt-get install dnsutils" - openim::log::error " For CentOS/RedHat: sudo yum install bind-utils" - openim::log::error " For macOS: 'dig' should be preinstalled. If missing, try: brew install bind" - openim::log::error " For Windows: Install BIND9 tools from https://www.isc.org/download/" - openim::log::error_exit "dig command not found." - fi - return 0 -} - -# outputs md5 hash of $1, works on macOS and Linux -function openim::util::md5() { - if which md5 >/dev/null 2>&1; then - md5 -q "$1" - else - md5sum "$1" | awk '{ print $1 }' - fi -} - -# openim::util::read-array -# Reads in stdin and adds it line by line to the array provided. This can be -# used instead of "mapfile -t", and is bash 3 compatible. -# -# Assumed vars: -# $1 (name of array to create/modify) -# -# Example usage: -# openim::util::read-array files < <(ls -1) -# -function openim::util::read-array { - local i=0 - unset -v "$1" - while IFS= read -r "$1[i++]"; do :; done - eval "[[ \${$1[--i]} ]]" || unset "$1[i]" # ensures last element isn't empty -} - -# Some useful colors. -if [[ -z "${color_start-}" ]]; then - declare -r color_start="\033[" - declare -r color_red="${color_start}0;31m" - declare -r color_yellow="${color_start}0;33m" - declare -r color_green="${color_start}0;32m" - declare -r color_blue="${color_start}1;34m" - declare -r color_cyan="${color_start}1;36m" - declare -r color_norm="${color_start}0m" - - openim::util::sourced_variable "${color_start}" - openim::util::sourced_variable "${color_red}" - openim::util::sourced_variable "${color_yellow}" - openim::util::sourced_variable "${color_green}" - openim::util::sourced_variable "${color_blue}" - openim::util::sourced_variable "${color_cyan}" - openim::util::sourced_variable "${color_norm}" -fi - -# ex: ts=2 sw=2 et filetype=sh - -function openim::util::desc() { - openim::util:run::maybe_first_prompt - rate=25 - if [ -n "$DEMO_RUN_FAST" ]; then - rate=1000 - fi - echo "$blue# $@$reset" | pv -qL $rate - openim::util:run::prompt -} - -function openim::util:run::prompt() { - echo -n "${yellow}\$ ${reset}" -} - -started="" -function openim::util:run::maybe_first_prompt() { - if [ -z "$started" ]; then - openim::util:run::prompt - started=true - fi -} - -# After a `run` this variable will hold the stdout of the command that was run. -# If the command was interactive, this will likely be garbage. -DEMO_RUN_STDOUT="" - -function openim::util::run() { - openim::util:run::maybe_first_prompt - rate=25 - if [ -n "$DEMO_RUN_FAST" ]; then - rate=1000 - fi - echo "${green}$1${reset}" | pv -qL "$rate" - if [ -n "$DEMO_RUN_FAST" ]; then - sleep 0.5 - fi - OFILE="$(mktemp -t $(basename $0).XXXXXX)" - if [ "$(uname)" == "Darwin" ]; then - script -q "$OFILE" $1 - else - script -eq -c "$1" -f "$OFILE" - fi - r=$? - read -d '' -t "${timeout}" -n 10000 # clear stdin - openim::util:run::prompt - if [ -z "$DEMO_AUTO_RUN" ]; then - read -s - fi - DEMO_RUN_STDOUT="$(tail -n +2 $OFILE | sed 's/\r//g')" - return $r -} - -function openim::util::run::relative() { - for arg; do - echo "$(realpath $(dirname $(which $0)))/$arg" | sed "s|$(realpath $(pwd))|.|" - done -} - -# This function retrieves the IP address of the current server. -# It primarily uses the `curl` command to fetch the public IP address from ifconfig.me. -# If curl or the service is not available, it falls back -# to the internal IP address provided by the hostname command. -# TODO: If a delay is found, the delay needs to be addressed -function openim::util::get_server_ip() { - # Check if the 'curl' command is available - if command -v curl &> /dev/null; then - # Try to retrieve the public IP address using curl and ifconfig.me - IP=$(dig TXT +short o-o.myaddr.l.google.com @ns1.google.com | sed 's/"//g' | tr -d '\n') - - # Check if IP retrieval was successful - if [[ -z "$IP" ]]; then - # If not, get the internal IP address - IP=$(ip addr show | grep 'inet ' | grep -v 127.0.0.1 | awk '{print $2}' | cut -d'/' -f1 | head -n 1) - fi - else - # If curl is not available, get the internal IP address - IP=$(ip addr show | grep 'inet ' | grep -v 127.0.0.1 | awk '{print $2}' | cut -d'/' -f1 | head -n 1) - fi - - # Return the fetched IP address - echo "$IP" -} - -function openim::util::onCtrlC() { - echo -e "\n${t_reset}Ctrl+C Press it. It's exiting openim make init..." - exit 1 -} - -# Function Function: Remove Spaces in the string -function openim::util::remove_space() { - value=$* # 获取传入的参数 - result=$(echo $value | sed 's/ //g') # 去除空格 -} - -function openim::util::gencpu() { - # Check the system type - system_type=$(uname) - - if [[ "$system_type" == "Darwin" ]]; then - # macOS (using sysctl) - cpu_count=$(sysctl -n hw.ncpu) - elif [[ "$system_type" == "Linux" ]]; then - # Linux (using lscpu) - cpu_count=$(lscpu --parse | grep -E '^([^#].*,){3}[^#]' | sort -u | wc -l) - else - echo "Unsupported operating system: $system_type" - exit 1 - fi - echo $cpu_count -} - -function openim::util::set_max_fd() { - local desired_fd=$1 - local max_fd_limit - - # Check if we're not on cygwin or darwin. - if [ "$(uname -s | tr '[:upper:]' '[:lower:]')" != "cygwin" ] && [ "$(uname -s | tr '[:upper:]' '[:lower:]')" != "darwin" ]; then - # Try to get the hard limit. - max_fd_limit=$(ulimit -H -n) - if [ $? -eq 0 ]; then - # If desired_fd is 'maximum' or 'max', set it to the hard limit. - if [ "$desired_fd" = "maximum" ] || [ "$desired_fd" = "max" ]; then - desired_fd="$max_fd_limit" - fi - - # Check if desired_fd is less than or equal to max_fd_limit. - if [ "$desired_fd" -le "$max_fd_limit" ]; then - ulimit -n "$desired_fd" - if [ $? -ne 0 ]; then - echo "Warning: Could not set maximum file descriptor limit to $desired_fd" - fi - else - echo "Warning: Desired file descriptor limit ($desired_fd) is greater than the hard limit ($max_fd_limit)" - fi - else - echo "Warning: Could not query the maximum file descriptor hard limit." - fi - else - echo "Warning: Not attempting to modify file descriptor limit on Cygwin or Darwin." - fi -} - - -function openim::util::gen_os_arch() { - # Get the current operating system and architecture - OS=$(uname -s | tr '[:upper:]' '[:lower:]') - ARCH=$(uname -m) - - # Select the repository home directory based on the operating system and architecture - if [[ "$OS" == "darwin" ]]; then - if [[ "$ARCH" == "x86_64" ]]; then - REPO_DIR="darwin/amd64" - else - REPO_DIR="darwin/386" - fi - elif [[ "$OS" == "linux" ]]; then - if [[ "$ARCH" == "x86_64" ]]; then - REPO_DIR="linux/amd64" - elif [[ "$ARCH" == "arm64" ]]; then - REPO_DIR="linux/arm64" - elif [[ "$ARCH" == "mips64" ]]; then - REPO_DIR="linux/mips64" - elif [[ "$ARCH" == "mips64le" ]]; then - REPO_DIR="linux/mips64le" - elif [[ "$ARCH" == "ppc64le" ]]; then - REPO_DIR="linux/ppc64le" - elif [[ "$ARCH" == "s390x" ]]; then - REPO_DIR="linux/s390x" - else - REPO_DIR="linux/386" - fi - elif [[ "$OS" == "windows" ]]; then - if [[ "$ARCH" == "x86_64" ]]; then - REPO_DIR="windows/amd64" - else - REPO_DIR="windows/386" - fi - else - echo -e "${RED_PREFIX}Unsupported OS: $OS${COLOR_SUFFIX}" - exit 1 - fi -} - -if [[ "$*" =~ openim::util:: ]];then - eval $* -fi - - openim::util:run::prompt -} - -function openim::util:run::prompt() { - echo -n "$yellow\$ $reset" -} - -started="" -function openim::util:run::maybe_first_prompt() { - if [ -z "$started" ]; then - openim::util:run::prompt - started=true - fi -} - -# After a `run` this variable will hold the stdout of the command that was run. -# If the command was interactive, this will likely be garbage. -DEMO_RUN_STDOUT="" - -function openim::util::run() { - openim::util:run::maybe_first_prompt - rate=25 - if [ -n "$DEMO_RUN_FAST" ]; then - rate=1000 - fi - echo "$green$1$reset" | pv -qL $rate - if [ -n "$DEMO_RUN_FAST" ]; then - sleep 0.5 - fi - OFILE="$(mktemp -t $(basename $0).XXXXXX)" - if [ "$(uname)" == "Darwin" ]; then - script -q "$OFILE" $1 - else - script -eq -c "$1" -f "$OFILE" - fi - r=$? - read -d '' -t "${timeout}" -n 10000 # clear stdin - openim::util:run::prompt - if [ -z "$DEMO_AUTO_RUN" ]; then - read -s - fi - DEMO_RUN_STDOUT="$(tail -n +2 $OFILE | sed 's/\r//g')" - return $r -} - -function openim::util::run::relative() { - for arg; do - echo "$(realpath $(dirname $(which $0)))/$arg" | sed "s|$(realpath $(pwd))|.|" - done -} - -# This function retrieves the IP address of the current server. -# It primarily uses the `curl` command to fetch the public IP address from ifconfig.me. -# If curl or the service is not available, it falls back -# to the internal IP address provided by the hostname command. -# TODO: If a delay is found, the delay needs to be addressed -function openim::util::get_server_ip() { - # Check if the 'curl' command is available - if command -v curl &> /dev/null; then - # Try to retrieve the public IP address using curl and ifconfig.me - IP=$(dig TXT +short o-o.myaddr.l.google.com @ns1.google.com | sed 's/"//g' | tr -d '\n') - - # Check if IP retrieval was successful - if [[ -z "$IP" ]]; then - # If not, get the internal IP address - IP=$(ip addr show | grep 'inet ' | grep -v 127.0.0.1 | awk '{print $2}' | cut -d'/' -f1 | head -n 1) - fi - else - # If curl is not available, get the internal IP address - IP=$(ip addr show | grep 'inet ' | grep -v 127.0.0.1 | awk '{print $2}' | cut -d'/' -f1 | head -n 1) - fi - - # Return the fetched IP address - echo "$IP" -} - -function openim::util::onCtrlC() { - echo -e "\n${t_reset}Ctrl+C Press it. It's exiting openim make init..." - exit 1 -} - -# Function Function: Remove Spaces in the string -function openim::util::remove_space() { - value=$* # 获取传入的参数 - result=$(echo $value | sed 's/ //g') # 去除空格 -} - -function openim::util::gencpu() { - # Check the system type - system_type=$(uname) - - if [[ "$system_type" == "Darwin" ]]; then - # macOS (using sysctl) - cpu_count=$(sysctl -n hw.ncpu) - elif [[ "$system_type" == "Linux" ]]; then - # Linux (using lscpu) - cpu_count=$(lscpu --parse | grep -E '^([^#].*,){3}[^#]' | sort -u | wc -l) - else - echo "Unsupported operating system: $system_type" - exit 1 - fi - echo $cpu_count -} - -function openim::util::set_max_fd() { - local desired_fd=$1 - local max_fd_limit - - # Check if we're not on cygwin or darwin. - if [ "$(uname -s | tr '[:upper:]' '[:lower:]')" != "cygwin" ] && [ "$(uname -s | tr '[:upper:]' '[:lower:]')" != "darwin" ]; then - # Try to get the hard limit. - max_fd_limit=$(ulimit -H -n) - if [ $? -eq 0 ]; then - # If desired_fd is 'maximum' or 'max', set it to the hard limit. - if [ "$desired_fd" = "maximum" ] || [ "$desired_fd" = "max" ]; then - desired_fd="$max_fd_limit" - fi - - # Check if desired_fd is less than or equal to max_fd_limit. - if [ "$desired_fd" -le "$max_fd_limit" ]; then - ulimit -n "$desired_fd" - if [ $? -ne 0 ]; then - echo "Warning: Could not set maximum file descriptor limit to $desired_fd" - fi - else - echo "Warning: Desired file descriptor limit ($desired_fd) is greater than the hard limit ($max_fd_limit)" - fi - else - echo "Warning: Could not query the maximum file descriptor hard limit." - fi - else - echo "Warning: Not attempting to modify file descriptor limit on Cygwin or Darwin." - fi -} - - -function openim::util::gen_os_arch() { - # Get the current operating system and architecture - OS=$(uname -s | tr '[:upper:]' '[:lower:]') - ARCH=$(uname -m) - - # Select the repository home directory based on the operating system and architecture - if [[ "$OS" == "darwin" ]]; then - if [[ "$ARCH" == "x86_64" ]]; then - REPO_DIR="darwin/amd64" - else - REPO_DIR="darwin/386" - fi - elif [[ "$OS" == "linux" ]]; then - if [[ "$ARCH" == "x86_64" ]]; then - REPO_DIR="linux/amd64" - elif [[ "$ARCH" == "arm64" ]]; then - REPO_DIR="linux/arm64" - elif [[ "$ARCH" == "mips64" ]]; then - REPO_DIR="linux/mips64" - elif [[ "$ARCH" == "mips64le" ]]; then - REPO_DIR="linux/mips64le" - elif [[ "$ARCH" == "ppc64le" ]]; then - REPO_DIR="linux/ppc64le" - elif [[ "$ARCH" == "s390x" ]]; then - REPO_DIR="linux/s390x" - else - REPO_DIR="linux/386" - fi - elif [[ "$OS" == "windows" ]]; then - if [[ "$ARCH" == "x86_64" ]]; then - REPO_DIR="windows/amd64" - else - REPO_DIR="windows/386" - fi - else - echo -e "${RED_PREFIX}Unsupported OS: $OS${COLOR_SUFFIX}" - exit 1 - fi -} - - - -function openim::util::is_running_in_container() { - if grep -qE 'docker|kubepods' /proc/1/cgroup || [ -f /.dockerenv ]; then - return 0 - else - return 1 - fi -} - - -function openim::util::check_process_names_for_stop() { - local all_stopped=true - for service in "${OPENIM_ALL_SERVICE_LIBRARIES[@]}"; do - - PIDS=$(pgrep -f "${service}") || PIDS="0" - if [ "$PIDS" = "0" ]; then - continue - fi - - - NUM_PROCESSES=$(echo "$PIDS" | wc -l | xargs) - if [ "$NUM_PROCESSES" -gt 0 ]; then - all_stopped=false - echo "Found $NUM_PROCESSES processes for ${service}" - for PID in $PIDS; do - if [[ "$OSTYPE" == "linux-gnu"* ]]; then - echo -e "\033[31m$(ps -p $PID -o pid,cmd)\033[0m" - elif [[ "$OSTYPE" == "darwin"* ]]; then - echo -e "\033[31m$(ps -p $PID -o pid,comm)\033[0m" - else - openim::log::error "Unsupported OS type: $OSTYPE" - fi - done - echo "Processes for ${service} have not been stopped properly. " "$NUM_PROCESSES" - fi - done - - if [ "$all_stopped" = true ]; then - openim::log::success "All processes have been stopped properly." - return 0 - fi - - return 1 -} - - - - -function openim::util::find_process_ports() { - local process_path="$1" - if [[ -z "$process_path" ]]; then - echo "Usage: find_process_ports /path/to/process" - return 1 - fi - - local protocol_ports="" - while read -r line; do - local port_protocol=($line) - local port=${port_protocol[0]##*:} - local protocol=${port_protocol[1]} - protocol_ports="${protocol_ports}${protocol} ${port}, " - - done < <(lsof -nP -iTCP -iUDP | grep LISTEN | grep "$(pgrep -f "$process_path")" | awk '{print $9, $8}') - - protocol_ports=${protocol_ports%, } - - if [[ -z "$protocol_ports" ]]; then - openim::log::colorless "$process_path is not listening on any ports" - else - openim::log::colorless "$process_path is listening on protocol & port: $protocol_ports" - fi -} - - - - - -function openim::util::find_ports_for_all_services() { - local services=("$@") - for service in "${services[@]}"; do - openim::util::find_process_ports "$service" - done -} - - - - - -if [[ "$*" =~ openim::util:: ]];then - eval $* -fi diff --git a/scripts/lib/version.sh b/scripts/lib/version.sh deleted file mode 100755 index cb47136fb2..0000000000 --- a/scripts/lib/version.sh +++ /dev/null @@ -1,145 +0,0 @@ -#!/usr/bin/env bash -# 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. - -# ----------------------------------------------------------------------------- -# Version management helpers. These functions help to set, save and load the -# following variables: -# -# OPENIM_GIT_COMMIT - The git commit id corresponding to this -# source code. -# OPENIM_GIT_TREE_STATE - "clean" indicates no changes since the git commit id -# "dirty" indicates source code changes after the git commit id -# "archive" indicates the tree was produced by 'git archive' -# OPENIM_GIT_VERSION - "vX.Y" used to indicate the last release version. -# OPENIM_GIT_MAJOR - The major part of the version -# OPENIM_GIT_MINOR - The minor component of the version - -# Grovels through git to set a set of env variables. -# -# If OPENIM_GIT_VERSION_FILE, this function will load from that file instead of -# querying git. -openim::version::get_version_vars() { - if [[ -n ${OPENIM_GIT_VERSION_FILE-} ]]; then - openim::version::load_version_vars "${OPENIM_GIT_VERSION_FILE}" - return - fi - - # If the iamrnetes source was exported through git archive, then - # we likely don't have a git tree, but these magic values may be filled in. - # shellcheck disable=SC2016,SC2050 - # Disabled as we're not expanding these at runtime, but rather expecting - # that another tool may have expanded these and rewritten the source (!) - if [[ '$Format:%%$' == "%" ]]; then - OPENIM_GIT_COMMIT='$Format:%H$' - OPENIM_GIT_TREE_STATE="archive" - # When a 'git archive' is exported, the '$Format:%D$' below will look - # something like 'HEAD -> release-1.8, tag: v1.8.3' where then 'tag: ' - # can be extracted from it. - if [[ '$Format:%D$' =~ tag:\ (v[^ ,]+) ]]; then - OPENIM_GIT_VERSION="${BASH_REMATCH[1]}" - fi - fi - - local git=(git --work-tree "${OPENIM_ROOT}") - - if [[ -n ${OPENIM_GIT_COMMIT-} ]] || OPENIM_GIT_COMMIT=$("${git[@]}" rev-parse "HEAD^{commit}" 2>/dev/null); then - if [[ -z ${OPENIM_GIT_TREE_STATE-} ]]; then - # Check if the tree is dirty. default to dirty - if git_status=$("${git[@]}" status --porcelain 2>/dev/null) && [[ -z ${git_status} ]]; then - OPENIM_GIT_TREE_STATE="clean" - else - OPENIM_GIT_TREE_STATE="dirty" - fi - fi - - # Use git describe to find the version based on tags. - if [[ -n ${OPENIM_GIT_VERSION-} ]] || OPENIM_GIT_VERSION=$("${git[@]}" describe --tags --always --match='v*' 2>/dev/null); then - # This translates the "git describe" to an actual semver.org - # compatible semantic version that looks something like this: - # v1.1.0-alpha.0.6+84c76d1142ea4d - # - # TODO: We continue calling this "git version" because so many - # downstream consumers are expecting it there. - # - # These regexes are painful enough in sed... - # We don't want to do them in pure shell, so disable SC2001 - # shellcheck disable=SC2001 - DASHES_IN_VERSION=$(echo "${OPENIM_GIT_VERSION}" | sed "s/[^-]//g") - if [[ "${DASHES_IN_VERSION}" == "---" ]] ; then - # shellcheck disable=SC2001 - # We have distance to subversion (v1.1.0-subversion-1-gCommitHash) - OPENIM_GIT_VERSION=$(echo "${OPENIM_GIT_VERSION}" | sed "s/-\([0-9]\{1,\}\)-g\([0-9a-f]\{14\}\)$/.\1\+\2/") - elif [[ "${DASHES_IN_VERSION}" == "--" ]] ; then - # shellcheck disable=SC2001 - # We have distance to base tag (v1.1.0-1-gCommitHash) - OPENIM_GIT_VERSION=$(echo "${OPENIM_GIT_VERSION}" | sed "s/-g\([0-9a-f]\{14\}\)$/+\1/") - fi - if [[ "${OPENIM_GIT_TREE_STATE}" == "dirty" ]]; then - # git describe --dirty only considers changes to existing files, but - # that is problematic since new untracked .go files affect the build, - # so use our idea of "dirty" from git status instead. - # TODO? - #OPENIM_GIT_VERSION+="-dirty" - : - fi - - # Try to match the "git describe" output to a regex to try to extract - # the "major" and "minor" versions and whether this is the exact tagged - # version or whether the tree is between two tagged versions. - if [[ "${OPENIM_GIT_VERSION}" =~ ^v([0-9]+)\.([0-9]+)(\.[0-9]+)?([-].*)?([+].*)?$ ]]; then - OPENIM_GIT_MAJOR=${BASH_REMATCH[1]} - OPENIM_GIT_MINOR=${BASH_REMATCH[2]} - if [[ -n "${BASH_REMATCH[4]}" ]]; then - OPENIM_GIT_MINOR+="+" - fi - fi - - # If OPENIM_GIT_VERSION is not a valid Semantic Version, then refuse to build. - if ! [[ "${OPENIM_GIT_VERSION}" =~ ^v([0-9]+)\.([0-9]+)(\.[0-9]+)?(-[0-9A-Za-z.-]+)?(\+[0-9A-Za-z.-]+)?$ ]]; then - echo "OPENIM_GIT_VERSION should be a valid Semantic Version. Current value: ${OPENIM_GIT_VERSION}" - echo "Please see more details here: https://semver.org" - exit 1 - fi - fi - fi -} - -# Saves the environment flags to $1 -openim::version::save_version_vars() { - local version_file=${1-} - [[ -n ${version_file} ]] || { - echo "!!! Internal error. No file specified in openim::version::save_version_vars" - return 1 - } - - cat <"${version_file}" -OPENIM_GIT_COMMIT='${OPENIM_GIT_COMMIT-}' -OPENIM_GIT_TREE_STATE='${OPENIM_GIT_TREE_STATE-}' -OPENIM_GIT_VERSION='${OPENIM_GIT_VERSION-}' -OPENIM_GIT_MAJOR='${OPENIM_GIT_MAJOR-}' -OPENIM_GIT_MINOR='${OPENIM_GIT_MINOR-}' -EOF -} - -# Loads up the version variables from file $1 -openim::version::load_version_vars() { - local version_file=${1-} - [[ -n ${version_file} ]] || { - echo "!!! Internal error. No file specified in openim::version::load_version_vars" - return 1 - } - - source "${version_file}" -} diff --git a/scripts/list-feature-tests.sh b/scripts/list-feature-tests.sh deleted file mode 100755 index f48a7a7e3c..0000000000 --- a/scripts/list-feature-tests.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/usr/bin/env bash -# 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. - - -# This script lists all of the [Feature:.+] tests in our e2e suite. -# -# Usage: `scripts/list-feature-tests.sh`. - - -OPENIM_ROOT=$(dirname "${BASH_SOURCE[0]}")/.. -grep "\[Feature:\w+\]" "${OPENIM_ROOT}"/test/e2e/**/*.go -Eoh | LC_ALL=C sort -u \ No newline at end of file diff --git a/scripts/make-rules/common-versions.mk b/scripts/make-rules/common-versions.mk deleted file mode 100644 index 572585fcee..0000000000 --- a/scripts/make-rules/common-versions.mk +++ /dev/null @@ -1,58 +0,0 @@ -# Copyright © 2023 OpenIMSDK. -# -# 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 Makefile Versions used -# -# Define the latest version for each tool to ensure consistent versioning across installations -GOLANGCI_LINT_VERSION ?= latest -GOIMPORTS_VERSION ?= latest -ADDLICENSE_VERSION ?= latest -DEEPCOPY_GEN_VERSION ?= latest -CONVERSION_GEN_VERSION ?= latest -GINKGO_VERSION ?= v1.16.2 -GO_GITLINT_VERSION ?= latest -GO_JUNIT_REPORT_VERSION ?= latest -GOTESTS_VERSION ?= latest -SWAGGER_VERSION ?= latest -KUBE_SCORE_VERSION ?= latest -KUBECONFORM_VERSION ?= latest -GSEMVER_VERSION ?= latest -GIT_CHGLOG_VERSION ?= latest -KO_VERSION ?= latest -GITHUB_RELEASE_VERSION ?= latest -COSCLI_VERSION ?= v0.19.0-beta -MINIO_VERSION ?= latest -DELVE_VERSION ?= latest -AIR_VERSION ?= latest -GOLINES_VERSION ?= latest -GO_MOD_OUTDATED_VERSION ?= latest -CFSSL_VERSION ?= latest -DEPTH_VERSION ?= latest -GO_CALLVIS_VERSION ?= latest -MISSPELL_VERSION ?= latest -GOTHANKS_VERSION ?= latest -RICHGO_VERSION ?= latest -RTS_VERSION ?= latest -TYPECHECK_VERSION ?= latest -COMMENT_LANG_DETECTOR_VERSION ?= latest -STANDARDIZER_VERSION ?= latest -GO_TESTS_VERSION ?= v1.6.0 -GO_APIDIFF_VERSION ?= v0.8.2 -KAFKACTL_VERSION ?= latest -GOTESTSUM_VERSION ?= latest - -WIRE_VERSION ?= latest -# WIRE_VERSION ?= $(call get_go_version,github.com/google/wire) -MOCKGEN_VERSION ?= $(call get_go_version,github.com/golang/mock) -PROTOC_GEN_GO_VERSION ?= $(call get_go_version,github.com/golang/protobuf/protoc-gen-go) \ No newline at end of file diff --git a/scripts/make-rules/common.mk b/scripts/make-rules/common.mk deleted file mode 100644 index ffbb69a55d..0000000000 --- a/scripts/make-rules/common.mk +++ /dev/null @@ -1,196 +0,0 @@ -# Copyright © 2023 OpenIMSDK. -# -# 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. - -# ============================================================================== -# Makefile helper functions for common tasks -# - -SHELL := /bin/bash -GO:=go -DIRS=$(shell ls) -DEBUG ?= 0 -GIT_TAG := $(shell git describe --exact-match --tags --abbrev=0 2> /dev/null || echo untagged) -GIT_COMMIT ?= $(shell git rev-parse --short HEAD || echo "0.0.0") -BUILD_DATE ?=$(shell date -u +'%Y-%m-%dT%H:%M:%SZ') # Blank error: date '+%FT %T %z':"buildDate":"2023-03-31T 20:05:43 +0800" - -# include the common makefile -COMMON_SELF_DIR := $(dir $(lastword $(MAKEFILE_LIST))) - -SRC = $(shell find . -type f -name '*.go' -not -path "./vendor/*") - -# ROOT_DIR: root directory of the code base -ifeq ($(origin ROOT_DIR),undefined) -ROOT_DIR := $(abspath $(shell cd $(COMMON_SELF_DIR)/../.. && pwd -P)) -endif - -# OUTPUT_DIR: The directory where the build output is stored. -ifeq ($(origin OUTPUT_DIR),undefined) -OUTPUT_DIR := $(ROOT_DIR)/_output -$(shell mkdir -p $(OUTPUT_DIR)) -endif - -# BIN_DIR: Directory where executable files are stored. -ifeq ($(origin BIN_DIR),undefined) -BIN_DIR := $(OUTPUT_DIR)/bin -$(shell mkdir -p $(BIN_DIR)) -endif - -# BIN_TOOLS_DIR: Directory where executable files are stored. -ifeq ($(origin BIN_TOOLS_DIR),undefined) -BIN_TOOLS_DIR := $(BIN_DIR)/tools -$(shell mkdir -p $(BIN_TOOLS_DIR)) -endif - -# LOGS_DIR: Directory where log files are stored. -ifeq ($(origin LOGS_DIR),undefined) -LOGS_DIR := $(OUTPUT_DIR)/logs -$(shell mkdir -p $(LOGS_DIR)) -endif - -# TOOLS_DIR: The directory where tools are stored for build and testing. -ifeq ($(origin TOOLS_DIR),undefined) -TOOLS_DIR := $(OUTPUT_DIR)/tools -$(shell mkdir -p $(TOOLS_DIR)) -endif - -# TMP_DIR: directory where temporary files are stored. -ifeq ($(origin TMP_DIR),undefined) -TMP_DIR := $(OUTPUT_DIR)/tmp -$(shell mkdir -p $(TMP_DIR)) -endif - -ifeq ($(origin VERSION), undefined) -# VERSION := $(shell git describe --tags --always --match='v*') -# git describe --tags --always --match="v*" --dirty -# VERSION := $(shell git describe --tags --always --match="v*" --dirty | sed 's/-/./g') #v2.3.3.631.g00abdc9b.dirty -VERSION := $(shell git describe --tags --always --match='v*') -# v2.3.3: git tag -endif - -# Helper function to get dependency version from go.mod -get_gomod_version = $(shell go list -m $1 | awk '{print $$2}') -define go_install -$(info ===========> Installing $(1)@$(2)) -$(GO) install $(1)@$(2) -endef - -# Check if the tree is dirty. default to dirty(maybe u should commit?) -GIT_TREE_STATE:="dirty" -ifeq (, $(shell git status --porcelain 2>/dev/null)) - GIT_TREE_STATE="clean" -endif -GIT_COMMIT:=$(shell git rev-parse HEAD) - -# Minimum test coverage -# can u use make cover COVERAGE=90 -ifeq ($(origin COVERAGE),undefined) -COVERAGE := 60 -endif - -# Get the currently used golang install path (in GOPATH/bin, unless GOBIN is set) -ifeq (,$(shell go env GOBIN)) -GOBIN=$(shell go env GOPATH)/bin -else -GOBIN=$(shell go env GOBIN) -endif - -# The OS must be linux when building docker images -# PLATFORMS ?= linux_amd64 linux_arm64 -# The OS can be linux/windows/darwin when building binaries -PLATFORMS ?= linux_s390x linux_mips64 linux_mips64le darwin_amd64 darwin_arm64 windows_amd64 linux_amd64 linux_arm64 linux_ppc64le # wasip1_wasm - -# set a specific PLATFORM, defaults to the host platform -ifeq ($(origin PLATFORM), undefined) - ifeq ($(origin GOARCH), undefined) - GOARCH := $(shell go env GOARCH) - endif - # Determine the host OS - GOOS := $(shell go env GOOS) - PLATFORM := $(GOOS)_$(GOARCH) - # Use the host OS and GOARCH as the default when building images - IMAGE_PLAT := $(PLATFORM) -else - # Parse the PLATFORM variable - GOOS := $(word 1, $(subst _, ,$(PLATFORM))) - GOARCH := $(word 2, $(subst _, ,$(PLATFORM))) - IMAGE_PLAT := $(PLATFORM) -endif - - -# Protobuf file storage path -APIROOT=$(ROOT_DIR)/pkg/proto - -# Linux command settings -# TODO: Whether you need to join utils? -FIND := find . ! -path './utils/*' ! -path './vendor/*' ! -path './third_party/*' ! -path './components/*' ! -path './logs/*' -XARGS := xargs -r --no-run-if-empty - -# Linux command settings-CODE DIRS Copyright -CODE_DIRS := $(ROOT_DIR)/pkg $(ROOT_DIR)/cmd $(ROOT_DIR)/config $(ROOT_DIR)/internal $(ROOT_DIR)/scripts $(ROOT_DIR)/test $(ROOT_DIR)/.github $(ROOT_DIR)/build $(ROOT_DIR)/tools $(ROOT_DIR)/deployments -FINDS := find $(CODE_DIRS) - -# Makefile settings: Select different behaviors by determining whether V option is set -ifndef V -MAKEFLAGS += --no-print-directory -endif - -# COMMA: Concatenate multiple strings to form a list of strings -COMMA := , -# SPACE: Used to separate strings -SPACE := -# SPACE: Replace multiple consecutive Spaces with a single space -SPACE += - -# ============================================================================== -# Makefile helper functions for common tasks - -# Help information for the makefile package -define makehelp - @printf "\n\033[1mUsage: make ...\033[0m\n\n\\033[1mTargets:\\033[0m\n\n" - @sed -n 's/^##//p' $< | awk -F':' '{printf "\033[36m%-28s\033[0m %s\n", $$1, $$2}' | sed -e 's/^/ /' - @printf "\n\033[1m$$USAGE_OPTIONS\033[0m\n" -endef - -# Here are some examples of builds -define MAKEFILE_EXAMPLE -# make build BINS=openim-api Only a single openim-api binary is built. -# make -j (nproc) all Run tidy gen add-copyright format lint cover build concurrently. -# make gen Generate all necessary files. -# make release Build release binaries for all platforms. -# make verify-copyright Verify the license headers for all files. -# make install-deepcopy-gen Install deepcopy-gen tools if the license is missing. -# make build BINS=openim-api V=1 DEBUG=1 Build debug binaries for only openim-api. -# make multiarch -j PLATFORMS="linux_arm64 linux_amd64" V=1 Build binaries for both platforms. -# make image -endef -export MAKEFILE_EXAMPLE - -# Define all help functions @printf "\n\033[1mCurrent openim-api version information: $(shell openim-api version):\033[0m\n\n" -define makeallhelp - @printf "\n\033[1mMake example:\033[0m\n\n" - $(call MAKEFILE_EXAMPLE) - @printf "\n\033[1mAriables:\033[0m\n\n" - @echo " DEBUG: $(DEBUG)" - @echo " BINS: $(BINS)" - @echo " PLATFORMS: $(PLATFORMS)" - @echo " V: $(V)" -endef - -# Help information for other makefile packages -CUT_OFF?="---------------------------------------------------------------------------------" -HELP_NAME:=$(shell basename $(MAKEFILE_LIST)) -define smallhelp - @sed -n 's/^##//p' $< | awk -F':' '{printf "\033[36m%-35s\033[0m %s\n", $$1, $$2}' | sed -e 's/^/ /' - @echo $(CUT_OFF) -endef \ No newline at end of file diff --git a/scripts/make-rules/copyright.mk b/scripts/make-rules/copyright.mk deleted file mode 100644 index 18b4dd7097..0000000000 --- a/scripts/make-rules/copyright.mk +++ /dev/null @@ -1,63 +0,0 @@ -# Copyright © 2023 OpenIMSDK. -# -# 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. -# -# ============================================================================== -# wget https://github.com/google/addlicense/releases/download/v1.0.0/addlicense_1.0.0_Linux_x86_64.tar.gz -# Makefile helper functions for copyright -# - -LICENSE_TEMPLATE ?= $(ROOT_DIR)/scripts/template/LICENSE_TEMPLATES - -## copyright.verify: Validate boilerplate headers for assign files -.PHONY: copyright.verify -copyright.verify: tools.verify.addlicense - @echo "===========> Validate boilerplate headers for assign files starting in the $(ROOT_DIR) directory" - @$(TOOLS_DIR)/addlicense -v -check -ignore **/test/** -ignore **pb** -f $(LICENSE_TEMPLATE) $(CODE_DIRS) - @echo "===========> End of boilerplate headers check..." - -## copyright.add: Add the boilerplate headers for all files -.PHONY: copyright.add -copyright.add: tools.verify.addlicense - @echo "===========> Adding $(LICENSE_TEMPLATE) the boilerplate headers for all files" - @$(TOOLS_DIR)/addlicense -y $(shell date +"%Y") -ignore **pb** -v -c "OpenIM." -f $(LICENSE_TEMPLATE) $(CODE_DIRS) - @echo "===========> End the copyright is added..." - -# Addlicense Flags: -# -c string -# copyright holder (default "Google LLC") -# -check -# check only mode: verify presence of license headers and exit with non-zero code if missing -# -f string -# license file -# -ignore value -# file patterns to ignore, for example: -ignore **/*.go -ignore vendor/** -# -l string -# license type: apache, bsd, mit, mpl (default "apache") -# -s Include SPDX identifier in license header. Set -s=only to only include SPDX identifier. -# -skip value -# [deprecated: see -ignore] file extensions to skip, for example: -skip rb -skip go -# -v verbose mode: print the name of the files that are modified or were skipped -# -y string -# copyright year(s) (default "2023") - -## copyright.advertise: Advertise the license of the project -.PHONY: copyright.advertise -copyright.advertise: - @chmod +x $(ROOT_DIR)/scripts/advertise.sh - @$(ROOT_DIR)/scripts/advertise.sh - -## copyright.help: Show copyright help -.PHONY: copyright.help -copyright.help: scripts/make-rules/copyright.mk - $(call smallhelp) \ No newline at end of file diff --git a/scripts/make-rules/dependencies.mk b/scripts/make-rules/dependencies.mk deleted file mode 100644 index 1a896f1ff5..0000000000 --- a/scripts/make-rules/dependencies.mk +++ /dev/null @@ -1,41 +0,0 @@ -# Copyright © 2023 OpenIMSDK. -# -# 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. - -# ============================================================================== -# Makefile helper functions for dependencies -# - -.PHONY: dependencies.run -dependencies.run: dependencies.packages dependencies.tools - -.PHONY: dependencies.packages -dependencies.packages: - @$(GO) mod tidy - -.PHONY: dependencies.tools -dependencies.tools: dependencies.tools.blocker dependencies.tools.critical - -.PHONY: dependencies.tools.blocker -dependencies.tools.blocker: go.build.verify $(addprefix tools.verify., $(BLOCKER_TOOLS)) - -.PHONY: dependencies.tools.critical -dependencies.tools.critical: $(addprefix tools.verify., $(CRITICAL_TOOLS)) - -.PHONY: dependencies.tools.trivial -dependencies.tools.trivial: $(addprefix tools.verify., $(TRIVIAL_TOOLS)) - -## dependencies.help: Print help for dependencies targets -.PHONY: dependencies.help -dependencies.help: scripts/make-rules/dependencies.mk - $(call smallhelp) \ No newline at end of file diff --git a/scripts/make-rules/gen.mk b/scripts/make-rules/gen.mk deleted file mode 100644 index fba0132ff5..0000000000 --- a/scripts/make-rules/gen.mk +++ /dev/null @@ -1,100 +0,0 @@ -# Copyright © 2023 OpenIMSDK. -# -# 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. - -# ============================================================================== -# Makefile helper functions for generate necessary files and docs -# https://cloud.redhat.com/blog/kubernetes-deep-dive-code-generation-customresources -# ! The stock of code generated by `make gen` should be idempotent -# -# Questions about go mod instead of go path: https://github.com/kubernetes/kubernetes/issues/117181 -# ============================================================================== -# Makefile helper functions for generate necessary files -# - -## gen.init: Initialize openim server project ✨ -.PHONY: gen.init -gen.init: - @echo "===========> Initializing openim server project" - @${ROOT_DIR}/scripts/init-config.sh - -## gen.init-githooks: Initialize git hooks ✨ -.PHONY: gen.init-githooks -gen.init-githooks: - @echo "===========> Initializing git hooks" - @${ROOT_DIR}/scripts/init-githooks.sh - -## gen.run: Generate necessary files and docs ✨ -.PHONY: gen.run -#gen.run: gen.errcode gen.docgo -gen.run: gen.clean gen.errcode gen.docgo.doc - -## gen.errcode: Generate necessary files and docs ✨ -.PHONY: gen.errcode -gen.errcode: gen.errcode.code gen.errcode.doc - -## gen.errcode.code: Generate openim error code go source files ✨ -.PHONY: gen.errcode.code -gen.errcode.code: tools.verify.codegen - @echo "===========> Generating openim error code go source files" - @codegen -type=int ${ROOT_DIR}/internal/pkg/code - -## gen.errcode.doc: Generate openim error code markdown documentation ✨ -.PHONY: gen.errcode.doc -gen.errcode.doc: tools.verify.codegen - @echo "===========> Generating error code markdown documentation" - @codegen -type=int -doc \ - -output ${ROOT_DIR}/docs/guide/zh-CN/api/error_code_generated.md ${ROOT_DIR}/internal/pkg/code - -## gen.docgo: Generate missing doc.go for go packages ✨ -.PHONY: gen.ca.% -gen.ca.%: - $(eval CA := $(word 1,$(subst ., ,$*))) - @echo "===========> Generating CA files for $(CA)" - @${ROOT_DIR}/scripts/gencerts.sh generate-openim-cert $(OUTPUT_DIR)/cert $(CA) - -## gen.ca: Generate CA files for all certificates ✨ -.PHONY: gen.ca -gen.ca: $(addprefix gen.ca., $(CERTIFICATES)) - -## gen.docgo: Generate missing doc.go for go packages ✨ -.PHONY: gen.docgo.doc -gen.docgo.doc: - @echo "===========> Generating missing doc.go for go packages" - @${ROOT_DIR}/scripts/gendoc.sh - -## gen.docgo.check: Check if there are untracked doc.go files ✨ -.PHONY: gen.docgo.check -gen.docgo.check: gen.docgo.doc - @n="$$(git ls-files --others '*/doc.go' | wc -l)"; \ - if test "$$n" -gt 0; then \ - git ls-files --others '*/doc.go' | sed -e 's/^/ /'; \ - echo "$@: untracked doc.go file(s) exist in working directory" >&2 ; \ - false ; \ - fi - -## gen.docgo.add: Add untracked doc.go files to git index ✨ -.PHONY: gen.docgo.add -gen.docgo.add: - @git ls-files --others '*/doc.go' | $(XARGS) -- git add - -## gen.docgo: Generate missing doc.go for go packages ✨ -.PHONY: gen.clean -gen.clean: - @rm -rf ./api/client/{clientset,informers,listers} - @$(FIND) -type f -name '*_generated.go' -delete - -## gen.help: show help for gen -.PHONY: gen.help -gen.help: scripts/make-rules/gen.m - $(call smallhelp) \ No newline at end of file diff --git a/scripts/make-rules/golang.mk b/scripts/make-rules/golang.mk deleted file mode 100644 index cdc5a5fc95..0000000000 --- a/scripts/make-rules/golang.mk +++ /dev/null @@ -1,272 +0,0 @@ -# Copyright © 2023 OpenIMSDK. -# -# 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. - -# ============================================================================== -# Build management helpers. These functions help to set, save and load the -# - -GO := go -GO_MINIMUM_VERSION ?= 1.19 - -GO_LDFLAGS += -X $(VERSION_PACKAGE).gitVersion=$(GIT_TAG) \ - -X $(VERSION_PACKAGE).gitCommit=$(GIT_COMMIT) \ - -X $(VERSION_PACKAGE).gitTreeState=$(GIT_TREE_STATE) \ - -X $(VERSION_PACKAGE).buildDate=$(BUILD_DATE) \ - -s -w # -s -w deletes debugging information and symbol tables -ifeq ($(DEBUG), 1) - GO_BUILD_FLAGS += -gcflags "all=-N -l" - GO_LDFLAGS= -endif - -GO_BUILD_FLAGS += -ldflags "$(GO_LDFLAGS)" - -ifeq ($(GOOS),windows) - GO_OUT_EXT := .exe -endif - -ifeq ($(ROOT_PACKAGE),) - $(error the variable ROOT_PACKAGE must be set prior to including golang.mk, ->/Makefile) -endif - -GOPATH ?= $(shell go env GOPATH) -ifeq ($(origin GOBIN), undefined) - GOBIN := $(GOPATH)/bin -endif - -# COMMANDS is Specify all files under ${ROOT_DIR}/cmd/ and ${ROOT_DIR}/tools/ except those ending in.md -COMMANDS ?= $(filter-out %.md, $(wildcard ${ROOT_DIR}/cmd/* ${ROOT_DIR}/tools/* ${ROOT_DIR}/tools/data-conversion/chat/cmd/* ${ROOT_DIR}/tools/data-conversion/openim/cmd/* ${ROOT_DIR}/cmd/openim-rpc/*)) -ifeq (${COMMANDS},) - $(error Could not determine COMMANDS, set ROOT_DIR or run in source dir) -endif - -# BINS is the name of each file in ${COMMANDS}, excluding the directory path -# If there are no files in ${COMMANDS}, or if all files end in.md, ${BINS} will be empty -BINS ?= $(foreach cmd,${COMMANDS},$(notdir ${cmd})) -ifeq (${BINS},) - $(error Could not determine BINS, set ROOT_DIR or run in source dir) -endif - -ifeq ($(OS),Windows_NT) - NULL := - SPACE := $(NULL) $(NULL) - ROOT_DIR := $(subst $(SPACE),\$(SPACE),$(shell cd)) -else - ROOT_DIR := $(shell pwd) -endif - -ifeq ($(strip $(COMMANDS)),) - $(error Could not determine COMMANDS, set ROOT_DIR or run in source dir) -endif -ifeq ($(strip $(BINS)),) - $(error Could not determine BINS, set ROOT_DIR or run in source dir) -endif - -# TODO: EXCLUDE_TESTS variable, which contains the name of the package to be excluded from the test -EXCLUDE_TESTS=github.com/openimsdk/open-im-server/test github.com/openimsdk/open-im-server/v3/pkg/log github.com/openimsdk/open-im-server/db github.com/openimsdk/open-im-server/scripts github.com/openimsdk/open-im-server/config - -# ============================================================================== -# ❯ tree -L 1 cmd -# cmd -# ├── openim-sdk-core/ - main.go -# ├── openim-api -# ├── openim_cms_api -# ├── openim-crontask -# ├── openim_demo -# ├── openim-rpc-msg_gateway -# ├── openim-msgtransfer -# ├── openim-push -# ├── rpc/openim_admin_cms/ - main.go -# └── test/ - main.go -# COMMAND=openim -# PLATFORM=linux_amd64 -# OS=linux -# ARCH=amd64 -# BINS=openim-api openim_cms_api openim-crontask openim_demo openim-rpc-msg_gateway openim-msgtransfer openim-push -# BIN_DIR=/root/workspaces/OpenIM/_output/bin -# ============================================================================== - -## go.build: Build binaries -.PHONY: go.build -go.build: go.build.verify $(addprefix go.build., $(addprefix $(PLATFORM)., $(BINS))) - @echo "===========> Building binary $(BINS) $(VERSION) for $(PLATFORM)" - -## go.start: Start openim -.PHONY: go.start -go.start: - @echo "=========================> Starting OpenIM <=========================" - @$(ROOT_DIR)/scripts/start-all.sh - -## go.stop: Stop openim -.PHONY: go.stop -go.stop: - @echo "=========================> Stopping OpenIM <=========================" - @$(ROOT_DIR)/scripts/stop-all.sh - -## go.check: Check openim -.PHONY: go.check -go.check: - @echo "=========================> Checking OpenIM <=========================" - @$(ROOT_DIR)/scripts/check-all.sh - -## go.check-component: Check openim component -.PHONY: go.check-component -go.check-component: - @echo "=========================> Checking OpenIM component <=========================" - @$(ROOT_DIR)/scripts/install/openim-tools.sh openim::tools::pre-start - -## go.versionchecker: Design, detect some environment variables and versions -go.versionchecker: - @$(ROOT_DIR)/scripts/install/openim-tools.sh openim::tools::post-start - -## go.build.verify: Verify that a suitable version of Go exists -.PHONY: go.build.verify -go.build.verify: -ifneq ($(shell $(GO) version|awk -v min=$(GO_MINIMUM_VERSION) '{gsub(/go/,"",$$3);if($$3 >= min){print 0}else{print 1}}'), 0) - $(error unsupported go version. Please install a go version which is greater than or equal to '$(GO_MINIMUM_VERSION)') -endif - -## go.build.%: Build binaries for a specific platform -# CGO_ENABLED=0 https://wiki.musl-libc.org/functional-differences-from-glibc.html -.PHONY: go.build.% -go.build.%: - $(eval COMMAND := $(word 2,$(subst ., ,$*))) - $(eval PLATFORM := $(word 1,$(subst ., ,$*))) - $(eval OS := $(word 1,$(subst _, ,$(PLATFORM)))) - $(eval ARCH := $(word 2,$(subst _, ,$(PLATFORM)))) - @echo "=====> COMMAND=$(COMMAND)" - @echo "=====> PLATFORM=$(PLATFORM)" - @echo "===========> Building binary $(COMMAND) $(VERSION) for $(OS)_$(ARCH)" - @mkdir -p $(BIN_DIR)/platforms/$(OS)/$(ARCH) - @if [ "$(COMMAND)" == "openim-sdk-core" ]; then \ - echo "===========> DEBUG: OpenIM-SDK-Core It is no longer supported for openim-server $(COMMAND)"; \ - elif [ -d $(ROOT_DIR)/cmd/openim-rpc/$(COMMAND) ]; then \ - CGO_ENABLED=0 GOOS=$(OS) GOARCH=$(ARCH) $(GO) build $(GO_BUILD_FLAGS) -o \ - $(BIN_DIR)/platforms/$(OS)/$(ARCH)/$(COMMAND)$(GO_OUT_EXT) $(ROOT_DIR)/cmd/openim-rpc/$(COMMAND)/main.go; \ - else \ - if [ -f $(ROOT_DIR)/cmd/$(COMMAND)/main.go ]; then \ - CGO_ENABLED=0 GOOS=$(OS) GOARCH=$(ARCH) $(GO) build $(GO_BUILD_FLAGS) -o \ - $(BIN_DIR)/platforms/$(OS)/$(ARCH)/$(COMMAND)$(GO_OUT_EXT) $(ROOT_DIR)/cmd/$(COMMAND)/main.go; \ - elif [ -f $(ROOT_DIR)/tools/$(COMMAND)/$(COMMAND).go ]; then \ - CGO_ENABLED=0 GOOS=$(OS) GOARCH=$(ARCH) $(GO) build $(GO_BUILD_FLAGS) -o \ - $(BIN_TOOLS_DIR)/$(OS)/$(ARCH)/$(COMMAND)$(GO_OUT_EXT) $(ROOT_DIR)/tools/$(COMMAND)/$(COMMAND).go; \ - chmod +x $(BIN_TOOLS_DIR)/$(OS)/$(ARCH)/$(COMMAND)$(GO_OUT_EXT); \ - elif [ -f $(ROOT_DIR)/tools/data-conversion/openim/cmd/$(COMMAND)/$(COMMAND).go ]; then \ - CGO_ENABLED=0 GOOS=$(OS) GOARCH=$(ARCH) $(GO) build $(GO_BUILD_FLAGS) -o \ - $(BIN_TOOLS_DIR)/$(OS)/$(ARCH)/$(COMMAND)$(GO_OUT_EXT) $(ROOT_DIR)/tools/data-conversion/openim/cmd/$(COMMAND)/$(COMMAND).go; \ - chmod +x $(BIN_TOOLS_DIR)/$(OS)/$(ARCH)/$(COMMAND)$(GO_OUT_EXT); \ - elif [ -f $(ROOT_DIR)/tools/data-conversion/chat/cmd/$(COMMAND)/$(COMMAND).go ]; then \ - CGO_ENABLED=0 GOOS=$(OS) GOARCH=$(ARCH) $(GO) build $(GO_BUILD_FLAGS) -o \ - $(BIN_TOOLS_DIR)/$(OS)/$(ARCH)/$(COMMAND)$(GO_OUT_EXT) $(ROOT_DIR)/tools/data-conversion/chat/cmd/$(COMMAND)/$(COMMAND).go; \ - chmod +x $(BIN_TOOLS_DIR)/$(OS)/$(ARCH)/$(COMMAND)$(GO_OUT_EXT); \ - fi \ - fi - -## go.install: Install deployment openim -.PHONY: go.install -go.install: - @echo "===========> Installing deployment openim" - @$(ROOT_DIR)/scripts/install-im-server.sh - -## go.multiarch: Build multi-arch binaries -.PHONY: go.build.multiarch -go.build.multiarch: go.build.verify $(foreach p,$(PLATFORMS),$(addprefix go.build., $(addprefix $(p)., $(BINS)))) - -## go.lint: Run golangci to lint source codes -.PHONY: go.lint -go.lint: tools.verify.golangci-lint - @echo "===========> Run golangci to lint source codes" - @$(TOOLS_DIR)/golangci-lint run --color always -c $(ROOT_DIR)/.golangci.yml $(ROOT_DIR)/... - -## go.test: Run unit test -.PHONY: go.test -go.test: - @$(GO) test ./... - -## go.test.api: Run api test -.PHONY: go.test.api -go.test.api: - @echo "===========> Run api test" - @$(ROOT_DIR)/scripts/install/test.sh openim::test::test - -## go.test.e2e: Run e2e test -.PHONY: go.test.e2e -go.test.e2e: tools.verify.ginkgo - @echo "===========> Run e2e test" - @$(TOOLS_DIR)/ginkgo -v $(ROOT_DIR)/test/e2e - -## go.demo: Run demo -.PHONY: go.demo -go.demo: - @echo "===========> Run demo" - @$(ROOT_DIR)/scripts/demo.sh - -## go.test.junit-report: Run unit test -.PHONY: go.test.junit-report -go.test.junit-report: tools.verify.go-junit-report - @touch $(TMP_DIR)/coverage.out - @echo "===========> Run unit test > $(TMP_DIR)/report.xml" -# @$(GO) test -v -coverprofile=$(TMP_DIR)/coverage.out 2>&1 $(GO_BUILD_FLAGS) ./... | $(TOOLS_DIR)/go-junit-report -set-exit-code > $(TMP_DIR)/report.xml - @$(GO) test -v -coverprofile=$(TMP_DIR)/coverage.out 2>&1 ./... | $(TOOLS_DIR)/go-junit-report -set-exit-code > $(TMP_DIR)/report.xml - @sed -i '/mock_.*.go/d' $(TMP_DIR)/coverage.out - @echo "===========> Test coverage of Go code is reported to $(TMP_DIR)/coverage.html by generating HTML" - @$(GO) tool cover -html=$(TMP_DIR)/coverage.out -o $(TMP_DIR)/coverage.html - -## go.test.cover: Run unit test with coverage -.PHONY: go.test.cover -go.test.cover: go.test.junit-report - @$(GO) tool cover -func=$(TMP_DIR)/coverage.out | \ - awk -v target=$(COVERAGE) -f $(ROOT_DIR)/scripts/coverage.awk - -## go.format: Run unit test and format codes -.PHONY: go.format -go.format: tools.verify.golines tools.verify.goimports - @echo "===========> Formatting codes" - @$(FIND) -type f -name '*.go' -not -name '*pb*' | $(XARGS) gofmt -s -w - @$(FIND) -type f -name '*.go' -not -name '*pb*' | $(XARGS) $(TOOLS_DIR)/goimports -w -local $(ROOT_PACKAGE) - @$(FIND) -type f -name '*.go' -not -name '*pb*' | $(XARGS) $(TOOLS_DIR)/golines -w --max-len=200 --reformat-tags --shorten-comments --ignore-generated . - @$(GO) mod edit -fmt - -## go.imports: task to automatically handle import packages in Go files using goimports tool -.PHONY: go.imports -go.imports: tools.verify.goimports - @$(TOOLS_DIR)/goimports -l -w $(SRC) - -## go.verify: execute all verity scripts. -.PHONY: go.verify -go.verify: tools.verify.misspell - @echo "Starting verification..." - @scripts_list=$$(find $(ROOT_DIR)/scripts -type f -name 'verify-*' | sort); \ - for script in $$scripts_list; do \ - echo "Executing $$script..."; \ - $$script || exit 1; \ - echo "$$script completed successfully"; \ - done - @echo "All verification scripts executed successfully." - -## go.updates: Check for updates to go.mod dependencies -.PHONY: go.updates -go.updates: tools.verify.go-mod-outdated - @$(GO) list -u -m -json all | go-mod-outdated -update -direct - -## go.clean: Clean all builds directories and files -.PHONY: go.clean -go.clean: - @echo "===========> Cleaning all builds tmp, bin, logs directories and files" - @-rm -vrf $(TMP_DIR) $(BIN_DIR) $(BIN_TOOLS_DIR) $(LOGS_DIR) - @echo "===========> End clean..." - -## go.help: Show go tools help -.PHONY: go.help -go.help: scripts/make-rules/golang.mk - $(call smallhelp) diff --git a/scripts/make-rules/image.mk b/scripts/make-rules/image.mk deleted file mode 100644 index eaec4a1271..0000000000 --- a/scripts/make-rules/image.mk +++ /dev/null @@ -1,183 +0,0 @@ -# Copyright © 2023 OpenIMSDK. -# -# 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. - -# ============================================================================== -# Makefile helper functions for docker image -# ============================================================================== -# Path: scripts/make-rules/image.mk -# docker registry: registry.example.com/namespace/image:tag as: registry.hub.docker.com/cubxxw/: -# https://docs.docker.com/build/building/multi-platform/ -# - -DOCKER := docker - -# read: https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/images.md -REGISTRY_PREFIX ?= registry.cn-hangzhou.aliyuncs.com/openimsdk -# REGISTRY_PREFIX ?= ghcr.io/openimsdk - -BASE_IMAGE ?= ghcr.io/openim-sigs/openim-bash-image - -IMAGE_PLAT ?= $(subst $(SPACE),$(COMMA),$(subst _,/,$(PLATFORMS))) - -EXTRA_ARGS ?= --no-cache -_DOCKER_BUILD_EXTRA_ARGS := - -ifdef HTTP_PROXY -_DOCKER_BUILD_EXTRA_ARGS += --build-arg HTTP_PROXY=${HTTP_PROXY} -endif - -ifneq ($(EXTRA_ARGS), ) -_DOCKER_BUILD_EXTRA_ARGS += $(EXTRA_ARGS) -endif - -# Determine image files by looking into build/images/*/Dockerfile -IMAGES_DIR ?= $(wildcard ${ROOT_DIR}/build/images/*) -# Determine images names by stripping out the dir names, and filter out the undesired directories -# IMAGES ?= $(filter-out Dockerfile,$(foreach image,${IMAGES_DIR},$(notdir ${image}))) -IMAGES ?= $(filter-out Dockerfile openim-tools openim-rpc-extend-msg openim-rpc-encryption openim-cmdutils,$(foreach image,${IMAGES_DIR},$(notdir ${image}))) -# IMAGES ?= $(filter-out Dockerfile openim-tools openim-cmdutils,$(foreach image,${IMAGES_DIR},$(notdir ${image}))) # !pro - -ifeq (${IMAGES},) - $(error Could not determine IMAGES, set ROOT_DIR or run in source dir) -endif - -# ============================================================================== -# Image targets -# ============================================================================== - -# PLATFORMS defines the target platforms for the manager image be build to provide support to multiple -# architectures. (i.e. make docker-buildx IMG=myregistry/mypoperator:0.0.1). To use this option you need to: -# - able to use docker buildx . More info: https://docs.docker.com/build/buildx/ -# - have enable BuildKit, More info: https://docs.docker.com/develop/develop-images/build_enhancements/ -# - be able to push the image for your registry (i.e. if you do not inform a valid value via IMG=> then the export will fail) -# To properly provided solutions that supports more than one platform you should use this option. -## image.docker-buildx: Build and push docker image for the manager for cross-platform support -PLATFORMS ?= linux/arm64,linux/amd64,linux/s390x,linux/ppc64le -# copy existing Dockerfile and insert --platform=${BUILDPLATFORM} into Dockerfile.cross, and preserve the original Dockerfile -.PHONY: image.docker-buildx -image.docker-buildx: - sed -e '1 s/\(^FROM\)/FROM --platform=\$$\{BUILDPLATFORM\}/; t' -e ' 1,// s//FROM --platform=\$$\{BUILDPLATFORM\}/' Dockerfile > Dockerfile.cross - - $(CONTAINER_TOOL) buildx create --name project-v3-builder - $(CONTAINER_TOOL) buildx use project-v3-builder - - $(CONTAINER_TOOL) buildx build --push --platform=$(PLATFORMS) --tag ${IMAGES} -f Dockerfile.cross . - - $(CONTAINER_TOOL) buildx rm project-v3-builder - rm Dockerfile.cross - -## image.verify: Verify docker version -.PHONY: image.verify -image.verify: - @$(ROOT_DIR)/scripts/lib/util.sh openim::util::check_docker_and_compose_versions - -## image.daemon.verify: Verify docker daemon experimental features -.PHONY: image.daemon.verify -image.daemon.verify: - @$(ROOT_DIR)/scripts/lib/util.sh openim::util::ensure_docker_daemon_connectivity - @$(ROOT_DIR)/scripts/lib/util.sh openim::util::ensure-docker-buildx - -# If you wish built the manager image targeting other platforms you can use the --platform flag. -# (i.e. docker build --platform linux/arm64 ). However, you must enable docker buildKit for it. -# More info: https://docs.docker.com/develop/develop-images/build_enhancements/ -## image.build: Build docker images -.PHONY: image.build -image.build: image.verify $(addprefix image.build., $(addprefix $(PLATFORM)., $(IMAGES))) - -.PHONY: image.build.multiarch -image.build.multiarch: image.verify $(foreach p,$(PLATFORMS),$(addprefix image.build., $(addprefix $(p)., $(IMAGES)))) - -## image.build.%: Build docker image for a specific platform -.PHONY: image.build.% -image.build.%: go.build.% - $(eval IMAGE := $(COMMAND)) - $(eval IMAGE_PLAT := $(subst _,/,$(PLATFORM))) - $(eval ARCH := $(word 2,$(subst _, ,$(PLATFORM)))) - @echo "===========> Building docker image $(IMAGE) $(VERSION) for $(IMAGE_PLAT)" - @mkdir -p $(TMP_DIR)/$(IMAGE)/$(PLATFORM) - @cat $(ROOT_DIR)/build/images/Dockerfile\ - | sed "s#BASE_IMAGE#$(BASE_IMAGE)#g" \ - | sed "s#BINARY_NAME#$(IMAGE)#g" >$(TMP_DIR)/$(IMAGE)/Dockerfile - @cp $(BIN_DIR)/platforms/$(IMAGE_PLAT)/$(IMAGE) $(TMP_DIR)/$(IMAGE) - $(eval BUILD_SUFFIX := $(_DOCKER_BUILD_EXTRA_ARGS) --pull -t $(REGISTRY_PREFIX)/$(IMAGE)-$(ARCH):$(VERSION) $(TMP_DIR)/$(IMAGE)) - @echo $(DOCKER) build --platform $(IMAGE_PLAT) $(BUILD_SUFFIX) - @if [ $(shell $(GO) env GOARCH) != $(ARCH) ] ; then \ - $(MAKE) image.daemon.verify ;\ - $(DOCKER) build --platform $(IMAGE_PLAT) $(BUILD_SUFFIX) ; \ - else \ - $(DOCKER) build $(BUILD_SUFFIX) ; \ - fi - @rm -rf $(TMP_DIR)/$(IMAGE) - -# https://docs.docker.com/build/building/multi-platform/ -# busybox image supports amd64, arm32v5, arm32v6, arm32v7, arm64v8, i386, ppc64le, and s390x -## image.buildx.%: Build docker images with buildx -.PHONY: image.buildx.% -image.buildx.%: - $(eval IMAGE := $(word 1,$(subst ., ,$*))) - echo "===========> Building docker image $(IMAGE) $(VERSION)" - $(DOCKER) buildx build -f $(ROOT_DIR)/Dockerfile --pull --no-cache --platform=$(PLATFORMS) --push . -t $(REGISTRY_PREFIX)/$(IMAGE)-$(ARCH):$(VERSION) - -## image.push: Push docker images -.PHONY: image.push -image.push: image.verify go.build.verify $(addprefix image.push., $(addprefix $(IMAGE_PLAT)., $(IMAGES))) - -## image.push.multiarch: Push docker images for all platforms -.PHONY: image.push.multiarch -image.push.multiarch: image.verify go.build.verify $(foreach p,$(PLATFORMS),$(addprefix image.push., $(addprefix $(p)., $(IMAGES)))) - -## image.push.%: Push docker image for a specific platform -.PHONY: image.push.% -image.push.%: image.build.% - @echo "===========> Pushing image $(IMAGE) $(VERSION) to $(REGISTRY_PREFIX)" - $(DOCKER) push $(REGISTRY_PREFIX)/$(IMAGE)-$(ARCH):$(VERSION) - -## image.manifest.push: Push manifest list for multi-arch images -.PHONY: image.manifest.push -image.manifest.push: export DOCKER_CLI_EXPERIMENTAL := enabled -image.manifest.push: image.verify go.build.verify \ -$(addprefix image.manifest.push., $(addprefix $(IMAGE_PLAT)., $(IMAGES))) - -## image.manifest.push.%: Push manifest list for multi-arch images for a specific platform -.PHONY: image.manifest.push.% -image.manifest.push.%: image.push.% image.manifest.remove.% - @echo "===========> Pushing manifest $(IMAGE) $(VERSION) to $(REGISTRY_PREFIX) and then remove the local manifest list" - @$(DOCKER) manifest create $(REGISTRY_PREFIX)/$(IMAGE):$(VERSION) \ - $(REGISTRY_PREFIX)/$(IMAGE)-$(ARCH):$(VERSION) - @$(DOCKER) manifest annotate $(REGISTRY_PREFIX)/$(IMAGE):$(VERSION) \ - $(REGISTRY_PREFIX)/$(IMAGE)-$(ARCH):$(VERSION) \ - --os $(OS) --arch ${ARCH} - @$(DOCKER) manifest push --purge $(REGISTRY_PREFIX)/$(IMAGE):$(VERSION) - -# Docker cli has a bug: https://github.com/docker/cli/issues/954 -# If you find your manifests were not updated, -# Please manually delete them in $HOME/.docker/manifests/ -# and re-run. -## image.manifest.remove.%: Remove local manifest list -.PHONY: image.manifest.remove.% -image.manifest.remove.%: - @rm -rf ${HOME}/.docker/manifests/docker.io_$(REGISTRY_PREFIX)_$(IMAGE)-$(VERSION) - -## image.manifest.push.multiarch: Push manifest list for multi-arch images for all platforms -.PHONY: image.manifest.push.multiarch -image.manifest.push.multiarch: image.push.multiarch $(addprefix image.manifest.push.multiarch., $(IMAGES)) - -## image.manifest.push.multiarch.%: Push manifest list for multi-arch images for all platforms for a specific image -.PHONY: image.manifest.push.multiarch.% -image.manifest.push.multiarch.%: - @echo "===========> Pushing manifest $* $(VERSION) to $(REGISTRY_PREFIX) and then remove the local manifest list" - REGISTRY_PREFIX=$(REGISTRY_PREFIX) PLATFORMS="$(PLATFORMS)" IMAGE=$* VERSION=$(VERSION) DOCKER_CLI_EXPERIMENTAL=enabled \ - $(ROOT_DIR)/build/lib/create-manifest.sh - -## image.help: Print help for image targets -.PHONY: image.help -image.help: scripts/make-rules/image.mk - $(call smallhelp) \ No newline at end of file diff --git a/scripts/make-rules/release.mk b/scripts/make-rules/release.mk deleted file mode 100644 index 68bf058981..0000000000 --- a/scripts/make-rules/release.mk +++ /dev/null @@ -1,42 +0,0 @@ -# Copyright © 2023 OpenIMSDK. -# -# 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. - -# ============================================================================== -# Makefile helper functions for release -# Versions are used after merging -# - -## release.run: release the project -.PHONY: release.run -release.run: release.verify release.ensure-tag - @scripts/release.sh - -## release.verify: Check if a tool is installed and install it -.PHONY: release.verify -release.verify: tools.verify.git-chglog tools.verify.github-release tools.verify.coscmd tools.verify.coscli - -## release.tag: release the project -.PHONY: release.tag -release.tag: tools.verify.gsemver release.ensure-tag - @git push origin `git describe --tags --abbrev=0` - -## release.ensure-tag: ensure tag -.PHONY: release.ensure-tag -release.ensure-tag: tools.verify.gsemver - @scripts/ensure-tag.sh - -## release.help: Display help information about the release package -.PHONY: release.help -release.help: scripts/make-rules/release.mk - $(call smallhelp) diff --git a/scripts/make-rules/swagger.mk b/scripts/make-rules/swagger.mk deleted file mode 100644 index 991de43c63..0000000000 --- a/scripts/make-rules/swagger.mk +++ /dev/null @@ -1,19 +0,0 @@ -# ============================================================================== -# Makefile helper functions for swagger -# - -## swagger.run: Generate swagger document. -.PHONY: swagger.run -swagger.run: tools.verify.swagger - @echo "===========> Generating swagger API docs" - @$(TOOLS_DIR)/swagger generate spec --scan-models -w $(ROOT_DIR)/cmd/genswaggertypedocs -o $(ROOT_DIR)/api/swagger/swagger.yaml - -## swagger.serve: Serve swagger spec and docs. -.PHONY: swagger.serve -swagger.serve: tools.verify.swagger - @$(TOOLS_DIR)/swagger serve -F=redoc --no-open --port 36666 $(ROOT_DIR)/api/swagger/swagger.yaml - -## swagger.help: Display help information about the release package -.PHONY: swagger.help -swagger.help: scripts/make-rules/swagger.mk - $(call smallhelp) \ No newline at end of file diff --git a/scripts/make-rules/tools.mk b/scripts/make-rules/tools.mk deleted file mode 100644 index 5335d094d9..0000000000 --- a/scripts/make-rules/tools.mk +++ /dev/null @@ -1,280 +0,0 @@ -# Copyright © 2023 OpenIMSDK. -# -# 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. - -# ============================================================================== -# Makefile helper functions for tools(https://github.com/avelino/awesome-go) -> DIR: {TOOT_DIR}/tools | (go >= 1.19) -# Why download to the tools directory, thinking we might often switch Go versions using gvm. -# - -# openim build use BUILD_TOOLS -BUILD_TOOLS ?= golangci-lint goimports addlicense deepcopy-gen conversion-gen ginkgo go-junit-report go-gitlint -# Code analysis tools -ANALYSIS_TOOLS = golangci-lint goimports golines go-callvis kube-score -# Code generation tools -GENERATION_TOOLS = deepcopy-gen conversion-gen protoc-gen-go cfssl rts codegen -# Testing tools -TEST_TOOLS = ginkgo go-junit-report gotests -# tenxun cos tools -COS_TOOLS = coscli coscmd -# Version control tools -VERSION_CONTROL_TOOLS = addlicense go-gitlint git-chglog github-release gsemver -# Utility tools -UTILITY_TOOLS = go-mod-outdated mockgen gothanks richgo kubeconform -# All tools -ALL_TOOLS ?= $(ANALYSIS_TOOLS) $(GENERATION_TOOLS) $(TEST_TOOLS) $(VERSION_CONTROL_TOOLS) $(UTILITY_TOOLS) $(COS_TOOLS) - -## tools.install: Install a must tools -.PHONY: tools.install -tools.install: $(addprefix tools.verify., $(BUILD_TOOLS)) - -## tools.install-all: Install all tools -.PHONY: tools.install-all -tools.install-all: $(addprefix tools.install-all., $(ALL_TOOLS)) - -## tools.install.%: Install a single tool in $GOBIN/ -.PHONY: tools.install.% -tools.install.%: - @echo "===========> Installing $,The default installation path is $(GOBIN)/$*" - @$(MAKE) install.$* - -## tools.install-all.%: Parallelism install a single tool in ./tools/* -.PHONY: tools.install-all.% -tools.install-all.%: - @echo "===========> Installing $,The default installation path is $(TOOLS_DIR)/$*" - @$(MAKE) -j $(nproc) install.$* - -## tools.verify.%: Check if a tool is installed and install it -.PHONY: tools.verify.% -tools.verify.%: - @echo "===========> Verifying $* is installed" - @if [ ! -f $(TOOLS_DIR)/$* ]; then GOBIN=$(TOOLS_DIR) $(MAKE) tools.install.$*; fi - @echo "===========> $* is install in $(TOOLS_DIR)/$*" - -## install.golangci-lint: Install golangci-lint -.PHONY: install.golangci-lint -install.golangci-lint: - @$(GO) install github.com/golangci/golangci-lint/cmd/golangci-lint@$(GOLANGCI_LINT_VERSION) - -## install.goimports: Install goimports, used to format go source files -.PHONY: install.goimports -install.goimports: - @$(GO) install golang.org/x/tools/cmd/goimports@$(GOIMPORTS_VERSION) - -## install.addlicense: Install addlicense, used to add license header to source files -.PHONY: install.addlicense -install.addlicense: - @$(GO) install github.com/google/addlicense@$(ADDLICENSE_VERSION) - -## install.deepcopy-gen: Install deepcopy-gen, used to generate deep copy functions -.PHONY: install.deepcopy-gen -install.deepcopy-gen: - @$(GO) install k8s.io/code-generator/cmd/deepcopy-gen@$(DEEPCOPY_GEN_VERSION) - -## install.conversion-gen: Install conversion-gen, used to generate conversion functions -.PHONY: install.conversion-gen -install.conversion-gen: - @$(GO) install k8s.io/code-generator/cmd/conversion-gen@$(CONVERSION_GEN_VERSION) - -## install.ginkgo: Install ginkgo to run a single test or set of tests -.PHONY: install.ginkgo -install.ginkgo: - @$(GO) install github.com/onsi/ginkgo/ginkgo@$(GINKGO_VERSION) - -## install.go-gitlint: Install go-gitlint, used to check git commit message -.PHONY: install.go-gitlint -install.go-gitlint: - @$(GO) install github.com/marmotedu/go-gitlint/cmd/go-gitlint@$(GO_GITLINT_VERSION) - -## install.go-junit-report: Install go-junit-report, used to convert go test output to junit xml -.PHONY: install.go-junit-report -install.go-junit-report: - @$(GO) install github.com/jstemmer/go-junit-report@$(GO_JUNIT_REPORT_VERSION) - -## install.gotests: Install gotests, used to generate go tests -.PHONY: install.gotests -install.gotests: - @$(GO) install github.com/cweill/gotests/gotests@$(GO_TESTS_VERSION) - -## install.kafkactl: Install kafkactl command line tool. -.PHONY: install.kafkactl -install.kafkactl: - @$(GO) install github.com/deviceinsight/kafkactl@$(KAFKACTL_VERSION) - -## install.go-apidiff: Install go-apidiff, used to check api changes -.PHONY: install.go-apidiff -install.go-apidiff: - @$(GO) install github.com/joelanford/go-apidiff@$(GO_APIDIFF_VERSION) - -## install.swagger: Install swagger, used to generate swagger documentation -.PHONY: install.swagger -install.swagger: - @$(GO) install github.com/go-swagger/go-swagger/cmd/swagger@$(SWAGGER_VERSION) - -# ============================================================================== -# Tools that might be used include go gvm -# - -## install.gotestsum: Install gotestsum, used to run go tests -.PHONY: install.gotestsum -install.gotestsum: - @$(GO) install gotest.tools/gotestsum@$(GOTESTSUM_VERSION) - -## install.kube-score: Install kube-score, used to check kubernetes yaml files -.PHONY: install.kube-score -install.kube-score: - @$(GO) install github.com/zegl/kube-score/cmd/kube-score@$(KUBE_SCORE_VERSION) - -## install.kubeconform: Install kubeconform, used to check kubernetes yaml files -.PHONY: install.kubeconform -install.kubeconform: - @$(GO) install github.com/yannh/kubeconform/cmd/kubeconform@$(KUBECONFORM_VERSION) - -## install.gsemver: Install gsemver, used to generate semver -.PHONY: install.gsemver -install.gsemver: - @$(GO) install github.com/arnaud-deprez/gsemver@$(GSEMVER_VERSION) - -## install.git-chglog: Install git-chglog, used to generate changelog -.PHONY: install.git-chglog -install.git-chglog: - @$(GO) install github.com/git-chglog/git-chglog/cmd/git-chglog@$(GIT_CHGLOG_VERSION) - -## install.ko: Install ko, used to build go program into container images -.PHONY: install.ko -install.ko: - @$(GO) install github.com/google/ko@$(KO_VERSION) - -## install.github-release: Install github-release, used to create github release -.PHONY: install.github-release -install.github-release: - @$(GO) install github.com/github-release/github-release@$(GITHUB_RELEASE_VERSION) - -## install.coscli: Install coscli, used to upload files to cos -# example: ./coscli cp/sync -r /home/off-line/docker-off-line/ cos://openim-1306374445/openim/image/amd/off-line/off-line/ -e cos.ap-guangzhou.myqcloud.com -# https://cloud.tencent.com/document/product/436/71763 -# amd64 -.PHONY: install.coscli -install.coscli: - @wget -q https://github.com/tencentyun/coscli/releases/download/$(COSCLI_VERSION)/coscli-linux -O ${TOOLS_DIR}/coscli - @chmod +x ${TOOLS_DIR}/coscli - -## install.coscmd: Install coscmd, used to upload files to cos -.PHONY: install.coscmd -install.coscmd: - @if which pip &>/dev/null; then pip install coscmd; else pip3 install coscmd; fi - -## install.minio: Install minio, used to upload files to minio -.PHONY: install.minio -install.minio: - @$(GO) install github.com/minio/minio@$(MINIO_VERSION) - -## install.delve: Install delve, used to debug go program -.PHONY: install.delve -install.delve: - @$(GO) install github.com/go-delve/delve/cmd/dlv@$(DELVE_VERSION) - -## install.air: Install air, used to hot reload go program -.PHONY: install.air -install.air: - @$(GO) install github.com/cosmtrek/air@$(AIR_VERSION) - -## install.gvm: Install gvm, gvm is a Go version manager, built on top of the official go tool. -.PHONY: install.gvm -install.gvm: - @echo "===========> Installing gvm, The default installation path is ~/.gvm/scripts/gvm" - @bash < <(curl -s -S -L https://raw.githubusercontent.com/moovweb/gvm/master/binscripts/gvm-installer) - @source /root/.gvm/scripts/gvm - -## install.golines: Install golines, used to format long lines -.PHONY: install.golines -install.golines: - @$(GO) install github.com/segmentio/golines@$(GOLINES_VERSION) - -## install.go-mod-outdated: Install go-mod-outdated, used to check outdated dependencies -.PHONY: install.go-mod-outdated -install.go-mod-outdated: - @$(GO) install github.com/psampaz/go-mod-outdated@$(GO_MOD_OUTDATED_VERSION) - -## install.mockgen: Install mockgen, used to generate mock functions -.PHONY: install.mockgen -install.mockgen: - @$(GO) install github.com/golang/mock/mockgen@$(MOCKGEN_VERSION) - -## install.wire: Install wire, used to generate wire files -.PHONY: install.wire -install.wire: - @$(GO) install github.com/google/wire/cmd/wire@$(WIRE_VERSION) - - -## install.protoc-gen-go: Install protoc-gen-go, used to generate go source files from protobuf files -.PHONY: install.protoc-gen-go -install.protoc-gen-go: - @$(GO) install github.com/golang/protobuf/protoc-gen-go@$(PROTOC_GEN_GO_VERSION) - -## install.cfssl: Install cfssl, used to generate certificates -.PHONY: install.cfssl -install.cfssl: - @$(ROOT_DIR)/scripts/install/install.sh openim::install::install_cfssl - -## install.depth: Install depth, used to check dependency tree -.PHONY: install.depth -install.depth: - @$(GO) install github.com/KyleBanks/depth/cmd/depth@$(DEPTH_VERSION) - -## install.go-callvis: Install go-callvis, used to visualize call graph -.PHONY: install.go-callvis -install.go-callvis: - @$(GO) install github.com/ofabry/go-callvis@$(GO_CALLVIS_VERSION) - -## install.misspell: Install misspell -.PHONY: install.misspell -install.misspell: - @$(GO) install github.com/client9/misspell/cmd/misspell@$(MISSPELL_VERSION) - -## install.gothanks: Install gothanks, used to thank go dependencies -.PHONY: install.gothanks -install.gothanks: - @$(GO) install github.com/psampaz/gothanks@$(GOTHANKS_VERSION) - -## install.richgo: Install richgo -.PHONY: install.richgo -install.richgo: - @$(GO) install github.com/kyoh86/richgo@$(RICHGO_VERSION) - -## install.rts: Install rts -.PHONY: install.rts -install.rts: - @$(GO) install github.com/galeone/rts/cmd/rts@$(RTS_VERSION) - -# ================= kubecub openim tools ========================================= -# https://github.com/kubecub -## install.typecheck: Install kubecub typecheck, checks for go code -.PHONY: install.typecheck -install.typecheck: - @$(GO) install github.com/kubecub/typecheck@$(TYPECHECK_VERSION) - -## install.comment-lang-detector: Install kubecub comment-lang-detector, checks for go code comment language -.PHONY: install.comment-lang-detector -install.comment-lang-detector: - @$(GO) install github.com/kubecub/comment-lang-detector/cmd/cld@$(COMMENT_LANG_DETECTOR_VERSION) - -## install.standardizer: Install kubecub standardizer, checks for go code standardization -.PHONY: install.standardizer -install.standardizer: - @$(GO) install github.com/kubecub/standardizer@$(STANDARDIZER_VERSION) - -## tools.help: Display help information about the tools package -.PHONY: tools.help -tools.help: scripts/make-rules/tools.mk - $(call smallhelp) \ No newline at end of file diff --git a/scripts/release.sh b/scripts/release.sh deleted file mode 100755 index eb8b04359f..0000000000 --- a/scripts/release.sh +++ /dev/null @@ -1,150 +0,0 @@ -#!/usr/bin/env bash -# 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. - -# Description: -# This script automates the process of building and releasing OpenIM, -# including tasks like setting up the environment, verifying prerequisites, -# building commands, packaging tarballs, uploading tarballs, creating GitHub -# releases, and generating changelogs. -# -# Usage: -# ./scripts/release.sh [options] -# Options include: -# -h, --help : Show help message -# -se, --setup-env : Execute setup environment -# -vp, --verify-prereqs : Execute prerequisites verification -# -bc, --build-command : Execute build command -# -bi, --build-image : Execute build image (default: not executed) -# -pt, --package-tarballs : Execute package tarballs -# -ut, --upload-tarballs : Execute upload tarballs -# -gr, --github-release : Execute GitHub release -# -gc, --generate-changelog: Execute generate changelog -# -# This script can also be executed via the 'make release' command as an alternative. -# -# Dependencies: -# This script depends on external scripts found in the 'scripts' directory and -# assumes the presence of necessary tools and permissions for building and -# releasing software. -# -# Note: -# The script uses standard bash script practices with error handling, -# and it defaults to executing all steps if no specific option is provided. -# -# Build a OpenIM release. This will build the binaries, create the Docker -# images and other build artifacts. -# Build a OpenIM release. This script supports various flags for flexible execution control. - - - - -OPENIM_ROOT=$(dirname "${BASH_SOURCE[0]}")/.. -source "${OPENIM_ROOT}/scripts/common.sh" -source "${OPENIM_ROOT}/scripts/lib/release.sh" - -OPENIM_RELEASE_RUN_TESTS=${OPENIM_RELEASE_RUN_TESTS-y} - -# Function to show help message -show_help() { - echo "Usage: $(basename $0) [options]" - echo "Options:" - echo " -h, --help Show this help message" - echo " -se, --setup-env Execute setup environment" - echo " -vp, --verify-prereqs Execute prerequisites verification" - echo " -bc, --build-command Execute build command" - echo " -bi, --build-image Execute build image (default: not executed)" - echo " -pt, --package-tarballs Execute package tarballs" - echo " -ut, --upload-tarballs Execute upload tarballs" - echo " -gr, --github-release Execute GitHub release" - echo " -gc, --generate-changelog Execute generate changelog" -} - -# Initialize all actions to false -perform_setup_env=false -perform_verify_prereqs=false -perform_build_command=false -perform_build_image=false # New flag for build image -perform_package_tarballs=false -perform_upload_tarballs=false -perform_github_release=false -perform_generate_changelog=false - -# Process command-line arguments -while getopts "hsevpbciptutgrgc-" opt; do - case "${opt}" in - h) show_help; exit 0 ;; - se) perform_setup_env=true ;; - vp) perform_verify_prereqs=true ;; - bc) perform_build_command=true ;; - bi) perform_build_image=true ;; # Handling new option - pt) perform_package_tarballs=true ;; - ut) perform_upload_tarballs=true ;; - gr) perform_github_release=true ;; - gc) perform_generate_changelog=true ;; - --) case "${OPTARG}" in - help) show_help; exit 0 ;; - setup-env) perform_setup_env=true ;; - verify-prereqs) perform_verify_prereqs=true ;; - build-command) perform_build_command=true ;; - build-image) perform_build_image=true ;; # Handling new long option - package-tarballs) perform_package_tarballs=true ;; - upload-tarballs) perform_upload_tarballs=true ;; - github-release) perform_github_release=true ;; - generate-changelog) perform_generate_changelog=true ;; - *) echo "Invalid option: --${OPTARG}"; show_help; exit 1 ;; - esac ;; - *) show_help; exit 1 ;; - esac -done - -# Enable all actions by default if no options are provided -if [ "$#" -eq 0 ]; then - perform_setup_env=true - perform_verify_prereqs=true - perform_build_command=true - perform_package_tarballs=true - perform_upload_tarballs=true - perform_github_release=true - perform_generate_changelog=true - # TODO: Not enabling build_image by default - # perform_build_image=true -fi - -# Function to perform actions -perform_action() { - local flag=$1 - local message=$2 - local command=$3 - - if [ "$flag" == true ]; then - openim::log::info "## $message..." - if ! eval "$command"; then - openim::log::errexit "Error in $message" - fi - fi -} - -echo "Starting script execution..." - -perform_action $perform_setup_env "Setting up environment" "openim::golang::setup_env" -perform_action $perform_verify_prereqs "Verifying prerequisites" "openim::build::verify_prereqs && openim::release::verify_prereqs" -perform_action $perform_build_command "Executing build command" "openim::build::build_command" -perform_action $perform_build_image "Building image" "openim::build::build_image" -perform_action $perform_package_tarballs "Packaging tarballs" "openim::release::package_tarballs" -perform_action $perform_upload_tarballs "Uploading tarballs" "openim::release::upload_tarballs" -perform_action $perform_github_release "Creating GitHub release" "openim::release::github_release" -perform_action $perform_generate_changelog "Generating changelog" "openim::release::generate_changelog" - -openim::log::success "OpenIM Relase Script Execution Completed." diff --git a/scripts/run-in-gopath.sh b/scripts/run-in-gopath.sh deleted file mode 100755 index 6d8b7943be..0000000000 --- a/scripts/run-in-gopath.sh +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/env bash -# 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. - - -# This script sets up a temporary openim GOPATH and runs an arbitrary -# command under it. Go tooling requires that the current directory be under -# GOPATH or else it fails to find some things, such as the vendor directory for -# the project. -# Usage: `scripts/run-in-gopath.sh `. - -OPENIM_ROOT=$(dirname "${BASH_SOURCE[0]}")/.. -source "${OPENIM_ROOT}/scripts/lib/init.sh" - -# This sets up a clean GOPATH and makes sure we are currently in it. -openim::golang::setup_env - -# Run the user-provided command. -"${@}" diff --git a/scripts/start-all.sh b/scripts/start-all.sh deleted file mode 100755 index 6f4a6c5748..0000000000 --- a/scripts/start-all.sh +++ /dev/null @@ -1,109 +0,0 @@ -#!/usr/bin/env bash -# 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. - -#FIXME This script is the startup script for multiple servers. -#FIXME The full names of the shell scripts that need to be started are placed in the `need_to_start_server_shell` array. - -OPENIM_ROOT=$(dirname "${BASH_SOURCE[0]}")/.. -source "${OPENIM_ROOT}/scripts/install/common.sh" - -# Function to execute the scripts. -function execute_start_scripts() { - for script_path in "${OPENIM_SERVER_SCRIPT_START_LIST[@]}"; do - # Extract the script name without extension for argument generation. - script_name_with_prefix=$(basename "$script_path" .sh) - - # Remove the "openim-" prefix. - script_name=${script_name_with_prefix#openim-} - - # Construct the argument based on the script name. - arg="openim::${script_name}::start" - - # Check if the script file exists and is executable. - if [[ -x "$script_path" ]]; then - openim::log::colorless "Starting script: ${script_path##*/}" # Log the script name. - # Execute the script with the constructed argument. - result=$("$script_path" "$arg") - if [[ $? -ne 0 ]]; then - openim::log::error "Start script: ${script_path##*/} failed" - openim::log::error "$result" - return 1 - fi - - else - openim::log::errexit "Script ${script_path##*/} is missing or not executable." - return 1 - fi - done -} - -if openim::util::is_running_in_container; then - exec >> ${DOCKER_LOG_FILE} 2>&1 -fi - -openim::golang::check_openim_binaries -if [[ $? -ne 0 ]]; then - openim::log::error "OpenIM binaries are not found. Please run 'make build' to build binaries." - "${OPENIM_ROOT}"/scripts/build-all-service.sh -fi - -"${OPENIM_ROOT}"/scripts/init-config.sh --skip - -#openim::log::print_blue "Execute the following script in sequence: ${OPENIM_SERVER_SCRIPTARIES[@]}" - -# TODO Prelaunch tools, simple for now, can abstract functions later -TOOLS_START_SCRIPTS_PATH=${START_SCRIPTS_PATH}/openim-tools.sh - -openim::log::status "Start the pre-start tools:" - -# if ! ${TOOLS_START_SCRIPTS_PATH} openim::tools::pre-start; then -# openim::log::error "Start the pre-start tools, aborting!" -# exit 1 -# fi - -openim::log::colorless "pre-start has been successfully completed!" - -result=$("${OPENIM_ROOT}"/scripts/stop-all.sh) -if [[ $? -ne 0 ]]; then - openim::log::error "View the error logs from this startup. ${LOG_FILE} \n" - openim::log::error "Some programs have not exited; the start process is aborted .\n $result" - exit 1 -fi - -openim::log::status "Start the OpenIM startup scripts: " -execute_start_scripts -openim::log::status "OpenIM startup scripts have been successfully completed!" - -sleep 2 - -result=$(. $(dirname ${BASH_SOURCE})/install/openim-msgtransfer.sh openim::msgtransfer::check) -if [[ $? -ne 0 ]]; then - openim::log::error "The OpenIM services may fail to start.\n $result" - exit 1 -fi - -result=$(openim::util::check_process_names ${OPENIM_ALL_SERVICE_LIBRARIES_NO_TRANSFER[@]}) -if [[ $? -ne 0 ]]; then - openim::log::error "The OpenIM services may fail to start.\n $result" - exit 1 -fi - -openim::log::status "Start the post-start tools:" -# ${TOOLS_START_SCRIPTS_PATH} openim::tools::post-start -openim::log::status "post-start has been successfully completed!" -openim::util::find_ports_for_all_services ${OPENIM_ALL_SERVICE_LIBRARIES_NO_TRANSFER[@]} -openim::util::find_ports_for_all_services ${OPENIM_MSGTRANSFER_BINARY[@]} - -openim::log::success "All OpenIM services have been successfully started!" \ No newline at end of file diff --git a/scripts/stop-all.sh b/scripts/stop-all.sh deleted file mode 100755 index b2572f7d5e..0000000000 --- a/scripts/stop-all.sh +++ /dev/null @@ -1,60 +0,0 @@ -#!/usr/bin/env bash -# 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. - -# This script is stop all openim service -# -# Usage: `scripts/stop.sh`. -# Encapsulated as: `make stop`. - - - - - -OPENIM_ROOT=$(dirname "${BASH_SOURCE[0]}")/.. - -source "${OPENIM_ROOT}/scripts/install/common.sh" - -openim::log::status "Begin to stop all openim service" - -openim::log::status "Stop all processes in the path ${OPENIM_OUTPUT_HOSTBIN}" - -openim::util::stop_services_with_name "${OPENIM_OUTPUT_HOSTBIN}" -# todo OPENIM_ALL_SERVICE_LIBRARIES - - - - -max_retries=15 -attempt=0 - -while [[ $attempt -lt $max_retries ]] -do - result=$(openim::util::check_process_names_for_stop) - - if [[ $? -ne 0 ]]; then - if [[ $attempt -ne 0 ]] ; then - echo "+++ cat openim log file >>> ${LOG_FILE} " $attempt - openim::log::error "stop process failed. continue waiting\n" "${result}" - fi - sleep 1 - ((attempt++)) - else - openim::log::success " All openim processes to be stopped" - exit 0 - fi -done - -openim::log::error "openim processes stopped failed" -exit 1 diff --git a/scripts/update-generated-docs.sh b/scripts/update-generated-docs.sh deleted file mode 100755 index 4c1fbfccc6..0000000000 --- a/scripts/update-generated-docs.sh +++ /dev/null @@ -1,45 +0,0 @@ -#!/usr/bin/env bash -# 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. - - -# This file is not intended to be run automatically. It is meant to be run -# immediately before exporting docs. We do not want to check these documents in -# by default. - -OPENIM_ROOT=$(dirname "${BASH_SOURCE[0]}")/.. -source "${OPENIM_ROOT}/scripts/lib/init.sh" - -openim::golang::setup_env - -BINS=( - gendocs - genopenimdocs - genman - genyaml -) -make -C "${OPENIM_ROOT}" BINS="${BINS[*]}" - -openim::util::ensure-temp-dir - -openim::util::gen-docs "${OPENIM_TEMP}" - -# remove all of the old docs -openim::util::remove-gen-docs - -# Copy fresh docs into the repo. -# the shopt is so that we get docs/.generated_docs from the glob. -shopt -s dotglob -cp -af "${OPENIM_TEMP}"/* "${OPENIM_ROOT}" -shopt -u dotglob diff --git a/scripts/update-yamlfmt.sh b/scripts/update-yamlfmt.sh deleted file mode 100755 index 8de0cc84c0..0000000000 --- a/scripts/update-yamlfmt.sh +++ /dev/null @@ -1,38 +0,0 @@ -#!/usr/bin/env bash -# 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. - -OPENIM_ROOT=$(dirname "${BASH_SOURCE[0]}")/.. -source "${OPENIM_ROOT}/scripts/lib/init.sh" - -openim::golang::setup_env - -cd "${OPENIM_ROOT}" - -find_files() { - find . -not \( \ - \( \ - -wholename './output' \ - -o -wholename './.git' \ - -o -wholename './_output' \ - -o -wholename './_gopath' \ - -o -wholename './release' \ - -o -wholename './target' \ - -o -wholename '*/vendor/*' \ - \) -prune \ - \) -name 'OWNERS*' -} - -export GO111MODULE=on -find_files | xargs go run tools/yamlfmt/yamlfmt.go \ No newline at end of file diff --git a/scripts/verify-pkg-names.sh b/scripts/verify-pkg-names.sh deleted file mode 100755 index be1acd015d..0000000000 --- a/scripts/verify-pkg-names.sh +++ /dev/null @@ -1,32 +0,0 @@ -#!/usr/bin/env bash -# 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. - - -# This script verifies whether codes follow golang convention. -# Usage: `scripts/verify-pkg-names.sh`. - - -OPENIM_ROOT=$(dirname "${BASH_SOURCE[0]}")/.. -source "${OPENIM_ROOT}/scripts/lib/init.sh" - -openim::golang::verify_go_version - -cd "${OPENIM_ROOT}" -if git --no-pager grep -E $'^(import |\t)[a-z]+[A-Z_][a-zA-Z]* "[^"]+"$' -- '**/*.go' ':(exclude)vendor/*' ':(exclude)**/*.pb.go'; then - openim::log::error "Some package aliases break go conventions." - echo "To fix these errors, do not use capitalized or underlined characters" - echo "in pkg aliases. Refer to https://blog.golang.org/package-names for more info." - exit 1 -fi diff --git a/scripts/verify-shellcheck.sh b/scripts/verify-shellcheck.sh deleted file mode 100755 index 3e56038dde..0000000000 --- a/scripts/verify-shellcheck.sh +++ /dev/null @@ -1,188 +0,0 @@ -#!/usr/bin/env bash -# 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. - - -# This script lints each shell script by `shellcheck`. -# Usage: `scripts/verify-shellcheck.sh`. - -OPENIM_ROOT=$(dirname "${BASH_SOURCE[0]}")/.. -source "${OPENIM_ROOT}/scripts/lib/init.sh" - -# allow overriding docker cli, which should work fine for this script -DOCKER="${DOCKER:-docker}" - -# required version for this script, if not installed on the host we will -# use the official docker image instead. keep this in sync with SHELLCHECK_IMAGE -SHELLCHECK_VERSION="0.8.0" -SHELLCHECK_IMAGE="docker.io/koalaman/shellcheck-alpine:v0.8.0@sha256:f42fde76d2d14a645a848826e54a4d650150e151d9c81057c898da89a82c8a56" - -# disabled lints -disabled=( - # this lint disallows non-constant source, which we use extensively without - # any known bugs - 1090 - # this lint warns when shellcheck cannot find a sourced file - # this wouldn't be a bad idea to warn on, but it fails on lots of path - # dependent sourcing, so just disable enforcing it - 1091 - # this lint prefers command -v to which, they are not the same - 2230 - # Error SC2155 indicates that you should separate variable declaration and assignment to avoid masking the return value of the command. - # In Bash scripts, when you declare and assign a local variable at the same time a command is executed, you only get the output of the command, but not the exit status (return value) of the command. # - 2155 - # ShellCheck issues SC2086 warnings when you refer to a variable in a script but don't put it in double quotes.This can lead to unexpected behavior when scripts encounter Spaces, - # newlines, and wildcards in file names or other data. - 2086 - 2206 - - # TODO: 需要修复,然后开启 - 2034 - 2048 - 2148 - 2059 - 2214 - 2145 - 2128 - 2550 - 2046 - 2181 - 1102 - 2045 - 2068 - 2145 - 2207 - 2231 - 2013 - 2154 - 2120 - 1083 - 2001 - 2012 - 2016 - 2164 - 2223 - 2166 - 2119 - 2162 - 2295 - 2002 - 2004 - 2202 - 2178 - 2064 - 2260 - 2261 - 2043 - 2178 - 2044 - 2153 -) -# comma separate for passing to shellcheck -join_by() { - local IFS="$1"; - shift; - echo "$*"; -} -SHELLCHECK_DISABLED="$(join_by , "${disabled[@]}")" -readonly SHELLCHECK_DISABLED - -# ensure we're linting the k8s source tree -cd "${OPENIM_ROOT}" - -# Find all shell scripts excluding: -# - Anything git-ignored - No need to lint untracked files. -# - ./_* - No need to lint output directories. -# - ./.git/* - Ignore anything in the git object store. -# - ./vendor* - Vendored code should be fixed upstream instead. -# - ./third_party/*, but re-include ./third_party/forked/* - only code we -# forked should be linted and fixed. -all_shell_scripts=() -while IFS=$'\n' read -r script; -do git check-ignore -q "$script" || all_shell_scripts+=("$script"); - done < <(find . -name "*.sh" \ - -not \( \ - -path ./_\* -o \ - -path ./.git\* -o \ - -path ./Godeps\* -o \ - -path ./_output\* -o \ - -path ./components\* -o \ - -path ./logs\* -o \ - -path ./vendor\* -o \ - \( -path ./third_party\* -a -not -path ./third_party/forked\* \) \ -\) -print 2>/dev/null) - -# detect if the host machine has the required shellcheck version installed -# if so, we will use that instead. -HAVE_SHELLCHECK=false -if which shellcheck &>/dev/null; then - detected_version="$(shellcheck --version | grep 'version: .*')" - if [[ "${detected_version}" = "version: ${SHELLCHECK_VERSION}" ]]; then - HAVE_SHELLCHECK=true - fi -fi - -# if KUBE_JUNIT_REPORT_DIR is set, disable colorized output. -# Colorized output causes malformed XML in the JUNIT report. -SHELLCHECK_COLORIZED_OUTPUT="auto" -if [[ -n "${KUBE_JUNIT_REPORT_DIR:-}" ]]; then - SHELLCHECK_COLORIZED_OUTPUT="never" -fi - -# common arguments we'll pass to shellcheck -SHELLCHECK_OPTIONS=( - # allow following sourced files that are not specified in the command, - # we need this because we specify one file at a time in order to trivially - # detect which files are failing - "--external-sources" - # include our disabled lints - "--exclude=${SHELLCHECK_DISABLED}" - # set colorized output - "--color=${SHELLCHECK_COLORIZED_OUTPUT}" -) - -# tell the user which we've selected and lint all scripts -# The shellcheck errors are printed to stdout by default, hence they need to be redirected -# to stderr in order to be well parsed for Junit representation by juLog function -res=0 -if ${HAVE_SHELLCHECK}; then - openim::log::info "Using host shellcheck ${SHELLCHECK_VERSION} binary." - shellcheck "${SHELLCHECK_OPTIONS[@]}" "${all_shell_scripts[@]}" >&2 || res=$? -else - openim::log::info "Using shellcheck ${SHELLCHECK_VERSION} docker image." - "${DOCKER}" run \ - --rm -v "${OPENIM_ROOT}:${OPENIM_ROOT}" -w "${OPENIM_ROOT}" \ - "${SHELLCHECK_IMAGE}" \ - shellcheck "${SHELLCHECK_OPTIONS[@]}" "${all_shell_scripts[@]}" >&2 || res=$? -fi - -# print a message based on the result -if [ $res -eq 0 ]; then - echo 'Congratulations! All shell files are passing lint :-)' -else - { - echo - echo 'Please review the above warnings. You can test via "./scripts/verify-shellcheck.sh"' - echo 'If the above warnings do not make sense, you can exempt this warning with a comment' - echo ' (if your reviewer is okay with it).' - echo 'In general please prefer to fix the error, we have already disabled specific lints' - echo ' that the project chooses to ignore.' - echo 'See: https://github.com/koalaman/shellcheck/wiki/Ignore#ignoring-one-specific-instance-in-a-file' - echo - } >&2 - exit 1 -fi - -# preserve the result -exit $res diff --git a/scripts/verify-spelling.sh b/scripts/verify-spelling.sh deleted file mode 100755 index c718c1ad15..0000000000 --- a/scripts/verify-spelling.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/env bash -# 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. - -# This script checks commonly misspelled English words in all files in the -# working directory by client9/misspell package. -# Usage: `scripts/verify-spelling.sh`. - -OPENIM_ROOT=$(dirname "${BASH_SOURCE[0]}")/.. -export OPENIM_ROOT -source "${OPENIM_ROOT}/scripts/lib/init.sh" - -# Spell checking -# All the skipping files are defined in scripts/.spelling_failures -skipping_file="${OPENIM_ROOT}/scripts/.spelling_failures" -failing_packages=$(sed "s| | -e |g" "${skipping_file}") -git ls-files | grep -v -e "${failing_packages}" | xargs "$OPENIM_ROOT/_output/tools/misspell" -i "Creater,creater,ect" -error -o stderr diff --git a/scripts/verify-standardizer.sh b/scripts/verify-standardizer.sh deleted file mode 100755 index 08a13b9a26..0000000000 --- a/scripts/verify-standardizer.sh +++ /dev/null @@ -1,33 +0,0 @@ -#!/usr/bin/env bash -# 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. - -# This script does a fast type check of script srnetes code for all platforms. -# Usage: `scripts/verify-standardizer.sh`. - -OPENIM_ROOT=$(dirname "${BASH_SOURCE[0]}")/.. -source "${OPENIM_ROOT}/scripts/lib/init.sh" - -openim::golang::verify_go_version - -cd "${OPENIM_ROOT}" -ret=0 -scripts/run-in-gopath.sh \ -make tools.verify.standardizer -${OPENIM_ROOT}/_output/tools/standardizer || ret=$? -if [[ $ret -ne 0 ]]; then - openim::log::error "Failed to check the directory name or file name. Your name may not meet the specification. Please check the configuration file and the directory or file name." >&2 - openim::log::error "Please see https://github.com/kubecub/standardizer for more information." >&2 - exit 1 -fi diff --git a/scripts/verify-typecheck.sh b/scripts/verify-typecheck.sh deleted file mode 100755 index f6c14844fc..0000000000 --- a/scripts/verify-typecheck.sh +++ /dev/null @@ -1,34 +0,0 @@ -#!/usr/bin/env bash -# 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. - -# This script does a fast type check of script srnetes code for all platforms. -# Usage: `scripts/verify-typecheck.sh`. - -OPENIM_ROOT=$(dirname "${BASH_SOURCE[0]}")/.. -source "${OPENIM_ROOT}/scripts/lib/init.sh" - -openim::golang::verify_go_version - -cd "${OPENIM_ROOT}" -ret=0 -TYPECHECK_SERIAL="${TYPECHECK_SERIAL:-false}" -scripts/run-in-gopath.sh \ -make tools.verify.typecheck -${OPENIM_ROOT}/_output/tools/typecheck "$@" "--serial=$TYPECHECK_SERIAL" || ret=$? -if [[ $ret -ne 0 ]]; then - openim::log::error "Type Check has failed. This may cause cross platform build failures." >&2 - openim::log::error "Please see https://github.com/kubecub/typecheck for more information." >&2 - exit 1 -fi diff --git a/scripts/verify-yamlfmt.sh b/scripts/verify-yamlfmt.sh deleted file mode 100755 index a0aa583a80..0000000000 --- a/scripts/verify-yamlfmt.sh +++ /dev/null @@ -1,44 +0,0 @@ -#!/usr/bin/env bash -# 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. - - -# This script checks whether the OWNERS files need to be formatted or not by -# `yamlfmt`. Run `scripts/update-yamlfmt.sh` to actually format sources. -# -# Usage: `scripts/verify-yamlfmt.sh`. - -OPENIM_ROOT=$(dirname "${BASH_SOURCE[0]}")/.. -source "${OPENIM_ROOT}/scripts/lib/init.sh" - -openim::util::ensure_clean_working_dir -# This sets up the environment, like GOCACHE, which keeps the worktree cleaner. -openim::golang::setup_env - -_tmpdir="$(openim::realpath "$(mktemp -d -t "$(basename "$0").XXXXXX")")" -git worktree add -f -q "${_tmpdir}" HEAD -openim::util::trap_add "git worktree remove -f ${_tmpdir}" EXIT -cd "${_tmpdir}" - -# Format YAML files -scripts/update-yamlfmt.sh - -# Test for diffs -diffs=$(git status --porcelain | wc -l) -if [[ ${diffs} -gt 0 ]]; then - echo "YAML files need to be formatted" >&2 - git diff - echo "Please run 'scripts/update-yamlfmt.sh'" >&2 - exit 1 -fi \ No newline at end of file diff --git a/scripts/wait-for-it.sh b/scripts/wait-for-it.sh deleted file mode 100755 index c05b856782..0000000000 --- a/scripts/wait-for-it.sh +++ /dev/null @@ -1,191 +0,0 @@ -#!/usr/bin/env bash -# 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. - -WAITFORIT_cmdname=${0##*/} - -echoerr() { if [[ $WAITFORIT_QUIET -ne 1 ]]; then echo "$@" 1>&2; fi } - -usage() { - cat << USAGE >&2 -Usage: - $WAITFORIT_cmdname host:port [-s] [-t timeout] [-- command args] - -h HOST | --host=HOST Host or IP under test - -p PORT | --port=PORT TCP port under test - Alternatively, you specify the host and port as host:port - -s | --strict Only execute subcommand if the test succeeds - -q | --quiet Don't output any status messages - -t TIMEOUT | --timeout=TIMEOUT - Timeout in seconds, zero for no timeout - -- COMMAND ARGS Execute command with args after the test finishes -USAGE - exit 1 -} - -wait_for() { - if [[ $WAITFORIT_TIMEOUT -gt 0 ]]; then - echoerr "$WAITFORIT_cmdname: waiting $WAITFORIT_TIMEOUT seconds for $WAITFORIT_HOST:$WAITFORIT_PORT" - else - echoerr "$WAITFORIT_cmdname: waiting for $WAITFORIT_HOST:$WAITFORIT_PORT without a timeout" - fi - WAITFORIT_start_ts=$(date +%s) - while : - do - if [[ $WAITFORIT_ISBUSY -eq 1 ]]; then - nc -z $WAITFORIT_HOST $WAITFORIT_PORT - WAITFORIT_result=$? - else - (echo -n > /dev/tcp/$WAITFORIT_HOST/$WAITFORIT_PORT) >/dev/null 2>&1 - WAITFORIT_result=$? - fi - if [[ $WAITFORIT_result -eq 0 ]]; then - WAITFORIT_end_ts=$(date +%s) - echoerr "$WAITFORIT_cmdname: $WAITFORIT_HOST:$WAITFORIT_PORT is available after $((WAITFORIT_end_ts - WAITFORIT_start_ts)) seconds" - break - fi - sleep 1 - done - return $WAITFORIT_result -} - -wait_for_wrapper() { - # In order to support SIGINT during timeout: http://unix.stackexchange.com/a/57692 - if [[ $WAITFORIT_QUIET -eq 1 ]]; then - timeout $WAITFORIT_BUSYTIMEFLAG $WAITFORIT_TIMEOUT $0 --quiet --child --host=$WAITFORIT_HOST --port=$WAITFORIT_PORT --timeout=$WAITFORIT_TIMEOUT & - else - timeout $WAITFORIT_BUSYTIMEFLAG $WAITFORIT_TIMEOUT $0 --child --host=$WAITFORIT_HOST --port=$WAITFORIT_PORT --timeout=$WAITFORIT_TIMEOUT & - fi - WAITFORIT_PID=$! - trap "kill -INT -$WAITFORIT_PID" INT - wait $WAITFORIT_PID - WAITFORIT_RESULT=$? - if [[ $WAITFORIT_RESULT -ne 0 ]]; then - echoerr "$WAITFORIT_cmdname: timeout occurred after waiting $WAITFORIT_TIMEOUT seconds for $WAITFORIT_HOST:$WAITFORIT_PORT" - fi - return $WAITFORIT_RESULT -} - -# process arguments -while [[ $# -gt 0 ]] -do - case "$1" in - *:* ) - WAITFORIT_hostport=(${1//:/ }) - WAITFORIT_HOST=${WAITFORIT_hostport[0]} - WAITFORIT_PORT=${WAITFORIT_hostport[1]} - shift 1 - ;; - --child) - WAITFORIT_CHILD=1 - shift 1 - ;; - -q | --quiet) - WAITFORIT_QUIET=1 - shift 1 - ;; - -s | --strict) - WAITFORIT_STRICT=1 - shift 1 - ;; - -h) - WAITFORIT_HOST="$2" - if [[ $WAITFORIT_HOST == "" ]]; then break; fi - shift 2 - ;; - --host=*) - WAITFORIT_HOST="${1#*=}" - shift 1 - ;; - -p) - WAITFORIT_PORT="$2" - if [[ $WAITFORIT_PORT == "" ]]; then break; fi - shift 2 - ;; - --port=*) - WAITFORIT_PORT="${1#*=}" - shift 1 - ;; - -t) - WAITFORIT_TIMEOUT="$2" - if [[ $WAITFORIT_TIMEOUT == "" ]]; then break; fi - shift 2 - ;; - --timeout=*) - WAITFORIT_TIMEOUT="${1#*=}" - shift 1 - ;; - --) - shift - WAITFORIT_CLI=("$@") - break - ;; - --help) - usage - ;; - *) - echoerr "Unknown argument: $1" - usage - ;; - esac -done - -if [[ "$WAITFORIT_HOST" == "" || "$WAITFORIT_PORT" == "" ]]; then - echoerr "Error: you need to provide a host and port to test." - usage -fi - -WAITFORIT_TIMEOUT=${WAITFORIT_TIMEOUT:-15} -WAITFORIT_STRICT=${WAITFORIT_STRICT:-0} -WAITFORIT_CHILD=${WAITFORIT_CHILD:-0} -WAITFORIT_QUIET=${WAITFORIT_QUIET:-0} - -# Check to see if timeout is from busybox? -WAITFORIT_TIMEOUT_PATH=$(type -p timeout) -WAITFORIT_TIMEOUT_PATH=$(realpath $WAITFORIT_TIMEOUT_PATH 2>/dev/null || readlink -f $WAITFORIT_TIMEOUT_PATH) - -WAITFORIT_BUSYTIMEFLAG="" -if [[ $WAITFORIT_TIMEOUT_PATH =~ "busybox" ]]; then - WAITFORIT_ISBUSY=1 - # Check if busybox timeout uses -t flag - # (recent Alpine versions don't support -t anymore) - if timeout &>/dev/stdout | grep -q -e '-t '; then - WAITFORIT_BUSYTIMEFLAG="-t" - fi -else - WAITFORIT_ISBUSY=0 -fi - -if [[ $WAITFORIT_CHILD -gt 0 ]]; then - wait_for - WAITFORIT_RESULT=$? - exit $WAITFORIT_RESULT -else - if [[ $WAITFORIT_TIMEOUT -gt 0 ]]; then - wait_for_wrapper - WAITFORIT_RESULT=$? - else - wait_for - WAITFORIT_RESULT=$? - fi -fi - -if [[ $WAITFORIT_CLI != "" ]]; then - if [[ $WAITFORIT_RESULT -ne 0 && $WAITFORIT_STRICT -eq 1 ]]; then - echoerr "$WAITFORIT_cmdname: strict mode, refusing to execute subprocess" - exit $WAITFORIT_RESULT - fi - exec "${WAITFORIT_CLI[@]}" -else - exit $WAITFORIT_RESULT -fi diff --git a/test/common.sh b/test/common.sh deleted file mode 100644 index e583fe8b38..0000000000 --- a/test/common.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/usr/bin/env bash -# 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. diff --git a/test/wrktest.sh b/test/wrktest.sh deleted file mode 100755 index 10a41121f5..0000000000 --- a/test/wrktest.sh +++ /dev/null @@ -1,276 +0,0 @@ -#!/usr/bin/env bash -# 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. - -: << EOF -The API performance test script automatically executes wrk commands, collects data, analyzes it, and calls gnuplot to plot it - -Usage (to test API performance) : -1. Start the openim-api(port 10002) -2. Execute the test script: ./wrktest.sh - -The script will generate the data file.dat, each column meaning: concurrency QPS average response time success rate - -Usage (Compare the results of 2 tests) -1. The performance test:. / wrktest. Sh openim apiserver - http://127.0.0.1:10002/healthz -2. Execute the command:./wrktest.sh diff apiserver.dat http.dat - -> Note: Make sure you have wrk and gnuplot installed on your system - -EOF - -openim_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd -P)" -wrkdir="${openim_root}/_output/wrk" -jobname="openim-api" -duration="300s" -threads=$((3 * $(grep -c processor /proc/cpuinfo))) - -source "${openim_root}/scripts/lib/color.sh" - -# Set wrk options -openim::wrk::setup() { - #concurrent="200 500 1000 3000 5000 10000 15000 20000 25000 50000 100000 200000 500000 1000000" - concurrent="200 500 1000 3000 5000 10000 15000 20000 25000 50000" - cmd="wrk -t${threads} -d${duration} -T30s --latency" -} - -# Print usage -openim::wrk::usage() { - cat << EOF - -Usage: $0 [OPTION] [diff] URL -Performance automation test script. - - URL HTTP request url, like: http://127.0.0.1:10002/healthz - diff Compare two performance test results - -OPTIONS: - -h Usage information - -n Performance test task name, default: apiserver - -d Directory used to store performance data and gnuplot graphic, default: _output/wrk - -Reprot bugs to <3293172751nss@gmail.com>. -EOF -} - -# Convert plot data to useable data -function openim::wrk::convert_plot_data() { - echo "$1" | awk -v datfile="${wrkdir}/${datfile}" ' { - if ($0 ~ "Running") { - common_time=$2 - } -if ($0 ~ "connections") { - connections=$4 - common_threads=$1 -} -if ($0 ~ "Latency ") { - avg_latency=convertLatency($2) -} -if ($0 ~ "50%") { - p50=convertLatency($2) -} -if ($0 ~ "75%") { - p75=convertLatency($2) -} -if ($0 ~ "90%") { - p90=convertLatency($2) -} -if ($0 ~ "99%") { - p99=convertLatency($2) -} -if ($0 ~ "Requests/sec") { - qps=$2 -} -if ($0 ~ "requests in") { - allrequest=$1 -} -if ($0 ~ "Socket errors") { - err=$4+$6+$8+$10 -} -} -END { -rate=sprintf("%.2f", (allrequest-err)*100/allrequest) -print connections,qps,avg_latency,rate >> datfile -} - -function convertLatency(s) { - if (s ~ "us") { - sub("us", "", s) - return s/1000 - } -if (s ~ "ms") { - sub("ms", "", s) - return s -} -if (s ~ "s") { - sub("s", "", s) - return s * 1000 -} -}' -} - -# Remove existing data file -function openim::wrk::prepare() { - rm -f "${wrkdir}"/"${datfile}" -} - -# Plot according to gunplot data file -function openim::wrk::plot() { - gnuplot << EOF -set terminal png enhanced #输出格式为png文件 -set ylabel 'QPS' -set xlabel 'Concurrent' -set y2label 'Average Latency (ms)' -set key top left vertical noreverse spacing 1.2 box -set tics out nomirror -set border 3 front -set style line 1 linecolor rgb '#00ff00' linewidth 2 linetype 3 pointtype 2 -set style line 2 linecolor rgb '#ff0000' linewidth 1 linetype 3 pointtype 2 -set style data linespoints - -set grid #显示网格 -set xtics nomirror rotate #by 90#只需要一个x轴 -set mxtics 5 -set mytics 5 #可以增加分刻度 -set ytics nomirror -set y2tics - -set autoscale y -set autoscale y2 - -set output "${wrkdir}/${qpsttlb}" #指定数据文件名称 -set title "QPS & TTLB\nRunning: ${duration}\nThreads: ${threads}" -plot "${wrkdir}/${datfile}" using 2:xticlabels(1) w lp pt 7 ps 1 lc rgbcolor "#EE0000" axis x1y1 t "QPS","${wrkdir}/${datfile}" using 3:xticlabels(1) w lp pt 5 ps 1 lc rgbcolor "#0000CD" axis x2y2 t "Avg Latency (ms)" - -unset y2tics -unset y2label -set ytics nomirror -set yrange[0:100] -set output "${wrkdir}/${successrate}" #指定数据文件名称 -set title "Success Rate\nRunning: ${duration}\nThreads: ${threads}" -plot "${wrkdir}/${datfile}" using 4:xticlabels(1) w lp pt 7 ps 1 lc rgbcolor "#F62817" t "Success Rate" -EOF -} - -# Plot diff graphic -function openim::wrk::plot_diff() { - gnuplot << EOF -set terminal png enhanced #输出格式为png文件 -set xlabel 'Concurrent' -set ylabel 'QPS' -set y2label 'Average Latency (ms)' -set key below left vertical noreverse spacing 1.2 box autotitle columnheader -set tics out nomirror -set border 3 front -set style line 1 linecolor rgb '#00ff00' linewidth 2 linetype 3 pointtype 2 -set style line 2 linecolor rgb '#ff0000' linewidth 1 linetype 3 pointtype 2 -set style data linespoints - -#set border 3 lt 3 lw 2 #这会让你的坐标图的border更好看 -set grid #显示网格 -set xtics nomirror rotate #by 90#只需要一个x轴 -set mxtics 5 -set mytics 5 #可以增加分刻度 -set ytics nomirror -set y2tics - -#set pointsize 0.4 #点的像素大小 -#set datafile separator '\t' #数据文件的字段用\t分开 - -set autoscale y -set autoscale y2 - -#设置图像的大小 为标准大小的2倍 -#set size 2.3,2 - -set output "${wrkdir}/${t1}_${t2}.qps.ttlb.diff.png" #指定数据文件名称 -set title "QPS & TTLB\nRunning: ${duration}\nThreads: ${threads}" -plot "/tmp/plot_diff.dat" using 2:xticlabels(1) w lp pt 7 ps 1 lc rgbcolor "#EE0000" axis x1y1 t "${t1} QPS","/tmp/plot_diff.dat" using 5:xticlabels(1) w lp pt 7 ps 1 lc rgbcolor "#EE82EE" axis x1y1 t "${t2} QPS","/tmp/plot_diff.dat" using 3:xticlabels(1) w lp pt 5 ps 1 lc rgbcolor "#0000CD" axis x2y2 t "${t1} Avg Latency (ms)", "/tmp/plot_diff.dat" using 6:xticlabels(1) w lp pt 5 ps 1 lc rgbcolor "#6495ED" axis x2y2 t "${t2} Avg Latency (ms)" - -unset y2tics -unset y2label -set ytics nomirror -set yrange[0:100] -set output "${wrkdir}/${t1}_${t2}.successrate.diff.png" #指定数据文件名称 -set title "Success Rate\nRunning: ${duration}\nThreads: ${threads}" -plot "/tmp/plot_diff.dat" using 4:xticlabels(1) w lp pt 7 ps 1 lc rgbcolor "#EE0000" t "${t1} Success Rate","/tmp/plot_diff.dat" using 7:xticlabels(1) w lp pt 7 ps 1 lc rgbcolor "#EE82EE" t "${t2} Success Rate" -EOF -} - -# Start API performance testing -openim::wrk::start_performance_test() { - openim::wrk::prepare - - for c in ${concurrent} - do - wrkcmd="${cmd} -c ${c} $1" - echo "Running wrk command: ${wrkcmd}" - result=$(eval "${wrkcmd}") - openim::wrk::convert_plot_data "${result}" - done - - echo -e "\nNow plot according to ${COLOR_MAGENTA}${wrkdir}/${datfile}${COLOR_NORMAL}" - openim::wrk::plot &> /dev/null - echo -e "QPS graphic file is: ${COLOR_MAGENTA}${wrkdir}/${qpsttlb}${COLOR_NORMAL} -Success rate graphic file is: ${COLOR_MAGENTA}${wrkdir}/${successrate}${COLOR_NORMAL}" -} - -while getopts "hd:n:" opt;do - case ${opt} in - d) - wrkdir=${OPTARG} - ;; - n) - jobname=${OPTARG} - ;; - ?) - openim::wrk::usage - exit 0 - ;; - esac -done - -shift $((OPTIND-1)) - -mkdir -p "${wrkdir}" - -case $1 in - "diff") - if [ "$#" -lt 3 ];then - openim::wrk::usage - exit 0 - fi - - t1=$(basename $2|sed 's/.dat//g') # 对比图中红色线条名称 - t2=$(basename $3|sed 's/.dat//g') # 对比图中粉色线条名称 - - join $2 $3 > /tmp/plot_diff.dat - openim::wrk::plot_diff "$(basename "$2")" "$(basename "$3")" - exit 0 - ;; - *) - if [ "$#" -lt 1 ];then - openim::wrk::usage - exit 0 - fi - url="$1" - - qpsttlb="${jobname}_qps_ttlb.png" - successrate="${jobname}_successrate.png" - datfile="${jobname}.dat" - - openim::wrk::setup - openim::wrk::start_performance_test "${url}" - ;; -esac From 281e3a8d6c6503ef2b26c525a19a9b9a0da56b36 Mon Sep 17 00:00:00 2001 From: xuan <146319162+wxuanF@users.noreply.github.com> Date: Sun, 28 Apr 2024 12:13:12 +0800 Subject: [PATCH 161/188] Auto close issue test (#2243) * Update README.md * Update README.md * Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 045d28f470..7c34664d6b 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ [![Good First Issues](https://img.shields.io/github/issues/openimsdk/open-im-server/good%20first%20issue?style=for-the-badge&logo=github)](https://github.com/openimsdk/open-im-server/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc+label%3A%22good+first+issue%22) [![Language](https://img.shields.io/badge/Language-Go-blue.svg?style=for-the-badge&logo=go&logoColor=white)](https://golang.org/) - +

Englist · 中文 · @@ -131,7 +131,7 @@ Thank you for contributing to building a powerful instant messaging solution! ## :closed_book: License -OpenIMSDK is available under the Apache License 2.0. See the [LICENSE file](https://github.com/openimsdk/open-im-server/blob/main/LICENSE) for more information. +OpenIMSDK is available under the Apache License 2.0. See the [LICENSE file](https://github.com/openimsdk/open-im-server/blob/main/LICENSE) for more information. From 879cf757436f4c8d160de992e82a4c5b0c62c625 Mon Sep 17 00:00:00 2001 From: skiffer-git <72860476+skiffer-git@users.noreply.github.com> Date: Sun, 28 Apr 2024 14:35:46 +0800 Subject: [PATCH 162/188] fix bug: If there are uppercase letters in the directory, 'mage start' encounters an error (#2253) * fix bug: If there are uppercase letters in the directory, 'mage start' encounters an error * update go.mod --- go.mod | 4 ++-- go.sum | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/go.mod b/go.mod index 21eca956e3..cc0de76142 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/openimsdk/open-im-server/v3 -go 1.21 +go 1.21.2 require ( firebase.google.com/go v3.13.0+incompatible @@ -34,7 +34,7 @@ require ( github.com/hashicorp/golang-lru/v2 v2.0.7 github.com/kelindar/bitmap v1.5.2 github.com/likexian/gokit v0.25.13 - github.com/openimsdk/gomake v0.0.9 + github.com/openimsdk/gomake v0.0.11 github.com/redis/go-redis/v9 v9.4.0 github.com/robfig/cron/v3 v3.0.1 github.com/shirou/gopsutil v3.21.11+incompatible diff --git a/go.sum b/go.sum index aa851c74b8..7c256c58d0 100644 --- a/go.sum +++ b/go.sum @@ -279,8 +279,8 @@ github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1y github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE= github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs= -github.com/openimsdk/gomake v0.0.9 h1:ouf25ygN2PMQ68Gfgns/EQRPiLPnp+77SIr68GfE+n4= -github.com/openimsdk/gomake v0.0.9/go.mod h1:PndCozNc2IsQIciyn9mvEblYWZwJmAI+06z94EY+csI= +github.com/openimsdk/gomake v0.0.11 h1:jJ9286zKFfBeARkmfqMEcUYg9lJ+Cj9lylxP8W9uCFM= +github.com/openimsdk/gomake v0.0.11/go.mod h1:PndCozNc2IsQIciyn9mvEblYWZwJmAI+06z94EY+csI= github.com/openimsdk/protocol v0.0.65 h1:SPT9qyUsFRTTKSKb/FjpS+xr6sxz/Kbnu+su1bxYagc= github.com/openimsdk/protocol v0.0.65/go.mod h1:OZQA9FR55lseYoN2Ql1XAHYKHJGu7OMNkUbuekrKCM8= github.com/openimsdk/tools v0.0.49-alpha.2 h1:8IfV6o2ySU7C54sh/MG7ctEp1h3lSNe03OCUDWSk5Ws= From a2d6a624548411844d7e1fc7d693f994301d4774 Mon Sep 17 00:00:00 2001 From: xuan <146319162+wxuanF@users.noreply.github.com> Date: Sun, 28 Apr 2024 14:35:48 +0800 Subject: [PATCH 163/188] Update action (#2256) * Rename check-coverage.yml to check-coverage.bak * Rename release.yml to release.bak * Update .env * Rename sync.yml to sync.bak * Rename sync-release.yml to sync-release.bak --- .env | 4 ++++ .github/workflows/{check-coverage.yml => check-coverage.bak} | 0 .github/workflows/{release.yml => release.bak} | 2 +- .github/workflows/{sync-release.yml => sync-release.bak} | 2 +- .github/workflows/{sync.yml => sync.bak} | 2 +- 5 files changed, 7 insertions(+), 3 deletions(-) rename .github/workflows/{check-coverage.yml => check-coverage.bak} (100%) rename .github/workflows/{release.yml => release.bak} (97%) rename .github/workflows/{sync-release.yml => sync-release.bak} (97%) rename .github/workflows/{sync.yml => sync.bak} (97%) diff --git a/.env b/.env index 6c2baa41d8..d3ae0426a9 100644 --- a/.env +++ b/.env @@ -9,5 +9,9 @@ MINIO_IMAGE=minio/minio:RELEASE.2024-01-11T07-46-16Z OPENIM_WEB_FRONT_IMAGE=openim/openim-web-front:release-v3.5.1 OPENIM_ADMIN_FRONT_IMAGE=openim/openim-admin-front:release-v1.7 +#FRONT_IMAGE: use aliyun images +#OPENIM_WEB_FRONT_IMAGE=registry.cn-hangzhou.aliyuncs.com/openimsdk/openim-web-front:release-v3.5.1 +#OPENIM_ADMIN_FRONT_IMAGE=registry.cn-hangzhou.aliyuncs.com/openimsdk/openim-admin-front:release-v1.7 + DATA_DIR=./ diff --git a/.github/workflows/check-coverage.yml b/.github/workflows/check-coverage.bak similarity index 100% rename from .github/workflows/check-coverage.yml rename to .github/workflows/check-coverage.bak diff --git a/.github/workflows/release.yml b/.github/workflows/release.bak similarity index 97% rename from .github/workflows/release.yml rename to .github/workflows/release.bak index 9950bdabb8..c15cff6a3c 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.bak @@ -78,4 +78,4 @@ jobs: ./_output/dist/*.rpm ./_output/dist/*.apk key: ${{ github.ref }} - - run: task goreleaser:test:${{ matrix.format }} \ No newline at end of file + - run: task goreleaser:test:${{ matrix.format }} diff --git a/.github/workflows/sync-release.yml b/.github/workflows/sync-release.bak similarity index 97% rename from .github/workflows/sync-release.yml rename to .github/workflows/sync-release.bak index e156e07d80..a85c74fde0 100644 --- a/.github/workflows/sync-release.yml +++ b/.github/workflows/sync-release.bak @@ -41,4 +41,4 @@ jobs: automerge ASSIGNEES: | kubbot - continue-on-error: true \ No newline at end of file + continue-on-error: true diff --git a/.github/workflows/sync.yml b/.github/workflows/sync.bak similarity index 97% rename from .github/workflows/sync.yml rename to .github/workflows/sync.bak index 77ed2f881b..595cbbe2c8 100644 --- a/.github/workflows/sync.yml +++ b/.github/workflows/sync.bak @@ -37,4 +37,4 @@ jobs: automerge ASSIGNEES: | kubbot - continue-on-error: true \ No newline at end of file + continue-on-error: true From 230c0dbb8be41909f9f0e692e6322abb7232b993 Mon Sep 17 00:00:00 2001 From: chao <48119764+withchao@users.noreply.github.com> Date: Mon, 29 Apr 2024 17:02:46 +0800 Subject: [PATCH 164/188] fix: minio config build (#2263) * fix: GroupApplicationAcceptedNotification * fix: GroupApplicationAcceptedNotification * fix: NotificationUserInfoUpdate * cicd: robot automated Change * fix: component * fix: getConversationInfo * feat: cron task * feat: cron task * feat: cron task * feat: cron task * feat: cron task * fix: minio config url recognition error --------- Co-authored-by: withchao --- pkg/common/config/config.go | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/pkg/common/config/config.go b/pkg/common/config/config.go index caf31036cd..24d04d8ccc 100644 --- a/pkg/common/config/config.go +++ b/pkg/common/config/config.go @@ -15,14 +15,13 @@ package config import ( - "fmt" "github.com/openimsdk/tools/db/mongoutil" "github.com/openimsdk/tools/db/redisutil" "github.com/openimsdk/tools/mq/kafka" "github.com/openimsdk/tools/s3/cos" "github.com/openimsdk/tools/s3/minio" "github.com/openimsdk/tools/s3/oss" - "net" + "strings" "time" ) @@ -473,25 +472,23 @@ func (k *Kafka) Build() *kafka.Config { }, } } + func (m *Minio) Build() *minio.Config { - conf := minio.Config{ + formatEndpoint := func(address string) string { + if strings.HasPrefix(address, "http://") || strings.HasPrefix(address, "https://") { + return address + } + return "http://" + address + } + return &minio.Config{ Bucket: m.Bucket, AccessKeyID: m.AccessKeyID, SecretAccessKey: m.SecretAccessKey, SessionToken: m.SessionToken, PublicRead: m.PublicRead, + Endpoint: formatEndpoint(m.InternalAddress), + SignEndpoint: formatEndpoint(m.ExternalAddress), } - if _, _, err := net.SplitHostPort(m.InternalAddress); err == nil { - conf.Endpoint = fmt.Sprintf("http://%s", m.InternalAddress) - } else { - conf.Endpoint = m.InternalAddress - } - if _, _, err := net.SplitHostPort(m.ExternalAddress); err == nil { - conf.SignEndpoint = fmt.Sprintf("http://%s", m.ExternalAddress) - } else { - conf.SignEndpoint = m.ExternalAddress - } - return &conf } func (c *Cos) Build() *cos.Config { return &cos.Config{ From 691cf740af346ca17ebdc1cfc6a5f41a587e4d8a Mon Sep 17 00:00:00 2001 From: blooming <37789413+Bloomingg@users.noreply.github.com> Date: Mon, 6 May 2024 16:37:52 +0800 Subject: [PATCH 165/188] fix: avoid frequent scheduled task (#2274) --- .github/workflows/build-docker-image.yml | 3 +-- .github/workflows/{lock-issue.yml => lock-issue.bak} | 0 .github/workflows/stale.yml | 4 ++-- 3 files changed, 3 insertions(+), 4 deletions(-) rename .github/workflows/{lock-issue.yml => lock-issue.bak} (100%) diff --git a/.github/workflows/build-docker-image.yml b/.github/workflows/build-docker-image.yml index 1e9711d2c9..b4733116e0 100644 --- a/.github/workflows/build-docker-image.yml +++ b/.github/workflows/build-docker-image.yml @@ -15,8 +15,6 @@ name: Publish Docker image on: - schedule: - - cron: '30 2 * * *' push: branches: - main @@ -31,6 +29,7 @@ env: jobs: build-dockerhub: + if: github.event_name == 'push' || (github.event_name == 'pull_request' && github.event.action == 'closed' && github.event.pull_request.merged == true) runs-on: ubuntu-latest steps: - name: Checkout diff --git a/.github/workflows/lock-issue.yml b/.github/workflows/lock-issue.bak similarity index 100% rename from .github/workflows/lock-issue.yml rename to .github/workflows/lock-issue.bak diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index da44cb7f30..4445f6ddaa 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -21,7 +21,7 @@ name: Mark stale issues and pull requests on: schedule: - - cron: '0 8 * * *' + - cron: '0 8 * * 1' jobs: stale: @@ -36,7 +36,7 @@ jobs: with: repo-token: ${{ secrets.BOT_GITHUB_TOKEN }} days-before-stale: 60 - days-before-close: 7 + days-before-close: 305 stale-issue-message: 'This issue is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 7 days.' stale-pr-message: 'This issue is stale because it has been open 60 days with no activity.' close-issue-message: 'This issue was closed because it has been stalled for 7 days with no activity.' From 8d84e2f01f87e2f3e8d9338362ce5a7a4c286c2a Mon Sep 17 00:00:00 2001 From: skiffer-git <72860476+skiffer-git@users.noreply.github.com> Date: Tue, 7 May 2024 21:05:41 +0800 Subject: [PATCH 166/188] Skip minio check (#2281) * If MinIO is not being used, then do not perform the MinIO check. * If MinIO is not being used, then do not perform the MinIO check. * If MinIO is not being used, then do not perform the MinIO check. * If MinIO is not being used, then do not perform the MinIO check. * kill binary before build * Stop the process before compiling. * Stop the process before compiling. --- docker-compose.yml | 3 +++ go.mod | 3 ++- go.sum | 4 ++-- internal/tools/cron_task.go | 14 +------------- magefile.go | 12 +----------- tools/check-component/main.go | 20 ++++++++++++++++---- 6 files changed, 25 insertions(+), 31 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 4acd00cdd5..aeb53a4170 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -51,6 +51,7 @@ services: ports: - "12181:2181" environment: + #JVMFLAGS: "-Xms32m -Xmx128m" TZ: "Asia/Shanghai" ALLOW_ANONYMOUS_LOGIN: "yes" restart: always @@ -70,6 +71,7 @@ services: command: > bash -c "/opt/bitnami/scripts/kafka/run.sh & /opt/bitnami/kafka/create-topic.sh; wait" environment: + #KAFKA_HEAP_OPTS: "-Xms128m -Xmx256m" TZ: Asia/Shanghai KAFKA_CFG_NODE_ID: 0 KAFKA_CFG_PROCESS_ROLES: controller,broker @@ -119,3 +121,4 @@ services: - openim + diff --git a/go.mod b/go.mod index cc0de76142..b522065da4 100644 --- a/go.mod +++ b/go.mod @@ -34,7 +34,7 @@ require ( github.com/hashicorp/golang-lru/v2 v2.0.7 github.com/kelindar/bitmap v1.5.2 github.com/likexian/gokit v0.25.13 - github.com/openimsdk/gomake v0.0.11 + github.com/openimsdk/gomake v0.0.13 github.com/redis/go-redis/v9 v9.4.0 github.com/robfig/cron/v3 v3.0.1 github.com/shirou/gopsutil v3.21.11+incompatible @@ -44,6 +44,7 @@ require ( golang.org/x/sync v0.6.0 ) + require ( cloud.google.com/go v0.112.0 // indirect cloud.google.com/go/compute v1.23.3 // indirect diff --git a/go.sum b/go.sum index 7c256c58d0..e2ecf7284e 100644 --- a/go.sum +++ b/go.sum @@ -279,8 +279,8 @@ github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1y github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE= github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs= -github.com/openimsdk/gomake v0.0.11 h1:jJ9286zKFfBeARkmfqMEcUYg9lJ+Cj9lylxP8W9uCFM= -github.com/openimsdk/gomake v0.0.11/go.mod h1:PndCozNc2IsQIciyn9mvEblYWZwJmAI+06z94EY+csI= +github.com/openimsdk/gomake v0.0.13 h1:xLDe/moqgWpRoptHzI4packAWzs4C16b+sVY+txNJp0= +github.com/openimsdk/gomake v0.0.13/go.mod h1:PndCozNc2IsQIciyn9mvEblYWZwJmAI+06z94EY+csI= github.com/openimsdk/protocol v0.0.65 h1:SPT9qyUsFRTTKSKb/FjpS+xr6sxz/Kbnu+su1bxYagc= github.com/openimsdk/protocol v0.0.65/go.mod h1:OZQA9FR55lseYoN2Ql1XAHYKHJGu7OMNkUbuekrKCM8= github.com/openimsdk/tools v0.0.49-alpha.2 h1:8IfV6o2ySU7C54sh/MG7ctEp1h3lSNe03OCUDWSk5Ws= diff --git a/internal/tools/cron_task.go b/internal/tools/cron_task.go index 7161f55fc1..20baeffaf0 100644 --- a/internal/tools/cron_task.go +++ b/internal/tools/cron_task.go @@ -25,8 +25,6 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" "os" - "os/signal" - "syscall" "time" "github.com/openimsdk/tools/errs" @@ -50,22 +48,12 @@ func Start(ctx context.Context, config *CronTaskConfig) error { return errs.WrapMsg(err, "failed to register discovery service") } client.AddOption(mw.GrpcClient(), grpc.WithTransportCredentials(insecure.NewCredentials())) - ctx, exitBy := context.WithCancelCause(context.Background()) ctx = mcontext.SetOpUserID(ctx, config.Share.IMAdminUserID[0]) conn, err := client.GetConn(ctx, config.Share.RpcRegisterName.Msg) if err != nil { return err } cli := msg.NewMsgClient(conn) - go func() { - sigs := make(chan os.Signal, 1) - signal.Notify(sigs, syscall.SIGTERM) - select { - case <-ctx.Done(): - case s := <-sigs: - exitBy(fmt.Errorf("exit signal %s", s)) - } - }() crontab := cron.New() clearFunc := func() { now := time.Now() @@ -84,5 +72,5 @@ func Start(ctx context.Context, config *CronTaskConfig) error { log.ZInfo(ctx, "start cron task", "chatRecordsClearTime", config.CronTask.ChatRecordsClearTime) crontab.Start() <-ctx.Done() - return context.Cause(ctx) + return nil } diff --git a/magefile.go b/magefile.go index 98ffa48f3f..a8a1c40400 100644 --- a/magefile.go +++ b/magefile.go @@ -6,22 +6,12 @@ package main import ( "github.com/openimsdk/gomake/mageutil" "os" - "strings" ) var Default = Build func Build() { - platforms := os.Getenv("PLATFORMS") - if platforms == "" { - platforms = mageutil.DetectPlatform() - } - - for _, platform := range strings.Split(platforms, " ") { - mageutil.CompileForPlatform(platform) - } - - mageutil.PrintGreen("All binaries under cmd and tools were successfully compiled.") + mageutil.Build() } func Start() { diff --git a/tools/check-component/main.go b/tools/check-component/main.go index d3225abb8e..7fe64d3c5b 100644 --- a/tools/check-component/main.go +++ b/tools/check-component/main.go @@ -66,6 +66,7 @@ func initConfig(configDir string) (*config.Mongo, *config.Redis, *config.Kafka, kafkaConfig = &config.Kafka{} minioConfig = &config.Minio{} zookeeperConfig = &config.ZooKeeper{} + thirdConfig = &config.Third{} ) err := config.LoadConfig(filepath.Join(configDir, cmd.MongodbConfigFileName), cmd.ConfigEnvPrefixMap[cmd.MongodbConfigFileName], mongoConfig) if err != nil { @@ -82,11 +83,19 @@ func initConfig(configDir string) (*config.Mongo, *config.Redis, *config.Kafka, return nil, nil, nil, nil, nil, err } - err = config.LoadConfig(filepath.Join(configDir, cmd.MinioConfigFileName), cmd.ConfigEnvPrefixMap[cmd.MinioConfigFileName], minioConfig) + err = config.LoadConfig(filepath.Join(configDir, cmd.OpenIMRPCThirdCfgFileName), cmd.ConfigEnvPrefixMap[cmd.OpenIMRPCThirdCfgFileName], thirdConfig) if err != nil { return nil, nil, nil, nil, nil, err } + if thirdConfig.Object.Enable == "minio" { + err = config.LoadConfig(filepath.Join(configDir, cmd.MinioConfigFileName), cmd.ConfigEnvPrefixMap[cmd.MinioConfigFileName], minioConfig) + if err != nil { + return nil, nil, nil, nil, nil, err + } + } else { + minioConfig = nil + } err = config.LoadConfig(filepath.Join(configDir, cmd.ZookeeperConfigFileName), cmd.ConfigEnvPrefixMap[cmd.ZookeeperConfigFileName], zookeeperConfig) if err != nil { return nil, nil, nil, nil, nil, err @@ -131,14 +140,17 @@ func performChecks(ctx context.Context, mongoConfig *config.Mongo, redisConfig * "Redis": func() error { return CheckRedis(ctx, redisConfig) }, - "MinIO": func() error { - return CheckMinIO(ctx, minioConfig) - }, "Kafka": func() error { return CheckKafka(ctx, kafkaConfig) }, } + if minioConfig != nil { + checks["MinIO"] = func() error { + return CheckMinIO(ctx, minioConfig) + } + } + for i := 0; i < maxRetry; i++ { allSuccess := true for name, check := range checks { From 5ba5402bee04d73d46a04c3461ae15a711f9abce Mon Sep 17 00:00:00 2001 From: skiffer-git <72860476+skiffer-git@users.noreply.github.com> Date: Wed, 8 May 2024 16:00:27 +0800 Subject: [PATCH 167/188] update gomake (#2286) --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 746dddf65a..3f765805c3 100644 --- a/Dockerfile +++ b/Dockerfile @@ -43,7 +43,7 @@ COPY --from=builder $SERVER_DIR/start-config.yml $SERVER_DIR/ COPY --from=builder $SERVER_DIR/go.mod $SERVER_DIR/ COPY --from=builder $SERVER_DIR/go.sum $SERVER_DIR/ -RUN go get github.com/openimsdk/gomake@v0.0.9 +RUN go get github.com/openimsdk/gomake@v0.0.13 # Set the command to run when the container starts ENTRYPOINT ["sh", "-c", "mage start && tail -f /dev/null"] From 66426cd98b5784e94340a5c85a950416af24b9a2 Mon Sep 17 00:00:00 2001 From: chao <48119764+withchao@users.noreply.github.com> Date: Wed, 8 May 2024 19:38:27 +0800 Subject: [PATCH 168/188] fix: search for messag (#2288) * fix: GroupApplicationAcceptedNotification * fix: GroupApplicationAcceptedNotification * fix: NotificationUserInfoUpdate * cicd: robot automated Change * fix: component * fix: getConversationInfo * feat: cron task * feat: cron task * feat: cron task * feat: cron task * feat: cron task * fix: minio config url recognition error * fix: SearchMessage --------- Co-authored-by: withchao --- pkg/common/db/mgo/msg.go | 122 +++++++++++++++++++++++---------------- 1 file changed, 72 insertions(+), 50 deletions(-) diff --git a/pkg/common/db/mgo/msg.go b/pkg/common/db/mgo/msg.go index 6fe24536bd..17e493d336 100644 --- a/pkg/common/db/mgo/msg.go +++ b/pkg/common/db/mgo/msg.go @@ -267,58 +267,80 @@ func (m *MsgMgo) MarkSingleChatMsgsAsRead(ctx context.Context, userID string, do } func (m *MsgMgo) SearchMessage(ctx context.Context, req *msg.SearchMessageReq) (int32, []*relation.MsgInfoModel, error) { - var pipe mongo.Pipeline - condition := bson.A{} - if req.SendTime != "" { - // Changed to keyed fields for bson.M to avoid govet errors - condition = append(condition, bson.M{"$eq": bson.A{bson.M{"$dateToString": bson.M{"format": "%Y-%m-%d", "date": bson.M{"$toDate": "$$item.msg.send_time"}}}, req.SendTime}}) + where := make(bson.A, 0, 6) + if req.RecvID != "" { + where = append(where, bson.M{"msgs.msg.recv_id": req.RecvID}) + } + if req.SendID != "" { + where = append(where, bson.M{"msgs.msg.send_id": req.SendID}) } if req.ContentType != 0 { - condition = append(condition, bson.M{"$eq": bson.A{"$$item.msg.content_type", req.ContentType}}) + where = append(where, bson.M{"msgs.msg.content_type": req.ContentType}) } if req.SessionType != 0 { - condition = append(condition, bson.M{"$eq": bson.A{"$$item.msg.session_type", req.SessionType}}) + where = append(where, bson.M{"msgs.msg.session_type": req.SessionType}) } - if req.RecvID != "" { - condition = append(condition, bson.M{"$regexFind": bson.M{"input": "$$item.msg.recv_id", "regex": req.RecvID}}) + if req.SendTime != "" { + sendTime, err := time.Parse(time.DateOnly, req.SendTime) + if err != nil { + return 0, nil, errs.ErrArgs.WrapMsg("invalid sendTime", "req", req.SendTime, "format", time.DateOnly, "cause", err.Error()) + } + where = append(where, + bson.M{ + "msgs.msg.send_time": bson.M{ + "$gte": sendTime.UnixMilli(), + }, + }, + bson.M{ + "msgs.msg.send_time": bson.M{ + "$lt": sendTime.Add(time.Hour * 24).UnixMilli(), + }, + }, + ) } - if req.SendID != "" { - condition = append(condition, bson.M{"$regexFind": bson.M{"input": "$$item.msg.send_id", "regex": req.SendID}}) + pipeline := bson.A{ + bson.M{ + "$unwind": "$msgs", + }, } - - or := bson.A{ - bson.M{"doc_id": bson.M{"$regex": "^si_", "$options": "i"}}, - bson.M{"doc_id": bson.M{"$regex": "^g_", "$options": "i"}}, - bson.M{"doc_id": bson.M{"$regex": "^sg_", "$options": "i"}}, + if len(where) > 0 { + pipeline = append(pipeline, bson.M{ + "$match": bson.M{"$and": where}, + }) } - - // Use bson.D with keyed fields to specify the order explicitly - pipe = mongo.Pipeline{ - {{"$match", bson.D{{Key: "$or", Value: or}}}}, - {{"$project", bson.D{ - {Key: "msgs", Value: bson.D{ - {Key: "$filter", Value: bson.D{ - {Key: "input", Value: "$msgs"}, - {Key: "as", Value: "item"}, - {Key: "cond", Value: bson.D{{Key: "$and", Value: condition}}}, - }}, - }}, - {Key: "doc_id", Value: 1}, - }}}, - {{"$unwind", bson.M{"path": "$msgs"}}}, - {{"$sort", bson.M{"msgs.msg.send_time": -1}}}, + pipeline = append(pipeline, + bson.M{ + "$project": bson.M{ + "_id": 0, + "msg": "$msgs.msg", + }, + }, + bson.M{ + "$count": "count", + }, + ) + count, err := mongoutil.Aggregate[int32](ctx, m.coll, pipeline) + if err != nil { + return 0, nil, err } - type docModel struct { - DocID string `bson:"doc_id"` - Msg *relation.MsgInfoModel `bson:"msgs"` + if len(count) == 0 || count[0] == 0 { + return 0, nil, nil } - msgsDocs, err := mongoutil.Aggregate[*docModel](ctx, m.coll, pipe) + pipeline = pipeline[:len(pipeline)-1] + pipeline = append(pipeline, + bson.M{ + "$skip": (req.Pagination.GetPageNumber() - 1) * req.Pagination.GetShowNumber(), + }, + bson.M{ + "$limit": req.Pagination.GetShowNumber(), + }, + ) + msgs, err := mongoutil.Aggregate[*relation.MsgInfoModel](ctx, m.coll, pipeline) if err != nil { return 0, nil, err } - msgs := make([]*relation.MsgInfoModel, 0) - for _, doc := range msgsDocs { - msgInfo := doc.Msg + for i := range msgs { + msgInfo := msgs[i] if msgInfo == nil || msgInfo.Msg == nil { continue } @@ -350,17 +372,17 @@ func (m *MsgMgo) SearchMessage(ctx context.Context, req *msg.SearchMessageReq) ( } msgs = append(msgs, msgInfo) } - start := (req.Pagination.PageNumber - 1) * req.Pagination.ShowNumber - n := int32(len(msgs)) - if start >= n { - return n, []*relation.MsgInfoModel{}, nil - } - if start+req.Pagination.ShowNumber < n { - msgs = msgs[start : start+req.Pagination.ShowNumber] - } else { - msgs = msgs[start:] - } - return n, msgs, nil + //start := (req.Pagination.PageNumber - 1) * req.Pagination.ShowNumber + //n := int32(len(msgs)) + //if start >= n { + // return n, []*relation.MsgInfoModel{}, nil + //} + //if start+req.Pagination.ShowNumber < n { + // msgs = msgs[start : start+req.Pagination.ShowNumber] + //} else { + // msgs = msgs[start:] + //} + return count[0], msgs, nil } func (m *MsgMgo) RangeUserSendCount(ctx context.Context, start time.Time, end time.Time, group bool, ase bool, pageNumber int32, showNumber int32) (msgCount int64, userCount int64, users []*relation.UserCount, dateCount map[string]int64, err error) { From 961fb472ea7f776b8495fd639b9f77588b80e70c Mon Sep 17 00:00:00 2001 From: skiffer-git <72860476+skiffer-git@users.noreply.github.com> Date: Fri, 10 May 2024 10:58:59 +0800 Subject: [PATCH 169/188] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7c34664d6b..d73d5749a5 100644 --- a/README.md +++ b/README.md @@ -54,7 +54,7 @@ ## :busts_in_silhouette: Join Our Community + 💬 [Follow us on Twitter](https://twitter.com/founder_im63606) -+ 🚀 [Join our Slack](https://join.slack.com/t/openimsdk/shared_invite/zt-2hljfom5u-9ZuzP3NfEKW~BJKbpLm0Hw) ++ 🚀 [Join our Slack](https://join.slack.com/t/openimsdk/shared_invite/zt-2ijy1ys1f-O0aEDCr7ExRZ7mwsHAVg9A) + :eyes: [Join our WeChat Group](https://openim-1253691595.cos.ap-nanjing.myqcloud.com/WechatIMG20.jpeg) ## Ⓜ️ About OpenIM From 835ff3824f52c8f525927b7332ebbe6e122b8282 Mon Sep 17 00:00:00 2001 From: skiffer-git <72860476+skiffer-git@users.noreply.github.com> Date: Tue, 14 May 2024 18:21:36 +0800 Subject: [PATCH 170/188] Etcd naming and discovery (#2300) * add etcd * add etcd * add etcd * add etcd * add etcd * add etcd * add etcd * add etcd * add etcd * add etcd * add etcd * add etcd * add etcd * add etcd * add etcd * add etcd * add etcd * add etcd * Add etcd as a service discovery mechanism * Add etcd as a service discovery mechanism * Add etcd as a service discovery mechanism * Add etcd as a service discovery mechanism * Add etcd as a service discovery mechanism * Add etcd as a service discovery mechanism * Add etcd as a service discovery mechanism * Add etcd as a service discovery mechanism * Add etcd as a service discovery mechanism * Add etcd as a service discovery mechanism * Add etcd as a service discovery mechanism * Add etcd as a service discovery mechanism * Add etcd as a service discovery mechanism * Add etcd as a service discovery mechanism * Add etcd as a service discovery mechanism * Add etcd as a service discovery mechanism * Add etcd as a service discovery mechanism * Add etcd as a service discovery mechanism * Add etcd as a service discovery mechanism * Add etcd as a service discovery mechanism * Add etcd as a service discovery mechanism * Add etcd as a service discovery mechanism * Add etcd as a service discovery mechanism * Add etcd as a service discovery mechanism * Add etcd as a service discovery mechanism * Add etcd as a service discovery mechanism * Add etcd as a service discovery mechanism * Add etcd as a service discovery mechanism * Add etcd as a service discovery mechanism * Add etcd as a service discovery mechanism * Add etcd as a service discovery mechanism * Add etcd as a service discovery mechanism * Add etcd as a service discovery mechanism * Add etcd as a service discovery mechanism * Add etcd as a service discovery mechanism * Add etcd as a service discovery mechanism * Add etcd as a service discovery mechanism * Add etcd as a service discovery mechanism * Add etcd as a service discovery mechanism * Add etcd as a service discovery mechanism * Add etcd as a service discovery mechanism * Add etcd as a service discovery mechanism * Add etcd as a service discovery mechanism * Add etcd as a service discovery mechanism * Add etcd as a service discovery mechanism * Add etcd as a service discovery mechanism * Add etcd as a service discovery mechanism * Add etcd as a service discovery mechanism * Add etcd as a service discovery mechanism * Add etcd as a service discovery mechanism * Add etcd as a service discovery mechanism --- .env | 2 +- config/discovery.yml | 13 +++++ config/share.yml | 1 - config/zookeeper.yml | 6 --- docker-compose.yml | 20 +++++++ go.mod | 10 ++-- go.sum | 19 +++++-- internal/api/init.go | 19 +++---- internal/api/router.go | 2 +- internal/msggateway/client.go | 1 + internal/msggateway/hub_server.go | 2 +- internal/msggateway/init.go | 8 +-- internal/msggateway/n_ws_server.go | 7 ++- internal/msgtransfer/init.go | 16 +++--- .../msgtransfer/online_history_msg_handler.go | 2 +- .../online_msg_to_mongo_handler.go | 2 +- internal/push/onlinepusher.go | 22 ++++---- internal/push/push.go | 2 +- internal/push/push_handler.go | 2 +- internal/rpc/auth/auth.go | 8 +-- internal/rpc/conversation/conversaion.go | 2 +- internal/rpc/friend/friend.go | 9 ++-- internal/rpc/group/group.go | 2 +- internal/rpc/msg/server.go | 2 +- internal/rpc/third/third.go | 2 +- internal/rpc/user/user.go | 2 +- internal/tools/cron_task.go | 8 +-- pkg/common/cmd/api.go | 4 +- pkg/common/cmd/auth.go | 4 +- pkg/common/cmd/constant.go | 8 +-- pkg/common/cmd/conversation.go | 4 +- pkg/common/cmd/cron_task.go | 2 +- pkg/common/cmd/friend.go | 4 +- pkg/common/cmd/group.go | 4 +- pkg/common/cmd/msg.go | 4 +- pkg/common/cmd/msg_gateway.go | 2 +- pkg/common/cmd/msg_transfer.go | 2 +- pkg/common/cmd/push.go | 4 +- pkg/common/cmd/third.go | 4 +- pkg/common/cmd/user.go | 4 +- pkg/common/config/config.go | 14 ++++- .../discoveryregister/discoveryregister.go | 34 ++++++------ pkg/common/discoveryregister/etcd/doc.go | 15 ++++++ .../discoveryregister/zookeeper/zookeeper.go | 44 --------------- pkg/common/startrpc/start.go | 4 +- tools/check-component/main.go | 54 ++++++++++++------- 46 files changed, 224 insertions(+), 182 deletions(-) create mode 100644 config/discovery.yml delete mode 100644 config/zookeeper.yml create mode 100644 pkg/common/discoveryregister/etcd/doc.go delete mode 100644 pkg/common/discoveryregister/zookeeper/zookeeper.go diff --git a/.env b/.env index d3ae0426a9..1e7b1e11a7 100644 --- a/.env +++ b/.env @@ -4,7 +4,7 @@ REDIS_IMAGE=redis:7.0.0 ZOOKEEPER_IMAGE=bitnami/zookeeper:3.8 KAFKA_IMAGE=bitnami/kafka:3.5.1 MINIO_IMAGE=minio/minio:RELEASE.2024-01-11T07-46-16Z - +ETCD_IMAGE=quay.io/coreos/etcd:v3.5.13 OPENIM_WEB_FRONT_IMAGE=openim/openim-web-front:release-v3.5.1 OPENIM_ADMIN_FRONT_IMAGE=openim/openim-admin-front:release-v1.7 diff --git a/config/discovery.yml b/config/discovery.yml new file mode 100644 index 0000000000..3d96ff9b66 --- /dev/null +++ b/config/discovery.yml @@ -0,0 +1,13 @@ +enable: "etcd" +etcd: + rootDirectory: openim + address: [ localhost:12379 ] + username: '' + password: '' + +zookeeper: + schema: openim + address: [ localhost:12181 ] + username: '' + password: '' + diff --git a/config/share.yml b/config/share.yml index 2abbb77a0f..fc97b6a1ff 100644 --- a/config/share.yml +++ b/config/share.yml @@ -1,5 +1,4 @@ secret: openIM123 -env: zookeeper rpcRegisterName: user: user friend: friend diff --git a/config/zookeeper.yml b/config/zookeeper.yml deleted file mode 100644 index 33f52d7ca7..0000000000 --- a/config/zookeeper.yml +++ /dev/null @@ -1,6 +0,0 @@ - -schema: openim -address: [ localhost:12181 ] -username: '' -password: '' - diff --git a/docker-compose.yml b/docker-compose.yml index aeb53a4170..d72c1a2fa4 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -58,6 +58,26 @@ services: networks: - openim + etcd: + image: "${ETCD_IMAGE}" + container_name: etcd + ports: + - "12379:2379" + - "12380:2380" + environment: + - ETCD_NAME=s1 + - ETCD_DATA_DIR=/etcd-data + - ETCD_LISTEN_CLIENT_URLS=http://0.0.0.0:2379 + - ETCD_ADVERTISE_CLIENT_URLS=http://0.0.0.0:2379 + - ETCD_LISTEN_PEER_URLS=http://0.0.0.0:2380 + - ETCD_INITIAL_ADVERTISE_PEER_URLS=http://0.0.0.0:2380 + - ETCD_INITIAL_CLUSTER=s1=http://0.0.0.0:2380 + - ETCD_INITIAL_CLUSTER_TOKEN=tkn + - ETCD_INITIAL_CLUSTER_STATE=new + restart: always + networks: + - openim + kafka: image: "${KAFKA_IMAGE}" container_name: kafka diff --git a/go.mod b/go.mod index b522065da4..e9777eaa8b 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,7 @@ require ( github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible // indirect github.com/mitchellh/mapstructure v1.5.0 github.com/openimsdk/protocol v0.0.65 - github.com/openimsdk/tools v0.0.49-alpha.2 + github.com/openimsdk/tools v0.0.49-alpha.18 github.com/pkg/errors v0.9.1 // indirect github.com/prometheus/client_golang v1.18.0 github.com/stretchr/testify v1.9.0 @@ -44,7 +44,6 @@ require ( golang.org/x/sync v0.6.0 ) - require ( cloud.google.com/go v0.112.0 // indirect cloud.google.com/go/compute v1.23.3 // indirect @@ -59,6 +58,8 @@ require ( github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect github.com/clbanning/mxj v1.8.4 // 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/dustin/go-humanize v1.0.1 // indirect @@ -75,7 +76,7 @@ require ( github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-zookeeper/zk v1.0.3 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect - github.com/golang/protobuf v1.5.3 // indirect + github.com/golang/protobuf v1.5.4 // indirect github.com/golang/snappy v0.0.4 // indirect github.com/google/go-querystring v1.1.0 // indirect github.com/google/s2a-go v0.1.7 // indirect @@ -138,6 +139,9 @@ require ( github.com/xdg-go/stringprep v1.0.4 // indirect github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect 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.opencensus.io v0.24.0 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.47.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.47.0 // indirect diff --git a/go.sum b/go.sum index e2ecf7284e..3acb4709c6 100644 --- a/go.sum +++ b/go.sum @@ -47,6 +47,10 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/xds/go v0.0.0-20231128003011-0fa0005c9caa h1:jQCWAUqqlij9Pgj2i/PB79y4KOPYVyFYdROxgaCwdTQ= github.com/cncf/xds/go v0.0.0-20231128003011-0fa0005c9caa/go.mod h1:x/1Gn8zydmfq8dk6e9PdstVsDgu9RuyIIJqAaF//0IM= +github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM= +github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +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/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= @@ -111,6 +115,7 @@ 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/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= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= @@ -132,8 +137,8 @@ github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= -github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +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/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= @@ -283,8 +288,8 @@ github.com/openimsdk/gomake v0.0.13 h1:xLDe/moqgWpRoptHzI4packAWzs4C16b+sVY+txNJ github.com/openimsdk/gomake v0.0.13/go.mod h1:PndCozNc2IsQIciyn9mvEblYWZwJmAI+06z94EY+csI= github.com/openimsdk/protocol v0.0.65 h1:SPT9qyUsFRTTKSKb/FjpS+xr6sxz/Kbnu+su1bxYagc= github.com/openimsdk/protocol v0.0.65/go.mod h1:OZQA9FR55lseYoN2Ql1XAHYKHJGu7OMNkUbuekrKCM8= -github.com/openimsdk/tools v0.0.49-alpha.2 h1:8IfV6o2ySU7C54sh/MG7ctEp1h3lSNe03OCUDWSk5Ws= -github.com/openimsdk/tools v0.0.49-alpha.2/go.mod h1:P4oGP1Pd+d4ctbLD5U/XQTgl8yu8Hd3skx640Fr69ko= +github.com/openimsdk/tools v0.0.49-alpha.18 h1:ARQeCiRmExvtB6XYItegThuV63JGOTxddwhSLHYXd78= +github.com/openimsdk/tools v0.0.49-alpha.18/go.mod h1:g7mkHXYUPi0/8aAX8VPMHpnb3hqdV69Jph+bXOGvvNM= 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/pierrec/lz4/v4 v4.1.21 h1:yOVMLb6qSIDP67pl/5F7RepeKYu/VmTyEXvuMI5d9mQ= @@ -378,6 +383,12 @@ github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9dec github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= +go.etcd.io/etcd/api/v3 v3.5.13 h1:8WXU2/NBge6AUF1K1gOexB6e07NgsN1hXK0rSTtgSp4= +go.etcd.io/etcd/api/v3 v3.5.13/go.mod h1:gBqlqkcMMZMVTMm4NDZloEVJzxQOQIls8splbqBDa0c= +go.etcd.io/etcd/client/pkg/v3 v3.5.13 h1:RVZSAnWWWiI5IrYAXjQorajncORbS0zI48LQlE2kQWg= +go.etcd.io/etcd/client/pkg/v3 v3.5.13/go.mod h1:XxHT4u1qU12E2+po+UVPrEeL94Um6zL58ppuJWXSAB8= +go.etcd.io/etcd/client/v3 v3.5.13 h1:o0fHTNJLeO0MyVbc7I3fsCf6nrOqn5d+diSarKnB2js= +go.etcd.io/etcd/client/v3 v3.5.13/go.mod h1:cqiAeY8b5DEEcpxvgWKsbLIWNM/8Wy2xJSDMtioMcoI= go.mongodb.org/mongo-driver v1.14.0 h1:P98w8egYRjYe3XDjxhYJagTokP/H6HzlsnojRgZRd80= go.mongodb.org/mongo-driver v1.14.0/go.mod h1:Vzb0Mk/pa7e6cWw85R4F/endUC3u0U9jGcNU603k65c= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= diff --git a/internal/api/init.go b/internal/api/init.go index 6e784da9a9..b49a145696 100644 --- a/internal/api/init.go +++ b/internal/api/init.go @@ -38,20 +38,17 @@ import ( ) type Config struct { - RpcConfig config.API - MongodbConfig config.Mongo - ZookeeperConfig config.ZooKeeper - NotificationConfig config.Notification - Share config.Share - MinioConfig config.Minio + API config.API + Share config.Share + Discovery config.Discovery } func Start(ctx context.Context, index int, config *Config) error { - apiPort, err := datautil.GetElemByIndex(config.RpcConfig.Api.Ports, index) + apiPort, err := datautil.GetElemByIndex(config.API.Api.Ports, index) if err != nil { return err } - prometheusPort, err := datautil.GetElemByIndex(config.RpcConfig.Prometheus.Ports, index) + prometheusPort, err := datautil.GetElemByIndex(config.API.Prometheus.Ports, index) if err != nil { return err } @@ -59,7 +56,7 @@ func Start(ctx context.Context, index int, config *Config) error { var client discovery.SvcDiscoveryRegistry // Determine whether zk is passed according to whether it is a clustered deployment - client, err = kdisc.NewDiscoveryRegister(&config.ZookeeperConfig, &config.Share) + client, err = kdisc.NewDiscoveryRegister(&config.Discovery, &config.Share) if err != nil { return errs.WrapMsg(err, "failed to register discovery service") } @@ -70,7 +67,7 @@ func Start(ctx context.Context, index int, config *Config) error { ) router := newGinRouter(client, config) - if config.RpcConfig.Prometheus.Enable { + if config.API.Prometheus.Enable { go func() { p := ginprom.NewPrometheus("app", prommetrics.GetGinCusMetrics("Api")) p.SetListenAddress(fmt.Sprintf(":%d", prometheusPort)) @@ -81,7 +78,7 @@ func Start(ctx context.Context, index int, config *Config) error { }() } - address := net.JoinHostPort(network.GetListenIP(config.RpcConfig.Api.ListenIP), strconv.Itoa(apiPort)) + address := net.JoinHostPort(network.GetListenIP(config.API.Api.ListenIP), strconv.Itoa(apiPort)) server := http.Server{Addr: address, Handler: router} log.CInfo(ctx, "API server is initializing", "address", address, "apiPort", apiPort, "prometheusPort", prometheusPort) diff --git a/internal/api/router.go b/internal/api/router.go index bd2de99db7..1fbb33b092 100644 --- a/internal/api/router.go +++ b/internal/api/router.go @@ -34,7 +34,7 @@ func newGinRouter(disCov discovery.SvcDiscoveryRegistry, config *Config) *gin.En messageRpc := rpcclient.NewMessage(disCov, config.Share.RpcRegisterName.Msg) conversationRpc := rpcclient.NewConversation(disCov, config.Share.RpcRegisterName.Conversation) authRpc := rpcclient.NewAuth(disCov, config.Share.RpcRegisterName.Auth) - thirdRpc := rpcclient.NewThird(disCov, config.Share.RpcRegisterName.Third, config.RpcConfig.Prometheus.GrafanaURL) + thirdRpc := rpcclient.NewThird(disCov, config.Share.RpcRegisterName.Third, config.API.Prometheus.GrafanaURL) u := NewUserApi(*userRpc) m := NewMessageApi(messageRpc, userRpc, config.Share.IMAdminUserID) diff --git a/internal/msggateway/client.go b/internal/msggateway/client.go index af869dd850..0581a025b4 100644 --- a/internal/msggateway/client.go +++ b/internal/msggateway/client.go @@ -286,6 +286,7 @@ func (c *Client) KickOnlineMessage() error { resp := Resp{ ReqIdentifier: WSKickOnlineMsg, } + log.ZDebug(c.ctx, "KickOnlineMessage debug ") err := c.writeBinaryMsg(resp) c.close() return err diff --git a/internal/msggateway/hub_server.go b/internal/msggateway/hub_server.go index bfe81b6024..f9bb699ed9 100644 --- a/internal/msggateway/hub_server.go +++ b/internal/msggateway/hub_server.go @@ -35,7 +35,7 @@ func (s *Server) InitServer(ctx context.Context, config *Config, disCov discover } func (s *Server) Start(ctx context.Context, index int, conf *Config) error { - return startrpc.Start(ctx, &conf.ZookeeperConfig, &conf.MsgGateway.Prometheus, conf.MsgGateway.ListenIP, + return startrpc.Start(ctx, &conf.Discovery, &conf.MsgGateway.Prometheus, conf.MsgGateway.ListenIP, conf.MsgGateway.RPC.RegisterIP, conf.MsgGateway.RPC.Ports, index, conf.Share.RpcRegisterName.MessageGateway, diff --git a/internal/msggateway/init.go b/internal/msggateway/init.go index 727ade0afd..ef24d1bf93 100644 --- a/internal/msggateway/init.go +++ b/internal/msggateway/init.go @@ -24,10 +24,10 @@ import ( ) type Config struct { - MsgGateway config.MsgGateway - ZookeeperConfig config.ZooKeeper - Share config.Share - WebhooksConfig config.Webhooks + MsgGateway config.MsgGateway + Share config.Share + WebhooksConfig config.Webhooks + Discovery config.Discovery } // Start run ws server. diff --git a/internal/msggateway/n_ws_server.go b/internal/msggateway/n_ws_server.go index cf607d4707..defec16df1 100644 --- a/internal/msggateway/n_ws_server.go +++ b/internal/msggateway/n_ws_server.go @@ -211,7 +211,8 @@ func (ws *WsServer) sendUserOnlineInfoToOtherNode(ctx context.Context, client *C // Online push user online message to other node for _, v := range conns { - v := v // safe closure var + v := v + log.ZDebug(ctx, " sendUserOnlineInfoToOtherNode conn ", "target", v.Target()) if v.Target() == ws.disCov.GetSelfConnTarget() { log.ZDebug(ctx, "Filter out this node", "node", v.Target()) continue @@ -267,7 +268,9 @@ func (ws *WsServer) registerClient(client *Client) { } wg := sync.WaitGroup{} - if ws.msgGatewayConfig.Share.Env == "zookeeper" { + log.ZDebug(client.ctx, "ws.msgGatewayConfig.Discovery.Enable", ws.msgGatewayConfig.Discovery.Enable) + + if ws.msgGatewayConfig.Discovery.Enable != "k8s" { wg.Add(1) go func() { defer wg.Done() diff --git a/internal/msgtransfer/init.go b/internal/msgtransfer/init.go index 68d953e902..3384b84937 100644 --- a/internal/msgtransfer/init.go +++ b/internal/msgtransfer/init.go @@ -56,13 +56,13 @@ type MsgTransfer struct { } type Config struct { - MsgTransfer config.MsgTransfer - RedisConfig config.Redis - MongodbConfig config.Mongo - KafkaConfig config.Kafka - ZookeeperConfig config.ZooKeeper - Share config.Share - WebhooksConfig config.Webhooks + MsgTransfer config.MsgTransfer + RedisConfig config.Redis + MongodbConfig config.Mongo + KafkaConfig config.Kafka + Share config.Share + WebhooksConfig config.Webhooks + Discovery config.Discovery } func Start(ctx context.Context, index int, config *Config) error { @@ -76,7 +76,7 @@ func Start(ctx context.Context, index int, config *Config) error { if err != nil { return err } - client, err := kdisc.NewDiscoveryRegister(&config.ZookeeperConfig, &config.Share) + client, err := kdisc.NewDiscoveryRegister(&config.Discovery, &config.Share) if err != nil { return err } diff --git a/internal/msgtransfer/online_history_msg_handler.go b/internal/msgtransfer/online_history_msg_handler.go index 8691e92ab6..df2660804d 100644 --- a/internal/msgtransfer/online_history_msg_handler.go +++ b/internal/msgtransfer/online_history_msg_handler.go @@ -83,7 +83,7 @@ type OnlineHistoryRedisConsumerHandler struct { func NewOnlineHistoryRedisConsumerHandler(kafkaConf *config.Kafka, database controller.CommonMsgDatabase, conversationRpcClient *rpcclient.ConversationRpcClient, groupRpcClient *rpcclient.GroupRpcClient) (*OnlineHistoryRedisConsumerHandler, error) { - historyConsumerGroup, err := kafka.NewMConsumerGroup(kafkaConf.Build(), kafkaConf.ToRedisGroupID, []string{kafkaConf.ToRedisTopic}) + historyConsumerGroup, err := kafka.NewMConsumerGroup(kafkaConf.Build(), kafkaConf.ToRedisGroupID, []string{kafkaConf.ToRedisTopic}, true) if err != nil { return nil, err } diff --git a/internal/msgtransfer/online_msg_to_mongo_handler.go b/internal/msgtransfer/online_msg_to_mongo_handler.go index 978302e768..c9c0358935 100644 --- a/internal/msgtransfer/online_msg_to_mongo_handler.go +++ b/internal/msgtransfer/online_msg_to_mongo_handler.go @@ -33,7 +33,7 @@ type OnlineHistoryMongoConsumerHandler struct { } func NewOnlineHistoryMongoConsumerHandler(kafkaConf *config.Kafka, database controller.CommonMsgDatabase) (*OnlineHistoryMongoConsumerHandler, error) { - historyConsumerGroup, err := kafka.NewMConsumerGroup(kafkaConf.Build(), kafkaConf.ToMongoGroupID, []string{kafkaConf.ToMongoTopic}) + historyConsumerGroup, err := kafka.NewMConsumerGroup(kafkaConf.Build(), kafkaConf.ToMongoGroupID, []string{kafkaConf.ToMongoTopic}, true) if err != nil { return nil, err } diff --git a/internal/push/onlinepusher.go b/internal/push/onlinepusher.go index 30bdf3e2ed..a61399fb6b 100644 --- a/internal/push/onlinepusher.go +++ b/internal/push/onlinepusher.go @@ -12,11 +12,6 @@ import ( "sync" ) -const ( - KUBERNETES = "k8s" - ZOOKEEPER = "zookeeper" -) - type OnlinePusher interface { GetConnsAndOnlinePush(ctx context.Context, msg *sdkws.MsgData, pushToUserIDs []string) (wsResults []*msggateway.SingleMsgToUserResults, err error) @@ -42,10 +37,12 @@ func (u emptyOnlinePUsher) GetOnlinePushFailedUserIDs(ctx context.Context, msg * } func NewOnlinePusher(disCov discovery.SvcDiscoveryRegistry, config *Config) OnlinePusher { - switch config.Share.Env { - case KUBERNETES: + switch config.Discovery.Enable { + case "k8s": return NewK8sStaticConsistentHash(disCov, config) - case ZOOKEEPER: + case "zookeeper": + return NewDefaultAllNode(disCov, config) + case "etcd": return NewDefaultAllNode(disCov, config) default: return newEmptyOnlinePUsher() @@ -64,7 +61,12 @@ func NewDefaultAllNode(disCov discovery.SvcDiscoveryRegistry, config *Config) *D func (d *DefaultAllNode) GetConnsAndOnlinePush(ctx context.Context, msg *sdkws.MsgData, pushToUserIDs []string) (wsResults []*msggateway.SingleMsgToUserResults, err error) { conns, err := d.disCov.GetConns(ctx, d.config.Share.RpcRegisterName.MessageGateway) - log.ZDebug(ctx, "get gateway conn", "conn length", len(conns)) + if len(conns) == 0 { + log.ZWarn(ctx, "get gateway conn 0 ", nil) + } else { + log.ZDebug(ctx, "get gateway conn", "conn length", len(conns)) + } + if err != nil { return nil, err } @@ -85,10 +87,12 @@ func (d *DefaultAllNode) GetConnsAndOnlinePush(ctx context.Context, msg *sdkws.M // Online push message for _, conn := range conns { conn := conn // loop var safe + ctx := ctx wg.Go(func() error { msgClient := msggateway.NewMsgGatewayClient(conn) reply, err := msgClient.SuperGroupOnlineBatchPushOneMsg(ctx, input) if err != nil { + log.ZError(ctx, "SuperGroupOnlineBatchPushOneMsg ", err, "req:", input.String()) return nil } diff --git a/internal/push/push.go b/internal/push/push.go index 18012a8646..2e5c4e5265 100644 --- a/internal/push/push.go +++ b/internal/push/push.go @@ -24,11 +24,11 @@ type Config struct { RedisConfig config.Redis MongodbConfig config.Mongo KafkaConfig config.Kafka - ZookeeperConfig config.ZooKeeper NotificationConfig config.Notification Share config.Share WebhooksConfig config.Webhooks LocalCacheConfig config.LocalCache + Discovery config.Discovery } func (p pushServer) PushMsg(ctx context.Context, req *pbpush.PushMsgReq) (*pbpush.PushMsgResp, error) { diff --git a/internal/push/push_handler.go b/internal/push/push_handler.go index 3a9a696f64..bf0ede375c 100644 --- a/internal/push/push_handler.go +++ b/internal/push/push_handler.go @@ -60,7 +60,7 @@ func NewConsumerHandler(config *Config, offlinePusher offlinepush.OfflinePusher, var consumerHandler ConsumerHandler var err error consumerHandler.pushConsumerGroup, err = kafka.NewMConsumerGroup(config.KafkaConfig.Build(), config.KafkaConfig.ToPushGroupID, - []string{config.KafkaConfig.ToPushTopic}) + []string{config.KafkaConfig.ToPushTopic}, true) if err != nil { return nil, err } diff --git a/internal/rpc/auth/auth.go b/internal/rpc/auth/auth.go index c6d236b21b..ddb655398d 100644 --- a/internal/rpc/auth/auth.go +++ b/internal/rpc/auth/auth.go @@ -45,10 +45,10 @@ type authServer struct { } type Config struct { - RpcConfig config.Auth - RedisConfig config.Redis - ZookeeperConfig config.ZooKeeper - Share config.Share + RpcConfig config.Auth + RedisConfig config.Redis + Share config.Share + Discovery config.Discovery } func Start(ctx context.Context, config *Config, client discovery.SvcDiscoveryRegistry, server *grpc.Server) error { diff --git a/internal/rpc/conversation/conversaion.go b/internal/rpc/conversation/conversaion.go index 96d2a403f6..4c7828610f 100644 --- a/internal/rpc/conversation/conversaion.go +++ b/internal/rpc/conversation/conversaion.go @@ -51,10 +51,10 @@ type Config struct { RpcConfig config.Conversation RedisConfig config.Redis MongodbConfig config.Mongo - ZookeeperConfig config.ZooKeeper NotificationConfig config.Notification Share config.Share LocalCacheConfig config.LocalCache + Discovery config.Discovery } func Start(ctx context.Context, config *Config, client discovery.SvcDiscoveryRegistry, server *grpc.Server) error { diff --git a/internal/rpc/friend/friend.go b/internal/rpc/friend/friend.go index bffda3c04e..b49490f264 100644 --- a/internal/rpc/friend/friend.go +++ b/internal/rpc/friend/friend.go @@ -50,14 +50,15 @@ type friendServer struct { } type Config struct { - RpcConfig config.Friend - RedisConfig config.Redis - MongodbConfig config.Mongo - ZookeeperConfig config.ZooKeeper + RpcConfig config.Friend + RedisConfig config.Redis + MongodbConfig config.Mongo + //ZookeeperConfig config.ZooKeeper NotificationConfig config.Notification Share config.Share WebhooksConfig config.Webhooks LocalCacheConfig config.LocalCache + Discovery config.Discovery } func Start(ctx context.Context, config *Config, client discovery.SvcDiscoveryRegistry, server *grpc.Server) error { diff --git a/internal/rpc/group/group.go b/internal/rpc/group/group.go index 13bd7f9beb..551554c236 100644 --- a/internal/rpc/group/group.go +++ b/internal/rpc/group/group.go @@ -68,11 +68,11 @@ type Config struct { RpcConfig config.Group RedisConfig config.Redis MongodbConfig config.Mongo - ZookeeperConfig config.ZooKeeper NotificationConfig config.Notification Share config.Share WebhooksConfig config.Webhooks LocalCacheConfig config.LocalCache + Discovery config.Discovery } func Start(ctx context.Context, config *Config, client discovery.SvcDiscoveryRegistry, server *grpc.Server) error { diff --git a/internal/rpc/msg/server.go b/internal/rpc/msg/server.go index 3f4df8d4b7..5d7c0b297b 100644 --- a/internal/rpc/msg/server.go +++ b/internal/rpc/msg/server.go @@ -59,11 +59,11 @@ type ( RedisConfig config.Redis MongodbConfig config.Mongo KafkaConfig config.Kafka - ZookeeperConfig config.ZooKeeper NotificationConfig config.Notification Share config.Share WebhooksConfig config.Webhooks LocalCacheConfig config.LocalCache + Discovery config.Discovery } ) diff --git a/internal/rpc/third/third.go b/internal/rpc/third/third.go index 9bf8cafa9e..a3d9085d31 100644 --- a/internal/rpc/third/third.go +++ b/internal/rpc/third/third.go @@ -46,11 +46,11 @@ type Config struct { RpcConfig config.Third RedisConfig config.Redis MongodbConfig config.Mongo - ZookeeperConfig config.ZooKeeper NotificationConfig config.Notification Share config.Share MinioConfig config.Minio LocalCacheConfig config.LocalCache + Discovery config.Discovery } func Start(ctx context.Context, config *Config, client discovery.SvcDiscoveryRegistry, server *grpc.Server) error { diff --git a/internal/rpc/user/user.go b/internal/rpc/user/user.go index c453ac9f85..a28fa24e28 100644 --- a/internal/rpc/user/user.go +++ b/internal/rpc/user/user.go @@ -61,11 +61,11 @@ type Config struct { RedisConfig config.Redis MongodbConfig config.Mongo KafkaConfig config.Kafka - ZookeeperConfig config.ZooKeeper NotificationConfig config.Notification Share config.Share WebhooksConfig config.Webhooks LocalCacheConfig config.LocalCache + Discovery config.Discovery } func Start(ctx context.Context, config *Config, client registry.SvcDiscoveryRegistry, server *grpc.Server) error { diff --git a/internal/tools/cron_task.go b/internal/tools/cron_task.go index 20baeffaf0..bf037b694b 100644 --- a/internal/tools/cron_task.go +++ b/internal/tools/cron_task.go @@ -33,9 +33,9 @@ import ( ) type CronTaskConfig struct { - CronTask config.CronTask - ZookeeperConfig config.ZooKeeper - Share config.Share + CronTask config.CronTask + Share config.Share + Discovery config.Discovery } func Start(ctx context.Context, config *CronTaskConfig) error { @@ -43,7 +43,7 @@ func Start(ctx context.Context, config *CronTaskConfig) error { if config.CronTask.RetainChatRecords < 1 { return errs.New("msg destruct time must be greater than 1").Wrap() } - client, err := kdisc.NewDiscoveryRegister(&config.ZookeeperConfig, &config.Share) + client, err := kdisc.NewDiscoveryRegister(&config.Discovery, &config.Share) if err != nil { return errs.WrapMsg(err, "failed to register discovery service") } diff --git a/pkg/common/cmd/api.go b/pkg/common/cmd/api.go index 022fb10978..ecdb0dd3ad 100644 --- a/pkg/common/cmd/api.go +++ b/pkg/common/cmd/api.go @@ -33,9 +33,9 @@ func NewApiCmd() *ApiCmd { var apiConfig api.Config ret := &ApiCmd{apiConfig: &apiConfig} ret.configMap = map[string]any{ - OpenIMAPICfgFileName: &apiConfig.RpcConfig, - ZookeeperConfigFileName: &apiConfig.ZookeeperConfig, + OpenIMAPICfgFileName: &apiConfig.API, ShareFileName: &apiConfig.Share, + DiscoveryConfigFilename: &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/auth.go b/pkg/common/cmd/auth.go index 5ed02ffd00..7d75a7da65 100644 --- a/pkg/common/cmd/auth.go +++ b/pkg/common/cmd/auth.go @@ -36,8 +36,8 @@ func NewAuthRpcCmd() *AuthRpcCmd { ret.configMap = map[string]any{ OpenIMRPCAuthCfgFileName: &authConfig.RpcConfig, RedisConfigFileName: &authConfig.RedisConfig, - ZookeeperConfigFileName: &authConfig.ZookeeperConfig, ShareFileName: &authConfig.Share, + DiscoveryConfigFilename: &authConfig.Discovery, } ret.RootCmd = NewRootCmd(program.GetProcessName(), WithConfigMap(ret.configMap)) ret.ctx = context.WithValue(context.Background(), "version", config.Version) @@ -53,7 +53,7 @@ func (a *AuthRpcCmd) Exec() error { } func (a *AuthRpcCmd) runE() error { - return startrpc.Start(a.ctx, &a.authConfig.ZookeeperConfig, &a.authConfig.RpcConfig.Prometheus, a.authConfig.RpcConfig.RPC.ListenIP, + return startrpc.Start(a.ctx, &a.authConfig.Discovery, &a.authConfig.RpcConfig.Prometheus, a.authConfig.RpcConfig.RPC.ListenIP, a.authConfig.RpcConfig.RPC.RegisterIP, a.authConfig.RpcConfig.RPC.Ports, a.Index(), a.authConfig.Share.RpcRegisterName.Auth, &a.authConfig.Share, a.authConfig, auth.Start) } diff --git a/pkg/common/cmd/constant.go b/pkg/common/cmd/constant.go index 55eb4a069f..45dbcafda2 100644 --- a/pkg/common/cmd/constant.go +++ b/pkg/common/cmd/constant.go @@ -26,7 +26,6 @@ var ( LocalCacheConfigFileName string KafkaConfigFileName string RedisConfigFileName string - ZookeeperConfigFileName string MongodbConfigFileName string MinioConfigFileName string LogConfigFileName string @@ -42,6 +41,7 @@ var ( OpenIMRPCMsgCfgFileName string OpenIMRPCThirdCfgFileName string OpenIMRPCUserCfgFileName string + DiscoveryConfigFilename string ) var ConfigEnvPrefixMap map[string]string @@ -54,7 +54,6 @@ func init() { LocalCacheConfigFileName = "local-cache.yml" KafkaConfigFileName = "kafka.yml" RedisConfigFileName = "redis.yml" - ZookeeperConfigFileName = "zookeeper.yml" MongodbConfigFileName = "mongodb.yml" MinioConfigFileName = "minio.yml" LogConfigFileName = "log.yml" @@ -70,16 +69,17 @@ func init() { OpenIMRPCMsgCfgFileName = "openim-rpc-msg.yml" OpenIMRPCThirdCfgFileName = "openim-rpc-third.yml" OpenIMRPCUserCfgFileName = "openim-rpc-user.yml" + DiscoveryConfigFilename = "discovery.yml" ConfigEnvPrefixMap = make(map[string]string) fileNames := []string{ FileName, NotificationFileName, ShareFileName, WebhooksConfigFileName, - KafkaConfigFileName, RedisConfigFileName, ZookeeperConfigFileName, + KafkaConfigFileName, RedisConfigFileName, MongodbConfigFileName, MinioConfigFileName, LogConfigFileName, OpenIMAPICfgFileName, OpenIMCronTaskCfgFileName, OpenIMMsgGatewayCfgFileName, OpenIMMsgTransferCfgFileName, OpenIMPushCfgFileName, OpenIMRPCAuthCfgFileName, OpenIMRPCConversationCfgFileName, OpenIMRPCFriendCfgFileName, OpenIMRPCGroupCfgFileName, - OpenIMRPCMsgCfgFileName, OpenIMRPCThirdCfgFileName, OpenIMRPCUserCfgFileName, + OpenIMRPCMsgCfgFileName, OpenIMRPCThirdCfgFileName, OpenIMRPCUserCfgFileName, DiscoveryConfigFilename, } for _, fileName := range fileNames { diff --git a/pkg/common/cmd/conversation.go b/pkg/common/cmd/conversation.go index 0a617c7296..57ffa52bc4 100644 --- a/pkg/common/cmd/conversation.go +++ b/pkg/common/cmd/conversation.go @@ -36,11 +36,11 @@ func NewConversationRpcCmd() *ConversationRpcCmd { ret.configMap = map[string]any{ OpenIMRPCConversationCfgFileName: &conversationConfig.RpcConfig, RedisConfigFileName: &conversationConfig.RedisConfig, - ZookeeperConfigFileName: &conversationConfig.ZookeeperConfig, MongodbConfigFileName: &conversationConfig.MongodbConfig, ShareFileName: &conversationConfig.Share, NotificationFileName: &conversationConfig.NotificationConfig, LocalCacheConfigFileName: &conversationConfig.LocalCacheConfig, + DiscoveryConfigFilename: &conversationConfig.Discovery, } ret.RootCmd = NewRootCmd(program.GetProcessName(), WithConfigMap(ret.configMap)) ret.ctx = context.WithValue(context.Background(), "version", config.Version) @@ -55,7 +55,7 @@ func (a *ConversationRpcCmd) Exec() error { } func (a *ConversationRpcCmd) runE() error { - return startrpc.Start(a.ctx, &a.conversationConfig.ZookeeperConfig, &a.conversationConfig.RpcConfig.Prometheus, a.conversationConfig.RpcConfig.RPC.ListenIP, + return startrpc.Start(a.ctx, &a.conversationConfig.Discovery, &a.conversationConfig.RpcConfig.Prometheus, a.conversationConfig.RpcConfig.RPC.ListenIP, a.conversationConfig.RpcConfig.RPC.RegisterIP, a.conversationConfig.RpcConfig.RPC.Ports, a.Index(), a.conversationConfig.Share.RpcRegisterName.Conversation, &a.conversationConfig.Share, a.conversationConfig, conversation.Start) } diff --git a/pkg/common/cmd/cron_task.go b/pkg/common/cmd/cron_task.go index be26f5af36..fd44475246 100644 --- a/pkg/common/cmd/cron_task.go +++ b/pkg/common/cmd/cron_task.go @@ -34,8 +34,8 @@ func NewCronTaskCmd() *CronTaskCmd { ret := &CronTaskCmd{cronTaskConfig: &cronTaskConfig} ret.configMap = map[string]any{ OpenIMCronTaskCfgFileName: &cronTaskConfig.CronTask, - ZookeeperConfigFileName: &cronTaskConfig.ZookeeperConfig, ShareFileName: &cronTaskConfig.Share, + DiscoveryConfigFilename: &cronTaskConfig.Discovery, } ret.RootCmd = NewRootCmd(program.GetProcessName(), WithConfigMap(ret.configMap)) ret.ctx = context.WithValue(context.Background(), "version", config.Version) diff --git a/pkg/common/cmd/friend.go b/pkg/common/cmd/friend.go index b8d46f77ef..8be1f77458 100644 --- a/pkg/common/cmd/friend.go +++ b/pkg/common/cmd/friend.go @@ -36,12 +36,12 @@ func NewFriendRpcCmd() *FriendRpcCmd { ret.configMap = map[string]any{ OpenIMRPCFriendCfgFileName: &friendConfig.RpcConfig, RedisConfigFileName: &friendConfig.RedisConfig, - ZookeeperConfigFileName: &friendConfig.ZookeeperConfig, MongodbConfigFileName: &friendConfig.MongodbConfig, ShareFileName: &friendConfig.Share, NotificationFileName: &friendConfig.NotificationConfig, WebhooksConfigFileName: &friendConfig.WebhooksConfig, LocalCacheConfigFileName: &friendConfig.LocalCacheConfig, + DiscoveryConfigFilename: &friendConfig.Discovery, } ret.RootCmd = NewRootCmd(program.GetProcessName(), WithConfigMap(ret.configMap)) ret.ctx = context.WithValue(context.Background(), "version", config.Version) @@ -56,7 +56,7 @@ func (a *FriendRpcCmd) Exec() error { } func (a *FriendRpcCmd) runE() error { - return startrpc.Start(a.ctx, &a.friendConfig.ZookeeperConfig, &a.friendConfig.RpcConfig.Prometheus, a.friendConfig.RpcConfig.RPC.ListenIP, + return startrpc.Start(a.ctx, &a.friendConfig.Discovery, &a.friendConfig.RpcConfig.Prometheus, a.friendConfig.RpcConfig.RPC.ListenIP, a.friendConfig.RpcConfig.RPC.RegisterIP, a.friendConfig.RpcConfig.RPC.Ports, a.Index(), a.friendConfig.Share.RpcRegisterName.Friend, &a.friendConfig.Share, a.friendConfig, friend.Start) } diff --git a/pkg/common/cmd/group.go b/pkg/common/cmd/group.go index 8bf9778249..f158b8c626 100644 --- a/pkg/common/cmd/group.go +++ b/pkg/common/cmd/group.go @@ -36,12 +36,12 @@ func NewGroupRpcCmd() *GroupRpcCmd { ret.configMap = map[string]any{ OpenIMRPCGroupCfgFileName: &groupConfig.RpcConfig, RedisConfigFileName: &groupConfig.RedisConfig, - ZookeeperConfigFileName: &groupConfig.ZookeeperConfig, MongodbConfigFileName: &groupConfig.MongodbConfig, ShareFileName: &groupConfig.Share, NotificationFileName: &groupConfig.NotificationConfig, WebhooksConfigFileName: &groupConfig.WebhooksConfig, LocalCacheConfigFileName: &groupConfig.LocalCacheConfig, + DiscoveryConfigFilename: &groupConfig.Discovery, } ret.RootCmd = NewRootCmd(program.GetProcessName(), WithConfigMap(ret.configMap)) ret.ctx = context.WithValue(context.Background(), "version", config.Version) @@ -56,7 +56,7 @@ func (a *GroupRpcCmd) Exec() error { } func (a *GroupRpcCmd) runE() error { - return startrpc.Start(a.ctx, &a.groupConfig.ZookeeperConfig, &a.groupConfig.RpcConfig.Prometheus, a.groupConfig.RpcConfig.RPC.ListenIP, + return startrpc.Start(a.ctx, &a.groupConfig.Discovery, &a.groupConfig.RpcConfig.Prometheus, a.groupConfig.RpcConfig.RPC.ListenIP, a.groupConfig.RpcConfig.RPC.RegisterIP, a.groupConfig.RpcConfig.RPC.Ports, a.Index(), a.groupConfig.Share.RpcRegisterName.Group, &a.groupConfig.Share, a.groupConfig, group.Start) } diff --git a/pkg/common/cmd/msg.go b/pkg/common/cmd/msg.go index a3b521b4b7..91f7931fbe 100644 --- a/pkg/common/cmd/msg.go +++ b/pkg/common/cmd/msg.go @@ -36,13 +36,13 @@ func NewMsgRpcCmd() *MsgRpcCmd { ret.configMap = map[string]any{ OpenIMRPCMsgCfgFileName: &msgConfig.RpcConfig, RedisConfigFileName: &msgConfig.RedisConfig, - ZookeeperConfigFileName: &msgConfig.ZookeeperConfig, MongodbConfigFileName: &msgConfig.MongodbConfig, KafkaConfigFileName: &msgConfig.KafkaConfig, ShareFileName: &msgConfig.Share, NotificationFileName: &msgConfig.NotificationConfig, WebhooksConfigFileName: &msgConfig.WebhooksConfig, LocalCacheConfigFileName: &msgConfig.LocalCacheConfig, + DiscoveryConfigFilename: &msgConfig.Discovery, } ret.RootCmd = NewRootCmd(program.GetProcessName(), WithConfigMap(ret.configMap)) ret.ctx = context.WithValue(context.Background(), "version", config.Version) @@ -57,7 +57,7 @@ func (a *MsgRpcCmd) Exec() error { } func (a *MsgRpcCmd) runE() error { - return startrpc.Start(a.ctx, &a.msgConfig.ZookeeperConfig, &a.msgConfig.RpcConfig.Prometheus, a.msgConfig.RpcConfig.RPC.ListenIP, + return startrpc.Start(a.ctx, &a.msgConfig.Discovery, &a.msgConfig.RpcConfig.Prometheus, a.msgConfig.RpcConfig.RPC.ListenIP, a.msgConfig.RpcConfig.RPC.RegisterIP, a.msgConfig.RpcConfig.RPC.Ports, a.Index(), a.msgConfig.Share.RpcRegisterName.Msg, &a.msgConfig.Share, a.msgConfig, msg.Start) } diff --git a/pkg/common/cmd/msg_gateway.go b/pkg/common/cmd/msg_gateway.go index 897fd70087..78004094c7 100644 --- a/pkg/common/cmd/msg_gateway.go +++ b/pkg/common/cmd/msg_gateway.go @@ -36,9 +36,9 @@ func NewMsgGatewayCmd() *MsgGatewayCmd { ret := &MsgGatewayCmd{msgGatewayConfig: &msgGatewayConfig} ret.configMap = map[string]any{ OpenIMMsgGatewayCfgFileName: &msgGatewayConfig.MsgGateway, - ZookeeperConfigFileName: &msgGatewayConfig.ZookeeperConfig, ShareFileName: &msgGatewayConfig.Share, WebhooksConfigFileName: &msgGatewayConfig.WebhooksConfig, + DiscoveryConfigFilename: &msgGatewayConfig.Discovery, } ret.RootCmd = NewRootCmd(program.GetProcessName(), WithConfigMap(ret.configMap)) ret.ctx = context.WithValue(context.Background(), "version", config.Version) diff --git a/pkg/common/cmd/msg_transfer.go b/pkg/common/cmd/msg_transfer.go index 86f42dc56f..0d48281e50 100644 --- a/pkg/common/cmd/msg_transfer.go +++ b/pkg/common/cmd/msg_transfer.go @@ -37,9 +37,9 @@ func NewMsgTransferCmd() *MsgTransferCmd { RedisConfigFileName: &msgTransferConfig.RedisConfig, MongodbConfigFileName: &msgTransferConfig.MongodbConfig, KafkaConfigFileName: &msgTransferConfig.KafkaConfig, - ZookeeperConfigFileName: &msgTransferConfig.ZookeeperConfig, ShareFileName: &msgTransferConfig.Share, WebhooksConfigFileName: &msgTransferConfig.WebhooksConfig, + DiscoveryConfigFilename: &msgTransferConfig.Discovery, } ret.RootCmd = NewRootCmd(program.GetProcessName(), WithConfigMap(ret.configMap)) ret.ctx = context.WithValue(context.Background(), "version", config.Version) diff --git a/pkg/common/cmd/push.go b/pkg/common/cmd/push.go index 0140ced237..3e7c4c2492 100644 --- a/pkg/common/cmd/push.go +++ b/pkg/common/cmd/push.go @@ -36,13 +36,13 @@ func NewPushRpcCmd() *PushRpcCmd { ret.configMap = map[string]any{ OpenIMPushCfgFileName: &pushConfig.RpcConfig, RedisConfigFileName: &pushConfig.RedisConfig, - ZookeeperConfigFileName: &pushConfig.ZookeeperConfig, MongodbConfigFileName: &pushConfig.MongodbConfig, KafkaConfigFileName: &pushConfig.KafkaConfig, ShareFileName: &pushConfig.Share, NotificationFileName: &pushConfig.NotificationConfig, WebhooksConfigFileName: &pushConfig.WebhooksConfig, LocalCacheConfigFileName: &pushConfig.LocalCacheConfig, + DiscoveryConfigFilename: &pushConfig.Discovery, } ret.RootCmd = NewRootCmd(program.GetProcessName(), WithConfigMap(ret.configMap)) ret.ctx = context.WithValue(context.Background(), "version", config.Version) @@ -57,7 +57,7 @@ func (a *PushRpcCmd) Exec() error { } func (a *PushRpcCmd) runE() error { - return startrpc.Start(a.ctx, &a.pushConfig.ZookeeperConfig, &a.pushConfig.RpcConfig.Prometheus, a.pushConfig.RpcConfig.RPC.ListenIP, + return startrpc.Start(a.ctx, &a.pushConfig.Discovery, &a.pushConfig.RpcConfig.Prometheus, a.pushConfig.RpcConfig.RPC.ListenIP, a.pushConfig.RpcConfig.RPC.RegisterIP, a.pushConfig.RpcConfig.RPC.Ports, a.Index(), a.pushConfig.Share.RpcRegisterName.Push, &a.pushConfig.Share, a.pushConfig, push.Start) } diff --git a/pkg/common/cmd/third.go b/pkg/common/cmd/third.go index 0dfa7d5be5..b6731f1ff4 100644 --- a/pkg/common/cmd/third.go +++ b/pkg/common/cmd/third.go @@ -36,12 +36,12 @@ func NewThirdRpcCmd() *ThirdRpcCmd { ret.configMap = map[string]any{ OpenIMRPCThirdCfgFileName: &thirdConfig.RpcConfig, RedisConfigFileName: &thirdConfig.RedisConfig, - ZookeeperConfigFileName: &thirdConfig.ZookeeperConfig, MongodbConfigFileName: &thirdConfig.MongodbConfig, ShareFileName: &thirdConfig.Share, NotificationFileName: &thirdConfig.NotificationConfig, MinioConfigFileName: &thirdConfig.MinioConfig, LocalCacheConfigFileName: &thirdConfig.LocalCacheConfig, + DiscoveryConfigFilename: &thirdConfig.Discovery, } ret.RootCmd = NewRootCmd(program.GetProcessName(), WithConfigMap(ret.configMap)) ret.ctx = context.WithValue(context.Background(), "version", config.Version) @@ -56,7 +56,7 @@ func (a *ThirdRpcCmd) Exec() error { } func (a *ThirdRpcCmd) runE() error { - return startrpc.Start(a.ctx, &a.thirdConfig.ZookeeperConfig, &a.thirdConfig.RpcConfig.Prometheus, a.thirdConfig.RpcConfig.RPC.ListenIP, + return startrpc.Start(a.ctx, &a.thirdConfig.Discovery, &a.thirdConfig.RpcConfig.Prometheus, a.thirdConfig.RpcConfig.RPC.ListenIP, a.thirdConfig.RpcConfig.RPC.RegisterIP, a.thirdConfig.RpcConfig.RPC.Ports, a.Index(), a.thirdConfig.Share.RpcRegisterName.Third, &a.thirdConfig.Share, a.thirdConfig, third.Start) } diff --git a/pkg/common/cmd/user.go b/pkg/common/cmd/user.go index 315b93256c..674f9e3a6d 100644 --- a/pkg/common/cmd/user.go +++ b/pkg/common/cmd/user.go @@ -36,13 +36,13 @@ func NewUserRpcCmd() *UserRpcCmd { ret.configMap = map[string]any{ OpenIMRPCUserCfgFileName: &userConfig.RpcConfig, RedisConfigFileName: &userConfig.RedisConfig, - ZookeeperConfigFileName: &userConfig.ZookeeperConfig, MongodbConfigFileName: &userConfig.MongodbConfig, KafkaConfigFileName: &userConfig.KafkaConfig, ShareFileName: &userConfig.Share, NotificationFileName: &userConfig.NotificationConfig, WebhooksConfigFileName: &userConfig.WebhooksConfig, LocalCacheConfigFileName: &userConfig.LocalCacheConfig, + DiscoveryConfigFilename: &userConfig.Discovery, } ret.RootCmd = NewRootCmd(program.GetProcessName(), WithConfigMap(ret.configMap)) ret.ctx = context.WithValue(context.Background(), "version", config.Version) @@ -57,7 +57,7 @@ func (a *UserRpcCmd) Exec() error { } func (a *UserRpcCmd) runE() error { - return startrpc.Start(a.ctx, &a.userConfig.ZookeeperConfig, &a.userConfig.RpcConfig.Prometheus, a.userConfig.RpcConfig.RPC.ListenIP, + return startrpc.Start(a.ctx, &a.userConfig.Discovery, &a.userConfig.RpcConfig.Prometheus, a.userConfig.RpcConfig.RPC.ListenIP, a.userConfig.RpcConfig.RPC.RegisterIP, a.userConfig.RpcConfig.RPC.Ports, a.Index(), a.userConfig.Share.RpcRegisterName.User, &a.userConfig.Share, a.userConfig, user.Start) } diff --git a/pkg/common/config/config.go b/pkg/common/config/config.go index 24d04d8ccc..12c4f7f789 100644 --- a/pkg/common/config/config.go +++ b/pkg/common/config/config.go @@ -345,7 +345,6 @@ type AfterConfig struct { type Share struct { Secret string `mapstructure:"secret"` - Env string `mapstructure:"env"` RpcRegisterName RpcRegisterName `mapstructure:"rpcRegisterName"` IMAdminUserID []string `mapstructure:"imAdminUserID"` } @@ -432,6 +431,19 @@ type ZooKeeper struct { Password string `mapstructure:"password"` } +type Discovery struct { + Enable string `mapstructure:"enable"` + Etcd Etcd `mapstructure:"etcd"` + ZooKeeper ZooKeeper `mapstructure:"zooKeeper"` +} + +type Etcd struct { + RootDirectory string `mapstructure:"rootDirectory"` + Address []string `mapstructure:"address"` + Username string `mapstructure:"username"` + Password string `mapstructure:"password"` +} + func (m *Mongo) Build() *mongoutil.Config { return &mongoutil.Config{ Uri: m.URI, diff --git a/pkg/common/discoveryregister/discoveryregister.go b/pkg/common/discoveryregister/discoveryregister.go index 38d7382fa6..559c937c10 100644 --- a/pkg/common/discoveryregister/discoveryregister.go +++ b/pkg/common/discoveryregister/discoveryregister.go @@ -18,36 +18,34 @@ import ( "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/discoveryregister/kubernetes" "github.com/openimsdk/tools/discovery" + "github.com/openimsdk/tools/discovery/etcd" "github.com/openimsdk/tools/discovery/zookeeper" "github.com/openimsdk/tools/errs" "time" ) -const ( - zookeeperConst = "zookeeper" - kubenetesConst = "k8s" - directConst = "direct" -) - // NewDiscoveryRegister creates a new service discovery and registry client based on the provided environment type. -func NewDiscoveryRegister(zookeeperConfig *config.ZooKeeper, share *config.Share) (discovery.SvcDiscoveryRegistry, error) { - switch share.Env { - case zookeeperConst: - +func NewDiscoveryRegister(discovery *config.Discovery, share *config.Share) (discovery.SvcDiscoveryRegistry, error) { + switch discovery.Enable { + case "zookeeper": return zookeeper.NewZkClient( - zookeeperConfig.Address, - zookeeperConfig.Schema, + discovery.ZooKeeper.Address, + discovery.ZooKeeper.Schema, zookeeper.WithFreq(time.Hour), - zookeeper.WithUserNameAndPassword(zookeeperConfig.Username, zookeeperConfig.Password), + zookeeper.WithUserNameAndPassword(discovery.ZooKeeper.Username, discovery.ZooKeeper.Password), zookeeper.WithRoundRobin(), zookeeper.WithTimeout(10), ) - case kubenetesConst: + case "k8s": return kubernetes.NewK8sDiscoveryRegister(share.RpcRegisterName.MessageGateway) - case directConst: - //return direct.NewConnDirect(config) + case "etcd": + return etcd.NewSvcDiscoveryRegistry( + discovery.Etcd.RootDirectory, + discovery.Etcd.Address, + etcd.WithDialTimeout(10*time.Second), + etcd.WithMaxCallSendMsgSize(20*1024*1024), + etcd.WithUsernameAndPassword(discovery.Etcd.Username, discovery.Etcd.Password)) default: - return nil, errs.New("unsupported discovery type", "type", share.Env).Wrap() + return nil, errs.New("unsupported discovery type", "type", discovery.Enable).Wrap() } - return nil, nil } diff --git a/pkg/common/discoveryregister/etcd/doc.go b/pkg/common/discoveryregister/etcd/doc.go new file mode 100644 index 0000000000..1da7508a16 --- /dev/null +++ b/pkg/common/discoveryregister/etcd/doc.go @@ -0,0 +1,15 @@ +// 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 kubernetes // import "github.com/openimsdk/open-im-server/v3/pkg/common/discoveryregister/etcd" diff --git a/pkg/common/discoveryregister/zookeeper/zookeeper.go b/pkg/common/discoveryregister/zookeeper/zookeeper.go deleted file mode 100644 index 1d11414b67..0000000000 --- a/pkg/common/discoveryregister/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 ebcd5aa7cc..a36bcfe1c8 100644 --- a/pkg/common/startrpc/start.go +++ b/pkg/common/startrpc/start.go @@ -44,7 +44,7 @@ import ( ) // Start rpc server. -func Start[T any](ctx context.Context, zookeeperConfig *config2.ZooKeeper, prometheusConfig *config2.Prometheus, listenIP, +func Start[T any](ctx context.Context, discovery *config2.Discovery, prometheusConfig *config2.Prometheus, listenIP, registerIP string, rpcPorts []int, index int, rpcRegisterName string, share *config2.Share, config T, rpcFn func(ctx context.Context, config T, client discovery.SvcDiscoveryRegistry, server *grpc.Server) error, options ...grpc.ServerOption) error { @@ -68,7 +68,7 @@ func Start[T any](ctx context.Context, zookeeperConfig *config2.ZooKeeper, prome } defer listener.Close() - client, err := kdisc.NewDiscoveryRegister(zookeeperConfig, share) + client, err := kdisc.NewDiscoveryRegister(discovery, share) if err != nil { return err } diff --git a/tools/check-component/main.go b/tools/check-component/main.go index 7fe64d3c5b..5fa84ac36f 100644 --- a/tools/check-component/main.go +++ b/tools/check-component/main.go @@ -22,6 +22,7 @@ import ( "github.com/openimsdk/open-im-server/v3/pkg/common/config" "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/mq/kafka" "github.com/openimsdk/tools/s3/minio" @@ -43,6 +44,14 @@ 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_openim_component", + true, + etcd.WithDialTimeout(10*time.Second), + etcd.WithMaxCallSendMsgSize(20*1024*1024), + etcd.WithUsernameAndPassword(config.Username, config.Password)) +} + func CheckMongo(ctx context.Context, config *config.Mongo) error { return mongoutil.Check(ctx, config.Build()) } @@ -59,14 +68,14 @@ func CheckKafka(ctx context.Context, conf *config.Kafka) error { return kafka.Check(ctx, conf.Build(), []string{conf.ToMongoTopic, conf.ToRedisTopic, conf.ToPushTopic}) } -func initConfig(configDir string) (*config.Mongo, *config.Redis, *config.Kafka, *config.Minio, *config.ZooKeeper, error) { +func initConfig(configDir string) (*config.Mongo, *config.Redis, *config.Kafka, *config.Minio, *config.Discovery, error) { var ( - mongoConfig = &config.Mongo{} - redisConfig = &config.Redis{} - kafkaConfig = &config.Kafka{} - minioConfig = &config.Minio{} - zookeeperConfig = &config.ZooKeeper{} - thirdConfig = &config.Third{} + mongoConfig = &config.Mongo{} + redisConfig = &config.Redis{} + kafkaConfig = &config.Kafka{} + minioConfig = &config.Minio{} + discovery = &config.Discovery{} + thirdConfig = &config.Third{} ) err := config.LoadConfig(filepath.Join(configDir, cmd.MongodbConfigFileName), cmd.ConfigEnvPrefixMap[cmd.MongodbConfigFileName], mongoConfig) if err != nil { @@ -96,11 +105,11 @@ func initConfig(configDir string) (*config.Mongo, *config.Redis, *config.Kafka, } else { minioConfig = nil } - err = config.LoadConfig(filepath.Join(configDir, cmd.ZookeeperConfigFileName), cmd.ConfigEnvPrefixMap[cmd.ZookeeperConfigFileName], zookeeperConfig) + err = config.LoadConfig(filepath.Join(configDir, cmd.DiscoveryConfigFilename), cmd.ConfigEnvPrefixMap[cmd.DiscoveryConfigFilename], discovery) if err != nil { return nil, nil, nil, nil, nil, err } - return mongoConfig, redisConfig, kafkaConfig, minioConfig, zookeeperConfig, nil + return mongoConfig, redisConfig, kafkaConfig, minioConfig, discovery, nil } func main() { @@ -127,35 +136,40 @@ func main() { } } -func performChecks(ctx context.Context, mongoConfig *config.Mongo, redisConfig *config.Redis, kafkaConfig *config.Kafka, minioConfig *config.Minio, zookeeperConfig *config.ZooKeeper, maxRetry int) error { +func performChecks(ctx context.Context, mongoConfig *config.Mongo, redisConfig *config.Redis, kafkaConfig *config.Kafka, minioConfig *config.Minio, discovery *config.Discovery, maxRetry int) error { checksDone := make(map[string]bool) - checks := map[string]func() error{ - "Zookeeper": func() error { - return CheckZookeeper(ctx, zookeeperConfig) - }, - "Mongo": func() error { + checks := map[string]func(ctx context.Context) error{ + "Mongo": func(ctx context.Context) error { return CheckMongo(ctx, mongoConfig) }, - "Redis": func() error { + "Redis": func(ctx context.Context) error { return CheckRedis(ctx, redisConfig) }, - "Kafka": func() error { + "Kafka": func(ctx context.Context) error { return CheckKafka(ctx, kafkaConfig) }, } - if minioConfig != nil { - checks["MinIO"] = func() error { + checks["MinIO"] = func(ctx context.Context) error { return CheckMinIO(ctx, minioConfig) } } + if discovery.Enable == "etcd" { + 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++ { allSuccess := true for name, check := range checks { if !checksDone[name] { - if err := check(); err != nil { + if err := check(ctx); err != nil { fmt.Printf("%s check failed: %v\n", name, err) allSuccess = false } else { From 2bcc65a24b15768d21796ab7844a0def3f98edd7 Mon Sep 17 00:00:00 2001 From: chao <48119764+withchao@users.noreply.github.com> Date: Wed, 15 May 2024 11:43:20 +0800 Subject: [PATCH 171/188] fix: s3 config (#2303) * fix: GroupApplicationAcceptedNotification * fix: GroupApplicationAcceptedNotification * fix: NotificationUserInfoUpdate * cicd: robot automated Change * fix: component * fix: getConversationInfo * feat: cron task * feat: cron task * feat: cron task * feat: cron task * feat: cron task * fix: minio config url recognition error * fix: SearchMessage * fix: s3 config * fix: oss panic * kafka * go.sum --------- Co-authored-by: withchao --- config/openim-rpc-third.yml | 17 +---------------- go.mod | 2 +- go.sum | 4 ++-- 3 files changed, 4 insertions(+), 19 deletions(-) diff --git a/config/openim-rpc-third.yml b/config/openim-rpc-third.yml index bb41c93aee..bde38ccc44 100644 --- a/config/openim-rpc-third.yml +++ b/config/openim-rpc-third.yml @@ -29,19 +29,4 @@ object: accessKeyID: '' accessKeySecret: '' sessionToken: '' - publicRead: false - kodo: - endpoint: "webhook://s3.cn-east-1.qiniucs.com" - bucket: "demo-9999999" - bucketURL: "webhook://your.domain.com" - accessKeyID: '' - accessKeySecret: '' - sessionToken: '' - publicRead: false - aws: - endpoint: "''" - region: "us-east-1" - bucket: "demo-9999999" - accessKeyID: '' - accessKeySecret: '' - publicRead: false + publicRead: false \ No newline at end of file diff --git a/go.mod b/go.mod index e9777eaa8b..54e8a8e0e5 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,7 @@ require ( github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible // indirect github.com/mitchellh/mapstructure v1.5.0 github.com/openimsdk/protocol v0.0.65 - github.com/openimsdk/tools v0.0.49-alpha.18 + github.com/openimsdk/tools v0.0.49-alpha.19 github.com/pkg/errors v0.9.1 // indirect github.com/prometheus/client_golang v1.18.0 github.com/stretchr/testify v1.9.0 diff --git a/go.sum b/go.sum index 3acb4709c6..5611a6ca65 100644 --- a/go.sum +++ b/go.sum @@ -288,8 +288,8 @@ github.com/openimsdk/gomake v0.0.13 h1:xLDe/moqgWpRoptHzI4packAWzs4C16b+sVY+txNJ github.com/openimsdk/gomake v0.0.13/go.mod h1:PndCozNc2IsQIciyn9mvEblYWZwJmAI+06z94EY+csI= github.com/openimsdk/protocol v0.0.65 h1:SPT9qyUsFRTTKSKb/FjpS+xr6sxz/Kbnu+su1bxYagc= github.com/openimsdk/protocol v0.0.65/go.mod h1:OZQA9FR55lseYoN2Ql1XAHYKHJGu7OMNkUbuekrKCM8= -github.com/openimsdk/tools v0.0.49-alpha.18 h1:ARQeCiRmExvtB6XYItegThuV63JGOTxddwhSLHYXd78= -github.com/openimsdk/tools v0.0.49-alpha.18/go.mod h1:g7mkHXYUPi0/8aAX8VPMHpnb3hqdV69Jph+bXOGvvNM= +github.com/openimsdk/tools v0.0.49-alpha.19 h1:CbASL0yefRSVAmWPVeRnhF7wZKd6umLfz31CIhEgrBs= +github.com/openimsdk/tools v0.0.49-alpha.19/go.mod h1:g7mkHXYUPi0/8aAX8VPMHpnb3hqdV69Jph+bXOGvvNM= 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/pierrec/lz4/v4 v4.1.21 h1:yOVMLb6qSIDP67pl/5F7RepeKYu/VmTyEXvuMI5d9mQ= From 13b1661a77cce14f69bf21866ebc336e2fc2895c Mon Sep 17 00:00:00 2001 From: skiffer-git <72860476+skiffer-git@users.noreply.github.com> Date: Wed, 15 May 2024 15:42:35 +0800 Subject: [PATCH 172/188] Delete .github/dependabot.yml --- .github/dependabot.yml | 59 ------------------------------------------ 1 file changed, 59 deletions(-) delete mode 100644 .github/dependabot.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml deleted file mode 100644 index 49ffd71738..0000000000 --- a/.github/dependabot.yml +++ /dev/null @@ -1,59 +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. - -# To get started with Dependabot version updates, you'll need to specify which -# package ecosystems to update and where the package manifests are located. -# Please see the documentation for all configuration options: -# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates - -version: 2 -updates: - - package-ecosystem: "gomod" - directory: "/" - schedule: - interval: "daily" - time: "08:00" - labels: - - "dependencies" - commit-message: - prefix: "feat" - include: "scope" - groups: - gomod-deps: - patterns: - - "*" - - package-ecosystem: "github-actions" - directory: "/" - schedule: - interval: "daily" - time: "08:00" - labels: - - "dependencies" - commit-message: - prefix: "chore" - include: "scope" - groups: - github-actions: - patterns: - - "*" - - package-ecosystem: "docker" - directory: "/" - schedule: - interval: "daily" - time: "08:00" - labels: - - "dependencies" - commit-message: - prefix: "feat" - include: "scope" \ No newline at end of file From 814e378fa1a6f24b5c0295c6c90d6905b3f61e21 Mon Sep 17 00:00:00 2001 From: skiffer-git <72860476+skiffer-git@users.noreply.github.com> Date: Wed, 15 May 2024 15:53:48 +0800 Subject: [PATCH 173/188] Update CONTRIBUTING-zh_CN.md --- CONTRIBUTING-zh_CN.md | 46 ++++++++++++++++++++++++++++--------------- 1 file changed, 30 insertions(+), 16 deletions(-) diff --git a/CONTRIBUTING-zh_CN.md b/CONTRIBUTING-zh_CN.md index c10d7337f8..47965a9f49 100644 --- a/CONTRIBUTING-zh_CN.md +++ b/CONTRIBUTING-zh_CN.md @@ -1,7 +1,9 @@ -# 如何给OpenIM贡献代码(提交pull request) + + +# 如何给 OpenIM 贡献代码(提交 Pull Request)

- Englist · + English · 中文 · Українська · Česky · @@ -28,55 +30,67 @@ Türkçe

+本指南将以 [openimsdk/open-im-server](https://github.com/openimsdk/open-im-server) 为例,详细说明如何为 OpenIM 项目贡献代码。我们采用“一问题一分支”的策略,确保每个 Issue 都对应一个专门的分支,以便有效管理代码变更。 -本指南将以 [openimsdk/open-im-server](https://github.com/openimsdk/open-im-server)为例详细说明如何为 OpenIM 项目贡献代码。我们采用“一问题一分支”的策略,确保每个 Issue 都对应一个专门的分支,以便有效管理代码变更。 - -## 1. Fork 仓库 +### 1. Fork 仓库 前往 [openimsdk/open-im-server](https://github.com/openimsdk/open-im-server) GitHub 页面,点击右上角的 "Fork" 按钮,将仓库 Fork 到你的 GitHub 账户下。 -## 2. 克隆仓库 +### 2. 克隆仓库 将你 Fork 的仓库克隆到本地: ```bash git clone https://github.com/your-username/open-im-server.git ``` -## 3. 设置远程上游 +### 3. 设置远程上游 添加原始仓库为远程上游以便跟踪其更新: ```bash git remote add upstream https://github.com/openimsdk/open-im-server.git ``` -## 4. 创建 Issue -在原始仓库中创建一个新的 Issue,详细描述你遇到的问题或希望添加的新功能。 +### 4. 创建 Issue +在原始仓库中创建一个新的 Issue,详细描述你遇到的问题或希望添加 -## 5. 创建新分支 +的新功能。 + +### 5. 创建新分支 基于主分支创建一个新分支,并使用描述性的名称与 Issue ID,例如: ```bash git checkout -b fix-bug-123 ``` -## 6. 提交更改 +### 6. 提交更改 在你的本地分支上进行更改后,提交这些更改: ```bash git add . git commit -m "Describe your changes in detail" ``` -## 7. 推送分支 +### 7. 推送分支 将你的分支推送回你的 GitHub Fork: ```bash git push origin fix-bug-123 ``` -## 8. 创建 Pull Request +### 8. 创建 Pull Request 在 GitHub 上转到你的 Fork 仓库,点击 "Pull Request" 按钮。确保 PR 描述清楚,并链接到相关的 Issue。 -## 9. 签署 CLA +### 9. 签署 CLA 如果这是你第一次提交 PR,你需要在 PR 的评论中回复: ``` I have read the CLA Document and I hereby sign the CLA ``` -## 其他说明 -如果需要将同一修改提交到两个不同的分支(例如 `main` 和 `release-v3.7`),应从对应的远程分支分别创建两个新分支。首先在一个分支上完成修改,然后使用 `cherry-pick` 命令将这些更改应用到另一个分支。之后,为每个分支独立提交 Pull Request。 +### 编程规范 +请参考以下文档以了解关于 Go 语言编程规范的详细信息: +- [Go 编码规范](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/go-code.md) +- [代码约定](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/code-conventions.md) + +### 日志规范 +- **禁止使用标准的 `log` 包**。 +- 应使用 `"github.com/openimsdk/tools/log"` 包来打印日志,该包支持多种日志级别:`debug`、`info`、`warn`、`error`。 +- **错误日志应仅在首次调用的函数中打印**,以防止日志重复,并确保错误的上下文清晰。 +### 异常及错误处理 +- **禁止使用 `panic`**:程序中不应使用 `panic`,以避免在遇到不可恢复的错误时突然终止。 +- **错误包裹**:使用 `"github.com/openimsdk/tools/errs"` 来包裹错误,保持错误信息的完整性并增加调试便利。 +- **错误传递**:如果函数本身不能处理错误,应将错误返回给调用者,而不是隐藏或忽略这些错误。 From ddf8cc98ce10dc624c4231226277405e09a39488 Mon Sep 17 00:00:00 2001 From: skiffer-git <72860476+skiffer-git@users.noreply.github.com> Date: Wed, 15 May 2024 15:56:14 +0800 Subject: [PATCH 174/188] Update CONTRIBUTING.md --- CONTRIBUTING.md | 41 +++++++++++++++++++++++++++-------------- 1 file changed, 27 insertions(+), 14 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a85ba891fc..0aa07393ee 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,7 +1,7 @@ -# How do I contribute code to OpenIM +# How to Contribute to OpenIM (Submitting Pull Requests)

- Englist · + English · 中文 · Українська · Česky · @@ -27,13 +27,14 @@ Ελληνικά · Türkçe

-This guide will explain in detail how to contribute code to the OpenIM project, using `openimsdk/open-im-server` as an example. We adopt a "one issue, one branch" strategy to ensure each issue corresponds to a dedicated branch, allowing for effective management of code changes. + +This guide will use [openimsdk/open-im-server](https://github.com/openimsdk/open-im-server) as an example to explain in detail how to contribute code to the OpenIM project. We adopt a "one issue, one branch" strategy to ensure each issue corresponds to a dedicated branch for effective code change management. ### 1. Fork the Repository -Go to the `openimsdk/open-im-server` GitHub page, click the "Fork" button in the upper right corner to fork the repository to your GitHub account. +Go to the [openimsdk/open-im-server](https://github.com/openimsdk/open-im-server) GitHub page, click the "Fork" button in the upper right corner to fork the repository to your GitHub account. ### 2. Clone the Repository -Clone the forked repository to your local machine: +Clone the repository you forked to your local machine: ```bash git clone https://github.com/your-username/open-im-server.git ``` @@ -45,19 +46,21 @@ git remote add upstream https://github.com/openimsdk/open-im-server.git ``` ### 4. Create an Issue -Create a new issue in the original repository describing the problem you are facing or the new feature you want to add. For significant feature adjustments, propose an RFC issue to facilitate broad discussion and participation from community members. +Create a new issue in the original repository detailing the problem you encountered or the new feature you wish to add. ### 5. Create a New Branch -Create a new branch based on the main branch and name it descriptively, including the Issue ID, for example: +Create a new branch off the main branch with a descriptive name and Issue ID, for example: ```bash git checkout -b fix-bug-123 ``` ### 6. Commit Changes -After making changes on your local branch, commit them: +After making changes on your local branch, commit these changes: ```bash git add . -git commit -m "Describe your changes in detail" +git commit -m "Describe your changes + + in detail" ``` ### 7. Push the Branch @@ -67,15 +70,25 @@ git push origin fix-bug-123 ``` ### 8. Create a Pull Request -Go to your fork on GitHub, click the "Pull Request" button. Make sure the PR description is clear and links to the related Issue. -#### 🅰 Fixed issue #issueID +Go to your fork on GitHub and click the "Pull Request" button. Ensure the PR description is clear and links to the related issue. ### 9. Sign the CLA -If this is your first time submitting a PR, you need to reply in the PR comments: +If this is your first time submitting a PR, you will need to reply in the comments of the PR: ``` I have read the CLA Document and I hereby sign the CLA ``` -### Additional Notes -If the same modification needs to be submitted to two different branches (e.g., main and release-v3.7), create two new branches from the corresponding remote branches. First complete the modification in one branch, then use the `cherry-pick` command to apply these changes to the other branch. After that, submit a separate Pull Request for each branch. +### Programming Standards +Please refer to the following documents for detailed information on Go language programming standards: +- [Go Coding Standards](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/go-code.md) +- [Code Conventions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/code-conventions.md) + +### Logging Standards +- **Do not use the standard `log` package**. +- Use the `"github.com/openimsdk/tools/log"` package for logging, which supports multiple log levels: `debug`, `info`, `warn`, `error`. +- **Error logs should only be printed in the function where they are first actively called** to prevent log duplication and ensure clear error context. +### Exception and Error Handling +- **Prohibit the use of `panic`**: The code should not use `panic` to avoid abrupt termination when encountering unrecoverable errors. +- **Error Wrapping**: Use `"github.com/openimsdk/tools/errs"` to wrap errors, maintaining the integrity of error information and facilitating debugging. +- **Error Propagation**: If a function cannot handle an error itself, it should return the error to the caller, rather than hiding or ignoring it. From 285523751d1d52f9bc1dc628a499e08c7ad31364 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=A3=AE=E5=B1=BF?= <42713450+memory-qianxiao@users.noreply.github.com> Date: Fri, 17 May 2024 10:43:54 +0800 Subject: [PATCH 175/188] feat: middleware authentication and whitelist are used to release permissions. (#2309) --- internal/api/router.go | 76 +++++++++++++++++++++++++----------------- 1 file changed, 45 insertions(+), 31 deletions(-) diff --git a/internal/api/router.go b/internal/api/router.go index 1fbb33b092..6005671785 100644 --- a/internal/api/router.go +++ b/internal/api/router.go @@ -15,6 +15,7 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" "net/http" + "strings" ) func newGinRouter(disCov discovery.SvcDiscoveryRegistry, config *Config) *gin.Engine { @@ -25,7 +26,6 @@ func newGinRouter(disCov discovery.SvcDiscoveryRegistry, config *Config) *gin.En if v, ok := binding.Validator.Engine().(*validator.Validate); ok { _ = v.RegisterValidation("required_if", RequiredIf) } - r.Use(gin.Recovery(), mw.CorsHandler(), mw.GinParseOperationID()) // init rpc client here userRpc := rpcclient.NewUser(disCov, config.Share.RpcRegisterName.User, config.Share.RpcRegisterName.MessageGateway, config.Share.IMAdminUserID) @@ -36,37 +36,37 @@ func newGinRouter(disCov discovery.SvcDiscoveryRegistry, config *Config) *gin.En authRpc := rpcclient.NewAuth(disCov, config.Share.RpcRegisterName.Auth) thirdRpc := rpcclient.NewThird(disCov, config.Share.RpcRegisterName.Third, config.API.Prometheus.GrafanaURL) + r.Use(gin.Recovery(), mw.CorsHandler(), mw.GinParseOperationID(), GinParseToken(authRpc)) u := NewUserApi(*userRpc) m := NewMessageApi(messageRpc, userRpc, config.Share.IMAdminUserID) - ParseToken := GinParseToken(authRpc) userRouterGroup := r.Group("/user") { userRouterGroup.POST("/user_register", u.UserRegister) - userRouterGroup.POST("/update_user_info", ParseToken, u.UpdateUserInfo) - userRouterGroup.POST("/update_user_info_ex", ParseToken, u.UpdateUserInfoEx) - userRouterGroup.POST("/set_global_msg_recv_opt", ParseToken, u.SetGlobalRecvMessageOpt) - userRouterGroup.POST("/get_users_info", ParseToken, u.GetUsersPublicInfo) - userRouterGroup.POST("/get_all_users_uid", ParseToken, u.GetAllUsersID) - userRouterGroup.POST("/account_check", ParseToken, u.AccountCheck) - userRouterGroup.POST("/get_users", ParseToken, u.GetUsers) - userRouterGroup.POST("/get_users_online_status", ParseToken, u.GetUsersOnlineStatus) - userRouterGroup.POST("/get_users_online_token_detail", ParseToken, u.GetUsersOnlineTokenDetail) - userRouterGroup.POST("/subscribe_users_status", ParseToken, u.SubscriberStatus) - userRouterGroup.POST("/get_users_status", ParseToken, u.GetUserStatus) - userRouterGroup.POST("/get_subscribe_users_status", ParseToken, u.GetSubscribeUsersStatus) + userRouterGroup.POST("/update_user_info", u.UpdateUserInfo) + userRouterGroup.POST("/update_user_info_ex", u.UpdateUserInfoEx) + userRouterGroup.POST("/set_global_msg_recv_opt", u.SetGlobalRecvMessageOpt) + userRouterGroup.POST("/get_users_info", u.GetUsersPublicInfo) + userRouterGroup.POST("/get_all_users_uid", u.GetAllUsersID) + userRouterGroup.POST("/account_check", u.AccountCheck) + userRouterGroup.POST("/get_users", u.GetUsers) + userRouterGroup.POST("/get_users_online_status", u.GetUsersOnlineStatus) + userRouterGroup.POST("/get_users_online_token_detail", u.GetUsersOnlineTokenDetail) + userRouterGroup.POST("/subscribe_users_status", u.SubscriberStatus) + userRouterGroup.POST("/get_users_status", u.GetUserStatus) + userRouterGroup.POST("/get_subscribe_users_status", u.GetSubscribeUsersStatus) - userRouterGroup.POST("/process_user_command_add", ParseToken, u.ProcessUserCommandAdd) - userRouterGroup.POST("/process_user_command_delete", ParseToken, u.ProcessUserCommandDelete) - userRouterGroup.POST("/process_user_command_update", ParseToken, u.ProcessUserCommandUpdate) - userRouterGroup.POST("/process_user_command_get", ParseToken, u.ProcessUserCommandGet) - userRouterGroup.POST("/process_user_command_get_all", ParseToken, u.ProcessUserCommandGetAll) + userRouterGroup.POST("/process_user_command_add", u.ProcessUserCommandAdd) + userRouterGroup.POST("/process_user_command_delete", u.ProcessUserCommandDelete) + userRouterGroup.POST("/process_user_command_update", u.ProcessUserCommandUpdate) + userRouterGroup.POST("/process_user_command_get", u.ProcessUserCommandGet) + userRouterGroup.POST("/process_user_command_get_all", u.ProcessUserCommandGetAll) - userRouterGroup.POST("/add_notification_account", ParseToken, u.AddNotificationAccount) - userRouterGroup.POST("/update_notification_account", ParseToken, u.UpdateNotificationAccountInfo) - userRouterGroup.POST("/search_notification_account", ParseToken, u.SearchNotificationAccount) + userRouterGroup.POST("/add_notification_account", u.AddNotificationAccount) + userRouterGroup.POST("/update_notification_account", u.UpdateNotificationAccountInfo) + userRouterGroup.POST("/search_notification_account", u.SearchNotificationAccount) } // friend routing group - friendRouterGroup := r.Group("/friend", ParseToken) + friendRouterGroup := r.Group("/friend") { f := NewFriendApi(*friendRpc) friendRouterGroup.POST("/delete_friend", f.DeleteFriend) @@ -88,7 +88,7 @@ func newGinRouter(disCov discovery.SvcDiscoveryRegistry, config *Config) *gin.En friendRouterGroup.POST("/update_friends", f.UpdateFriends) } g := NewGroupApi(*groupRpc) - groupRouterGroup := r.Group("/group", ParseToken) + groupRouterGroup := r.Group("/group") { groupRouterGroup.POST("/create_group", g.CreateGroup) groupRouterGroup.POST("/set_group_info", g.SetGroupInfo) @@ -120,12 +120,12 @@ func newGinRouter(disCov discovery.SvcDiscoveryRegistry, config *Config) *gin.En { a := NewAuthApi(*authRpc) authRouterGroup.POST("/user_token", a.UserToken) - authRouterGroup.POST("/get_user_token", ParseToken, a.GetUserToken) + authRouterGroup.POST("/get_user_token", a.GetUserToken) authRouterGroup.POST("/parse_token", a.ParseToken) - authRouterGroup.POST("/force_logout", ParseToken, a.ForceLogout) + authRouterGroup.POST("/force_logout", a.ForceLogout) } // Third service - thirdGroup := r.Group("/third", ParseToken) + thirdGroup := r.Group("/third") { t := NewThirdApi(*thirdRpc) thirdGroup.GET("/prometheus", t.GetPrometheus) @@ -137,7 +137,7 @@ func newGinRouter(disCov discovery.SvcDiscoveryRegistry, config *Config) *gin.En logs.POST("/delete", t.DeleteLogs) logs.POST("/search", t.SearchLogs) - objectGroup := r.Group("/object", ParseToken) + objectGroup := r.Group("/object") objectGroup.POST("/part_limit", t.PartLimit) objectGroup.POST("/part_size", t.PartSize) @@ -150,7 +150,7 @@ func newGinRouter(disCov discovery.SvcDiscoveryRegistry, config *Config) *gin.En objectGroup.GET("/*name", t.ObjectRedirect) } // Message - msgGroup := r.Group("/msg", ParseToken) + msgGroup := r.Group("/msg") { msgGroup.POST("/newest_seq", m.GetSeq) msgGroup.POST("/search_msg", m.SearchMsg) @@ -174,7 +174,7 @@ func newGinRouter(disCov discovery.SvcDiscoveryRegistry, config *Config) *gin.En msgGroup.POST("/get_server_time", m.GetServerTime) } // Conversation - conversationGroup := r.Group("/conversation", ParseToken) + conversationGroup := r.Group("/conversation") { c := NewConversationApi(*conversationRpc) conversationGroup.POST("/get_sorted_conversation_list", c.GetSortedConversationList) @@ -185,7 +185,7 @@ func newGinRouter(disCov discovery.SvcDiscoveryRegistry, config *Config) *gin.En conversationGroup.POST("/get_conversation_offline_push_user_ids", c.GetConversationOfflinePushUserIDs) } - statisticsGroup := r.Group("/statistics", ParseToken) + statisticsGroup := r.Group("/statistics") { statisticsGroup.POST("/user/register", u.UserRegisterCount) statisticsGroup.POST("/user/active", m.GetActiveUser) @@ -199,6 +199,13 @@ func GinParseToken(authRPC *rpcclient.Auth) gin.HandlerFunc { return func(c *gin.Context) { switch c.Request.Method { case http.MethodPost: + for _, wApi := range Whitelist { + if strings.HasPrefix(c.Request.URL.Path, wApi) { + c.Next() + return + } + } + token := c.Request.Header.Get(constant.Token) if token == "" { log.ZWarn(c, "header get token error", servererrs.ErrArgs.WrapMsg("header must have token")) @@ -218,3 +225,10 @@ func GinParseToken(authRPC *rpcclient.Auth) gin.HandlerFunc { } } } + +// Whitelist api not parse token +var Whitelist = []string{ + "/user/user_register", + "/auth/user_token", + "/auth/parse_token", +} From 1eef4013e2f7561f2a8bd63816e4257638370deb Mon Sep 17 00:00:00 2001 From: OpenIM-Gordon <46924906+FGadvancer@users.noreply.github.com> Date: Mon, 27 May 2024 11:56:46 +0800 Subject: [PATCH 176/188] fix: main bug fix notification unread (#2266) * fix: notification has counted unread counts bug fix. * fix: notification has counted unread counts bug fix. --- .../msgtransfer/online_history_msg_handler.go | 23 ++++++++----------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/internal/msgtransfer/online_history_msg_handler.go b/internal/msgtransfer/online_history_msg_handler.go index df2660804d..551e3fe911 100644 --- a/internal/msgtransfer/online_history_msg_handler.go +++ b/internal/msgtransfer/online_history_msg_handler.go @@ -176,20 +176,15 @@ func (och *OnlineHistoryRedisConsumerHandler) getPushStorageMsgList( if v.message.Options != nil { msg.Options = msgprocessor.NewMsgOptions() } - if options.IsOfflinePush() { - v.message.Options = msgprocessor.WithOptions( - v.message.Options, - msgprocessor.WithOfflinePush(false), - ) - msg.Options = msgprocessor.WithOptions(msg.Options, msgprocessor.WithOfflinePush(true)) - } - if options.IsUnreadCount() { - v.message.Options = msgprocessor.WithOptions( - v.message.Options, - msgprocessor.WithUnreadCount(false), - ) - msg.Options = msgprocessor.WithOptions(msg.Options, msgprocessor.WithUnreadCount(true)) - } + msg.Options = msgprocessor.WithOptions(msg.Options, + msgprocessor.WithOfflinePush(options.IsOfflinePush()), + msgprocessor.WithUnreadCount(options.IsUnreadCount()), + ) + v.message.Options = msgprocessor.WithOptions( + v.message.Options, + msgprocessor.WithOfflinePush(false), + msgprocessor.WithUnreadCount(false), + ) storageMsgList = append(storageMsgList, msg) } if isStorage(v.message) { From 76d9688a541efa2c3fcd6482a31c781b11e24188 Mon Sep 17 00:00:00 2001 From: OpenIM-Gordon <46924906+FGadvancer@users.noreply.github.com> Date: Mon, 27 May 2024 11:58:36 +0800 Subject: [PATCH 177/188] refactor: db refactor and cache key add. (#2320) * refactor: db refactor and cache key add. * refactor: db refactor and cache key add. * refactor: go version update. * refactor: file name change. --- internal/msgtransfer/init.go | 10 +- .../msgtransfer/online_history_msg_handler.go | 2 +- .../online_msg_to_mongo_handler.go | 2 +- internal/push/offlinepush/fcm/push.go | 2 +- internal/push/offlinepush/getui/push.go | 2 +- internal/push/offlinepush/offlinepusher.go | 2 +- internal/push/push.go | 6 +- internal/rpc/auth/auth.go | 6 +- internal/rpc/conversation/conversaion.go | 34 +- internal/rpc/friend/black.go | 8 +- internal/rpc/friend/friend.go | 21 +- internal/rpc/friend/notification.go | 6 +- internal/rpc/group/callback.go | 4 +- internal/rpc/group/convert.go | 6 +- internal/rpc/group/fill.go | 5 +- internal/rpc/group/group.go | 109 ++--- internal/rpc/group/notification.go | 12 +- internal/rpc/msg/revoke.go | 4 +- internal/rpc/msg/server.go | 10 +- internal/rpc/msg/statistics.go | 6 +- internal/rpc/third/log.go | 12 +- internal/rpc/third/s3.go | 8 +- internal/rpc/third/third.go | 13 +- internal/rpc/user/notification.go | 6 +- internal/rpc/user/user.go | 34 +- pkg/common/config/config.go | 2 +- pkg/common/convert/black.go | 4 +- pkg/common/convert/conversation.go | 14 +- pkg/common/convert/friend.go | 16 +- pkg/common/convert/group.go | 22 +- pkg/common/convert/msg.go | 10 +- pkg/common/convert/user.go | 8 +- pkg/common/convert/user_test.go | 7 +- pkg/common/db/cache/conversation.go | 371 ------------------ pkg/common/db/cache/meta_cache.go | 284 -------------- pkg/common/db/cache/third.go | 85 ---- pkg/common/db/table/relation/doc.go | 15 - pkg/common/storage/cache/batch_handler.go | 17 + pkg/common/storage/cache/black.go | 27 ++ .../{ => storage/cache}/cachekey/black.go | 0 .../cache}/cachekey/conversation.go | 0 .../{ => storage/cache}/cachekey/doc.go | 2 +- .../{ => storage/cache}/cachekey/friend.go | 0 .../{ => storage/cache}/cachekey/group.go | 0 pkg/common/storage/cache/cachekey/msg.go | 70 ++++ pkg/common/storage/cache/cachekey/s3.go | 40 ++ pkg/common/storage/cache/cachekey/seq.go | 38 ++ pkg/common/storage/cache/cachekey/third.go | 41 ++ .../{ => storage/cache}/cachekey/token.go | 0 .../{ => storage/cache}/cachekey/user.go | 5 + pkg/common/storage/cache/conversation.go | 60 +++ pkg/common/{db => storage}/cache/doc.go | 2 +- pkg/common/storage/cache/friend.go | 35 ++ pkg/common/storage/cache/group.go | 62 +++ pkg/common/storage/cache/msg.go | 43 ++ .../storage/cache/redis/batch_handler.go | 211 ++++++++++ .../cache => storage/cache/redis}/black.go | 54 +-- .../storage/cache/redis/conversation.go | 246 ++++++++++++ pkg/common/storage/cache/redis/doc.go | 15 + .../cache => storage/cache/redis}/friend.go | 85 ++-- .../cache => storage/cache/redis}/group.go | 182 ++++----- pkg/common/storage/cache/redis/meta_cache.go | 15 + .../{db/cache => storage/cache/redis}/msg.go | 178 ++------- .../cache => storage/cache/redis}/msg_test.go | 7 +- .../{db/cache => storage/cache/redis}/s3.go | 154 +++----- .../{db/cache => storage/cache/redis}/seq.go | 53 ++- pkg/common/storage/cache/redis/third.go | 103 +++++ .../cache => storage/cache/redis}/token.go | 37 +- .../{db/cache => storage/cache/redis}/user.go | 90 ++--- pkg/common/storage/cache/s3.go | 51 +++ pkg/common/storage/cache/seq.go | 30 ++ pkg/common/storage/cache/third.go | 18 + pkg/common/storage/cache/token.go | 12 + pkg/common/storage/cache/user.go | 33 ++ pkg/common/storage/common/types.go | 26 ++ pkg/common/{db => storage}/controller/auth.go | 2 +- .../{db => storage}/controller/black.go | 32 +- .../controller/conversation.go | 83 ++-- pkg/common/{db => storage}/controller/doc.go | 2 +- .../{db => storage}/controller/friend.go | 80 ++-- .../{db => storage}/controller/group.go | 153 ++++---- pkg/common/{db => storage}/controller/msg.go | 93 ++--- pkg/common/{db => storage}/controller/push.go | 2 +- pkg/common/{db => storage}/controller/s3.go | 20 +- .../{db => storage}/controller/third.go | 21 +- pkg/common/{db => storage}/controller/user.go | 67 ++-- .../relation => storage/database}/black.go | 30 +- .../database}/conversation.go | 42 +- pkg/common/storage/database/doc.go | 15 + .../relation => storage/database}/friend.go | 35 +- .../database}/friend_request.go | 33 +- pkg/common/storage/database/group.go | 35 ++ .../database}/group_member.go | 34 +- .../database}/group_request.go | 31 +- pkg/common/storage/database/log.go | 29 ++ .../{db => storage/database}/mgo/black.go | 29 +- .../database}/mgo/conversation.go | 26 +- .../{db => storage/database}/mgo/doc.go | 2 +- .../{db => storage/database}/mgo/friend.go | 35 +- .../database}/mgo/friend_request.go | 27 +- .../{db => storage/database}/mgo/group.go | 19 +- .../database}/mgo/group_member.go | 21 +- .../database}/mgo/group_request.go | 23 +- .../database/mgo/helpers.go} | 13 +- .../{db => storage/database}/mgo/log.go | 17 +- .../{db => storage/database}/mgo/msg.go | 61 +-- .../{db => storage/database}/mgo/object.go | 13 +- .../{db => storage/database}/mgo/subscribe.go | 11 +- .../{db => storage/database}/mgo/user.go | 35 +- pkg/common/storage/database/msg.go | 48 +++ pkg/common/storage/database/object.go | 26 ++ .../database}/subscribe.go | 21 +- .../relation => storage/database}/user.go | 50 +-- pkg/common/storage/model/black.go | 28 ++ pkg/common/storage/model/conversation.go | 40 ++ pkg/common/storage/model/doc.go | 15 + pkg/common/storage/model/friend.go | 31 ++ pkg/common/storage/model/friend_request.go | 31 ++ .../table/relation => storage/model}/group.go | 20 +- pkg/common/storage/model/group_member.go | 33 ++ pkg/common/storage/model/group_request.go | 33 ++ .../table/relation => storage/model}/log.go | 14 +- .../table/relation => storage/model}/msg.go | 40 +- .../relation => storage/model}/object.go | 11 +- pkg/common/storage/model/subscribe.go | 30 ++ pkg/common/storage/model/user.go | 45 +++ .../db/cache/config.go => localcache/init.go} | 43 +- pkg/rpccache/conversation.go | 2 +- pkg/rpccache/friend.go | 10 +- pkg/rpccache/group.go | 2 +- pkg/rpccache/user.go | 2 +- test/testdata/README.md | 2 +- 132 files changed, 2703 insertions(+), 2255 deletions(-) delete mode 100644 pkg/common/db/cache/conversation.go delete mode 100644 pkg/common/db/cache/meta_cache.go delete mode 100644 pkg/common/db/cache/third.go delete mode 100644 pkg/common/db/table/relation/doc.go create mode 100644 pkg/common/storage/cache/batch_handler.go create mode 100644 pkg/common/storage/cache/black.go rename pkg/common/{ => storage/cache}/cachekey/black.go (100%) rename pkg/common/{ => storage/cache}/cachekey/conversation.go (100%) rename pkg/common/{ => storage/cache}/cachekey/doc.go (95%) rename pkg/common/{ => storage/cache}/cachekey/friend.go (100%) rename pkg/common/{ => storage/cache}/cachekey/group.go (100%) create mode 100644 pkg/common/storage/cache/cachekey/msg.go create mode 100644 pkg/common/storage/cache/cachekey/s3.go create mode 100644 pkg/common/storage/cache/cachekey/seq.go create mode 100644 pkg/common/storage/cache/cachekey/third.go rename pkg/common/{ => storage/cache}/cachekey/token.go (100%) rename pkg/common/{ => storage/cache}/cachekey/user.go (87%) create mode 100644 pkg/common/storage/cache/conversation.go rename pkg/common/{db => storage}/cache/doc.go (96%) create mode 100644 pkg/common/storage/cache/friend.go create mode 100644 pkg/common/storage/cache/group.go create mode 100644 pkg/common/storage/cache/msg.go create mode 100644 pkg/common/storage/cache/redis/batch_handler.go rename pkg/common/{db/cache => storage/cache/redis}/black.go (59%) create mode 100644 pkg/common/storage/cache/redis/conversation.go create mode 100644 pkg/common/storage/cache/redis/doc.go rename pkg/common/{db/cache => storage/cache/redis}/friend.go (67%) rename pkg/common/{db/cache => storage/cache/redis}/group.go (61%) create mode 100644 pkg/common/storage/cache/redis/meta_cache.go rename pkg/common/{db/cache => storage/cache/redis}/msg.go (68%) rename pkg/common/{db/cache => storage/cache/redis}/msg_test.go (99%) rename pkg/common/{db/cache => storage/cache/redis}/s3.go (52%) rename pkg/common/{db/cache => storage/cache/redis}/seq.go (73%) create mode 100644 pkg/common/storage/cache/redis/third.go rename pkg/common/{db/cache => storage/cache/redis}/token.go (60%) rename pkg/common/{db/cache => storage/cache/redis}/user.go (78%) create mode 100644 pkg/common/storage/cache/s3.go create mode 100644 pkg/common/storage/cache/seq.go create mode 100644 pkg/common/storage/cache/third.go create mode 100644 pkg/common/storage/cache/token.go create mode 100644 pkg/common/storage/cache/user.go create mode 100644 pkg/common/storage/common/types.go rename pkg/common/{db => storage}/controller/auth.go (97%) rename pkg/common/{db => storage}/controller/black.go (75%) rename pkg/common/{db => storage}/controller/conversation.go (86%) rename pkg/common/{db => storage}/controller/doc.go (94%) rename pkg/common/{db => storage}/controller/friend.go (82%) rename pkg/common/{db => storage}/controller/group.go (77%) rename pkg/common/{db => storage}/controller/msg.go (93%) rename pkg/common/{db => storage}/controller/push.go (94%) rename pkg/common/{db => storage}/controller/s3.go (84%) rename pkg/common/{db => storage}/controller/third.go (80%) rename pkg/common/{db => storage}/controller/user.go (82%) rename pkg/common/{db/table/relation => storage/database}/black.go (51%) rename pkg/common/{db/table/relation => storage/database}/conversation.go (56%) create mode 100644 pkg/common/storage/database/doc.go rename pkg/common/{db/table/relation => storage/database}/friend.go (70%) rename pkg/common/{db/table/relation => storage/database}/friend_request.go (60%) create mode 100644 pkg/common/storage/database/group.go rename pkg/common/{db/table/relation => storage/database}/group_member.go (56%) rename pkg/common/{db/table/relation => storage/database}/group_request.go (55%) create mode 100644 pkg/common/storage/database/log.go rename pkg/common/{db => storage/database}/mgo/black.go (67%) rename pkg/common/{db => storage/database}/mgo/conversation.go (84%) rename pkg/common/{db => storage/database}/mgo/doc.go (96%) rename pkg/common/{db => storage/database}/mgo/friend.go (80%) rename pkg/common/{db => storage/database}/mgo/friend_request.go (76%) rename pkg/common/{db => storage/database}/mgo/group.go (82%) rename pkg/common/{db => storage/database}/mgo/group_member.go (83%) rename pkg/common/{db => storage/database}/mgo/group_request.go (69%) rename pkg/common/{db/table/relation/utils.go => storage/database/mgo/helpers.go} (80%) rename pkg/common/{db => storage/database}/mgo/log.go (75%) rename pkg/common/{db => storage/database}/mgo/msg.go (91%) rename pkg/common/{db => storage/database}/mgo/object.go (79%) rename pkg/common/{db => storage/database}/mgo/subscribe.go (93%) rename pkg/common/{db => storage/database}/mgo/user.go (87%) create mode 100644 pkg/common/storage/database/msg.go create mode 100644 pkg/common/storage/database/object.go rename pkg/common/{db/table/relation => storage/database}/subscribe.go (74%) rename pkg/common/{db/table/relation => storage/database}/user.go (63%) create mode 100644 pkg/common/storage/model/black.go create mode 100644 pkg/common/storage/model/conversation.go create mode 100644 pkg/common/storage/model/doc.go create mode 100644 pkg/common/storage/model/friend.go create mode 100644 pkg/common/storage/model/friend_request.go rename pkg/common/{db/table/relation => storage/model}/group.go (62%) create mode 100644 pkg/common/storage/model/group_member.go create mode 100644 pkg/common/storage/model/group_request.go rename pkg/common/{db/table/relation => storage/model}/log.go (67%) rename pkg/common/{db/table/relation => storage/model}/msg.go (65%) rename pkg/common/{db/table/relation => storage/model}/object.go (76%) create mode 100644 pkg/common/storage/model/subscribe.go create mode 100644 pkg/common/storage/model/user.go rename pkg/{common/db/cache/config.go => localcache/init.go} (73%) diff --git a/internal/msgtransfer/init.go b/internal/msgtransfer/init.go index 3384b84937..ba82abacfd 100644 --- a/internal/msgtransfer/init.go +++ b/internal/msgtransfer/init.go @@ -17,6 +17,8 @@ package msgtransfer import ( "context" "fmt" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/cache/redis" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/database/mgo" "github.com/openimsdk/tools/db/mongoutil" "github.com/openimsdk/tools/db/redisutil" "github.com/openimsdk/tools/utils/datautil" @@ -26,11 +28,9 @@ import ( "syscall" "github.com/openimsdk/open-im-server/v3/pkg/common/config" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/mgo" kdisc "github.com/openimsdk/open-im-server/v3/pkg/common/discoveryregister" "github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/controller" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" "github.com/openimsdk/tools/errs" "github.com/openimsdk/tools/log" @@ -83,8 +83,8 @@ func Start(ctx context.Context, index int, config *Config) error { client.AddOption(mw.GrpcClient(), grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithDefaultServiceConfig(fmt.Sprintf(`{"LoadBalancingPolicy": "%s"}`, "round_robin"))) //todo MsgCacheTimeout - msgModel := cache.NewMsgCache(rdb, config.RedisConfig.EnablePipeline) - seqModel := cache.NewSeqCache(rdb) + msgModel := redis.NewMsgCache(rdb, config.RedisConfig.EnablePipeline) + seqModel := redis.NewSeqCache(rdb) msgDocModel, err := mgo.NewMsgMongo(mgocli.GetDB()) if err != nil { return err diff --git a/internal/msgtransfer/online_history_msg_handler.go b/internal/msgtransfer/online_history_msg_handler.go index 551e3fe911..194b70187e 100644 --- a/internal/msgtransfer/online_history_msg_handler.go +++ b/internal/msgtransfer/online_history_msg_handler.go @@ -25,7 +25,7 @@ import ( "github.com/IBM/sarama" "github.com/go-redis/redis" "github.com/openimsdk/open-im-server/v3/pkg/common/config" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/controller" "github.com/openimsdk/open-im-server/v3/pkg/msgprocessor" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" "github.com/openimsdk/protocol/constant" diff --git a/internal/msgtransfer/online_msg_to_mongo_handler.go b/internal/msgtransfer/online_msg_to_mongo_handler.go index c9c0358935..0fa9fe0d12 100644 --- a/internal/msgtransfer/online_msg_to_mongo_handler.go +++ b/internal/msgtransfer/online_msg_to_mongo_handler.go @@ -19,8 +19,8 @@ import ( "github.com/IBM/sarama" "github.com/openimsdk/open-im-server/v3/pkg/common/config" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" "github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/controller" pbmsg "github.com/openimsdk/protocol/msg" "github.com/openimsdk/tools/log" "github.com/openimsdk/tools/mq/kafka" diff --git a/internal/push/offlinepush/fcm/push.go b/internal/push/offlinepush/fcm/push.go index 34ad1c0d6c..ec973008e3 100644 --- a/internal/push/offlinepush/fcm/push.go +++ b/internal/push/offlinepush/fcm/push.go @@ -22,7 +22,7 @@ import ( firebase "firebase.google.com/go" "firebase.google.com/go/messaging" "github.com/openimsdk/open-im-server/v3/pkg/common/config" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/cache" "github.com/openimsdk/protocol/constant" "github.com/openimsdk/tools/errs" "github.com/redis/go-redis/v9" diff --git a/internal/push/offlinepush/getui/push.go b/internal/push/offlinepush/getui/push.go index 8ecea3a622..27b19e8fe0 100644 --- a/internal/push/offlinepush/getui/push.go +++ b/internal/push/offlinepush/getui/push.go @@ -24,7 +24,7 @@ import ( "time" "github.com/openimsdk/open-im-server/v3/pkg/common/config" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/cache" "github.com/openimsdk/tools/errs" "github.com/openimsdk/tools/log" "github.com/openimsdk/tools/mcontext" diff --git a/internal/push/offlinepush/offlinepusher.go b/internal/push/offlinepush/offlinepusher.go index d4fcae434a..8dc8a0bc6b 100644 --- a/internal/push/offlinepush/offlinepusher.go +++ b/internal/push/offlinepush/offlinepusher.go @@ -22,7 +22,7 @@ import ( "github.com/openimsdk/open-im-server/v3/internal/push/offlinepush/jpush" "github.com/openimsdk/open-im-server/v3/internal/push/offlinepush/options" "github.com/openimsdk/open-im-server/v3/pkg/common/config" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/cache" ) const ( diff --git a/internal/push/push.go b/internal/push/push.go index 2e5c4e5265..c7e245dfe2 100644 --- a/internal/push/push.go +++ b/internal/push/push.go @@ -4,8 +4,8 @@ import ( "context" "github.com/openimsdk/open-im-server/v3/internal/push/offlinepush" "github.com/openimsdk/open-im-server/v3/pkg/common/config" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/cache/redis" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/controller" pbpush "github.com/openimsdk/protocol/push" "github.com/openimsdk/tools/db/redisutil" "github.com/openimsdk/tools/discovery" @@ -49,7 +49,7 @@ func Start(ctx context.Context, config *Config, client discovery.SvcDiscoveryReg if err != nil { return err } - cacheModel := cache.NewThirdCache(rdb) + cacheModel := redis.NewThirdCache(rdb) offlinePusher, err := offlinepush.NewOfflinePusher(&config.RpcConfig, cacheModel) if err != nil { return err diff --git a/internal/rpc/auth/auth.go b/internal/rpc/auth/auth.go index ddb655398d..6270b39b3a 100644 --- a/internal/rpc/auth/auth.go +++ b/internal/rpc/auth/auth.go @@ -17,14 +17,14 @@ package auth import ( "context" "github.com/openimsdk/open-im-server/v3/pkg/common/config" + redis2 "github.com/openimsdk/open-im-server/v3/pkg/common/storage/cache/redis" "github.com/openimsdk/tools/db/redisutil" "github.com/redis/go-redis/v9" "github.com/openimsdk/open-im-server/v3/pkg/authverify" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" "github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics" "github.com/openimsdk/open-im-server/v3/pkg/common/servererrs" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/controller" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" pbauth "github.com/openimsdk/protocol/auth" "github.com/openimsdk/protocol/constant" @@ -61,7 +61,7 @@ func Start(ctx context.Context, config *Config, client discovery.SvcDiscoveryReg userRpcClient: &userRpcClient, RegisterCenter: client, authDatabase: controller.NewAuthDatabase( - cache.NewTokenCacheModel(rdb), + redis2.NewTokenCacheModel(rdb), config.Share.Secret, config.RpcConfig.TokenPolicy.Expire, ), diff --git a/internal/rpc/conversation/conversaion.go b/internal/rpc/conversation/conversaion.go index 4c7828610f..df9267ae04 100644 --- a/internal/rpc/conversation/conversaion.go +++ b/internal/rpc/conversation/conversaion.go @@ -17,15 +17,16 @@ package conversation import ( "context" "github.com/openimsdk/open-im-server/v3/pkg/common/config" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/cache/redis" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/database/mgo" + tablerelation "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model" + "github.com/openimsdk/open-im-server/v3/pkg/localcache" "github.com/openimsdk/tools/db/redisutil" "sort" "github.com/openimsdk/open-im-server/v3/pkg/common/convert" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/mgo" - tablerelation "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" "github.com/openimsdk/open-im-server/v3/pkg/common/servererrs" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/controller" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" "github.com/openimsdk/protocol/constant" pbconversation "github.com/openimsdk/protocol/conversation" @@ -73,13 +74,14 @@ func Start(ctx context.Context, config *Config, client discovery.SvcDiscoveryReg groupRpcClient := rpcclient.NewGroupRpcClient(client, config.Share.RpcRegisterName.Group) msgRpcClient := rpcclient.NewMessageRpcClient(client, config.Share.RpcRegisterName.Msg) userRpcClient := rpcclient.NewUserRpcClient(client, config.Share.RpcRegisterName.User, config.Share.IMAdminUserID) - cache.InitLocalCache(&config.LocalCacheConfig) + localcache.InitLocalCache(&config.LocalCacheConfig) pbconversation.RegisterConversationServer(server, &conversationServer{ msgRpcClient: &msgRpcClient, user: &userRpcClient, conversationNotificationSender: NewConversationNotificationSender(&config.NotificationConfig, &msgRpcClient), groupRpcClient: &groupRpcClient, - conversationDatabase: controller.NewConversationDatabase(conversationDB, cache.NewConversationRedis(rdb, &config.LocalCacheConfig, cache.GetDefaultOpt(), conversationDB), mgocli.GetTx()), + conversationDatabase: controller.NewConversationDatabase(conversationDB, + redis.NewConversationRedis(rdb, &config.LocalCacheConfig, redis.GetRocksCacheOptions(), conversationDB), mgocli.GetTx()), }) return nil } @@ -192,11 +194,11 @@ func (c *conversationServer) GetConversations(ctx context.Context, req *pbconver } func (c *conversationServer) SetConversation(ctx context.Context, req *pbconversation.SetConversationReq) (*pbconversation.SetConversationResp, error) { - var conversation tablerelation.ConversationModel + var conversation tablerelation.Conversation if err := datautil.CopyStructFields(&conversation, req.Conversation); err != nil { return nil, err } - err := c.conversationDatabase.SetUserConversations(ctx, req.Conversation.OwnerUserID, []*tablerelation.ConversationModel{&conversation}) + err := c.conversationDatabase.SetUserConversations(ctx, req.Conversation.OwnerUserID, []*tablerelation.Conversation{&conversation}) if err != nil { return nil, err } @@ -220,7 +222,7 @@ func (c *conversationServer) SetConversations(ctx context.Context, req *pbconver } } var unequal int - var conv tablerelation.ConversationModel + var conv tablerelation.Conversation if len(req.UserIDs) == 1 { cs, err := c.conversationDatabase.FindConversations(ctx, req.UserIDs[0], []string{req.Conversation.ConversationID}) if err != nil { @@ -231,7 +233,7 @@ func (c *conversationServer) SetConversations(ctx context.Context, req *pbconver } conv = *cs[0] } - var conversation tablerelation.ConversationModel + var conversation tablerelation.Conversation conversation.ConversationID = req.Conversation.ConversationID conversation.ConversationType = req.Conversation.ConversationType conversation.UserID = req.Conversation.UserID @@ -280,7 +282,7 @@ func (c *conversationServer) SetConversations(ctx context.Context, req *pbconver } } if req.Conversation.IsPrivateChat != nil && req.Conversation.ConversationType != constant.ReadGroupChatType { - var conversations []*tablerelation.ConversationModel + var conversations []*tablerelation.Conversation for _, ownerUserID := range req.UserIDs { conversation2 := conversation conversation2.OwnerUserID = ownerUserID @@ -328,12 +330,12 @@ func (c *conversationServer) CreateSingleChatConversations(ctx context.Context, ) (*pbconversation.CreateSingleChatConversationsResp, error) { switch req.ConversationType { case constant.SingleChatType: - var conversation tablerelation.ConversationModel + var conversation tablerelation.Conversation conversation.ConversationID = req.ConversationID conversation.ConversationType = req.ConversationType conversation.OwnerUserID = req.SendID conversation.UserID = req.RecvID - err := c.conversationDatabase.CreateConversation(ctx, []*tablerelation.ConversationModel{&conversation}) + err := c.conversationDatabase.CreateConversation(ctx, []*tablerelation.Conversation{&conversation}) if err != nil { log.ZWarn(ctx, "create conversation failed", err, "conversation", conversation) } @@ -341,17 +343,17 @@ func (c *conversationServer) CreateSingleChatConversations(ctx context.Context, conversation2 := conversation conversation2.OwnerUserID = req.RecvID conversation2.UserID = req.SendID - err = c.conversationDatabase.CreateConversation(ctx, []*tablerelation.ConversationModel{&conversation2}) + err = c.conversationDatabase.CreateConversation(ctx, []*tablerelation.Conversation{&conversation2}) if err != nil { log.ZWarn(ctx, "create conversation failed", err, "conversation2", conversation) } case constant.NotificationChatType: - var conversation tablerelation.ConversationModel + var conversation tablerelation.Conversation conversation.ConversationID = req.ConversationID conversation.ConversationType = req.ConversationType conversation.OwnerUserID = req.RecvID conversation.UserID = req.SendID - err := c.conversationDatabase.CreateConversation(ctx, []*tablerelation.ConversationModel{&conversation}) + err := c.conversationDatabase.CreateConversation(ctx, []*tablerelation.Conversation{&conversation}) if err != nil { log.ZWarn(ctx, "create conversation failed", err, "conversation2", conversation) } diff --git a/internal/rpc/friend/black.go b/internal/rpc/friend/black.go index 1f52286f34..caec08b7ac 100644 --- a/internal/rpc/friend/black.go +++ b/internal/rpc/friend/black.go @@ -16,11 +16,11 @@ package friend import ( "context" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model" "time" "github.com/openimsdk/open-im-server/v3/pkg/authverify" "github.com/openimsdk/open-im-server/v3/pkg/common/convert" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" pbfriend "github.com/openimsdk/protocol/friend" "github.com/openimsdk/tools/mcontext" ) @@ -58,7 +58,7 @@ func (s *friendServer) RemoveBlack(ctx context.Context, req *pbfriend.RemoveBlac return nil, err } - if err := s.blackDatabase.Delete(ctx, []*relation.BlackModel{{OwnerUserID: req.OwnerUserID, BlockUserID: req.BlackUserID}}); err != nil { + if err := s.blackDatabase.Delete(ctx, []*model.Black{{OwnerUserID: req.OwnerUserID, BlockUserID: req.BlackUserID}}); err != nil { return nil, err } @@ -75,7 +75,7 @@ func (s *friendServer) AddBlack(ctx context.Context, req *pbfriend.AddBlackReq) if err != nil { return nil, err } - black := relation.BlackModel{ + black := model.Black{ OwnerUserID: req.OwnerUserID, BlockUserID: req.BlackUserID, OperatorUserID: mcontext.GetOpUserID(ctx), @@ -83,7 +83,7 @@ func (s *friendServer) AddBlack(ctx context.Context, req *pbfriend.AddBlackReq) Ex: req.Ex, } - if err := s.blackDatabase.Create(ctx, []*relation.BlackModel{&black}); err != nil { + if err := s.blackDatabase.Create(ctx, []*model.Black{&black}); err != nil { return nil, err } s.notificationSender.BlackAddedNotification(ctx, req) diff --git a/internal/rpc/friend/friend.go b/internal/rpc/friend/friend.go index b49490f264..8b2dea995f 100644 --- a/internal/rpc/friend/friend.go +++ b/internal/rpc/friend/friend.go @@ -17,16 +17,17 @@ package friend import ( "context" "github.com/openimsdk/open-im-server/v3/pkg/common/config" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/cache/redis" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/database/mgo" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model" "github.com/openimsdk/open-im-server/v3/pkg/common/webhook" + "github.com/openimsdk/open-im-server/v3/pkg/localcache" "github.com/openimsdk/tools/db/redisutil" "github.com/openimsdk/open-im-server/v3/pkg/authverify" "github.com/openimsdk/open-im-server/v3/pkg/common/convert" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/mgo" - tablerelation "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" "github.com/openimsdk/open-im-server/v3/pkg/common/servererrs" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/controller" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" "github.com/openimsdk/protocol/constant" pbfriend "github.com/openimsdk/protocol/friend" @@ -96,19 +97,19 @@ func Start(ctx context.Context, config *Config, client discovery.SvcDiscoveryReg &msgRpcClient, WithRpcFunc(userRpcClient.GetUsersInfo), ) - cache.InitLocalCache(&config.LocalCacheConfig) + localcache.InitLocalCache(&config.LocalCacheConfig) // Register Friend server with refactored MongoDB and Redis integrations pbfriend.RegisterFriendServer(server, &friendServer{ friendDatabase: controller.NewFriendDatabase( friendMongoDB, friendRequestMongoDB, - cache.NewFriendCacheRedis(rdb, &config.LocalCacheConfig, friendMongoDB, cache.GetDefaultOpt()), + redis.NewFriendCacheRedis(rdb, &config.LocalCacheConfig, friendMongoDB, redis.GetRocksCacheOptions()), mgocli.GetTx(), ), blackDatabase: controller.NewBlackDatabase( blackMongoDB, - cache.NewBlackCacheRedis(rdb, &config.LocalCacheConfig, blackMongoDB, cache.GetDefaultOpt()), + redis.NewBlackCacheRedis(rdb, &config.LocalCacheConfig, blackMongoDB, redis.GetRocksCacheOptions()), ), userRpcClient: &userRpcClient, notificationSender: notificationSender, @@ -193,7 +194,7 @@ func (s *friendServer) RespondFriendApply(ctx context.Context, req *pbfriend.Res return nil, err } - friendRequest := tablerelation.FriendRequestModel{ + friendRequest := model.FriendRequest{ FromUserID: req.FromUserID, ToUserID: req.ToUserID, HandleMsg: req.HandleMsg, @@ -384,10 +385,10 @@ func (s *friendServer) GetSpecifiedFriendsInfo(ctx context.Context, req *pbfrien if err != nil { return nil, err } - friendMap := datautil.SliceToMap(friends, func(e *tablerelation.FriendModel) string { + friendMap := datautil.SliceToMap(friends, func(e *model.Friend) string { return e.FriendUserID }) - blackMap := datautil.SliceToMap(blacks, func(e *tablerelation.BlackModel) string { + blackMap := datautil.SliceToMap(blacks, func(e *model.Black) string { return e.BlockUserID }) resp := &pbfriend.GetSpecifiedFriendsInfoResp{ diff --git a/internal/rpc/friend/notification.go b/internal/rpc/friend/notification.go index f88c9664e6..8089a9bdc8 100644 --- a/internal/rpc/friend/notification.go +++ b/internal/rpc/friend/notification.go @@ -16,11 +16,11 @@ package friend import ( "context" + relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model" "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/convert" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" - relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/controller" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient/notification" "github.com/openimsdk/protocol/constant" @@ -46,7 +46,7 @@ func WithFriendDB(db controller.FriendDatabase) friendNotificationSenderOptions } func WithDBFunc( - fn func(ctx context.Context, userIDs []string) (users []*relationtb.UserModel, err error), + fn func(ctx context.Context, userIDs []string) (users []*relationtb.User, err error), ) friendNotificationSenderOptions { return func(s *FriendNotificationSender) { f := func(ctx context.Context, userIDs []string) (result []notification.CommonUser, err error) { diff --git a/internal/rpc/group/callback.go b/internal/rpc/group/callback.go index 1690e3973f..f31c4587c5 100644 --- a/internal/rpc/group/callback.go +++ b/internal/rpc/group/callback.go @@ -19,7 +19,7 @@ import ( "github.com/openimsdk/open-im-server/v3/pkg/apistruct" "github.com/openimsdk/open-im-server/v3/pkg/callbackstruct" "github.com/openimsdk/open-im-server/v3/pkg/common/config" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model" "github.com/openimsdk/open-im-server/v3/pkg/common/webhook" "github.com/openimsdk/protocol/constant" "github.com/openimsdk/protocol/group" @@ -100,7 +100,7 @@ func (s *groupServer) webhookAfterCreateGroup(ctx context.Context, after *config s.webhookClient.AsyncPost(ctx, cbReq.GetCallbackCommand(), cbReq, &callbackstruct.CallbackAfterCreateGroupResp{}, after) } -func (s *groupServer) webhookBeforeMemberJoinGroup(ctx context.Context, before *config.BeforeConfig, groupMember *relation.GroupMemberModel, groupEx string) error { +func (s *groupServer) webhookBeforeMemberJoinGroup(ctx context.Context, before *config.BeforeConfig, groupMember *model.GroupMember, groupEx string) error { return webhook.WithCondition(ctx, before, func(ctx context.Context) error { cbReq := &callbackstruct.CallbackBeforeMemberJoinGroupReq{ CallbackCommand: callbackstruct.CallbackBeforeMemberJoinGroupCommand, diff --git a/internal/rpc/group/convert.go b/internal/rpc/group/convert.go index 86978ce3ae..a75693904d 100644 --- a/internal/rpc/group/convert.go +++ b/internal/rpc/group/convert.go @@ -15,11 +15,11 @@ package group import ( - "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model" "github.com/openimsdk/protocol/sdkws" ) -func (s *groupServer) groupDB2PB(group *relation.GroupModel, ownerUserID string, memberCount uint32) *sdkws.GroupInfo { +func (s *groupServer) groupDB2PB(group *model.Group, ownerUserID string, memberCount uint32) *sdkws.GroupInfo { return &sdkws.GroupInfo{ GroupID: group.GroupID, GroupName: group.GroupName, @@ -41,7 +41,7 @@ func (s *groupServer) groupDB2PB(group *relation.GroupModel, ownerUserID string, } } -func (s *groupServer) groupMemberDB2PB(member *relation.GroupMemberModel, appMangerLevel int32) *sdkws.GroupMemberFullInfo { +func (s *groupServer) groupMemberDB2PB(member *model.GroupMember, appMangerLevel int32) *sdkws.GroupMemberFullInfo { return &sdkws.GroupMemberFullInfo{ GroupID: member.GroupID, UserID: member.UserID, diff --git a/internal/rpc/group/fill.go b/internal/rpc/group/fill.go index c504db8d6e..1c86481df8 100644 --- a/internal/rpc/group/fill.go +++ b/internal/rpc/group/fill.go @@ -16,10 +16,9 @@ package group import ( "context" - - relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" + relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model" ) -func (s *groupServer) PopulateGroupMember(ctx context.Context, members ...*relationtb.GroupMemberModel) error { +func (s *groupServer) PopulateGroupMember(ctx context.Context, members ...*relationtb.GroupMember) error { return s.notification.PopulateGroupMember(ctx, members...) } diff --git a/internal/rpc/group/group.go b/internal/rpc/group/group.go index 551554c236..51fd2d7b66 100644 --- a/internal/rpc/group/group.go +++ b/internal/rpc/group/group.go @@ -18,8 +18,11 @@ import ( "context" "fmt" "github.com/openimsdk/open-im-server/v3/pkg/common/config" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/common" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/database/mgo" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model" "github.com/openimsdk/open-im-server/v3/pkg/common/webhook" + "github.com/openimsdk/open-im-server/v3/pkg/localcache" "math/big" "math/rand" "strconv" @@ -29,10 +32,8 @@ import ( "github.com/openimsdk/open-im-server/v3/pkg/authverify" "github.com/openimsdk/open-im-server/v3/pkg/callbackstruct" "github.com/openimsdk/open-im-server/v3/pkg/common/convert" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/mgo" - relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" "github.com/openimsdk/open-im-server/v3/pkg/common/servererrs" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/controller" "github.com/openimsdk/open-im-server/v3/pkg/msgprocessor" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient/grouphash" @@ -110,7 +111,7 @@ func Start(ctx context.Context, config *Config, client discovery.SvcDiscoveryReg } return datautil.Slice(users, func(e *sdkws.UserInfo) notification.CommonUser { return e }), nil }) - cache.InitLocalCache(&config.LocalCacheConfig) + localcache.InitLocalCache(&config.LocalCacheConfig) gs.conversationRpcClient = conversationRpcClient gs.msgRpcClient = msgRpcClient gs.config = config @@ -234,14 +235,14 @@ func (s *groupServer) CreateGroup(ctx context.Context, req *pbgroup.CreateGroupR return nil, err } - var groupMembers []*relationtb.GroupMemberModel + var groupMembers []*model.GroupMember group := convert.Pb2DBGroupInfo(req.GroupInfo) if err := s.GenGroupID(ctx, &group.GroupID); err != nil { return nil, err } joinGroup := func(userID string, roleLevel int32) error { - groupMember := &relationtb.GroupMemberModel{ + groupMember := &model.GroupMember{ GroupID: group.GroupID, UserID: userID, RoleLevel: roleLevel, @@ -271,7 +272,7 @@ func (s *groupServer) CreateGroup(ctx context.Context, req *pbgroup.CreateGroupR return nil, err } } - if err := s.db.CreateGroup(ctx, []*relationtb.GroupModel{group}, groupMembers); err != nil { + if err := s.db.CreateGroup(ctx, []*model.Group{group}, groupMembers); err != nil { return nil, err } resp := &pbgroup.CreateGroupResp{GroupInfo: &sdkws.GroupInfo{}} @@ -339,7 +340,7 @@ func (s *groupServer) GetJoinedGroupList(ctx context.Context, req *pbgroup.GetJo if len(members) == 0 { return &resp, nil } - groupIDs := datautil.Slice(members, func(e *relationtb.GroupMemberModel) string { + groupIDs := datautil.Slice(members, func(e *model.GroupMember) string { return e.GroupID }) groups, err := s.db.FindGroup(ctx, groupIDs) @@ -357,12 +358,12 @@ func (s *groupServer) GetJoinedGroupList(ctx context.Context, req *pbgroup.GetJo if err := s.PopulateGroupMember(ctx, members...); err != nil { return nil, err } - ownerMap := datautil.SliceToMap(owners, func(e *relationtb.GroupMemberModel) string { + ownerMap := datautil.SliceToMap(owners, func(e *model.GroupMember) string { return e.GroupID }) - resp.Groups = datautil.Slice(datautil.Order(groupIDs, groups, func(group *relationtb.GroupModel) string { + resp.Groups = datautil.Slice(datautil.Order(groupIDs, groups, func(group *model.Group) string { return group.GroupID - }), func(group *relationtb.GroupModel) *sdkws.GroupInfo { + }), func(group *model.Group) *sdkws.GroupInfo { var userID string if user := ownerMap[group.GroupID]; user != nil { userID = user.UserID @@ -397,7 +398,7 @@ func (s *groupServer) InviteUserToGroup(ctx context.Context, req *pbgroup.Invite return nil, errs.ErrRecordNotFound.WrapMsg("user not found") } - var groupMember *relationtb.GroupMemberModel + var groupMember *model.GroupMember var opUserID string if !authverify.IsAppManagerUid(ctx, s.config.Share.IMAdminUserID) { opUserID = mcontext.GetOpUserID(ctx) @@ -418,9 +419,9 @@ func (s *groupServer) InviteUserToGroup(ctx context.Context, req *pbgroup.Invite if group.NeedVerification == constant.AllNeedVerification { if !authverify.IsAppManagerUid(ctx, s.config.Share.IMAdminUserID) { if !(groupMember.RoleLevel == constant.GroupOwner || groupMember.RoleLevel == constant.GroupAdmin) { - var requests []*relationtb.GroupRequestModel + var requests []*model.GroupRequest for _, userID := range req.InvitedUserIDs { - requests = append(requests, &relationtb.GroupRequestModel{ + requests = append(requests, &model.GroupRequest{ UserID: userID, GroupID: req.GroupID, JoinSource: constant.JoinByInvitation, @@ -444,9 +445,9 @@ func (s *groupServer) InviteUserToGroup(ctx context.Context, req *pbgroup.Invite } } } - var groupMembers []*relationtb.GroupMemberModel + var groupMembers []*model.GroupMember for _, userID := range req.InvitedUserIDs { - member := &relationtb.GroupMemberModel{ + member := &model.GroupMember{ GroupID: req.GroupID, UserID: userID, RoleLevel: constant.GroupOrdinaryUsers, @@ -482,7 +483,7 @@ func (s *groupServer) GetGroupAllMember(ctx context.Context, req *pbgroup.GetGro return nil, err } var resp pbgroup.GetGroupAllMemberResp - resp.Members = datautil.Slice(members, func(e *relationtb.GroupMemberModel) *sdkws.GroupMemberFullInfo { + resp.Members = datautil.Slice(members, func(e *model.GroupMember) *sdkws.GroupMemberFullInfo { return convert.Db2PbGroupMember(e) }) return &resp, nil @@ -491,7 +492,7 @@ func (s *groupServer) GetGroupAllMember(ctx context.Context, req *pbgroup.GetGro func (s *groupServer) GetGroupMemberList(ctx context.Context, req *pbgroup.GetGroupMemberListReq) (*pbgroup.GetGroupMemberListResp, error) { var ( total int64 - members []*relationtb.GroupMemberModel + members []*model.GroupMember err error ) if req.Keyword == "" { @@ -506,7 +507,7 @@ func (s *groupServer) GetGroupMemberList(ctx context.Context, req *pbgroup.GetGr return nil, err } if req.Keyword != "" { - groupMembers := make([]*relationtb.GroupMemberModel, 0) + groupMembers := make([]*model.GroupMember, 0) for _, member := range members { if member.UserID == req.Keyword { groupMembers = append(groupMembers, member) @@ -554,7 +555,7 @@ func (s *groupServer) KickGroupMember(ctx context.Context, req *pbgroup.KickGrou if err := s.PopulateGroupMember(ctx, members...); err != nil { return nil, err } - memberMap := make(map[string]*relationtb.GroupMemberModel) + memberMap := make(map[string]*model.GroupMember) for i, member := range members { memberMap[member.UserID] = members[i] } @@ -649,7 +650,7 @@ func (s *groupServer) GetGroupMembersInfo(ctx context.Context, req *pbgroup.GetG return nil, err } return &pbgroup.GetGroupMembersInfoResp{ - Members: datautil.Slice(members, func(e *relationtb.GroupMemberModel) *sdkws.GroupMemberFullInfo { + Members: datautil.Slice(members, func(e *model.GroupMember) *sdkws.GroupMemberFullInfo { return convert.Db2PbGroupMember(e) }), }, nil @@ -687,7 +688,7 @@ func (s *groupServer) GetGroupApplicationList(ctx context.Context, req *pbgroup. if err != nil { return nil, err } - groupMap := datautil.SliceToMap(groups, func(e *relationtb.GroupModel) string { + groupMap := datautil.SliceToMap(groups, func(e *model.Group) string { return e.GroupID }) if ids := datautil.Single(datautil.Keys(groupMap), groupIDs); len(ids) > 0 { @@ -704,10 +705,10 @@ func (s *groupServer) GetGroupApplicationList(ctx context.Context, req *pbgroup. if err := s.PopulateGroupMember(ctx, owners...); err != nil { return nil, err } - ownerMap := datautil.SliceToMap(owners, func(e *relationtb.GroupMemberModel) string { + ownerMap := datautil.SliceToMap(owners, func(e *model.GroupMember) string { return e.GroupID }) - resp.GroupRequests = datautil.Slice(groupRequests, func(e *relationtb.GroupRequestModel) *sdkws.GroupRequest { + resp.GroupRequests = datautil.Slice(groupRequests, func(e *model.GroupRequest) *sdkws.GroupRequest { var ownerUserID string if owner, ok := ownerMap[e.GroupID]; ok { ownerUserID = owner.UserID @@ -736,11 +737,11 @@ func (s *groupServer) GetGroupsInfo(ctx context.Context, req *pbgroup.GetGroupsI if err := s.PopulateGroupMember(ctx, owners...); err != nil { return nil, err } - ownerMap := datautil.SliceToMap(owners, func(e *relationtb.GroupMemberModel) string { + ownerMap := datautil.SliceToMap(owners, func(e *model.GroupMember) string { return e.GroupID }) return &pbgroup.GetGroupsInfoResp{ - GroupInfos: datautil.Slice(groups, func(e *relationtb.GroupModel) *sdkws.GroupInfo { + GroupInfos: datautil.Slice(groups, func(e *model.Group) *sdkws.GroupInfo { var ownerUserID string if owner, ok := ownerMap[e.GroupID]; ok { ownerUserID = owner.UserID @@ -783,9 +784,9 @@ func (s *groupServer) GroupApplicationResponse(ctx context.Context, req *pbgroup if _, err := s.user.GetPublicUserInfo(ctx, req.FromUserID); err != nil { return nil, err } - var member *relationtb.GroupMemberModel + var member *model.GroupMember if (!inGroup) && req.HandleResult == constant.GroupResponseAgree { - member = &relationtb.GroupMemberModel{ + member = &model.GroupMember{ GroupID: req.GroupID, UserID: req.FromUserID, Nickname: "", @@ -857,7 +858,7 @@ func (s *groupServer) JoinGroup(ctx context.Context, req *pbgroup.JoinGroupReq) } log.ZDebug(ctx, "JoinGroup.groupInfo", "group", group, "eq", group.NeedVerification == constant.Directly) if group.NeedVerification == constant.Directly { - groupMember := &relationtb.GroupMemberModel{ + groupMember := &model.GroupMember{ GroupID: group.GroupID, UserID: user.UserID, RoleLevel: constant.GroupOrdinaryUsers, @@ -871,7 +872,7 @@ func (s *groupServer) JoinGroup(ctx context.Context, req *pbgroup.JoinGroupReq) return nil, err } - if err := s.db.CreateGroup(ctx, nil, []*relationtb.GroupMemberModel{groupMember}); err != nil { + if err := s.db.CreateGroup(ctx, nil, []*model.GroupMember{groupMember}); err != nil { return nil, err } @@ -883,7 +884,7 @@ func (s *groupServer) JoinGroup(ctx context.Context, req *pbgroup.JoinGroupReq) return &pbgroup.JoinGroupResp{}, nil } - groupRequest := relationtb.GroupRequestModel{ + groupRequest := model.GroupRequest{ UserID: req.InviterUserID, ReqMsg: req.ReqMessage, GroupID: req.GroupID, @@ -892,7 +893,7 @@ func (s *groupServer) JoinGroup(ctx context.Context, req *pbgroup.JoinGroupReq) HandledTime: time.Unix(0, 0), Ex: req.Ex, } - if err = s.db.CreateGroupRequest(ctx, []*relationtb.GroupRequestModel{&groupRequest}); err != nil { + if err = s.db.CreateGroupRequest(ctx, []*model.GroupRequest{&groupRequest}); err != nil { return nil, err } s.notification.JoinGroupApplicationNotification(ctx, req) @@ -940,7 +941,7 @@ func (s *groupServer) deleteMemberAndSetConversationSeq(ctx context.Context, gro } func (s *groupServer) SetGroupInfo(ctx context.Context, req *pbgroup.SetGroupInfoReq) (*pbgroup.SetGroupInfoResp, error) { - var opMember *relationtb.GroupMemberModel + var opMember *model.GroupMember if !authverify.IsAppManagerUid(ctx, s.config.Share.IMAdminUserID) { var err error opMember, err = s.db.TakeGroupMember(ctx, req.GroupInfoForSet.GroupID, mcontext.GetOpUserID(ctx)) @@ -1049,7 +1050,7 @@ func (s *groupServer) TransferGroupOwner(ctx context.Context, req *pbgroup.Trans if err := s.PopulateGroupMember(ctx, members...); err != nil { return nil, err } - memberMap := datautil.SliceToMap(members, func(e *relationtb.GroupMemberModel) string { return e.UserID }) + memberMap := datautil.SliceToMap(members, func(e *model.GroupMember) string { return e.UserID }) if ids := datautil.Single([]string{req.OldOwnerUserID, req.NewOwnerUserID}, datautil.Keys(memberMap)); len(ids) > 0 { return nil, errs.ErrArgs.WrapMsg("user not in group " + strings.Join(ids, ",")) } @@ -1078,7 +1079,7 @@ func (s *groupServer) TransferGroupOwner(ctx context.Context, req *pbgroup.Trans func (s *groupServer) GetGroups(ctx context.Context, req *pbgroup.GetGroupsReq) (*pbgroup.GetGroupsResp, error) { var ( - group []*relationtb.GroupModel + group []*model.Group err error ) var resp pbgroup.GetGroupsResp @@ -1095,7 +1096,7 @@ func (s *groupServer) GetGroups(ctx context.Context, req *pbgroup.GetGroupsReq) return nil, err } - groupIDs := datautil.Slice(group, func(e *relationtb.GroupModel) string { + groupIDs := datautil.Slice(group, func(e *model.Group) string { return e.GroupID }) @@ -1104,14 +1105,14 @@ func (s *groupServer) GetGroups(ctx context.Context, req *pbgroup.GetGroupsReq) return nil, err } - ownerMemberMap := datautil.SliceToMap(ownerMembers, func(e *relationtb.GroupMemberModel) string { + ownerMemberMap := datautil.SliceToMap(ownerMembers, func(e *model.GroupMember) string { return e.GroupID }) groupMemberNumMap, err := s.db.MapGroupMemberNum(ctx, groupIDs) if err != nil { return nil, err } - resp.Groups = datautil.Slice(group, func(group *relationtb.GroupModel) *pbgroup.CMSGroup { + resp.Groups = datautil.Slice(group, func(group *model.Group) *pbgroup.CMSGroup { var ( userID string username string @@ -1135,7 +1136,7 @@ func (s *groupServer) GetGroupMembersCMS(ctx context.Context, req *pbgroup.GetGr if err := s.PopulateGroupMember(ctx, members...); err != nil { return nil, err } - resp.Members = datautil.Slice(members, func(e *relationtb.GroupMemberModel) *sdkws.GroupMemberFullInfo { + resp.Members = datautil.Slice(members, func(e *model.GroupMember) *sdkws.GroupMemberFullInfo { return convert.Db2PbGroupMember(e) }) return &resp, nil @@ -1153,14 +1154,14 @@ func (s *groupServer) GetUserReqApplicationList(ctx context.Context, req *pbgrou if len(requests) == 0 { return &pbgroup.GetUserReqApplicationListResp{Total: uint32(total)}, nil } - groupIDs := datautil.Distinct(datautil.Slice(requests, func(e *relationtb.GroupRequestModel) string { + groupIDs := datautil.Distinct(datautil.Slice(requests, func(e *model.GroupRequest) string { return e.GroupID })) groups, err := s.db.FindGroup(ctx, groupIDs) if err != nil { return nil, err } - groupMap := datautil.SliceToMap(groups, func(e *relationtb.GroupModel) string { + groupMap := datautil.SliceToMap(groups, func(e *model.Group) string { return e.GroupID }) owners, err := s.db.FindGroupsOwner(ctx, groupIDs) @@ -1170,7 +1171,7 @@ func (s *groupServer) GetUserReqApplicationList(ctx context.Context, req *pbgrou if err := s.PopulateGroupMember(ctx, owners...); err != nil { return nil, err } - ownerMap := datautil.SliceToMap(owners, func(e *relationtb.GroupMemberModel) string { + ownerMap := datautil.SliceToMap(owners, func(e *model.GroupMember) string { return e.GroupID }) groupMemberNum, err := s.db.MapGroupMemberNum(ctx, groupIDs) @@ -1179,7 +1180,7 @@ func (s *groupServer) GetUserReqApplicationList(ctx context.Context, req *pbgrou } return &pbgroup.GetUserReqApplicationListResp{ Total: uint32(total), - GroupRequests: datautil.Slice(requests, func(e *relationtb.GroupRequestModel) *sdkws.GroupRequest { + GroupRequests: datautil.Slice(requests, func(e *model.GroupRequest) *sdkws.GroupRequest { var ownerUserID string if owner, ok := ownerMap[e.GroupID]; ok { ownerUserID = owner.UserID @@ -1430,8 +1431,8 @@ func (s *groupServer) SetGroupMemberInfo(ctx context.Context, req *pbgroup.SetGr } } - if err := s.db.UpdateGroupMembers(ctx, datautil.Slice(req.Members, func(e *pbgroup.SetGroupMemberInfo) *relationtb.BatchUpdateGroupMember { - return &relationtb.BatchUpdateGroupMember{ + if err := s.db.UpdateGroupMembers(ctx, datautil.Slice(req.Members, func(e *pbgroup.SetGroupMemberInfo) *common.BatchUpdateGroupMember { + return &common.BatchUpdateGroupMember{ GroupID: e.GroupID, UserID: e.UserID, Map: UpdateGroupMemberMap(e), @@ -1470,7 +1471,7 @@ func (s *groupServer) GetGroupAbstractInfo(ctx context.Context, req *pbgroup.Get if err != nil { return nil, err } - if ids := datautil.Single(req.GroupIDs, datautil.Slice(groups, func(group *relationtb.GroupModel) string { + if ids := datautil.Single(req.GroupIDs, datautil.Slice(groups, func(group *model.Group) string { return group.GroupID })); len(ids) > 0 { return nil, servererrs.ErrGroupIDNotFound.WrapMsg("not found group " + strings.Join(ids, ",")) @@ -1483,7 +1484,7 @@ func (s *groupServer) GetGroupAbstractInfo(ctx context.Context, req *pbgroup.Get return nil, servererrs.ErrGroupIDNotFound.WrapMsg(fmt.Sprintf("group %s not found member", strings.Join(ids, ","))) } return &pbgroup.GetGroupAbstractInfoResp{ - GroupAbstractInfos: datautil.Slice(groups, func(group *relationtb.GroupModel) *pbgroup.GroupAbstractInfo { + GroupAbstractInfos: datautil.Slice(groups, func(group *model.Group) *pbgroup.GroupAbstractInfo { users := groupUserMap[group.GroupID] return convert.Db2PbGroupAbstractInfo(group.GroupID, users.MemberNum, users.Hash) }), @@ -1502,7 +1503,7 @@ func (s *groupServer) GetUserInGroupMembers(ctx context.Context, req *pbgroup.Ge return nil, err } return &pbgroup.GetUserInGroupMembersResp{ - Members: datautil.Slice(members, func(e *relationtb.GroupMemberModel) *sdkws.GroupMemberFullInfo { + Members: datautil.Slice(members, func(e *model.GroupMember) *sdkws.GroupMemberFullInfo { return convert.Db2PbGroupMember(e) }), }, nil @@ -1530,7 +1531,7 @@ func (s *groupServer) GetGroupMemberRoleLevel(ctx context.Context, req *pbgroup. return nil, err } return &pbgroup.GetGroupMemberRoleLevelResp{ - Members: datautil.Slice(members, func(e *relationtb.GroupMemberModel) *sdkws.GroupMemberFullInfo { + Members: datautil.Slice(members, func(e *model.GroupMember) *sdkws.GroupMemberFullInfo { return convert.Db2PbGroupMember(e) }), }, nil @@ -1544,14 +1545,14 @@ func (s *groupServer) GetGroupUsersReqApplicationList(ctx context.Context, req * if len(requests) == 0 { return &pbgroup.GetGroupUsersReqApplicationListResp{}, nil } - groupIDs := datautil.Distinct(datautil.Slice(requests, func(e *relationtb.GroupRequestModel) string { + groupIDs := datautil.Distinct(datautil.Slice(requests, func(e *model.GroupRequest) string { return e.GroupID })) groups, err := s.db.FindGroup(ctx, groupIDs) if err != nil { return nil, err } - groupMap := datautil.SliceToMap(groups, func(e *relationtb.GroupModel) string { + groupMap := datautil.SliceToMap(groups, func(e *model.Group) string { return e.GroupID }) if ids := datautil.Single(groupIDs, datautil.Keys(groupMap)); len(ids) > 0 { @@ -1564,7 +1565,7 @@ func (s *groupServer) GetGroupUsersReqApplicationList(ctx context.Context, req * if err := s.PopulateGroupMember(ctx, owners...); err != nil { return nil, err } - ownerMap := datautil.SliceToMap(owners, func(e *relationtb.GroupMemberModel) string { + ownerMap := datautil.SliceToMap(owners, func(e *model.GroupMember) string { return e.GroupID }) groupMemberNum, err := s.db.MapGroupMemberNum(ctx, groupIDs) @@ -1573,7 +1574,7 @@ func (s *groupServer) GetGroupUsersReqApplicationList(ctx context.Context, req * } return &pbgroup.GetGroupUsersReqApplicationListResp{ Total: int64(len(requests)), - GroupRequests: datautil.Slice(requests, func(e *relationtb.GroupRequestModel) *sdkws.GroupRequest { + GroupRequests: datautil.Slice(requests, func(e *model.GroupRequest) *sdkws.GroupRequest { var ownerUserID string if owner, ok := ownerMap[e.GroupID]; ok { ownerUserID = owner.UserID diff --git a/internal/rpc/group/notification.go b/internal/rpc/group/notification.go index 6d7cebcbc6..f0f054d0ab 100644 --- a/internal/rpc/group/notification.go +++ b/internal/rpc/group/notification.go @@ -17,12 +17,12 @@ package group import ( "context" "fmt" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient/notification" "github.com/openimsdk/open-im-server/v3/pkg/authverify" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" "github.com/openimsdk/open-im-server/v3/pkg/common/servererrs" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/controller" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" "github.com/openimsdk/protocol/constant" pbgroup "github.com/openimsdk/protocol/group" @@ -50,7 +50,7 @@ type GroupNotificationSender struct { config *Config } -func (g *GroupNotificationSender) PopulateGroupMember(ctx context.Context, members ...*relation.GroupMemberModel) error { +func (g *GroupNotificationSender) PopulateGroupMember(ctx context.Context, members ...*model.GroupMember) error { if len(members) == 0 { return nil } @@ -186,12 +186,12 @@ func (g *GroupNotificationSender) getGroupOwnerAndAdminUserID(ctx context.Contex if err := g.PopulateGroupMember(ctx, members...); err != nil { return nil, err } - fn := func(e *relation.GroupMemberModel) string { return e.UserID } + fn := func(e *model.GroupMember) string { return e.UserID } return datautil.Slice(members, fn), nil } //nolint:unused -func (g *GroupNotificationSender) groupDB2PB(group *relation.GroupModel, ownerUserID string, memberCount uint32) *sdkws.GroupInfo { +func (g *GroupNotificationSender) groupDB2PB(group *model.Group, ownerUserID string, memberCount uint32) *sdkws.GroupInfo { return &sdkws.GroupInfo{ GroupID: group.GroupID, GroupName: group.GroupName, @@ -213,7 +213,7 @@ func (g *GroupNotificationSender) groupDB2PB(group *relation.GroupModel, ownerUs } } -func (g *GroupNotificationSender) groupMemberDB2PB(member *relation.GroupMemberModel, appMangerLevel int32) *sdkws.GroupMemberFullInfo { +func (g *GroupNotificationSender) groupMemberDB2PB(member *model.GroupMember, appMangerLevel int32) *sdkws.GroupMemberFullInfo { return &sdkws.GroupMemberFullInfo{ GroupID: member.GroupID, UserID: member.UserID, diff --git a/internal/rpc/msg/revoke.go b/internal/rpc/msg/revoke.go index 7dbc307a19..b7cc7df62e 100644 --- a/internal/rpc/msg/revoke.go +++ b/internal/rpc/msg/revoke.go @@ -17,10 +17,10 @@ package msg import ( "context" "encoding/json" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model" "time" "github.com/openimsdk/open-im-server/v3/pkg/authverify" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" "github.com/openimsdk/open-im-server/v3/pkg/common/servererrs" "github.com/openimsdk/protocol/constant" "github.com/openimsdk/protocol/msg" @@ -93,7 +93,7 @@ func (m *msgServer) RevokeMsg(ctx context.Context, req *msg.RevokeMsgReq) (*msg. } } now := time.Now().UnixMilli() - err = m.MsgDatabase.RevokeMsg(ctx, req.ConversationID, req.Seq, &relation.RevokeModel{ + err = m.MsgDatabase.RevokeMsg(ctx, req.ConversationID, req.Seq, &model.RevokeModel{ Role: role, UserID: req.UserID, Nickname: user.Nickname, diff --git a/internal/rpc/msg/server.go b/internal/rpc/msg/server.go index 5d7c0b297b..6ff45605e4 100644 --- a/internal/rpc/msg/server.go +++ b/internal/rpc/msg/server.go @@ -17,14 +17,14 @@ package msg import ( "context" "github.com/openimsdk/open-im-server/v3/pkg/common/config" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/cache/redis" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/database/mgo" "github.com/openimsdk/open-im-server/v3/pkg/common/webhook" "github.com/openimsdk/protocol/sdkws" "github.com/openimsdk/tools/db/mongoutil" "github.com/openimsdk/tools/db/redisutil" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/mgo" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/controller" "github.com/openimsdk/open-im-server/v3/pkg/rpccache" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" "github.com/openimsdk/protocol/constant" @@ -86,8 +86,8 @@ func Start(ctx context.Context, config *Config, client discovery.SvcDiscoveryReg return err } //todo MsgCacheTimeout - msgModel := cache.NewMsgCache(rdb, config.RedisConfig.EnablePipeline) - seqModel := cache.NewSeqCache(rdb) + msgModel := redis.NewMsgCache(rdb, config.RedisConfig.EnablePipeline) + seqModel := redis.NewSeqCache(rdb) conversationClient := rpcclient.NewConversationRpcClient(client, config.Share.RpcRegisterName.Conversation) userRpcClient := rpcclient.NewUserRpcClient(client, config.Share.RpcRegisterName.User, config.Share.IMAdminUserID) groupRpcClient := rpcclient.NewGroupRpcClient(client, config.Share.RpcRegisterName.Group) diff --git a/internal/rpc/msg/statistics.go b/internal/rpc/msg/statistics.go index 15a0aaa577..01c0f1c46c 100644 --- a/internal/rpc/msg/statistics.go +++ b/internal/rpc/msg/statistics.go @@ -16,9 +16,9 @@ package msg import ( "context" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model" "time" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" "github.com/openimsdk/protocol/msg" "github.com/openimsdk/protocol/sdkws" "github.com/openimsdk/tools/utils/datautil" @@ -31,7 +31,7 @@ func (m *msgServer) GetActiveUser(ctx context.Context, req *msg.GetActiveUserReq } var pbUsers []*msg.ActiveUser if len(users) > 0 { - userIDs := datautil.Slice(users, func(e *relation.UserCount) string { return e.UserID }) + userIDs := datautil.Slice(users, func(e *model.UserCount) string { return e.UserID }) userMap, err := m.UserLocalCache.GetUsersInfoMap(ctx, userIDs) if err != nil { return nil, err @@ -66,7 +66,7 @@ func (m *msgServer) GetActiveGroup(ctx context.Context, req *msg.GetActiveGroupR } var pbgroups []*msg.ActiveGroup if len(groups) > 0 { - groupIDs := datautil.Slice(groups, func(e *relation.GroupCount) string { return e.GroupID }) + groupIDs := datautil.Slice(groups, func(e *model.GroupCount) string { return e.GroupID }) resp, err := m.GroupLocalCache.GetGroupInfos(ctx, groupIDs) if err != nil { return nil, err diff --git a/internal/rpc/third/log.go b/internal/rpc/third/log.go index 7712851ed9..5c0b1f2e6b 100644 --- a/internal/rpc/third/log.go +++ b/internal/rpc/third/log.go @@ -17,10 +17,10 @@ package third import ( "context" "crypto/rand" + relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model" "time" "github.com/openimsdk/open-im-server/v3/pkg/authverify" - relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" "github.com/openimsdk/open-im-server/v3/pkg/common/servererrs" "github.com/openimsdk/protocol/constant" "github.com/openimsdk/protocol/third" @@ -45,11 +45,11 @@ func genLogID() string { } func (t *thirdServer) UploadLogs(ctx context.Context, req *third.UploadLogsReq) (*third.UploadLogsResp, error) { - var dbLogs []*relationtb.LogModel + var dbLogs []*relationtb.Log userID := ctx.Value(constant.OpUserID).(string) platform := constant.PlatformID2Name[int(req.Platform)] for _, fileURL := range req.FileURLs { - log := relationtb.LogModel{ + log := relationtb.Log{ Version: req.Version, SystemType: req.SystemType, Platform: platform, @@ -70,7 +70,7 @@ func (t *thirdServer) UploadLogs(ctx context.Context, req *third.UploadLogsReq) } } if log.LogID == "" { - return nil, servererrs.ErrData.WrapMsg("LogModel id gen error") + return nil, servererrs.ErrData.WrapMsg("Log id gen error") } dbLogs = append(dbLogs, &log) } @@ -105,8 +105,8 @@ func (t *thirdServer) DeleteLogs(ctx context.Context, req *third.DeleteLogsReq) return &third.DeleteLogsResp{}, nil } -func dbToPbLogInfos(logs []*relationtb.LogModel) []*third.LogInfo { - db2pbForLogInfo := func(log *relationtb.LogModel) *third.LogInfo { +func dbToPbLogInfos(logs []*relationtb.Log) []*third.LogInfo { + db2pbForLogInfo := func(log *relationtb.Log) *third.LogInfo { return &third.LogInfo{ Filename: log.FileName, UserID: log.UserID, diff --git a/internal/rpc/third/s3.go b/internal/rpc/third/s3.go index 21d982268e..4cb1b81d06 100644 --- a/internal/rpc/third/s3.go +++ b/internal/rpc/third/s3.go @@ -19,12 +19,12 @@ import ( "encoding/base64" "encoding/hex" "encoding/json" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model" "path" "strconv" "time" "github.com/google/uuid" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" "github.com/openimsdk/open-im-server/v3/pkg/common/servererrs" "github.com/openimsdk/protocol/third" "github.com/openimsdk/tools/errs" @@ -60,7 +60,7 @@ func (t *thirdServer) InitiateMultipartUpload(ctx context.Context, req *third.In result, err := t.s3dataBase.InitiateMultipartUpload(ctx, req.Hash, req.Size, t.defaultExpire, int(req.MaxParts)) if err != nil { if haErr, ok := errs.Unwrap(err).(*cont.HashAlreadyExistsError); ok { - obj := &relation.ObjectModel{ + obj := &model.Object{ Name: req.Name, UserID: mcontext.GetOpUserID(ctx), Hash: req.Hash, @@ -137,7 +137,7 @@ func (t *thirdServer) CompleteMultipartUpload(ctx context.Context, req *third.Co if err != nil { return nil, err } - obj := &relation.ObjectModel{ + obj := &model.Object{ Name: req.Name, UserID: mcontext.GetOpUserID(ctx), Hash: result.Hash, @@ -263,7 +263,7 @@ func (t *thirdServer) CompleteFormData(ctx context.Context, req *third.CompleteF if info.Size > 0 && info.Size != mate.Size { return nil, servererrs.ErrData.WrapMsg("file size mismatch") } - obj := &relation.ObjectModel{ + obj := &model.Object{ Name: mate.Name, UserID: mcontext.GetOpUserID(ctx), Hash: "etag_" + info.ETag, diff --git a/internal/rpc/third/third.go b/internal/rpc/third/third.go index a3d9085d31..7560486a00 100644 --- a/internal/rpc/third/third.go +++ b/internal/rpc/third/third.go @@ -18,11 +18,12 @@ import ( "context" "fmt" "github.com/openimsdk/open-im-server/v3/pkg/common/config" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/cache/redis" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/database/mgo" + "github.com/openimsdk/open-im-server/v3/pkg/localcache" "time" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/mgo" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/controller" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" "github.com/openimsdk/protocol/third" "github.com/openimsdk/tools/db/mongoutil" @@ -75,7 +76,7 @@ func Start(ctx context.Context, config *Config, client discovery.SvcDiscoveryReg var o s3.Interface switch enable { case "minio": - o, err = minio.NewMinio(ctx, cache.NewMinioCache(rdb), *config.MinioConfig.Build()) + o, err = minio.NewMinio(ctx, redis.NewMinioCache(rdb), *config.MinioConfig.Build()) case "cos": o, err = cos.NewCos(*config.RpcConfig.Object.Cos.Build()) case "oss": @@ -86,9 +87,9 @@ func Start(ctx context.Context, config *Config, client discovery.SvcDiscoveryReg if err != nil { return err } - cache.InitLocalCache(&config.LocalCacheConfig) + localcache.InitLocalCache(&config.LocalCacheConfig) third.RegisterThirdServer(server, &thirdServer{ - thirdDatabase: controller.NewThirdDatabase(cache.NewThirdCache(rdb), logdb), + thirdDatabase: controller.NewThirdDatabase(redis.NewThirdCache(rdb), logdb), userRpcClient: rpcclient.NewUserRpcClient(client, config.Share.RpcRegisterName.User, config.Share.IMAdminUserID), s3dataBase: controller.NewS3Database(rdb, o, s3db), defaultExpire: time.Hour * 24 * 7, diff --git a/internal/rpc/user/notification.go b/internal/rpc/user/notification.go index 348cd56281..b992c9d123 100644 --- a/internal/rpc/user/notification.go +++ b/internal/rpc/user/notification.go @@ -16,10 +16,10 @@ package user import ( "context" + relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient/notification" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" - relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/controller" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" "github.com/openimsdk/protocol/constant" "github.com/openimsdk/protocol/sdkws" @@ -41,7 +41,7 @@ func WithUserDB(db controller.UserDatabase) userNotificationSenderOptions { } func WithUserFunc( - fn func(ctx context.Context, userIDs []string) (users []*relationtb.UserModel, err error), + fn func(ctx context.Context, userIDs []string) (users []*relationtb.User, err error), ) userNotificationSenderOptions { return func(u *UserNotificationSender) { f := func(ctx context.Context, userIDs []string) (result []notification.CommonUser, err error) { diff --git a/internal/rpc/user/user.go b/internal/rpc/user/user.go index a28fa24e28..d0d3dbf603 100644 --- a/internal/rpc/user/user.go +++ b/internal/rpc/user/user.go @@ -18,7 +18,11 @@ import ( "context" "github.com/openimsdk/open-im-server/v3/internal/rpc/friend" "github.com/openimsdk/open-im-server/v3/pkg/common/config" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/cache/redis" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/database/mgo" + tablerelation "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model" "github.com/openimsdk/open-im-server/v3/pkg/common/webhook" + "github.com/openimsdk/open-im-server/v3/pkg/localcache" "github.com/openimsdk/tools/db/redisutil" "math/rand" "strings" @@ -26,12 +30,8 @@ import ( "github.com/openimsdk/open-im-server/v3/pkg/authverify" "github.com/openimsdk/open-im-server/v3/pkg/common/convert" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/mgo" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" - tablerelation "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" "github.com/openimsdk/open-im-server/v3/pkg/common/servererrs" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/controller" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" "github.com/openimsdk/protocol/constant" "github.com/openimsdk/protocol/sdkws" @@ -77,22 +77,22 @@ func Start(ctx context.Context, config *Config, client registry.SvcDiscoveryRegi if err != nil { return err } - users := make([]*tablerelation.UserModel, 0) + users := make([]*tablerelation.User, 0) for _, v := range config.Share.IMAdminUserID { - users = append(users, &tablerelation.UserModel{UserID: v, Nickname: v, AppMangerLevel: constant.AppNotificationAdmin}) + users = append(users, &tablerelation.User{UserID: v, Nickname: v, AppMangerLevel: constant.AppNotificationAdmin}) } userDB, err := mgo.NewUserMongo(mgocli.GetDB()) if err != nil { return err } - userCache := cache.NewUserCacheRedis(rdb, &config.LocalCacheConfig, userDB, cache.GetDefaultOpt()) + userCache := redis.NewUserCacheRedis(rdb, &config.LocalCacheConfig, userDB, redis.GetRocksCacheOptions()) userMongoDB := mgo.NewUserMongoDriver(mgocli.GetDB()) database := controller.NewUserDatabase(userDB, userCache, mgocli.GetTx(), userMongoDB) friendRpcClient := rpcclient.NewFriendRpcClient(client, config.Share.RpcRegisterName.Friend) groupRpcClient := rpcclient.NewGroupRpcClient(client, config.Share.RpcRegisterName.Group) msgRpcClient := rpcclient.NewMessageRpcClient(client, config.Share.RpcRegisterName.Msg) - cache.InitLocalCache(&config.LocalCacheConfig) + localcache.InitLocalCache(&config.LocalCacheConfig) u := &userServer{ db: database, RegisterCenter: client, @@ -281,9 +281,9 @@ func (s *userServer) UserRegister(ctx context.Context, req *pbuser.UserRegisterR return nil, err } now := time.Now() - users := make([]*tablerelation.UserModel, 0, len(req.Users)) + users := make([]*tablerelation.User, 0, len(req.Users)) for _, user := range req.Users { - users = append(users, &tablerelation.UserModel{ + users = append(users, &tablerelation.User{ UserID: user.UserID, Nickname: user.Nickname, FaceURL: user.FaceURL, @@ -403,7 +403,7 @@ func (s *userServer) ProcessUserCommandAdd(ctx context.Context, req *pbuser.Proc if req.Ex != nil { value = req.Ex.Value } - // Assuming you have a method in s.db to add a user command + // Assuming you have a method in s.storage to add a user command err = s.db.AddUserCommand(ctx, req.UserID, req.Type, req.Uuid, value, ex) if err != nil { return nil, err @@ -451,7 +451,7 @@ func (s *userServer) ProcessUserCommandUpdate(ctx context.Context, req *pbuser.P val["ex"] = req.Ex.Value } - // Assuming you have a method in s.db to update a user command + // Assuming you have a method in s.storage to update a user command err = s.db.UpdateUserCommand(ctx, req.UserID, req.Type, req.Uuid, val) if err != nil { return nil, err @@ -548,14 +548,14 @@ func (s *userServer) AddNotificationAccount(ctx context.Context, req *pbuser.Add } } - user := &tablerelation.UserModel{ + user := &tablerelation.User{ UserID: req.UserID, Nickname: req.NickName, FaceURL: req.FaceURL, CreateTime: time.Now(), AppMangerLevel: constant.AppNotificationAdmin, } - if err := s.db.Create(ctx, []*tablerelation.UserModel{user}); err != nil { + if err := s.db.Create(ctx, []*tablerelation.User{user}); err != nil { return nil, err } @@ -598,7 +598,7 @@ func (s *userServer) SearchNotificationAccount(ctx context.Context, req *pbuser. return nil, err } - var users []*relation.UserModel + var users []*tablerelation.User var err error // If a keyword is provided in the request @@ -664,7 +664,7 @@ func (s *userServer) genUserID() string { return string(data) } -func (s *userServer) userModelToResp(users []*relation.UserModel, pagination pagination.Pagination) *pbuser.SearchNotificationAccountResp { +func (s *userServer) userModelToResp(users []*tablerelation.User, pagination pagination.Pagination) *pbuser.SearchNotificationAccountResp { accounts := make([]*pbuser.NotificationAccountInfo, 0) var total int64 for _, v := range users { diff --git a/pkg/common/config/config.go b/pkg/common/config/config.go index 12c4f7f789..a75d45ebbd 100644 --- a/pkg/common/config/config.go +++ b/pkg/common/config/config.go @@ -328,7 +328,7 @@ type Redis struct { Password string `mapstructure:"password"` EnablePipeline bool `mapstructure:"enablePipeline"` ClusterMode bool `mapstructure:"clusterMode"` - DB int `mapstructure:"db"` + DB int `mapstructure:"storage"` MaxRetry int `mapstructure:"MaxRetry"` } diff --git a/pkg/common/convert/black.go b/pkg/common/convert/black.go index 635b1a5862..6c24051fdb 100644 --- a/pkg/common/convert/black.go +++ b/pkg/common/convert/black.go @@ -16,13 +16,13 @@ package convert import ( "context" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" "github.com/openimsdk/protocol/sdkws" sdk "github.com/openimsdk/protocol/sdkws" ) -func BlackDB2Pb(ctx context.Context, blackDBs []*relation.BlackModel, f func(ctx context.Context, userIDs []string) (map[string]*sdkws.UserInfo, error)) (blackPbs []*sdk.BlackInfo, err error) { +func BlackDB2Pb(ctx context.Context, blackDBs []*model.Black, f func(ctx context.Context, userIDs []string) (map[string]*sdkws.UserInfo, error)) (blackPbs []*sdk.BlackInfo, err error) { if len(blackDBs) == 0 { return nil, nil } diff --git a/pkg/common/convert/conversation.go b/pkg/common/convert/conversation.go index 510f40d700..a76d7d9f6d 100644 --- a/pkg/common/convert/conversation.go +++ b/pkg/common/convert/conversation.go @@ -15,12 +15,12 @@ package convert import ( - "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model" "github.com/openimsdk/protocol/conversation" "github.com/openimsdk/tools/utils/datautil" ) -func ConversationDB2Pb(conversationDB *relation.ConversationModel) *conversation.Conversation { +func ConversationDB2Pb(conversationDB *model.Conversation) *conversation.Conversation { conversationPB := &conversation.Conversation{} conversationPB.LatestMsgDestructTime = conversationDB.LatestMsgDestructTime.Unix() if err := datautil.CopyStructFields(conversationPB, conversationDB); err != nil { @@ -29,7 +29,7 @@ func ConversationDB2Pb(conversationDB *relation.ConversationModel) *conversation return conversationPB } -func ConversationsDB2Pb(conversationsDB []*relation.ConversationModel) (conversationsPB []*conversation.Conversation) { +func ConversationsDB2Pb(conversationsDB []*model.Conversation) (conversationsPB []*conversation.Conversation) { for _, conversationDB := range conversationsDB { conversationPB := &conversation.Conversation{} if err := datautil.CopyStructFields(conversationPB, conversationDB); err != nil { @@ -41,17 +41,17 @@ func ConversationsDB2Pb(conversationsDB []*relation.ConversationModel) (conversa return conversationsPB } -func ConversationPb2DB(conversationPB *conversation.Conversation) *relation.ConversationModel { - conversationDB := &relation.ConversationModel{} +func ConversationPb2DB(conversationPB *conversation.Conversation) *model.Conversation { + conversationDB := &model.Conversation{} if err := datautil.CopyStructFields(conversationDB, conversationPB); err != nil { return nil } return conversationDB } -func ConversationsPb2DB(conversationsPB []*conversation.Conversation) (conversationsDB []*relation.ConversationModel) { +func ConversationsPb2DB(conversationsPB []*conversation.Conversation) (conversationsDB []*model.Conversation) { for _, conversationPB := range conversationsPB { - conversationDB := &relation.ConversationModel{} + conversationDB := &model.Conversation{} if err := datautil.CopyStructFields(conversationDB, conversationPB); err != nil { continue } diff --git a/pkg/common/convert/friend.go b/pkg/common/convert/friend.go index ad8f9071e1..8d6cfad183 100644 --- a/pkg/common/convert/friend.go +++ b/pkg/common/convert/friend.go @@ -17,15 +17,15 @@ package convert import ( "context" "fmt" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" "github.com/openimsdk/protocol/sdkws" "github.com/openimsdk/tools/utils/datautil" "github.com/openimsdk/tools/utils/timeutil" ) -func FriendPb2DB(friend *sdkws.FriendInfo) *relation.FriendModel { - dbFriend := &relation.FriendModel{} +func FriendPb2DB(friend *sdkws.FriendInfo) *model.Friend { + dbFriend := &model.Friend{} err := datautil.CopyStructFields(dbFriend, friend) if err != nil { return nil @@ -35,7 +35,7 @@ func FriendPb2DB(friend *sdkws.FriendInfo) *relation.FriendModel { return dbFriend } -func FriendDB2Pb(ctx context.Context, friendDB *relation.FriendModel, +func FriendDB2Pb(ctx context.Context, friendDB *model.Friend, getUsers func(ctx context.Context, userIDs []string) (map[string]*sdkws.UserInfo, error), ) (*sdkws.FriendInfo, error) { users, err := getUsers(ctx, []string{friendDB.FriendUserID}) @@ -55,7 +55,7 @@ func FriendDB2Pb(ctx context.Context, friendDB *relation.FriendModel, func FriendsDB2Pb( ctx context.Context, - friendsDB []*relation.FriendModel, + friendsDB []*model.Friend, getUsers func(ctx context.Context, userIDs []string) (map[string]*sdkws.UserInfo, error), ) (friendsPb []*sdkws.FriendInfo, err error) { if len(friendsDB) == 0 { @@ -89,7 +89,7 @@ func FriendsDB2Pb( } -func FriendRequestDB2Pb(ctx context.Context, friendRequests []*relation.FriendRequestModel, getUsers func(ctx context.Context, userIDs []string) (map[string]*sdkws.UserInfo, error)) ([]*sdkws.FriendRequest, error) { +func FriendRequestDB2Pb(ctx context.Context, friendRequests []*model.FriendRequest, getUsers func(ctx context.Context, userIDs []string) (map[string]*sdkws.UserInfo, error)) ([]*sdkws.FriendRequest, error) { if len(friendRequests) == 0 { return nil, nil } @@ -134,8 +134,8 @@ func FriendPb2DBMap(friend *sdkws.FriendInfo) map[string]any { val := make(map[string]any) - // Assuming FriendInfo has similar fields to those in FriendModel. - // Add or remove fields based on your actual FriendInfo and FriendModel structures. + // Assuming FriendInfo has similar fields to those in Friend. + // Add or remove fields based on your actual FriendInfo and Friend structures. if friend.FriendUser != nil { if friend.FriendUser.UserID != "" { val["friend_user_id"] = friend.FriendUser.UserID diff --git a/pkg/common/convert/group.go b/pkg/common/convert/group.go index 9b7353cfdc..bc2b2f9985 100644 --- a/pkg/common/convert/group.go +++ b/pkg/common/convert/group.go @@ -15,14 +15,14 @@ package convert import ( + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model" "time" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" pbgroup "github.com/openimsdk/protocol/group" sdkws "github.com/openimsdk/protocol/sdkws" ) -func Db2PbGroupInfo(m *relation.GroupModel, ownerUserID string, memberCount uint32) *sdkws.GroupInfo { +func Db2PbGroupInfo(m *model.Group, ownerUserID string, memberCount uint32) *sdkws.GroupInfo { return &sdkws.GroupInfo{ GroupID: m.GroupID, GroupName: m.GroupName, @@ -44,8 +44,8 @@ func Db2PbGroupInfo(m *relation.GroupModel, ownerUserID string, memberCount uint } } -func Pb2DbGroupRequest(req *pbgroup.GroupApplicationResponseReq, handleUserID string) *relation.GroupRequestModel { - return &relation.GroupRequestModel{ +func Pb2DbGroupRequest(req *pbgroup.GroupApplicationResponseReq, handleUserID string) *model.GroupRequest { + return &model.GroupRequest{ UserID: req.FromUserID, GroupID: req.GroupID, HandleResult: req.HandleResult, @@ -55,7 +55,7 @@ func Pb2DbGroupRequest(req *pbgroup.GroupApplicationResponseReq, handleUserID st } } -func Db2PbCMSGroup(m *relation.GroupModel, ownerUserID string, ownerUserName string, memberCount uint32) *pbgroup.CMSGroup { +func Db2PbCMSGroup(m *model.Group, ownerUserID string, ownerUserName string, memberCount uint32) *pbgroup.CMSGroup { return &pbgroup.CMSGroup{ GroupInfo: Db2PbGroupInfo(m, ownerUserID, memberCount), GroupOwnerUserID: ownerUserID, @@ -63,7 +63,7 @@ func Db2PbCMSGroup(m *relation.GroupModel, ownerUserID string, ownerUserName str } } -func Db2PbGroupMember(m *relation.GroupMemberModel) *sdkws.GroupMemberFullInfo { +func Db2PbGroupMember(m *model.GroupMember) *sdkws.GroupMemberFullInfo { return &sdkws.GroupMemberFullInfo{ GroupID: m.GroupID, UserID: m.UserID, @@ -80,7 +80,7 @@ func Db2PbGroupMember(m *relation.GroupMemberModel) *sdkws.GroupMemberFullInfo { } } -func Db2PbGroupRequest(m *relation.GroupRequestModel, user *sdkws.PublicUserInfo, group *sdkws.GroupInfo) *sdkws.GroupRequest { +func Db2PbGroupRequest(m *model.GroupRequest, user *sdkws.PublicUserInfo, group *sdkws.GroupInfo) *sdkws.GroupRequest { return &sdkws.GroupRequest{ UserInfo: user, GroupInfo: group, @@ -108,8 +108,8 @@ func Db2PbGroupAbstractInfo( } } -func Pb2DBGroupInfo(m *sdkws.GroupInfo) *relation.GroupModel { - return &relation.GroupModel{ +func Pb2DBGroupInfo(m *sdkws.GroupInfo) *model.Group { + return &model.Group{ GroupID: m.GroupID, GroupName: m.GroupName, Notification: m.Notification, @@ -128,8 +128,8 @@ func Pb2DBGroupInfo(m *sdkws.GroupInfo) *relation.GroupModel { } } -// func Pb2DbGroupMember(m *sdkws.UserInfo) *relation.GroupMemberModel { -// return &relation.GroupMemberModel{ +// func Pb2DbGroupMember(m *sdkws.UserInfo) *relation.GroupMember { +// return &relation.GroupMember{ // UserID: m.UserID, // Nickname: m.Nickname, // FaceURL: m.FaceURL, diff --git a/pkg/common/convert/msg.go b/pkg/common/convert/msg.go index 594a0ffc2c..41f6b41f6b 100644 --- a/pkg/common/convert/msg.go +++ b/pkg/common/convert/msg.go @@ -15,16 +15,16 @@ package convert import ( - "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model" "github.com/openimsdk/protocol/constant" "github.com/openimsdk/protocol/sdkws" ) -func MsgPb2DB(msg *sdkws.MsgData) *relation.MsgDataModel { +func MsgPb2DB(msg *sdkws.MsgData) *model.MsgDataModel { if msg == nil { return nil } - var msgDataModel relation.MsgDataModel + var msgDataModel model.MsgDataModel msgDataModel.SendID = msg.SendID msgDataModel.RecvID = msg.RecvID msgDataModel.GroupID = msg.GroupID @@ -43,7 +43,7 @@ func MsgPb2DB(msg *sdkws.MsgData) *relation.MsgDataModel { msgDataModel.Status = msg.Status msgDataModel.Options = msg.Options if msg.OfflinePushInfo != nil { - msgDataModel.OfflinePush = &relation.OfflinePushModel{ + msgDataModel.OfflinePush = &model.OfflinePushModel{ Title: msg.OfflinePushInfo.Title, Desc: msg.OfflinePushInfo.Desc, Ex: msg.OfflinePushInfo.Ex, @@ -57,7 +57,7 @@ func MsgPb2DB(msg *sdkws.MsgData) *relation.MsgDataModel { return &msgDataModel } -func MsgDB2Pb(msgModel *relation.MsgDataModel) *sdkws.MsgData { +func MsgDB2Pb(msgModel *model.MsgDataModel) *sdkws.MsgData { if msgModel == nil { return nil } diff --git a/pkg/common/convert/user.go b/pkg/common/convert/user.go index a9378e1a0f..ccc574f51b 100644 --- a/pkg/common/convert/user.go +++ b/pkg/common/convert/user.go @@ -15,13 +15,13 @@ package convert import ( + relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model" "time" - relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" "github.com/openimsdk/protocol/sdkws" ) -func UsersDB2Pb(users []*relationtb.UserModel) []*sdkws.UserInfo { +func UsersDB2Pb(users []*relationtb.User) []*sdkws.UserInfo { result := make([]*sdkws.UserInfo, 0, len(users)) for _, user := range users { userPb := &sdkws.UserInfo{ @@ -38,8 +38,8 @@ func UsersDB2Pb(users []*relationtb.UserModel) []*sdkws.UserInfo { return result } -func UserPb2DB(user *sdkws.UserInfo) *relationtb.UserModel { - return &relationtb.UserModel{ +func UserPb2DB(user *sdkws.UserInfo) *relationtb.User { + return &relationtb.User{ UserID: user.UserID, Nickname: user.Nickname, FaceURL: user.FaceURL, diff --git a/pkg/common/convert/user_test.go b/pkg/common/convert/user_test.go index 88eb812d27..be8137265e 100644 --- a/pkg/common/convert/user_test.go +++ b/pkg/common/convert/user_test.go @@ -15,17 +15,16 @@ package convert import ( + relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model" "reflect" "testing" "github.com/openimsdk/protocol/sdkws" - - relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" ) func TestUsersDB2Pb(t *testing.T) { type args struct { - users []*relationtb.UserModel + users []*relationtb.User } tests := []struct { name string @@ -50,7 +49,7 @@ func TestUserPb2DB(t *testing.T) { tests := []struct { name string args args - want *relationtb.UserModel + want *relationtb.User }{ // TODO: Add test cases. } diff --git a/pkg/common/db/cache/conversation.go b/pkg/common/db/cache/conversation.go deleted file mode 100644 index bd189f2a9c..0000000000 --- a/pkg/common/db/cache/conversation.go +++ /dev/null @@ -1,371 +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 cache - -import ( - "context" - "math/big" - "strings" - "time" - - "github.com/dtm-labs/rockscache" - "github.com/openimsdk/open-im-server/v3/pkg/common/cachekey" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" - relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" - "github.com/openimsdk/tools/log" - "github.com/openimsdk/tools/utils/datautil" - "github.com/openimsdk/tools/utils/encrypt" - "github.com/redis/go-redis/v9" -) - -const ( - // ConversationKey = "CONVERSATION:" - // conversationIDsKey = "CONVERSATION_IDS:" - // conversationIDsHashKey = "CONVERSATION_IDS_HASH:" - // conversationHasReadSeqKey = "CONVERSATION_HAS_READ_SEQ:" - // recvMsgOptKey = "RECV_MSG_OPT:" - // superGroupRecvMsgNotNotifyUserIDsKey = "SUPER_GROUP_RECV_MSG_NOT_NOTIFY_USER_IDS:" - // superGroupRecvMsgNotNotifyUserIDsHashKey = "SUPER_GROUP_RECV_MSG_NOT_NOTIFY_USER_IDS_HASH:" - // conversationNotReceiveMessageUserIDsKey = "CONVERSATION_NOT_RECEIVE_MESSAGE_USER_IDS:". - - conversationExpireTime = time.Second * 60 * 60 * 12 -) - -// arg fn will exec when no data in msgCache. -type ConversationCache interface { - metaCache - NewCache() ConversationCache - // get user's conversationIDs from msgCache - GetUserConversationIDs(ctx context.Context, ownerUserID string) ([]string, error) - DelConversationIDs(userIDs ...string) ConversationCache - - GetUserConversationIDsHash(ctx context.Context, ownerUserID string) (hash uint64, err error) - DelUserConversationIDsHash(ownerUserIDs ...string) ConversationCache - - // get one conversation from msgCache - GetConversation(ctx context.Context, ownerUserID, conversationID string) (*relationtb.ConversationModel, error) - DelConversations(ownerUserID string, conversationIDs ...string) ConversationCache - DelUsersConversation(conversationID string, ownerUserIDs ...string) ConversationCache - // get one conversation from msgCache - GetConversations(ctx context.Context, ownerUserID string, - conversationIDs []string) ([]*relationtb.ConversationModel, error) - // get one user's all conversations from msgCache - GetUserAllConversations(ctx context.Context, ownerUserID string) ([]*relationtb.ConversationModel, error) - // get user conversation recv msg from msgCache - GetUserRecvMsgOpt(ctx context.Context, ownerUserID, conversationID string) (opt int, err error) - DelUserRecvMsgOpt(ownerUserID, conversationID string) ConversationCache - // get one super group recv msg but do not notification userID list - // GetSuperGroupRecvMsgNotNotifyUserIDs(ctx context.Context, groupID string) (userIDs []string, err error) - DelSuperGroupRecvMsgNotNotifyUserIDs(groupID string) ConversationCache - // get one super group recv msg but do not notification userID list hash - // GetSuperGroupRecvMsgNotNotifyUserIDsHash(ctx context.Context, groupID string) (hash uint64, err error) - DelSuperGroupRecvMsgNotNotifyUserIDsHash(groupID string) ConversationCache - - // GetUserAllHasReadSeqs(ctx context.Context, ownerUserID string) (map[string]int64, error) - DelUserAllHasReadSeqs(ownerUserID string, conversationIDs ...string) ConversationCache - - GetConversationsByConversationID(ctx context.Context, - conversationIDs []string) ([]*relationtb.ConversationModel, error) - DelConversationByConversationID(conversationIDs ...string) ConversationCache - GetConversationNotReceiveMessageUserIDs(ctx context.Context, conversationID string) ([]string, error) - DelConversationNotReceiveMessageUserIDs(conversationIDs ...string) ConversationCache -} - -func NewConversationRedis(rdb redis.UniversalClient, localCache *config.LocalCache, opts rockscache.Options, db relationtb.ConversationModelInterface) ConversationCache { - rcClient := rockscache.NewClient(rdb, opts) - mc := NewMetaCacheRedis(rcClient) - c := localCache.Conversation - log.ZDebug(context.Background(), "black local cache init", "Topic", c.Topic, "SlotNum", c.SlotNum, "SlotSize", c.SlotSize, "enable", c.Enable()) - mc.SetTopic(c.Topic) - mc.SetRawRedisClient(rdb) - return &ConversationRedisCache{ - rcClient: rcClient, - metaCache: mc, - conversationDB: db, - expireTime: conversationExpireTime, - } -} - -type ConversationRedisCache struct { - metaCache - rcClient *rockscache.Client - conversationDB relationtb.ConversationModelInterface - expireTime time.Duration -} - -// func NewNewConversationRedis( -// rdb redis.UniversalClient, -// conversationDB *relation.ConversationGorm, -// options rockscache.Options, -// ) ConversationCache { -// rcClient := rockscache.NewClient(rdb, options) -// -// return &ConversationRedisCache{ -// rcClient: rcClient, -// metaCache: NewMetaCacheRedis(rcClient), -// conversationDB: conversationDB, -// expireTime: conversationExpireTime, -// } -//} - -func (c *ConversationRedisCache) NewCache() ConversationCache { - return &ConversationRedisCache{ - rcClient: c.rcClient, - metaCache: c.Copy(), - conversationDB: c.conversationDB, - expireTime: c.expireTime, - } -} - -func (c *ConversationRedisCache) getConversationKey(ownerUserID, conversationID string) string { - return cachekey.GetConversationKey(ownerUserID, conversationID) -} - -func (c *ConversationRedisCache) getConversationIDsKey(ownerUserID string) string { - return cachekey.GetConversationIDsKey(ownerUserID) -} - -func (c *ConversationRedisCache) getSuperGroupRecvNotNotifyUserIDsKey(groupID string) string { - return cachekey.GetSuperGroupRecvNotNotifyUserIDsKey(groupID) -} - -func (c *ConversationRedisCache) getRecvMsgOptKey(ownerUserID, conversationID string) string { - return cachekey.GetRecvMsgOptKey(ownerUserID, conversationID) -} - -func (c *ConversationRedisCache) getSuperGroupRecvNotNotifyUserIDsHashKey(groupID string) string { - return cachekey.GetSuperGroupRecvNotNotifyUserIDsHashKey(groupID) -} - -func (c *ConversationRedisCache) getConversationHasReadSeqKey(ownerUserID, conversationID string) string { - return cachekey.GetConversationHasReadSeqKey(ownerUserID, conversationID) -} - -func (c *ConversationRedisCache) getConversationNotReceiveMessageUserIDsKey(conversationID string) string { - return cachekey.GetConversationNotReceiveMessageUserIDsKey(conversationID) -} - -func (c *ConversationRedisCache) getUserConversationIDsHashKey(ownerUserID string) string { - return cachekey.GetUserConversationIDsHashKey(ownerUserID) -} - -func (c *ConversationRedisCache) GetUserConversationIDs(ctx context.Context, ownerUserID string) ([]string, error) { - return getCache(ctx, c.rcClient, c.getConversationIDsKey(ownerUserID), c.expireTime, func(ctx context.Context) ([]string, error) { - return c.conversationDB.FindUserIDAllConversationID(ctx, ownerUserID) - }) -} - -func (c *ConversationRedisCache) DelConversationIDs(userIDs ...string) ConversationCache { - keys := make([]string, 0, len(userIDs)) - for _, userID := range userIDs { - keys = append(keys, c.getConversationIDsKey(userID)) - } - cache := c.NewCache() - cache.AddKeys(keys...) - - return cache -} - -func (c *ConversationRedisCache) GetUserConversationIDsHash(ctx context.Context, ownerUserID string) (hash uint64, err error) { - return getCache( - ctx, - c.rcClient, - c.getUserConversationIDsHashKey(ownerUserID), - c.expireTime, - func(ctx context.Context) (uint64, error) { - conversationIDs, err := c.GetUserConversationIDs(ctx, ownerUserID) - if err != nil { - return 0, err - } - datautil.Sort(conversationIDs, true) - bi := big.NewInt(0) - bi.SetString(encrypt.Md5(strings.Join(conversationIDs, ";"))[0:8], 16) - return bi.Uint64(), nil - }, - ) -} - -func (c *ConversationRedisCache) DelUserConversationIDsHash(ownerUserIDs ...string) ConversationCache { - keys := make([]string, 0, len(ownerUserIDs)) - for _, ownerUserID := range ownerUserIDs { - keys = append(keys, c.getUserConversationIDsHashKey(ownerUserID)) - } - cache := c.NewCache() - cache.AddKeys(keys...) - - return cache -} - -func (c *ConversationRedisCache) GetConversation(ctx context.Context, ownerUserID, conversationID string) (*relationtb.ConversationModel, error) { - return getCache(ctx, c.rcClient, c.getConversationKey(ownerUserID, conversationID), c.expireTime, func(ctx context.Context) (*relationtb.ConversationModel, error) { - return c.conversationDB.Take(ctx, ownerUserID, conversationID) - }) -} - -func (c *ConversationRedisCache) DelConversations(ownerUserID string, conversationIDs ...string) ConversationCache { - keys := make([]string, 0, len(conversationIDs)) - for _, conversationID := range conversationIDs { - keys = append(keys, c.getConversationKey(ownerUserID, conversationID)) - } - cache := c.NewCache() - cache.AddKeys(keys...) - - return cache -} - -// func (c *ConversationRedisCache) getConversationIndex(convsation *relationtb.ConversationModel, keys []string) (int, error) { -// key := c.getConversationKey(convsation.OwnerUserID, convsation.ConversationID) -// for _i, _key := range keys { -// if _key == key { -// return _i, nil -// } -// } - -// return 0, errs.New("not found key:" + key + " in keys") -// } - -func (c *ConversationRedisCache) GetConversations(ctx context.Context, ownerUserID string, conversationIDs []string) ([]*relationtb.ConversationModel, error) { - // var keys []string - // for _, conversarionID := range conversationIDs { - // keys = append(keys, c.getConversationKey(ownerUserID, conversarionID)) - //} - // return batchGetCache( - // ctx, - // c.rcClient, - // keys, - // c.expireTime, - // c.getConversationIndex, - // func(ctx context.Context) ([]*relationtb.ConversationModel, error) { - // return c.conversationDB.Find(ctx, ownerUserID, conversationIDs) - // }, - //) - return batchGetCache2(ctx, c.rcClient, c.expireTime, conversationIDs, func(conversationID string) string { - return c.getConversationKey(ownerUserID, conversationID) - }, func(ctx context.Context, conversationID string) (*relationtb.ConversationModel, error) { - return c.conversationDB.Take(ctx, ownerUserID, conversationID) - }) -} - -func (c *ConversationRedisCache) GetUserAllConversations(ctx context.Context, ownerUserID string) ([]*relationtb.ConversationModel, error) { - conversationIDs, err := c.GetUserConversationIDs(ctx, ownerUserID) - if err != nil { - return nil, err - } - // var keys []string - // for _, conversarionID := range conversationIDs { - // keys = append(keys, c.getConversationKey(ownerUserID, conversarionID)) - //} - // return batchGetCache( - // ctx, - // c.rcClient, - // keys, - // c.expireTime, - // c.getConversationIndex, - // func(ctx context.Context) ([]*relationtb.ConversationModel, error) { - // return c.conversationDB.FindUserIDAllConversations(ctx, ownerUserID) - // }, - //) - return c.GetConversations(ctx, ownerUserID, conversationIDs) -} - -func (c *ConversationRedisCache) GetUserRecvMsgOpt(ctx context.Context, ownerUserID, conversationID string) (opt int, err error) { - return getCache(ctx, c.rcClient, c.getRecvMsgOptKey(ownerUserID, conversationID), c.expireTime, func(ctx context.Context) (opt int, err error) { - return c.conversationDB.GetUserRecvMsgOpt(ctx, ownerUserID, conversationID) - }) -} - -// func (c *ConversationRedisCache) GetSuperGroupRecvMsgNotNotifyUserIDs(ctx context.Context, groupID string) (userIDs []string, err error) { -// return getCache(ctx, c.rcClient, c.getSuperGroupRecvNotNotifyUserIDsKey(groupID), c.expireTime, func(ctx context.Context) (userIDs []string, err error) { -// return c.conversationDB.FindSuperGroupRecvMsgNotNotifyUserIDs(ctx, groupID) -// }) -//} - -func (c *ConversationRedisCache) DelUsersConversation(conversationID string, ownerUserIDs ...string) ConversationCache { - keys := make([]string, 0, len(ownerUserIDs)) - for _, ownerUserID := range ownerUserIDs { - keys = append(keys, c.getConversationKey(ownerUserID, conversationID)) - } - cache := c.NewCache() - cache.AddKeys(keys...) - - return cache -} - -func (c *ConversationRedisCache) DelUserRecvMsgOpt(ownerUserID, conversationID string) ConversationCache { - cache := c.NewCache() - cache.AddKeys(c.getRecvMsgOptKey(ownerUserID, conversationID)) - - return cache -} - -func (c *ConversationRedisCache) DelSuperGroupRecvMsgNotNotifyUserIDs(groupID string) ConversationCache { - cache := c.NewCache() - cache.AddKeys(c.getSuperGroupRecvNotNotifyUserIDsKey(groupID)) - - return cache -} - -// func (c *ConversationRedisCache) GetSuperGroupRecvMsgNotNotifyUserIDsHash(ctx context.Context, groupID string) (hash uint64, err error) { -// return getCache(ctx, c.rcClient, c.getSuperGroupRecvNotNotifyUserIDsHashKey(groupID), c.expireTime, func(ctx context.Context) (hash uint64, err error) { -// userIDs, err := c.GetSuperGroupRecvMsgNotNotifyUserIDs(ctx, groupID) -// if err != nil { -// return 0, err -// } -// utils.Sort(userIDs, true) -// bi := big.NewInt(0) -// bi.SetString(utils.Md5(strings.Join(userIDs, ";"))[0:8], 16) -// return bi.Uint64(), nil -// }, -// ) -//} - -func (c *ConversationRedisCache) DelSuperGroupRecvMsgNotNotifyUserIDsHash(groupID string) ConversationCache { - cache := c.NewCache() - cache.AddKeys(c.getSuperGroupRecvNotNotifyUserIDsHashKey(groupID)) - - return cache -} - -func (c *ConversationRedisCache) DelUserAllHasReadSeqs(ownerUserID string, conversationIDs ...string) ConversationCache { - cache := c.NewCache() - for _, conversationID := range conversationIDs { - cache.AddKeys(c.getConversationHasReadSeqKey(ownerUserID, conversationID)) - } - - return cache -} - -func (c *ConversationRedisCache) GetConversationsByConversationID(ctx context.Context, conversationIDs []string) ([]*relationtb.ConversationModel, error) { - panic("implement me") -} - -func (c *ConversationRedisCache) DelConversationByConversationID(conversationIDs ...string) ConversationCache { - panic("implement me") -} - -func (c *ConversationRedisCache) GetConversationNotReceiveMessageUserIDs(ctx context.Context, conversationID string) ([]string, error) { - return getCache(ctx, c.rcClient, c.getConversationNotReceiveMessageUserIDsKey(conversationID), c.expireTime, func(ctx context.Context) ([]string, error) { - return c.conversationDB.GetConversationNotReceiveMessageUserIDs(ctx, conversationID) - }) -} - -func (c *ConversationRedisCache) DelConversationNotReceiveMessageUserIDs(conversationIDs ...string) ConversationCache { - cache := c.NewCache() - for _, conversationID := range conversationIDs { - cache.AddKeys(c.getConversationNotReceiveMessageUserIDsKey(conversationID)) - } - - return cache -} diff --git a/pkg/common/db/cache/meta_cache.go b/pkg/common/db/cache/meta_cache.go deleted file mode 100644 index e633e4fbd0..0000000000 --- a/pkg/common/db/cache/meta_cache.go +++ /dev/null @@ -1,284 +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 cache - -import ( - "context" - "encoding/json" - "fmt" - "time" - - "github.com/dtm-labs/rockscache" - "github.com/openimsdk/tools/errs" - "github.com/openimsdk/tools/log" - "github.com/openimsdk/tools/mw/specialerror" - "github.com/openimsdk/tools/utils/datautil" - "github.com/redis/go-redis/v9" -) - -const ( - scanCount = 3000 - maxRetryTimes = 5 - retryInterval = time.Millisecond * 100 -) - -var errIndex = errs.New("err index") - -type metaCache interface { - ExecDel(ctx context.Context, distinct ...bool) error - // delete key rapid - DelKey(ctx context.Context, key string) error - AddKeys(keys ...string) - ClearKeys() - GetPreDelKeys() []string - SetTopic(topic string) - SetRawRedisClient(cli redis.UniversalClient) - Copy() metaCache -} - -func NewMetaCacheRedis(rcClient *rockscache.Client, keys ...string) metaCache { - return &metaCacheRedis{rcClient: rcClient, keys: keys, maxRetryTimes: maxRetryTimes, retryInterval: retryInterval} -} - -type metaCacheRedis struct { - topic string - rcClient *rockscache.Client - keys []string - maxRetryTimes int - retryInterval time.Duration - redisClient redis.UniversalClient -} - -func (m *metaCacheRedis) Copy() metaCache { - var keys []string - if len(m.keys) > 0 { - keys = make([]string, 0, len(m.keys)*2) - keys = append(keys, m.keys...) - } - return &metaCacheRedis{ - topic: m.topic, - rcClient: m.rcClient, - keys: keys, - maxRetryTimes: m.maxRetryTimes, - retryInterval: m.retryInterval, - redisClient: m.redisClient, - } -} - -func (m *metaCacheRedis) SetTopic(topic string) { - m.topic = topic -} - -func (m *metaCacheRedis) SetRawRedisClient(cli redis.UniversalClient) { - m.redisClient = cli -} - -func (m *metaCacheRedis) ExecDel(ctx context.Context, distinct ...bool) error { - if len(distinct) > 0 && distinct[0] { - m.keys = datautil.Distinct(m.keys) - } - if len(m.keys) > 0 { - log.ZDebug(ctx, "delete cache", "topic", m.topic, "keys", m.keys) - for _, key := range m.keys { - for i := 0; i < m.maxRetryTimes; i++ { - if err := m.rcClient.TagAsDeleted(key); err != nil { - log.ZError(ctx, "delete cache failed", err, "key", key) - time.Sleep(m.retryInterval) - continue - } - break - } - } - if pk := getPublishKey(m.topic, m.keys); len(pk) > 0 { - data, err := json.Marshal(pk) - if err != nil { - log.ZError(ctx, "keys json marshal failed", err, "topic", m.topic, "keys", pk) - } else { - if err := m.redisClient.Publish(ctx, m.topic, string(data)).Err(); err != nil { - log.ZError(ctx, "redis publish cache delete error", err, "topic", m.topic, "keys", pk) - } - } - } - } - return nil -} - -func (m *metaCacheRedis) DelKey(ctx context.Context, key string) error { - return m.rcClient.TagAsDeleted2(ctx, key) -} - -func (m *metaCacheRedis) AddKeys(keys ...string) { - m.keys = append(m.keys, keys...) -} - -func (m *metaCacheRedis) ClearKeys() { - m.keys = []string{} -} - -func (m *metaCacheRedis) GetPreDelKeys() []string { - return m.keys -} - -func GetDefaultOpt() rockscache.Options { - opts := rockscache.NewDefaultOptions() - opts.StrongConsistency = true - opts.RandomExpireAdjustment = 0.2 - - return opts -} - -func getCache[T any](ctx context.Context, rcClient *rockscache.Client, key string, expire time.Duration, fn func(ctx context.Context) (T, error)) (T, error) { - var t T - var write bool - v, err := rcClient.Fetch2(ctx, key, expire, func() (s string, err error) { - t, err = fn(ctx) - if err != nil { - return "", err - } - bs, err := json.Marshal(t) - if err != nil { - return "", errs.WrapMsg(err, "marshal failed") - } - write = true - - return string(bs), nil - }) - if err != nil { - return t, errs.Wrap(err) - } - if write { - return t, nil - } - if v == "" { - return t, errs.ErrRecordNotFound.WrapMsg("cache is not found") - } - err = json.Unmarshal([]byte(v), &t) - if err != nil { - errInfo := fmt.Sprintf("cache json.Unmarshal failed, key:%s, value:%s, expire:%s", key, v, expire) - return t, errs.WrapMsg(err, errInfo) - } - - return t, nil -} - -// func batchGetCache[T any](ctx context.Context, rcClient *rockscache.Client, keys []string, expire time.Duration, keyIndexFn func(t T, keys []string) (int, error), fn func(ctx context.Context) ([]T, -// error)) ([]T, error) { -// batchMap, err := rcClient.FetchBatch2(ctx, keys, expire, func(idxs []int) (m map[int]string, err error) { -// values := make(map[int]string) -// tArrays, err := fn(ctx) -// if err != nil { -// return nil, err -// } -// for _, v := range tArrays { -// index, err := keyIndexFn(v, keys) -// if err != nil { -// continue -// } -// bs, err := json.Marshal(v) -// if err != nil { -// return nil, utils.Wrap(err, "marshal failed") -// } -// values[index] = string(bs) -// } -// return values, nil -// }) -// if err != nil { -// return nil, err -// } -// var tArrays []T -// for _, v := range batchMap { -// if v != "" { -// var t T -// err = json.Unmarshal([]byte(v), &t) -// if err != nil { -// return nil, utils.Wrap(err, "unmarshal failed") -// } -// tArrays = append(tArrays, t) -// } -// } -// return tArrays, nil -//} - -func batchGetCache2[T any, K comparable]( - ctx context.Context, - rcClient *rockscache.Client, - expire time.Duration, - keys []K, - keyFn func(key K) string, - fns func(ctx context.Context, key K) (T, error), -) ([]T, error) { - if len(keys) == 0 { - return nil, nil - } - res := make([]T, 0, len(keys)) - for _, key := range keys { - val, err := getCache(ctx, rcClient, keyFn(key), expire, func(ctx context.Context) (T, error) { - return fns(ctx, key) - }) - if err != nil { - if errs.ErrRecordNotFound.Is(specialerror.ErrCode(errs.Unwrap(err))) { - continue - } - return nil, errs.Wrap(err) - } - res = append(res, val) - } - - return res, nil -} - -// func batchGetCacheMap[T any]( -// ctx context.Context, -// rcClient *rockscache.Client, -// keys, originKeys []string, -// expire time.Duration, -// keyIndexFn func(s string, keys []string) (int, error), -// fn func(ctx context.Context) (map[string]T, error), -// ) (map[string]T, error) { -// batchMap, err := rcClient.FetchBatch2(ctx, keys, expire, func(idxs []int) (m map[int]string, err error) { -// tArrays, err := fn(ctx) -// if err != nil { -// return nil, err -// } -// values := make(map[int]string) -// for k, v := range tArrays { -// index, err := keyIndexFn(k, originKeys) -// if err != nil { -// continue -// } -// bs, err := json.Marshal(v) -// if err != nil { -// return nil, utils.Wrap(err, "marshal failed") -// } -// values[index] = string(bs) -// } -// return values, nil -// }) -// if err != nil { -// return nil, err -// } -// tMap := make(map[string]T) -// for i, v := range batchMap { -// if v != "" { -// var t T -// err = json.Unmarshal([]byte(v), &t) -// if err != nil { -// return nil, utils.Wrap(err, "unmarshal failed") -// } -// tMap[originKeys[i]] = t -// } -// } -// return tMap, nil -//} diff --git a/pkg/common/db/cache/third.go b/pkg/common/db/cache/third.go deleted file mode 100644 index d2900a32de..0000000000 --- a/pkg/common/db/cache/third.go +++ /dev/null @@ -1,85 +0,0 @@ -package cache - -import ( - "context" - "github.com/openimsdk/tools/errs" - "github.com/redis/go-redis/v9" - "strconv" - "time" -) - -type ThirdCache interface { - SetFcmToken(ctx context.Context, account string, platformID int, fcmToken string, expireTime int64) (err error) - GetFcmToken(ctx context.Context, account string, platformID int) (string, error) - DelFcmToken(ctx context.Context, account string, platformID int) error - IncrUserBadgeUnreadCountSum(ctx context.Context, userID string) (int, error) - SetUserBadgeUnreadCountSum(ctx context.Context, userID string, value int) error - GetUserBadgeUnreadCountSum(ctx context.Context, userID string) (int, error) - SetGetuiToken(ctx context.Context, token string, expireTime int64) error - GetGetuiToken(ctx context.Context) (string, error) - SetGetuiTaskID(ctx context.Context, taskID string, expireTime int64) error - GetGetuiTaskID(ctx context.Context) (string, error) -} - -func NewThirdCache(rdb redis.UniversalClient) ThirdCache { - return &thirdCache{rdb: rdb} -} - -type thirdCache struct { - rdb redis.UniversalClient -} - -func (c *thirdCache) SetFcmToken(ctx context.Context, account string, platformID int, fcmToken string, expireTime int64) (err error) { - return errs.Wrap(c.rdb.Set(ctx, FCM_TOKEN+account+":"+strconv.Itoa(platformID), fcmToken, time.Duration(expireTime)*time.Second).Err()) -} - -func (c *thirdCache) GetFcmToken(ctx context.Context, account string, platformID int) (string, error) { - val, err := c.rdb.Get(ctx, FCM_TOKEN+account+":"+strconv.Itoa(platformID)).Result() - if err != nil { - return "", errs.Wrap(err) - } - return val, nil -} - -func (c *thirdCache) DelFcmToken(ctx context.Context, account string, platformID int) error { - return errs.Wrap(c.rdb.Del(ctx, FCM_TOKEN+account+":"+strconv.Itoa(platformID)).Err()) -} - -func (c *thirdCache) IncrUserBadgeUnreadCountSum(ctx context.Context, userID string) (int, error) { - seq, err := c.rdb.Incr(ctx, userBadgeUnreadCountSum+userID).Result() - - return int(seq), errs.Wrap(err) -} - -func (c *thirdCache) SetUserBadgeUnreadCountSum(ctx context.Context, userID string, value int) error { - return errs.Wrap(c.rdb.Set(ctx, userBadgeUnreadCountSum+userID, value, 0).Err()) -} - -func (c *thirdCache) GetUserBadgeUnreadCountSum(ctx context.Context, userID string) (int, error) { - val, err := c.rdb.Get(ctx, userBadgeUnreadCountSum+userID).Int() - return val, errs.Wrap(err) -} - -func (c *thirdCache) SetGetuiToken(ctx context.Context, token string, expireTime int64) error { - return errs.Wrap(c.rdb.Set(ctx, getuiToken, token, time.Duration(expireTime)*time.Second).Err()) -} - -func (c *thirdCache) GetGetuiToken(ctx context.Context) (string, error) { - val, err := c.rdb.Get(ctx, getuiToken).Result() - if err != nil { - return "", errs.Wrap(err) - } - return val, nil -} - -func (c *thirdCache) SetGetuiTaskID(ctx context.Context, taskID string, expireTime int64) error { - return errs.Wrap(c.rdb.Set(ctx, getuiTaskID, taskID, time.Duration(expireTime)*time.Second).Err()) -} - -func (c *thirdCache) GetGetuiTaskID(ctx context.Context) (string, error) { - val, err := c.rdb.Get(ctx, getuiTaskID).Result() - if err != nil { - return "", errs.Wrap(err) - } - return val, nil -} diff --git a/pkg/common/db/table/relation/doc.go b/pkg/common/db/table/relation/doc.go deleted file mode 100644 index c711dec705..0000000000 --- a/pkg/common/db/table/relation/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 relation // import "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" diff --git a/pkg/common/storage/cache/batch_handler.go b/pkg/common/storage/cache/batch_handler.go new file mode 100644 index 0000000000..84174258aa --- /dev/null +++ b/pkg/common/storage/cache/batch_handler.go @@ -0,0 +1,17 @@ +package cache + +import ( + "context" +) + +// BatchDeleter interface defines a set of methods for batch deleting cache and publishing deletion information. +type BatchDeleter interface { + //ChainExecDel method is used for chain calls and must call Clone to prevent memory pollution. + ChainExecDel(ctx context.Context) error + //ExecDelWithKeys method directly takes keys for deletion. + ExecDelWithKeys(ctx context.Context, keys []string) error + //Clone method creates a copy of the BatchDeleter to avoid modifying the original object. + Clone() BatchDeleter + //AddKeys method adds keys to be deleted. + AddKeys(keys ...string) +} diff --git a/pkg/common/storage/cache/black.go b/pkg/common/storage/cache/black.go new file mode 100644 index 0000000000..515ce3c123 --- /dev/null +++ b/pkg/common/storage/cache/black.go @@ -0,0 +1,27 @@ +// 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 cache + +import ( + "context" +) + +type BlackCache interface { + BatchDeleter + CloneBlackCache() BlackCache + GetBlackIDs(ctx context.Context, userID string) (blackIDs []string, err error) + // del user's blackIDs msgCache, exec when a user's black list changed + DelBlackIDs(ctx context.Context, userID string) BlackCache +} diff --git a/pkg/common/cachekey/black.go b/pkg/common/storage/cache/cachekey/black.go similarity index 100% rename from pkg/common/cachekey/black.go rename to pkg/common/storage/cache/cachekey/black.go diff --git a/pkg/common/cachekey/conversation.go b/pkg/common/storage/cache/cachekey/conversation.go similarity index 100% rename from pkg/common/cachekey/conversation.go rename to pkg/common/storage/cache/cachekey/conversation.go diff --git a/pkg/common/cachekey/doc.go b/pkg/common/storage/cache/cachekey/doc.go similarity index 95% rename from pkg/common/cachekey/doc.go rename to pkg/common/storage/cache/cachekey/doc.go index 4975537ec6..caeda4cea8 100644 --- a/pkg/common/cachekey/doc.go +++ b/pkg/common/storage/cache/cachekey/doc.go @@ -12,4 +12,4 @@ // See the License for the specific language governing permissions and // limitations under the License. -package cachekey // import "github.com/openimsdk/open-im-server/v3/pkg/common/cachekey" +package cachekey // import "github.com/openimsdk/open-im-server/v3/pkg/common/storage/cachekey" diff --git a/pkg/common/cachekey/friend.go b/pkg/common/storage/cache/cachekey/friend.go similarity index 100% rename from pkg/common/cachekey/friend.go rename to pkg/common/storage/cache/cachekey/friend.go diff --git a/pkg/common/cachekey/group.go b/pkg/common/storage/cache/cachekey/group.go similarity index 100% rename from pkg/common/cachekey/group.go rename to pkg/common/storage/cache/cachekey/group.go diff --git a/pkg/common/storage/cache/cachekey/msg.go b/pkg/common/storage/cache/cachekey/msg.go new file mode 100644 index 0000000000..d1e8eeb7bc --- /dev/null +++ b/pkg/common/storage/cache/cachekey/msg.go @@ -0,0 +1,70 @@ +// 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 cachekey + +import ( + "github.com/openimsdk/protocol/constant" + "strconv" +) + +const ( + messageCache = "MESSAGE_CACHE:" + messageDelUserList = "MESSAGE_DEL_USER_LIST:" + userDelMessagesList = "USER_DEL_MESSAGES_LIST:" + sendMsgFailedFlag = "SEND_MSG_FAILED_FLAG:" + exTypeKeyLocker = "EX_LOCK:" + reactionExSingle = "EX_SINGLE_" + reactionWriteGroup = "EX_GROUP_" + reactionReadGroup = "EX_SUPER_GROUP_" + reactionNotification = "EX_NOTIFICATION_" +) + +func GetAllMessageCacheKey(conversationID string) string { + return messageCache + conversationID + "_*" +} + +func GetMessageCacheKey(conversationID string, seq int64) string { + return messageCache + conversationID + "_" + strconv.Itoa(int(seq)) +} + +func GetMessageDelUserListKey(conversationID string, seq int64) string { + return messageDelUserList + conversationID + ":" + strconv.Itoa(int(seq)) +} + +func GetUserDelListKey(conversationID, userID string) string { + return userDelMessagesList + conversationID + ":" + userID +} + +func GetMessageReactionExKey(clientMsgID string, sessionType int32) string { + switch sessionType { + case constant.SingleChatType: + return reactionExSingle + clientMsgID + case constant.WriteGroupChatType: + return reactionWriteGroup + clientMsgID + case constant.ReadGroupChatType: + return reactionReadGroup + clientMsgID + case constant.NotificationChatType: + return reactionNotification + clientMsgID + } + + return "" +} +func GetLockMessageTypeKey(clientMsgID string, TypeKey string) string { + return exTypeKeyLocker + clientMsgID + "_" + TypeKey +} + +func GetSendMsgKey(id string) string { + return sendMsgFailedFlag + id +} diff --git a/pkg/common/storage/cache/cachekey/s3.go b/pkg/common/storage/cache/cachekey/s3.go new file mode 100644 index 0000000000..5c9540b9ef --- /dev/null +++ b/pkg/common/storage/cache/cachekey/s3.go @@ -0,0 +1,40 @@ +// 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 cachekey + +import "strconv" + +const ( + object = "OBJECT:" + s3 = "S3:" + minioImageInfo = "MINIO:IMAGE:" + minioThumbnail = "MINIO:THUMBNAIL:" +) + +func GetObjectKey(engine string, name string) string { + return object + engine + ":" + name +} + +func GetS3Key(engine string, name string) string { + return s3 + engine + ":" + name +} + +func GetObjectImageInfoKey(key string) string { + return minioImageInfo + key +} + +func GetMinioImageThumbnailKey(key string, format string, width int, height int) string { + return minioThumbnail + format + ":w" + strconv.Itoa(width) + ":h" + strconv.Itoa(height) + ":" + key +} diff --git a/pkg/common/storage/cache/cachekey/seq.go b/pkg/common/storage/cache/cachekey/seq.go new file mode 100644 index 0000000000..3f0ce98a4d --- /dev/null +++ b/pkg/common/storage/cache/cachekey/seq.go @@ -0,0 +1,38 @@ +// 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 cachekey + +const ( + maxSeq = "MAX_SEQ:" + minSeq = "MIN_SEQ:" + conversationUserMinSeq = "CON_USER_MIN_SEQ:" + hasReadSeq = "HAS_READ_SEQ:" +) + +func GetMaxSeqKey(conversationID string) string { + return maxSeq + conversationID +} + +func GetMinSeqKey(conversationID string) string { + return minSeq + conversationID +} + +func GetHasReadSeqKey(conversationID string, userID string) string { + return hasReadSeq + userID + ":" + conversationID +} + +func GetConversationUserMinSeqKey(conversationID, userID string) string { + return conversationUserMinSeq + conversationID + "u:" + userID +} diff --git a/pkg/common/storage/cache/cachekey/third.go b/pkg/common/storage/cache/cachekey/third.go new file mode 100644 index 0000000000..469900c343 --- /dev/null +++ b/pkg/common/storage/cache/cachekey/third.go @@ -0,0 +1,41 @@ +// 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 cachekey + +import ( + "strconv" +) + +const ( + getuiToken = "GETUI_TOKEN" + getuiTaskID = "GETUI_TASK_ID" + fmcToken = "FCM_TOKEN:" + userBadgeUnreadCountSum = "USER_BADGE_UNREAD_COUNT_SUM:" +) + +func GetFcmAccountTokenKey(account string, platformID int) string { + return fmcToken + account + ":" + strconv.Itoa(platformID) +} + +func GetUserBadgeUnreadCountSumKey(userID string) string { + return userBadgeUnreadCountSum + userID +} + +func GetGetuiTokenKey() string { + return getuiToken +} +func GetGetuiTaskIDKey() string { + return getuiTaskID +} diff --git a/pkg/common/cachekey/token.go b/pkg/common/storage/cache/cachekey/token.go similarity index 100% rename from pkg/common/cachekey/token.go rename to pkg/common/storage/cache/cachekey/token.go diff --git a/pkg/common/cachekey/user.go b/pkg/common/storage/cache/cachekey/user.go similarity index 87% rename from pkg/common/cachekey/user.go rename to pkg/common/storage/cache/cachekey/user.go index 473ca1b12f..7d06d4f751 100644 --- a/pkg/common/cachekey/user.go +++ b/pkg/common/storage/cache/cachekey/user.go @@ -17,6 +17,7 @@ package cachekey const ( UserInfoKey = "USER_INFO:" UserGlobalRecvMsgOptKey = "USER_GLOBAL_RECV_MSG_OPT_KEY:" + olineStatusKey = "ONLINE_STATUS:" ) func GetUserInfoKey(userID string) string { @@ -26,3 +27,7 @@ func GetUserInfoKey(userID string) string { func GetUserGlobalRecvMsgOptKey(userID string) string { return UserGlobalRecvMsgOptKey + userID } + +func GetOnlineStatusKey(modKey string) string { + return olineStatusKey + modKey +} diff --git a/pkg/common/storage/cache/conversation.go b/pkg/common/storage/cache/conversation.go new file mode 100644 index 0000000000..bf85af0c5f --- /dev/null +++ b/pkg/common/storage/cache/conversation.go @@ -0,0 +1,60 @@ +// 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 cache + +import ( + "context" + relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model" +) + +// arg fn will exec when no data in msgCache. +type ConversationCache interface { + BatchDeleter + CloneConversationCache() ConversationCache + // get user's conversationIDs from msgCache + GetUserConversationIDs(ctx context.Context, ownerUserID string) ([]string, error) + DelConversationIDs(userIDs ...string) ConversationCache + + GetUserConversationIDsHash(ctx context.Context, ownerUserID string) (hash uint64, err error) + DelUserConversationIDsHash(ownerUserIDs ...string) ConversationCache + + // get one conversation from msgCache + GetConversation(ctx context.Context, ownerUserID, conversationID string) (*relationtb.Conversation, error) + DelConversations(ownerUserID string, conversationIDs ...string) ConversationCache + DelUsersConversation(conversationID string, ownerUserIDs ...string) ConversationCache + // get one conversation from msgCache + GetConversations(ctx context.Context, ownerUserID string, + conversationIDs []string) ([]*relationtb.Conversation, error) + // get one user's all conversations from msgCache + GetUserAllConversations(ctx context.Context, ownerUserID string) ([]*relationtb.Conversation, error) + // get user conversation recv msg from msgCache + GetUserRecvMsgOpt(ctx context.Context, ownerUserID, conversationID string) (opt int, err error) + DelUserRecvMsgOpt(ownerUserID, conversationID string) ConversationCache + // get one super group recv msg but do not notification userID list + // GetSuperGroupRecvMsgNotNotifyUserIDs(ctx context.Context, groupID string) (userIDs []string, err error) + DelSuperGroupRecvMsgNotNotifyUserIDs(groupID string) ConversationCache + // get one super group recv msg but do not notification userID list hash + // GetSuperGroupRecvMsgNotNotifyUserIDsHash(ctx context.Context, groupID string) (hash uint64, err error) + DelSuperGroupRecvMsgNotNotifyUserIDsHash(groupID string) ConversationCache + + // GetUserAllHasReadSeqs(ctx context.Context, ownerUserID string) (map[string]int64, error) + DelUserAllHasReadSeqs(ownerUserID string, conversationIDs ...string) ConversationCache + + GetConversationsByConversationID(ctx context.Context, + conversationIDs []string) ([]*relationtb.Conversation, error) + DelConversationByConversationID(conversationIDs ...string) ConversationCache + GetConversationNotReceiveMessageUserIDs(ctx context.Context, conversationID string) ([]string, error) + DelConversationNotReceiveMessageUserIDs(conversationIDs ...string) ConversationCache +} diff --git a/pkg/common/db/cache/doc.go b/pkg/common/storage/cache/doc.go similarity index 96% rename from pkg/common/db/cache/doc.go rename to pkg/common/storage/cache/doc.go index a5c237249e..c74bc75c0f 100644 --- a/pkg/common/db/cache/doc.go +++ b/pkg/common/storage/cache/doc.go @@ -12,4 +12,4 @@ // See the License for the specific language governing permissions and // limitations under the License. -package cache // import "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" +package cache // import "github.com/openimsdk/open-im-server/v3/pkg/common/storage/cache" diff --git a/pkg/common/storage/cache/friend.go b/pkg/common/storage/cache/friend.go new file mode 100644 index 0000000000..acff829f86 --- /dev/null +++ b/pkg/common/storage/cache/friend.go @@ -0,0 +1,35 @@ +// 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 cache + +import ( + "context" + relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model" +) + +// FriendCache is an interface for caching friend-related data. +type FriendCache interface { + BatchDeleter + CloneFriendCache() FriendCache + GetFriendIDs(ctx context.Context, ownerUserID string) (friendIDs []string, err error) + // Called when friendID list changed + DelFriendIDs(ownerUserID ...string) FriendCache + // Get single friendInfo from the cache + GetFriend(ctx context.Context, ownerUserID, friendUserID string) (friend *relationtb.Friend, err error) + // Delete friend when friend info changed + DelFriend(ownerUserID, friendUserID string) FriendCache + // Delete friends when friends' info changed + DelFriends(ownerUserID string, friendUserIDs []string) FriendCache +} diff --git a/pkg/common/storage/cache/group.go b/pkg/common/storage/cache/group.go new file mode 100644 index 0000000000..53e2cd1c74 --- /dev/null +++ b/pkg/common/storage/cache/group.go @@ -0,0 +1,62 @@ +// 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 cache + +import ( + "context" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/common" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model" +) + +type GroupHash interface { + GetGroupHash(ctx context.Context, groupID string) (uint64, error) +} + +type GroupCache interface { + BatchDeleter + CloneGroupCache() GroupCache + GetGroupsInfo(ctx context.Context, groupIDs []string) (groups []*model.Group, err error) + GetGroupInfo(ctx context.Context, groupID string) (group *model.Group, err error) + DelGroupsInfo(groupIDs ...string) GroupCache + + GetGroupMembersHash(ctx context.Context, groupID string) (hashCode uint64, err error) + GetGroupMemberHashMap(ctx context.Context, groupIDs []string) (map[string]*common.GroupSimpleUserID, error) + DelGroupMembersHash(groupID string) GroupCache + + GetGroupMemberIDs(ctx context.Context, groupID string) (groupMemberIDs []string, err error) + GetGroupsMemberIDs(ctx context.Context, groupIDs []string) (groupMemberIDs map[string][]string, err error) + + DelGroupMemberIDs(groupID string) GroupCache + + GetJoinedGroupIDs(ctx context.Context, userID string) (joinedGroupIDs []string, err error) + DelJoinedGroupID(userID ...string) GroupCache + + GetGroupMemberInfo(ctx context.Context, groupID, userID string) (groupMember *model.GroupMember, err error) + GetGroupMembersInfo(ctx context.Context, groupID string, userID []string) (groupMembers []*model.GroupMember, err error) + GetAllGroupMembersInfo(ctx context.Context, groupID string) (groupMembers []*model.GroupMember, err error) + GetGroupMembersPage(ctx context.Context, groupID string, userID []string, showNumber, pageNumber int32) (total uint32, groupMembers []*model.GroupMember, err error) + FindGroupMemberUser(ctx context.Context, groupIDs []string, userID string) ([]*model.GroupMember, error) + + GetGroupRoleLevelMemberIDs(ctx context.Context, groupID string, roleLevel int32) ([]string, error) + GetGroupOwner(ctx context.Context, groupID string) (*model.GroupMember, error) + GetGroupsOwner(ctx context.Context, groupIDs []string) ([]*model.GroupMember, error) + DelGroupRoleLevel(groupID string, roleLevel []int32) GroupCache + DelGroupAllRoleLevel(groupID string) GroupCache + DelGroupMembersInfo(groupID string, userID ...string) GroupCache + GetGroupRoleLevelMemberInfo(ctx context.Context, groupID string, roleLevel int32) ([]*model.GroupMember, error) + GetGroupRolesLevelMemberInfo(ctx context.Context, groupID string, roleLevels []int32) ([]*model.GroupMember, error) + GetGroupMemberNum(ctx context.Context, groupID string) (memberNum int64, err error) + DelGroupsMemberNum(groupID ...string) GroupCache +} diff --git a/pkg/common/storage/cache/msg.go b/pkg/common/storage/cache/msg.go new file mode 100644 index 0000000000..0adbb35726 --- /dev/null +++ b/pkg/common/storage/cache/msg.go @@ -0,0 +1,43 @@ +// 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 cache + +import ( + "context" + "time" + + "github.com/openimsdk/protocol/sdkws" +) + +type MsgCache interface { + GetMessagesBySeq(ctx context.Context, conversationID string, seqs []int64) (seqMsg []*sdkws.MsgData, failedSeqList []int64, err error) + SetMessageToCache(ctx context.Context, conversationID string, msgs []*sdkws.MsgData) (int, error) + UserDeleteMsgs(ctx context.Context, conversationID string, seqs []int64, userID string) error + DelUserDeleteMsgsList(ctx context.Context, conversationID string, seqs []int64) + DeleteMessages(ctx context.Context, conversationID string, seqs []int64) error + GetUserDelList(ctx context.Context, userID, conversationID string) (seqs []int64, err error) + CleanUpOneConversationAllMsg(ctx context.Context, conversationID string) error + DelMsgFromCache(ctx context.Context, userID string, seqList []int64) error + SetSendMsgStatus(ctx context.Context, id string, status int32) error + GetSendMsgStatus(ctx context.Context, id string) (int32, error) + JudgeMessageReactionExist(ctx context.Context, clientMsgID string, sessionType int32) (bool, error) + GetOneMessageAllReactionList(ctx context.Context, clientMsgID string, sessionType int32) (map[string]string, error) + DeleteOneMessageKey(ctx context.Context, clientMsgID string, sessionType int32, subKey string) error + SetMessageReactionExpire(ctx context.Context, clientMsgID string, sessionType int32, expiration time.Duration) (bool, error) + GetMessageTypeKeyValue(ctx context.Context, clientMsgID string, sessionType int32, typeKey string) (string, error) + SetMessageTypeKeyValue(ctx context.Context, clientMsgID string, sessionType int32, typeKey, value string) error + LockMessageTypeKey(ctx context.Context, clientMsgID string, TypeKey string) error + UnLockMessageTypeKey(ctx context.Context, clientMsgID string, TypeKey string) error +} diff --git a/pkg/common/storage/cache/redis/batch_handler.go b/pkg/common/storage/cache/redis/batch_handler.go new file mode 100644 index 0000000000..b68d8f86dc --- /dev/null +++ b/pkg/common/storage/cache/redis/batch_handler.go @@ -0,0 +1,211 @@ +// 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 redis + +import ( + "context" + "encoding/json" + "fmt" + "github.com/dtm-labs/rockscache" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/cache" + "github.com/openimsdk/open-im-server/v3/pkg/localcache" + "github.com/openimsdk/tools/errs" + "github.com/openimsdk/tools/log" + "github.com/openimsdk/tools/mw/specialerror" + "github.com/openimsdk/tools/utils/datautil" + "github.com/redis/go-redis/v9" + "time" +) + +// BatchDeleterRedis is a concrete implementation of the BatchDeleter interface based on Redis and RocksCache. +type BatchDeleterRedis struct { + redisClient redis.UniversalClient + keys []string + rocksClient *rockscache.Client + redisPubTopics []string +} + +// NewBatchDeleterRedis creates a new BatchDeleterRedis instance. +func NewBatchDeleterRedis(redisClient redis.UniversalClient, options *rockscache.Options, redisPubTopics []string) *BatchDeleterRedis { + return &BatchDeleterRedis{ + redisClient: redisClient, + rocksClient: rockscache.NewClient(redisClient, *options), + redisPubTopics: redisPubTopics, + } +} + +// ExecDelWithKeys directly takes keys for batch deletion and publishes deletion information. +func (c *BatchDeleterRedis) ExecDelWithKeys(ctx context.Context, keys []string) error { + distinctKeys := datautil.Distinct(keys) + return c.execDel(ctx, distinctKeys) +} + +// ChainExecDel is used for chain calls for batch deletion. It must call Clone to prevent memory pollution. +func (c *BatchDeleterRedis) ChainExecDel(ctx context.Context) error { + distinctKeys := datautil.Distinct(c.keys) + return c.execDel(ctx, distinctKeys) +} + +// execDel performs batch deletion and publishes the keys that have been deleted to update the local cache information of other nodes. +func (c *BatchDeleterRedis) execDel(ctx context.Context, keys []string) error { + if len(keys) > 0 { + log.ZDebug(ctx, "delete cache", "topic", c.redisPubTopics, "keys", keys) + slotMapKeys, err := groupKeysBySlot(ctx, c.redisClient, keys) + if err != nil { + return err + } + // Batch delete keys + for slot, singleSlotKeys := range slotMapKeys { + if err := c.rocksClient.TagAsDeletedBatch2(ctx, singleSlotKeys); err != nil { + log.ZWarn(ctx, "Batch delete cache failed", err, "slot", slot, "keys", singleSlotKeys) + continue + } + } + // Publish the keys that have been deleted to Redis to update the local cache information of other nodes + if len(c.redisPubTopics) > 0 && len(keys) > 0 { + keysByTopic := localcache.GetPublishKeysByTopic(c.redisPubTopics, keys) + for topic, keys := range keysByTopic { + if len(keys) > 0 { + data, err := json.Marshal(keys) + if err != nil { + log.ZWarn(ctx, "keys json marshal failed", err, "topic", topic, "keys", keys) + } else { + if err := c.redisClient.Publish(ctx, topic, string(data)).Err(); err != nil { + log.ZWarn(ctx, "redis publish cache delete error", err, "topic", topic, "keys", keys) + } + } + } + } + } + } + return nil +} + +// Clone creates a copy of BatchDeleterRedis for chain calls to prevent memory pollution. +func (c *BatchDeleterRedis) Clone() cache.BatchDeleter { + return &BatchDeleterRedis{ + redisClient: c.redisClient, + keys: c.keys, + rocksClient: c.rocksClient, + redisPubTopics: c.redisPubTopics, + } +} + +// AddKeys adds keys to be deleted. +func (c *BatchDeleterRedis) AddKeys(keys ...string) { + c.keys = append(c.keys, keys...) +} + +// GetRocksCacheOptions returns the default configuration options for RocksCache. +func GetRocksCacheOptions() *rockscache.Options { + opts := rockscache.NewDefaultOptions() + opts.StrongConsistency = true + opts.RandomExpireAdjustment = 0.2 + + return &opts +} + +// groupKeysBySlot groups keys by their Redis cluster hash slots. +func groupKeysBySlot(ctx context.Context, redisClient redis.UniversalClient, keys []string) (map[int64][]string, error) { + slots := make(map[int64][]string) + clusterClient, isCluster := redisClient.(*redis.ClusterClient) + if isCluster { + pipe := clusterClient.Pipeline() + cmds := make([]*redis.IntCmd, len(keys)) + for i, key := range keys { + cmds[i] = pipe.ClusterKeySlot(ctx, key) + } + _, err := pipe.Exec(ctx) + if err != nil { + return nil, errs.WrapMsg(err, "get slot err") + } + + for i, cmd := range cmds { + slot, err := cmd.Result() + if err != nil { + log.ZWarn(ctx, "some key get slot err", err, "key", keys[i]) + continue + } + slots[slot] = append(slots[slot], keys[i]) + } + } else { + // If not a cluster client, put all keys in the same slot (0) + slots[0] = keys + } + + return slots, nil +} + +func getCache[T any](ctx context.Context, rcClient *rockscache.Client, key string, expire time.Duration, fn func(ctx context.Context) (T, error)) (T, error) { + var t T + var write bool + v, err := rcClient.Fetch2(ctx, key, expire, func() (s string, err error) { + t, err = fn(ctx) + if err != nil { + return "", err + } + bs, err := json.Marshal(t) + if err != nil { + return "", errs.WrapMsg(err, "marshal failed") + } + write = true + + return string(bs), nil + }) + if err != nil { + return t, errs.Wrap(err) + } + if write { + return t, nil + } + if v == "" { + return t, errs.ErrRecordNotFound.WrapMsg("cache is not found") + } + err = json.Unmarshal([]byte(v), &t) + if err != nil { + errInfo := fmt.Sprintf("cache json.Unmarshal failed, key:%s, value:%s, expire:%s", key, v, expire) + return t, errs.WrapMsg(err, errInfo) + } + + return t, nil +} + +func batchGetCache[T any, K comparable]( + ctx context.Context, + rcClient *rockscache.Client, + expire time.Duration, + keys []K, + keyFn func(key K) string, + fns func(ctx context.Context, key K) (T, error), +) ([]T, error) { + if len(keys) == 0 { + return nil, nil + } + res := make([]T, 0, len(keys)) + for _, key := range keys { + val, err := getCache(ctx, rcClient, keyFn(key), expire, func(ctx context.Context) (T, error) { + return fns(ctx, key) + }) + if err != nil { + if errs.ErrRecordNotFound.Is(specialerror.ErrCode(errs.Unwrap(err))) { + continue + } + return nil, errs.Wrap(err) + } + res = append(res, val) + } + + return res, nil +} diff --git a/pkg/common/db/cache/black.go b/pkg/common/storage/cache/redis/black.go similarity index 59% rename from pkg/common/db/cache/black.go rename to pkg/common/storage/cache/redis/black.go index 615f2cbf1e..fac6dbe6fb 100644 --- a/pkg/common/db/cache/black.go +++ b/pkg/common/storage/cache/redis/black.go @@ -12,63 +12,49 @@ // See the License for the specific language governing permissions and // limitations under the License. -package cache +package redis import ( "context" - "time" - "github.com/dtm-labs/rockscache" - "github.com/openimsdk/open-im-server/v3/pkg/common/cachekey" "github.com/openimsdk/open-im-server/v3/pkg/common/config" - relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/cache" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/cache/cachekey" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/database" "github.com/openimsdk/tools/log" "github.com/redis/go-redis/v9" + "time" ) const ( - blackIDsKey = "BLACK_IDS:" blackExpireTime = time.Second * 60 * 60 * 12 ) -// args fn will exec when no data in msgCache. -type BlackCache interface { - // get blackIDs from msgCache - metaCache - NewCache() BlackCache - GetBlackIDs(ctx context.Context, userID string) (blackIDs []string, err error) - // del user's blackIDs msgCache, exec when a user's black list changed - DelBlackIDs(ctx context.Context, userID string) BlackCache -} - type BlackCacheRedis struct { - metaCache + cache.BatchDeleter expireTime time.Duration rcClient *rockscache.Client - blackDB relationtb.BlackModelInterface + blackDB database.Black } -func NewBlackCacheRedis(rdb redis.UniversalClient, localCache *config.LocalCache, blackDB relationtb.BlackModelInterface, options rockscache.Options) BlackCache { - rcClient := rockscache.NewClient(rdb, options) - mc := NewMetaCacheRedis(rcClient) +func NewBlackCacheRedis(rdb redis.UniversalClient, localCache *config.LocalCache, blackDB database.Black, options *rockscache.Options) cache.BlackCache { + batchHandler := NewBatchDeleterRedis(rdb, options, []string{localCache.Friend.Topic}) b := localCache.Friend log.ZDebug(context.Background(), "black local cache init", "Topic", b.Topic, "SlotNum", b.SlotNum, "SlotSize", b.SlotSize, "enable", b.Enable()) - mc.SetTopic(b.Topic) - mc.SetRawRedisClient(rdb) return &BlackCacheRedis{ - expireTime: blackExpireTime, - rcClient: rcClient, - metaCache: mc, - blackDB: blackDB, + BatchDeleter: batchHandler, + expireTime: blackExpireTime, + rcClient: rockscache.NewClient(rdb, *options), + blackDB: blackDB, } } -func (b *BlackCacheRedis) NewCache() BlackCache { +func (b *BlackCacheRedis) CloneBlackCache() cache.BlackCache { return &BlackCacheRedis{ - expireTime: b.expireTime, - rcClient: b.rcClient, - blackDB: b.blackDB, - metaCache: b.Copy(), + BatchDeleter: b.BatchDeleter.Clone(), + expireTime: b.expireTime, + rcClient: b.rcClient, + blackDB: b.blackDB, } } @@ -88,8 +74,8 @@ func (b *BlackCacheRedis) GetBlackIDs(ctx context.Context, userID string) (black ) } -func (b *BlackCacheRedis) DelBlackIDs(ctx context.Context, userID string) BlackCache { - cache := b.NewCache() +func (b *BlackCacheRedis) DelBlackIDs(_ context.Context, userID string) cache.BlackCache { + cache := b.CloneBlackCache() cache.AddKeys(b.getBlackIDsKey(userID)) return cache diff --git a/pkg/common/storage/cache/redis/conversation.go b/pkg/common/storage/cache/redis/conversation.go new file mode 100644 index 0000000000..5fac79a7e1 --- /dev/null +++ b/pkg/common/storage/cache/redis/conversation.go @@ -0,0 +1,246 @@ +// 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 redis + +import ( + "context" + "github.com/dtm-labs/rockscache" + "github.com/openimsdk/open-im-server/v3/pkg/common/config" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/cache" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/cache/cachekey" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/database" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model" + "github.com/openimsdk/tools/log" + "github.com/openimsdk/tools/utils/datautil" + "github.com/openimsdk/tools/utils/encrypt" + "github.com/redis/go-redis/v9" + "math/big" + "strings" + "time" +) + +const ( + conversationExpireTime = time.Second * 60 * 60 * 12 +) + +func NewConversationRedis(rdb redis.UniversalClient, localCache *config.LocalCache, opts *rockscache.Options, db database.Conversation) cache.ConversationCache { + batchHandler := NewBatchDeleterRedis(rdb, opts, []string{localCache.Conversation.Topic}) + c := localCache.Conversation + log.ZDebug(context.Background(), "black local cache init", "Topic", c.Topic, "SlotNum", c.SlotNum, "SlotSize", c.SlotSize, "enable", c.Enable()) + return &ConversationRedisCache{ + BatchDeleter: batchHandler, + rcClient: rockscache.NewClient(rdb, *opts), + conversationDB: db, + expireTime: conversationExpireTime, + } +} + +type ConversationRedisCache struct { + cache.BatchDeleter + rcClient *rockscache.Client + conversationDB database.Conversation + expireTime time.Duration +} + +func (c *ConversationRedisCache) CloneConversationCache() cache.ConversationCache { + return &ConversationRedisCache{ + BatchDeleter: c.BatchDeleter.Clone(), + rcClient: c.rcClient, + conversationDB: c.conversationDB, + expireTime: c.expireTime, + } +} + +func (c *ConversationRedisCache) getConversationKey(ownerUserID, conversationID string) string { + return cachekey.GetConversationKey(ownerUserID, conversationID) +} + +func (c *ConversationRedisCache) getConversationIDsKey(ownerUserID string) string { + return cachekey.GetConversationIDsKey(ownerUserID) +} + +func (c *ConversationRedisCache) getSuperGroupRecvNotNotifyUserIDsKey(groupID string) string { + return cachekey.GetSuperGroupRecvNotNotifyUserIDsKey(groupID) +} + +func (c *ConversationRedisCache) getRecvMsgOptKey(ownerUserID, conversationID string) string { + return cachekey.GetRecvMsgOptKey(ownerUserID, conversationID) +} + +func (c *ConversationRedisCache) getSuperGroupRecvNotNotifyUserIDsHashKey(groupID string) string { + return cachekey.GetSuperGroupRecvNotNotifyUserIDsHashKey(groupID) +} + +func (c *ConversationRedisCache) getConversationHasReadSeqKey(ownerUserID, conversationID string) string { + return cachekey.GetConversationHasReadSeqKey(ownerUserID, conversationID) +} + +func (c *ConversationRedisCache) getConversationNotReceiveMessageUserIDsKey(conversationID string) string { + return cachekey.GetConversationNotReceiveMessageUserIDsKey(conversationID) +} + +func (c *ConversationRedisCache) getUserConversationIDsHashKey(ownerUserID string) string { + return cachekey.GetUserConversationIDsHashKey(ownerUserID) +} + +func (c *ConversationRedisCache) GetUserConversationIDs(ctx context.Context, ownerUserID string) ([]string, error) { + return getCache(ctx, c.rcClient, c.getConversationIDsKey(ownerUserID), c.expireTime, func(ctx context.Context) ([]string, error) { + return c.conversationDB.FindUserIDAllConversationID(ctx, ownerUserID) + }) +} + +func (c *ConversationRedisCache) DelConversationIDs(userIDs ...string) cache.ConversationCache { + keys := make([]string, 0, len(userIDs)) + for _, userID := range userIDs { + keys = append(keys, c.getConversationIDsKey(userID)) + } + cache := c.CloneConversationCache() + cache.AddKeys(keys...) + + return cache +} + +func (c *ConversationRedisCache) GetUserConversationIDsHash(ctx context.Context, ownerUserID string) (hash uint64, err error) { + return getCache( + ctx, + c.rcClient, + c.getUserConversationIDsHashKey(ownerUserID), + c.expireTime, + func(ctx context.Context) (uint64, error) { + conversationIDs, err := c.GetUserConversationIDs(ctx, ownerUserID) + if err != nil { + return 0, err + } + datautil.Sort(conversationIDs, true) + bi := big.NewInt(0) + bi.SetString(encrypt.Md5(strings.Join(conversationIDs, ";"))[0:8], 16) + return bi.Uint64(), nil + }, + ) +} + +func (c *ConversationRedisCache) DelUserConversationIDsHash(ownerUserIDs ...string) cache.ConversationCache { + keys := make([]string, 0, len(ownerUserIDs)) + for _, ownerUserID := range ownerUserIDs { + keys = append(keys, c.getUserConversationIDsHashKey(ownerUserID)) + } + cache := c.CloneConversationCache() + cache.AddKeys(keys...) + + return cache +} + +func (c *ConversationRedisCache) GetConversation(ctx context.Context, ownerUserID, conversationID string) (*model.Conversation, error) { + return getCache(ctx, c.rcClient, c.getConversationKey(ownerUserID, conversationID), c.expireTime, func(ctx context.Context) (*model.Conversation, error) { + return c.conversationDB.Take(ctx, ownerUserID, conversationID) + }) +} + +func (c *ConversationRedisCache) DelConversations(ownerUserID string, conversationIDs ...string) cache.ConversationCache { + keys := make([]string, 0, len(conversationIDs)) + for _, conversationID := range conversationIDs { + keys = append(keys, c.getConversationKey(ownerUserID, conversationID)) + } + cache := c.CloneConversationCache() + cache.AddKeys(keys...) + + return cache +} + +func (c *ConversationRedisCache) GetConversations(ctx context.Context, ownerUserID string, conversationIDs []string) ([]*model.Conversation, error) { + return batchGetCache(ctx, c.rcClient, c.expireTime, conversationIDs, func(conversationID string) string { + return c.getConversationKey(ownerUserID, conversationID) + }, func(ctx context.Context, conversationID string) (*model.Conversation, error) { + return c.conversationDB.Take(ctx, ownerUserID, conversationID) + }) +} + +func (c *ConversationRedisCache) GetUserAllConversations(ctx context.Context, ownerUserID string) ([]*model.Conversation, error) { + conversationIDs, err := c.GetUserConversationIDs(ctx, ownerUserID) + if err != nil { + return nil, err + } + return c.GetConversations(ctx, ownerUserID, conversationIDs) +} + +func (c *ConversationRedisCache) GetUserRecvMsgOpt(ctx context.Context, ownerUserID, conversationID string) (opt int, err error) { + return getCache(ctx, c.rcClient, c.getRecvMsgOptKey(ownerUserID, conversationID), c.expireTime, func(ctx context.Context) (opt int, err error) { + return c.conversationDB.GetUserRecvMsgOpt(ctx, ownerUserID, conversationID) + }) +} + +func (c *ConversationRedisCache) DelUsersConversation(conversationID string, ownerUserIDs ...string) cache.ConversationCache { + keys := make([]string, 0, len(ownerUserIDs)) + for _, ownerUserID := range ownerUserIDs { + keys = append(keys, c.getConversationKey(ownerUserID, conversationID)) + } + cache := c.CloneConversationCache() + cache.AddKeys(keys...) + + return cache +} + +func (c *ConversationRedisCache) DelUserRecvMsgOpt(ownerUserID, conversationID string) cache.ConversationCache { + cache := c.CloneConversationCache() + cache.AddKeys(c.getRecvMsgOptKey(ownerUserID, conversationID)) + + return cache +} + +func (c *ConversationRedisCache) DelSuperGroupRecvMsgNotNotifyUserIDs(groupID string) cache.ConversationCache { + cache := c.CloneConversationCache() + cache.AddKeys(c.getSuperGroupRecvNotNotifyUserIDsKey(groupID)) + + return cache +} + +func (c *ConversationRedisCache) DelSuperGroupRecvMsgNotNotifyUserIDsHash(groupID string) cache.ConversationCache { + cache := c.CloneConversationCache() + cache.AddKeys(c.getSuperGroupRecvNotNotifyUserIDsHashKey(groupID)) + + return cache +} + +func (c *ConversationRedisCache) DelUserAllHasReadSeqs(ownerUserID string, conversationIDs ...string) cache.ConversationCache { + cache := c.CloneConversationCache() + for _, conversationID := range conversationIDs { + cache.AddKeys(c.getConversationHasReadSeqKey(ownerUserID, conversationID)) + } + + return cache +} + +func (c *ConversationRedisCache) GetConversationsByConversationID(ctx context.Context, conversationIDs []string) ([]*model.Conversation, error) { + panic("implement me") +} + +func (c *ConversationRedisCache) DelConversationByConversationID(conversationIDs ...string) cache.ConversationCache { + panic("implement me") +} + +func (c *ConversationRedisCache) GetConversationNotReceiveMessageUserIDs(ctx context.Context, conversationID string) ([]string, error) { + return getCache(ctx, c.rcClient, c.getConversationNotReceiveMessageUserIDsKey(conversationID), c.expireTime, func(ctx context.Context) ([]string, error) { + return c.conversationDB.GetConversationNotReceiveMessageUserIDs(ctx, conversationID) + }) +} + +func (c *ConversationRedisCache) DelConversationNotReceiveMessageUserIDs(conversationIDs ...string) cache.ConversationCache { + cache := c.CloneConversationCache() + for _, conversationID := range conversationIDs { + cache.AddKeys(c.getConversationNotReceiveMessageUserIDsKey(conversationID)) + } + + return cache +} diff --git a/pkg/common/storage/cache/redis/doc.go b/pkg/common/storage/cache/redis/doc.go new file mode 100644 index 0000000000..4c2fcacd13 --- /dev/null +++ b/pkg/common/storage/cache/redis/doc.go @@ -0,0 +1,15 @@ +// 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 redis diff --git a/pkg/common/db/cache/friend.go b/pkg/common/storage/cache/redis/friend.go similarity index 67% rename from pkg/common/db/cache/friend.go rename to pkg/common/storage/cache/redis/friend.go index 73fe5ea694..f76e5ff6ba 100644 --- a/pkg/common/db/cache/friend.go +++ b/pkg/common/storage/cache/redis/friend.go @@ -12,75 +12,54 @@ // See the License for the specific language governing permissions and // limitations under the License. -package cache +package redis import ( "context" - "time" - "github.com/dtm-labs/rockscache" - "github.com/openimsdk/open-im-server/v3/pkg/common/cachekey" "github.com/openimsdk/open-im-server/v3/pkg/common/config" - relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/cache" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/cache/cachekey" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/database" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model" "github.com/openimsdk/tools/log" "github.com/openimsdk/tools/utils/datautil" "github.com/redis/go-redis/v9" + "time" ) const ( friendExpireTime = time.Second * 60 * 60 * 12 - // FriendIDsKey = "FRIEND_IDS:" - // TwoWayFriendsIDsKey = "COMMON_FRIENDS_IDS:" - // friendKey = "FRIEND_INFO:". ) -// FriendCache is an interface for caching friend-related data. -type FriendCache interface { - metaCache - NewCache() FriendCache - GetFriendIDs(ctx context.Context, ownerUserID string) (friendIDs []string, err error) - // Called when friendID list changed - DelFriendIDs(ownerUserID ...string) FriendCache - // Get single friendInfo from the cache - GetFriend(ctx context.Context, ownerUserID, friendUserID string) (friend *relationtb.FriendModel, err error) - // Delete friend when friend info changed - DelFriend(ownerUserID, friendUserID string) FriendCache - // Delete friends when friends' info changed - DelFriends(ownerUserID string, friendUserIDs []string) FriendCache -} - // FriendCacheRedis is an implementation of the FriendCache interface using Redis. type FriendCacheRedis struct { - metaCache - friendDB relationtb.FriendModelInterface + cache.BatchDeleter + friendDB database.Friend expireTime time.Duration rcClient *rockscache.Client } // NewFriendCacheRedis creates a new instance of FriendCacheRedis. -func NewFriendCacheRedis(rdb redis.UniversalClient, localCache *config.LocalCache, friendDB relationtb.FriendModelInterface, - options rockscache.Options) FriendCache { - rcClient := rockscache.NewClient(rdb, options) - mc := NewMetaCacheRedis(rcClient) +func NewFriendCacheRedis(rdb redis.UniversalClient, localCache *config.LocalCache, friendDB database.Friend, + options *rockscache.Options) cache.FriendCache { + batchHandler := NewBatchDeleterRedis(rdb, options, []string{localCache.Friend.Topic}) f := localCache.Friend log.ZDebug(context.Background(), "friend local cache init", "Topic", f.Topic, "SlotNum", f.SlotNum, "SlotSize", f.SlotSize, "enable", f.Enable()) - mc.SetTopic(f.Topic) - mc.SetRawRedisClient(rdb) return &FriendCacheRedis{ - metaCache: mc, - friendDB: friendDB, - expireTime: friendExpireTime, - rcClient: rcClient, + BatchDeleter: batchHandler, + friendDB: friendDB, + expireTime: friendExpireTime, + rcClient: rockscache.NewClient(rdb, *options), } } -// NewCache creates a new instance of FriendCacheRedis with the same configuration. -func (f *FriendCacheRedis) NewCache() FriendCache { +func (f *FriendCacheRedis) CloneFriendCache() cache.FriendCache { return &FriendCacheRedis{ - rcClient: f.rcClient, - metaCache: f.Copy(), - friendDB: f.friendDB, - expireTime: f.expireTime, + BatchDeleter: f.BatchDeleter.Clone(), + friendDB: f.friendDB, + expireTime: f.expireTime, + rcClient: f.rcClient, } } @@ -107,15 +86,15 @@ func (f *FriendCacheRedis) GetFriendIDs(ctx context.Context, ownerUserID string) } // DelFriendIDs deletes friend IDs from the cache. -func (f *FriendCacheRedis) DelFriendIDs(ownerUserIDs ...string) FriendCache { - newGroupCache := f.NewCache() +func (f *FriendCacheRedis) DelFriendIDs(ownerUserIDs ...string) cache.FriendCache { + newFriendCache := f.CloneFriendCache() keys := make([]string, 0, len(ownerUserIDs)) for _, userID := range ownerUserIDs { keys = append(keys, f.getFriendIDsKey(userID)) } - newGroupCache.AddKeys(keys...) + newFriendCache.AddKeys(keys...) - return newGroupCache + return newFriendCache } // GetTwoWayFriendIDs retrieves two-way friend IDs from the cache. @@ -138,32 +117,32 @@ func (f *FriendCacheRedis) GetTwoWayFriendIDs(ctx context.Context, ownerUserID s } // DelTwoWayFriendIDs deletes two-way friend IDs from the cache. -func (f *FriendCacheRedis) DelTwoWayFriendIDs(ctx context.Context, ownerUserID string) FriendCache { - newFriendCache := f.NewCache() +func (f *FriendCacheRedis) DelTwoWayFriendIDs(ctx context.Context, ownerUserID string) cache.FriendCache { + newFriendCache := f.CloneFriendCache() newFriendCache.AddKeys(f.getTwoWayFriendsIDsKey(ownerUserID)) return newFriendCache } // GetFriend retrieves friend info from the cache or the database if not found. -func (f *FriendCacheRedis) GetFriend(ctx context.Context, ownerUserID, friendUserID string) (friend *relationtb.FriendModel, err error) { +func (f *FriendCacheRedis) GetFriend(ctx context.Context, ownerUserID, friendUserID string) (friend *model.Friend, err error) { return getCache(ctx, f.rcClient, f.getFriendKey(ownerUserID, - friendUserID), f.expireTime, func(ctx context.Context) (*relationtb.FriendModel, error) { + friendUserID), f.expireTime, func(ctx context.Context) (*model.Friend, error) { return f.friendDB.Take(ctx, ownerUserID, friendUserID) }) } // DelFriend deletes friend info from the cache. -func (f *FriendCacheRedis) DelFriend(ownerUserID, friendUserID string) FriendCache { - newFriendCache := f.NewCache() +func (f *FriendCacheRedis) DelFriend(ownerUserID, friendUserID string) cache.FriendCache { + newFriendCache := f.CloneFriendCache() newFriendCache.AddKeys(f.getFriendKey(ownerUserID, friendUserID)) return newFriendCache } // DelFriends deletes multiple friend infos from the cache. -func (f *FriendCacheRedis) DelFriends(ownerUserID string, friendUserIDs []string) FriendCache { - newFriendCache := f.NewCache() +func (f *FriendCacheRedis) DelFriends(ownerUserID string, friendUserIDs []string) cache.FriendCache { + newFriendCache := f.CloneFriendCache() for _, friendUserID := range friendUserIDs { key := f.getFriendKey(ownerUserID, friendUserID) diff --git a/pkg/common/db/cache/group.go b/pkg/common/storage/cache/redis/group.go similarity index 61% rename from pkg/common/db/cache/group.go rename to pkg/common/storage/cache/redis/group.go index 66c2d65c48..2de03906f1 100644 --- a/pkg/common/db/cache/group.go +++ b/pkg/common/storage/cache/redis/group.go @@ -12,110 +12,74 @@ // See the License for the specific language governing permissions and // limitations under the License. -package cache +package redis import ( "context" "fmt" - "time" - "github.com/dtm-labs/rockscache" - "github.com/openimsdk/open-im-server/v3/pkg/common/cachekey" "github.com/openimsdk/open-im-server/v3/pkg/common/config" - relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/cache" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/cache/cachekey" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/common" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/database" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model" "github.com/openimsdk/protocol/constant" "github.com/openimsdk/tools/errs" "github.com/openimsdk/tools/log" "github.com/openimsdk/tools/utils/datautil" "github.com/redis/go-redis/v9" + "time" ) const ( groupExpireTime = time.Second * 60 * 60 * 12 ) -type GroupHash interface { - GetGroupHash(ctx context.Context, groupID string) (uint64, error) -} - -type GroupCache interface { - metaCache - NewCache() GroupCache - GetGroupsInfo(ctx context.Context, groupIDs []string) (groups []*relationtb.GroupModel, err error) - GetGroupInfo(ctx context.Context, groupID string) (group *relationtb.GroupModel, err error) - DelGroupsInfo(groupIDs ...string) GroupCache - - GetGroupMembersHash(ctx context.Context, groupID string) (hashCode uint64, err error) - GetGroupMemberHashMap(ctx context.Context, groupIDs []string) (map[string]*relationtb.GroupSimpleUserID, error) - DelGroupMembersHash(groupID string) GroupCache - - GetGroupMemberIDs(ctx context.Context, groupID string) (groupMemberIDs []string, err error) - GetGroupsMemberIDs(ctx context.Context, groupIDs []string) (groupMemberIDs map[string][]string, err error) - - DelGroupMemberIDs(groupID string) GroupCache - - GetJoinedGroupIDs(ctx context.Context, userID string) (joinedGroupIDs []string, err error) - DelJoinedGroupID(userID ...string) GroupCache - - GetGroupMemberInfo(ctx context.Context, groupID, userID string) (groupMember *relationtb.GroupMemberModel, err error) - GetGroupMembersInfo(ctx context.Context, groupID string, userID []string) (groupMembers []*relationtb.GroupMemberModel, err error) - GetAllGroupMembersInfo(ctx context.Context, groupID string) (groupMembers []*relationtb.GroupMemberModel, err error) - GetGroupMembersPage(ctx context.Context, groupID string, userID []string, showNumber, pageNumber int32) (total uint32, groupMembers []*relationtb.GroupMemberModel, err error) - FindGroupMemberUser(ctx context.Context, groupIDs []string, userID string) ([]*relationtb.GroupMemberModel, error) - - GetGroupRoleLevelMemberIDs(ctx context.Context, groupID string, roleLevel int32) ([]string, error) - GetGroupOwner(ctx context.Context, groupID string) (*relationtb.GroupMemberModel, error) - GetGroupsOwner(ctx context.Context, groupIDs []string) ([]*relationtb.GroupMemberModel, error) - DelGroupRoleLevel(groupID string, roleLevel []int32) GroupCache - DelGroupAllRoleLevel(groupID string) GroupCache - DelGroupMembersInfo(groupID string, userID ...string) GroupCache - GetGroupRoleLevelMemberInfo(ctx context.Context, groupID string, roleLevel int32) ([]*relationtb.GroupMemberModel, error) - GetGroupRolesLevelMemberInfo(ctx context.Context, groupID string, roleLevels []int32) ([]*relationtb.GroupMemberModel, error) - GetGroupMemberNum(ctx context.Context, groupID string) (memberNum int64, err error) - DelGroupsMemberNum(groupID ...string) GroupCache -} +var errIndex = errs.New("err index") type GroupCacheRedis struct { - metaCache - groupDB relationtb.GroupModelInterface - groupMemberDB relationtb.GroupMemberModelInterface - groupRequestDB relationtb.GroupRequestModelInterface + cache.BatchDeleter + groupDB database.Group + groupMemberDB database.GroupMember + groupRequestDB database.GroupRequest expireTime time.Duration rcClient *rockscache.Client - groupHash GroupHash + groupHash cache.GroupHash } func NewGroupCacheRedis( rdb redis.UniversalClient, localCache *config.LocalCache, - groupDB relationtb.GroupModelInterface, - groupMemberDB relationtb.GroupMemberModelInterface, - groupRequestDB relationtb.GroupRequestModelInterface, - hashCode GroupHash, - opts rockscache.Options, -) GroupCache { - rcClient := rockscache.NewClient(rdb, opts) - mc := NewMetaCacheRedis(rcClient) + groupDB database.Group, + groupMemberDB database.GroupMember, + groupRequestDB database.GroupRequest, + hashCode cache.GroupHash, + opts *rockscache.Options, +) cache.GroupCache { + batchHandler := NewBatchDeleterRedis(rdb, opts, []string{localCache.Group.Topic}) g := localCache.Group - mc.SetTopic(g.Topic) log.ZDebug(context.Background(), "group local cache init", "Topic", g.Topic, "SlotNum", g.SlotNum, "SlotSize", g.SlotSize, "enable", g.Enable()) - mc.SetRawRedisClient(rdb) + return &GroupCacheRedis{ - rcClient: rcClient, expireTime: groupExpireTime, - groupDB: groupDB, groupMemberDB: groupMemberDB, groupRequestDB: groupRequestDB, - groupHash: hashCode, - metaCache: mc, + BatchDeleter: batchHandler, + rcClient: rockscache.NewClient(rdb, *opts), + expireTime: groupExpireTime, + groupDB: groupDB, + groupMemberDB: groupMemberDB, + groupRequestDB: groupRequestDB, + groupHash: hashCode, } } -func (g *GroupCacheRedis) NewCache() GroupCache { +func (g *GroupCacheRedis) CloneGroupCache() cache.GroupCache { return &GroupCacheRedis{ + BatchDeleter: g.BatchDeleter.Clone(), rcClient: g.rcClient, expireTime: g.expireTime, groupDB: g.groupDB, groupMemberDB: g.groupMemberDB, groupRequestDB: g.groupRequestDB, - metaCache: g.Copy(), } } @@ -147,7 +111,7 @@ func (g *GroupCacheRedis) getGroupRoleLevelMemberIDsKey(groupID string, roleLeve return cachekey.GetGroupRoleLevelMemberIDsKey(groupID, roleLevel) } -func (g *GroupCacheRedis) GetGroupIndex(group *relationtb.GroupModel, keys []string) (int, error) { +func (g *GroupCacheRedis) GetGroupIndex(group *model.Group, keys []string) (int, error) { key := g.getGroupInfoKey(group.GroupID) for i, _key := range keys { if _key == key { @@ -158,7 +122,7 @@ func (g *GroupCacheRedis) GetGroupIndex(group *relationtb.GroupModel, keys []str return 0, errIndex } -func (g *GroupCacheRedis) GetGroupMemberIndex(groupMember *relationtb.GroupMemberModel, keys []string) (int, error) { +func (g *GroupCacheRedis) GetGroupMemberIndex(groupMember *model.GroupMember, keys []string) (int, error) { key := g.getGroupMemberInfoKey(groupMember.GroupID, groupMember.UserID) for i, _key := range keys { if _key == key { @@ -169,22 +133,22 @@ func (g *GroupCacheRedis) GetGroupMemberIndex(groupMember *relationtb.GroupMembe return 0, errIndex } -func (g *GroupCacheRedis) GetGroupsInfo(ctx context.Context, groupIDs []string) (groups []*relationtb.GroupModel, err error) { - return batchGetCache2(ctx, g.rcClient, g.expireTime, groupIDs, func(groupID string) string { +func (g *GroupCacheRedis) GetGroupsInfo(ctx context.Context, groupIDs []string) (groups []*model.Group, err error) { + return batchGetCache(ctx, g.rcClient, g.expireTime, groupIDs, func(groupID string) string { return g.getGroupInfoKey(groupID) - }, func(ctx context.Context, groupID string) (*relationtb.GroupModel, error) { + }, func(ctx context.Context, groupID string) (*model.Group, error) { return g.groupDB.Take(ctx, groupID) }) } -func (g *GroupCacheRedis) GetGroupInfo(ctx context.Context, groupID string) (group *relationtb.GroupModel, err error) { - return getCache(ctx, g.rcClient, g.getGroupInfoKey(groupID), g.expireTime, func(ctx context.Context) (*relationtb.GroupModel, error) { +func (g *GroupCacheRedis) GetGroupInfo(ctx context.Context, groupID string) (group *model.Group, err error) { + return getCache(ctx, g.rcClient, g.getGroupInfoKey(groupID), g.expireTime, func(ctx context.Context) (*model.Group, error) { return g.groupDB.Take(ctx, groupID) }) } -func (g *GroupCacheRedis) DelGroupsInfo(groupIDs ...string) GroupCache { - newGroupCache := g.NewCache() +func (g *GroupCacheRedis) DelGroupsInfo(groupIDs ...string) cache.GroupCache { + newGroupCache := g.CloneGroupCache() keys := make([]string, 0, len(groupIDs)) for _, groupID := range groupIDs { keys = append(keys, g.getGroupInfoKey(groupID)) @@ -194,8 +158,8 @@ func (g *GroupCacheRedis) DelGroupsInfo(groupIDs ...string) GroupCache { return newGroupCache } -func (g *GroupCacheRedis) DelGroupsOwner(groupIDs ...string) GroupCache { - newGroupCache := g.NewCache() +func (g *GroupCacheRedis) DelGroupsOwner(groupIDs ...string) cache.GroupCache { + newGroupCache := g.CloneGroupCache() keys := make([]string, 0, len(groupIDs)) for _, groupID := range groupIDs { keys = append(keys, g.getGroupRoleLevelMemberIDsKey(groupID, constant.GroupOwner)) @@ -205,8 +169,8 @@ func (g *GroupCacheRedis) DelGroupsOwner(groupIDs ...string) GroupCache { return newGroupCache } -func (g *GroupCacheRedis) DelGroupRoleLevel(groupID string, roleLevels []int32) GroupCache { - newGroupCache := g.NewCache() +func (g *GroupCacheRedis) DelGroupRoleLevel(groupID string, roleLevels []int32) cache.GroupCache { + newGroupCache := g.CloneGroupCache() keys := make([]string, 0, len(roleLevels)) for _, roleLevel := range roleLevels { keys = append(keys, g.getGroupRoleLevelMemberIDsKey(groupID, roleLevel)) @@ -215,7 +179,7 @@ func (g *GroupCacheRedis) DelGroupRoleLevel(groupID string, roleLevels []int32) return newGroupCache } -func (g *GroupCacheRedis) DelGroupAllRoleLevel(groupID string) GroupCache { +func (g *GroupCacheRedis) DelGroupAllRoleLevel(groupID string) cache.GroupCache { return g.DelGroupRoleLevel(groupID, []int32{constant.GroupOwner, constant.GroupAdmin, constant.GroupOrdinaryUsers}) } @@ -228,11 +192,11 @@ func (g *GroupCacheRedis) GetGroupMembersHash(ctx context.Context, groupID strin }) } -func (g *GroupCacheRedis) GetGroupMemberHashMap(ctx context.Context, groupIDs []string) (map[string]*relationtb.GroupSimpleUserID, error) { +func (g *GroupCacheRedis) GetGroupMemberHashMap(ctx context.Context, groupIDs []string) (map[string]*common.GroupSimpleUserID, error) { if g.groupHash == nil { return nil, errs.ErrInternalServer.WrapMsg("group hash is nil") } - res := make(map[string]*relationtb.GroupSimpleUserID) + res := make(map[string]*common.GroupSimpleUserID) for _, groupID := range groupIDs { hash, err := g.GetGroupMembersHash(ctx, groupID) if err != nil { @@ -243,14 +207,14 @@ func (g *GroupCacheRedis) GetGroupMemberHashMap(ctx context.Context, groupIDs [] if err != nil { return nil, err } - res[groupID] = &relationtb.GroupSimpleUserID{Hash: hash, MemberNum: uint32(num)} + res[groupID] = &common.GroupSimpleUserID{Hash: hash, MemberNum: uint32(num)} } return res, nil } -func (g *GroupCacheRedis) DelGroupMembersHash(groupID string) GroupCache { - cache := g.NewCache() +func (g *GroupCacheRedis) DelGroupMembersHash(groupID string) cache.GroupCache { + cache := g.CloneGroupCache() cache.AddKeys(g.getGroupMembersHashKey(groupID)) return cache @@ -275,8 +239,8 @@ func (g *GroupCacheRedis) GetGroupsMemberIDs(ctx context.Context, groupIDs []str return m, nil } -func (g *GroupCacheRedis) DelGroupMemberIDs(groupID string) GroupCache { - cache := g.NewCache() +func (g *GroupCacheRedis) DelGroupMemberIDs(groupID string) cache.GroupCache { + cache := g.CloneGroupCache() cache.AddKeys(g.getGroupMemberIDsKey(groupID)) return cache @@ -288,27 +252,27 @@ func (g *GroupCacheRedis) GetJoinedGroupIDs(ctx context.Context, userID string) }) } -func (g *GroupCacheRedis) DelJoinedGroupID(userIDs ...string) GroupCache { +func (g *GroupCacheRedis) DelJoinedGroupID(userIDs ...string) cache.GroupCache { keys := make([]string, 0, len(userIDs)) for _, userID := range userIDs { keys = append(keys, g.getJoinedGroupsKey(userID)) } - cache := g.NewCache() + cache := g.CloneGroupCache() cache.AddKeys(keys...) return cache } -func (g *GroupCacheRedis) GetGroupMemberInfo(ctx context.Context, groupID, userID string) (groupMember *relationtb.GroupMemberModel, err error) { - return getCache(ctx, g.rcClient, g.getGroupMemberInfoKey(groupID, userID), g.expireTime, func(ctx context.Context) (*relationtb.GroupMemberModel, error) { +func (g *GroupCacheRedis) GetGroupMemberInfo(ctx context.Context, groupID, userID string) (groupMember *model.GroupMember, err error) { + return getCache(ctx, g.rcClient, g.getGroupMemberInfoKey(groupID, userID), g.expireTime, func(ctx context.Context) (*model.GroupMember, error) { return g.groupMemberDB.Take(ctx, groupID, userID) }) } -func (g *GroupCacheRedis) GetGroupMembersInfo(ctx context.Context, groupID string, userIDs []string) ([]*relationtb.GroupMemberModel, error) { - return batchGetCache2(ctx, g.rcClient, g.expireTime, userIDs, func(userID string) string { +func (g *GroupCacheRedis) GetGroupMembersInfo(ctx context.Context, groupID string, userIDs []string) ([]*model.GroupMember, error) { + return batchGetCache(ctx, g.rcClient, g.expireTime, userIDs, func(userID string) string { return g.getGroupMemberInfoKey(groupID, userID) - }, func(ctx context.Context, userID string) (*relationtb.GroupMemberModel, error) { + }, func(ctx context.Context, userID string) (*model.GroupMember, error) { return g.groupMemberDB.Take(ctx, groupID, userID) }) } @@ -318,7 +282,7 @@ func (g *GroupCacheRedis) GetGroupMembersPage( groupID string, userIDs []string, showNumber, pageNumber int32, -) (total uint32, groupMembers []*relationtb.GroupMemberModel, err error) { +) (total uint32, groupMembers []*model.GroupMember, err error) { groupMemberIDs, err := g.GetGroupMemberIDs(ctx, groupID) if err != nil { return 0, nil, err @@ -333,7 +297,7 @@ func (g *GroupCacheRedis) GetGroupMembersPage( return uint32(len(userIDs)), groupMembers, err } -func (g *GroupCacheRedis) GetAllGroupMembersInfo(ctx context.Context, groupID string) (groupMembers []*relationtb.GroupMemberModel, err error) { +func (g *GroupCacheRedis) GetAllGroupMembersInfo(ctx context.Context, groupID string) (groupMembers []*model.GroupMember, err error) { groupMemberIDs, err := g.GetGroupMemberIDs(ctx, groupID) if err != nil { return nil, err @@ -342,7 +306,7 @@ func (g *GroupCacheRedis) GetAllGroupMembersInfo(ctx context.Context, groupID st return g.GetGroupMembersInfo(ctx, groupID, groupMemberIDs) } -func (g *GroupCacheRedis) GetAllGroupMemberInfo(ctx context.Context, groupID string) ([]*relationtb.GroupMemberModel, error) { +func (g *GroupCacheRedis) GetAllGroupMemberInfo(ctx context.Context, groupID string) ([]*model.GroupMember, error) { groupMemberIDs, err := g.GetGroupMemberIDs(ctx, groupID) if err != nil { return nil, err @@ -350,12 +314,12 @@ func (g *GroupCacheRedis) GetAllGroupMemberInfo(ctx context.Context, groupID str return g.GetGroupMembersInfo(ctx, groupID, groupMemberIDs) } -func (g *GroupCacheRedis) DelGroupMembersInfo(groupID string, userIDs ...string) GroupCache { +func (g *GroupCacheRedis) DelGroupMembersInfo(groupID string, userIDs ...string) cache.GroupCache { keys := make([]string, 0, len(userIDs)) for _, userID := range userIDs { keys = append(keys, g.getGroupMemberInfoKey(groupID, userID)) } - cache := g.NewCache() + cache := g.CloneGroupCache() cache.AddKeys(keys...) return cache @@ -367,18 +331,18 @@ func (g *GroupCacheRedis) GetGroupMemberNum(ctx context.Context, groupID string) }) } -func (g *GroupCacheRedis) DelGroupsMemberNum(groupID ...string) GroupCache { +func (g *GroupCacheRedis) DelGroupsMemberNum(groupID ...string) cache.GroupCache { keys := make([]string, 0, len(groupID)) for _, groupID := range groupID { keys = append(keys, g.getGroupMemberNumKey(groupID)) } - cache := g.NewCache() + cache := g.CloneGroupCache() cache.AddKeys(keys...) return cache } -func (g *GroupCacheRedis) GetGroupOwner(ctx context.Context, groupID string) (*relationtb.GroupMemberModel, error) { +func (g *GroupCacheRedis) GetGroupOwner(ctx context.Context, groupID string) (*model.GroupMember, error) { members, err := g.GetGroupRoleLevelMemberInfo(ctx, groupID, constant.GroupOwner) if err != nil { return nil, err @@ -389,8 +353,8 @@ func (g *GroupCacheRedis) GetGroupOwner(ctx context.Context, groupID string) (*r return members[0], nil } -func (g *GroupCacheRedis) GetGroupsOwner(ctx context.Context, groupIDs []string) ([]*relationtb.GroupMemberModel, error) { - members := make([]*relationtb.GroupMemberModel, 0, len(groupIDs)) +func (g *GroupCacheRedis) GetGroupsOwner(ctx context.Context, groupIDs []string) ([]*model.GroupMember, error) { + members := make([]*model.GroupMember, 0, len(groupIDs)) for _, groupID := range groupIDs { items, err := g.GetGroupRoleLevelMemberInfo(ctx, groupID, constant.GroupOwner) if err != nil { @@ -409,7 +373,7 @@ func (g *GroupCacheRedis) GetGroupRoleLevelMemberIDs(ctx context.Context, groupI }) } -func (g *GroupCacheRedis) GetGroupRoleLevelMemberInfo(ctx context.Context, groupID string, roleLevel int32) ([]*relationtb.GroupMemberModel, error) { +func (g *GroupCacheRedis) GetGroupRoleLevelMemberInfo(ctx context.Context, groupID string, roleLevel int32) ([]*model.GroupMember, error) { userIDs, err := g.GetGroupRoleLevelMemberIDs(ctx, groupID, roleLevel) if err != nil { return nil, err @@ -417,7 +381,7 @@ func (g *GroupCacheRedis) GetGroupRoleLevelMemberInfo(ctx context.Context, group return g.GetGroupMembersInfo(ctx, groupID, userIDs) } -func (g *GroupCacheRedis) GetGroupRolesLevelMemberInfo(ctx context.Context, groupID string, roleLevels []int32) ([]*relationtb.GroupMemberModel, error) { +func (g *GroupCacheRedis) GetGroupRolesLevelMemberInfo(ctx context.Context, groupID string, roleLevels []int32) ([]*model.GroupMember, error) { var userIDs []string for _, roleLevel := range roleLevels { ids, err := g.GetGroupRoleLevelMemberIDs(ctx, groupID, roleLevel) @@ -429,16 +393,16 @@ func (g *GroupCacheRedis) GetGroupRolesLevelMemberInfo(ctx context.Context, grou return g.GetGroupMembersInfo(ctx, groupID, userIDs) } -func (g *GroupCacheRedis) FindGroupMemberUser(ctx context.Context, groupIDs []string, userID string) (_ []*relationtb.GroupMemberModel, err error) { +func (g *GroupCacheRedis) FindGroupMemberUser(ctx context.Context, groupIDs []string, userID string) (_ []*model.GroupMember, err error) { if len(groupIDs) == 0 { groupIDs, err = g.GetJoinedGroupIDs(ctx, userID) if err != nil { return nil, err } } - return batchGetCache2(ctx, g.rcClient, g.expireTime, groupIDs, func(groupID string) string { + return batchGetCache(ctx, g.rcClient, g.expireTime, groupIDs, func(groupID string) string { return g.getGroupMemberInfoKey(groupID, userID) - }, func(ctx context.Context, groupID string) (*relationtb.GroupMemberModel, error) { + }, func(ctx context.Context, groupID string) (*model.GroupMember, error) { return g.groupMemberDB.Take(ctx, groupID, userID) }) } diff --git a/pkg/common/storage/cache/redis/meta_cache.go b/pkg/common/storage/cache/redis/meta_cache.go new file mode 100644 index 0000000000..4c2fcacd13 --- /dev/null +++ b/pkg/common/storage/cache/redis/meta_cache.go @@ -0,0 +1,15 @@ +// 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 redis diff --git a/pkg/common/db/cache/msg.go b/pkg/common/storage/cache/redis/msg.go similarity index 68% rename from pkg/common/db/cache/msg.go rename to pkg/common/storage/cache/redis/msg.go index e8a86b71bd..df69bc6451 100644 --- a/pkg/common/db/cache/msg.go +++ b/pkg/common/storage/cache/redis/msg.go @@ -12,15 +12,14 @@ // See the License for the specific language governing permissions and // limitations under the License. -package cache +package redis import ( "context" "errors" - "strconv" - "time" - "github.com/gogo/protobuf/jsonpb" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/cache" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/cache/cachekey" "github.com/openimsdk/open-im-server/v3/pkg/msgprocessor" "github.com/openimsdk/protocol/constant" "github.com/openimsdk/protocol/sdkws" @@ -29,78 +28,48 @@ import ( "github.com/openimsdk/tools/utils/stringutil" "github.com/redis/go-redis/v9" "golang.org/x/sync/errgroup" + "time" ) const msgCacheTimeout = 86400 * time.Second -const ( - maxSeq = "MAX_SEQ:" - minSeq = "MIN_SEQ:" - conversationUserMinSeq = "CON_USER_MIN_SEQ:" - hasReadSeq = "HAS_READ_SEQ:" - - getuiToken = "GETUI_TOKEN" - getuiTaskID = "GETUI_TASK_ID" - FCM_TOKEN = "FCM_TOKEN:" - - messageCache = "MESSAGE_CACHE:" - messageDelUserList = "MESSAGE_DEL_USER_LIST:" - userDelMessagesList = "USER_DEL_MESSAGES_LIST:" - sendMsgFailedFlag = "SEND_MSG_FAILED_FLAG:" - userBadgeUnreadCountSum = "USER_BADGE_UNREAD_COUNT_SUM:" - exTypeKeyLocker = "EX_LOCK:" -) - var concurrentLimit = 3 -//type MsgModel interface { -// SeqCache -// ThirdCache -// MsgCache -//} - -type MsgCache interface { - GetMessagesBySeq(ctx context.Context, conversationID string, seqs []int64) (seqMsg []*sdkws.MsgData, failedSeqList []int64, err error) - SetMessageToCache(ctx context.Context, conversationID string, msgs []*sdkws.MsgData) (int, error) - UserDeleteMsgs(ctx context.Context, conversationID string, seqs []int64, userID string) error - DelUserDeleteMsgsList(ctx context.Context, conversationID string, seqs []int64) - DeleteMessages(ctx context.Context, conversationID string, seqs []int64) error - GetUserDelList(ctx context.Context, userID, conversationID string) (seqs []int64, err error) - CleanUpOneConversationAllMsg(ctx context.Context, conversationID string) error - DelMsgFromCache(ctx context.Context, userID string, seqList []int64) error - SetSendMsgStatus(ctx context.Context, id string, status int32) error - GetSendMsgStatus(ctx context.Context, id string) (int32, error) - JudgeMessageReactionExist(ctx context.Context, clientMsgID string, sessionType int32) (bool, error) - GetOneMessageAllReactionList(ctx context.Context, clientMsgID string, sessionType int32) (map[string]string, error) - DeleteOneMessageKey(ctx context.Context, clientMsgID string, sessionType int32, subKey string) error - SetMessageReactionExpire(ctx context.Context, clientMsgID string, sessionType int32, expiration time.Duration) (bool, error) - GetMessageTypeKeyValue(ctx context.Context, clientMsgID string, sessionType int32, typeKey string) (string, error) - SetMessageTypeKeyValue(ctx context.Context, clientMsgID string, sessionType int32, typeKey, value string) error - LockMessageTypeKey(ctx context.Context, clientMsgID string, TypeKey string) error - UnLockMessageTypeKey(ctx context.Context, clientMsgID string, TypeKey string) error -} - -//func NewMsgCacheModel(client redis.UniversalClient, msgCacheTimeout int, redisConf *config.Redis) MsgModel { -// return &msgCache{rdb: client, msgCacheTimeout: msgCacheTimeout, redisConf: redisConf} -//} - -func NewMsgCache(client redis.UniversalClient, redisEnablePipeline bool) MsgCache { +func NewMsgCache(client redis.UniversalClient, redisEnablePipeline bool) cache.MsgCache { return &msgCache{rdb: client, msgCacheTimeout: msgCacheTimeout, redisEnablePipeline: redisEnablePipeline} } type msgCache struct { - metaCache rdb redis.UniversalClient msgCacheTimeout time.Duration redisEnablePipeline bool } -func (c *msgCache) allMessageCacheKey(conversationID string) string { - return messageCache + conversationID + "_*" +func (c *msgCache) getAllMessageCacheKey(conversationID string) string { + return cachekey.GetAllMessageCacheKey(conversationID) } func (c *msgCache) getMessageCacheKey(conversationID string, seq int64) string { - return messageCache + conversationID + "_" + strconv.Itoa(int(seq)) + return cachekey.GetMessageCacheKey(conversationID, seq) +} +func (c *msgCache) getMessageDelUserListKey(conversationID string, seq int64) string { + return cachekey.GetMessageDelUserListKey(conversationID, seq) +} + +func (c *msgCache) getUserDelList(conversationID, userID string) string { + return cachekey.GetUserDelListKey(conversationID, userID) +} + +func (c *msgCache) getSendMsgKey(id string) string { + return cachekey.GetSendMsgKey(id) +} + +func (c *msgCache) getLockMessageTypeKey(clientMsgID string, TypeKey string) string { + return cachekey.GetLockMessageTypeKey(clientMsgID, TypeKey) +} + +func (c *msgCache) getMessageReactionExPrefix(clientMsgID string, sessionType int32) string { + return cachekey.GetMessageReactionExKey(clientMsgID, sessionType) } func (c *msgCache) SetMessageToCache(ctx context.Context, conversationID string, msgs []*sdkws.MsgData) (int, error) { @@ -164,14 +133,6 @@ func (c *msgCache) ParallelSetMessageToCache(ctx context.Context, conversationID return len(msgs), nil } -func (c *msgCache) getMessageDelUserListKey(conversationID string, seq int64) string { - return messageDelUserList + conversationID + ":" + strconv.Itoa(int(seq)) -} - -func (c *msgCache) getUserDelList(conversationID, userID string) string { - return userDelMessagesList + conversationID + ":" + userID -} - func (c *msgCache) UserDeleteMsgs(ctx context.Context, conversationID string, seqs []int64, userID string) error { for _, seq := range seqs { delUserListKey := c.getMessageDelUserListKey(conversationID, seq) @@ -193,27 +154,6 @@ func (c *msgCache) UserDeleteMsgs(ctx context.Context, conversationID string, se } return nil - // pipe := c.rdb.Pipeline() - // for _, seq := range seqs { - // delUserListKey := c.getMessageDelUserListKey(conversationID, seq) - // userDelListKey := c.getUserDelList(conversationID, userID) - // err := pipe.SAdd(ctx, delUserListKey, userID).Err() - // if err != nil { - // return errs.Wrap(err) - // } - // err = pipe.SAdd(ctx, userDelListKey, seq).Err() - // if err != nil { - // return errs.Wrap(err) - // } - // if err := pipe.Expire(ctx, delUserListKey, time.Duration(config.Config.MsgCacheTimeout)*time.Second).Err(); err != nil { - // return errs.Wrap(err) - // } - // if err := pipe.Expire(ctx, userDelListKey, time.Duration(config.Config.MsgCacheTimeout)*time.Second).Err(); err != nil { - // return errs.Wrap(err) - // } - //} - // _, err := pipe.Exec(ctx) - // return errs.Wrap(err) } func (c *msgCache) GetUserDelList(ctx context.Context, userID, conversationID string) (seqs []int64, err error) { @@ -253,42 +193,6 @@ func (c *msgCache) DelUserDeleteMsgsList(ctx context.Context, conversationID str } } } - // for _, seq := range seqs { - // delUsers, err := c.rdb.SMembers(ctx, c.getMessageDelUserListKey(conversationID, seq)).Result() - // if err != nil { - // log.ZWarn(ctx, "DelUserDeleteMsgsList failed", err, "conversationID", conversationID, "seq", seq) - // continue - // } - // if len(delUsers) > 0 { - // pipe := c.rdb.Pipeline() - // var failedFlag bool - // for _, userID := range delUsers { - // err = pipe.SRem(ctx, c.getUserDelList(conversationID, userID), seq).Err() - // if err != nil { - // failedFlag = true - // log.ZWarn( - // ctx, - // "DelUserDeleteMsgsList failed", - // err, - // "conversationID", - // conversationID, - // "seq", - // seq, - // "userID", - // userID, - // ) - // } - // } - // if !failedFlag { - // if err := pipe.Del(ctx, c.getMessageDelUserListKey(conversationID, seq)).Err(); err != nil { - // log.ZWarn(ctx, "DelUserDeleteMsgsList failed", err, "conversationID", conversationID, "seq", seq) - // } - // } - // if _, err := pipe.Exec(ctx); err != nil { - // log.ZError(ctx, "pipe exec failed", err, "conversationID", conversationID, "seq", seq) - // } - // } - //} } func (c *msgCache) DeleteMessages(ctx context.Context, conversationID string, seqs []int64) error { @@ -338,7 +242,7 @@ func (c *msgCache) PipeDeleteMessages(ctx context.Context, conversationID string } func (c *msgCache) CleanUpOneConversationAllMsg(ctx context.Context, conversationID string) error { - vals, err := c.rdb.Keys(ctx, c.allMessageCacheKey(conversationID)).Result() + vals, err := c.rdb.Keys(ctx, c.getAllMessageCacheKey(conversationID)).Result() if errors.Is(err, redis.Nil) { return nil } @@ -383,42 +287,24 @@ func (c *msgCache) DelMsgFromCache(ctx context.Context, userID string, seqs []in } func (c *msgCache) SetSendMsgStatus(ctx context.Context, id string, status int32) error { - return errs.Wrap(c.rdb.Set(ctx, sendMsgFailedFlag+id, status, time.Hour*24).Err()) + return errs.Wrap(c.rdb.Set(ctx, c.getSendMsgKey(id), status, time.Hour*24).Err()) } func (c *msgCache) GetSendMsgStatus(ctx context.Context, id string) (int32, error) { - result, err := c.rdb.Get(ctx, sendMsgFailedFlag+id).Int() - + result, err := c.rdb.Get(ctx, c.getSendMsgKey(id)).Int() return int32(result), errs.Wrap(err) } func (c *msgCache) LockMessageTypeKey(ctx context.Context, clientMsgID string, TypeKey string) error { - key := exTypeKeyLocker + clientMsgID + "_" + TypeKey - + key := c.getLockMessageTypeKey(clientMsgID, TypeKey) return errs.Wrap(c.rdb.SetNX(ctx, key, 1, time.Minute).Err()) } func (c *msgCache) UnLockMessageTypeKey(ctx context.Context, clientMsgID string, TypeKey string) error { - key := exTypeKeyLocker + clientMsgID + "_" + TypeKey - + key := c.getLockMessageTypeKey(clientMsgID, TypeKey) return errs.Wrap(c.rdb.Del(ctx, key).Err()) } -func (c *msgCache) getMessageReactionExPrefix(clientMsgID string, sessionType int32) string { - switch sessionType { - case constant.SingleChatType: - return "EX_SINGLE_" + clientMsgID - case constant.WriteGroupChatType: - return "EX_GROUP_" + clientMsgID - case constant.ReadGroupChatType: - return "EX_SUPER_GROUP_" + clientMsgID - case constant.NotificationChatType: - return "EX_NOTIFICATION" + clientMsgID - } - - return "" -} - func (c *msgCache) JudgeMessageReactionExist(ctx context.Context, clientMsgID string, sessionType int32) (bool, error) { n, err := c.rdb.Exists(ctx, c.getMessageReactionExPrefix(clientMsgID, sessionType)).Result() if err != nil { diff --git a/pkg/common/db/cache/msg_test.go b/pkg/common/storage/cache/redis/msg_test.go similarity index 99% rename from pkg/common/db/cache/msg_test.go rename to pkg/common/storage/cache/redis/msg_test.go index 481b4012c1..d47fa18e18 100644 --- a/pkg/common/db/cache/msg_test.go +++ b/pkg/common/storage/cache/redis/msg_test.go @@ -12,17 +12,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -package cache +package redis import ( "context" "fmt" - "math/rand" - "testing" - "github.com/openimsdk/protocol/sdkws" "github.com/redis/go-redis/v9" "github.com/stretchr/testify/assert" + "math/rand" + "testing" ) func TestParallelSetMessageToCache(t *testing.T) { diff --git a/pkg/common/db/cache/s3.go b/pkg/common/storage/cache/redis/s3.go similarity index 52% rename from pkg/common/db/cache/s3.go rename to pkg/common/storage/cache/redis/s3.go index 1610283ca4..954557aca7 100644 --- a/pkg/common/db/cache/s3.go +++ b/pkg/common/storage/cache/redis/s3.go @@ -12,55 +12,55 @@ // See the License for the specific language governing permissions and // limitations under the License. -package cache +package redis import ( "context" - "github.com/openimsdk/tools/s3/cont" - "github.com/openimsdk/tools/s3/minio" - "strconv" - "time" - "github.com/dtm-labs/rockscache" - relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/cache" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/cache/cachekey" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/database" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model" "github.com/openimsdk/tools/s3" + "github.com/openimsdk/tools/s3/cont" + "github.com/openimsdk/tools/s3/minio" "github.com/redis/go-redis/v9" + "time" ) -type ObjectCache interface { - metaCache - GetName(ctx context.Context, engine string, name string) (*relationtb.ObjectModel, error) - DelObjectName(engine string, names ...string) ObjectCache -} - -func NewObjectCacheRedis(rdb redis.UniversalClient, objDB relationtb.ObjectInfoModelInterface) ObjectCache { - rcClient := rockscache.NewClient(rdb, rockscache.NewDefaultOptions()) +func NewObjectCacheRedis(rdb redis.UniversalClient, objDB database.ObjectInfo) cache.ObjectCache { + opts := rockscache.NewDefaultOptions() + batchHandler := NewBatchDeleterRedis(rdb, &opts, nil) return &objectCacheRedis{ - rcClient: rcClient, - expireTime: time.Hour * 12, - objDB: objDB, - metaCache: NewMetaCacheRedis(rcClient), + BatchDeleter: batchHandler, + rcClient: rockscache.NewClient(rdb, opts), + expireTime: time.Hour * 12, + objDB: objDB, } } type objectCacheRedis struct { - metaCache - objDB relationtb.ObjectInfoModelInterface + cache.BatchDeleter + objDB database.ObjectInfo rcClient *rockscache.Client expireTime time.Duration } -func (g *objectCacheRedis) NewCache() ObjectCache { +func (g *objectCacheRedis) getObjectKey(engine string, name string) string { + return cachekey.GetObjectKey(engine, name) +} + +func (g *objectCacheRedis) CloneObjectCache() cache.ObjectCache { return &objectCacheRedis{ - rcClient: g.rcClient, - expireTime: g.expireTime, - objDB: g.objDB, - metaCache: NewMetaCacheRedis(g.rcClient, g.metaCache.GetPreDelKeys()...), + BatchDeleter: g.BatchDeleter.Clone(), + rcClient: g.rcClient, + expireTime: g.expireTime, + objDB: g.objDB, } } -func (g *objectCacheRedis) DelObjectName(engine string, names ...string) ObjectCache { - objectCache := g.NewCache() +func (g *objectCacheRedis) DelObjectName(engine string, names ...string) cache.ObjectCache { + objectCache := g.CloneObjectCache() keys := make([]string, 0, len(names)) for _, name := range names { keys = append(keys, g.getObjectKey(name, engine)) @@ -69,60 +69,40 @@ func (g *objectCacheRedis) DelObjectName(engine string, names ...string) ObjectC return objectCache } -func (g *objectCacheRedis) getObjectKey(engine string, name string) string { - return "OBJECT:" + engine + ":" + name -} - -func (g *objectCacheRedis) GetName(ctx context.Context, engine string, name string) (*relationtb.ObjectModel, error) { - return getCache(ctx, g.rcClient, g.getObjectKey(name, engine), g.expireTime, func(ctx context.Context) (*relationtb.ObjectModel, error) { +func (g *objectCacheRedis) GetName(ctx context.Context, engine string, name string) (*model.Object, error) { + return getCache(ctx, g.rcClient, g.getObjectKey(name, engine), g.expireTime, func(ctx context.Context) (*model.Object, error) { return g.objDB.Take(ctx, engine, name) }) } -type S3Cache interface { - metaCache - GetKey(ctx context.Context, engine string, key string) (*s3.ObjectInfo, error) - DelS3Key(engine string, keys ...string) S3Cache -} - func NewS3Cache(rdb redis.UniversalClient, s3 s3.Interface) cont.S3Cache { - rcClient := rockscache.NewClient(rdb, rockscache.NewDefaultOptions()) + opts := rockscache.NewDefaultOptions() + batchHandler := NewBatchDeleterRedis(rdb, &opts, nil) return &s3CacheRedis{ - rcClient: rcClient, - expireTime: time.Hour * 12, - s3: s3, - metaCache: NewMetaCacheRedis(rcClient), + BatchDeleter: batchHandler, + rcClient: rockscache.NewClient(rdb, opts), + expireTime: time.Hour * 12, + s3: s3, } } type s3CacheRedis struct { - metaCache + cache.BatchDeleter s3 s3.Interface rcClient *rockscache.Client expireTime time.Duration } -func (g *s3CacheRedis) newCache() *s3CacheRedis { - return &s3CacheRedis{ - rcClient: g.rcClient, - expireTime: g.expireTime, - s3: g.s3, - metaCache: NewMetaCacheRedis(g.rcClient, g.metaCache.GetPreDelKeys()...), - } +func (g *s3CacheRedis) getS3Key(engine string, name string) string { + return cachekey.GetS3Key(engine, name) } func (g *s3CacheRedis) DelS3Key(ctx context.Context, engine string, keys ...string) error { - s3cache := g.newCache() ks := make([]string, 0, len(keys)) for _, key := range keys { ks = append(ks, g.getS3Key(engine, key)) } - s3cache.AddKeys(ks...) - return s3cache.ExecDel(ctx) -} - -func (g *s3CacheRedis) getS3Key(engine string, name string) string { - return "S3:" + engine + ":" + name + return g.BatchDeleter.ExecDelWithKeys(ctx, ks) } func (g *s3CacheRedis) GetKey(ctx context.Context, engine string, name string) (*s3.ObjectInfo, error) { @@ -131,59 +111,41 @@ func (g *s3CacheRedis) GetKey(ctx context.Context, engine string, name string) ( }) } -type MinioCache interface { - metaCache - GetImageObjectKeyInfo(ctx context.Context, key string, fn func(ctx context.Context) (*MinioImageInfo, error)) (*MinioImageInfo, error) - GetThumbnailKey(ctx context.Context, key string, format string, width int, height int, minioCache func(ctx context.Context) (string, error)) (string, error) - DelObjectImageInfoKey(keys ...string) MinioCache - DelImageThumbnailKey(key string, format string, width int, height int) MinioCache -} - func NewMinioCache(rdb redis.UniversalClient) minio.Cache { - rcClient := rockscache.NewClient(rdb, rockscache.NewDefaultOptions()) + opts := rockscache.NewDefaultOptions() + batchHandler := NewBatchDeleterRedis(rdb, &opts, nil) return &minioCacheRedis{ - rcClient: rcClient, - expireTime: time.Hour * 24 * 7, - metaCache: NewMetaCacheRedis(rcClient), + BatchDeleter: batchHandler, + rcClient: rockscache.NewClient(rdb, opts), + expireTime: time.Hour * 24 * 7, } } type minioCacheRedis struct { - metaCache + cache.BatchDeleter rcClient *rockscache.Client expireTime time.Duration } -func (g *minioCacheRedis) newCache() *minioCacheRedis { - return &minioCacheRedis{ - rcClient: g.rcClient, - expireTime: g.expireTime, - metaCache: NewMetaCacheRedis(g.rcClient, g.metaCache.GetPreDelKeys()...), - } +func (g *minioCacheRedis) getObjectImageInfoKey(key string) string { + return cachekey.GetObjectImageInfoKey(key) +} + +func (g *minioCacheRedis) getMinioImageThumbnailKey(key string, format string, width int, height int) string { + return cachekey.GetMinioImageThumbnailKey(key, format, width, height) } func (g *minioCacheRedis) DelObjectImageInfoKey(ctx context.Context, keys ...string) error { - s3cache := g.newCache() ks := make([]string, 0, len(keys)) for _, key := range keys { ks = append(ks, g.getObjectImageInfoKey(key)) } - s3cache.AddKeys(ks...) - return s3cache.ExecDel(ctx) + return g.BatchDeleter.ExecDelWithKeys(ctx, ks) } func (g *minioCacheRedis) DelImageThumbnailKey(ctx context.Context, key string, format string, width int, height int) error { - s3cache := g.newCache() - s3cache.AddKeys(g.getMinioImageThumbnailKey(key, format, width, height)) - return s3cache.ExecDel(ctx) -} + return g.BatchDeleter.ExecDelWithKeys(ctx, []string{g.getMinioImageThumbnailKey(key, format, width, height)}) -func (g *minioCacheRedis) getObjectImageInfoKey(key string) string { - return "MINIO:IMAGE:" + key -} - -func (g *minioCacheRedis) getMinioImageThumbnailKey(key string, format string, width int, height int) string { - return "MINIO:THUMBNAIL:" + format + ":w" + strconv.Itoa(width) + ":h" + strconv.Itoa(height) + ":" + key } func (g *minioCacheRedis) GetImageObjectKeyInfo(ctx context.Context, key string, fn func(ctx context.Context) (*minio.ImageInfo, error)) (*minio.ImageInfo, error) { @@ -197,11 +159,3 @@ func (g *minioCacheRedis) GetImageObjectKeyInfo(ctx context.Context, key string, func (g *minioCacheRedis) GetThumbnailKey(ctx context.Context, key string, format string, width int, height int, minioCache func(ctx context.Context) (string, error)) (string, error) { return getCache(ctx, g.rcClient, g.getMinioImageThumbnailKey(key, format, width, height), g.expireTime, minioCache) } - -type MinioImageInfo struct { - IsImg bool `json:"isImg"` - Width int `json:"width"` - Height int `json:"height"` - Format string `json:"format"` - Etag string `json:"etag"` -} diff --git a/pkg/common/db/cache/seq.go b/pkg/common/storage/cache/redis/seq.go similarity index 73% rename from pkg/common/db/cache/seq.go rename to pkg/common/storage/cache/redis/seq.go index 6fbb091836..76dd921a50 100644 --- a/pkg/common/db/cache/seq.go +++ b/pkg/common/storage/cache/redis/seq.go @@ -1,38 +1,29 @@ -package cache +// 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 redis import ( "context" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/cache" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/cache/cachekey" "github.com/openimsdk/tools/errs" "github.com/openimsdk/tools/utils/stringutil" "github.com/redis/go-redis/v9" ) -type SeqCache interface { - SetMaxSeq(ctx context.Context, conversationID string, maxSeq int64) error - GetMaxSeqs(ctx context.Context, conversationIDs []string) (map[string]int64, error) - GetMaxSeq(ctx context.Context, conversationID string) (int64, error) - SetMinSeq(ctx context.Context, conversationID string, minSeq int64) error - SetMinSeqs(ctx context.Context, seqs map[string]int64) error - GetMinSeqs(ctx context.Context, conversationIDs []string) (map[string]int64, error) - GetMinSeq(ctx context.Context, conversationID string) (int64, error) - GetConversationUserMinSeq(ctx context.Context, conversationID string, userID string) (int64, error) - GetConversationUserMinSeqs(ctx context.Context, conversationID string, userIDs []string) (map[string]int64, error) - SetConversationUserMinSeq(ctx context.Context, conversationID string, userID string, minSeq int64) error - // seqs map: key userID value minSeq - SetConversationUserMinSeqs(ctx context.Context, conversationID string, seqs map[string]int64) (err error) - // seqs map: key conversationID value minSeq - SetUserConversationsMinSeqs(ctx context.Context, userID string, seqs map[string]int64) error - // has read seq - SetHasReadSeq(ctx context.Context, userID string, conversationID string, hasReadSeq int64) error - // k: user, v: seq - SetHasReadSeqs(ctx context.Context, conversationID string, hasReadSeqs map[string]int64) error - // k: conversation, v :seq - UserSetHasReadSeqs(ctx context.Context, userID string, hasReadSeqs map[string]int64) error - GetHasReadSeqs(ctx context.Context, userID string, conversationIDs []string) (map[string]int64, error) - GetHasReadSeq(ctx context.Context, userID string, conversationID string) (int64, error) -} - -func NewSeqCache(rdb redis.UniversalClient) SeqCache { +func NewSeqCache(rdb redis.UniversalClient) cache.SeqCache { return &seqCache{rdb: rdb} } @@ -41,19 +32,19 @@ type seqCache struct { } func (c *seqCache) getMaxSeqKey(conversationID string) string { - return maxSeq + conversationID + return cachekey.GetMaxSeqKey(conversationID) } func (c *seqCache) getMinSeqKey(conversationID string) string { - return minSeq + conversationID + return cachekey.GetMinSeqKey(conversationID) } func (c *seqCache) getHasReadSeqKey(conversationID string, userID string) string { - return hasReadSeq + userID + ":" + conversationID + return cachekey.GetHasReadSeqKey(conversationID, userID) } func (c *seqCache) getConversationUserMinSeqKey(conversationID, userID string) string { - return conversationUserMinSeq + conversationID + "u:" + userID + return cachekey.GetConversationUserMinSeqKey(conversationID, userID) } func (c *seqCache) setSeq(ctx context.Context, conversationID string, seq int64, getkey func(conversationID string) string) error { diff --git a/pkg/common/storage/cache/redis/third.go b/pkg/common/storage/cache/redis/third.go new file mode 100644 index 0000000000..3288cecb8f --- /dev/null +++ b/pkg/common/storage/cache/redis/third.go @@ -0,0 +1,103 @@ +// 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 redis + +import ( + "context" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/cache" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/cache/cachekey" + "github.com/openimsdk/tools/errs" + "github.com/redis/go-redis/v9" + "time" +) + +func NewThirdCache(rdb redis.UniversalClient) cache.ThirdCache { + return &thirdCache{rdb: rdb} +} + +type thirdCache struct { + rdb redis.UniversalClient +} + +func (c *thirdCache) getGetuiTokenKey() string { + return cachekey.GetGetuiTokenKey() +} + +func (c *thirdCache) getGetuiTaskIDKey() string { + return cachekey.GetGetuiTaskIDKey() +} + +func (c *thirdCache) getUserBadgeUnreadCountSumKey(userID string) string { + return cachekey.GetUserBadgeUnreadCountSumKey(userID) +} + +func (c *thirdCache) getFcmAccountTokenKey(account string, platformID int) string { + return cachekey.GetFcmAccountTokenKey(account, platformID) +} + +func (c *thirdCache) SetFcmToken(ctx context.Context, account string, platformID int, fcmToken string, expireTime int64) (err error) { + return errs.Wrap(c.rdb.Set(ctx, c.getFcmAccountTokenKey(account, platformID), fcmToken, time.Duration(expireTime)*time.Second).Err()) +} + +func (c *thirdCache) GetFcmToken(ctx context.Context, account string, platformID int) (string, error) { + val, err := c.rdb.Get(ctx, c.getFcmAccountTokenKey(account, platformID)).Result() + if err != nil { + return "", errs.Wrap(err) + } + return val, nil +} + +func (c *thirdCache) DelFcmToken(ctx context.Context, account string, platformID int) error { + return errs.Wrap(c.rdb.Del(ctx, c.getFcmAccountTokenKey(account, platformID)).Err()) +} + +func (c *thirdCache) IncrUserBadgeUnreadCountSum(ctx context.Context, userID string) (int, error) { + seq, err := c.rdb.Incr(ctx, c.getUserBadgeUnreadCountSumKey(userID)).Result() + + return int(seq), errs.Wrap(err) +} + +func (c *thirdCache) SetUserBadgeUnreadCountSum(ctx context.Context, userID string, value int) error { + return errs.Wrap(c.rdb.Set(ctx, c.getUserBadgeUnreadCountSumKey(userID), value, 0).Err()) +} + +func (c *thirdCache) GetUserBadgeUnreadCountSum(ctx context.Context, userID string) (int, error) { + val, err := c.rdb.Get(ctx, c.getUserBadgeUnreadCountSumKey(userID)).Int() + return val, errs.Wrap(err) +} + +func (c *thirdCache) SetGetuiToken(ctx context.Context, token string, expireTime int64) error { + return errs.Wrap(c.rdb.Set(ctx, c.getGetuiTokenKey(), token, time.Duration(expireTime)*time.Second).Err()) +} + +func (c *thirdCache) GetGetuiToken(ctx context.Context) (string, error) { + val, err := c.rdb.Get(ctx, c.getGetuiTokenKey()).Result() + if err != nil { + return "", errs.Wrap(err) + } + return val, nil +} + +func (c *thirdCache) SetGetuiTaskID(ctx context.Context, taskID string, expireTime int64) error { + return errs.Wrap(c.rdb.Set(ctx, c.getGetuiTaskIDKey(), taskID, time.Duration(expireTime)*time.Second).Err()) +} + +func (c *thirdCache) GetGetuiTaskID(ctx context.Context) (string, error) { + val, err := c.rdb.Get(ctx, c.getGetuiTaskIDKey()).Result() + if err != nil { + return "", errs.Wrap(err) + } + return val, nil +} diff --git a/pkg/common/db/cache/token.go b/pkg/common/storage/cache/redis/token.go similarity index 60% rename from pkg/common/db/cache/token.go rename to pkg/common/storage/cache/redis/token.go index 88580e932f..6098a666cf 100644 --- a/pkg/common/db/cache/token.go +++ b/pkg/common/storage/cache/redis/token.go @@ -1,31 +1,38 @@ -package cache +// 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 redis import ( "context" - - "github.com/openimsdk/open-im-server/v3/pkg/common/cachekey" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/cache" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/cache/cachekey" "github.com/openimsdk/tools/errs" "github.com/openimsdk/tools/utils/stringutil" "github.com/redis/go-redis/v9" ) -func NewTokenCacheModel(rdb redis.UniversalClient) TokenModel { +type tokenCache struct { + rdb redis.UniversalClient +} + +func NewTokenCacheModel(rdb redis.UniversalClient) cache.TokenModel { return &tokenCache{ rdb: rdb, } } -type TokenModel interface { - AddTokenFlag(ctx context.Context, userID string, platformID int, token string, flag int) error - GetTokensWithoutError(ctx context.Context, userID string, platformID int) (map[string]int, error) - SetTokenMapByUidPid(ctx context.Context, userID string, platformID int, m map[string]int) error - DeleteTokenByUidPid(ctx context.Context, userID string, platformID int, fields []string) error -} - -type tokenCache struct { - rdb redis.UniversalClient -} - func (c *tokenCache) AddTokenFlag(ctx context.Context, userID string, platformID int, token string, flag int) error { return errs.Wrap(c.rdb.HSet(ctx, cachekey.GetTokenKey(userID, platformID), token, flag).Err()) } diff --git a/pkg/common/db/cache/user.go b/pkg/common/storage/cache/redis/user.go similarity index 78% rename from pkg/common/db/cache/user.go rename to pkg/common/storage/cache/redis/user.go index c10e9611a4..3de01563bf 100644 --- a/pkg/common/db/cache/user.go +++ b/pkg/common/storage/cache/redis/user.go @@ -12,78 +12,66 @@ // See the License for the specific language governing permissions and // limitations under the License. -package cache +package redis import ( "context" "encoding/json" "errors" - "hash/crc32" - "strconv" - "time" - "github.com/dtm-labs/rockscache" - "github.com/openimsdk/open-im-server/v3/pkg/common/cachekey" "github.com/openimsdk/open-im-server/v3/pkg/common/config" - relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/cache" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/cache/cachekey" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/database" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model" "github.com/openimsdk/protocol/constant" "github.com/openimsdk/protocol/user" "github.com/openimsdk/tools/errs" "github.com/openimsdk/tools/log" "github.com/redis/go-redis/v9" + "hash/crc32" + "strconv" + "time" ) const ( userExpireTime = time.Second * 60 * 60 * 12 - olineStatusKey = "ONLINE_STATUS:" userOlineStatusExpireTime = time.Second * 60 * 60 * 24 statusMod = 501 ) -type UserCache interface { - metaCache - NewCache() UserCache - GetUserInfo(ctx context.Context, userID string) (userInfo *relationtb.UserModel, err error) - GetUsersInfo(ctx context.Context, userIDs []string) ([]*relationtb.UserModel, error) - DelUsersInfo(userIDs ...string) UserCache - GetUserGlobalRecvMsgOpt(ctx context.Context, userID string) (opt int, err error) - DelUsersGlobalRecvMsgOpt(userIDs ...string) UserCache - GetUserStatus(ctx context.Context, userIDs []string) ([]*user.OnlineStatus, error) - SetUserStatus(ctx context.Context, userID string, status, platformID int32) error -} - type UserCacheRedis struct { - metaCache - rdb redis.UniversalClient - // userDB relationtb.UserModelInterface - userDB relationtb.UserModelInterface + cache.BatchDeleter + rdb redis.UniversalClient + userDB database.User expireTime time.Duration rcClient *rockscache.Client } -func NewUserCacheRedis(rdb redis.UniversalClient, localCache *config.LocalCache, userDB relationtb.UserModelInterface, options rockscache.Options) UserCache { - rcClient := rockscache.NewClient(rdb, options) - mc := NewMetaCacheRedis(rcClient) +func NewUserCacheRedis(rdb redis.UniversalClient, localCache *config.LocalCache, userDB database.User, options *rockscache.Options) cache.UserCache { + batchHandler := NewBatchDeleterRedis(rdb, options, []string{localCache.User.Topic}) u := localCache.User log.ZDebug(context.Background(), "user local cache init", "Topic", u.Topic, "SlotNum", u.SlotNum, "SlotSize", u.SlotSize, "enable", u.Enable()) - mc.SetTopic(u.Topic) - mc.SetRawRedisClient(rdb) return &UserCacheRedis{ - rdb: rdb, - metaCache: NewMetaCacheRedis(rcClient), - userDB: userDB, - expireTime: userExpireTime, - rcClient: rcClient, + BatchDeleter: batchHandler, + rdb: rdb, + userDB: userDB, + expireTime: userExpireTime, + rcClient: rockscache.NewClient(rdb, *options), } } -func (u *UserCacheRedis) NewCache() UserCache { +func (u *UserCacheRedis) getOnlineStatusKey(modKey string) string { + return cachekey.GetOnlineStatusKey(modKey) +} + +func (u *UserCacheRedis) CloneUserCache() cache.UserCache { return &UserCacheRedis{ - rdb: u.rdb, - metaCache: u.Copy(), - userDB: u.userDB, - expireTime: u.expireTime, - rcClient: u.rcClient, + BatchDeleter: u.BatchDeleter.Clone(), + rdb: u.rdb, + userDB: u.userDB, + expireTime: u.expireTime, + rcClient: u.rcClient, } } @@ -95,26 +83,26 @@ func (u *UserCacheRedis) getUserGlobalRecvMsgOptKey(userID string) string { return cachekey.GetUserGlobalRecvMsgOptKey(userID) } -func (u *UserCacheRedis) GetUserInfo(ctx context.Context, userID string) (userInfo *relationtb.UserModel, err error) { - return getCache(ctx, u.rcClient, u.getUserInfoKey(userID), u.expireTime, func(ctx context.Context) (*relationtb.UserModel, error) { +func (u *UserCacheRedis) GetUserInfo(ctx context.Context, userID string) (userInfo *model.User, err error) { + return getCache(ctx, u.rcClient, u.getUserInfoKey(userID), u.expireTime, func(ctx context.Context) (*model.User, error) { return u.userDB.Take(ctx, userID) }) } -func (u *UserCacheRedis) GetUsersInfo(ctx context.Context, userIDs []string) ([]*relationtb.UserModel, error) { - return batchGetCache2(ctx, u.rcClient, u.expireTime, userIDs, func(userID string) string { +func (u *UserCacheRedis) GetUsersInfo(ctx context.Context, userIDs []string) ([]*model.User, error) { + return batchGetCache(ctx, u.rcClient, u.expireTime, userIDs, func(userID string) string { return u.getUserInfoKey(userID) - }, func(ctx context.Context, userID string) (*relationtb.UserModel, error) { + }, func(ctx context.Context, userID string) (*model.User, error) { return u.userDB.Take(ctx, userID) }) } -func (u *UserCacheRedis) DelUsersInfo(userIDs ...string) UserCache { +func (u *UserCacheRedis) DelUsersInfo(userIDs ...string) cache.UserCache { keys := make([]string, 0, len(userIDs)) for _, userID := range userIDs { keys = append(keys, u.getUserInfoKey(userID)) } - cache := u.NewCache() + cache := u.CloneUserCache() cache.AddKeys(keys...) return cache @@ -132,12 +120,12 @@ func (u *UserCacheRedis) GetUserGlobalRecvMsgOpt(ctx context.Context, userID str ) } -func (u *UserCacheRedis) DelUsersGlobalRecvMsgOpt(userIDs ...string) UserCache { +func (u *UserCacheRedis) DelUsersGlobalRecvMsgOpt(userIDs ...string) cache.UserCache { keys := make([]string, 0, len(userIDs)) for _, userID := range userIDs { keys = append(keys, u.getUserGlobalRecvMsgOptKey(userID)) } - cache := u.NewCache() + cache := u.CloneUserCache() cache.AddKeys(keys...) return cache @@ -150,7 +138,7 @@ func (u *UserCacheRedis) GetUserStatus(ctx context.Context, userIDs []string) ([ UserIDNum := crc32.ChecksumIEEE([]byte(userID)) modKey := strconv.Itoa(int(UserIDNum % statusMod)) var onlineStatus user.OnlineStatus - key := olineStatusKey + modKey + key := u.getOnlineStatusKey(modKey) result, err := u.rdb.HGet(ctx, key, userID).Result() if err != nil { if errors.Is(err, redis.Nil) { @@ -182,7 +170,7 @@ func (u *UserCacheRedis) GetUserStatus(ctx context.Context, userIDs []string) ([ func (u *UserCacheRedis) SetUserStatus(ctx context.Context, userID string, status, platformID int32) error { UserIDNum := crc32.ChecksumIEEE([]byte(userID)) modKey := strconv.Itoa(int(UserIDNum % statusMod)) - key := olineStatusKey + modKey + key := u.getOnlineStatusKey(modKey) log.ZDebug(ctx, "SetUserStatus args", "userID", userID, "status", status, "platformID", platformID, "modKey", modKey, "key", key) isNewKey, err := u.rdb.Exists(ctx, key).Result() if err != nil { diff --git a/pkg/common/storage/cache/s3.go b/pkg/common/storage/cache/s3.go new file mode 100644 index 0000000000..4d899586cc --- /dev/null +++ b/pkg/common/storage/cache/s3.go @@ -0,0 +1,51 @@ +// 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 cache + +import ( + "context" + relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model" + "github.com/openimsdk/tools/s3" +) + +type ObjectCache interface { + BatchDeleter + CloneObjectCache() ObjectCache + GetName(ctx context.Context, engine string, name string) (*relationtb.Object, error) + DelObjectName(engine string, names ...string) ObjectCache +} + +type S3Cache interface { + BatchDeleter + GetKey(ctx context.Context, engine string, key string) (*s3.ObjectInfo, error) + DelS3Key(engine string, keys ...string) S3Cache +} + +// TODO integrating minio.Cache and MinioCache interfaces. +type MinioCache interface { + BatchDeleter + GetImageObjectKeyInfo(ctx context.Context, key string, fn func(ctx context.Context) (*MinioImageInfo, error)) (*MinioImageInfo, error) + GetThumbnailKey(ctx context.Context, key string, format string, width int, height int, minioCache func(ctx context.Context) (string, error)) (string, error) + DelObjectImageInfoKey(keys ...string) MinioCache + DelImageThumbnailKey(key string, format string, width int, height int) MinioCache +} + +type MinioImageInfo struct { + IsImg bool `json:"isImg"` + Width int `json:"width"` + Height int `json:"height"` + Format string `json:"format"` + Etag string `json:"etag"` +} diff --git a/pkg/common/storage/cache/seq.go b/pkg/common/storage/cache/seq.go new file mode 100644 index 0000000000..091b318c89 --- /dev/null +++ b/pkg/common/storage/cache/seq.go @@ -0,0 +1,30 @@ +package cache + +import ( + "context" +) + +type SeqCache interface { + SetMaxSeq(ctx context.Context, conversationID string, maxSeq int64) error + GetMaxSeqs(ctx context.Context, conversationIDs []string) (map[string]int64, error) + GetMaxSeq(ctx context.Context, conversationID string) (int64, error) + SetMinSeq(ctx context.Context, conversationID string, minSeq int64) error + SetMinSeqs(ctx context.Context, seqs map[string]int64) error + GetMinSeqs(ctx context.Context, conversationIDs []string) (map[string]int64, error) + GetMinSeq(ctx context.Context, conversationID string) (int64, error) + GetConversationUserMinSeq(ctx context.Context, conversationID string, userID string) (int64, error) + GetConversationUserMinSeqs(ctx context.Context, conversationID string, userIDs []string) (map[string]int64, error) + SetConversationUserMinSeq(ctx context.Context, conversationID string, userID string, minSeq int64) error + // seqs map: key userID value minSeq + SetConversationUserMinSeqs(ctx context.Context, conversationID string, seqs map[string]int64) (err error) + // seqs map: key conversationID value minSeq + SetUserConversationsMinSeqs(ctx context.Context, userID string, seqs map[string]int64) error + // has read seq + SetHasReadSeq(ctx context.Context, userID string, conversationID string, hasReadSeq int64) error + // k: user, v: seq + SetHasReadSeqs(ctx context.Context, conversationID string, hasReadSeqs map[string]int64) error + // k: conversation, v :seq + UserSetHasReadSeqs(ctx context.Context, userID string, hasReadSeqs map[string]int64) error + GetHasReadSeqs(ctx context.Context, userID string, conversationIDs []string) (map[string]int64, error) + GetHasReadSeq(ctx context.Context, userID string, conversationID string) (int64, error) +} diff --git a/pkg/common/storage/cache/third.go b/pkg/common/storage/cache/third.go new file mode 100644 index 0000000000..ba6d04061a --- /dev/null +++ b/pkg/common/storage/cache/third.go @@ -0,0 +1,18 @@ +package cache + +import ( + "context" +) + +type ThirdCache interface { + SetFcmToken(ctx context.Context, account string, platformID int, fcmToken string, expireTime int64) (err error) + GetFcmToken(ctx context.Context, account string, platformID int) (string, error) + DelFcmToken(ctx context.Context, account string, platformID int) error + IncrUserBadgeUnreadCountSum(ctx context.Context, userID string) (int, error) + SetUserBadgeUnreadCountSum(ctx context.Context, userID string, value int) error + GetUserBadgeUnreadCountSum(ctx context.Context, userID string) (int, error) + SetGetuiToken(ctx context.Context, token string, expireTime int64) error + GetGetuiToken(ctx context.Context) (string, error) + SetGetuiTaskID(ctx context.Context, taskID string, expireTime int64) error + GetGetuiTaskID(ctx context.Context) (string, error) +} diff --git a/pkg/common/storage/cache/token.go b/pkg/common/storage/cache/token.go new file mode 100644 index 0000000000..55b3321ef6 --- /dev/null +++ b/pkg/common/storage/cache/token.go @@ -0,0 +1,12 @@ +package cache + +import ( + "context" +) + +type TokenModel interface { + AddTokenFlag(ctx context.Context, userID string, platformID int, token string, flag int) error + GetTokensWithoutError(ctx context.Context, userID string, platformID int) (map[string]int, error) + SetTokenMapByUidPid(ctx context.Context, userID string, platformID int, m map[string]int) error + DeleteTokenByUidPid(ctx context.Context, userID string, platformID int, fields []string) error +} diff --git a/pkg/common/storage/cache/user.go b/pkg/common/storage/cache/user.go new file mode 100644 index 0000000000..4a129ddd18 --- /dev/null +++ b/pkg/common/storage/cache/user.go @@ -0,0 +1,33 @@ +// 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 cache + +import ( + "context" + relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model" + "github.com/openimsdk/protocol/user" +) + +type UserCache interface { + BatchDeleter + CloneUserCache() UserCache + GetUserInfo(ctx context.Context, userID string) (userInfo *relationtb.User, err error) + GetUsersInfo(ctx context.Context, userIDs []string) ([]*relationtb.User, error) + DelUsersInfo(userIDs ...string) UserCache + GetUserGlobalRecvMsgOpt(ctx context.Context, userID string) (opt int, err error) + DelUsersGlobalRecvMsgOpt(userIDs ...string) UserCache + GetUserStatus(ctx context.Context, userIDs []string) ([]*user.OnlineStatus, error) + SetUserStatus(ctx context.Context, userID string, status, platformID int32) error +} diff --git a/pkg/common/storage/common/types.go b/pkg/common/storage/common/types.go new file mode 100644 index 0000000000..7591211588 --- /dev/null +++ b/pkg/common/storage/common/types.go @@ -0,0 +1,26 @@ +// 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 common + +type BatchUpdateGroupMember struct { + GroupID string + UserID string + Map map[string]any +} + +type GroupSimpleUserID struct { + Hash uint64 + MemberNum uint32 +} diff --git a/pkg/common/db/controller/auth.go b/pkg/common/storage/controller/auth.go similarity index 97% rename from pkg/common/db/controller/auth.go rename to pkg/common/storage/controller/auth.go index 8190e5017a..321583743a 100644 --- a/pkg/common/db/controller/auth.go +++ b/pkg/common/storage/controller/auth.go @@ -19,7 +19,7 @@ import ( "github.com/golang-jwt/jwt/v4" "github.com/openimsdk/open-im-server/v3/pkg/authverify" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/cache" "github.com/openimsdk/protocol/constant" "github.com/openimsdk/tools/errs" "github.com/openimsdk/tools/tokenverify" diff --git a/pkg/common/db/controller/black.go b/pkg/common/storage/controller/black.go similarity index 75% rename from pkg/common/db/controller/black.go rename to pkg/common/storage/controller/black.go index 5991a9dfe5..8a12f2aa2d 100644 --- a/pkg/common/db/controller/black.go +++ b/pkg/common/storage/controller/black.go @@ -16,9 +16,9 @@ package controller import ( "context" - - "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/cache" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/database" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model" "github.com/openimsdk/tools/db/pagination" "github.com/openimsdk/tools/log" "github.com/openimsdk/tools/utils/datautil" @@ -26,27 +26,27 @@ import ( type BlackDatabase interface { // Create add BlackList - Create(ctx context.Context, blacks []*relation.BlackModel) (err error) + Create(ctx context.Context, blacks []*model.Black) (err error) // Delete delete BlackList - Delete(ctx context.Context, blacks []*relation.BlackModel) (err error) + Delete(ctx context.Context, blacks []*model.Black) (err error) // FindOwnerBlacks get BlackList list - FindOwnerBlacks(ctx context.Context, ownerUserID string, pagination pagination.Pagination) (total int64, blacks []*relation.BlackModel, err error) - FindBlackInfos(ctx context.Context, ownerUserID string, userIDs []string) (blacks []*relation.BlackModel, err error) + FindOwnerBlacks(ctx context.Context, ownerUserID string, pagination pagination.Pagination) (total int64, blacks []*model.Black, err error) + FindBlackInfos(ctx context.Context, ownerUserID string, userIDs []string) (blacks []*model.Black, err error) // CheckIn Check whether user2 is in the black list of user1 (inUser1Blacks==true) Check whether user1 is in the black list of user2 (inUser2Blacks==true) CheckIn(ctx context.Context, userID1, userID2 string) (inUser1Blacks bool, inUser2Blacks bool, err error) } type blackDatabase struct { - black relation.BlackModelInterface + black database.Black cache cache.BlackCache } -func NewBlackDatabase(black relation.BlackModelInterface, cache cache.BlackCache) BlackDatabase { +func NewBlackDatabase(black database.Black, cache cache.BlackCache) BlackDatabase { return &blackDatabase{black, cache} } // Create Add Blacklist. -func (b *blackDatabase) Create(ctx context.Context, blacks []*relation.BlackModel) (err error) { +func (b *blackDatabase) Create(ctx context.Context, blacks []*model.Black) (err error) { if err := b.black.Create(ctx, blacks); err != nil { return err } @@ -54,7 +54,7 @@ func (b *blackDatabase) Create(ctx context.Context, blacks []*relation.BlackMode } // Delete Delete Blacklist. -func (b *blackDatabase) Delete(ctx context.Context, blacks []*relation.BlackModel) (err error) { +func (b *blackDatabase) Delete(ctx context.Context, blacks []*model.Black) (err error) { if err := b.black.Delete(ctx, blacks); err != nil { return err } @@ -62,16 +62,16 @@ func (b *blackDatabase) Delete(ctx context.Context, blacks []*relation.BlackMode } // FindOwnerBlacks Get Blacklist List. -func (b *blackDatabase) deleteBlackIDsCache(ctx context.Context, blacks []*relation.BlackModel) (err error) { - cache := b.cache.NewCache() +func (b *blackDatabase) deleteBlackIDsCache(ctx context.Context, blacks []*model.Black) (err error) { + cache := b.cache.CloneBlackCache() for _, black := range blacks { cache = cache.DelBlackIDs(ctx, black.OwnerUserID) } - return cache.ExecDel(ctx) + return cache.ChainExecDel(ctx) } // FindOwnerBlacks Get Blacklist List. -func (b *blackDatabase) FindOwnerBlacks(ctx context.Context, ownerUserID string, pagination pagination.Pagination) (total int64, blacks []*relation.BlackModel, err error) { +func (b *blackDatabase) FindOwnerBlacks(ctx context.Context, ownerUserID string, pagination pagination.Pagination) (total int64, blacks []*model.Black, err error) { return b.black.FindOwnerBlacks(ctx, ownerUserID, pagination) } @@ -95,6 +95,6 @@ func (b *blackDatabase) FindBlackIDs(ctx context.Context, ownerUserID string) (b } // FindBlackInfos Get Blacklist List. -func (b *blackDatabase) FindBlackInfos(ctx context.Context, ownerUserID string, userIDs []string) (blacks []*relation.BlackModel, err error) { +func (b *blackDatabase) FindBlackInfos(ctx context.Context, ownerUserID string, userIDs []string) (blacks []*model.Black, err error) { return b.black.FindOwnerBlackInfos(ctx, ownerUserID, userIDs) } diff --git a/pkg/common/db/controller/conversation.go b/pkg/common/storage/controller/conversation.go similarity index 86% rename from pkg/common/db/controller/conversation.go rename to pkg/common/storage/controller/conversation.go index 567bcb2704..18ef3f8bad 100644 --- a/pkg/common/db/controller/conversation.go +++ b/pkg/common/storage/controller/conversation.go @@ -16,10 +16,11 @@ package controller import ( "context" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/database" + relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model" "time" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" - relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/cache" "github.com/openimsdk/open-im-server/v3/pkg/msgprocessor" "github.com/openimsdk/protocol/constant" "github.com/openimsdk/tools/db/pagination" @@ -33,18 +34,18 @@ type ConversationDatabase interface { // UpdateUsersConversationField updates the properties of a conversation for specified users. UpdateUsersConversationField(ctx context.Context, userIDs []string, conversationID string, args map[string]any) error // CreateConversation creates a batch of new conversations. - CreateConversation(ctx context.Context, conversations []*relationtb.ConversationModel) error + CreateConversation(ctx context.Context, conversations []*relationtb.Conversation) error // SyncPeerUserPrivateConversationTx ensures transactional operation while syncing private conversations between peers. - SyncPeerUserPrivateConversationTx(ctx context.Context, conversation []*relationtb.ConversationModel) error + SyncPeerUserPrivateConversationTx(ctx context.Context, conversation []*relationtb.Conversation) error // FindConversations retrieves multiple conversations of a user by conversation IDs. - FindConversations(ctx context.Context, ownerUserID string, conversationIDs []string) ([]*relationtb.ConversationModel, error) + FindConversations(ctx context.Context, ownerUserID string, conversationIDs []string) ([]*relationtb.Conversation, error) // GetUserAllConversation fetches all conversations of a user on the server. - GetUserAllConversation(ctx context.Context, ownerUserID string) ([]*relationtb.ConversationModel, error) + GetUserAllConversation(ctx context.Context, ownerUserID string) ([]*relationtb.Conversation, error) // SetUserConversations sets multiple conversation properties for a user, creates new conversations if they do not exist, or updates them otherwise. This operation is atomic. - SetUserConversations(ctx context.Context, ownerUserID string, conversations []*relationtb.ConversationModel) error + SetUserConversations(ctx context.Context, ownerUserID string, conversations []*relationtb.Conversation) error // SetUsersConversationFieldTx updates a specific field for multiple users' conversations, creating new conversations if they do not exist, or updates them otherwise. This operation is // transactional. - SetUsersConversationFieldTx(ctx context.Context, userIDs []string, conversation *relationtb.ConversationModel, fieldMap map[string]any) error + SetUsersConversationFieldTx(ctx context.Context, userIDs []string, conversation *relationtb.Conversation, fieldMap map[string]any) error // CreateGroupChatConversation creates a group chat conversation for the specified group ID and user IDs. CreateGroupChatConversation(ctx context.Context, groupID string, userIDs []string) error // GetConversationIDs retrieves conversation IDs for a given user. @@ -58,16 +59,16 @@ type ConversationDatabase interface { // PageConversationIDs paginates through conversation IDs based on the specified pagination settings. PageConversationIDs(ctx context.Context, pagination pagination.Pagination) (conversationIDs []string, err error) // GetConversationsByConversationID retrieves conversations by their IDs. - GetConversationsByConversationID(ctx context.Context, conversationIDs []string) ([]*relationtb.ConversationModel, error) + GetConversationsByConversationID(ctx context.Context, conversationIDs []string) ([]*relationtb.Conversation, error) // GetConversationIDsNeedDestruct fetches conversations that need to be destructed based on specific criteria. - GetConversationIDsNeedDestruct(ctx context.Context) ([]*relationtb.ConversationModel, error) + GetConversationIDsNeedDestruct(ctx context.Context) ([]*relationtb.Conversation, error) // GetConversationNotReceiveMessageUserIDs gets user IDs for users in a conversation who have not received messages. GetConversationNotReceiveMessageUserIDs(ctx context.Context, conversationID string) ([]string, error) // GetUserAllHasReadSeqs(ctx context.Context, ownerUserID string) (map[string]int64, error) // FindRecvMsgNotNotifyUserIDs(ctx context.Context, groupID string) ([]string, error) } -func NewConversationDatabase(conversation relationtb.ConversationModelInterface, cache cache.ConversationCache, tx tx.Tx) ConversationDatabase { +func NewConversationDatabase(conversation database.Conversation, cache cache.ConversationCache, tx tx.Tx) ConversationDatabase { return &conversationDatabase{ conversationDB: conversation, cache: cache, @@ -76,14 +77,14 @@ func NewConversationDatabase(conversation relationtb.ConversationModelInterface, } type conversationDatabase struct { - conversationDB relationtb.ConversationModelInterface + conversationDB database.Conversation cache cache.ConversationCache tx tx.Tx } -func (c *conversationDatabase) SetUsersConversationFieldTx(ctx context.Context, userIDs []string, conversation *relationtb.ConversationModel, fieldMap map[string]any) (err error) { +func (c *conversationDatabase) SetUsersConversationFieldTx(ctx context.Context, userIDs []string, conversation *relationtb.Conversation, fieldMap map[string]any) (err error) { return c.tx.Transaction(ctx, func(ctx context.Context) error { - cache := c.cache.NewCache() + cache := c.cache.CloneConversationCache() if conversation.GroupID != "" { cache = cache.DelSuperGroupRecvMsgNotNotifyUserIDs(conversation.GroupID).DelSuperGroupRecvMsgNotNotifyUserIDsHash(conversation.GroupID) } @@ -108,10 +109,10 @@ func (c *conversationDatabase) SetUsersConversationFieldTx(ctx context.Context, } NotUserIDs := stringutil.DifferenceString(haveUserIDs, userIDs) log.ZDebug(ctx, "SetUsersConversationFieldTx", "NotUserIDs", NotUserIDs, "haveUserIDs", haveUserIDs, "userIDs", userIDs) - var conversations []*relationtb.ConversationModel + var conversations []*relationtb.Conversation now := time.Now() for _, v := range NotUserIDs { - temp := new(relationtb.ConversationModel) + temp := new(relationtb.Conversation) if err = datautil.CopyStructFields(temp, conversation); err != nil { return err } @@ -126,7 +127,7 @@ func (c *conversationDatabase) SetUsersConversationFieldTx(ctx context.Context, } cache = cache.DelConversationIDs(NotUserIDs...).DelUserConversationIDsHash(NotUserIDs...).DelConversations(conversation.ConversationID, NotUserIDs...) } - return cache.ExecDel(ctx) + return cache.ChainExecDel(ctx) }) } @@ -135,31 +136,31 @@ func (c *conversationDatabase) UpdateUsersConversationField(ctx context.Context, if err != nil { return err } - cache := c.cache.NewCache() + cache := c.cache.CloneConversationCache() cache = cache.DelUsersConversation(conversationID, userIDs...) if _, ok := args["recv_msg_opt"]; ok { cache = cache.DelConversationNotReceiveMessageUserIDs(conversationID) } - return cache.ExecDel(ctx) + return cache.ChainExecDel(ctx) } -func (c *conversationDatabase) CreateConversation(ctx context.Context, conversations []*relationtb.ConversationModel) error { +func (c *conversationDatabase) CreateConversation(ctx context.Context, conversations []*relationtb.Conversation) error { if err := c.conversationDB.Create(ctx, conversations); err != nil { return err } var userIDs []string - cache := c.cache.NewCache() + cache := c.cache.CloneConversationCache() for _, conversation := range conversations { cache = cache.DelConversations(conversation.OwnerUserID, conversation.ConversationID) cache = cache.DelConversationNotReceiveMessageUserIDs(conversation.ConversationID) userIDs = append(userIDs, conversation.OwnerUserID) } - return cache.DelConversationIDs(userIDs...).DelUserConversationIDsHash(userIDs...).ExecDel(ctx) + return cache.DelConversationIDs(userIDs...).DelUserConversationIDsHash(userIDs...).ChainExecDel(ctx) } -func (c *conversationDatabase) SyncPeerUserPrivateConversationTx(ctx context.Context, conversations []*relationtb.ConversationModel) error { +func (c *conversationDatabase) SyncPeerUserPrivateConversationTx(ctx context.Context, conversations []*relationtb.Conversation) error { return c.tx.Transaction(ctx, func(ctx context.Context) error { - cache := c.cache.NewCache() + cache := c.cache.CloneConversationCache() for _, conversation := range conversations { for _, v := range [][2]string{{conversation.OwnerUserID, conversation.UserID}, {conversation.UserID, conversation.OwnerUserID}} { ownerUserID := v[0] @@ -180,33 +181,33 @@ func (c *conversationDatabase) SyncPeerUserPrivateConversationTx(ctx context.Con newConversation.UserID = userID newConversation.ConversationID = conversation.ConversationID newConversation.IsPrivateChat = conversation.IsPrivateChat - if err := c.conversationDB.Create(ctx, []*relationtb.ConversationModel{&newConversation}); err != nil { + if err := c.conversationDB.Create(ctx, []*relationtb.Conversation{&newConversation}); err != nil { return err } cache = cache.DelConversationIDs(ownerUserID).DelUserConversationIDsHash(ownerUserID) } } } - return cache.ExecDel(ctx) + return cache.ChainExecDel(ctx) }) } -func (c *conversationDatabase) FindConversations(ctx context.Context, ownerUserID string, conversationIDs []string) ([]*relationtb.ConversationModel, error) { +func (c *conversationDatabase) FindConversations(ctx context.Context, ownerUserID string, conversationIDs []string) ([]*relationtb.Conversation, error) { return c.cache.GetConversations(ctx, ownerUserID, conversationIDs) } -func (c *conversationDatabase) GetConversation(ctx context.Context, ownerUserID string, conversationID string) (*relationtb.ConversationModel, error) { +func (c *conversationDatabase) GetConversation(ctx context.Context, ownerUserID string, conversationID string) (*relationtb.Conversation, error) { return c.cache.GetConversation(ctx, ownerUserID, conversationID) } -func (c *conversationDatabase) GetUserAllConversation(ctx context.Context, ownerUserID string) ([]*relationtb.ConversationModel, error) { +func (c *conversationDatabase) GetUserAllConversation(ctx context.Context, ownerUserID string) ([]*relationtb.Conversation, error) { return c.cache.GetUserAllConversations(ctx, ownerUserID) } -func (c *conversationDatabase) SetUserConversations(ctx context.Context, ownerUserID string, conversations []*relationtb.ConversationModel) error { +func (c *conversationDatabase) SetUserConversations(ctx context.Context, ownerUserID string, conversations []*relationtb.Conversation) error { return c.tx.Transaction(ctx, func(ctx context.Context) error { - cache := c.cache.NewCache() - groupIDs := datautil.Distinct(datautil.Filter(conversations, func(e *relationtb.ConversationModel) (string, bool) { + cache := c.cache.CloneConversationCache() + groupIDs := datautil.Distinct(datautil.Filter(conversations, func(e *relationtb.Conversation) (string, bool) { return e.GroupID, e.GroupID != "" })) for _, groupID := range groupIDs { @@ -234,7 +235,7 @@ func (c *conversationDatabase) SetUserConversations(ctx context.Context, ownerUs existConversationIDs = append(existConversationIDs, conversation.ConversationID) } - var notExistConversations []*relationtb.ConversationModel + var notExistConversations []*relationtb.Conversation for _, conversation := range conversations { if !datautil.Contain(conversation.ConversationID, existConversationIDs...) { notExistConversations = append(notExistConversations, conversation) @@ -247,9 +248,9 @@ func (c *conversationDatabase) SetUserConversations(ctx context.Context, ownerUs } cache = cache.DelConversationIDs(ownerUserID). DelUserConversationIDsHash(ownerUserID). - DelConversationNotReceiveMessageUserIDs(datautil.Slice(notExistConversations, func(e *relationtb.ConversationModel) string { return e.ConversationID })...) + DelConversationNotReceiveMessageUserIDs(datautil.Slice(notExistConversations, func(e *relationtb.Conversation) string { return e.ConversationID })...) } - return cache.ExecDel(ctx) + return cache.ChainExecDel(ctx) }) } @@ -259,16 +260,16 @@ func (c *conversationDatabase) SetUserConversations(ctx context.Context, ownerUs func (c *conversationDatabase) CreateGroupChatConversation(ctx context.Context, groupID string, userIDs []string) error { return c.tx.Transaction(ctx, func(ctx context.Context) error { - cache := c.cache.NewCache() + cache := c.cache.CloneConversationCache() conversationID := msgprocessor.GetConversationIDBySessionType(constant.ReadGroupChatType, groupID) existConversationUserIDs, err := c.conversationDB.FindUserID(ctx, userIDs, []string{conversationID}) if err != nil { return err } notExistUserIDs := stringutil.DifferenceString(userIDs, existConversationUserIDs) - var conversations []*relationtb.ConversationModel + var conversations []*relationtb.Conversation for _, v := range notExistUserIDs { - conversation := relationtb.ConversationModel{ConversationType: constant.ReadGroupChatType, GroupID: groupID, OwnerUserID: v, ConversationID: conversationID} + conversation := relationtb.Conversation{ConversationType: constant.ReadGroupChatType, GroupID: groupID, OwnerUserID: v, ConversationID: conversationID} conversations = append(conversations, &conversation) cache = cache.DelConversations(v, conversationID).DelConversationNotReceiveMessageUserIDs(conversationID) } @@ -286,7 +287,7 @@ func (c *conversationDatabase) CreateGroupChatConversation(ctx context.Context, for _, v := range existConversationUserIDs { cache = cache.DelConversations(v, conversationID) } - return cache.ExecDel(ctx) + return cache.ChainExecDel(ctx) }) } @@ -310,11 +311,11 @@ func (c *conversationDatabase) PageConversationIDs(ctx context.Context, paginati return c.conversationDB.PageConversationIDs(ctx, pagination) } -func (c *conversationDatabase) GetConversationsByConversationID(ctx context.Context, conversationIDs []string) ([]*relationtb.ConversationModel, error) { +func (c *conversationDatabase) GetConversationsByConversationID(ctx context.Context, conversationIDs []string) ([]*relationtb.Conversation, error) { return c.conversationDB.GetConversationsByConversationID(ctx, conversationIDs) } -func (c *conversationDatabase) GetConversationIDsNeedDestruct(ctx context.Context) ([]*relationtb.ConversationModel, error) { +func (c *conversationDatabase) GetConversationIDsNeedDestruct(ctx context.Context) ([]*relationtb.Conversation, error) { return c.conversationDB.GetConversationIDsNeedDestruct(ctx) } diff --git a/pkg/common/db/controller/doc.go b/pkg/common/storage/controller/doc.go similarity index 94% rename from pkg/common/db/controller/doc.go rename to pkg/common/storage/controller/doc.go index 97ec08799f..8ade2b13a1 100644 --- a/pkg/common/db/controller/doc.go +++ b/pkg/common/storage/controller/doc.go @@ -12,4 +12,4 @@ // See the License for the specific language governing permissions and // limitations under the License. -package controller // import "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" +package controller // import "github.com/openimsdk/open-im-server/v3/pkg/common/storage/controller" diff --git a/pkg/common/db/controller/friend.go b/pkg/common/storage/controller/friend.go similarity index 82% rename from pkg/common/db/controller/friend.go rename to pkg/common/storage/controller/friend.go index 49136f2288..1c3d9f139a 100644 --- a/pkg/common/db/controller/friend.go +++ b/pkg/common/storage/controller/friend.go @@ -17,10 +17,12 @@ package controller import ( "context" "fmt" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/database" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/database/mgo" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model" "time" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/cache" "github.com/openimsdk/protocol/constant" "github.com/openimsdk/tools/db/pagination" "github.com/openimsdk/tools/db/tx" @@ -37,14 +39,14 @@ type FriendDatabase interface { // AddFriendRequest adds or updates a friend request AddFriendRequest(ctx context.Context, fromUserID, toUserID string, reqMsg string, ex string) (err error) - // BecomeFriends first checks if the users are already in the friends table; if not, it inserts them as friends + // BecomeFriends first checks if the users are already in the friends model; if not, it inserts them as friends BecomeFriends(ctx context.Context, ownerUserID string, friendUserIDs []string, addSource int32) (err error) // RefuseFriendRequest refuses a friend request - RefuseFriendRequest(ctx context.Context, friendRequest *relation.FriendRequestModel) (err error) + RefuseFriendRequest(ctx context.Context, friendRequest *model.FriendRequest) (err error) // AgreeFriendRequest accepts a friend request - AgreeFriendRequest(ctx context.Context, friendRequest *relation.FriendRequestModel) (err error) + AgreeFriendRequest(ctx context.Context, friendRequest *model.FriendRequest) (err error) // Delete removes a friend or friends from the owner's friend list Delete(ctx context.Context, ownerUserID string, friendUserIDs []string) (err error) @@ -53,38 +55,38 @@ type FriendDatabase interface { UpdateRemark(ctx context.Context, ownerUserID, friendUserID, remark string) (err error) // PageOwnerFriends retrieves the friend list of ownerUserID with pagination - PageOwnerFriends(ctx context.Context, ownerUserID string, pagination pagination.Pagination) (total int64, friends []*relation.FriendModel, err error) + PageOwnerFriends(ctx context.Context, ownerUserID string, pagination pagination.Pagination) (total int64, friends []*model.Friend, err error) // PageInWhoseFriends finds the users who have friendUserID in their friend list with pagination - PageInWhoseFriends(ctx context.Context, friendUserID string, pagination pagination.Pagination) (total int64, friends []*relation.FriendModel, err error) + PageInWhoseFriends(ctx context.Context, friendUserID string, pagination pagination.Pagination) (total int64, friends []*model.Friend, err error) // PageFriendRequestFromMe retrieves the friend requests sent by the user with pagination - PageFriendRequestFromMe(ctx context.Context, userID string, pagination pagination.Pagination) (total int64, friends []*relation.FriendRequestModel, err error) + PageFriendRequestFromMe(ctx context.Context, userID string, pagination pagination.Pagination) (total int64, friends []*model.FriendRequest, err error) // PageFriendRequestToMe retrieves the friend requests received by the user with pagination - PageFriendRequestToMe(ctx context.Context, userID string, pagination pagination.Pagination) (total int64, friends []*relation.FriendRequestModel, err error) + PageFriendRequestToMe(ctx context.Context, userID string, pagination pagination.Pagination) (total int64, friends []*model.FriendRequest, err error) // FindFriendsWithError fetches specified friends of a user and returns an error if any do not exist - FindFriendsWithError(ctx context.Context, ownerUserID string, friendUserIDs []string) (friends []*relation.FriendModel, err error) + FindFriendsWithError(ctx context.Context, ownerUserID string, friendUserIDs []string) (friends []*model.Friend, err error) // FindFriendUserIDs retrieves the friend IDs of a user FindFriendUserIDs(ctx context.Context, ownerUserID string) (friendUserIDs []string, err error) // FindBothFriendRequests finds friend requests sent and received - FindBothFriendRequests(ctx context.Context, fromUserID, toUserID string) (friends []*relation.FriendRequestModel, err error) + FindBothFriendRequests(ctx context.Context, fromUserID, toUserID string) (friends []*model.FriendRequest, err error) // UpdateFriends updates fields for friends UpdateFriends(ctx context.Context, ownerUserID string, friendUserIDs []string, val map[string]any) (err error) } type friendDatabase struct { - friend relation.FriendModelInterface - friendRequest relation.FriendRequestModelInterface + friend database.Friend + friendRequest database.FriendRequest tx tx.Tx cache cache.FriendCache } -func NewFriendDatabase(friend relation.FriendModelInterface, friendRequest relation.FriendRequestModelInterface, cache cache.FriendCache, tx tx.Tx) FriendDatabase { +func NewFriendDatabase(friend database.Friend, friendRequest database.FriendRequest, cache cache.FriendCache, tx tx.Tx) FriendDatabase { return &friendDatabase{friend: friend, friendRequest: friendRequest, cache: cache, tx: tx} } @@ -124,10 +126,10 @@ func (f *friendDatabase) AddFriendRequest(ctx context.Context, fromUserID, toUse m["ex"] = ex m["create_time"] = time.Now() return f.friendRequest.UpdateByMap(ctx, fromUserID, toUserID, m) - case relation.IsNotFound(err): + case mgo.IsNotFound(err): return f.friendRequest.Create( ctx, - []*relation.FriendRequestModel{{FromUserID: fromUserID, ToUserID: toUserID, ReqMsg: reqMsg, Ex: ex, CreateTime: time.Now(), HandleTime: time.Unix(0, 0)}}, + []*model.FriendRequest{{FromUserID: fromUserID, ToUserID: toUserID, ReqMsg: reqMsg, Ex: ex, CreateTime: time.Now(), HandleTime: time.Unix(0, 0)}}, ) default: return err @@ -138,7 +140,7 @@ func (f *friendDatabase) AddFriendRequest(ctx context.Context, fromUserID, toUse // (1) First determine whether it is in the friends list (in or out does not return an error) (2) for not in the friends list can be inserted. func (f *friendDatabase) BecomeFriends(ctx context.Context, ownerUserID string, friendUserIDs []string, addSource int32) (err error) { return f.tx.Transaction(ctx, func(ctx context.Context) error { - cache := f.cache.NewCache() + cache := f.cache.CloneFriendCache() // user find friends fs1, err := f.friend.FindFriends(ctx, ownerUserID, friendUserIDs) if err != nil { @@ -146,9 +148,9 @@ func (f *friendDatabase) BecomeFriends(ctx context.Context, ownerUserID string, } opUserID := mcontext.GetOperationID(ctx) for _, v := range friendUserIDs { - fs1 = append(fs1, &relation.FriendModel{OwnerUserID: ownerUserID, FriendUserID: v, AddSource: addSource, OperatorUserID: opUserID}) + fs1 = append(fs1, &model.Friend{OwnerUserID: ownerUserID, FriendUserID: v, AddSource: addSource, OperatorUserID: opUserID}) } - fs11 := datautil.DistinctAny(fs1, func(e *relation.FriendModel) string { + fs11 := datautil.DistinctAny(fs1, func(e *model.Friend) string { return e.FriendUserID }) @@ -162,10 +164,10 @@ func (f *friendDatabase) BecomeFriends(ctx context.Context, ownerUserID string, } var newFriendIDs []string for _, v := range friendUserIDs { - fs2 = append(fs2, &relation.FriendModel{OwnerUserID: v, FriendUserID: ownerUserID, AddSource: addSource, OperatorUserID: opUserID}) + fs2 = append(fs2, &model.Friend{OwnerUserID: v, FriendUserID: ownerUserID, AddSource: addSource, OperatorUserID: opUserID}) newFriendIDs = append(newFriendIDs, v) } - fs22 := datautil.DistinctAny(fs2, func(e *relation.FriendModel) string { + fs22 := datautil.DistinctAny(fs2, func(e *model.Friend) string { return e.OwnerUserID }) err = f.friend.Create(ctx, fs22) @@ -174,14 +176,14 @@ func (f *friendDatabase) BecomeFriends(ctx context.Context, ownerUserID string, } newFriendIDs = append(newFriendIDs, ownerUserID) cache = cache.DelFriendIDs(newFriendIDs...) - return cache.ExecDel(ctx) + return cache.ChainExecDel(ctx) }) } // RefuseFriendRequest rejects a friend request. It first checks for an existing, unprocessed request. // If no such request exists, it returns an error. Otherwise, it marks the request as refused. -func (f *friendDatabase) RefuseFriendRequest(ctx context.Context, friendRequest *relation.FriendRequestModel) error { +func (f *friendDatabase) RefuseFriendRequest(ctx context.Context, friendRequest *model.FriendRequest) error { // Attempt to retrieve the friend request from the database. fr, err := f.friendRequest.Take(ctx, friendRequest.FromUserID, friendRequest.ToUserID) if err != nil { @@ -210,7 +212,7 @@ func (f *friendDatabase) RefuseFriendRequest(ctx context.Context, friendRequest } // AgreeFriendRequest accepts a friend request. It first checks for an existing, unprocessed request. -func (f *friendDatabase) AgreeFriendRequest(ctx context.Context, friendRequest *relation.FriendRequestModel) (err error) { +func (f *friendDatabase) AgreeFriendRequest(ctx context.Context, friendRequest *model.FriendRequest) (err error) { return f.tx.Transaction(ctx, func(ctx context.Context) error { now := time.Now() fr, err := f.friendRequest.Take(ctx, friendRequest.FromUserID, friendRequest.ToUserID) @@ -237,7 +239,7 @@ func (f *friendDatabase) AgreeFriendRequest(ctx context.Context, friendRequest * if err != nil { return err } - } else if err != nil && (!relation.IsNotFound(err)) { + } else if err != nil && (!mgo.IsNotFound(err)) { return err } @@ -245,14 +247,14 @@ func (f *friendDatabase) AgreeFriendRequest(ctx context.Context, friendRequest * if err != nil { return err } - existsMap := datautil.SliceSet(datautil.Slice(exists, func(friend *relation.FriendModel) [2]string { + existsMap := datautil.SliceSet(datautil.Slice(exists, func(friend *model.Friend) [2]string { return [...]string{friend.OwnerUserID, friend.FriendUserID} // My - Friend })) - var adds []*relation.FriendModel + var adds []*model.Friend if _, ok := existsMap[[...]string{friendRequest.ToUserID, friendRequest.FromUserID}]; !ok { // My - Friend adds = append( adds, - &relation.FriendModel{ + &model.Friend{ OwnerUserID: friendRequest.ToUserID, FriendUserID: friendRequest.FromUserID, AddSource: int32(constant.BecomeFriendByApply), @@ -263,7 +265,7 @@ func (f *friendDatabase) AgreeFriendRequest(ctx context.Context, friendRequest * if _, ok := existsMap[[...]string{friendRequest.FromUserID, friendRequest.ToUserID}]; !ok { // My - Friend adds = append( adds, - &relation.FriendModel{ + &model.Friend{ OwnerUserID: friendRequest.FromUserID, FriendUserID: friendRequest.ToUserID, AddSource: int32(constant.BecomeFriendByApply), @@ -276,7 +278,7 @@ func (f *friendDatabase) AgreeFriendRequest(ctx context.Context, friendRequest * return err } } - return f.cache.DelFriendIDs(friendRequest.ToUserID, friendRequest.FromUserID).ExecDel(ctx) + return f.cache.DelFriendIDs(friendRequest.ToUserID, friendRequest.FromUserID).ChainExecDel(ctx) }) } @@ -285,7 +287,7 @@ func (f *friendDatabase) Delete(ctx context.Context, ownerUserID string, friendU if err := f.friend.Delete(ctx, ownerUserID, friendUserIDs); err != nil { return err } - return f.cache.DelFriendIDs(append(friendUserIDs, ownerUserID)...).ExecDel(ctx) + return f.cache.DelFriendIDs(append(friendUserIDs, ownerUserID)...).ChainExecDel(ctx) } // UpdateRemark updates the remark for a friend. Zero value for remark is also supported. @@ -293,31 +295,31 @@ func (f *friendDatabase) UpdateRemark(ctx context.Context, ownerUserID, friendUs if err := f.friend.UpdateRemark(ctx, ownerUserID, friendUserID, remark); err != nil { return err } - return f.cache.DelFriend(ownerUserID, friendUserID).ExecDel(ctx) + return f.cache.DelFriend(ownerUserID, friendUserID).ChainExecDel(ctx) } // PageOwnerFriends retrieves the list of friends for the ownerUserID. It does not return an error if the result is empty. -func (f *friendDatabase) PageOwnerFriends(ctx context.Context, ownerUserID string, pagination pagination.Pagination) (total int64, friends []*relation.FriendModel, err error) { +func (f *friendDatabase) PageOwnerFriends(ctx context.Context, ownerUserID string, pagination pagination.Pagination) (total int64, friends []*model.Friend, err error) { return f.friend.FindOwnerFriends(ctx, ownerUserID, pagination) } // PageInWhoseFriends identifies in whose friend lists the friendUserID appears. -func (f *friendDatabase) PageInWhoseFriends(ctx context.Context, friendUserID string, pagination pagination.Pagination) (total int64, friends []*relation.FriendModel, err error) { +func (f *friendDatabase) PageInWhoseFriends(ctx context.Context, friendUserID string, pagination pagination.Pagination) (total int64, friends []*model.Friend, err error) { return f.friend.FindInWhoseFriends(ctx, friendUserID, pagination) } // PageFriendRequestFromMe retrieves friend requests sent by me. It does not return an error if the result is empty. -func (f *friendDatabase) PageFriendRequestFromMe(ctx context.Context, userID string, pagination pagination.Pagination) (total int64, friends []*relation.FriendRequestModel, err error) { +func (f *friendDatabase) PageFriendRequestFromMe(ctx context.Context, userID string, pagination pagination.Pagination) (total int64, friends []*model.FriendRequest, err error) { return f.friendRequest.FindFromUserID(ctx, userID, pagination) } // PageFriendRequestToMe retrieves friend requests received by me. It does not return an error if the result is empty. -func (f *friendDatabase) PageFriendRequestToMe(ctx context.Context, userID string, pagination pagination.Pagination) (total int64, friends []*relation.FriendRequestModel, err error) { +func (f *friendDatabase) PageFriendRequestToMe(ctx context.Context, userID string, pagination pagination.Pagination) (total int64, friends []*model.FriendRequest, err error) { return f.friendRequest.FindToUserID(ctx, userID, pagination) } // FindFriendsWithError retrieves specified friends' information for ownerUserID. Returns an error if any friend does not exist. -func (f *friendDatabase) FindFriendsWithError(ctx context.Context, ownerUserID string, friendUserIDs []string) (friends []*relation.FriendModel, err error) { +func (f *friendDatabase) FindFriendsWithError(ctx context.Context, ownerUserID string, friendUserIDs []string) (friends []*model.Friend, err error) { friends, err = f.friend.FindFriends(ctx, ownerUserID, friendUserIDs) if err != nil { return @@ -332,7 +334,7 @@ func (f *friendDatabase) FindFriendUserIDs(ctx context.Context, ownerUserID stri return f.cache.GetFriendIDs(ctx, ownerUserID) } -func (f *friendDatabase) FindBothFriendRequests(ctx context.Context, fromUserID, toUserID string) (friends []*relation.FriendRequestModel, err error) { +func (f *friendDatabase) FindBothFriendRequests(ctx context.Context, fromUserID, toUserID string) (friends []*model.FriendRequest, err error) { return f.friendRequest.FindBothFriendRequests(ctx, fromUserID, toUserID) } func (f *friendDatabase) UpdateFriends(ctx context.Context, ownerUserID string, friendUserIDs []string, val map[string]any) (err error) { @@ -342,5 +344,5 @@ func (f *friendDatabase) UpdateFriends(ctx context.Context, ownerUserID string, if err := f.friend.UpdateFriends(ctx, ownerUserID, friendUserIDs, val); err != nil { return err } - return f.cache.DelFriends(ownerUserID, friendUserIDs).ExecDel(ctx) + return f.cache.DelFriends(ownerUserID, friendUserIDs).ChainExecDel(ctx) } diff --git a/pkg/common/db/controller/group.go b/pkg/common/storage/controller/group.go similarity index 77% rename from pkg/common/db/controller/group.go rename to pkg/common/storage/controller/group.go index ddf72b7bf1..f2a1358357 100644 --- a/pkg/common/db/controller/group.go +++ b/pkg/common/storage/controller/group.go @@ -17,11 +17,13 @@ package controller import ( "context" "github.com/openimsdk/open-im-server/v3/pkg/common/config" + redis2 "github.com/openimsdk/open-im-server/v3/pkg/common/storage/cache/redis" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/common" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/database" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model" "time" - "github.com/dtm-labs/rockscache" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" - relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/cache" "github.com/openimsdk/protocol/constant" "github.com/openimsdk/tools/db/pagination" "github.com/openimsdk/tools/db/tx" @@ -31,32 +33,32 @@ import ( type GroupDatabase interface { // CreateGroup creates new groups along with their members. - CreateGroup(ctx context.Context, groups []*relationtb.GroupModel, groupMembers []*relationtb.GroupMemberModel) error + CreateGroup(ctx context.Context, groups []*model.Group, groupMembers []*model.GroupMember) error // TakeGroup retrieves a single group by its ID. - TakeGroup(ctx context.Context, groupID string) (group *relationtb.GroupModel, err error) + TakeGroup(ctx context.Context, groupID string) (group *model.Group, err error) // FindGroup retrieves multiple groups by their IDs. - FindGroup(ctx context.Context, groupIDs []string) (groups []*relationtb.GroupModel, err error) + FindGroup(ctx context.Context, groupIDs []string) (groups []*model.Group, err error) // SearchGroup searches for groups based on a keyword and pagination settings, returns total count and groups. - SearchGroup(ctx context.Context, keyword string, pagination pagination.Pagination) (int64, []*relationtb.GroupModel, error) + SearchGroup(ctx context.Context, keyword string, pagination pagination.Pagination) (int64, []*model.Group, error) // UpdateGroup updates the properties of a group identified by its ID. UpdateGroup(ctx context.Context, groupID string, data map[string]any) error // DismissGroup disbands a group and optionally removes its members based on the deleteMember flag. DismissGroup(ctx context.Context, groupID string, deleteMember bool) error // TakeGroupMember retrieves a specific group member by group ID and user ID. - TakeGroupMember(ctx context.Context, groupID string, userID string) (groupMember *relationtb.GroupMemberModel, err error) + TakeGroupMember(ctx context.Context, groupID string, userID string) (groupMember *model.GroupMember, err error) // TakeGroupOwner retrieves the owner of a group by group ID. - TakeGroupOwner(ctx context.Context, groupID string) (*relationtb.GroupMemberModel, error) + TakeGroupOwner(ctx context.Context, groupID string) (*model.GroupMember, error) // FindGroupMembers retrieves members of a group filtered by user IDs. - FindGroupMembers(ctx context.Context, groupID string, userIDs []string) (groupMembers []*relationtb.GroupMemberModel, err error) + FindGroupMembers(ctx context.Context, groupID string, userIDs []string) (groupMembers []*model.GroupMember, err error) // FindGroupMemberUser retrieves groups that a user is a member of, filtered by group IDs. - FindGroupMemberUser(ctx context.Context, groupIDs []string, userID string) (groupMembers []*relationtb.GroupMemberModel, err error) + FindGroupMemberUser(ctx context.Context, groupIDs []string, userID string) (groupMembers []*model.GroupMember, err error) // FindGroupMemberRoleLevels retrieves group members filtered by their role levels within a group. - FindGroupMemberRoleLevels(ctx context.Context, groupID string, roleLevels []int32) (groupMembers []*relationtb.GroupMemberModel, err error) + FindGroupMemberRoleLevels(ctx context.Context, groupID string, roleLevels []int32) (groupMembers []*model.GroupMember, err error) // FindGroupMemberAll retrieves all members of a group. - FindGroupMemberAll(ctx context.Context, groupID string) (groupMembers []*relationtb.GroupMemberModel, err error) + FindGroupMemberAll(ctx context.Context, groupID string) (groupMembers []*model.GroupMember, err error) // FindGroupsOwner retrieves the owners for multiple groups. - FindGroupsOwner(ctx context.Context, groupIDs []string) ([]*relationtb.GroupMemberModel, error) + FindGroupsOwner(ctx context.Context, groupIDs []string) ([]*model.GroupMember, error) // FindGroupMemberUserID retrieves the user IDs of all members in a group. FindGroupMemberUserID(ctx context.Context, groupID string) ([]string, error) // FindGroupMemberNum retrieves the number of members in a group. @@ -64,22 +66,22 @@ type GroupDatabase interface { // FindUserManagedGroupID retrieves group IDs managed by a user. FindUserManagedGroupID(ctx context.Context, userID string) (groupIDs []string, err error) // PageGroupRequest paginates through group requests for specified groups. - PageGroupRequest(ctx context.Context, groupIDs []string, pagination pagination.Pagination) (int64, []*relationtb.GroupRequestModel, error) + PageGroupRequest(ctx context.Context, groupIDs []string, pagination pagination.Pagination) (int64, []*model.GroupRequest, error) // GetGroupRoleLevelMemberIDs retrieves user IDs of group members with a specific role level. GetGroupRoleLevelMemberIDs(ctx context.Context, groupID string, roleLevel int32) ([]string, error) // PageGetJoinGroup paginates through groups that a user has joined. - PageGetJoinGroup(ctx context.Context, userID string, pagination pagination.Pagination) (total int64, totalGroupMembers []*relationtb.GroupMemberModel, err error) + PageGetJoinGroup(ctx context.Context, userID string, pagination pagination.Pagination) (total int64, totalGroupMembers []*model.GroupMember, err error) // PageGetGroupMember paginates through members of a group. - PageGetGroupMember(ctx context.Context, groupID string, pagination pagination.Pagination) (total int64, totalGroupMembers []*relationtb.GroupMemberModel, err error) + PageGetGroupMember(ctx context.Context, groupID string, pagination pagination.Pagination) (total int64, totalGroupMembers []*model.GroupMember, err error) // SearchGroupMember searches for group members based on a keyword, group ID, and pagination settings. - SearchGroupMember(ctx context.Context, keyword string, groupID string, pagination pagination.Pagination) (int64, []*relationtb.GroupMemberModel, error) + SearchGroupMember(ctx context.Context, keyword string, groupID string, pagination pagination.Pagination) (int64, []*model.GroupMember, error) // HandlerGroupRequest processes a group join request with a specified result. - HandlerGroupRequest(ctx context.Context, groupID string, userID string, handledMsg string, handleResult int32, member *relationtb.GroupMemberModel) error + HandlerGroupRequest(ctx context.Context, groupID string, userID string, handledMsg string, handleResult int32, member *model.GroupMember) error // DeleteGroupMember removes specified users from a group. DeleteGroupMember(ctx context.Context, groupID string, userIDs []string) error // MapGroupMemberUserID maps group IDs to their members' simplified user IDs. - MapGroupMemberUserID(ctx context.Context, groupIDs []string) (map[string]*relationtb.GroupSimpleUserID, error) + MapGroupMemberUserID(ctx context.Context, groupIDs []string) (map[string]*common.GroupSimpleUserID, error) // MapGroupMemberNum maps group IDs to their member count. MapGroupMemberNum(ctx context.Context, groupIDs []string) (map[string]uint32, error) // TransferGroupOwner transfers the ownership of a group to another user. @@ -87,16 +89,16 @@ type GroupDatabase interface { // UpdateGroupMember updates properties of a group member. UpdateGroupMember(ctx context.Context, groupID string, userID string, data map[string]any) error // UpdateGroupMembers batch updates properties of group members. - UpdateGroupMembers(ctx context.Context, data []*relationtb.BatchUpdateGroupMember) error + UpdateGroupMembers(ctx context.Context, data []*common.BatchUpdateGroupMember) error // CreateGroupRequest creates new group join requests. - CreateGroupRequest(ctx context.Context, requests []*relationtb.GroupRequestModel) error + CreateGroupRequest(ctx context.Context, requests []*model.GroupRequest) error // TakeGroupRequest retrieves a specific group join request. - TakeGroupRequest(ctx context.Context, groupID string, userID string) (*relationtb.GroupRequestModel, error) + TakeGroupRequest(ctx context.Context, groupID string, userID string) (*model.GroupRequest, error) // FindGroupRequests retrieves multiple group join requests. - FindGroupRequests(ctx context.Context, groupID string, userIDs []string) ([]*relationtb.GroupRequestModel, error) + FindGroupRequests(ctx context.Context, groupID string, userIDs []string) ([]*model.GroupRequest, error) // PageGroupRequestUser paginates through group join requests made by a user. - PageGroupRequestUser(ctx context.Context, userID string, pagination pagination.Pagination) (int64, []*relationtb.GroupRequestModel, error) + PageGroupRequestUser(ctx context.Context, userID string, pagination pagination.Pagination) (int64, []*model.GroupRequest, error) // CountTotal counts the total number of groups as of a certain date. CountTotal(ctx context.Context, before *time.Time) (count int64, err error) @@ -109,49 +111,46 @@ type GroupDatabase interface { func NewGroupDatabase( rdb redis.UniversalClient, localCache *config.LocalCache, - groupDB relationtb.GroupModelInterface, - groupMemberDB relationtb.GroupMemberModelInterface, - groupRequestDB relationtb.GroupRequestModelInterface, + groupDB database.Group, + groupMemberDB database.GroupMember, + groupRequestDB database.GroupRequest, ctxTx tx.Tx, groupHash cache.GroupHash, ) GroupDatabase { - rcOptions := rockscache.NewDefaultOptions() - rcOptions.StrongConsistency = true - rcOptions.RandomExpireAdjustment = 0.2 return &groupDatabase{ groupDB: groupDB, groupMemberDB: groupMemberDB, groupRequestDB: groupRequestDB, ctxTx: ctxTx, - cache: cache.NewGroupCacheRedis(rdb, localCache, groupDB, groupMemberDB, groupRequestDB, groupHash, rcOptions), + cache: redis2.NewGroupCacheRedis(rdb, localCache, groupDB, groupMemberDB, groupRequestDB, groupHash, redis2.GetRocksCacheOptions()), } } type groupDatabase struct { - groupDB relationtb.GroupModelInterface - groupMemberDB relationtb.GroupMemberModelInterface - groupRequestDB relationtb.GroupRequestModelInterface + groupDB database.Group + groupMemberDB database.GroupMember + groupRequestDB database.GroupRequest ctxTx tx.Tx cache cache.GroupCache } -func (g *groupDatabase) FindGroupMembers(ctx context.Context, groupID string, userIDs []string) ([]*relationtb.GroupMemberModel, error) { +func (g *groupDatabase) FindGroupMembers(ctx context.Context, groupID string, userIDs []string) ([]*model.GroupMember, error) { return g.cache.GetGroupMembersInfo(ctx, groupID, userIDs) } -func (g *groupDatabase) FindGroupMemberUser(ctx context.Context, groupIDs []string, userID string) ([]*relationtb.GroupMemberModel, error) { +func (g *groupDatabase) FindGroupMemberUser(ctx context.Context, groupIDs []string, userID string) ([]*model.GroupMember, error) { return g.cache.FindGroupMemberUser(ctx, groupIDs, userID) } -func (g *groupDatabase) FindGroupMemberRoleLevels(ctx context.Context, groupID string, roleLevels []int32) ([]*relationtb.GroupMemberModel, error) { +func (g *groupDatabase) FindGroupMemberRoleLevels(ctx context.Context, groupID string, roleLevels []int32) ([]*model.GroupMember, error) { return g.cache.GetGroupRolesLevelMemberInfo(ctx, groupID, roleLevels) } -func (g *groupDatabase) FindGroupMemberAll(ctx context.Context, groupID string) ([]*relationtb.GroupMemberModel, error) { +func (g *groupDatabase) FindGroupMemberAll(ctx context.Context, groupID string) ([]*model.GroupMember, error) { return g.cache.GetAllGroupMembersInfo(ctx, groupID) } -func (g *groupDatabase) FindGroupsOwner(ctx context.Context, groupIDs []string) ([]*relationtb.GroupMemberModel, error) { +func (g *groupDatabase) FindGroupsOwner(ctx context.Context, groupIDs []string) ([]*model.GroupMember, error) { return g.cache.GetGroupsOwner(ctx, groupIDs) } @@ -159,12 +158,12 @@ func (g *groupDatabase) GetGroupRoleLevelMemberIDs(ctx context.Context, groupID return g.cache.GetGroupRoleLevelMemberIDs(ctx, groupID, roleLevel) } -func (g *groupDatabase) CreateGroup(ctx context.Context, groups []*relationtb.GroupModel, groupMembers []*relationtb.GroupMemberModel) error { +func (g *groupDatabase) CreateGroup(ctx context.Context, groups []*model.Group, groupMembers []*model.GroupMember) error { if len(groups)+len(groupMembers) == 0 { return nil } return g.ctxTx.Transaction(ctx, func(ctx context.Context) error { - c := g.cache.NewCache() + c := g.cache.CloneGroupCache() if len(groups) > 0 { if err := g.groupDB.Create(ctx, groups); err != nil { return err @@ -191,7 +190,7 @@ func (g *groupDatabase) CreateGroup(ctx context.Context, groups []*relationtb.Gr DelGroupAllRoleLevel(groupMember.GroupID) } } - return c.ExecDel(ctx, true) + return c.ChainExecDel(ctx) }) } @@ -207,15 +206,15 @@ func (g *groupDatabase) FindGroupMemberNum(ctx context.Context, groupID string) return uint32(num), nil } -func (g *groupDatabase) TakeGroup(ctx context.Context, groupID string) (*relationtb.GroupModel, error) { +func (g *groupDatabase) TakeGroup(ctx context.Context, groupID string) (*model.Group, error) { return g.cache.GetGroupInfo(ctx, groupID) } -func (g *groupDatabase) FindGroup(ctx context.Context, groupIDs []string) ([]*relationtb.GroupModel, error) { +func (g *groupDatabase) FindGroup(ctx context.Context, groupIDs []string) ([]*model.Group, error) { return g.cache.GetGroupsInfo(ctx, groupIDs) } -func (g *groupDatabase) SearchGroup(ctx context.Context, keyword string, pagination pagination.Pagination) (int64, []*relationtb.GroupModel, error) { +func (g *groupDatabase) SearchGroup(ctx context.Context, keyword string, pagination pagination.Pagination) (int64, []*model.Group, error) { return g.groupDB.Search(ctx, keyword, pagination) } @@ -223,12 +222,12 @@ func (g *groupDatabase) UpdateGroup(ctx context.Context, groupID string, data ma if err := g.groupDB.UpdateMap(ctx, groupID, data); err != nil { return err } - return g.cache.DelGroupsInfo(groupID).ExecDel(ctx) + return g.cache.DelGroupsInfo(groupID).ChainExecDel(ctx) } func (g *groupDatabase) DismissGroup(ctx context.Context, groupID string, deleteMember bool) error { return g.ctxTx.Transaction(ctx, func(ctx context.Context) error { - c := g.cache.NewCache() + c := g.cache.CloneGroupCache() if err := g.groupDB.UpdateStatus(ctx, groupID, constant.GroupStatusDismissed); err != nil { return err } @@ -247,15 +246,15 @@ func (g *groupDatabase) DismissGroup(ctx context.Context, groupID string, delete DelGroupAllRoleLevel(groupID). DelGroupMembersInfo(groupID, userIDs...) } - return c.DelGroupsInfo(groupID).ExecDel(ctx) + return c.DelGroupsInfo(groupID).ChainExecDel(ctx) }) } -func (g *groupDatabase) TakeGroupMember(ctx context.Context, groupID string, userID string) (*relationtb.GroupMemberModel, error) { +func (g *groupDatabase) TakeGroupMember(ctx context.Context, groupID string, userID string) (*model.GroupMember, error) { return g.cache.GetGroupMemberInfo(ctx, groupID, userID) } -func (g *groupDatabase) TakeGroupOwner(ctx context.Context, groupID string) (*relationtb.GroupMemberModel, error) { +func (g *groupDatabase) TakeGroupOwner(ctx context.Context, groupID string) (*model.GroupMember, error) { return g.cache.GetGroupOwner(ctx, groupID) } @@ -263,11 +262,11 @@ func (g *groupDatabase) FindUserManagedGroupID(ctx context.Context, userID strin return g.groupMemberDB.FindUserManagedGroupID(ctx, userID) } -func (g *groupDatabase) PageGroupRequest(ctx context.Context, groupIDs []string, pagination pagination.Pagination) (int64, []*relationtb.GroupRequestModel, error) { +func (g *groupDatabase) PageGroupRequest(ctx context.Context, groupIDs []string, pagination pagination.Pagination) (int64, []*model.GroupRequest, error) { return g.groupRequestDB.PageGroup(ctx, groupIDs, pagination) } -func (g *groupDatabase) PageGetJoinGroup(ctx context.Context, userID string, pagination pagination.Pagination) (total int64, totalGroupMembers []*relationtb.GroupMemberModel, err error) { +func (g *groupDatabase) PageGetJoinGroup(ctx context.Context, userID string, pagination pagination.Pagination) (total int64, totalGroupMembers []*model.GroupMember, err error) { groupIDs, err := g.cache.GetJoinedGroupIDs(ctx, userID) if err != nil { return 0, nil, err @@ -282,7 +281,7 @@ func (g *groupDatabase) PageGetJoinGroup(ctx context.Context, userID string, pag return int64(len(groupIDs)), totalGroupMembers, nil } -func (g *groupDatabase) PageGetGroupMember(ctx context.Context, groupID string, pagination pagination.Pagination) (total int64, totalGroupMembers []*relationtb.GroupMemberModel, err error) { +func (g *groupDatabase) PageGetGroupMember(ctx context.Context, groupID string, pagination pagination.Pagination) (total int64, totalGroupMembers []*model.GroupMember, err error) { groupMemberIDs, err := g.cache.GetGroupMemberIDs(ctx, groupID) if err != nil { return 0, nil, err @@ -298,26 +297,27 @@ func (g *groupDatabase) PageGetGroupMember(ctx context.Context, groupID string, return int64(len(groupMemberIDs)), members, nil } -func (g *groupDatabase) SearchGroupMember(ctx context.Context, keyword string, groupID string, pagination pagination.Pagination) (int64, []*relationtb.GroupMemberModel, error) { +func (g *groupDatabase) SearchGroupMember(ctx context.Context, keyword string, groupID string, pagination pagination.Pagination) (int64, []*model.GroupMember, error) { return g.groupMemberDB.SearchMember(ctx, keyword, groupID, pagination) } -func (g *groupDatabase) HandlerGroupRequest(ctx context.Context, groupID string, userID string, handledMsg string, handleResult int32, member *relationtb.GroupMemberModel) error { +func (g *groupDatabase) HandlerGroupRequest(ctx context.Context, groupID string, userID string, handledMsg string, handleResult int32, member *model.GroupMember) error { return g.ctxTx.Transaction(ctx, func(ctx context.Context) error { if err := g.groupRequestDB.UpdateHandler(ctx, groupID, userID, handledMsg, handleResult); err != nil { return err } if member != nil { - if err := g.groupMemberDB.Create(ctx, []*relationtb.GroupMemberModel{member}); err != nil { + c := g.cache.CloneGroupCache() + if err := g.groupMemberDB.Create(ctx, []*model.GroupMember{member}); err != nil { return err } - c := g.cache.DelGroupMembersHash(groupID). + c = c.DelGroupMembersHash(groupID). DelGroupMembersInfo(groupID, member.UserID). DelGroupMemberIDs(groupID). DelGroupsMemberNum(groupID). DelJoinedGroupID(member.UserID). DelGroupRoleLevel(groupID, []int32{member.RoleLevel}) - if err := c.ExecDel(ctx); err != nil { + if err := c.ChainExecDel(ctx); err != nil { return err } } @@ -329,16 +329,17 @@ func (g *groupDatabase) DeleteGroupMember(ctx context.Context, groupID string, u if err := g.groupMemberDB.Delete(ctx, groupID, userIDs); err != nil { return err } - return g.cache.DelGroupMembersHash(groupID). + c := g.cache.CloneGroupCache() + return c.DelGroupMembersHash(groupID). DelGroupMemberIDs(groupID). DelGroupsMemberNum(groupID). DelJoinedGroupID(userIDs...). DelGroupMembersInfo(groupID, userIDs...). DelGroupAllRoleLevel(groupID). - ExecDel(ctx) + ChainExecDel(ctx) } -func (g *groupDatabase) MapGroupMemberUserID(ctx context.Context, groupIDs []string) (map[string]*relationtb.GroupSimpleUserID, error) { +func (g *groupDatabase) MapGroupMemberUserID(ctx context.Context, groupIDs []string) (map[string]*common.GroupSimpleUserID, error) { return g.cache.GetGroupMemberHashMap(ctx, groupIDs) } @@ -362,9 +363,10 @@ func (g *groupDatabase) TransferGroupOwner(ctx context.Context, groupID string, if err := g.groupMemberDB.UpdateRoleLevel(ctx, groupID, newOwnerUserID, constant.GroupOwner); err != nil { return err } - return g.cache.DelGroupMembersInfo(groupID, oldOwnerUserID, newOwnerUserID). + c := g.cache.CloneGroupCache() + return c.DelGroupMembersInfo(groupID, oldOwnerUserID, newOwnerUserID). DelGroupAllRoleLevel(groupID). - DelGroupMembersHash(groupID).ExecDel(ctx) + DelGroupMembersHash(groupID).ChainExecDel(ctx) }) } @@ -372,16 +374,17 @@ func (g *groupDatabase) UpdateGroupMember(ctx context.Context, groupID string, u if err := g.groupMemberDB.Update(ctx, groupID, userID, data); err != nil { return err } - c := g.cache.DelGroupMembersInfo(groupID, userID) + c := g.cache.CloneGroupCache() + c = c.DelGroupMembersInfo(groupID, userID) if g.groupMemberDB.IsUpdateRoleLevel(data) { c = c.DelGroupAllRoleLevel(groupID) } - return c.ExecDel(ctx) + return c.ChainExecDel(ctx) } -func (g *groupDatabase) UpdateGroupMembers(ctx context.Context, data []*relationtb.BatchUpdateGroupMember) error { +func (g *groupDatabase) UpdateGroupMembers(ctx context.Context, data []*common.BatchUpdateGroupMember) error { return g.ctxTx.Transaction(ctx, func(ctx context.Context) error { - c := g.cache.NewCache() + c := g.cache.CloneGroupCache() for _, item := range data { if err := g.groupMemberDB.Update(ctx, item.GroupID, item.UserID, item.Map); err != nil { return err @@ -391,11 +394,11 @@ func (g *groupDatabase) UpdateGroupMembers(ctx context.Context, data []*relation } c = c.DelGroupMembersInfo(item.GroupID, item.UserID).DelGroupMembersHash(item.GroupID) } - return c.ExecDel(ctx, true) + return c.ChainExecDel(ctx) }) } -func (g *groupDatabase) CreateGroupRequest(ctx context.Context, requests []*relationtb.GroupRequestModel) error { +func (g *groupDatabase) CreateGroupRequest(ctx context.Context, requests []*model.GroupRequest) error { return g.ctxTx.Transaction(ctx, func(ctx context.Context) error { for _, request := range requests { if err := g.groupRequestDB.Delete(ctx, request.GroupID, request.UserID); err != nil { @@ -410,11 +413,11 @@ func (g *groupDatabase) TakeGroupRequest( ctx context.Context, groupID string, userID string, -) (*relationtb.GroupRequestModel, error) { +) (*model.GroupRequest, error) { return g.groupRequestDB.Take(ctx, groupID, userID) } -func (g *groupDatabase) PageGroupRequestUser(ctx context.Context, userID string, pagination pagination.Pagination) (int64, []*relationtb.GroupRequestModel, error) { +func (g *groupDatabase) PageGroupRequestUser(ctx context.Context, userID string, pagination pagination.Pagination) (int64, []*model.GroupRequest, error) { return g.groupRequestDB.Page(ctx, userID, pagination) } @@ -426,7 +429,7 @@ func (g *groupDatabase) CountRangeEverydayTotal(ctx context.Context, start time. return g.groupDB.CountRangeEverydayTotal(ctx, start, end) } -func (g *groupDatabase) FindGroupRequests(ctx context.Context, groupID string, userIDs []string) ([]*relationtb.GroupRequestModel, error) { +func (g *groupDatabase) FindGroupRequests(ctx context.Context, groupID string, userIDs []string) ([]*model.GroupRequest, error) { return g.groupRequestDB.FindGroupRequests(ctx, groupID, userIDs) } @@ -434,9 +437,9 @@ func (g *groupDatabase) DeleteGroupMemberHash(ctx context.Context, groupIDs []st if len(groupIDs) == 0 { return nil } - c := g.cache.NewCache() + c := g.cache.CloneGroupCache() for _, groupID := range groupIDs { c = c.DelGroupMembersHash(groupID) } - return c.ExecDel(ctx) + return c.ChainExecDel(ctx) } diff --git a/pkg/common/db/controller/msg.go b/pkg/common/storage/controller/msg.go similarity index 93% rename from pkg/common/db/controller/msg.go rename to pkg/common/storage/controller/msg.go index c0a013c175..ce107e9237 100644 --- a/pkg/common/db/controller/msg.go +++ b/pkg/common/storage/controller/msg.go @@ -18,14 +18,15 @@ import ( "context" "encoding/json" "errors" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/database" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model" "strings" "time" "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/convert" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" "github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/cache" "github.com/openimsdk/protocol/constant" pbmsg "github.com/openimsdk/protocol/msg" "github.com/openimsdk/protocol/sdkws" @@ -48,7 +49,7 @@ type CommonMsgDatabase interface { // BatchInsertChat2DB inserts a batch of messages into the database for a specific conversation. BatchInsertChat2DB(ctx context.Context, conversationID string, msgs []*sdkws.MsgData, currentMaxSeq int64) error // RevokeMsg revokes a message in a conversation. - RevokeMsg(ctx context.Context, conversationID string, seq int64, revoke *relation.RevokeModel) error + RevokeMsg(ctx context.Context, conversationID string, seq int64, revoke *model.RevokeModel) error // MarkSingleChatMsgsAsRead marks messages as read for a single chat by sequence numbers. MarkSingleChatMsgsAsRead(ctx context.Context, userID string, conversationID string, seqs []int64) error // DeleteMessagesFromCache deletes message caches from Redis by sequence numbers. @@ -101,16 +102,16 @@ type CommonMsgDatabase interface { MsgToPushMQ(ctx context.Context, key, conversarionID string, msg2mq *sdkws.MsgData) (int32, int64, error) MsgToMongoMQ(ctx context.Context, key, conversarionID string, msgs []*sdkws.MsgData, lastSeq int64) error - RangeUserSendCount(ctx context.Context, start time.Time, end time.Time, group bool, ase bool, pageNumber int32, showNumber int32) (msgCount int64, userCount int64, users []*relation.UserCount, dateCount map[string]int64, err error) - RangeGroupSendCount(ctx context.Context, start time.Time, end time.Time, ase bool, pageNumber int32, showNumber int32) (msgCount int64, userCount int64, groups []*relation.GroupCount, dateCount map[string]int64, err error) + RangeUserSendCount(ctx context.Context, start time.Time, end time.Time, group bool, ase bool, pageNumber int32, showNumber int32) (msgCount int64, userCount int64, users []*model.UserCount, dateCount map[string]int64, err error) + RangeGroupSendCount(ctx context.Context, start time.Time, end time.Time, ase bool, pageNumber int32, showNumber int32) (msgCount int64, userCount int64, groups []*model.GroupCount, dateCount map[string]int64, err error) ConvertMsgsDocLen(ctx context.Context, conversationIDs []string) // clear msg - GetBeforeMsg(ctx context.Context, ts int64, limit int) ([]*relation.MsgDocModel, error) - DeleteDocMsgBefore(ctx context.Context, ts int64, doc *relation.MsgDocModel) ([]int, error) + GetBeforeMsg(ctx context.Context, ts int64, limit int) ([]*model.MsgDocModel, error) + DeleteDocMsgBefore(ctx context.Context, ts int64, doc *model.MsgDocModel) ([]int, error) } -func NewCommonMsgDatabase(msgDocModel relation.MsgDocModelInterface, msg cache.MsgCache, seq cache.SeqCache, kafkaConf *config.Kafka) (CommonMsgDatabase, error) { +func NewCommonMsgDatabase(msgDocModel database.Msg, msg cache.MsgCache, seq cache.SeqCache, kafkaConf *config.Kafka) (CommonMsgDatabase, error) { conf, err := kafka.BuildProducerConfig(*kafkaConf.Build()) if err != nil { return nil, err @@ -138,7 +139,7 @@ func NewCommonMsgDatabase(msgDocModel relation.MsgDocModelInterface, msg cache.M } //func InitCommonMsgDatabase(rdb redis.UniversalClient, database *mongo.Database, config *tools.CronTaskConfig) (CommonMsgDatabase, error) { -// msgDocModel, err := mgo.NewMsgMongo(database) +// msgDocModel, err := database.NewMsgMongo(database) // if err != nil { // return nil, err // } @@ -149,8 +150,8 @@ func NewCommonMsgDatabase(msgDocModel relation.MsgDocModelInterface, msg cache.M //} type commonMsgDatabase struct { - msgDocDatabase relation.MsgDocModelInterface - msgTable relation.MsgDocModel + msgDocDatabase database.Msg + msgTable model.MsgDocModel msg cache.MsgCache seq cache.SeqCache producer *kafka.Producer @@ -199,13 +200,13 @@ func (db *commonMsgDatabase) BatchInsertBlock(ctx context.Context, conversationI var ok bool switch key { case updateKeyMsg: - var msg *relation.MsgDataModel - msg, ok = field.(*relation.MsgDataModel) + var msg *model.MsgDataModel + msg, ok = field.(*model.MsgDataModel) if msg != nil && msg.Seq != firstSeq+int64(i) { return errs.ErrInternalServer.WrapMsg("seq is invalid") } case updateKeyRevoke: - _, ok = field.(*relation.RevokeModel) + _, ok = field.(*model.RevokeModel) default: return errs.ErrInternalServer.WrapMsg("key is invalid") } @@ -245,9 +246,9 @@ func (db *commonMsgDatabase) BatchInsertBlock(ctx context.Context, conversationI continue // The current data has been updated, skip the current data } } - doc := relation.MsgDocModel{ + doc := model.MsgDocModel{ DocID: db.msgTable.GetDocID(conversationID, seq), - Msg: make([]*relation.MsgInfoModel, num), + Msg: make([]*model.MsgInfoModel, num), } var insert int // Inserted data number for j := i; j < len(fields); j++ { @@ -258,21 +259,21 @@ func (db *commonMsgDatabase) BatchInsertBlock(ctx context.Context, conversationI insert++ switch key { case updateKeyMsg: - doc.Msg[db.msgTable.GetMsgIndex(seq)] = &relation.MsgInfoModel{ - Msg: fields[j].(*relation.MsgDataModel), + doc.Msg[db.msgTable.GetMsgIndex(seq)] = &model.MsgInfoModel{ + Msg: fields[j].(*model.MsgDataModel), } case updateKeyRevoke: - doc.Msg[db.msgTable.GetMsgIndex(seq)] = &relation.MsgInfoModel{ - Revoke: fields[j].(*relation.RevokeModel), + doc.Msg[db.msgTable.GetMsgIndex(seq)] = &model.MsgInfoModel{ + Revoke: fields[j].(*model.RevokeModel), } } } - for i, model := range doc.Msg { - if model == nil { - model = &relation.MsgInfoModel{} - doc.Msg[i] = model + for i, msgInfo := range doc.Msg { + if msgInfo == nil { + msgInfo = &model.MsgInfoModel{} + doc.Msg[i] = msgInfo } - if model.DelList == nil { + if msgInfo.DelList == nil { doc.Msg[i].DelList = []string{} } } @@ -299,9 +300,9 @@ func (db *commonMsgDatabase) BatchInsertChat2DB(ctx context.Context, conversatio if msg == nil { continue } - var offlinePushModel *relation.OfflinePushModel + var offlinePushModel *model.OfflinePushModel if msg.OfflinePushInfo != nil { - offlinePushModel = &relation.OfflinePushModel{ + offlinePushModel = &model.OfflinePushModel{ Title: msg.OfflinePushInfo.Title, Desc: msg.OfflinePushInfo.Desc, Ex: msg.OfflinePushInfo.Ex, @@ -309,7 +310,7 @@ func (db *commonMsgDatabase) BatchInsertChat2DB(ctx context.Context, conversatio IOSBadgeCount: msg.OfflinePushInfo.IOSBadgeCount, } } - msgs[i] = &relation.MsgDataModel{ + msgs[i] = &model.MsgDataModel{ SendID: msg.SendID, RecvID: msg.RecvID, GroupID: msg.GroupID, @@ -336,7 +337,7 @@ func (db *commonMsgDatabase) BatchInsertChat2DB(ctx context.Context, conversatio return db.BatchInsertBlock(ctx, conversationID, msgs, updateKeyMsg, msgList[0].Seq) } -func (db *commonMsgDatabase) RevokeMsg(ctx context.Context, conversationID string, seq int64, revoke *relation.RevokeModel) error { +func (db *commonMsgDatabase) RevokeMsg(ctx context.Context, conversationID string, seq int64, revoke *model.RevokeModel) error { return db.BatchInsertBlock(ctx, conversationID, []any{revoke}, updateKeyRevoke, seq) } @@ -366,7 +367,7 @@ func (db *commonMsgDatabase) DelUserDeleteMsgsList(ctx context.Context, conversa func (db *commonMsgDatabase) BatchInsertChat2Cache(ctx context.Context, conversationID string, msgs []*sdkws.MsgData) (seq int64, isNew bool, err error) { currentMaxSeq, err := db.seq.GetMaxSeq(ctx, conversationID) if err != nil && errs.Unwrap(err) != redis.Nil { - log.ZError(ctx, "db.seq.GetMaxSeq", err) + log.ZError(ctx, "storage.seq.GetMaxSeq", err) return 0, false, err } lenList := len(msgs) @@ -397,7 +398,7 @@ func (db *commonMsgDatabase) BatchInsertChat2Cache(ctx context.Context, conversa err = db.seq.SetMaxSeq(ctx, conversationID, currentMaxSeq) if err != nil { - log.ZError(ctx, "db.seq.SetMaxSeq error", err, "conversationID", conversationID) + log.ZError(ctx, "storage.seq.SetMaxSeq error", err, "conversationID", conversationID) prommetrics.SeqSetFailedCounter.Inc() } @@ -423,7 +424,7 @@ func (db *commonMsgDatabase) getMsgBySeqs(ctx context.Context, userID, conversat return totalMsgs, nil } -func (db *commonMsgDatabase) handlerDBMsg(ctx context.Context, cache map[int64][]*relation.MsgInfoModel, userID, conversationID string, msg *relation.MsgInfoModel) { +func (db *commonMsgDatabase) handlerDBMsg(ctx context.Context, cache map[int64][]*model.MsgInfoModel, userID, conversationID string, msg *model.MsgInfoModel) { if msg.IsRead { msg.Msg.IsRead = true } @@ -445,7 +446,7 @@ func (db *commonMsgDatabase) handlerDBMsg(ctx context.Context, cache map[int64][ if quoteMsg.QuoteMessage == nil || quoteMsg.QuoteMessage.ContentType == constant.MsgRevokeNotification { return } - var msgs []*relation.MsgInfoModel + var msgs []*model.MsgInfoModel if v, ok := cache[quoteMsg.QuoteMessage.Seq]; ok { msgs = v } else { @@ -479,12 +480,12 @@ func (db *commonMsgDatabase) handlerDBMsg(ctx context.Context, cache map[int64][ } } -func (db *commonMsgDatabase) findMsgInfoBySeq(ctx context.Context, userID, docID string, conversationID string, seqs []int64) (totalMsgs []*relation.MsgInfoModel, err error) { +func (db *commonMsgDatabase) findMsgInfoBySeq(ctx context.Context, userID, docID string, conversationID string, seqs []int64) (totalMsgs []*model.MsgInfoModel, err error) { msgs, err := db.msgDocDatabase.GetMsgBySeqIndexIn1Doc(ctx, userID, docID, seqs) if err != nil { return nil, err } - tempCache := make(map[int64][]*relation.MsgInfoModel) + tempCache := make(map[int64][]*model.MsgInfoModel) for _, msg := range msgs { db.handlerDBMsg(ctx, tempCache, userID, conversationID, msg) } @@ -636,7 +637,7 @@ func (db *commonMsgDatabase) GetMsgBySeqsRange(ctx context.Context, userID strin if len(failedSeqs) != 0 { log.ZDebug(ctx, "msgs not exist in redis", "seqs", failedSeqs) } - // get from cache or db + // get from cache or storage if len(failedSeqs) > 0 { mongoMsgs, err := db.getMsgBySeqsRange(ctx, userID, conversationID, failedSeqs, begin, end) @@ -678,7 +679,7 @@ func (db *commonMsgDatabase) GetMsgBySeqs(ctx context.Context, userID string, co log.ZError(ctx, "get message from redis exception", err, "failedSeqs", failedSeqs, "conversationID", conversationID) } } - log.ZDebug(ctx, "db.seq.GetMessagesBySeq", "userID", userID, "conversationID", conversationID, "seqs", + log.ZDebug(ctx, "storage.seq.GetMessagesBySeq", "userID", userID, "conversationID", conversationID, "seqs", seqs, "len(successMsgs)", len(successMsgs), "failedSeqs", failedSeqs) if len(failedSeqs) > 0 { @@ -720,7 +721,7 @@ func (db *commonMsgDatabase) UserMsgsDestruct(ctx context.Context, userID string msgDocModel, err := db.msgDocDatabase.GetMsgDocModelByIndex(ctx, conversationID, index, 1) if err != nil || msgDocModel.DocID == "" { if err != nil { - if err == relation.ErrMsgListNotExist { + if err == model.ErrMsgListNotExist { log.ZDebug(ctx, "not doc find", "conversationID", conversationID, "userID", userID, "index", index) } else { log.ZError(ctx, "deleteMsgRecursion GetUserMsgListByIndex failed", err, "conversationID", conversationID, "index", index) @@ -787,7 +788,7 @@ func (db *commonMsgDatabase) deleteMsgRecursion(ctx context.Context, conversatio msgDocModel, err := db.msgDocDatabase.GetMsgDocModelByIndex(ctx, conversationID, index, 1) if err != nil || msgDocModel.DocID == "" { if err != nil { - if err == relation.ErrMsgListNotExist { + if err == model.ErrMsgListNotExist { log.ZDebug(ctx, "deleteMsgRecursion ErrMsgListNotExist", "conversationID", conversationID, "index:", index) } else { log.ZError(ctx, "deleteMsgRecursion GetUserMsgListByIndex failed", err, "conversationID", conversationID, "index", index) @@ -1005,7 +1006,7 @@ func (db *commonMsgDatabase) RangeUserSendCount( ase bool, pageNumber int32, showNumber int32, -) (msgCount int64, userCount int64, users []*relation.UserCount, dateCount map[string]int64, err error) { +) (msgCount int64, userCount int64, users []*model.UserCount, dateCount map[string]int64, err error) { return db.msgDocDatabase.RangeUserSendCount(ctx, start, end, group, ase, pageNumber, showNumber) } @@ -1016,7 +1017,7 @@ func (db *commonMsgDatabase) RangeGroupSendCount( ase bool, pageNumber int32, showNumber int32, -) (msgCount int64, userCount int64, groups []*relation.GroupCount, dateCount map[string]int64, err error) { +) (msgCount int64, userCount int64, groups []*model.GroupCount, dateCount map[string]int64, err error) { return db.msgDocDatabase.RangeGroupSendCount(ctx, start, end, ase, pageNumber, showNumber) } @@ -1054,11 +1055,11 @@ func (db *commonMsgDatabase) ConvertMsgsDocLen(ctx context.Context, conversation db.msgDocDatabase.ConvertMsgsDocLen(ctx, conversationIDs) } -func (db *commonMsgDatabase) GetBeforeMsg(ctx context.Context, ts int64, limit int) ([]*relation.MsgDocModel, error) { +func (db *commonMsgDatabase) GetBeforeMsg(ctx context.Context, ts int64, limit int) ([]*model.MsgDocModel, error) { return db.msgDocDatabase.GetBeforeMsg(ctx, ts, limit) } -func (db *commonMsgDatabase) DeleteDocMsgBefore(ctx context.Context, ts int64, doc *relation.MsgDocModel) ([]int, error) { +func (db *commonMsgDatabase) DeleteDocMsgBefore(ctx context.Context, ts int64, doc *model.MsgDocModel) ([]int, error) { var notNull int index := make([]int, 0, len(doc.Msg)) for i, message := range doc.Msg { @@ -1084,14 +1085,14 @@ func (db *commonMsgDatabase) DeleteDocMsgBefore(ctx context.Context, ts int64, d } } -//func (db *commonMsgDatabase) ClearMsg(ctx context.Context, ts int64) (err error) { +//func (storage *commonMsgDatabase) ClearMsg(ctx context.Context, ts int64) (err error) { // var ( // docNum int // msgNum int // start = time.Now() // ) // for { -// msgs, err := db.msgDocDatabase.GetBeforeMsg(ctx, ts, 100) +// msgs, err := storage.msgDocDatabase.GetBeforeMsg(ctx, ts, 100) // if err != nil { // return err // } @@ -1099,7 +1100,7 @@ func (db *commonMsgDatabase) DeleteDocMsgBefore(ctx context.Context, ts int64, d // return nil // } // for _, msg := range msgs { -// num, err := db.deleteOneMsg(ctx, ts, msg) +// num, err := storage.deleteOneMsg(ctx, ts, msg) // if err != nil { // return err // } diff --git a/pkg/common/db/controller/push.go b/pkg/common/storage/controller/push.go similarity index 94% rename from pkg/common/db/controller/push.go rename to pkg/common/storage/controller/push.go index 390d70b7ba..199a0ba678 100644 --- a/pkg/common/db/controller/push.go +++ b/pkg/common/storage/controller/push.go @@ -17,7 +17,7 @@ package controller import ( "context" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/cache" ) type PushDatabase interface { diff --git a/pkg/common/db/controller/s3.go b/pkg/common/storage/controller/s3.go similarity index 84% rename from pkg/common/db/controller/s3.go rename to pkg/common/storage/controller/s3.go index eae47c4212..b0ad612038 100644 --- a/pkg/common/db/controller/s3.go +++ b/pkg/common/storage/controller/s3.go @@ -16,11 +16,13 @@ package controller import ( "context" + redis2 "github.com/openimsdk/open-im-server/v3/pkg/common/storage/cache/redis" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/database" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model" "path/filepath" "time" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/cache" "github.com/openimsdk/tools/s3" "github.com/openimsdk/tools/s3/cont" "github.com/redis/go-redis/v9" @@ -33,15 +35,15 @@ type S3Database interface { InitiateMultipartUpload(ctx context.Context, hash string, size int64, expire time.Duration, maxParts int) (*cont.InitiateUploadResult, error) CompleteMultipartUpload(ctx context.Context, uploadID string, parts []string) (*cont.UploadResult, error) AccessURL(ctx context.Context, name string, expire time.Duration, opt *s3.AccessURLOption) (time.Time, string, error) - SetObject(ctx context.Context, info *relation.ObjectModel) error + SetObject(ctx context.Context, info *model.Object) error StatObject(ctx context.Context, name string) (*s3.ObjectInfo, error) FormData(ctx context.Context, name string, size int64, contentType string, duration time.Duration) (*s3.FormData, error) } -func NewS3Database(rdb redis.UniversalClient, s3 s3.Interface, obj relation.ObjectInfoModelInterface) S3Database { +func NewS3Database(rdb redis.UniversalClient, s3 s3.Interface, obj database.ObjectInfo) S3Database { return &s3Database{ - s3: cont.New(cache.NewS3Cache(rdb, s3), s3), - cache: cache.NewObjectCacheRedis(rdb, obj), + s3: cont.New(redis2.NewS3Cache(rdb, s3), s3), + cache: redis2.NewObjectCacheRedis(rdb, obj), db: obj, } } @@ -49,7 +51,7 @@ func NewS3Database(rdb redis.UniversalClient, s3 s3.Interface, obj relation.Obje type s3Database struct { s3 *cont.Controller cache cache.ObjectCache - db relation.ObjectInfoModelInterface + db database.ObjectInfo } func (s *s3Database) PartSize(ctx context.Context, size int64) (int64, error) { @@ -72,12 +74,12 @@ func (s *s3Database) CompleteMultipartUpload(ctx context.Context, uploadID strin return s.s3.CompleteUpload(ctx, uploadID, parts) } -func (s *s3Database) SetObject(ctx context.Context, info *relation.ObjectModel) error { +func (s *s3Database) SetObject(ctx context.Context, info *model.Object) error { info.Engine = s.s3.Engine() if err := s.db.SetObject(ctx, info); err != nil { return err } - return s.cache.DelObjectName(info.Engine, info.Name).ExecDel(ctx) + return s.cache.DelObjectName(info.Engine, info.Name).ChainExecDel(ctx) } func (s *s3Database) AccessURL(ctx context.Context, name string, expire time.Duration, opt *s3.AccessURLOption) (time.Time, string, error) { diff --git a/pkg/common/db/controller/third.go b/pkg/common/storage/controller/third.go similarity index 80% rename from pkg/common/db/controller/third.go rename to pkg/common/storage/controller/third.go index be618843fd..344501466b 100644 --- a/pkg/common/db/controller/third.go +++ b/pkg/common/storage/controller/third.go @@ -16,10 +16,11 @@ package controller import ( "context" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/database" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model" "time" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/cache" "github.com/openimsdk/tools/db/pagination" ) @@ -27,15 +28,15 @@ type ThirdDatabase interface { FcmUpdateToken(ctx context.Context, account string, platformID int, fcmToken string, expireTime int64) error SetAppBadge(ctx context.Context, userID string, value int) error // about log for debug - UploadLogs(ctx context.Context, logs []*relation.LogModel) error + UploadLogs(ctx context.Context, logs []*model.Log) error DeleteLogs(ctx context.Context, logID []string, userID string) error - SearchLogs(ctx context.Context, keyword string, start time.Time, end time.Time, pagination pagination.Pagination) (int64, []*relation.LogModel, error) - GetLogs(ctx context.Context, LogIDs []string, userID string) ([]*relation.LogModel, error) + SearchLogs(ctx context.Context, keyword string, start time.Time, end time.Time, pagination pagination.Pagination) (int64, []*model.Log, error) + GetLogs(ctx context.Context, LogIDs []string, userID string) ([]*model.Log, error) } type thirdDatabase struct { cache cache.ThirdCache - logdb relation.LogInterface + logdb database.Log } // DeleteLogs implements ThirdDatabase. @@ -44,21 +45,21 @@ func (t *thirdDatabase) DeleteLogs(ctx context.Context, logID []string, userID s } // GetLogs implements ThirdDatabase. -func (t *thirdDatabase) GetLogs(ctx context.Context, LogIDs []string, userID string) ([]*relation.LogModel, error) { +func (t *thirdDatabase) GetLogs(ctx context.Context, LogIDs []string, userID string) ([]*model.Log, error) { return t.logdb.Get(ctx, LogIDs, userID) } // SearchLogs implements ThirdDatabase. -func (t *thirdDatabase) SearchLogs(ctx context.Context, keyword string, start time.Time, end time.Time, pagination pagination.Pagination) (int64, []*relation.LogModel, error) { +func (t *thirdDatabase) SearchLogs(ctx context.Context, keyword string, start time.Time, end time.Time, pagination pagination.Pagination) (int64, []*model.Log, error) { return t.logdb.Search(ctx, keyword, start, end, pagination) } // UploadLogs implements ThirdDatabase. -func (t *thirdDatabase) UploadLogs(ctx context.Context, logs []*relation.LogModel) error { +func (t *thirdDatabase) UploadLogs(ctx context.Context, logs []*model.Log) error { return t.logdb.Create(ctx, logs) } -func NewThirdDatabase(cache cache.ThirdCache, logdb relation.LogInterface) ThirdDatabase { +func NewThirdDatabase(cache cache.ThirdCache, logdb database.Log) ThirdDatabase { return &thirdDatabase{cache: cache, logdb: logdb} } diff --git a/pkg/common/db/controller/user.go b/pkg/common/storage/controller/user.go similarity index 82% rename from pkg/common/db/controller/user.go rename to pkg/common/storage/controller/user.go index b2aba41faa..09dc2db22b 100644 --- a/pkg/common/db/controller/user.go +++ b/pkg/common/storage/controller/user.go @@ -16,6 +16,8 @@ package controller import ( "context" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/database" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model" "github.com/openimsdk/tools/db/pagination" "github.com/openimsdk/tools/db/tx" "github.com/openimsdk/tools/utils/datautil" @@ -24,37 +26,36 @@ import ( "github.com/openimsdk/protocol/user" "github.com/openimsdk/tools/errs" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/cache" ) type UserDatabase interface { // FindWithError Get the information of the specified user. If the userID is not found, it will also return an error - FindWithError(ctx context.Context, userIDs []string) (users []*relation.UserModel, err error) + FindWithError(ctx context.Context, userIDs []string) (users []*model.User, err error) // Find Get the information of the specified user If the userID is not found, no error will be returned - Find(ctx context.Context, userIDs []string) (users []*relation.UserModel, err error) + Find(ctx context.Context, userIDs []string) (users []*model.User, err error) // Find userInfo By Nickname - FindByNickname(ctx context.Context, nickname string) (users []*relation.UserModel, err error) + FindByNickname(ctx context.Context, nickname string) (users []*model.User, err error) // Find notificationAccounts - FindNotification(ctx context.Context, level int64) (users []*relation.UserModel, err error) - // Create Insert multiple external guarantees that the userID is not repeated and does not exist in the db - Create(ctx context.Context, users []*relation.UserModel) (err error) + FindNotification(ctx context.Context, level int64) (users []*model.User, err error) + // Create Insert multiple external guarantees that the userID is not repeated and does not exist in the storage + Create(ctx context.Context, users []*model.User) (err error) // UpdateByMap update (zero value) external guarantee userID exists UpdateByMap(ctx context.Context, userID string, args map[string]any) (err error) // FindUser - PageFindUser(ctx context.Context, level1 int64, level2 int64, pagination pagination.Pagination) (count int64, users []*relation.UserModel, err error) + PageFindUser(ctx context.Context, level1 int64, level2 int64, pagination pagination.Pagination) (count int64, users []*model.User, err error) // FindUser with keyword - PageFindUserWithKeyword(ctx context.Context, level1 int64, level2 int64, userID string, nickName string, pagination pagination.Pagination) (count int64, users []*relation.UserModel, err error) + PageFindUserWithKeyword(ctx context.Context, level1 int64, level2 int64, userID string, nickName string, pagination pagination.Pagination) (count int64, users []*model.User, err error) // Page If not found, no error is returned - Page(ctx context.Context, pagination pagination.Pagination) (count int64, users []*relation.UserModel, err error) + Page(ctx context.Context, pagination pagination.Pagination) (count int64, users []*model.User, err error) // IsExist true as long as one exists IsExist(ctx context.Context, userIDs []string) (exist bool, err error) // GetAllUserID Get all user IDs GetAllUserID(ctx context.Context, pagination pagination.Pagination) (int64, []string, error) // Get user by userID - GetUserByID(ctx context.Context, userID string) (user *relation.UserModel, err error) - // InitOnce Inside the function, first query whether it exists in the db, if it exists, do nothing; if it does not exist, insert it - InitOnce(ctx context.Context, users []*relation.UserModel) (err error) + GetUserByID(ctx context.Context, userID string) (user *model.User, err error) + // InitOnce Inside the function, first query whether it exists in the storage, if it exists, do nothing; if it does not exist, insert it + InitOnce(ctx context.Context, users []*model.User) (err error) // CountTotal Get the total number of users CountTotal(ctx context.Context, before *time.Time) (int64, error) // CountRangeEverydayTotal Get the user increment in the range @@ -82,18 +83,18 @@ type UserDatabase interface { type userDatabase struct { tx tx.Tx - userDB relation.UserModelInterface + userDB database.User cache cache.UserCache - mongoDB relation.SubscribeUserModelInterface + mongoDB database.SubscribeUser } -func NewUserDatabase(userDB relation.UserModelInterface, cache cache.UserCache, tx tx.Tx, mongoDB relation.SubscribeUserModelInterface) UserDatabase { +func NewUserDatabase(userDB database.User, cache cache.UserCache, tx tx.Tx, mongoDB database.SubscribeUser) UserDatabase { return &userDatabase{userDB: userDB, cache: cache, tx: tx, mongoDB: mongoDB} } -func (u *userDatabase) InitOnce(ctx context.Context, users []*relation.UserModel) error { +func (u *userDatabase) InitOnce(ctx context.Context, users []*model.User) error { // Extract user IDs from the given user models. - userIDs := datautil.Slice(users, func(e *relation.UserModel) string { + userIDs := datautil.Slice(users, func(e *model.User) string { return e.UserID }) @@ -104,7 +105,7 @@ func (u *userDatabase) InitOnce(ctx context.Context, users []*relation.UserModel } // Determine which users are missing from the database. - missingUsers := datautil.SliceAnySub(users, existingUsers, func(e *relation.UserModel) string { + missingUsers := datautil.SliceAnySub(users, existingUsers, func(e *model.User) string { return e.UserID }) @@ -119,7 +120,7 @@ func (u *userDatabase) InitOnce(ctx context.Context, users []*relation.UserModel } // FindWithError Get the information of the specified user and return an error if the userID is not found. -func (u *userDatabase) FindWithError(ctx context.Context, userIDs []string) (users []*relation.UserModel, err error) { +func (u *userDatabase) FindWithError(ctx context.Context, userIDs []string) (users []*model.User, err error) { users, err = u.cache.GetUsersInfo(ctx, userIDs) if err != nil { return @@ -131,27 +132,27 @@ func (u *userDatabase) FindWithError(ctx context.Context, userIDs []string) (use } // Find Get the information of the specified user. If the userID is not found, no error will be returned. -func (u *userDatabase) Find(ctx context.Context, userIDs []string) (users []*relation.UserModel, err error) { +func (u *userDatabase) Find(ctx context.Context, userIDs []string) (users []*model.User, err error) { return u.cache.GetUsersInfo(ctx, userIDs) } -func (u *userDatabase) FindByNickname(ctx context.Context, nickname string) (users []*relation.UserModel, err error) { +func (u *userDatabase) FindByNickname(ctx context.Context, nickname string) (users []*model.User, err error) { return u.userDB.TakeByNickname(ctx, nickname) } -func (u *userDatabase) FindNotification(ctx context.Context, level int64) (users []*relation.UserModel, err error) { +func (u *userDatabase) FindNotification(ctx context.Context, level int64) (users []*model.User, err error) { return u.userDB.TakeNotification(ctx, level) } -// Create Insert multiple external guarantees that the userID is not repeated and does not exist in the db. -func (u *userDatabase) Create(ctx context.Context, users []*relation.UserModel) (err error) { +// Create Insert multiple external guarantees that the userID is not repeated and does not exist in the storage. +func (u *userDatabase) Create(ctx context.Context, users []*model.User) (err error) { return u.tx.Transaction(ctx, func(ctx context.Context) error { if err = u.userDB.Create(ctx, users); err != nil { return err } - return u.cache.DelUsersInfo(datautil.Slice(users, func(e *relation.UserModel) string { + return u.cache.DelUsersInfo(datautil.Slice(users, func(e *model.User) string { return e.UserID - })...).ExecDel(ctx) + })...).ChainExecDel(ctx) }) } @@ -161,20 +162,20 @@ func (u *userDatabase) UpdateByMap(ctx context.Context, userID string, args map[ if err := u.userDB.UpdateByMap(ctx, userID, args); err != nil { return err } - return u.cache.DelUsersInfo(userID).ExecDel(ctx) + return u.cache.DelUsersInfo(userID).ChainExecDel(ctx) }) } // Page Gets, returns no error if not found. -func (u *userDatabase) Page(ctx context.Context, pagination pagination.Pagination) (count int64, users []*relation.UserModel, err error) { +func (u *userDatabase) Page(ctx context.Context, pagination pagination.Pagination) (count int64, users []*model.User, err error) { return u.userDB.Page(ctx, pagination) } -func (u *userDatabase) PageFindUser(ctx context.Context, level1 int64, level2 int64, pagination pagination.Pagination) (count int64, users []*relation.UserModel, err error) { +func (u *userDatabase) PageFindUser(ctx context.Context, level1 int64, level2 int64, pagination pagination.Pagination) (count int64, users []*model.User, err error) { return u.userDB.PageFindUser(ctx, level1, level2, pagination) } -func (u *userDatabase) PageFindUserWithKeyword(ctx context.Context, level1 int64, level2 int64, userID, nickName string, pagination pagination.Pagination) (count int64, users []*relation.UserModel, err error) { +func (u *userDatabase) PageFindUserWithKeyword(ctx context.Context, level1 int64, level2 int64, userID, nickName string, pagination pagination.Pagination) (count int64, users []*model.User, err error) { return u.userDB.PageFindUserWithKeyword(ctx, level1, level2, userID, nickName, pagination) } @@ -195,7 +196,7 @@ func (u *userDatabase) GetAllUserID(ctx context.Context, pagination pagination.P return u.userDB.GetAllUserID(ctx, pagination) } -func (u *userDatabase) GetUserByID(ctx context.Context, userID string) (user *relation.UserModel, err error) { +func (u *userDatabase) GetUserByID(ctx context.Context, userID string) (user *model.User, err error) { return u.userDB.Take(ctx, userID) } diff --git a/pkg/common/db/table/relation/black.go b/pkg/common/storage/database/black.go similarity index 51% rename from pkg/common/db/table/relation/black.go rename to pkg/common/storage/database/black.go index f5d1cb2369..b53fdd14dc 100644 --- a/pkg/common/db/table/relation/black.go +++ b/pkg/common/storage/database/black.go @@ -12,32 +12,20 @@ // See the License for the specific language governing permissions and // limitations under the License. -package relation +package database import ( "context" - "time" - + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model" "github.com/openimsdk/tools/db/pagination" ) -type BlackModel struct { - OwnerUserID string `bson:"owner_user_id"` - BlockUserID string `bson:"block_user_id"` - CreateTime time.Time `bson:"create_time"` - AddSource int32 `bson:"add_source"` - OperatorUserID string `bson:"operator_user_id"` - Ex string `bson:"ex"` -} - -type BlackModelInterface interface { - Create(ctx context.Context, blacks []*BlackModel) (err error) - Delete(ctx context.Context, blacks []*BlackModel) (err error) - // UpdateByMap(ctx context.Context, ownerUserID, blockUserID string, args map[string]any) (err error) - // Update(ctx context.Context, blacks []*BlackModel) (err error) - Find(ctx context.Context, blacks []*BlackModel) (blackList []*BlackModel, err error) - Take(ctx context.Context, ownerUserID, blockUserID string) (black *BlackModel, err error) - FindOwnerBlacks(ctx context.Context, ownerUserID string, pagination pagination.Pagination) (total int64, blacks []*BlackModel, err error) - FindOwnerBlackInfos(ctx context.Context, ownerUserID string, userIDs []string) (blacks []*BlackModel, err error) +type Black interface { + Create(ctx context.Context, blacks []*model.Black) (err error) + Delete(ctx context.Context, blacks []*model.Black) (err error) + Find(ctx context.Context, blacks []*model.Black) (blackList []*model.Black, err error) + Take(ctx context.Context, ownerUserID, blockUserID string) (black *model.Black, err error) + FindOwnerBlacks(ctx context.Context, ownerUserID string, pagination pagination.Pagination) (total int64, blacks []*model.Black, err error) + FindOwnerBlackInfos(ctx context.Context, ownerUserID string, userIDs []string) (blacks []*model.Black, err error) FindBlackUserIDs(ctx context.Context, ownerUserID string) (blackUserIDs []string, err error) } diff --git a/pkg/common/db/table/relation/conversation.go b/pkg/common/storage/database/conversation.go similarity index 56% rename from pkg/common/db/table/relation/conversation.go rename to pkg/common/storage/database/conversation.go index 4990c96c60..46aa02d98e 100644 --- a/pkg/common/db/table/relation/conversation.go +++ b/pkg/common/storage/database/conversation.go @@ -12,53 +12,31 @@ // See the License for the specific language governing permissions and // limitations under the License. -package relation +package database import ( "context" - "time" - + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model" "github.com/openimsdk/tools/db/pagination" ) -type ConversationModel struct { - OwnerUserID string `bson:"owner_user_id"` - ConversationID string `bson:"conversation_id"` - ConversationType int32 `bson:"conversation_type"` - UserID string `bson:"user_id"` - GroupID string `bson:"group_id"` - RecvMsgOpt int32 `bson:"recv_msg_opt"` - IsPinned bool `bson:"is_pinned"` - IsPrivateChat bool `bson:"is_private_chat"` - BurnDuration int32 `bson:"burn_duration"` - GroupAtType int32 `bson:"group_at_type"` - AttachedInfo string `bson:"attached_info"` - Ex string `bson:"ex"` - MaxSeq int64 `bson:"max_seq"` - MinSeq int64 `bson:"min_seq"` - CreateTime time.Time `bson:"create_time"` - IsMsgDestruct bool `bson:"is_msg_destruct"` - MsgDestructTime int64 `bson:"msg_destruct_time"` - LatestMsgDestructTime time.Time `bson:"latest_msg_destruct_time"` -} - -type ConversationModelInterface interface { - Create(ctx context.Context, conversations []*ConversationModel) (err error) +type Conversation interface { + Create(ctx context.Context, conversations []*model.Conversation) (err error) Delete(ctx context.Context, groupIDs []string) (err error) UpdateByMap(ctx context.Context, userIDs []string, conversationID string, args map[string]any) (rows int64, err error) - Update(ctx context.Context, conversation *ConversationModel) (err error) - Find(ctx context.Context, ownerUserID string, conversationIDs []string) (conversations []*ConversationModel, err error) + Update(ctx context.Context, conversation *model.Conversation) (err error) + Find(ctx context.Context, ownerUserID string, conversationIDs []string) (conversations []*model.Conversation, err error) FindUserID(ctx context.Context, userIDs []string, conversationIDs []string) ([]string, error) FindUserIDAllConversationID(ctx context.Context, userID string) ([]string, error) - Take(ctx context.Context, userID, conversationID string) (conversation *ConversationModel, err error) + Take(ctx context.Context, userID, conversationID string) (conversation *model.Conversation, err error) FindConversationID(ctx context.Context, userID string, conversationIDs []string) (existConversationID []string, err error) - FindUserIDAllConversations(ctx context.Context, userID string) (conversations []*ConversationModel, err error) + FindUserIDAllConversations(ctx context.Context, userID string) (conversations []*model.Conversation, err error) FindRecvMsgUserIDs(ctx context.Context, conversationID string, recvOpts []int) ([]string, error) GetUserRecvMsgOpt(ctx context.Context, ownerUserID, conversationID string) (opt int, err error) GetAllConversationIDs(ctx context.Context) ([]string, error) GetAllConversationIDsNumber(ctx context.Context) (int64, error) PageConversationIDs(ctx context.Context, pagination pagination.Pagination) (conversationIDs []string, err error) - GetConversationsByConversationID(ctx context.Context, conversationIDs []string) ([]*ConversationModel, error) - GetConversationIDsNeedDestruct(ctx context.Context) ([]*ConversationModel, error) + GetConversationsByConversationID(ctx context.Context, conversationIDs []string) ([]*model.Conversation, error) + GetConversationIDsNeedDestruct(ctx context.Context) ([]*model.Conversation, error) GetConversationNotReceiveMessageUserIDs(ctx context.Context, conversationID string) ([]string, error) } diff --git a/pkg/common/storage/database/doc.go b/pkg/common/storage/database/doc.go new file mode 100644 index 0000000000..4a691442ee --- /dev/null +++ b/pkg/common/storage/database/doc.go @@ -0,0 +1,15 @@ +// 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 database // import "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model/relation" diff --git a/pkg/common/db/table/relation/friend.go b/pkg/common/storage/database/friend.go similarity index 70% rename from pkg/common/db/table/relation/friend.go rename to pkg/common/storage/database/friend.go index 4c84e773dd..33d9c17bc5 100644 --- a/pkg/common/db/table/relation/friend.go +++ b/pkg/common/storage/database/friend.go @@ -12,31 +12,18 @@ // See the License for the specific language governing permissions and // limitations under the License. -package relation +package database import ( "context" - "time" - + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model" "github.com/openimsdk/tools/db/pagination" ) -// FriendModel represents the data structure for a friend relationship in MongoDB. -type FriendModel struct { - OwnerUserID string `bson:"owner_user_id"` - FriendUserID string `bson:"friend_user_id"` - Remark string `bson:"remark"` - CreateTime time.Time `bson:"create_time"` - AddSource int32 `bson:"add_source"` - OperatorUserID string `bson:"operator_user_id"` - Ex string `bson:"ex"` - IsPinned bool `bson:"is_pinned"` -} - -// FriendModelInterface defines the operations for managing friends in MongoDB. -type FriendModelInterface interface { +// Friend defines the operations for managing friends in MongoDB. +type Friend interface { // Create inserts multiple friend records. - Create(ctx context.Context, friends []*FriendModel) (err error) + Create(ctx context.Context, friends []*model.Friend) (err error) // Delete removes specified friends of the owner user. Delete(ctx context.Context, ownerUserID string, friendUserIDs []string) (err error) // UpdateByMap updates specific fields of a friend document using a map. @@ -44,17 +31,17 @@ type FriendModelInterface interface { // UpdateRemark modify remarks. UpdateRemark(ctx context.Context, ownerUserID, friendUserID, remark string) (err error) // Take retrieves a single friend document. Returns an error if not found. - Take(ctx context.Context, ownerUserID, friendUserID string) (friend *FriendModel, err error) + Take(ctx context.Context, ownerUserID, friendUserID string) (friend *model.Friend, err error) // FindUserState finds the friendship status between two users. - FindUserState(ctx context.Context, userID1, userID2 string) (friends []*FriendModel, err error) + FindUserState(ctx context.Context, userID1, userID2 string) (friends []*model.Friend, err error) // FindFriends retrieves a list of friends for a given owner. Missing friends do not cause an error. - FindFriends(ctx context.Context, ownerUserID string, friendUserIDs []string) (friends []*FriendModel, err error) + FindFriends(ctx context.Context, ownerUserID string, friendUserIDs []string) (friends []*model.Friend, err error) // FindReversalFriends finds users who have added the specified user as a friend. - FindReversalFriends(ctx context.Context, friendUserID string, ownerUserIDs []string) (friends []*FriendModel, err error) + FindReversalFriends(ctx context.Context, friendUserID string, ownerUserIDs []string) (friends []*model.Friend, err error) // FindOwnerFriends retrieves a paginated list of friends for a given owner. - FindOwnerFriends(ctx context.Context, ownerUserID string, pagination pagination.Pagination) (total int64, friends []*FriendModel, err error) + FindOwnerFriends(ctx context.Context, ownerUserID string, pagination pagination.Pagination) (total int64, friends []*model.Friend, err error) // FindInWhoseFriends finds users who have added the specified user as a friend, with pagination. - FindInWhoseFriends(ctx context.Context, friendUserID string, pagination pagination.Pagination) (total int64, friends []*FriendModel, err error) + FindInWhoseFriends(ctx context.Context, friendUserID string, pagination pagination.Pagination) (total int64, friends []*model.Friend, err error) // FindFriendUserIDs retrieves a list of friend user IDs for a given owner. FindFriendUserIDs(ctx context.Context, ownerUserID string) (friendUserIDs []string, err error) // UpdateFriends update friends' fields diff --git a/pkg/common/db/table/relation/friend_request.go b/pkg/common/storage/database/friend_request.go similarity index 60% rename from pkg/common/db/table/relation/friend_request.go rename to pkg/common/storage/database/friend_request.go index d59e3bb0b5..f163b4831f 100644 --- a/pkg/common/db/table/relation/friend_request.go +++ b/pkg/common/storage/database/friend_request.go @@ -12,42 +12,29 @@ // See the License for the specific language governing permissions and // limitations under the License. -package relation +package database import ( "context" - "time" - + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model" "github.com/openimsdk/tools/db/pagination" ) -type FriendRequestModel struct { - FromUserID string `bson:"from_user_id"` - ToUserID string `bson:"to_user_id"` - HandleResult int32 `bson:"handle_result"` - ReqMsg string `bson:"req_msg"` - CreateTime time.Time `bson:"create_time"` - HandlerUserID string `bson:"handler_user_id"` - HandleMsg string `bson:"handle_msg"` - HandleTime time.Time `bson:"handle_time"` - Ex string `bson:"ex"` -} - -type FriendRequestModelInterface interface { +type FriendRequest interface { // Insert multiple records - Create(ctx context.Context, friendRequests []*FriendRequestModel) (err error) + Create(ctx context.Context, friendRequests []*model.FriendRequest) (err error) // Delete record Delete(ctx context.Context, fromUserID, toUserID string) (err error) // Update with zero values UpdateByMap(ctx context.Context, formUserID string, toUserID string, args map[string]any) (err error) // Update multiple records (non-zero values) - Update(ctx context.Context, friendRequest *FriendRequestModel) (err error) + Update(ctx context.Context, friendRequest *model.FriendRequest) (err error) // Get friend requests sent to a specific user, no error returned if not found - Find(ctx context.Context, fromUserID, toUserID string) (friendRequest *FriendRequestModel, err error) - Take(ctx context.Context, fromUserID, toUserID string) (friendRequest *FriendRequestModel, err error) + Find(ctx context.Context, fromUserID, toUserID string) (friendRequest *model.FriendRequest, err error) + Take(ctx context.Context, fromUserID, toUserID string) (friendRequest *model.FriendRequest, err error) // Get list of friend requests received by toUserID - FindToUserID(ctx context.Context, toUserID string, pagination pagination.Pagination) (total int64, friendRequests []*FriendRequestModel, err error) + FindToUserID(ctx context.Context, toUserID string, pagination pagination.Pagination) (total int64, friendRequests []*model.FriendRequest, err error) // Get list of friend requests sent by fromUserID - FindFromUserID(ctx context.Context, fromUserID string, pagination pagination.Pagination) (total int64, friendRequests []*FriendRequestModel, err error) - FindBothFriendRequests(ctx context.Context, fromUserID, toUserID string) (friends []*FriendRequestModel, err error) + FindFromUserID(ctx context.Context, fromUserID string, pagination pagination.Pagination) (total int64, friendRequests []*model.FriendRequest, err error) + FindBothFriendRequests(ctx context.Context, fromUserID, toUserID string) (friends []*model.FriendRequest, err error) } diff --git a/pkg/common/storage/database/group.go b/pkg/common/storage/database/group.go new file mode 100644 index 0000000000..712db09d2d --- /dev/null +++ b/pkg/common/storage/database/group.go @@ -0,0 +1,35 @@ +// 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 database + +import ( + "context" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model" + "github.com/openimsdk/tools/db/pagination" + "time" +) + +type Group interface { + Create(ctx context.Context, groups []*model.Group) (err error) + UpdateMap(ctx context.Context, groupID string, args map[string]any) (err error) + UpdateStatus(ctx context.Context, groupID string, status int32) (err error) + Find(ctx context.Context, groupIDs []string) (groups []*model.Group, err error) + Take(ctx context.Context, groupID string) (group *model.Group, err error) + Search(ctx context.Context, keyword string, pagination pagination.Pagination) (total int64, groups []*model.Group, err error) + // Get Group total quantity + CountTotal(ctx context.Context, before *time.Time) (count int64, err error) + // Get Group total quantity every day + CountRangeEverydayTotal(ctx context.Context, start time.Time, end time.Time) (map[string]int64, error) +} diff --git a/pkg/common/db/table/relation/group_member.go b/pkg/common/storage/database/group_member.go similarity index 56% rename from pkg/common/db/table/relation/group_member.go rename to pkg/common/storage/database/group_member.go index 37f1cfc03e..f57f2c3173 100644 --- a/pkg/common/db/table/relation/group_member.go +++ b/pkg/common/storage/database/group_member.go @@ -12,46 +12,26 @@ // See the License for the specific language governing permissions and // limitations under the License. -package relation +package database import ( "context" - "time" - + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model" "github.com/openimsdk/tools/db/pagination" ) -type GroupMemberModel struct { - GroupID string `bson:"group_id"` - UserID string `bson:"user_id"` - Nickname string `bson:"nickname"` - FaceURL string `bson:"face_url"` - RoleLevel int32 `bson:"role_level"` - JoinTime time.Time `bson:"join_time"` - JoinSource int32 `bson:"join_source"` - InviterUserID string `bson:"inviter_user_id"` - OperatorUserID string `bson:"operator_user_id"` - MuteEndTime time.Time `bson:"mute_end_time"` - Ex string `bson:"ex"` -} - -type GroupMemberModelInterface interface { - // NewTx(tx any) GroupMemberModelInterface - Create(ctx context.Context, groupMembers []*GroupMemberModel) (err error) +type GroupMember interface { + Create(ctx context.Context, groupMembers []*model.GroupMember) (err error) Delete(ctx context.Context, groupID string, userIDs []string) (err error) - // DeleteGroup(ctx context.Context, groupIDs []string) (err error) Update(ctx context.Context, groupID string, userID string, data map[string]any) (err error) UpdateRoleLevel(ctx context.Context, groupID string, userID string, roleLevel int32) error FindMemberUserID(ctx context.Context, groupID string) (userIDs []string, err error) - Take(ctx context.Context, groupID string, userID string) (groupMember *GroupMemberModel, err error) - TakeOwner(ctx context.Context, groupID string) (groupMember *GroupMemberModel, err error) - SearchMember(ctx context.Context, keyword string, groupID string, pagination pagination.Pagination) (total int64, groupList []*GroupMemberModel, err error) + Take(ctx context.Context, groupID string, userID string) (groupMember *model.GroupMember, err error) + TakeOwner(ctx context.Context, groupID string) (groupMember *model.GroupMember, err error) + SearchMember(ctx context.Context, keyword string, groupID string, pagination pagination.Pagination) (total int64, groupList []*model.GroupMember, err error) FindRoleLevelUserIDs(ctx context.Context, groupID string, roleLevel int32) ([]string, error) - // MapGroupMemberNum(ctx context.Context, groupIDs []string) (count map[string]uint32, err error) - // FindJoinUserID(ctx context.Context, groupIDs []string) (groupUsers map[string][]string, err error) FindUserJoinedGroupID(ctx context.Context, userID string) (groupIDs []string, err error) TakeGroupMemberNum(ctx context.Context, groupID string) (count int64, err error) - // FindUsersJoinedGroupID(ctx context.Context, userIDs []string) (map[string][]string, error) FindUserManagedGroupID(ctx context.Context, userID string) (groupIDs []string, err error) IsUpdateRoleLevel(data map[string]any) bool } diff --git a/pkg/common/db/table/relation/group_request.go b/pkg/common/storage/database/group_request.go similarity index 55% rename from pkg/common/db/table/relation/group_request.go rename to pkg/common/storage/database/group_request.go index 7e9b258de0..7309584f01 100644 --- a/pkg/common/db/table/relation/group_request.go +++ b/pkg/common/storage/database/group_request.go @@ -12,35 +12,20 @@ // See the License for the specific language governing permissions and // limitations under the License. -package relation +package database import ( "context" - "time" - + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model" "github.com/openimsdk/tools/db/pagination" ) -type GroupRequestModel struct { - UserID string `bson:"user_id"` - GroupID string `bson:"group_id"` - HandleResult int32 `bson:"handle_result"` - ReqMsg string `bson:"req_msg"` - HandledMsg string `bson:"handled_msg"` - ReqTime time.Time `bson:"req_time"` - HandleUserID string `bson:"handle_user_id"` - HandledTime time.Time `bson:"handled_time"` - JoinSource int32 `bson:"join_source"` - InviterUserID string `bson:"inviter_user_id"` - Ex string `bson:"ex"` -} - -type GroupRequestModelInterface interface { - Create(ctx context.Context, groupRequests []*GroupRequestModel) (err error) +type GroupRequest interface { + Create(ctx context.Context, groupRequests []*model.GroupRequest) (err error) Delete(ctx context.Context, groupID string, userID string) (err error) UpdateHandler(ctx context.Context, groupID string, userID string, handledMsg string, handleResult int32) (err error) - Take(ctx context.Context, groupID string, userID string) (groupRequest *GroupRequestModel, err error) - FindGroupRequests(ctx context.Context, groupID string, userIDs []string) ([]*GroupRequestModel, error) - Page(ctx context.Context, userID string, pagination pagination.Pagination) (total int64, groups []*GroupRequestModel, err error) - PageGroup(ctx context.Context, groupIDs []string, pagination pagination.Pagination) (total int64, groups []*GroupRequestModel, err error) + Take(ctx context.Context, groupID string, userID string) (groupRequest *model.GroupRequest, err error) + FindGroupRequests(ctx context.Context, groupID string, userIDs []string) ([]*model.GroupRequest, error) + Page(ctx context.Context, userID string, pagination pagination.Pagination) (total int64, groups []*model.GroupRequest, err error) + PageGroup(ctx context.Context, groupIDs []string, pagination pagination.Pagination) (total int64, groups []*model.GroupRequest, err error) } diff --git a/pkg/common/storage/database/log.go b/pkg/common/storage/database/log.go new file mode 100644 index 0000000000..383cc55470 --- /dev/null +++ b/pkg/common/storage/database/log.go @@ -0,0 +1,29 @@ +// 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 database + +import ( + "context" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model" + "github.com/openimsdk/tools/db/pagination" + "time" +) + +type Log interface { + Create(ctx context.Context, log []*model.Log) error + Search(ctx context.Context, keyword string, start time.Time, end time.Time, pagination pagination.Pagination) (int64, []*model.Log, error) + Delete(ctx context.Context, logID []string, userID string) error + Get(ctx context.Context, logIDs []string, userID string) ([]*model.Log, error) +} diff --git a/pkg/common/db/mgo/black.go b/pkg/common/storage/database/mgo/black.go similarity index 67% rename from pkg/common/db/mgo/black.go rename to pkg/common/storage/database/mgo/black.go index d588aece6e..cf74cfab14 100644 --- a/pkg/common/db/mgo/black.go +++ b/pkg/common/storage/database/mgo/black.go @@ -16,8 +16,9 @@ package mgo import ( "context" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/database" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" "github.com/openimsdk/tools/db/mongoutil" "github.com/openimsdk/tools/db/pagination" "go.mongodb.org/mongo-driver/bson" @@ -25,7 +26,7 @@ import ( "go.mongodb.org/mongo-driver/mongo/options" ) -func NewBlackMongo(db *mongo.Database) (relation.BlackModelInterface, error) { +func NewBlackMongo(db *mongo.Database) (database.Black, error) { coll := db.Collection("black") _, err := coll.Indexes().CreateOne(context.Background(), mongo.IndexModel{ Keys: bson.D{ @@ -51,7 +52,7 @@ func (b *BlackMgo) blackFilter(ownerUserID, blockUserID string) bson.M { } } -func (b *BlackMgo) blacksFilter(blacks []*relation.BlackModel) bson.M { +func (b *BlackMgo) blacksFilter(blacks []*model.Black) bson.M { if len(blacks) == 0 { return nil } @@ -62,11 +63,11 @@ func (b *BlackMgo) blacksFilter(blacks []*relation.BlackModel) bson.M { return bson.M{"$or": or} } -func (b *BlackMgo) Create(ctx context.Context, blacks []*relation.BlackModel) (err error) { +func (b *BlackMgo) Create(ctx context.Context, blacks []*model.Black) (err error) { return mongoutil.InsertMany(ctx, b.coll, blacks) } -func (b *BlackMgo) Delete(ctx context.Context, blacks []*relation.BlackModel) (err error) { +func (b *BlackMgo) Delete(ctx context.Context, blacks []*model.Black) (err error) { if len(blacks) == 0 { return nil } @@ -80,23 +81,23 @@ func (b *BlackMgo) UpdateByMap(ctx context.Context, ownerUserID, blockUserID str return mongoutil.UpdateOne(ctx, b.coll, b.blackFilter(ownerUserID, blockUserID), bson.M{"$set": args}, false) } -func (b *BlackMgo) Find(ctx context.Context, blacks []*relation.BlackModel) (blackList []*relation.BlackModel, err error) { - return mongoutil.Find[*relation.BlackModel](ctx, b.coll, b.blacksFilter(blacks)) +func (b *BlackMgo) Find(ctx context.Context, blacks []*model.Black) (blackList []*model.Black, err error) { + return mongoutil.Find[*model.Black](ctx, b.coll, b.blacksFilter(blacks)) } -func (b *BlackMgo) Take(ctx context.Context, ownerUserID, blockUserID string) (black *relation.BlackModel, err error) { - return mongoutil.FindOne[*relation.BlackModel](ctx, b.coll, b.blackFilter(ownerUserID, blockUserID)) +func (b *BlackMgo) Take(ctx context.Context, ownerUserID, blockUserID string) (black *model.Black, err error) { + return mongoutil.FindOne[*model.Black](ctx, b.coll, b.blackFilter(ownerUserID, blockUserID)) } -func (b *BlackMgo) FindOwnerBlacks(ctx context.Context, ownerUserID string, pagination pagination.Pagination) (total int64, blacks []*relation.BlackModel, err error) { - return mongoutil.FindPage[*relation.BlackModel](ctx, b.coll, bson.M{"owner_user_id": ownerUserID}, pagination) +func (b *BlackMgo) FindOwnerBlacks(ctx context.Context, ownerUserID string, pagination pagination.Pagination) (total int64, blacks []*model.Black, err error) { + return mongoutil.FindPage[*model.Black](ctx, b.coll, bson.M{"owner_user_id": ownerUserID}, pagination) } -func (b *BlackMgo) FindOwnerBlackInfos(ctx context.Context, ownerUserID string, userIDs []string) (blacks []*relation.BlackModel, err error) { +func (b *BlackMgo) FindOwnerBlackInfos(ctx context.Context, ownerUserID string, userIDs []string) (blacks []*model.Black, err error) { if len(userIDs) == 0 { - return mongoutil.Find[*relation.BlackModel](ctx, b.coll, bson.M{"owner_user_id": ownerUserID}) + return mongoutil.Find[*model.Black](ctx, b.coll, bson.M{"owner_user_id": ownerUserID}) } - return mongoutil.Find[*relation.BlackModel](ctx, b.coll, bson.M{"owner_user_id": ownerUserID, "block_user_id": bson.M{"$in": userIDs}}) + return mongoutil.Find[*model.Black](ctx, b.coll, bson.M{"owner_user_id": ownerUserID, "block_user_id": bson.M{"$in": userIDs}}) } func (b *BlackMgo) FindBlackUserIDs(ctx context.Context, ownerUserID string) (blackUserIDs []string, err error) { diff --git a/pkg/common/db/mgo/conversation.go b/pkg/common/storage/database/mgo/conversation.go similarity index 84% rename from pkg/common/db/mgo/conversation.go rename to pkg/common/storage/database/mgo/conversation.go index 5292cb60cf..9c35f841b6 100644 --- a/pkg/common/db/mgo/conversation.go +++ b/pkg/common/storage/database/mgo/conversation.go @@ -16,9 +16,9 @@ package mgo import ( "context" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model" "time" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" "github.com/openimsdk/protocol/constant" "github.com/openimsdk/tools/db/mongoutil" "github.com/openimsdk/tools/db/pagination" @@ -47,7 +47,7 @@ type ConversationMgo struct { coll *mongo.Collection } -func (c *ConversationMgo) Create(ctx context.Context, conversations []*relation.ConversationModel) (err error) { +func (c *ConversationMgo) Create(ctx context.Context, conversations []*model.Conversation) (err error) { return mongoutil.InsertMany(ctx, c.coll, conversations) } @@ -72,12 +72,12 @@ func (c *ConversationMgo) UpdateByMap(ctx context.Context, userIDs []string, con return res.ModifiedCount, nil } -func (c *ConversationMgo) Update(ctx context.Context, conversation *relation.ConversationModel) (err error) { +func (c *ConversationMgo) Update(ctx context.Context, conversation *model.Conversation) (err error) { return mongoutil.UpdateOne(ctx, c.coll, bson.M{"owner_user_id": conversation.OwnerUserID, "conversation_id": conversation.ConversationID}, bson.M{"$set": conversation}, true) } -func (c *ConversationMgo) Find(ctx context.Context, ownerUserID string, conversationIDs []string) (conversations []*relation.ConversationModel, err error) { - return mongoutil.Find[*relation.ConversationModel](ctx, c.coll, bson.M{"owner_user_id": ownerUserID, "conversation_id": bson.M{"$in": conversationIDs}}) +func (c *ConversationMgo) Find(ctx context.Context, ownerUserID string, conversationIDs []string) (conversations []*model.Conversation, err error) { + return mongoutil.Find[*model.Conversation](ctx, c.coll, bson.M{"owner_user_id": ownerUserID, "conversation_id": bson.M{"$in": conversationIDs}}) } func (c *ConversationMgo) FindUserID(ctx context.Context, userIDs []string, conversationIDs []string) ([]string, error) { @@ -92,16 +92,16 @@ func (c *ConversationMgo) FindUserIDAllConversationID(ctx context.Context, userI return mongoutil.Find[string](ctx, c.coll, bson.M{"owner_user_id": userID}, options.Find().SetProjection(bson.M{"_id": 0, "conversation_id": 1})) } -func (c *ConversationMgo) Take(ctx context.Context, userID, conversationID string) (conversation *relation.ConversationModel, err error) { - return mongoutil.FindOne[*relation.ConversationModel](ctx, c.coll, bson.M{"owner_user_id": userID, "conversation_id": conversationID}) +func (c *ConversationMgo) Take(ctx context.Context, userID, conversationID string) (conversation *model.Conversation, err error) { + return mongoutil.FindOne[*model.Conversation](ctx, c.coll, bson.M{"owner_user_id": userID, "conversation_id": conversationID}) } func (c *ConversationMgo) FindConversationID(ctx context.Context, userID string, conversationIDs []string) (existConversationID []string, err error) { return mongoutil.Find[string](ctx, c.coll, bson.M{"owner_user_id": userID, "conversation_id": bson.M{"$in": conversationIDs}}, options.Find().SetProjection(bson.M{"_id": 0, "conversation_id": 1})) } -func (c *ConversationMgo) FindUserIDAllConversations(ctx context.Context, userID string) (conversations []*relation.ConversationModel, err error) { - return mongoutil.Find[*relation.ConversationModel](ctx, c.coll, bson.M{"owner_user_id": userID}) +func (c *ConversationMgo) FindUserIDAllConversations(ctx context.Context, userID string) (conversations []*model.Conversation, err error) { + return mongoutil.Find[*model.Conversation](ctx, c.coll, bson.M{"owner_user_id": userID}) } func (c *ConversationMgo) FindRecvMsgUserIDs(ctx context.Context, conversationID string, recvOpts []int) ([]string, error) { @@ -144,13 +144,13 @@ func (c *ConversationMgo) PageConversationIDs(ctx context.Context, pagination pa return mongoutil.FindPageOnly[string](ctx, c.coll, bson.M{}, pagination, options.Find().SetProjection(bson.M{"conversation_id": 1})) } -func (c *ConversationMgo) GetConversationsByConversationID(ctx context.Context, conversationIDs []string) ([]*relation.ConversationModel, error) { - return mongoutil.Find[*relation.ConversationModel](ctx, c.coll, bson.M{"conversation_id": bson.M{"$in": conversationIDs}}) +func (c *ConversationMgo) GetConversationsByConversationID(ctx context.Context, conversationIDs []string) ([]*model.Conversation, error) { + return mongoutil.Find[*model.Conversation](ctx, c.coll, bson.M{"conversation_id": bson.M{"$in": conversationIDs}}) } -func (c *ConversationMgo) GetConversationIDsNeedDestruct(ctx context.Context) ([]*relation.ConversationModel, error) { +func (c *ConversationMgo) GetConversationIDsNeedDestruct(ctx context.Context) ([]*model.Conversation, error) { // "is_msg_destruct = 1 && msg_destruct_time != 0 && (UNIX_TIMESTAMP(NOW()) > (msg_destruct_time + UNIX_TIMESTAMP(latest_msg_destruct_time)) || latest_msg_destruct_time is NULL)" - return mongoutil.Find[*relation.ConversationModel](ctx, c.coll, bson.M{ + return mongoutil.Find[*model.Conversation](ctx, c.coll, bson.M{ "is_msg_destruct": 1, "msg_destruct_time": bson.M{"$ne": 0}, "$or": []bson.M{ diff --git a/pkg/common/db/mgo/doc.go b/pkg/common/storage/database/mgo/doc.go similarity index 96% rename from pkg/common/db/mgo/doc.go rename to pkg/common/storage/database/mgo/doc.go index f9d43e8858..3bc6611ff0 100644 --- a/pkg/common/db/mgo/doc.go +++ b/pkg/common/storage/database/mgo/doc.go @@ -12,4 +12,4 @@ // See the License for the specific language governing permissions and // limitations under the License. -package mgo // import "github.com/openimsdk/open-im-server/v3/pkg/common/db/mgo" +package mgo // import "github.com/openimsdk/open-im-server/v3/pkg/common/storage/database" diff --git a/pkg/common/db/mgo/friend.go b/pkg/common/storage/database/mgo/friend.go similarity index 80% rename from pkg/common/db/mgo/friend.go rename to pkg/common/storage/database/mgo/friend.go index 269bb594ab..ffa006d013 100644 --- a/pkg/common/db/mgo/friend.go +++ b/pkg/common/storage/database/mgo/friend.go @@ -16,8 +16,9 @@ package mgo import ( "context" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/database" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" "github.com/openimsdk/tools/db/mongoutil" "github.com/openimsdk/tools/db/pagination" "go.mongodb.org/mongo-driver/bson" @@ -25,13 +26,13 @@ import ( "go.mongodb.org/mongo-driver/mongo/options" ) -// FriendMgo implements FriendModelInterface using MongoDB as the storage backend. +// FriendMgo implements Friend using MongoDB as the storage backend. type FriendMgo struct { coll *mongo.Collection } // NewFriendMongo creates a new instance of FriendMgo with the provided MongoDB database. -func NewFriendMongo(db *mongo.Database) (relation.FriendModelInterface, error) { +func NewFriendMongo(db *mongo.Database) (database.Friend, error) { coll := db.Collection("friend") _, err := coll.Indexes().CreateOne(context.Background(), mongo.IndexModel{ Keys: bson.D{ @@ -47,7 +48,7 @@ func NewFriendMongo(db *mongo.Database) (relation.FriendModelInterface, error) { } // Create inserts multiple friend records. -func (f *FriendMgo) Create(ctx context.Context, friends []*relation.FriendModel) error { +func (f *FriendMgo) Create(ctx context.Context, friends []*model.Friend) error { return mongoutil.InsertMany(ctx, f.coll, friends) } @@ -73,7 +74,7 @@ func (f *FriendMgo) UpdateByMap(ctx context.Context, ownerUserID string, friendU } // Update modifies multiple friend documents. -// func (f *FriendMgo) Update(ctx context.Context, friends []*relation.FriendModel) error { +// func (f *FriendMgo) Update(ctx context.Context, friends []*relation.Friend) error { // filter := bson.M{ // "owner_user_id": ownerUserID, // "friend_user_id": friendUserID, @@ -87,53 +88,53 @@ func (f *FriendMgo) UpdateRemark(ctx context.Context, ownerUserID, friendUserID, } // Take retrieves a single friend document. Returns an error if not found. -func (f *FriendMgo) Take(ctx context.Context, ownerUserID, friendUserID string) (*relation.FriendModel, error) { +func (f *FriendMgo) Take(ctx context.Context, ownerUserID, friendUserID string) (*model.Friend, error) { filter := bson.M{ "owner_user_id": ownerUserID, "friend_user_id": friendUserID, } - return mongoutil.FindOne[*relation.FriendModel](ctx, f.coll, filter) + return mongoutil.FindOne[*model.Friend](ctx, f.coll, filter) } // FindUserState finds the friendship status between two users. -func (f *FriendMgo) FindUserState(ctx context.Context, userID1, userID2 string) ([]*relation.FriendModel, error) { +func (f *FriendMgo) FindUserState(ctx context.Context, userID1, userID2 string) ([]*model.Friend, error) { filter := bson.M{ "$or": []bson.M{ {"owner_user_id": userID1, "friend_user_id": userID2}, {"owner_user_id": userID2, "friend_user_id": userID1}, }, } - return mongoutil.Find[*relation.FriendModel](ctx, f.coll, filter) + return mongoutil.Find[*model.Friend](ctx, f.coll, filter) } // FindFriends retrieves a list of friends for a given owner. Missing friends do not cause an error. -func (f *FriendMgo) FindFriends(ctx context.Context, ownerUserID string, friendUserIDs []string) ([]*relation.FriendModel, error) { +func (f *FriendMgo) FindFriends(ctx context.Context, ownerUserID string, friendUserIDs []string) ([]*model.Friend, error) { filter := bson.M{ "owner_user_id": ownerUserID, "friend_user_id": bson.M{"$in": friendUserIDs}, } - return mongoutil.Find[*relation.FriendModel](ctx, f.coll, filter) + return mongoutil.Find[*model.Friend](ctx, f.coll, filter) } // FindReversalFriends finds users who have added the specified user as a friend. -func (f *FriendMgo) FindReversalFriends(ctx context.Context, friendUserID string, ownerUserIDs []string) ([]*relation.FriendModel, error) { +func (f *FriendMgo) FindReversalFriends(ctx context.Context, friendUserID string, ownerUserIDs []string) ([]*model.Friend, error) { filter := bson.M{ "owner_user_id": bson.M{"$in": ownerUserIDs}, "friend_user_id": friendUserID, } - return mongoutil.Find[*relation.FriendModel](ctx, f.coll, filter) + return mongoutil.Find[*model.Friend](ctx, f.coll, filter) } // FindOwnerFriends retrieves a paginated list of friends for a given owner. -func (f *FriendMgo) FindOwnerFriends(ctx context.Context, ownerUserID string, pagination pagination.Pagination) (int64, []*relation.FriendModel, error) { +func (f *FriendMgo) FindOwnerFriends(ctx context.Context, ownerUserID string, pagination pagination.Pagination) (int64, []*model.Friend, error) { filter := bson.M{"owner_user_id": ownerUserID} - return mongoutil.FindPage[*relation.FriendModel](ctx, f.coll, filter, pagination) + return mongoutil.FindPage[*model.Friend](ctx, f.coll, filter, pagination) } // FindInWhoseFriends finds users who have added the specified user as a friend, with pagination. -func (f *FriendMgo) FindInWhoseFriends(ctx context.Context, friendUserID string, pagination pagination.Pagination) (int64, []*relation.FriendModel, error) { +func (f *FriendMgo) FindInWhoseFriends(ctx context.Context, friendUserID string, pagination pagination.Pagination) (int64, []*model.Friend, error) { filter := bson.M{"friend_user_id": friendUserID} - return mongoutil.FindPage[*relation.FriendModel](ctx, f.coll, filter, pagination) + return mongoutil.FindPage[*model.Friend](ctx, f.coll, filter, pagination) } // FindFriendUserIDs retrieves a list of friend user IDs for a given owner. diff --git a/pkg/common/db/mgo/friend_request.go b/pkg/common/storage/database/mgo/friend_request.go similarity index 76% rename from pkg/common/db/mgo/friend_request.go rename to pkg/common/storage/database/mgo/friend_request.go index 704b681267..0d60b213dd 100644 --- a/pkg/common/db/mgo/friend_request.go +++ b/pkg/common/storage/database/mgo/friend_request.go @@ -16,8 +16,9 @@ package mgo import ( "context" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/database" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" "github.com/openimsdk/tools/db/mongoutil" "github.com/openimsdk/tools/db/pagination" "go.mongodb.org/mongo-driver/bson" @@ -25,7 +26,7 @@ import ( "go.mongodb.org/mongo-driver/mongo/options" ) -func NewFriendRequestMongo(db *mongo.Database) (relation.FriendRequestModelInterface, error) { +func NewFriendRequestMongo(db *mongo.Database) (database.FriendRequest, error) { coll := db.Collection("friend_request") _, err := coll.Indexes().CreateOne(context.Background(), mongo.IndexModel{ Keys: bson.D{ @@ -44,23 +45,23 @@ type FriendRequestMgo struct { coll *mongo.Collection } -func (f *FriendRequestMgo) FindToUserID(ctx context.Context, toUserID string, pagination pagination.Pagination) (total int64, friendRequests []*relation.FriendRequestModel, err error) { - return mongoutil.FindPage[*relation.FriendRequestModel](ctx, f.coll, bson.M{"to_user_id": toUserID}, pagination) +func (f *FriendRequestMgo) FindToUserID(ctx context.Context, toUserID string, pagination pagination.Pagination) (total int64, friendRequests []*model.FriendRequest, err error) { + return mongoutil.FindPage[*model.FriendRequest](ctx, f.coll, bson.M{"to_user_id": toUserID}, pagination) } -func (f *FriendRequestMgo) FindFromUserID(ctx context.Context, fromUserID string, pagination pagination.Pagination) (total int64, friendRequests []*relation.FriendRequestModel, err error) { - return mongoutil.FindPage[*relation.FriendRequestModel](ctx, f.coll, bson.M{"from_user_id": fromUserID}, pagination) +func (f *FriendRequestMgo) FindFromUserID(ctx context.Context, fromUserID string, pagination pagination.Pagination) (total int64, friendRequests []*model.FriendRequest, err error) { + return mongoutil.FindPage[*model.FriendRequest](ctx, f.coll, bson.M{"from_user_id": fromUserID}, pagination) } -func (f *FriendRequestMgo) FindBothFriendRequests(ctx context.Context, fromUserID, toUserID string) (friends []*relation.FriendRequestModel, err error) { +func (f *FriendRequestMgo) FindBothFriendRequests(ctx context.Context, fromUserID, toUserID string) (friends []*model.FriendRequest, err error) { filter := bson.M{"$or": []bson.M{ {"from_user_id": fromUserID, "to_user_id": toUserID}, {"from_user_id": toUserID, "to_user_id": fromUserID}, }} - return mongoutil.Find[*relation.FriendRequestModel](ctx, f.coll, filter) + return mongoutil.Find[*model.FriendRequest](ctx, f.coll, filter) } -func (f *FriendRequestMgo) Create(ctx context.Context, friendRequests []*relation.FriendRequestModel) error { +func (f *FriendRequestMgo) Create(ctx context.Context, friendRequests []*model.FriendRequest) error { return mongoutil.InsertMany(ctx, f.coll, friendRequests) } @@ -75,7 +76,7 @@ func (f *FriendRequestMgo) UpdateByMap(ctx context.Context, formUserID, toUserID return mongoutil.UpdateOne(ctx, f.coll, bson.M{"from_user_id": formUserID, "to_user_id": toUserID}, bson.M{"$set": args}, true) } -func (f *FriendRequestMgo) Update(ctx context.Context, friendRequest *relation.FriendRequestModel) (err error) { +func (f *FriendRequestMgo) Update(ctx context.Context, friendRequest *model.FriendRequest) (err error) { updater := bson.M{} if friendRequest.HandleResult != 0 { updater["handle_result"] = friendRequest.HandleResult @@ -102,10 +103,10 @@ func (f *FriendRequestMgo) Update(ctx context.Context, friendRequest *relation.F return mongoutil.UpdateOne(ctx, f.coll, filter, bson.M{"$set": updater}, true) } -func (f *FriendRequestMgo) Find(ctx context.Context, fromUserID, toUserID string) (friendRequest *relation.FriendRequestModel, err error) { - return mongoutil.FindOne[*relation.FriendRequestModel](ctx, f.coll, bson.M{"from_user_id": fromUserID, "to_user_id": toUserID}) +func (f *FriendRequestMgo) Find(ctx context.Context, fromUserID, toUserID string) (friendRequest *model.FriendRequest, err error) { + return mongoutil.FindOne[*model.FriendRequest](ctx, f.coll, bson.M{"from_user_id": fromUserID, "to_user_id": toUserID}) } -func (f *FriendRequestMgo) Take(ctx context.Context, fromUserID, toUserID string) (friendRequest *relation.FriendRequestModel, err error) { +func (f *FriendRequestMgo) Take(ctx context.Context, fromUserID, toUserID string) (friendRequest *model.FriendRequest, err error) { return f.Find(ctx, fromUserID, toUserID) } diff --git a/pkg/common/db/mgo/group.go b/pkg/common/storage/database/mgo/group.go similarity index 82% rename from pkg/common/db/mgo/group.go rename to pkg/common/storage/database/mgo/group.go index 0169c23391..48d24560bc 100644 --- a/pkg/common/db/mgo/group.go +++ b/pkg/common/storage/database/mgo/group.go @@ -16,9 +16,10 @@ package mgo import ( "context" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/database" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model" "time" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" "github.com/openimsdk/protocol/constant" "github.com/openimsdk/tools/db/mongoutil" "github.com/openimsdk/tools/db/pagination" @@ -28,7 +29,7 @@ import ( "go.mongodb.org/mongo-driver/mongo/options" ) -func NewGroupMongo(db *mongo.Database) (relation.GroupModelInterface, error) { +func NewGroupMongo(db *mongo.Database) (database.Group, error) { coll := db.Collection("group") _, err := coll.Indexes().CreateOne(context.Background(), mongo.IndexModel{ Keys: bson.D{ @@ -46,7 +47,7 @@ type GroupMgo struct { coll *mongo.Collection } -func (g *GroupMgo) Create(ctx context.Context, groups []*relation.GroupModel) (err error) { +func (g *GroupMgo) Create(ctx context.Context, groups []*model.Group) (err error) { return mongoutil.InsertMany(ctx, g.coll, groups) } @@ -61,20 +62,20 @@ func (g *GroupMgo) UpdateMap(ctx context.Context, groupID string, args map[strin return mongoutil.UpdateOne(ctx, g.coll, bson.M{"group_id": groupID}, bson.M{"$set": args}, true) } -func (g *GroupMgo) Find(ctx context.Context, groupIDs []string) (groups []*relation.GroupModel, err error) { - return mongoutil.Find[*relation.GroupModel](ctx, g.coll, bson.M{"group_id": bson.M{"$in": groupIDs}}) +func (g *GroupMgo) Find(ctx context.Context, groupIDs []string) (groups []*model.Group, err error) { + return mongoutil.Find[*model.Group](ctx, g.coll, bson.M{"group_id": bson.M{"$in": groupIDs}}) } -func (g *GroupMgo) Take(ctx context.Context, groupID string) (group *relation.GroupModel, err error) { - return mongoutil.FindOne[*relation.GroupModel](ctx, g.coll, bson.M{"group_id": groupID}) +func (g *GroupMgo) Take(ctx context.Context, groupID string) (group *model.Group, err error) { + return mongoutil.FindOne[*model.Group](ctx, g.coll, bson.M{"group_id": groupID}) } -func (g *GroupMgo) Search(ctx context.Context, keyword string, pagination pagination.Pagination) (total int64, groups []*relation.GroupModel, err error) { +func (g *GroupMgo) Search(ctx context.Context, keyword string, pagination pagination.Pagination) (total int64, groups []*model.Group, err error) { // Define the sorting options opts := options.Find().SetSort(bson.D{{Key: "created_at", Value: -1}}) // Perform the search with pagination and sorting - return mongoutil.FindPage[*relation.GroupModel](ctx, g.coll, bson.M{ + return mongoutil.FindPage[*model.Group](ctx, g.coll, bson.M{ "group_name": bson.M{"$regex": keyword}, "status": bson.M{"$ne": constant.GroupStatusDismissed}, }, pagination, opts) diff --git a/pkg/common/db/mgo/group_member.go b/pkg/common/storage/database/mgo/group_member.go similarity index 83% rename from pkg/common/db/mgo/group_member.go rename to pkg/common/storage/database/mgo/group_member.go index 29d69d0f0b..ccca386e57 100644 --- a/pkg/common/db/mgo/group_member.go +++ b/pkg/common/storage/database/mgo/group_member.go @@ -16,8 +16,9 @@ package mgo import ( "context" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/database" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" "github.com/openimsdk/protocol/constant" "github.com/openimsdk/tools/db/mongoutil" "github.com/openimsdk/tools/db/pagination" @@ -27,7 +28,7 @@ import ( "go.mongodb.org/mongo-driver/mongo/options" ) -func NewGroupMember(db *mongo.Database) (relation.GroupMemberModelInterface, error) { +func NewGroupMember(db *mongo.Database) (database.GroupMember, error) { coll := db.Collection("group_member") _, err := coll.Indexes().CreateOne(context.Background(), mongo.IndexModel{ Keys: bson.D{ @@ -46,7 +47,7 @@ type GroupMemberMgo struct { coll *mongo.Collection } -func (g *GroupMemberMgo) Create(ctx context.Context, groupMembers []*relation.GroupMemberModel) (err error) { +func (g *GroupMemberMgo) Create(ctx context.Context, groupMembers []*model.GroupMember) (err error) { return mongoutil.InsertMany(ctx, g.coll, groupMembers) } @@ -66,7 +67,7 @@ func (g *GroupMemberMgo) Update(ctx context.Context, groupID string, userID stri return mongoutil.UpdateOne(ctx, g.coll, bson.M{"group_id": groupID, "user_id": userID}, bson.M{"$set": data}, true) } -func (g *GroupMemberMgo) Find(ctx context.Context, groupIDs []string, userIDs []string, roleLevels []int32) (groupMembers []*relation.GroupMemberModel, err error) { +func (g *GroupMemberMgo) Find(ctx context.Context, groupIDs []string, userIDs []string, roleLevels []int32) (groupMembers []*model.GroupMember, err error) { // TODO implement me panic("implement me") } @@ -75,21 +76,21 @@ func (g *GroupMemberMgo) FindMemberUserID(ctx context.Context, groupID string) ( return mongoutil.Find[string](ctx, g.coll, bson.M{"group_id": groupID}, options.Find().SetProjection(bson.M{"_id": 0, "user_id": 1})) } -func (g *GroupMemberMgo) Take(ctx context.Context, groupID string, userID string) (groupMember *relation.GroupMemberModel, err error) { - return mongoutil.FindOne[*relation.GroupMemberModel](ctx, g.coll, bson.M{"group_id": groupID, "user_id": userID}) +func (g *GroupMemberMgo) Take(ctx context.Context, groupID string, userID string) (groupMember *model.GroupMember, err error) { + return mongoutil.FindOne[*model.GroupMember](ctx, g.coll, bson.M{"group_id": groupID, "user_id": userID}) } -func (g *GroupMemberMgo) TakeOwner(ctx context.Context, groupID string) (groupMember *relation.GroupMemberModel, err error) { - return mongoutil.FindOne[*relation.GroupMemberModel](ctx, g.coll, bson.M{"group_id": groupID, "role_level": constant.GroupOwner}) +func (g *GroupMemberMgo) TakeOwner(ctx context.Context, groupID string) (groupMember *model.GroupMember, err error) { + return mongoutil.FindOne[*model.GroupMember](ctx, g.coll, bson.M{"group_id": groupID, "role_level": constant.GroupOwner}) } func (g *GroupMemberMgo) FindRoleLevelUserIDs(ctx context.Context, groupID string, roleLevel int32) ([]string, error) { return mongoutil.Find[string](ctx, g.coll, bson.M{"group_id": groupID, "role_level": roleLevel}, options.Find().SetProjection(bson.M{"_id": 0, "user_id": 1})) } -func (g *GroupMemberMgo) SearchMember(ctx context.Context, keyword string, groupID string, pagination pagination.Pagination) (total int64, groupList []*relation.GroupMemberModel, err error) { +func (g *GroupMemberMgo) SearchMember(ctx context.Context, keyword string, groupID string, pagination pagination.Pagination) (total int64, groupList []*model.GroupMember, err error) { filter := bson.M{"group_id": groupID, "nickname": bson.M{"$regex": keyword}} - return mongoutil.FindPage[*relation.GroupMemberModel](ctx, g.coll, filter, pagination) + return mongoutil.FindPage[*model.GroupMember](ctx, g.coll, filter, pagination) } func (g *GroupMemberMgo) FindUserJoinedGroupID(ctx context.Context, userID string) (groupIDs []string, err error) { diff --git a/pkg/common/db/mgo/group_request.go b/pkg/common/storage/database/mgo/group_request.go similarity index 69% rename from pkg/common/db/mgo/group_request.go rename to pkg/common/storage/database/mgo/group_request.go index 17cbeab179..4ae7785276 100644 --- a/pkg/common/db/mgo/group_request.go +++ b/pkg/common/storage/database/mgo/group_request.go @@ -16,8 +16,9 @@ package mgo import ( "context" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/database" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" "github.com/openimsdk/tools/db/mongoutil" "github.com/openimsdk/tools/db/pagination" "github.com/openimsdk/tools/errs" @@ -26,7 +27,7 @@ import ( "go.mongodb.org/mongo-driver/mongo/options" ) -func NewGroupRequestMgo(db *mongo.Database) (relation.GroupRequestModelInterface, error) { +func NewGroupRequestMgo(db *mongo.Database) (database.GroupRequest, error) { coll := db.Collection("group_request") _, err := coll.Indexes().CreateOne(context.Background(), mongo.IndexModel{ Keys: bson.D{ @@ -45,7 +46,7 @@ type GroupRequestMgo struct { coll *mongo.Collection } -func (g *GroupRequestMgo) Create(ctx context.Context, groupRequests []*relation.GroupRequestModel) (err error) { +func (g *GroupRequestMgo) Create(ctx context.Context, groupRequests []*model.GroupRequest) (err error) { return mongoutil.InsertMany(ctx, g.coll, groupRequests) } @@ -57,18 +58,18 @@ func (g *GroupRequestMgo) UpdateHandler(ctx context.Context, groupID string, use return mongoutil.UpdateOne(ctx, g.coll, bson.M{"group_id": groupID, "user_id": userID}, bson.M{"$set": bson.M{"handle_msg": handledMsg, "handle_result": handleResult}}, true) } -func (g *GroupRequestMgo) Take(ctx context.Context, groupID string, userID string) (groupRequest *relation.GroupRequestModel, err error) { - return mongoutil.FindOne[*relation.GroupRequestModel](ctx, g.coll, bson.M{"group_id": groupID, "user_id": userID}) +func (g *GroupRequestMgo) Take(ctx context.Context, groupID string, userID string) (groupRequest *model.GroupRequest, err error) { + return mongoutil.FindOne[*model.GroupRequest](ctx, g.coll, bson.M{"group_id": groupID, "user_id": userID}) } -func (g *GroupRequestMgo) FindGroupRequests(ctx context.Context, groupID string, userIDs []string) ([]*relation.GroupRequestModel, error) { - return mongoutil.Find[*relation.GroupRequestModel](ctx, g.coll, bson.M{"group_id": groupID, "user_id": bson.M{"$in": userIDs}}) +func (g *GroupRequestMgo) FindGroupRequests(ctx context.Context, groupID string, userIDs []string) ([]*model.GroupRequest, error) { + return mongoutil.Find[*model.GroupRequest](ctx, g.coll, bson.M{"group_id": groupID, "user_id": bson.M{"$in": userIDs}}) } -func (g *GroupRequestMgo) Page(ctx context.Context, userID string, pagination pagination.Pagination) (total int64, groups []*relation.GroupRequestModel, err error) { - return mongoutil.FindPage[*relation.GroupRequestModel](ctx, g.coll, bson.M{"user_id": userID}, pagination) +func (g *GroupRequestMgo) Page(ctx context.Context, userID string, pagination pagination.Pagination) (total int64, groups []*model.GroupRequest, err error) { + return mongoutil.FindPage[*model.GroupRequest](ctx, g.coll, bson.M{"user_id": userID}, pagination) } -func (g *GroupRequestMgo) PageGroup(ctx context.Context, groupIDs []string, pagination pagination.Pagination) (total int64, groups []*relation.GroupRequestModel, err error) { - return mongoutil.FindPage[*relation.GroupRequestModel](ctx, g.coll, bson.M{"group_id": bson.M{"$in": groupIDs}}, pagination) +func (g *GroupRequestMgo) PageGroup(ctx context.Context, groupIDs []string, pagination pagination.Pagination) (total int64, groups []*model.GroupRequest, err error) { + return mongoutil.FindPage[*model.GroupRequest](ctx, g.coll, bson.M{"group_id": bson.M{"$in": groupIDs}}, pagination) } diff --git a/pkg/common/db/table/relation/utils.go b/pkg/common/storage/database/mgo/helpers.go similarity index 80% rename from pkg/common/db/table/relation/utils.go rename to pkg/common/storage/database/mgo/helpers.go index 006da48083..23e66236ad 100644 --- a/pkg/common/db/table/relation/utils.go +++ b/pkg/common/storage/database/mgo/helpers.go @@ -12,24 +12,13 @@ // See the License for the specific language governing permissions and // limitations under the License. -package relation +package mgo import ( "github.com/openimsdk/tools/errs" "go.mongodb.org/mongo-driver/mongo" ) -type BatchUpdateGroupMember struct { - GroupID string - UserID string - Map map[string]any -} - -type GroupSimpleUserID struct { - Hash uint64 - MemberNum uint32 -} - func IsNotFound(err error) bool { return errs.Unwrap(err) == mongo.ErrNoDocuments } diff --git a/pkg/common/db/mgo/log.go b/pkg/common/storage/database/mgo/log.go similarity index 75% rename from pkg/common/db/mgo/log.go rename to pkg/common/storage/database/mgo/log.go index 36a0bbbc55..51715bd771 100644 --- a/pkg/common/db/mgo/log.go +++ b/pkg/common/storage/database/mgo/log.go @@ -16,9 +16,10 @@ package mgo import ( "context" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/database" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model" "time" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" "github.com/openimsdk/tools/db/mongoutil" "github.com/openimsdk/tools/db/pagination" "go.mongodb.org/mongo-driver/bson" @@ -26,7 +27,7 @@ import ( "go.mongodb.org/mongo-driver/mongo/options" ) -func NewLogMongo(db *mongo.Database) (relation.LogInterface, error) { +func NewLogMongo(db *mongo.Database) (database.Log, error) { coll := db.Collection("log") _, err := coll.Indexes().CreateMany(context.Background(), []mongo.IndexModel{ { @@ -56,16 +57,16 @@ type LogMgo struct { coll *mongo.Collection } -func (l *LogMgo) Create(ctx context.Context, log []*relation.LogModel) error { +func (l *LogMgo) Create(ctx context.Context, log []*model.Log) error { return mongoutil.InsertMany(ctx, l.coll, log) } -func (l *LogMgo) Search(ctx context.Context, keyword string, start time.Time, end time.Time, pagination pagination.Pagination) (int64, []*relation.LogModel, error) { +func (l *LogMgo) Search(ctx context.Context, keyword string, start time.Time, end time.Time, pagination pagination.Pagination) (int64, []*model.Log, error) { filter := bson.M{"create_time": bson.M{"$gte": start, "$lte": end}} if keyword != "" { filter["user_id"] = bson.M{"$regex": keyword} } - return mongoutil.FindPage[*relation.LogModel](ctx, l.coll, filter, pagination, options.Find().SetSort(bson.M{"create_time": -1})) + return mongoutil.FindPage[*model.Log](ctx, l.coll, filter, pagination, options.Find().SetSort(bson.M{"create_time": -1})) } func (l *LogMgo) Delete(ctx context.Context, logID []string, userID string) error { @@ -75,9 +76,9 @@ func (l *LogMgo) Delete(ctx context.Context, logID []string, userID string) erro return mongoutil.DeleteMany(ctx, l.coll, bson.M{"log_id": bson.M{"$in": logID}, "user_id": userID}) } -func (l *LogMgo) Get(ctx context.Context, logIDs []string, userID string) ([]*relation.LogModel, error) { +func (l *LogMgo) Get(ctx context.Context, logIDs []string, userID string) ([]*model.Log, error) { if userID == "" { - return mongoutil.Find[*relation.LogModel](ctx, l.coll, bson.M{"log_id": bson.M{"$in": logIDs}}) + return mongoutil.Find[*model.Log](ctx, l.coll, bson.M{"log_id": bson.M{"$in": logIDs}}) } - return mongoutil.Find[*relation.LogModel](ctx, l.coll, bson.M{"log_id": bson.M{"$in": logIDs}, "user_id": userID}) + return mongoutil.Find[*model.Log](ctx, l.coll, bson.M{"log_id": bson.M{"$in": logIDs}, "user_id": userID}) } diff --git a/pkg/common/db/mgo/msg.go b/pkg/common/storage/database/mgo/msg.go similarity index 91% rename from pkg/common/db/mgo/msg.go rename to pkg/common/storage/database/mgo/msg.go index 17e493d336..f676c1f59c 100644 --- a/pkg/common/db/mgo/msg.go +++ b/pkg/common/storage/database/mgo/msg.go @@ -3,9 +3,10 @@ package mgo import ( "context" "fmt" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/database" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model" "time" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" "github.com/openimsdk/protocol/constant" "github.com/openimsdk/protocol/msg" "github.com/openimsdk/protocol/sdkws" @@ -19,8 +20,8 @@ import ( "go.mongodb.org/mongo-driver/mongo/options" ) -func NewMsgMongo(db *mongo.Database) (relation.MsgDocModelInterface, error) { - coll := db.Collection(new(relation.MsgDocModel).TableName()) +func NewMsgMongo(db *mongo.Database) (database.Msg, error) { + coll := db.Collection(new(model.MsgDocModel).TableName()) _, err := coll.Indexes().CreateOne(context.Background(), mongo.IndexModel{ Keys: bson.D{ {Key: "doc_id", Value: 1}, @@ -35,17 +36,17 @@ func NewMsgMongo(db *mongo.Database) (relation.MsgDocModelInterface, error) { type MsgMgo struct { coll *mongo.Collection - model relation.MsgDocModel + model model.MsgDocModel } -func (m *MsgMgo) PushMsgsToDoc(ctx context.Context, docID string, msgsToMongo []relation.MsgInfoModel) error { +func (m *MsgMgo) PushMsgsToDoc(ctx context.Context, docID string, msgsToMongo []model.MsgInfoModel) error { filter := bson.M{"doc_id": docID} update := bson.M{"$push": bson.M{"msgs": bson.M{"$each": msgsToMongo}}} return mongoutil.UpdateOne(ctx, m.coll, filter, update, false) } -func (m *MsgMgo) Create(ctx context.Context, model *relation.MsgDocModel) error { - return mongoutil.InsertMany(ctx, m.coll, []*relation.MsgDocModel{model}) +func (m *MsgMgo) Create(ctx context.Context, msg *model.MsgDocModel) error { + return mongoutil.InsertMany(ctx, m.coll, []*model.MsgDocModel{msg}) } func (m *MsgMgo) UpdateMsg(ctx context.Context, docID string, index int64, key string, value any) (*mongo.UpdateResult, error) { @@ -86,11 +87,11 @@ func (m *MsgMgo) IsExistDocID(ctx context.Context, docID string) (bool, error) { return mongoutil.Exist(ctx, m.coll, bson.M{"doc_id": docID}) } -func (m *MsgMgo) FindOneByDocID(ctx context.Context, docID string) (*relation.MsgDocModel, error) { - return mongoutil.FindOne[*relation.MsgDocModel](ctx, m.coll, bson.M{"doc_id": docID}) +func (m *MsgMgo) FindOneByDocID(ctx context.Context, docID string) (*model.MsgDocModel, error) { + return mongoutil.FindOne[*model.MsgDocModel](ctx, m.coll, bson.M{"doc_id": docID}) } -func (m *MsgMgo) GetMsgBySeqIndexIn1Doc(ctx context.Context, userID, docID string, seqs []int64) ([]*relation.MsgInfoModel, error) { +func (m *MsgMgo) GetMsgBySeqIndexIn1Doc(ctx context.Context, userID, docID string, seqs []int64) ([]*model.MsgInfoModel, error) { indexs := make([]int64, 0, len(seqs)) for _, seq := range seqs { indexs = append(indexs, m.model.GetMsgIndex(seq)) @@ -131,14 +132,14 @@ func (m *MsgMgo) GetMsgBySeqIndexIn1Doc(ctx context.Context, userID, docID strin {Key: "msgs.del_list", Value: 0}, }}}, } - msgDocModel, err := mongoutil.Aggregate[*relation.MsgDocModel](ctx, m.coll, pipeline) + msgDocModel, err := mongoutil.Aggregate[*model.MsgDocModel](ctx, m.coll, pipeline) if err != nil { return nil, err } if len(msgDocModel) == 0 { return nil, errs.Wrap(mongo.ErrNoDocuments) } - msgs := make([]*relation.MsgInfoModel, 0, len(msgDocModel[0].Msg)) + msgs := make([]*model.MsgInfoModel, 0, len(msgDocModel[0].Msg)) for i := range msgDocModel[0].Msg { msg := msgDocModel[0].Msg[i] if msg == nil || msg.Msg == nil { @@ -177,7 +178,7 @@ func (m *MsgMgo) GetMsgBySeqIndexIn1Doc(ctx context.Context, userID, docID strin return msgs, nil } -func (m *MsgMgo) GetNewestMsg(ctx context.Context, conversationID string) (*relation.MsgInfoModel, error) { +func (m *MsgMgo) GetNewestMsg(ctx context.Context, conversationID string) (*model.MsgInfoModel, error) { for skip := int64(0); ; skip++ { msgDocModel, err := m.GetMsgDocModelByIndex(ctx, conversationID, skip, -1) if err != nil { @@ -191,7 +192,7 @@ func (m *MsgMgo) GetNewestMsg(ctx context.Context, conversationID string) (*rela } } -func (m *MsgMgo) GetOldestMsg(ctx context.Context, conversationID string) (*relation.MsgInfoModel, error) { +func (m *MsgMgo) GetOldestMsg(ctx context.Context, conversationID string) (*model.MsgInfoModel, error) { for skip := int64(0); ; skip++ { msgDocModel, err := m.GetMsgDocModelByIndex(ctx, conversationID, skip, 1) if err != nil { @@ -212,20 +213,20 @@ func (m *MsgMgo) DeleteDocs(ctx context.Context, docIDs []string) error { return mongoutil.DeleteMany(ctx, m.coll, bson.M{"doc_id": bson.M{"$in": docIDs}}) } -func (m *MsgMgo) GetMsgDocModelByIndex(ctx context.Context, conversationID string, index, sort int64) (*relation.MsgDocModel, error) { +func (m *MsgMgo) GetMsgDocModelByIndex(ctx context.Context, conversationID string, index, sort int64) (*model.MsgDocModel, error) { if sort != 1 && sort != -1 { return nil, errs.ErrArgs.WrapMsg("mongo sort must be 1 or -1") } opt := options.Find().SetLimit(1).SetSkip(index).SetSort(bson.M{"doc_id": sort}).SetLimit(1) filter := bson.M{"doc_id": primitive.Regex{Pattern: fmt.Sprintf("^%s:", conversationID)}} - msgs, err := mongoutil.Find[*relation.MsgDocModel](ctx, m.coll, filter, opt) + msgs, err := mongoutil.Find[*model.MsgDocModel](ctx, m.coll, filter, opt) if err != nil { return nil, err } if len(msgs) > 0 { return msgs[0], nil } - return nil, errs.Wrap(relation.ErrMsgListNotExist) + return nil, errs.Wrap(model.ErrMsgListNotExist) } func (m *MsgMgo) DeleteMsgsInOneDocByIndex(ctx context.Context, docID string, indexes []int) error { @@ -266,7 +267,7 @@ func (m *MsgMgo) MarkSingleChatMsgsAsRead(ctx context.Context, userID string, do return nil } -func (m *MsgMgo) SearchMessage(ctx context.Context, req *msg.SearchMessageReq) (int32, []*relation.MsgInfoModel, error) { +func (m *MsgMgo) SearchMessage(ctx context.Context, req *msg.SearchMessageReq) (int32, []*model.MsgInfoModel, error) { where := make(bson.A, 0, 6) if req.RecvID != "" { where = append(where, bson.M{"msgs.msg.recv_id": req.RecvID}) @@ -335,7 +336,7 @@ func (m *MsgMgo) SearchMessage(ctx context.Context, req *msg.SearchMessageReq) ( "$limit": req.Pagination.GetShowNumber(), }, ) - msgs, err := mongoutil.Aggregate[*relation.MsgInfoModel](ctx, m.coll, pipeline) + msgs, err := mongoutil.Aggregate[*model.MsgInfoModel](ctx, m.coll, pipeline) if err != nil { return 0, nil, err } @@ -385,7 +386,7 @@ func (m *MsgMgo) SearchMessage(ctx context.Context, req *msg.SearchMessageReq) ( return count[0], msgs, nil } -func (m *MsgMgo) RangeUserSendCount(ctx context.Context, start time.Time, end time.Time, group bool, ase bool, pageNumber int32, showNumber int32) (msgCount int64, userCount int64, users []*relation.UserCount, dateCount map[string]int64, err error) { +func (m *MsgMgo) RangeUserSendCount(ctx context.Context, start time.Time, end time.Time, group bool, ase bool, pageNumber int32, showNumber int32) (msgCount int64, userCount int64, users []*model.UserCount, dateCount map[string]int64, err error) { var sort int if ase { sort = 1 @@ -619,9 +620,9 @@ func (m *MsgMgo) RangeUserSendCount(ctx context.Context, start time.Time, end ti if len(result) == 0 { return 0, 0, nil, nil, errs.Wrap(err) } - users = make([]*relation.UserCount, len(result[0].Users)) + users = make([]*model.UserCount, len(result[0].Users)) for i, r := range result[0].Users { - users[i] = &relation.UserCount{ + users[i] = &model.UserCount{ UserID: r.UserID, Count: r.Count, } @@ -633,7 +634,7 @@ func (m *MsgMgo) RangeUserSendCount(ctx context.Context, start time.Time, end ti return result[0].MsgCount, result[0].UserCount, users, dateCount, nil } -func (m *MsgMgo) RangeGroupSendCount(ctx context.Context, start time.Time, end time.Time, ase bool, pageNumber int32, showNumber int32) (msgCount int64, userCount int64, groups []*relation.GroupCount, dateCount map[string]int64, err error) { +func (m *MsgMgo) RangeGroupSendCount(ctx context.Context, start time.Time, end time.Time, ase bool, pageNumber int32, showNumber int32) (msgCount int64, userCount int64, groups []*model.GroupCount, dateCount map[string]int64, err error) { var sort int if ase { sort = 1 @@ -856,9 +857,9 @@ func (m *MsgMgo) RangeGroupSendCount(ctx context.Context, start time.Time, end t if len(result) == 0 { return 0, 0, nil, nil, errs.Wrap(err) } - groups = make([]*relation.GroupCount, len(result[0].Groups)) + groups = make([]*model.GroupCount, len(result[0].Groups)) for i, r := range result[0].Groups { - groups[i] = &relation.GroupCount{ + groups[i] = &model.GroupCount{ GroupID: r.GroupID, Count: r.Count, } @@ -873,7 +874,7 @@ func (m *MsgMgo) RangeGroupSendCount(ctx context.Context, start time.Time, end t func (m *MsgMgo) ConvertMsgsDocLen(ctx context.Context, conversationIDs []string) { for _, conversationID := range conversationIDs { regex := primitive.Regex{Pattern: fmt.Sprintf("^%s:", conversationID)} - msgDocs, err := mongoutil.Find[*relation.MsgDocModel](ctx, m.coll, bson.M{"doc_id": regex}) + msgDocs, err := mongoutil.Find[*model.MsgDocModel](ctx, m.coll, bson.M{"doc_id": regex}) if err != nil { log.ZError(ctx, "convertAll find msg doc failed", err, "conversationID", conversationID) continue @@ -896,7 +897,7 @@ func (m *MsgMgo) ConvertMsgsDocLen(ctx context.Context, conversationIDs []string for index < int64(len(msgDoc.Msg)) { msg := msgDoc.Msg[index] if msg != nil && msg.Msg != nil { - msgDocModel := relation.MsgDocModel{DocID: m.model.GetDocID(conversationID, msg.Msg.Seq)} + msgDocModel := model.MsgDocModel{DocID: m.model.GetDocID(conversationID, msg.Msg.Seq)} end := index + m.model.GetSingleGocMsgNum() if int(end) >= len(msgDoc.Msg) { msgDocModel.Msg = msgDoc.Msg[index:] @@ -919,8 +920,8 @@ func (m *MsgMgo) ConvertMsgsDocLen(ctx context.Context, conversationIDs []string } } -func (m *MsgMgo) GetBeforeMsg(ctx context.Context, ts int64, limit int) ([]*relation.MsgDocModel, error) { - return mongoutil.Aggregate[*relation.MsgDocModel](ctx, m.coll, []bson.M{ +func (m *MsgMgo) GetBeforeMsg(ctx context.Context, ts int64, limit int) ([]*model.MsgDocModel, error) { + return mongoutil.Aggregate[*model.MsgDocModel](ctx, m.coll, []bson.M{ { "$match": bson.M{ "msgs.msg.send_time": bson.M{ @@ -946,7 +947,7 @@ func (m *MsgMgo) DeleteMsgByIndex(ctx context.Context, docID string, index []int if len(index) == 0 { return nil } - model := &relation.MsgInfoModel{DelList: []string{}} + model := &model.MsgInfoModel{DelList: []string{}} set := make(map[string]any) for i := range index { set[fmt.Sprintf("msgs.%d", i)] = model diff --git a/pkg/common/db/mgo/object.go b/pkg/common/storage/database/mgo/object.go similarity index 79% rename from pkg/common/db/mgo/object.go rename to pkg/common/storage/database/mgo/object.go index 1c628bb51c..8ed7b3a561 100644 --- a/pkg/common/db/mgo/object.go +++ b/pkg/common/storage/database/mgo/object.go @@ -16,8 +16,9 @@ package mgo import ( "context" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/database" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" "github.com/openimsdk/tools/db/mongoutil" "github.com/openimsdk/tools/errs" "go.mongodb.org/mongo-driver/bson" @@ -25,7 +26,7 @@ import ( "go.mongodb.org/mongo-driver/mongo/options" ) -func NewS3Mongo(db *mongo.Database) (relation.ObjectInfoModelInterface, error) { +func NewS3Mongo(db *mongo.Database) (database.ObjectInfo, error) { coll := db.Collection("s3") _, err := coll.Indexes().CreateOne(context.Background(), mongo.IndexModel{ Keys: bson.D{ @@ -43,7 +44,7 @@ type S3Mongo struct { coll *mongo.Collection } -func (o *S3Mongo) SetObject(ctx context.Context, obj *relation.ObjectModel) error { +func (o *S3Mongo) SetObject(ctx context.Context, obj *model.Object) error { filter := bson.M{"name": obj.Name, "engine": obj.Engine} update := bson.M{ "name": obj.Name, @@ -57,11 +58,11 @@ func (o *S3Mongo) SetObject(ctx context.Context, obj *relation.ObjectModel) erro return mongoutil.UpdateOne(ctx, o.coll, filter, bson.M{"$set": update}, false, options.Update().SetUpsert(true)) } -func (o *S3Mongo) Take(ctx context.Context, engine string, name string) (*relation.ObjectModel, error) { +func (o *S3Mongo) Take(ctx context.Context, engine string, name string) (*model.Object, error) { if engine == "" { - return mongoutil.FindOne[*relation.ObjectModel](ctx, o.coll, bson.M{"name": name}) + return mongoutil.FindOne[*model.Object](ctx, o.coll, bson.M{"name": name}) } - return mongoutil.FindOne[*relation.ObjectModel](ctx, o.coll, bson.M{"name": name, "engine": engine}) + return mongoutil.FindOne[*model.Object](ctx, o.coll, bson.M{"name": name, "engine": engine}) } func (o *S3Mongo) Delete(ctx context.Context, engine string, name string) error { diff --git a/pkg/common/db/mgo/subscribe.go b/pkg/common/storage/database/mgo/subscribe.go similarity index 93% rename from pkg/common/db/mgo/subscribe.go rename to pkg/common/storage/database/mgo/subscribe.go index f2057dc453..5b7d9786b7 100644 --- a/pkg/common/db/mgo/subscribe.go +++ b/pkg/common/storage/database/mgo/subscribe.go @@ -16,8 +16,9 @@ package mgo import ( "context" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/database" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" "github.com/openimsdk/tools/errs" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/mongo" @@ -35,9 +36,9 @@ const ( MaximumSubscription = 3000 ) -func NewUserMongoDriver(database *mongo.Database) relation.SubscribeUserModelInterface { +func NewUserMongoDriver(database *mongo.Database) database.SubscribeUser { return &UserMongoDriver{ - userCollection: database.Collection(relation.SubscribeUser), + userCollection: database.Collection(model.SubscribeUserTableName), } } @@ -155,7 +156,7 @@ func (u *UserMongoDriver) RemoveSubscribedListFromUser(ctx context.Context, user // GetAllSubscribeList Get all users subscribed by this user. func (u *UserMongoDriver) GetAllSubscribeList(ctx context.Context, userID string) (userIDList []string, err error) { - var user relation.SubscribeUserModel + var user model.SubscribeUser cursor := u.userCollection.FindOne( ctx, bson.M{"user_id": SubscriptionPrefix + userID}) @@ -172,7 +173,7 @@ func (u *UserMongoDriver) GetAllSubscribeList(ctx context.Context, userID string // GetSubscribedList Get the user subscribed by those users. func (u *UserMongoDriver) GetSubscribedList(ctx context.Context, userID string) (userIDList []string, err error) { - var user relation.SubscribeUserModel + var user model.SubscribeUser cursor := u.userCollection.FindOne( ctx, bson.M{"user_id": SubscribedPrefix + userID}) diff --git a/pkg/common/db/mgo/user.go b/pkg/common/storage/database/mgo/user.go similarity index 87% rename from pkg/common/db/mgo/user.go rename to pkg/common/storage/database/mgo/user.go index 696479871e..96cb18882b 100644 --- a/pkg/common/db/mgo/user.go +++ b/pkg/common/storage/database/mgo/user.go @@ -16,9 +16,10 @@ package mgo import ( "context" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/database" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model" "time" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" "github.com/openimsdk/protocol/user" "github.com/openimsdk/tools/db/mongoutil" "github.com/openimsdk/tools/db/pagination" @@ -29,7 +30,7 @@ import ( "go.mongodb.org/mongo-driver/mongo/options" ) -func NewUserMongo(db *mongo.Database) (relation.UserModelInterface, error) { +func NewUserMongo(db *mongo.Database) (database.User, error) { coll := db.Collection("user") _, err := coll.Indexes().CreateOne(context.Background(), mongo.IndexModel{ Keys: bson.D{ @@ -47,7 +48,7 @@ type UserMgo struct { coll *mongo.Collection } -func (u *UserMgo) Create(ctx context.Context, users []*relation.UserModel) error { +func (u *UserMgo) Create(ctx context.Context, users []*model.User) error { return mongoutil.InsertMany(ctx, u.coll, users) } @@ -58,27 +59,27 @@ func (u *UserMgo) UpdateByMap(ctx context.Context, userID string, args map[strin return mongoutil.UpdateOne(ctx, u.coll, bson.M{"user_id": userID}, bson.M{"$set": args}, true) } -func (u *UserMgo) Find(ctx context.Context, userIDs []string) (users []*relation.UserModel, err error) { - return mongoutil.Find[*relation.UserModel](ctx, u.coll, bson.M{"user_id": bson.M{"$in": userIDs}}) +func (u *UserMgo) Find(ctx context.Context, userIDs []string) (users []*model.User, err error) { + return mongoutil.Find[*model.User](ctx, u.coll, bson.M{"user_id": bson.M{"$in": userIDs}}) } -func (u *UserMgo) Take(ctx context.Context, userID string) (user *relation.UserModel, err error) { - return mongoutil.FindOne[*relation.UserModel](ctx, u.coll, bson.M{"user_id": userID}) +func (u *UserMgo) Take(ctx context.Context, userID string) (user *model.User, err error) { + return mongoutil.FindOne[*model.User](ctx, u.coll, bson.M{"user_id": userID}) } -func (u *UserMgo) TakeNotification(ctx context.Context, level int64) (user []*relation.UserModel, err error) { - return mongoutil.Find[*relation.UserModel](ctx, u.coll, bson.M{"app_manger_level": level}) +func (u *UserMgo) TakeNotification(ctx context.Context, level int64) (user []*model.User, err error) { + return mongoutil.Find[*model.User](ctx, u.coll, bson.M{"app_manger_level": level}) } -func (u *UserMgo) TakeByNickname(ctx context.Context, nickname string) (user []*relation.UserModel, err error) { - return mongoutil.Find[*relation.UserModel](ctx, u.coll, bson.M{"nickname": nickname}) +func (u *UserMgo) TakeByNickname(ctx context.Context, nickname string) (user []*model.User, err error) { + return mongoutil.Find[*model.User](ctx, u.coll, bson.M{"nickname": nickname}) } -func (u *UserMgo) Page(ctx context.Context, pagination pagination.Pagination) (count int64, users []*relation.UserModel, err error) { - return mongoutil.FindPage[*relation.UserModel](ctx, u.coll, bson.M{}, pagination) +func (u *UserMgo) Page(ctx context.Context, pagination pagination.Pagination) (count int64, users []*model.User, err error) { + return mongoutil.FindPage[*model.User](ctx, u.coll, bson.M{}, pagination) } -func (u *UserMgo) PageFindUser(ctx context.Context, level1 int64, level2 int64, pagination pagination.Pagination) (count int64, users []*relation.UserModel, err error) { +func (u *UserMgo) PageFindUser(ctx context.Context, level1 int64, level2 int64, pagination pagination.Pagination) (count int64, users []*model.User, err error) { query := bson.M{ "$or": []bson.M{ {"app_manger_level": level1}, @@ -86,7 +87,7 @@ func (u *UserMgo) PageFindUser(ctx context.Context, level1 int64, level2 int64, }, } - return mongoutil.FindPage[*relation.UserModel](ctx, u.coll, query, pagination) + return mongoutil.FindPage[*model.User](ctx, u.coll, query, pagination) } func (u *UserMgo) PageFindUserWithKeyword( @@ -96,7 +97,7 @@ func (u *UserMgo) PageFindUserWithKeyword( userID string, nickName string, pagination pagination.Pagination, -) (count int64, users []*relation.UserModel, err error) { +) (count int64, users []*model.User, err error) { // Initialize the base query with level conditions query := bson.M{ "$and": []bson.M{ @@ -121,7 +122,7 @@ func (u *UserMgo) PageFindUserWithKeyword( } // Perform the paginated search - return mongoutil.FindPage[*relation.UserModel](ctx, u.coll, query, pagination) + return mongoutil.FindPage[*model.User](ctx, u.coll, query, pagination) } func (u *UserMgo) GetAllUserID(ctx context.Context, pagination pagination.Pagination) (int64, []string, error) { diff --git a/pkg/common/storage/database/msg.go b/pkg/common/storage/database/msg.go new file mode 100644 index 0000000000..b402f3ac7d --- /dev/null +++ b/pkg/common/storage/database/msg.go @@ -0,0 +1,48 @@ +// 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 database + +import ( + "context" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model" + "github.com/openimsdk/protocol/msg" + "go.mongodb.org/mongo-driver/mongo" + "time" +) + +type Msg interface { + PushMsgsToDoc(ctx context.Context, docID string, msgsToMongo []model.MsgInfoModel) error + Create(ctx context.Context, model *model.MsgDocModel) error + UpdateMsg(ctx context.Context, docID string, index int64, key string, value any) (*mongo.UpdateResult, error) + PushUnique(ctx context.Context, docID string, index int64, key string, value any) (*mongo.UpdateResult, error) + UpdateMsgContent(ctx context.Context, docID string, index int64, msg []byte) error + IsExistDocID(ctx context.Context, docID string) (bool, error) + FindOneByDocID(ctx context.Context, docID string) (*model.MsgDocModel, error) + GetMsgBySeqIndexIn1Doc(ctx context.Context, userID, docID string, seqs []int64) ([]*model.MsgInfoModel, error) + GetNewestMsg(ctx context.Context, conversationID string) (*model.MsgInfoModel, error) + GetOldestMsg(ctx context.Context, conversationID string) (*model.MsgInfoModel, error) + DeleteDocs(ctx context.Context, docIDs []string) error + GetMsgDocModelByIndex(ctx context.Context, conversationID string, index, sort int64) (*model.MsgDocModel, error) + DeleteMsgsInOneDocByIndex(ctx context.Context, docID string, indexes []int) error + MarkSingleChatMsgsAsRead(ctx context.Context, userID string, docID string, indexes []int64) error + SearchMessage(ctx context.Context, req *msg.SearchMessageReq) (int32, []*model.MsgInfoModel, error) + RangeUserSendCount(ctx context.Context, start time.Time, end time.Time, group bool, ase bool, pageNumber int32, showNumber int32) (msgCount int64, userCount int64, users []*model.UserCount, dateCount map[string]int64, err error) + RangeGroupSendCount(ctx context.Context, start time.Time, end time.Time, ase bool, pageNumber int32, showNumber int32) (msgCount int64, userCount int64, groups []*model.GroupCount, dateCount map[string]int64, err error) + ConvertMsgsDocLen(ctx context.Context, conversationIDs []string) + + DeleteDoc(ctx context.Context, docID string) error + DeleteMsgByIndex(ctx context.Context, docID string, index []int) error + GetBeforeMsg(ctx context.Context, ts int64, limit int) ([]*model.MsgDocModel, error) +} diff --git a/pkg/common/storage/database/object.go b/pkg/common/storage/database/object.go new file mode 100644 index 0000000000..554f71f35d --- /dev/null +++ b/pkg/common/storage/database/object.go @@ -0,0 +1,26 @@ +// 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 database + +import ( + "context" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model" +) + +type ObjectInfo interface { + SetObject(ctx context.Context, obj *model.Object) error + Take(ctx context.Context, engine string, name string) (*model.Object, error) + Delete(ctx context.Context, engine string, name string) error +} diff --git a/pkg/common/db/table/relation/subscribe.go b/pkg/common/storage/database/subscribe.go similarity index 74% rename from pkg/common/db/table/relation/subscribe.go rename to pkg/common/storage/database/subscribe.go index 4e184cf384..5905ecd073 100644 --- a/pkg/common/db/table/relation/subscribe.go +++ b/pkg/common/storage/database/subscribe.go @@ -12,27 +12,12 @@ // See the License for the specific language governing permissions and // limitations under the License. -package relation +package database import "context" -// SubscribeUser collection constant. -const ( - SubscribeUser = "subscribe_user" -) - -// SubscribeUserModel collection structure. -type SubscribeUserModel struct { - UserID string `bson:"user_id" json:"userID"` - UserIDList []string `bson:"user_id_list" json:"userIDList"` -} - -func (SubscribeUserModel) TableName() string { - return SubscribeUser -} - -// SubscribeUserModelInterface Operation interface of user mongodb. -type SubscribeUserModelInterface interface { +// SubscribeUser Operation interface of user mongodb. +type SubscribeUser interface { // AddSubscriptionList Subscriber's handling of thresholds. AddSubscriptionList(ctx context.Context, userID string, userIDList []string) error // UnsubscriptionList Handling of unsubscribe. diff --git a/pkg/common/db/table/relation/user.go b/pkg/common/storage/database/user.go similarity index 63% rename from pkg/common/db/table/relation/user.go rename to pkg/common/storage/database/user.go index 938a8a77d7..2e40886205 100644 --- a/pkg/common/db/table/relation/user.go +++ b/pkg/common/storage/database/user.go @@ -12,52 +12,26 @@ // See the License for the specific language governing permissions and // limitations under the License. -package relation +package database import ( "context" - "time" - + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model" "github.com/openimsdk/protocol/user" "github.com/openimsdk/tools/db/pagination" + "time" ) -type UserModel struct { - UserID string `bson:"user_id"` - Nickname string `bson:"nickname"` - FaceURL string `bson:"face_url"` - Ex string `bson:"ex"` - AppMangerLevel int32 `bson:"app_manger_level"` - GlobalRecvMsgOpt int32 `bson:"global_recv_msg_opt"` - CreateTime time.Time `bson:"create_time"` -} - -func (u *UserModel) GetNickname() string { - return u.Nickname -} - -func (u *UserModel) GetFaceURL() string { - return u.FaceURL -} - -func (u UserModel) GetUserID() string { - return u.UserID -} - -func (u UserModel) GetEx() string { - return u.Ex -} - -type UserModelInterface interface { - Create(ctx context.Context, users []*UserModel) (err error) +type User interface { + Create(ctx context.Context, users []*model.User) (err error) UpdateByMap(ctx context.Context, userID string, args map[string]any) (err error) - Find(ctx context.Context, userIDs []string) (users []*UserModel, err error) - Take(ctx context.Context, userID string) (user *UserModel, err error) - TakeNotification(ctx context.Context, level int64) (user []*UserModel, err error) - TakeByNickname(ctx context.Context, nickname string) (user []*UserModel, err error) - Page(ctx context.Context, pagination pagination.Pagination) (count int64, users []*UserModel, err error) - PageFindUser(ctx context.Context, level1 int64, level2 int64, pagination pagination.Pagination) (count int64, users []*UserModel, err error) - PageFindUserWithKeyword(ctx context.Context, level1 int64, level2 int64, userID, nickName string, pagination pagination.Pagination) (count int64, users []*UserModel, err error) + Find(ctx context.Context, userIDs []string) (users []*model.User, err error) + Take(ctx context.Context, userID string) (user *model.User, err error) + TakeNotification(ctx context.Context, level int64) (user []*model.User, err error) + TakeByNickname(ctx context.Context, nickname string) (user []*model.User, err error) + Page(ctx context.Context, pagination pagination.Pagination) (count int64, users []*model.User, err error) + PageFindUser(ctx context.Context, level1 int64, level2 int64, pagination pagination.Pagination) (count int64, users []*model.User, err error) + PageFindUserWithKeyword(ctx context.Context, level1 int64, level2 int64, userID, nickName string, pagination pagination.Pagination) (count int64, users []*model.User, err error) Exist(ctx context.Context, userID string) (exist bool, err error) GetAllUserID(ctx context.Context, pagination pagination.Pagination) (count int64, userIDs []string, err error) GetUserGlobalRecvMsgOpt(ctx context.Context, userID string) (opt int, err error) diff --git a/pkg/common/storage/model/black.go b/pkg/common/storage/model/black.go new file mode 100644 index 0000000000..5e60a2fc3b --- /dev/null +++ b/pkg/common/storage/model/black.go @@ -0,0 +1,28 @@ +// 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 model + +import ( + "time" +) + +type Black struct { + OwnerUserID string `bson:"owner_user_id"` + BlockUserID string `bson:"block_user_id"` + CreateTime time.Time `bson:"create_time"` + AddSource int32 `bson:"add_source"` + OperatorUserID string `bson:"operator_user_id"` + Ex string `bson:"ex"` +} diff --git a/pkg/common/storage/model/conversation.go b/pkg/common/storage/model/conversation.go new file mode 100644 index 0000000000..590899b3f7 --- /dev/null +++ b/pkg/common/storage/model/conversation.go @@ -0,0 +1,40 @@ +// 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 model + +import ( + "time" +) + +type Conversation struct { + OwnerUserID string `bson:"owner_user_id"` + ConversationID string `bson:"conversation_id"` + ConversationType int32 `bson:"conversation_type"` + UserID string `bson:"user_id"` + GroupID string `bson:"group_id"` + RecvMsgOpt int32 `bson:"recv_msg_opt"` + IsPinned bool `bson:"is_pinned"` + IsPrivateChat bool `bson:"is_private_chat"` + BurnDuration int32 `bson:"burn_duration"` + GroupAtType int32 `bson:"group_at_type"` + AttachedInfo string `bson:"attached_info"` + Ex string `bson:"ex"` + MaxSeq int64 `bson:"max_seq"` + MinSeq int64 `bson:"min_seq"` + CreateTime time.Time `bson:"create_time"` + IsMsgDestruct bool `bson:"is_msg_destruct"` + MsgDestructTime int64 `bson:"msg_destruct_time"` + LatestMsgDestructTime time.Time `bson:"latest_msg_destruct_time"` +} diff --git a/pkg/common/storage/model/doc.go b/pkg/common/storage/model/doc.go new file mode 100644 index 0000000000..5eb7b36b0a --- /dev/null +++ b/pkg/common/storage/model/doc.go @@ -0,0 +1,15 @@ +// 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 model // import "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model/relation" diff --git a/pkg/common/storage/model/friend.go b/pkg/common/storage/model/friend.go new file mode 100644 index 0000000000..60a40d9c2a --- /dev/null +++ b/pkg/common/storage/model/friend.go @@ -0,0 +1,31 @@ +// 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 model + +import ( + "time" +) + +// Friend represents the data structure for a friend relationship in MongoDB. +type Friend struct { + OwnerUserID string `bson:"owner_user_id"` + FriendUserID string `bson:"friend_user_id"` + Remark string `bson:"remark"` + CreateTime time.Time `bson:"create_time"` + AddSource int32 `bson:"add_source"` + OperatorUserID string `bson:"operator_user_id"` + Ex string `bson:"ex"` + IsPinned bool `bson:"is_pinned"` +} diff --git a/pkg/common/storage/model/friend_request.go b/pkg/common/storage/model/friend_request.go new file mode 100644 index 0000000000..7835690cb3 --- /dev/null +++ b/pkg/common/storage/model/friend_request.go @@ -0,0 +1,31 @@ +// 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 model + +import ( + "time" +) + +type FriendRequest struct { + FromUserID string `bson:"from_user_id"` + ToUserID string `bson:"to_user_id"` + HandleResult int32 `bson:"handle_result"` + ReqMsg string `bson:"req_msg"` + CreateTime time.Time `bson:"create_time"` + HandlerUserID string `bson:"handler_user_id"` + HandleMsg string `bson:"handle_msg"` + HandleTime time.Time `bson:"handle_time"` + Ex string `bson:"ex"` +} diff --git a/pkg/common/db/table/relation/group.go b/pkg/common/storage/model/group.go similarity index 62% rename from pkg/common/db/table/relation/group.go rename to pkg/common/storage/model/group.go index f479a4745b..714fcc782b 100644 --- a/pkg/common/db/table/relation/group.go +++ b/pkg/common/storage/model/group.go @@ -12,16 +12,13 @@ // See the License for the specific language governing permissions and // limitations under the License. -package relation +package model import ( - "context" "time" - - "github.com/openimsdk/tools/db/pagination" ) -type GroupModel struct { +type Group struct { GroupID string `bson:"group_id"` GroupName string `bson:"group_name"` Notification string `bson:"notification"` @@ -38,16 +35,3 @@ type GroupModel struct { NotificationUpdateTime time.Time `bson:"notification_update_time"` NotificationUserID string `bson:"notification_user_id"` } - -type GroupModelInterface interface { - Create(ctx context.Context, groups []*GroupModel) (err error) - UpdateMap(ctx context.Context, groupID string, args map[string]any) (err error) - UpdateStatus(ctx context.Context, groupID string, status int32) (err error) - Find(ctx context.Context, groupIDs []string) (groups []*GroupModel, err error) - Take(ctx context.Context, groupID string) (group *GroupModel, err error) - Search(ctx context.Context, keyword string, pagination pagination.Pagination) (total int64, groups []*GroupModel, err error) - // Get Group total quantity - CountTotal(ctx context.Context, before *time.Time) (count int64, err error) - // Get Group total quantity every day - CountRangeEverydayTotal(ctx context.Context, start time.Time, end time.Time) (map[string]int64, error) -} diff --git a/pkg/common/storage/model/group_member.go b/pkg/common/storage/model/group_member.go new file mode 100644 index 0000000000..4cb0703edc --- /dev/null +++ b/pkg/common/storage/model/group_member.go @@ -0,0 +1,33 @@ +// 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 model + +import ( + "time" +) + +type GroupMember struct { + GroupID string `bson:"group_id"` + UserID string `bson:"user_id"` + Nickname string `bson:"nickname"` + FaceURL string `bson:"face_url"` + RoleLevel int32 `bson:"role_level"` + JoinTime time.Time `bson:"join_time"` + JoinSource int32 `bson:"join_source"` + InviterUserID string `bson:"inviter_user_id"` + OperatorUserID string `bson:"operator_user_id"` + MuteEndTime time.Time `bson:"mute_end_time"` + Ex string `bson:"ex"` +} diff --git a/pkg/common/storage/model/group_request.go b/pkg/common/storage/model/group_request.go new file mode 100644 index 0000000000..d075699f1a --- /dev/null +++ b/pkg/common/storage/model/group_request.go @@ -0,0 +1,33 @@ +// 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 model + +import ( + "time" +) + +type GroupRequest struct { + UserID string `bson:"user_id"` + GroupID string `bson:"group_id"` + HandleResult int32 `bson:"handle_result"` + ReqMsg string `bson:"req_msg"` + HandledMsg string `bson:"handled_msg"` + ReqTime time.Time `bson:"req_time"` + HandleUserID string `bson:"handle_user_id"` + HandledTime time.Time `bson:"handled_time"` + JoinSource int32 `bson:"join_source"` + InviterUserID string `bson:"inviter_user_id"` + Ex string `bson:"ex"` +} diff --git a/pkg/common/db/table/relation/log.go b/pkg/common/storage/model/log.go similarity index 67% rename from pkg/common/db/table/relation/log.go rename to pkg/common/storage/model/log.go index afc32c68e5..9db72c695a 100644 --- a/pkg/common/db/table/relation/log.go +++ b/pkg/common/storage/model/log.go @@ -12,16 +12,13 @@ // See the License for the specific language governing permissions and // limitations under the License. -package relation +package model import ( - "context" "time" - - "github.com/openimsdk/tools/db/pagination" ) -type LogModel struct { +type Log struct { LogID string `bson:"log_id"` Platform string `bson:"platform"` UserID string `bson:"user_id"` @@ -32,10 +29,3 @@ type LogModel struct { Version string `bson:"version"` Ex string `bson:"ex"` } - -type LogInterface interface { - Create(ctx context.Context, log []*LogModel) error - Search(ctx context.Context, keyword string, start time.Time, end time.Time, pagination pagination.Pagination) (int64, []*LogModel, error) - Delete(ctx context.Context, logID []string, userID string) error - Get(ctx context.Context, logIDs []string, userID string) ([]*LogModel, error) -} diff --git a/pkg/common/db/table/relation/msg.go b/pkg/common/storage/model/msg.go similarity index 65% rename from pkg/common/db/table/relation/msg.go rename to pkg/common/storage/model/msg.go index 41a6ede974..8095665d2f 100644 --- a/pkg/common/db/table/relation/msg.go +++ b/pkg/common/storage/model/msg.go @@ -12,23 +12,18 @@ // See the License for the specific language governing permissions and // limitations under the License. -package relation +package model import ( - "context" - "strconv" - "time" - - "github.com/openimsdk/protocol/msg" "github.com/openimsdk/protocol/sdkws" "github.com/openimsdk/tools/errs" - "go.mongodb.org/mongo-driver/mongo" + "strconv" ) const ( singleGocMsgNum = 100 singleGocMsgNum5000 = 5000 - Msg = "msg" + MsgTableName = "msg" OldestList = 0 NewestList = -1 ) @@ -97,35 +92,8 @@ type GroupCount struct { Count int64 `bson:"count"` } -type MsgDocModelInterface interface { - PushMsgsToDoc(ctx context.Context, docID string, msgsToMongo []MsgInfoModel) error - Create(ctx context.Context, model *MsgDocModel) error - UpdateMsg(ctx context.Context, docID string, index int64, key string, value any) (*mongo.UpdateResult, error) - PushUnique(ctx context.Context, docID string, index int64, key string, value any) (*mongo.UpdateResult, error) - UpdateMsgContent(ctx context.Context, docID string, index int64, msg []byte) error - IsExistDocID(ctx context.Context, docID string) (bool, error) - FindOneByDocID(ctx context.Context, docID string) (*MsgDocModel, error) - GetMsgBySeqIndexIn1Doc(ctx context.Context, userID, docID string, seqs []int64) ([]*MsgInfoModel, error) - GetNewestMsg(ctx context.Context, conversationID string) (*MsgInfoModel, error) - GetOldestMsg(ctx context.Context, conversationID string) (*MsgInfoModel, error) - DeleteDocs(ctx context.Context, docIDs []string) error - GetMsgDocModelByIndex(ctx context.Context, conversationID string, index, sort int64) (*MsgDocModel, error) - DeleteMsgsInOneDocByIndex(ctx context.Context, docID string, indexes []int) error - MarkSingleChatMsgsAsRead(ctx context.Context, userID string, docID string, indexes []int64) error - SearchMessage(ctx context.Context, req *msg.SearchMessageReq) (int32, []*MsgInfoModel, error) - RangeUserSendCount(ctx context.Context, start time.Time, end time.Time, group bool, ase bool, pageNumber int32, showNumber int32) (msgCount int64, userCount int64, users []*UserCount, dateCount map[string]int64, err error) - RangeGroupSendCount(ctx context.Context, start time.Time, end time.Time, ase bool, pageNumber int32, showNumber int32) (msgCount int64, userCount int64, groups []*GroupCount, dateCount map[string]int64, err error) - ConvertMsgsDocLen(ctx context.Context, conversationIDs []string) - - DeleteDoc(ctx context.Context, docID string) error - DeleteMsgByIndex(ctx context.Context, docID string, index []int) error - GetBeforeMsg(ctx context.Context, ts int64, limit int) ([]*MsgDocModel, error) - - //ClearMsg(ctx context.Context, t time.Time) (int64, error) -} - func (MsgDocModel) TableName() string { - return Msg + return MsgTableName } func (MsgDocModel) GetSingleGocMsgNum() int64 { diff --git a/pkg/common/db/table/relation/object.go b/pkg/common/storage/model/object.go similarity index 76% rename from pkg/common/db/table/relation/object.go rename to pkg/common/storage/model/object.go index 678fddcfdb..e08a55d73a 100644 --- a/pkg/common/db/table/relation/object.go +++ b/pkg/common/storage/model/object.go @@ -12,14 +12,13 @@ // See the License for the specific language governing permissions and // limitations under the License. -package relation +package model import ( - "context" "time" ) -type ObjectModel struct { +type Object struct { Name string `bson:"name"` UserID string `bson:"user_id"` Hash string `bson:"hash"` @@ -30,9 +29,3 @@ type ObjectModel struct { Group string `bson:"group"` CreateTime time.Time `bson:"create_time"` } - -type ObjectInfoModelInterface interface { - SetObject(ctx context.Context, obj *ObjectModel) error - Take(ctx context.Context, engine string, name string) (*ObjectModel, error) - Delete(ctx context.Context, engine string, name string) error -} diff --git a/pkg/common/storage/model/subscribe.go b/pkg/common/storage/model/subscribe.go new file mode 100644 index 0000000000..e71fef3e98 --- /dev/null +++ b/pkg/common/storage/model/subscribe.go @@ -0,0 +1,30 @@ +// 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 model + +// SubscribeUserTableName collection constant. +const ( + SubscribeUserTableName = "subscribe_user" +) + +// SubscribeUser collection structure. +type SubscribeUser struct { + UserID string `bson:"user_id" json:"userID"` + UserIDList []string `bson:"user_id_list" json:"userIDList"` +} + +func (SubscribeUser) TableName() string { + return SubscribeUserTableName +} diff --git a/pkg/common/storage/model/user.go b/pkg/common/storage/model/user.go new file mode 100644 index 0000000000..c6a4f952c2 --- /dev/null +++ b/pkg/common/storage/model/user.go @@ -0,0 +1,45 @@ +// 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 model + +import ( + "time" +) + +type User struct { + UserID string `bson:"user_id"` + Nickname string `bson:"nickname"` + FaceURL string `bson:"face_url"` + Ex string `bson:"ex"` + AppMangerLevel int32 `bson:"app_manger_level"` + GlobalRecvMsgOpt int32 `bson:"global_recv_msg_opt"` + CreateTime time.Time `bson:"create_time"` +} + +func (u *User) GetNickname() string { + return u.Nickname +} + +func (u *User) GetFaceURL() string { + return u.FaceURL +} + +func (u User) GetUserID() string { + return u.UserID +} + +func (u User) GetEx() string { + return u.Ex +} diff --git a/pkg/common/db/cache/config.go b/pkg/localcache/init.go similarity index 73% rename from pkg/common/db/cache/config.go rename to pkg/localcache/init.go index bb5bd449b9..d1c16f6751 100644 --- a/pkg/common/db/cache/config.go +++ b/pkg/localcache/init.go @@ -12,14 +12,13 @@ // See the License for the specific language governing permissions and // limitations under the License. -package cache +package localcache import ( + "github.com/openimsdk/open-im-server/v3/pkg/common/config" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/cache/cachekey" "strings" "sync" - - "github.com/openimsdk/open-im-server/v3/pkg/common/cachekey" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" ) var ( @@ -59,26 +58,26 @@ func InitLocalCache(localCache *config.LocalCache) { }) } -func getPublishKey(topic string, key []string) []string { - if topic == "" || len(key) == 0 { - return nil - } - prefix, ok := subscribe[topic] - if !ok { - return nil +func GetPublishKeysByTopic(topics []string, keys []string) map[string][]string { + keysByTopic := make(map[string][]string) + for _, topic := range topics { + keysByTopic[topic] = []string{} } - res := make([]string, 0, len(key)) - for _, k := range key { - var exist bool - for _, p := range prefix { - if strings.HasPrefix(k, p) { - exist = true - break + + for _, key := range keys { + for _, topic := range topics { + prefixes, ok := subscribe[topic] + if !ok { + continue + } + for _, prefix := range prefixes { + if strings.HasPrefix(key, prefix) { + keysByTopic[topic] = append(keysByTopic[topic], key) + break + } } - } - if exist { - res = append(res, k) } } - return res + + return keysByTopic } diff --git a/pkg/rpccache/conversation.go b/pkg/rpccache/conversation.go index 55897a8dae..4c00dd1f7e 100644 --- a/pkg/rpccache/conversation.go +++ b/pkg/rpccache/conversation.go @@ -16,8 +16,8 @@ package rpccache import ( "context" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/cache/cachekey" - "github.com/openimsdk/open-im-server/v3/pkg/common/cachekey" "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/localcache" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" diff --git a/pkg/rpccache/friend.go b/pkg/rpccache/friend.go index 3e9e7863ab..a5cee2567c 100644 --- a/pkg/rpccache/friend.go +++ b/pkg/rpccache/friend.go @@ -16,8 +16,8 @@ package rpccache import ( "context" + cachekey2 "github.com/openimsdk/open-im-server/v3/pkg/common/storage/cache/cachekey" - "github.com/openimsdk/open-im-server/v3/pkg/common/cachekey" "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/localcache" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" @@ -58,10 +58,10 @@ func (f *FriendLocalCache) IsFriend(ctx context.Context, possibleFriendUserID, u log.ZError(ctx, "FriendLocalCache IsFriend return", err) } }() - return localcache.AnyValue[bool](f.local.GetLink(ctx, cachekey.GetIsFriendKey(possibleFriendUserID, userID), func(ctx context.Context) (any, error) { + return localcache.AnyValue[bool](f.local.GetLink(ctx, cachekey2.GetIsFriendKey(possibleFriendUserID, userID), func(ctx context.Context) (any, error) { log.ZDebug(ctx, "FriendLocalCache IsFriend rpc", "possibleFriendUserID", possibleFriendUserID, "userID", userID) return f.client.IsFriend(ctx, possibleFriendUserID, userID) - }, cachekey.GetFriendIDsKey(possibleFriendUserID))) + }, cachekey2.GetFriendIDsKey(possibleFriendUserID))) } // IsBlack possibleBlackUserID selfUserID. @@ -74,8 +74,8 @@ func (f *FriendLocalCache) IsBlack(ctx context.Context, possibleBlackUserID, use log.ZError(ctx, "FriendLocalCache IsBlack return", err) } }() - return localcache.AnyValue[bool](f.local.GetLink(ctx, cachekey.GetIsBlackIDsKey(possibleBlackUserID, userID), func(ctx context.Context) (any, error) { + return localcache.AnyValue[bool](f.local.GetLink(ctx, cachekey2.GetIsBlackIDsKey(possibleBlackUserID, userID), func(ctx context.Context) (any, error) { log.ZDebug(ctx, "FriendLocalCache IsBlack rpc", "possibleBlackUserID", possibleBlackUserID, "userID", userID) return f.client.IsBlack(ctx, possibleBlackUserID, userID) - }, cachekey.GetBlackIDsKey(userID))) + }, cachekey2.GetBlackIDsKey(userID))) } diff --git a/pkg/rpccache/group.go b/pkg/rpccache/group.go index 7ba22beb82..55e1438be3 100644 --- a/pkg/rpccache/group.go +++ b/pkg/rpccache/group.go @@ -16,8 +16,8 @@ package rpccache import ( "context" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/cache/cachekey" - "github.com/openimsdk/open-im-server/v3/pkg/common/cachekey" "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/localcache" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" diff --git a/pkg/rpccache/user.go b/pkg/rpccache/user.go index 0a7a4e4b84..25a8eb20d4 100644 --- a/pkg/rpccache/user.go +++ b/pkg/rpccache/user.go @@ -16,8 +16,8 @@ package rpccache import ( "context" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/cache/cachekey" - "github.com/openimsdk/open-im-server/v3/pkg/common/cachekey" "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/localcache" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" diff --git a/test/testdata/README.md b/test/testdata/README.md index 74cdb71f86..b9dfea6760 100644 --- a/test/testdata/README.md +++ b/test/testdata/README.md @@ -10,7 +10,7 @@ testdata/ │ ├── README.md # 描述该目录下各子目录和文件的作用 │ -├── db/ # 存储模拟的数据库数据 +├── storage/ # 存储模拟的数据库数据 │ ├── users.json # 用户的模拟数据 │ └── messages.json # 消息的模拟数据 │ From 67fe13f089224333571ed59cb4f3ad63ff3a3cd1 Mon Sep 17 00:00:00 2001 From: OpenIM-Gordon <46924906+FGadvancer@users.noreply.github.com> Date: Mon, 27 May 2024 11:59:35 +0800 Subject: [PATCH 178/188] fix: at group message. (#2316) --- internal/rpc/msg/send.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/internal/rpc/msg/send.go b/internal/rpc/msg/send.go index 4a2d21019b..a16ca56653 100644 --- a/internal/rpc/msg/send.go +++ b/internal/rpc/msg/send.go @@ -41,7 +41,7 @@ func (m *msgServer) SendMsg(ctx context.Context, req *pbmsg.SendMsgReq) (*pbmsg. case constant.NotificationChatType: return m.sendMsgNotification(ctx, req) case constant.ReadGroupChatType: - return m.sendMsgSuperGroupChat(ctx, req) + return m.sendMsgGroupChat(ctx, req) default: return nil, errs.ErrArgs.WrapMsg("unknown sessionType") } @@ -49,7 +49,7 @@ func (m *msgServer) SendMsg(ctx context.Context, req *pbmsg.SendMsgReq) (*pbmsg. return nil, errs.ErrArgs.WrapMsg("msgData is nil") } -func (m *msgServer) sendMsgSuperGroupChat(ctx context.Context, req *pbmsg.SendMsgReq) (resp *pbmsg.SendMsgResp, err error) { +func (m *msgServer) sendMsgGroupChat(ctx context.Context, req *pbmsg.SendMsgReq) (resp *pbmsg.SendMsgResp, err error) { if err = m.messageVerification(ctx, req); err != nil { prommetrics.GroupChatMsgProcessFailedCounter.Inc() return nil, err @@ -110,6 +110,7 @@ func (m *msgServer) setConversationAtInfo(nctx context.Context, msg *sdkws.MsgDa if err != nil { log.ZWarn(ctx, "SetConversations", err, "userID", memberUserIDList, "conversation", conversation) } + return } conversation.GroupAtType = &wrapperspb.Int32Value{Value: constant.AtMe} err := m.Conversation.SetConversations(ctx, msg.AtUserIDList, conversation) From 973442e3d329286cfa31ed43c5d51852d3b6cc91 Mon Sep 17 00:00:00 2001 From: OpenIM-Gordon <46924906+FGadvancer@users.noreply.github.com> Date: Mon, 3 Jun 2024 11:24:37 +0800 Subject: [PATCH 179/188] refactor: db cache batch refactor and batch consume message. (#2325) * refactor: cmd update. * refactor: msg transfer refactor. * refactor: msg transfer refactor. * refactor: msg transfer refactor. * fix: read prometheus port when flag set to enable and prevent failure during startup. * fix: notification has counted unread counts bug fix. * fix: merge opensource code into local. * refactor: delete message and message batch use lua. * refactor: delete message and message batch use lua. * refactor: delete message and message batch use lua. * refactor: delete message and message batch use lua. * refactor: delete message and message batch use lua. * refactor: delete message and message batch use lua. * refactor: delete message and message batch use lua. * refactor: delete message and message batch use lua. * refactor: delete message and message batch use lua. * refactor: delete message and message batch use lua. * refactor: delete message and message batch use lua. * refactor: delete message and message batch use lua. * refactor: delete message and message batch use lua. * refactor: delete message and message batch use lua. * refactor: delete message and message batch use lua. * refactor: delete message and message batch use lua. * refactor: delete message and message batch use lua. * refactor: delete message and message batch use lua. * refactor: delete message and message batch use lua. * refactor: delete message and message batch use lua. * refactor: delete message and message batch use lua. * refactor: delete message and message batch use lua. * refactor: delete message and message batch use lua. * refactor: delete message and message batch use lua. * refactor: delete message and message batch use lua. * refactor: delete message and message batch use lua. * refactor: delete message and message batch use lua. * refactor: delete message and message batch use lua. * refactor: delete message and message batch use lua. * refactor: delete message and message batch use lua. * fix: add protective measures against memory overflow. --- config/redis.yml | 1 - go.mod | 5 +- go.sum | 42 +- internal/api/init.go | 15 +- internal/msggateway/hub_server.go | 4 +- internal/msggateway/init.go | 6 +- internal/msgtransfer/init.go | 58 +-- .../msgtransfer/online_history_msg_handler.go | 463 ++++++------------ .../online_msg_to_mongo_handler.go | 1 - internal/push/push_handler.go | 20 +- internal/rpc/group/group.go | 23 +- internal/rpc/group/notification.go | 4 - internal/rpc/msg/server.go | 3 +- pkg/common/config/config.go | 13 +- pkg/common/startrpc/start.go | 22 +- pkg/common/storage/cache/cachekey/msg.go | 4 - pkg/common/storage/cache/conversation.go | 3 - pkg/common/storage/cache/msg.go | 9 +- .../storage/cache/redis/batch_handler.go | 43 +- .../storage/cache/redis/conversation.go | 8 - pkg/common/storage/cache/redis/lua_script.go | 125 +++++ .../storage/cache/redis/lua_script_test.go | 75 +++ pkg/common/storage/cache/redis/meta_cache.go | 15 - pkg/common/storage/cache/redis/msg.go | 364 +++----------- pkg/common/storage/cache/redis/msg_test.go | 453 ++++------------- .../cache/redis/redis_shard_manager.go | 197 ++++++++ pkg/common/storage/cache/user.go | 6 +- pkg/common/storage/controller/msg.go | 115 +---- pkg/common/storage/database/mgo/msg.go | 25 +- pkg/tools/batcher/batcher.go | 272 ++++++++++ pkg/tools/batcher/batcher_test.go | 66 +++ 31 files changed, 1137 insertions(+), 1323 deletions(-) create mode 100644 pkg/common/storage/cache/redis/lua_script.go create mode 100644 pkg/common/storage/cache/redis/lua_script_test.go delete mode 100644 pkg/common/storage/cache/redis/meta_cache.go create mode 100644 pkg/common/storage/cache/redis/redis_shard_manager.go create mode 100644 pkg/tools/batcher/batcher.go create mode 100644 pkg/tools/batcher/batcher_test.go diff --git a/config/redis.yml b/config/redis.yml index 26becd887d..6fe0dd02d4 100644 --- a/config/redis.yml +++ b/config/redis.yml @@ -1,7 +1,6 @@ address: [ localhost:16379 ] username: '' password: openIM123 -enablePipeline: false clusterMode: false db: 0 maxRetry: 10 \ No newline at end of file diff --git a/go.mod b/go.mod index 54e8a8e0e5..e34e3e4bd8 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ require ( github.com/dtm-labs/rockscache v0.1.1 github.com/gin-gonic/gin v1.9.1 github.com/go-playground/validator/v10 v10.18.0 - github.com/gogo/protobuf v1.3.2 + github.com/gogo/protobuf v1.3.2 // indirect github.com/golang-jwt/jwt/v4 v4.5.0 github.com/gorilla/websocket v1.5.1 github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 @@ -31,6 +31,7 @@ require ( github.com/IBM/sarama v1.43.0 github.com/fatih/color v1.14.1 github.com/go-redis/redis v6.15.9+incompatible + github.com/go-redis/redismock/v9 v9.2.0 github.com/hashicorp/golang-lru/v2 v2.0.7 github.com/kelindar/bitmap v1.5.2 github.com/likexian/gokit v0.25.13 @@ -112,8 +113,6 @@ require ( github.com/modern-go/reflect2 v1.0.2 // indirect github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe // indirect github.com/mozillazg/go-httpheader v0.4.0 // indirect - github.com/onsi/ginkgo v1.16.5 // indirect - github.com/onsi/gomega v1.18.1 // indirect github.com/pelletier/go-toml/v2 v2.1.0 // indirect github.com/pierrec/lz4/v4 v4.1.21 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect diff --git a/go.sum b/go.sum index 5611a6ca65..b2fa7f318d 100644 --- a/go.sum +++ b/go.sum @@ -38,9 +38,6 @@ github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams= github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= -github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= -github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= -github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/clbanning/mxj v1.8.4 h1:HuhwZtbyvyOw+3Z1AowPkU87JkJUSv751ELWaiTpj8I= github.com/clbanning/mxj v1.8.4/go.mod h1:BVjHeAH+rl9rs6f+QIpeRl0tfu10SXn1pUSa5PVGJng= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= @@ -83,8 +80,6 @@ github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8 github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= 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/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= 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/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0= @@ -110,7 +105,8 @@ github.com/go-playground/validator/v10 v10.18.0 h1:BvolUXjp4zuvkZ5YN5t7ebzbhlUtP github.com/go-playground/validator/v10 v10.18.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM= github.com/go-redis/redis v6.15.9+incompatible h1:K0pv1D7EQUjfyoMql+r/jZqCLizCGKFlFgcHWWmHQjg= github.com/go-redis/redis v6.15.9+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= -github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= +github.com/go-redis/redismock/v9 v9.2.0 h1:ZrMYQeKPECZPjOj5u9eyOjg8Nnb0BS9lkVIZ6IpsKLw= +github.com/go-redis/redismock/v9 v9.2.0/go.mod h1:18KHfGDK4Y6c2R0H38EUGWAdc7ZQS9gfYxc94k7rWT0= 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/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= @@ -133,7 +129,6 @@ github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrU github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= -github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= @@ -157,7 +152,6 @@ github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17 github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian/v3 v3.3.2 h1:IqNFLAmvJOgVlpdEBiQbDc2EwKW77amAycfTuWKdfvw= github.com/google/martian/v3 v3.3.2/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= -github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o= github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -186,8 +180,6 @@ github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/jcmturner/aescts/v2 v2.0.0 h1:9YKLH6ey7H4eDBXW8khjYslgyqG2xZikXP0EQFKrle8= @@ -270,20 +262,12 @@ github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJ github.com/mozillazg/go-httpheader v0.2.1/go.mod h1:jJ8xECTlalr6ValeXYdOF8fFUISeBAdw6E61aqQma60= github.com/mozillazg/go-httpheader v0.4.0 h1:aBn6aRXtFzyDLZ4VIRLsZbbJloagQfMnCiYgOq6hK4w= github.com/mozillazg/go-httpheader v0.4.0/go.mod h1:PuT8h0pw6efvp8ZeUec1Rs7dwjK08bt6gKSReGMqtdA= -github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= -github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= -github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= -github.com/onsi/ginkgo/v2 v2.0.0/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= -github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= -github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= -github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE= -github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs= +github.com/onsi/gomega v1.25.0 h1:Vw7br2PCDYijJHSfBOWhov+8cAnUf8MfMaIOV323l6Y= +github.com/onsi/gomega v1.25.0/go.mod h1:r+zV744Re+DiYCIPRlYOTxn0YkOLcAnW8k1xXdMPGhM= github.com/openimsdk/gomake v0.0.13 h1:xLDe/moqgWpRoptHzI4packAWzs4C16b+sVY+txNJp0= github.com/openimsdk/gomake v0.0.13/go.mod h1:PndCozNc2IsQIciyn9mvEblYWZwJmAI+06z94EY+csI= github.com/openimsdk/protocol v0.0.65 h1:SPT9qyUsFRTTKSKb/FjpS+xr6sxz/Kbnu+su1bxYagc= @@ -348,7 +332,6 @@ 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.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -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= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= @@ -438,18 +421,15 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= @@ -467,21 +447,12 @@ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJ 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/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 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-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -494,7 +465,6 @@ golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuX golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= @@ -509,7 +479,6 @@ golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3 golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 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/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -556,14 +525,11 @@ google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHh gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/internal/api/init.go b/internal/api/init.go index b49a145696..23866c4a07 100644 --- a/internal/api/init.go +++ b/internal/api/init.go @@ -48,10 +48,6 @@ func Start(ctx context.Context, index int, config *Config) error { if err != nil { return err } - prometheusPort, err := datautil.GetElemByIndex(config.API.Prometheus.Ports, index) - if err != nil { - return err - } var client discovery.SvcDiscoveryRegistry @@ -62,13 +58,20 @@ func Start(ctx context.Context, index int, config *Config) error { } var ( - netDone = make(chan struct{}, 1) - netErr error + netDone = make(chan struct{}, 1) + netErr error + prometheusPort int ) router := newGinRouter(client, config) if config.API.Prometheus.Enable { go func() { + prometheusPort, err = datautil.GetElemByIndex(config.API.Prometheus.Ports, index) + if err != nil { + netErr = err + netDone <- struct{}{} + return + } p := ginprom.NewPrometheus("app", prommetrics.GetGinCusMetrics("Api")) p.SetListenAddress(fmt.Sprintf(":%d", prometheusPort)) if err = p.Use(router); err != nil && err != http.ErrServerClosed { diff --git a/internal/msggateway/hub_server.go b/internal/msggateway/hub_server.go index f9bb699ed9..8ff6d10018 100644 --- a/internal/msggateway/hub_server.go +++ b/internal/msggateway/hub_server.go @@ -47,7 +47,6 @@ func (s *Server) Start(ctx context.Context, index int, conf *Config) error { type Server struct { rpcPort int - prometheusPort int LongConnServer LongConnServer config *Config pushTerminal map[int]struct{} @@ -57,10 +56,9 @@ func (s *Server) SetLongConnServer(LongConnServer LongConnServer) { s.LongConnServer = LongConnServer } -func NewServer(rpcPort int, proPort int, longConnServer LongConnServer, conf *Config) *Server { +func NewServer(rpcPort int, longConnServer LongConnServer, conf *Config) *Server { s := &Server{ rpcPort: rpcPort, - prometheusPort: proPort, LongConnServer: longConnServer, pushTerminal: make(map[int]struct{}), config: conf, diff --git a/internal/msggateway/init.go b/internal/msggateway/init.go index ef24d1bf93..f4d8b0381a 100644 --- a/internal/msggateway/init.go +++ b/internal/msggateway/init.go @@ -38,10 +38,6 @@ func Start(ctx context.Context, index int, conf *Config) error { if err != nil { return err } - prometheusPort, err := datautil.GetElemByIndex(conf.MsgGateway.Prometheus.Ports, index) - if err != nil { - return err - } rpcPort, err := datautil.GetElemByIndex(conf.MsgGateway.RPC.Ports, index) if err != nil { return err @@ -57,7 +53,7 @@ func Start(ctx context.Context, index int, conf *Config) error { return err } - hubServer := NewServer(rpcPort, prometheusPort, longServer, conf) + hubServer := NewServer(rpcPort, longServer, conf) netDone := make(chan error) go func() { err = hubServer.Start(ctx, index, conf) diff --git a/internal/msgtransfer/init.go b/internal/msgtransfer/init.go index ba82abacfd..65d04f3810 100644 --- a/internal/msgtransfer/init.go +++ b/internal/msgtransfer/init.go @@ -44,15 +44,14 @@ import ( ) type MsgTransfer struct { - // This consumer aggregated messages, subscribed to the topic:ws2ms_chat, - // the modification notification is sent to msg_to_modify topic, the message is stored in redis, Incr Redis, - // and then the message is sent to ms2pschat topic for push, and the message is sent to msg_to_mongo topic for persistence - historyCH *OnlineHistoryRedisConsumerHandler + // This consumer aggregated messages, subscribed to the topic:toRedis, + // the message is stored in redis, Incr Redis, and then the message is sent to toPush topic for push, + // and the message is sent to toMongo topic for persistence + historyCH *OnlineHistoryRedisConsumerHandler + //This consumer handle message to mongo historyMongoCH *OnlineHistoryMongoConsumerHandler - // mongoDB batch insert, delete messages in redis after success, - // and handle the deletion notification message deleted subscriptions topic: msg_to_mongo - ctx context.Context - cancel context.CancelFunc + ctx context.Context + cancel context.CancelFunc } type Config struct { @@ -82,8 +81,7 @@ func Start(ctx context.Context, index int, config *Config) error { } client.AddOption(mw.GrpcClient(), grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithDefaultServiceConfig(fmt.Sprintf(`{"LoadBalancingPolicy": "%s"}`, "round_robin"))) - //todo MsgCacheTimeout - msgModel := redis.NewMsgCache(rdb, config.RedisConfig.EnablePipeline) + msgModel := redis.NewMsgCache(rdb) seqModel := redis.NewSeqCache(rdb) msgDocModel, err := mgo.NewMsgMongo(mgocli.GetDB()) if err != nil { @@ -95,37 +93,23 @@ func Start(ctx context.Context, index int, config *Config) error { } conversationRpcClient := rpcclient.NewConversationRpcClient(client, config.Share.RpcRegisterName.Conversation) groupRpcClient := rpcclient.NewGroupRpcClient(client, config.Share.RpcRegisterName.Group) - msgTransfer, err := NewMsgTransfer(&config.KafkaConfig, msgDatabase, &conversationRpcClient, &groupRpcClient) + historyCH, err := NewOnlineHistoryRedisConsumerHandler(&config.KafkaConfig, msgDatabase, &conversationRpcClient, &groupRpcClient) if err != nil { return err } - return msgTransfer.Start(index, config) -} - -func NewMsgTransfer(kafkaConf *config.Kafka, msgDatabase controller.CommonMsgDatabase, - conversationRpcClient *rpcclient.ConversationRpcClient, groupRpcClient *rpcclient.GroupRpcClient) (*MsgTransfer, error) { - historyCH, err := NewOnlineHistoryRedisConsumerHandler(kafkaConf, msgDatabase, conversationRpcClient, groupRpcClient) - if err != nil { - return nil, err - } - historyMongoCH, err := NewOnlineHistoryMongoConsumerHandler(kafkaConf, msgDatabase) + historyMongoCH, err := NewOnlineHistoryMongoConsumerHandler(&config.KafkaConfig, msgDatabase) if err != nil { - return nil, err + return err } - - return &MsgTransfer{ + msgTransfer := &MsgTransfer{ historyCH: historyCH, historyMongoCH: historyMongoCH, - }, nil + } + return msgTransfer.Start(index, config) } func (m *MsgTransfer) Start(index int, config *Config) error { - prometheusPort, err := datautil.GetElemByIndex(config.MsgTransfer.Prometheus.Ports, index) - if err != nil { - return err - } m.ctx, m.cancel = context.WithCancel(context.Background()) - var ( netDone = make(chan struct{}, 1) netErr error @@ -133,16 +117,26 @@ func (m *MsgTransfer) Start(index int, config *Config) error { go m.historyCH.historyConsumerGroup.RegisterHandleAndConsumer(m.ctx, m.historyCH) go m.historyMongoCH.historyConsumerGroup.RegisterHandleAndConsumer(m.ctx, m.historyMongoCH) + err := m.historyCH.redisMessageBatches.Start() + if err != nil { + return err + } if config.MsgTransfer.Prometheus.Enable { go func() { + prometheusPort, err := datautil.GetElemByIndex(config.MsgTransfer.Prometheus.Ports, index) + if err != nil { + netErr = err + netDone <- struct{}{} + return + } proreg := prometheus.NewRegistry() proreg.MustRegister( collectors.NewGoCollector(), ) proreg.MustRegister(prommetrics.GetGrpcCusMetrics("Transfer", &config.Share)...) http.Handle("/metrics", promhttp.HandlerFor(proreg, promhttp.HandlerOpts{Registry: proreg})) - err := http.ListenAndServe(fmt.Sprintf(":%d", prometheusPort), nil) + err = http.ListenAndServe(fmt.Sprintf(":%d", prometheusPort), nil) if err != nil && err != http.ErrServerClosed { netErr = errs.WrapMsg(err, "prometheus start error", "prometheusPort", prometheusPort) netDone <- struct{}{} @@ -157,11 +151,13 @@ func (m *MsgTransfer) Start(index int, config *Config) error { program.SIGTERMExit() // graceful close kafka client. m.cancel() + m.historyCH.redisMessageBatches.Close() m.historyCH.historyConsumerGroup.Close() m.historyMongoCH.historyConsumerGroup.Close() return nil case <-netDone: m.cancel() + m.historyCH.redisMessageBatches.Close() m.historyCH.historyConsumerGroup.Close() m.historyMongoCH.historyConsumerGroup.Close() close(netDone) diff --git a/internal/msgtransfer/online_history_msg_handler.go b/internal/msgtransfer/online_history_msg_handler.go index 194b70187e..d671ec52a2 100644 --- a/internal/msgtransfer/online_history_msg_handler.go +++ b/internal/msgtransfer/online_history_msg_handler.go @@ -16,51 +16,34 @@ package msgtransfer import ( "context" - "strconv" - "strings" - "sync" - "sync/atomic" - "time" - "github.com/IBM/sarama" "github.com/go-redis/redis" "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/storage/controller" "github.com/openimsdk/open-im-server/v3/pkg/msgprocessor" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" + "github.com/openimsdk/open-im-server/v3/pkg/tools/batcher" "github.com/openimsdk/protocol/constant" "github.com/openimsdk/protocol/sdkws" "github.com/openimsdk/tools/errs" "github.com/openimsdk/tools/log" "github.com/openimsdk/tools/mcontext" "github.com/openimsdk/tools/mq/kafka" - "github.com/openimsdk/tools/utils/idutil" "github.com/openimsdk/tools/utils/stringutil" "google.golang.org/protobuf/proto" + "strconv" + "strings" + "time" ) const ( - ConsumerMsgs = 3 - SourceMessages = 4 - MongoMessages = 5 - ChannelNum = 100 + size = 500 + mainDataBuffer = 500 + subChanBuffer = 50 + worker = 50 + interval = 100 * time.Millisecond ) -type MsgChannelValue struct { - uniqueKey string - ctx context.Context - ctxMsgList []*ContextMsg -} - -type TriggerChannelValue struct { - ctx context.Context - cMsgList []*sarama.ConsumerMessage -} - -type Cmd2Value struct { - Cmd int - Value any -} type ContextMsg struct { message *sdkws.MsgData ctx context.Context @@ -68,13 +51,8 @@ type ContextMsg struct { type OnlineHistoryRedisConsumerHandler struct { historyConsumerGroup *kafka.MConsumerGroup - chArrays [ChannelNum]chan Cmd2Value - msgDistributionCh chan Cmd2Value - // singleMsgSuccessCount uint64 - // singleMsgFailedCount uint64 - // singleMsgSuccessCountMutex sync.Mutex - // singleMsgFailedCountMutex sync.Mutex + redisMessageBatches *batcher.Batcher[sarama.ConsumerMessage] msgDatabase controller.CommonMsgDatabase conversationRpcClient *rpcclient.ConversationRpcClient @@ -83,89 +61,82 @@ type OnlineHistoryRedisConsumerHandler struct { func NewOnlineHistoryRedisConsumerHandler(kafkaConf *config.Kafka, database controller.CommonMsgDatabase, conversationRpcClient *rpcclient.ConversationRpcClient, groupRpcClient *rpcclient.GroupRpcClient) (*OnlineHistoryRedisConsumerHandler, error) { - historyConsumerGroup, err := kafka.NewMConsumerGroup(kafkaConf.Build(), kafkaConf.ToRedisGroupID, []string{kafkaConf.ToRedisTopic}, true) + historyConsumerGroup, err := kafka.NewMConsumerGroup(kafkaConf.Build(), kafkaConf.ToRedisGroupID, []string{kafkaConf.ToRedisTopic}, false) if err != nil { return nil, err } var och OnlineHistoryRedisConsumerHandler och.msgDatabase = database - och.msgDistributionCh = make(chan Cmd2Value) // no buffer channel - go och.MessagesDistributionHandle() - for i := 0; i < ChannelNum; i++ { - och.chArrays[i] = make(chan Cmd2Value, 50) - go och.Run(i) + + b := batcher.New[sarama.ConsumerMessage]( + batcher.WithSize(size), + batcher.WithWorker(worker), + batcher.WithInterval(interval), + batcher.WithDataBuffer(mainDataBuffer), + batcher.WithSyncWait(true), + batcher.WithBuffer(subChanBuffer), + ) + b.Sharding = func(key string) int { + hashCode := stringutil.GetHashCode(key) + return int(hashCode) % och.redisMessageBatches.Worker() + } + b.Key = func(consumerMessage *sarama.ConsumerMessage) string { + return string(consumerMessage.Key) } + b.Do = och.do + och.redisMessageBatches = b och.conversationRpcClient = conversationRpcClient och.groupRpcClient = groupRpcClient och.historyConsumerGroup = historyConsumerGroup return &och, err } +func (och *OnlineHistoryRedisConsumerHandler) do(ctx context.Context, channelID int, val *batcher.Msg[sarama.ConsumerMessage]) { + ctx = mcontext.WithTriggerIDContext(ctx, val.TriggerID()) + ctxMessages := och.parseConsumerMessages(ctx, val.Val()) + ctx = withAggregationCtx(ctx, ctxMessages) + log.ZInfo(ctx, "msg arrived channel", "channel id", channelID, "msgList length", len(ctxMessages), + "key", val.Key()) + + storageMsgList, notStorageMsgList, storageNotificationList, notStorageNotificationList := + och.categorizeMessageLists(ctxMessages) + log.ZDebug(ctx, "number of categorized messages", "storageMsgList", len(storageMsgList), "notStorageMsgList", + len(notStorageMsgList), "storageNotificationList", len(storageNotificationList), "notStorageNotificationList", + len(notStorageNotificationList)) + + conversationIDMsg := msgprocessor.GetChatConversationIDByMsg(ctxMessages[0].message) + conversationIDNotification := msgprocessor.GetNotificationConversationIDByMsg(ctxMessages[0].message) + och.handleMsg(ctx, val.Key(), conversationIDMsg, storageMsgList, notStorageMsgList) + och.handleNotification(ctx, val.Key(), conversationIDNotification, storageNotificationList, notStorageNotificationList) +} -func (och *OnlineHistoryRedisConsumerHandler) Run(channelID int) { - for cmd := range och.chArrays[channelID] { - switch cmd.Cmd { - case SourceMessages: - msgChannelValue := cmd.Value.(MsgChannelValue) - ctxMsgList := msgChannelValue.ctxMsgList - ctx := msgChannelValue.ctx - log.ZDebug( - ctx, - "msg arrived channel", - "channel id", - channelID, - "msgList length", - len(ctxMsgList), - "uniqueKey", - msgChannelValue.uniqueKey, - ) - storageMsgList, notStorageMsgList, storageNotificationList, notStorageNotificationList, modifyMsgList := och.getPushStorageMsgList( - ctxMsgList, - ) - log.ZDebug( - ctx, - "msg lens", - "storageMsgList", - len(storageMsgList), - "notStorageMsgList", - len(notStorageMsgList), - "storageNotificationList", - len(storageNotificationList), - "notStorageNotificationList", - len(notStorageNotificationList), - "modifyMsgList", - len(modifyMsgList), - ) - conversationIDMsg := msgprocessor.GetChatConversationIDByMsg(ctxMsgList[0].message) - conversationIDNotification := msgprocessor.GetNotificationConversationIDByMsg(ctxMsgList[0].message) - och.handleMsg(ctx, msgChannelValue.uniqueKey, conversationIDMsg, storageMsgList, notStorageMsgList) - och.handleNotification( - ctx, - msgChannelValue.uniqueKey, - conversationIDNotification, - storageNotificationList, - notStorageNotificationList, - ) - if err := och.msgDatabase.MsgToModifyMQ(ctx, msgChannelValue.uniqueKey, conversationIDNotification, modifyMsgList); err != nil { - log.ZError(ctx, "msg to modify mq error", err, "uniqueKey", msgChannelValue.uniqueKey, "modifyMsgList", modifyMsgList) - } +func (och *OnlineHistoryRedisConsumerHandler) parseConsumerMessages(ctx context.Context, consumerMessages []*sarama.ConsumerMessage) []*ContextMsg { + var ctxMessages []*ContextMsg + for i := 0; i < len(consumerMessages); i++ { + ctxMsg := &ContextMsg{} + msgFromMQ := &sdkws.MsgData{} + err := proto.Unmarshal(consumerMessages[i].Value, msgFromMQ) + if err != nil { + log.ZWarn(ctx, "msg_transfer Unmarshal msg err", err, string(consumerMessages[i].Value)) + continue } + var arr []string + for i, header := range consumerMessages[i].Headers { + arr = append(arr, strconv.Itoa(i), string(header.Key), string(header.Value)) + } + log.ZDebug(ctx, "consumer.kafka.GetContextWithMQHeader", "len", len(consumerMessages[i].Headers), + "header", strings.Join(arr, ", ")) + ctxMsg.ctx = kafka.GetContextWithMQHeader(consumerMessages[i].Headers) + ctxMsg.message = msgFromMQ + log.ZDebug(ctx, "message parse finish", "message", msgFromMQ, "key", + string(consumerMessages[i].Key)) + ctxMessages = append(ctxMessages, ctxMsg) } + return ctxMessages } // Get messages/notifications stored message list, not stored and pushed message list. -func (och *OnlineHistoryRedisConsumerHandler) getPushStorageMsgList( - totalMsgs []*ContextMsg, -) (storageMsgList, notStorageMsgList, storageNotificatoinList, notStorageNotificationList, modifyMsgList []*sdkws.MsgData) { - isStorage := func(msg *sdkws.MsgData) bool { - options2 := msgprocessor.Options(msg.Options) - if options2.IsHistory() { - return true - } - // if !(!options2.IsSenderSync() && conversationID == msg.MsgData.SendID) { - // return false - // } - return false - } +func (och *OnlineHistoryRedisConsumerHandler) categorizeMessageLists(totalMsgs []*ContextMsg) (storageMsgList, + notStorageMsgList, storageNotificationList, notStorageNotificationList []*ContextMsg) { for _, v := range totalMsgs { options := msgprocessor.Options(v.message.Options) if !options.IsNotNotification() { @@ -185,176 +156,106 @@ func (och *OnlineHistoryRedisConsumerHandler) getPushStorageMsgList( msgprocessor.WithOfflinePush(false), msgprocessor.WithUnreadCount(false), ) - storageMsgList = append(storageMsgList, msg) + ctxMsg := &ContextMsg{ + message: msg, + ctx: v.ctx, + } + storageMsgList = append(storageMsgList, ctxMsg) } - if isStorage(v.message) { - storageNotificatoinList = append(storageNotificatoinList, v.message) + if options.IsHistory() { + storageNotificationList = append(storageNotificationList, v) } else { - notStorageNotificationList = append(notStorageNotificationList, v.message) + notStorageNotificationList = append(notStorageNotificationList, v) } } else { - if isStorage(v.message) { - storageMsgList = append(storageMsgList, v.message) + if options.IsHistory() { + storageMsgList = append(storageMsgList, v) } else { - notStorageMsgList = append(notStorageMsgList, v.message) + notStorageMsgList = append(notStorageMsgList, v) } } - if v.message.ContentType == constant.ReactionMessageModifier || - v.message.ContentType == constant.ReactionMessageDeleter { - modifyMsgList = append(modifyMsgList, v.message) - } } return } -func (och *OnlineHistoryRedisConsumerHandler) handleNotification( - ctx context.Context, - key, conversationID string, - storageList, notStorageList []*sdkws.MsgData, -) { +func (och *OnlineHistoryRedisConsumerHandler) handleMsg(ctx context.Context, key, conversationID string, storageList, notStorageList []*ContextMsg) { och.toPushTopic(ctx, key, conversationID, notStorageList) - if len(storageList) > 0 { - lastSeq, _, err := och.msgDatabase.BatchInsertChat2Cache(ctx, conversationID, storageList) - if err != nil { - log.ZError( - ctx, - "notification batch insert to redis error", - err, - "conversationID", - conversationID, - "storageList", - storageList, - ) - return - } - log.ZDebug(ctx, "success to next topic", "conversationID", conversationID) - err = och.msgDatabase.MsgToMongoMQ(ctx, key, conversationID, storageList, lastSeq) - if err != nil { - log.ZError(ctx, "MsgToMongoMQ error", err) - } - och.toPushTopic(ctx, key, conversationID, storageList) - } -} - -func (och *OnlineHistoryRedisConsumerHandler) toPushTopic(ctx context.Context, key, conversationID string, msgs []*sdkws.MsgData) { - for _, v := range msgs { - och.msgDatabase.MsgToPushMQ(ctx, key, conversationID, v) // nolint: errcheck + var storageMessageList []*sdkws.MsgData + for _, msg := range storageList { + storageMessageList = append(storageMessageList, msg.message) } -} - -func (och *OnlineHistoryRedisConsumerHandler) handleMsg(ctx context.Context, key, conversationID string, storageList, notStorageList []*sdkws.MsgData) { - och.toPushTopic(ctx, key, conversationID, notStorageList) - if len(storageList) > 0 { - lastSeq, isNewConversation, err := och.msgDatabase.BatchInsertChat2Cache(ctx, conversationID, storageList) + if len(storageMessageList) > 0 { + msg := storageMessageList[0] + lastSeq, isNewConversation, err := och.msgDatabase.BatchInsertChat2Cache(ctx, conversationID, storageMessageList) if err != nil && errs.Unwrap(err) != redis.Nil { - log.ZError(ctx, "batch data insert to redis err", err, "storageMsgList", storageList) + log.ZError(ctx, "batch data insert to redis err", err, "storageMsgList", storageMessageList) return } if isNewConversation { - switch storageList[0].SessionType { + switch msg.SessionType { case constant.ReadGroupChatType: log.ZInfo(ctx, "group chat first create conversation", "conversationID", conversationID) - userIDs, err := och.groupRpcClient.GetGroupMemberIDs(ctx, storageList[0].GroupID) + userIDs, err := och.groupRpcClient.GetGroupMemberIDs(ctx, msg.GroupID) if err != nil { log.ZWarn(ctx, "get group member ids error", err, "conversationID", conversationID) } else { if err := och.conversationRpcClient.GroupChatFirstCreateConversation(ctx, - storageList[0].GroupID, userIDs); err != nil { + msg.GroupID, userIDs); err != nil { log.ZWarn(ctx, "single chat first create conversation error", err, "conversationID", conversationID) } } case constant.SingleChatType, constant.NotificationChatType: - if err := och.conversationRpcClient.SingleChatFirstCreateConversation(ctx, storageList[0].RecvID, - storageList[0].SendID, conversationID, storageList[0].SessionType); err != nil { + if err := och.conversationRpcClient.SingleChatFirstCreateConversation(ctx, msg.RecvID, + msg.SendID, conversationID, msg.SessionType); err != nil { log.ZWarn(ctx, "single chat or notification first create conversation error", err, - "conversationID", conversationID, "sessionType", storageList[0].SessionType) + "conversationID", conversationID, "sessionType", msg.SessionType) } default: log.ZWarn(ctx, "unknown session type", nil, "sessionType", - storageList[0].SessionType) + msg.SessionType) } } log.ZDebug(ctx, "success incr to next topic") - err = och.msgDatabase.MsgToMongoMQ(ctx, key, conversationID, storageList, lastSeq) + err = och.msgDatabase.MsgToMongoMQ(ctx, key, conversationID, storageMessageList, lastSeq) if err != nil { - log.ZError(ctx, "MsgToMongoMQ error", err) + log.ZError(ctx, "Msg To MongoDB MQ error", err, "conversationID", + conversationID, "storageList", storageMessageList, "lastSeq", lastSeq) } och.toPushTopic(ctx, key, conversationID, storageList) } } -func (och *OnlineHistoryRedisConsumerHandler) MessagesDistributionHandle() { - for { - aggregationMsgs := make(map[string][]*ContextMsg, ChannelNum) - select { - case cmd := <-och.msgDistributionCh: - switch cmd.Cmd { - case ConsumerMsgs: - triggerChannelValue := cmd.Value.(TriggerChannelValue) - ctx := triggerChannelValue.ctx - consumerMessages := triggerChannelValue.cMsgList - // Aggregation map[userid]message list - log.ZDebug(ctx, "batch messages come to distribution center", "length", len(consumerMessages)) - for i := 0; i < len(consumerMessages); i++ { - ctxMsg := &ContextMsg{} - msgFromMQ := &sdkws.MsgData{} - err := proto.Unmarshal(consumerMessages[i].Value, msgFromMQ) - if err != nil { - log.ZError(ctx, "msg_transfer Unmarshal msg err", err, string(consumerMessages[i].Value)) - continue - } - var arr []string - for i, header := range consumerMessages[i].Headers { - arr = append(arr, strconv.Itoa(i), string(header.Key), string(header.Value)) - } - log.ZInfo(ctx, "consumer.kafka.GetContextWithMQHeader", "len", len(consumerMessages[i].Headers), - "header", strings.Join(arr, ", ")) - ctxMsg.ctx = kafka.GetContextWithMQHeader(consumerMessages[i].Headers) - ctxMsg.message = msgFromMQ - log.ZDebug( - ctx, - "single msg come to distribution center", - "message", - msgFromMQ, - "key", - string(consumerMessages[i].Key), - ) - // aggregationMsgs[string(consumerMessages[i].Key)] = - // append(aggregationMsgs[string(consumerMessages[i].Key)], ctxMsg) - if oldM, ok := aggregationMsgs[string(consumerMessages[i].Key)]; ok { - oldM = append(oldM, ctxMsg) - aggregationMsgs[string(consumerMessages[i].Key)] = oldM - } else { - m := make([]*ContextMsg, 0, 100) - m = append(m, ctxMsg) - aggregationMsgs[string(consumerMessages[i].Key)] = m - } - } - log.ZDebug(ctx, "generate map list users len", "length", len(aggregationMsgs)) - for uniqueKey, v := range aggregationMsgs { - if len(v) >= 0 { - hashCode := stringutil.GetHashCode(uniqueKey) - channelID := hashCode % ChannelNum - newCtx := withAggregationCtx(ctx, v) - log.ZDebug( - newCtx, - "generate channelID", - "hashCode", - hashCode, - "channelID", - channelID, - "uniqueKey", - uniqueKey, - ) - och.chArrays[channelID] <- Cmd2Value{Cmd: SourceMessages, Value: MsgChannelValue{uniqueKey: uniqueKey, ctxMsgList: v, ctx: newCtx}} - } - } - } +func (och *OnlineHistoryRedisConsumerHandler) handleNotification(ctx context.Context, key, conversationID string, + storageList, notStorageList []*ContextMsg) { + och.toPushTopic(ctx, key, conversationID, notStorageList) + var storageMessageList []*sdkws.MsgData + for _, msg := range storageList { + storageMessageList = append(storageMessageList, msg.message) + } + if len(storageMessageList) > 0 { + lastSeq, _, err := och.msgDatabase.BatchInsertChat2Cache(ctx, conversationID, storageMessageList) + if err != nil { + log.ZError(ctx, "notification batch insert to redis error", err, "conversationID", conversationID, + "storageList", storageMessageList) + return + } + log.ZDebug(ctx, "success to next topic", "conversationID", conversationID) + err = och.msgDatabase.MsgToMongoMQ(ctx, key, conversationID, storageMessageList, lastSeq) + if err != nil { + log.ZError(ctx, "Msg To MongoDB MQ error", err, "conversationID", + conversationID, "storageList", storageMessageList, "lastSeq", lastSeq) } + och.toPushTopic(ctx, key, conversationID, storageList) + } +} + +func (och *OnlineHistoryRedisConsumerHandler) toPushTopic(_ context.Context, key, conversationID string, msgs []*ContextMsg) { + for _, v := range msgs { + och.msgDatabase.MsgToPushMQ(v.ctx, key, conversationID, v.message) } } @@ -377,106 +278,30 @@ func (och *OnlineHistoryRedisConsumerHandler) Cleanup(_ sarama.ConsumerGroupSess return nil } -func (och *OnlineHistoryRedisConsumerHandler) ConsumeClaim( - sess sarama.ConsumerGroupSession, - claim sarama.ConsumerGroupClaim, -) error { // a instance in the consumer group - for { - if sess == nil { - log.ZWarn(context.Background(), "sess == nil, waiting", nil) - time.Sleep(100 * time.Millisecond) - } else { - break - } - } +func (och *OnlineHistoryRedisConsumerHandler) ConsumeClaim(session sarama.ConsumerGroupSession, + claim sarama.ConsumerGroupClaim) error { // a instance in the consumer group log.ZInfo(context.Background(), "online new session msg come", "highWaterMarkOffset", claim.HighWaterMarkOffset(), "topic", claim.Topic(), "partition", claim.Partition()) - - var ( - split = 1000 - rwLock = new(sync.RWMutex) - messages = make([]*sarama.ConsumerMessage, 0, 1000) - ticker = time.NewTicker(time.Millisecond * 100) - - wg = sync.WaitGroup{} - running = new(atomic.Bool) - ) - running.Store(true) - - wg.Add(1) - go func() { - defer wg.Done() - - for { - select { - case <-ticker.C: - // if the buffer is empty and running is false, return loop. - if len(messages) == 0 { - if !running.Load() { - return - } - - continue - } - - rwLock.Lock() - buffer := make([]*sarama.ConsumerMessage, 0, len(messages)) - buffer = append(buffer, messages...) - - // reuse slice, set cap to 0 - messages = messages[:0] - rwLock.Unlock() - - start := time.Now() - ctx := mcontext.WithTriggerIDContext(context.Background(), idutil.OperationIDGenerator()) - log.ZDebug(ctx, "timer trigger msg consumer start", "length", len(buffer)) - for i := 0; i < len(buffer)/split; i++ { - och.msgDistributionCh <- Cmd2Value{Cmd: ConsumerMsgs, Value: TriggerChannelValue{ - ctx: ctx, cMsgList: buffer[i*split : (i+1)*split], - }} - } - if (len(buffer) % split) > 0 { - och.msgDistributionCh <- Cmd2Value{Cmd: ConsumerMsgs, Value: TriggerChannelValue{ - ctx: ctx, cMsgList: buffer[split*(len(buffer)/split):], - }} - } - - log.ZDebug(ctx, "timer trigger msg consumer end", - "length", len(buffer), "time_cost", time.Since(start), - ) + och.redisMessageBatches.OnComplete = func(lastMessage *sarama.ConsumerMessage, totalCount int) { + session.MarkMessage(lastMessage, "") + session.Commit() + } + for { + select { + case msg, ok := <-claim.Messages(): + if !ok { + return nil } - } - }() - wg.Add(1) - go func() { - defer wg.Done() - - for running.Load() { - select { - case msg, ok := <-claim.Messages(): - if !ok { - running.Store(false) - return - } - - if len(msg.Value) == 0 { - continue - } - - rwLock.Lock() - messages = append(messages, msg) - rwLock.Unlock() - - sess.MarkMessage(msg, "") - - case <-sess.Context().Done(): - running.Store(false) - return + if len(msg.Value) == 0 { + continue + } + err := och.redisMessageBatches.Put(context.Background(), msg) + if err != nil { + log.ZWarn(context.Background(), "put msg to error", err, "msg", msg) } + case <-session.Context().Done(): + return nil } - }() - - wg.Wait() - return nil + } } diff --git a/internal/msgtransfer/online_msg_to_mongo_handler.go b/internal/msgtransfer/online_msg_to_mongo_handler.go index 0fa9fe0d12..e5651012c6 100644 --- a/internal/msgtransfer/online_msg_to_mongo_handler.go +++ b/internal/msgtransfer/online_msg_to_mongo_handler.go @@ -89,7 +89,6 @@ func (mc *OnlineHistoryMongoConsumerHandler) handleChatWs2Mongo(ctx context.Cont msgFromMQ.ConversationID, ) } - mc.msgDatabase.DelUserDeleteMsgsList(ctx, msgFromMQ.ConversationID, seqs) } func (OnlineHistoryMongoConsumerHandler) Setup(_ sarama.ConsumerGroupSession) error { return nil } diff --git a/internal/push/push_handler.go b/internal/push/push_handler.go index bf0ede375c..03c299b7ab 100644 --- a/internal/push/push_handler.go +++ b/internal/push/push_handler.go @@ -17,6 +17,7 @@ package push import ( "context" "encoding/json" + "github.com/IBM/sarama" "github.com/openimsdk/open-im-server/v3/internal/push/offlinepush" "github.com/openimsdk/open-im-server/v3/internal/push/offlinepush/options" "github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics" @@ -25,20 +26,18 @@ import ( "github.com/openimsdk/open-im-server/v3/pkg/rpccache" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" "github.com/openimsdk/open-im-server/v3/pkg/util/conversationutil" - "github.com/openimsdk/protocol/sdkws" - "github.com/openimsdk/tools/discovery" - "github.com/openimsdk/tools/mcontext" - "github.com/openimsdk/tools/utils/jsonutil" - "github.com/redis/go-redis/v9" - - "github.com/IBM/sarama" "github.com/openimsdk/protocol/constant" pbchat "github.com/openimsdk/protocol/msg" pbpush "github.com/openimsdk/protocol/push" + "github.com/openimsdk/protocol/sdkws" + "github.com/openimsdk/tools/discovery" "github.com/openimsdk/tools/log" + "github.com/openimsdk/tools/mcontext" "github.com/openimsdk/tools/mq/kafka" "github.com/openimsdk/tools/utils/datautil" + "github.com/openimsdk/tools/utils/jsonutil" "github.com/openimsdk/tools/utils/timeutil" + "github.com/redis/go-redis/v9" "google.golang.org/protobuf/proto" ) @@ -162,7 +161,8 @@ func (c *ConsumerHandler) Push2User(ctx context.Context, userIDs []string, msg * err = c.offlinePushMsg(ctx, msg, offlinePUshUserID) if err != nil { - return err + log.ZWarn(ctx, "offlinePushMsg failed", err, "offlinePUshUserID", offlinePUshUserID, "msg", msg) + return nil } return nil @@ -223,8 +223,8 @@ func (c *ConsumerHandler) Push2Group(ctx context.Context, groupID string, msg *s err = c.offlinePushMsg(ctx, msg, needOfflinePushUserIDs) if err != nil { - log.ZError(ctx, "offlinePushMsg failed", err, "groupID", groupID, "msg", msg) - return err + log.ZWarn(ctx, "offlinePushMsg failed", err, "groupID", groupID, "msg", msg) + return nil } } diff --git a/internal/rpc/group/group.go b/internal/rpc/group/group.go index 51fd2d7b66..a9cea4ff22 100644 --- a/internal/rpc/group/group.go +++ b/internal/rpc/group/group.go @@ -292,28 +292,7 @@ func (s *groupServer) CreateGroup(ctx context.Context, req *pbgroup.CreateGroupR break } } - if req.GroupInfo.GroupType == constant.SuperGroup { - go func() { - for _, userID := range userIDs { - s.notification.SuperGroupNotification(ctx, userID, userID) - } - }() - } else { - tips := &sdkws.GroupCreatedTips{ - Group: resp.GroupInfo, - OperationTime: group.CreateTime.UnixMilli(), - GroupOwnerUser: s.groupMemberDB2PB(groupMembers[0], userMap[groupMembers[0].UserID].AppMangerLevel), - } - for _, member := range groupMembers { - member.Nickname = userMap[member.UserID].Nickname - tips.MemberList = append(tips.MemberList, s.groupMemberDB2PB(member, userMap[member.UserID].AppMangerLevel)) - if member.UserID == opUserID { - tips.OpUser = s.groupMemberDB2PB(member, userMap[member.UserID].AppMangerLevel) - break - } - } - s.notification.GroupCreatedNotification(ctx, tips) - } + s.notification.GroupCreatedNotification(ctx, tips) reqCallBackAfter := &pbgroup.CreateGroupReq{ MemberUserIDs: userIDs, diff --git a/internal/rpc/group/notification.go b/internal/rpc/group/notification.go index f0f054d0ab..cfa62c85db 100644 --- a/internal/rpc/group/notification.go +++ b/internal/rpc/group/notification.go @@ -715,7 +715,3 @@ func (g *GroupNotificationSender) GroupMemberSetToOrdinaryUserNotification(ctx c } g.Notification(ctx, mcontext.GetOpUserID(ctx), group.GroupID, constant.GroupMemberSetToOrdinaryUserNotification, tips) } - -func (g *GroupNotificationSender) SuperGroupNotification(ctx context.Context, sendID, recvID string) { - g.Notification(ctx, sendID, recvID, constant.SuperGroupUpdateNotification, nil) -} diff --git a/internal/rpc/msg/server.go b/internal/rpc/msg/server.go index 6ff45605e4..f1fb28ffff 100644 --- a/internal/rpc/msg/server.go +++ b/internal/rpc/msg/server.go @@ -85,8 +85,7 @@ func Start(ctx context.Context, config *Config, client discovery.SvcDiscoveryReg if err != nil { return err } - //todo MsgCacheTimeout - msgModel := redis.NewMsgCache(rdb, config.RedisConfig.EnablePipeline) + msgModel := redis.NewMsgCache(rdb) seqModel := redis.NewSeqCache(rdb) conversationClient := rpcclient.NewConversationRpcClient(client, config.Share.RpcRegisterName.Conversation) userRpcClient := rpcclient.NewUserRpcClient(client, config.Share.RpcRegisterName.User, config.Share.IMAdminUserID) diff --git a/pkg/common/config/config.go b/pkg/common/config/config.go index a75d45ebbd..5313c196ac 100644 --- a/pkg/common/config/config.go +++ b/pkg/common/config/config.go @@ -323,13 +323,12 @@ type User struct { } type Redis struct { - Address []string `mapstructure:"address"` - Username string `mapstructure:"username"` - Password string `mapstructure:"password"` - EnablePipeline bool `mapstructure:"enablePipeline"` - ClusterMode bool `mapstructure:"clusterMode"` - DB int `mapstructure:"storage"` - MaxRetry int `mapstructure:"MaxRetry"` + Address []string `mapstructure:"address"` + Username string `mapstructure:"username"` + Password string `mapstructure:"password"` + ClusterMode bool `mapstructure:"clusterMode"` + DB int `mapstructure:"storage"` + MaxRetry int `mapstructure:"MaxRetry"` } type BeforeConfig struct { diff --git a/pkg/common/startrpc/start.go b/pkg/common/startrpc/start.go index a36bcfe1c8..069c92012a 100644 --- a/pkg/common/startrpc/start.go +++ b/pkg/common/startrpc/start.go @@ -52,12 +52,9 @@ func Start[T any](ctx context.Context, discovery *config2.Discovery, prometheusC if err != nil { return err } - prometheusPort, err := datautil.GetElemByIndex(prometheusConfig.Ports, index) - if err != nil { - return err - } + log.CInfo(ctx, "RPC server is initializing", "rpcRegisterName", rpcRegisterName, "rpcPort", rpcPort, - "prometheusPort", prometheusPort) + "prometheusPorts", prometheusConfig.Ports) rpcTcpAddr := net.JoinHostPort(network.GetListenIP(listenIP), strconv.Itoa(rpcPort)) listener, err := net.Listen( "tcp", @@ -117,9 +114,14 @@ func Start[T any](ctx context.Context, discovery *config2.Discovery, prometheusC netErr error httpServer *http.Server ) - - go func() { - if prometheusConfig.Enable && prometheusPort != 0 { + if prometheusConfig.Enable { + go func() { + prometheusPort, err := datautil.GetElemByIndex(prometheusConfig.Ports, index) + if err != nil { + netErr = err + netDone <- struct{}{} + return + } metric.InitializeMetrics(srv) // Create a HTTP server for prometheus. httpServer = &http.Server{Handler: promhttp.HandlerFor(reg, promhttp.HandlerOpts{}), Addr: fmt.Sprintf("0.0.0.0:%d", prometheusPort)} @@ -127,8 +129,8 @@ func Start[T any](ctx context.Context, discovery *config2.Discovery, prometheusC netErr = errs.WrapMsg(err, "prometheus start err", httpServer.Addr) netDone <- struct{}{} } - } - }() + }() + } go func() { err := srv.Serve(listener) diff --git a/pkg/common/storage/cache/cachekey/msg.go b/pkg/common/storage/cache/cachekey/msg.go index d1e8eeb7bc..8e05b64f1f 100644 --- a/pkg/common/storage/cache/cachekey/msg.go +++ b/pkg/common/storage/cache/cachekey/msg.go @@ -31,10 +31,6 @@ const ( reactionNotification = "EX_NOTIFICATION_" ) -func GetAllMessageCacheKey(conversationID string) string { - return messageCache + conversationID + "_*" -} - func GetMessageCacheKey(conversationID string, seq int64) string { return messageCache + conversationID + "_" + strconv.Itoa(int(seq)) } diff --git a/pkg/common/storage/cache/conversation.go b/pkg/common/storage/cache/conversation.go index bf85af0c5f..f34fd599f8 100644 --- a/pkg/common/storage/cache/conversation.go +++ b/pkg/common/storage/cache/conversation.go @@ -52,9 +52,6 @@ type ConversationCache interface { // GetUserAllHasReadSeqs(ctx context.Context, ownerUserID string) (map[string]int64, error) DelUserAllHasReadSeqs(ownerUserID string, conversationIDs ...string) ConversationCache - GetConversationsByConversationID(ctx context.Context, - conversationIDs []string) ([]*relationtb.Conversation, error) - DelConversationByConversationID(conversationIDs ...string) ConversationCache GetConversationNotReceiveMessageUserIDs(ctx context.Context, conversationID string) ([]string, error) DelConversationNotReceiveMessageUserIDs(conversationIDs ...string) ConversationCache } diff --git a/pkg/common/storage/cache/msg.go b/pkg/common/storage/cache/msg.go index 0adbb35726..00eb28c02e 100644 --- a/pkg/common/storage/cache/msg.go +++ b/pkg/common/storage/cache/msg.go @@ -23,13 +23,8 @@ import ( type MsgCache interface { GetMessagesBySeq(ctx context.Context, conversationID string, seqs []int64) (seqMsg []*sdkws.MsgData, failedSeqList []int64, err error) - SetMessageToCache(ctx context.Context, conversationID string, msgs []*sdkws.MsgData) (int, error) - UserDeleteMsgs(ctx context.Context, conversationID string, seqs []int64, userID string) error - DelUserDeleteMsgsList(ctx context.Context, conversationID string, seqs []int64) - DeleteMessages(ctx context.Context, conversationID string, seqs []int64) error - GetUserDelList(ctx context.Context, userID, conversationID string) (seqs []int64, err error) - CleanUpOneConversationAllMsg(ctx context.Context, conversationID string) error - DelMsgFromCache(ctx context.Context, userID string, seqList []int64) error + SetMessagesToCache(ctx context.Context, conversationID string, msgs []*sdkws.MsgData) (int, error) + DeleteMessagesFromCache(ctx context.Context, conversationID string, seqs []int64) error SetSendMsgStatus(ctx context.Context, id string, status int32) error GetSendMsgStatus(ctx context.Context, id string) (int32, error) JudgeMessageReactionExist(ctx context.Context, clientMsgID string, sessionType int32) (bool, error) diff --git a/pkg/common/storage/cache/redis/batch_handler.go b/pkg/common/storage/cache/redis/batch_handler.go index b68d8f86dc..95f6699047 100644 --- a/pkg/common/storage/cache/redis/batch_handler.go +++ b/pkg/common/storage/cache/redis/batch_handler.go @@ -62,17 +62,13 @@ func (c *BatchDeleterRedis) ChainExecDel(ctx context.Context) error { func (c *BatchDeleterRedis) execDel(ctx context.Context, keys []string) error { if len(keys) > 0 { log.ZDebug(ctx, "delete cache", "topic", c.redisPubTopics, "keys", keys) - slotMapKeys, err := groupKeysBySlot(ctx, c.redisClient, keys) + // Batch delete keys + err := ProcessKeysBySlot(ctx, c.redisClient, keys, func(ctx context.Context, slot int64, keys []string) error { + return c.rocksClient.TagAsDeletedBatch2(ctx, keys) + }) if err != nil { return err } - // Batch delete keys - for slot, singleSlotKeys := range slotMapKeys { - if err := c.rocksClient.TagAsDeletedBatch2(ctx, singleSlotKeys); err != nil { - log.ZWarn(ctx, "Batch delete cache failed", err, "slot", slot, "keys", singleSlotKeys) - continue - } - } // Publish the keys that have been deleted to Redis to update the local cache information of other nodes if len(c.redisPubTopics) > 0 && len(keys) > 0 { keysByTopic := localcache.GetPublishKeysByTopic(c.redisPubTopics, keys) @@ -117,37 +113,6 @@ func GetRocksCacheOptions() *rockscache.Options { return &opts } -// groupKeysBySlot groups keys by their Redis cluster hash slots. -func groupKeysBySlot(ctx context.Context, redisClient redis.UniversalClient, keys []string) (map[int64][]string, error) { - slots := make(map[int64][]string) - clusterClient, isCluster := redisClient.(*redis.ClusterClient) - if isCluster { - pipe := clusterClient.Pipeline() - cmds := make([]*redis.IntCmd, len(keys)) - for i, key := range keys { - cmds[i] = pipe.ClusterKeySlot(ctx, key) - } - _, err := pipe.Exec(ctx) - if err != nil { - return nil, errs.WrapMsg(err, "get slot err") - } - - for i, cmd := range cmds { - slot, err := cmd.Result() - if err != nil { - log.ZWarn(ctx, "some key get slot err", err, "key", keys[i]) - continue - } - slots[slot] = append(slots[slot], keys[i]) - } - } else { - // If not a cluster client, put all keys in the same slot (0) - slots[0] = keys - } - - return slots, nil -} - func getCache[T any](ctx context.Context, rcClient *rockscache.Client, key string, expire time.Duration, fn func(ctx context.Context) (T, error)) (T, error) { var t T var write bool diff --git a/pkg/common/storage/cache/redis/conversation.go b/pkg/common/storage/cache/redis/conversation.go index 5fac79a7e1..8c0393dd56 100644 --- a/pkg/common/storage/cache/redis/conversation.go +++ b/pkg/common/storage/cache/redis/conversation.go @@ -222,14 +222,6 @@ func (c *ConversationRedisCache) DelUserAllHasReadSeqs(ownerUserID string, conve return cache } -func (c *ConversationRedisCache) GetConversationsByConversationID(ctx context.Context, conversationIDs []string) ([]*model.Conversation, error) { - panic("implement me") -} - -func (c *ConversationRedisCache) DelConversationByConversationID(conversationIDs ...string) cache.ConversationCache { - panic("implement me") -} - func (c *ConversationRedisCache) GetConversationNotReceiveMessageUserIDs(ctx context.Context, conversationID string) ([]string, error) { return getCache(ctx, c.rcClient, c.getConversationNotReceiveMessageUserIDsKey(conversationID), c.expireTime, func(ctx context.Context) ([]string, error) { return c.conversationDB.GetConversationNotReceiveMessageUserIDs(ctx, conversationID) diff --git a/pkg/common/storage/cache/redis/lua_script.go b/pkg/common/storage/cache/redis/lua_script.go new file mode 100644 index 0000000000..c7609cb443 --- /dev/null +++ b/pkg/common/storage/cache/redis/lua_script.go @@ -0,0 +1,125 @@ +package redis + +import ( + "context" + "fmt" + "github.com/openimsdk/open-im-server/v3/pkg/common/servererrs" + "github.com/openimsdk/tools/errs" + "github.com/openimsdk/tools/log" + "github.com/redis/go-redis/v9" +) + +var ( + setBatchWithCommonExpireScript = redis.NewScript(` +local expire = tonumber(ARGV[1]) +for i, key in ipairs(KEYS) do + redis.call('SET', key, ARGV[i + 1]) + redis.call('EXPIRE', key, expire) +end +return #KEYS +`) + + setBatchWithIndividualExpireScript = redis.NewScript(` +local n = #KEYS +for i = 1, n do + redis.call('SET', KEYS[i], ARGV[i]) + redis.call('EXPIRE', KEYS[i], ARGV[i + n]) +end +return n +`) + + deleteBatchScript = redis.NewScript(` +for i, key in ipairs(KEYS) do + redis.call('DEL', key) +end +return #KEYS +`) + + getBatchScript = redis.NewScript(` +local values = {} +for i, key in ipairs(KEYS) do + local value = redis.call('GET', key) + table.insert(values, value) +end +return values +`) +) + +func callLua(ctx context.Context, rdb redis.Scripter, script *redis.Script, keys []string, args []any) (any, error) { + log.ZDebug(ctx, "callLua args", "scriptHash", script.Hash(), "keys", keys, "args", args) + r := script.EvalSha(ctx, rdb, keys, args) + if redis.HasErrorPrefix(r.Err(), "NOSCRIPT") { + if err := script.Load(ctx, rdb).Err(); err != nil { + r = script.Eval(ctx, rdb, keys, args) + } else { + r = script.EvalSha(ctx, rdb, keys, args) + } + } + v, err := r.Result() + if err == redis.Nil { + err = nil + } + return v, errs.WrapMsg(err, "call lua err", "scriptHash", script.Hash(), "keys", keys, "args", args) +} + +func LuaSetBatchWithCommonExpire(ctx context.Context, rdb redis.Scripter, keys []string, values []string, expire int) error { + // Check if the lengths of keys and values match + if len(keys) != len(values) { + return errs.New("keys and values length mismatch").Wrap() + } + + // Ensure allocation size does not overflow + maxAllowedLen := (1 << 31) - 1 // 2GB limit (maximum address space for 32-bit systems) + + if len(values) > maxAllowedLen-1 { + return fmt.Errorf("values length is too large, causing overflow") + } + var vals = make([]any, 0, 1+len(values)) + vals = append(vals, expire) + for _, v := range values { + vals = append(vals, v) + } + _, err := callLua(ctx, rdb, setBatchWithCommonExpireScript, keys, vals) + return err +} + +func LuaSetBatchWithIndividualExpire(ctx context.Context, rdb redis.Scripter, keys []string, values []string, expires []int) error { + // Check if the lengths of keys, values, and expires match + if len(keys) != len(values) || len(keys) != len(expires) { + return errs.New("keys and values length mismatch").Wrap() + } + + // Ensure the allocation size does not overflow + maxAllowedLen := (1 << 31) - 1 // 2GB limit (maximum address space for 32-bit systems) + + if len(values) > maxAllowedLen-1 { + return errs.New(fmt.Sprintf("values length %d exceeds the maximum allowed length %d", len(values), maxAllowedLen-1)).Wrap() + } + var vals = make([]any, 0, len(values)+len(expires)) + for _, v := range values { + vals = append(vals, v) + } + for _, ex := range expires { + vals = append(vals, ex) + } + _, err := callLua(ctx, rdb, setBatchWithIndividualExpireScript, keys, vals) + return err +} + +func LuaDeleteBatch(ctx context.Context, rdb redis.Scripter, keys []string) error { + _, err := callLua(ctx, rdb, deleteBatchScript, keys, nil) + return err +} + +func LuaGetBatch(ctx context.Context, rdb redis.Scripter, keys []string) ([]any, error) { + v, err := callLua(ctx, rdb, getBatchScript, keys, nil) + if err != nil { + return nil, err + } + values, ok := v.([]any) + if !ok { + return nil, servererrs.ErrArgs.WrapMsg("invalid lua get batch result") + } + return values, nil + +} diff --git a/pkg/common/storage/cache/redis/lua_script_test.go b/pkg/common/storage/cache/redis/lua_script_test.go new file mode 100644 index 0000000000..1566b59a0b --- /dev/null +++ b/pkg/common/storage/cache/redis/lua_script_test.go @@ -0,0 +1,75 @@ +package redis + +import ( + "context" + "github.com/go-redis/redismock/v9" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "testing" +) + +func TestLuaSetBatchWithCommonExpire(t *testing.T) { + rdb, mock := redismock.NewClientMock() + ctx := context.Background() + + keys := []string{"key1", "key2"} + values := []string{"value1", "value2"} + expire := 10 + + mock.ExpectEvalSha(setBatchWithCommonExpireScript.Hash(), keys, []any{expire, "value1", "value2"}).SetVal(int64(len(keys))) + + err := LuaSetBatchWithCommonExpire(ctx, rdb, keys, values, expire) + require.NoError(t, err) + assert.NoError(t, mock.ExpectationsWereMet()) +} + +func TestLuaSetBatchWithIndividualExpire(t *testing.T) { + rdb, mock := redismock.NewClientMock() + ctx := context.Background() + + keys := []string{"key1", "key2"} + values := []string{"value1", "value2"} + expires := []int{10, 20} + + args := make([]any, 0, len(values)+len(expires)) + for _, v := range values { + args = append(args, v) + } + for _, ex := range expires { + args = append(args, ex) + } + + mock.ExpectEvalSha(setBatchWithIndividualExpireScript.Hash(), keys, args).SetVal(int64(len(keys))) + + err := LuaSetBatchWithIndividualExpire(ctx, rdb, keys, values, expires) + require.NoError(t, err) + assert.NoError(t, mock.ExpectationsWereMet()) +} + +func TestLuaDeleteBatch(t *testing.T) { + rdb, mock := redismock.NewClientMock() + ctx := context.Background() + + keys := []string{"key1", "key2"} + + mock.ExpectEvalSha(deleteBatchScript.Hash(), keys, []any{}).SetVal(int64(len(keys))) + + err := LuaDeleteBatch(ctx, rdb, keys) + require.NoError(t, err) + assert.NoError(t, mock.ExpectationsWereMet()) +} + +func TestLuaGetBatch(t *testing.T) { + rdb, mock := redismock.NewClientMock() + ctx := context.Background() + + keys := []string{"key1", "key2"} + expectedValues := []any{"value1", "value2"} + + mock.ExpectEvalSha(getBatchScript.Hash(), keys, []any{}).SetVal(expectedValues) + + values, err := LuaGetBatch(ctx, rdb, keys) + require.NoError(t, err) + assert.NoError(t, mock.ExpectationsWereMet()) + assert.Equal(t, expectedValues, values) +} diff --git a/pkg/common/storage/cache/redis/meta_cache.go b/pkg/common/storage/cache/redis/meta_cache.go deleted file mode 100644 index 4c2fcacd13..0000000000 --- a/pkg/common/storage/cache/redis/meta_cache.go +++ /dev/null @@ -1,15 +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 redis diff --git a/pkg/common/storage/cache/redis/msg.go b/pkg/common/storage/cache/redis/msg.go index df69bc6451..2d21cfe135 100644 --- a/pkg/common/storage/cache/redis/msg.go +++ b/pkg/common/storage/cache/redis/msg.go @@ -16,37 +16,25 @@ package redis import ( "context" - "errors" - "github.com/gogo/protobuf/jsonpb" "github.com/openimsdk/open-im-server/v3/pkg/common/storage/cache" "github.com/openimsdk/open-im-server/v3/pkg/common/storage/cache/cachekey" "github.com/openimsdk/open-im-server/v3/pkg/msgprocessor" - "github.com/openimsdk/protocol/constant" "github.com/openimsdk/protocol/sdkws" "github.com/openimsdk/tools/errs" - "github.com/openimsdk/tools/log" - "github.com/openimsdk/tools/utils/stringutil" + "github.com/openimsdk/tools/utils/datautil" "github.com/redis/go-redis/v9" - "golang.org/x/sync/errgroup" "time" -) +) // -const msgCacheTimeout = 86400 * time.Second +// msgCacheTimeout is expiration time of message cache, 86400 seconds +const msgCacheTimeout = 86400 -var concurrentLimit = 3 - -func NewMsgCache(client redis.UniversalClient, redisEnablePipeline bool) cache.MsgCache { - return &msgCache{rdb: client, msgCacheTimeout: msgCacheTimeout, redisEnablePipeline: redisEnablePipeline} +func NewMsgCache(client redis.UniversalClient) cache.MsgCache { + return &msgCache{rdb: client} } type msgCache struct { - rdb redis.UniversalClient - msgCacheTimeout time.Duration - redisEnablePipeline bool -} - -func (c *msgCache) getAllMessageCacheKey(conversationID string) string { - return cachekey.GetAllMessageCacheKey(conversationID) + rdb redis.UniversalClient } func (c *msgCache) getMessageCacheKey(conversationID string, seq int64) string { @@ -72,218 +60,41 @@ func (c *msgCache) getMessageReactionExPrefix(clientMsgID string, sessionType in return cachekey.GetMessageReactionExKey(clientMsgID, sessionType) } -func (c *msgCache) SetMessageToCache(ctx context.Context, conversationID string, msgs []*sdkws.MsgData) (int, error) { - if c.redisEnablePipeline { - return c.PipeSetMessageToCache(ctx, conversationID, msgs) - } - return c.ParallelSetMessageToCache(ctx, conversationID, msgs) -} - -func (c *msgCache) PipeSetMessageToCache(ctx context.Context, conversationID string, msgs []*sdkws.MsgData) (int, error) { - pipe := c.rdb.Pipeline() - for _, msg := range msgs { - s, err := msgprocessor.Pb2String(msg) - if err != nil { - return 0, err - } - - key := c.getMessageCacheKey(conversationID, msg.Seq) - _ = pipe.Set(ctx, key, s, c.msgCacheTimeout) - } - - results, err := pipe.Exec(ctx) - if err != nil { - return 0, errs.Wrap(err) - } - - for _, res := range results { - if res.Err() != nil { - return 0, errs.Wrap(err) - } - } - - return len(msgs), nil -} - -func (c *msgCache) ParallelSetMessageToCache(ctx context.Context, conversationID string, msgs []*sdkws.MsgData) (int, error) { - wg := errgroup.Group{} - wg.SetLimit(concurrentLimit) - - for _, msg := range msgs { - msg := msg // closure safe var - wg.Go(func() error { - s, err := msgprocessor.Pb2String(msg) - if err != nil { - return errs.Wrap(err) - } - - key := c.getMessageCacheKey(conversationID, msg.Seq) - if err := c.rdb.Set(ctx, key, s, c.msgCacheTimeout).Err(); err != nil { - return errs.Wrap(err) - } - return nil - }) - } - - err := wg.Wait() - if err != nil { - return 0, errs.WrapMsg(err, "wg.Wait failed") - } - - return len(msgs), nil -} - -func (c *msgCache) UserDeleteMsgs(ctx context.Context, conversationID string, seqs []int64, userID string) error { - for _, seq := range seqs { - delUserListKey := c.getMessageDelUserListKey(conversationID, seq) - userDelListKey := c.getUserDelList(conversationID, userID) - err := c.rdb.SAdd(ctx, delUserListKey, userID).Err() - if err != nil { - return errs.Wrap(err) - } - err = c.rdb.SAdd(ctx, userDelListKey, seq).Err() - if err != nil { - return errs.Wrap(err) - } - if err := c.rdb.Expire(ctx, delUserListKey, c.msgCacheTimeout).Err(); err != nil { - return errs.Wrap(err) - } - if err := c.rdb.Expire(ctx, userDelListKey, c.msgCacheTimeout).Err(); err != nil { - return errs.Wrap(err) - } - } - - return nil -} - -func (c *msgCache) GetUserDelList(ctx context.Context, userID, conversationID string) (seqs []int64, err error) { - result, err := c.rdb.SMembers(ctx, c.getUserDelList(conversationID, userID)).Result() - if err != nil { - return nil, errs.Wrap(err) - } - seqs = make([]int64, len(result)) - for i, v := range result { - seqs[i] = stringutil.StringToInt64(v) - } - - return seqs, nil -} - -func (c *msgCache) DelUserDeleteMsgsList(ctx context.Context, conversationID string, seqs []int64) { - for _, seq := range seqs { - delUsers, err := c.rdb.SMembers(ctx, c.getMessageDelUserListKey(conversationID, seq)).Result() - if err != nil { - log.ZWarn(ctx, "DelUserDeleteMsgsList failed", err, "conversationID", conversationID, "seq", seq) - - continue - } - if len(delUsers) > 0 { - var failedFlag bool - for _, userID := range delUsers { - err = c.rdb.SRem(ctx, c.getUserDelList(conversationID, userID), seq).Err() +func (c *msgCache) SetMessagesToCache(ctx context.Context, conversationID string, msgs []*sdkws.MsgData) (int, error) { + msgMap := datautil.SliceToMap(msgs, func(msg *sdkws.MsgData) string { + return c.getMessageCacheKey(conversationID, msg.Seq) + }) + keys := datautil.Slice(msgs, func(msg *sdkws.MsgData) string { + return c.getMessageCacheKey(conversationID, msg.Seq) + }) + err := ProcessKeysBySlot(ctx, c.rdb, keys, func(ctx context.Context, slot int64, keys []string) error { + var values []string + for _, key := range keys { + if msg, ok := msgMap[key]; ok { + s, err := msgprocessor.Pb2String(msg) if err != nil { - failedFlag = true - log.ZWarn(ctx, "DelUserDeleteMsgsList failed", err, "conversationID", conversationID, "seq", seq, "userID", userID) - } - } - if !failedFlag { - if err := c.rdb.Del(ctx, c.getMessageDelUserListKey(conversationID, seq)).Err(); err != nil { - log.ZWarn(ctx, "DelUserDeleteMsgsList failed", err, "conversationID", conversationID, "seq", seq) + return err } + values = append(values, s) } } - } -} - -func (c *msgCache) DeleteMessages(ctx context.Context, conversationID string, seqs []int64) error { - if c.redisEnablePipeline { - return c.PipeDeleteMessages(ctx, conversationID, seqs) - } - - return c.ParallelDeleteMessages(ctx, conversationID, seqs) -} - -func (c *msgCache) ParallelDeleteMessages(ctx context.Context, conversationID string, seqs []int64) error { - wg := errgroup.Group{} - wg.SetLimit(concurrentLimit) - - for _, seq := range seqs { - seq := seq - wg.Go(func() error { - err := c.rdb.Del(ctx, c.getMessageCacheKey(conversationID, seq)).Err() - if err != nil { - return errs.Wrap(err) - } - return nil - }) - } - - return wg.Wait() -} - -func (c *msgCache) PipeDeleteMessages(ctx context.Context, conversationID string, seqs []int64) error { - pipe := c.rdb.Pipeline() - for _, seq := range seqs { - _ = pipe.Del(ctx, c.getMessageCacheKey(conversationID, seq)) - } - - results, err := pipe.Exec(ctx) - if err != nil { - return errs.WrapMsg(err, "pipe.del") - } - - for _, res := range results { - if res.Err() != nil { - return errs.Wrap(err) - } - } - - return nil -} - -func (c *msgCache) CleanUpOneConversationAllMsg(ctx context.Context, conversationID string) error { - vals, err := c.rdb.Keys(ctx, c.getAllMessageCacheKey(conversationID)).Result() - if errors.Is(err, redis.Nil) { - return nil - } + return LuaSetBatchWithCommonExpire(ctx, c.rdb, keys, values, msgCacheTimeout) + }) if err != nil { - return errs.Wrap(err) - } - for _, v := range vals { - if err := c.rdb.Del(ctx, v).Err(); err != nil { - return errs.Wrap(err) - } + return 0, err } - return nil + return len(msgs), nil } -func (c *msgCache) DelMsgFromCache(ctx context.Context, userID string, seqs []int64) error { +func (c *msgCache) DeleteMessagesFromCache(ctx context.Context, conversationID string, seqs []int64) error { + var keys []string for _, seq := range seqs { - key := c.getMessageCacheKey(userID, seq) - result, err := c.rdb.Get(ctx, key).Result() - if err != nil { - if errors.Is(err, redis.Nil) { - continue - } - - return errs.Wrap(err) - } - var msg sdkws.MsgData - err = jsonpb.UnmarshalString(result, &msg) - if err != nil { - return err - } - msg.Status = constant.MsgDeleted - s, err := msgprocessor.Pb2String(&msg) - if err != nil { - return errs.Wrap(err) - } - if err := c.rdb.Set(ctx, key, s, c.msgCacheTimeout).Err(); err != nil { - return errs.Wrap(err) - } + keys = append(keys, c.getMessageCacheKey(conversationID, seq)) } - return nil + return ProcessKeysBySlot(ctx, c.rdb, keys, func(ctx context.Context, slot int64, keys []string) error { + return LuaDeleteBatch(ctx, c.rdb, keys) + }) } func (c *msgCache) SetSendMsgStatus(ctx context.Context, id string, status int32) error { @@ -338,102 +149,39 @@ func (c *msgCache) DeleteOneMessageKey(ctx context.Context, clientMsgID string, } func (c *msgCache) GetMessagesBySeq(ctx context.Context, conversationID string, seqs []int64) (seqMsgs []*sdkws.MsgData, failedSeqs []int64, err error) { - if c.redisEnablePipeline { - return c.PipeGetMessagesBySeq(ctx, conversationID, seqs) - } - - return c.ParallelGetMessagesBySeq(ctx, conversationID, seqs) -} - -func (c *msgCache) PipeGetMessagesBySeq(ctx context.Context, conversationID string, seqs []int64) (seqMsgs []*sdkws.MsgData, failedSeqs []int64, err error) { - pipe := c.rdb.Pipeline() - - results := []*redis.StringCmd{} + var keys []string + keySeqMap := make(map[string]int64, 10) for _, seq := range seqs { - results = append(results, pipe.Get(ctx, c.getMessageCacheKey(conversationID, seq))) + key := c.getMessageCacheKey(conversationID, seq) + keys = append(keys, key) + keySeqMap[key] = seq } - - _, err = pipe.Exec(ctx) - if err != nil && err != redis.Nil { - return seqMsgs, failedSeqs, errs.WrapMsg(err, "pipe.get") - } - - for idx, res := range results { - seq := seqs[idx] - if res.Err() != nil { - log.ZError(ctx, "GetMessagesBySeq failed", err, "conversationID", conversationID, "seq", seq, "err", res.Err()) - failedSeqs = append(failedSeqs, seq) - continue - } - - msg := sdkws.MsgData{} - if err = msgprocessor.String2Pb(res.Val(), &msg); err != nil { - log.ZError(ctx, "GetMessagesBySeq Unmarshal failed", err, "res", res, "conversationID", conversationID, "seq", seq) - failedSeqs = append(failedSeqs, seq) - continue - } - - if msg.Status == constant.MsgDeleted { - failedSeqs = append(failedSeqs, seq) - continue + err = ProcessKeysBySlot(ctx, c.rdb, keys, func(ctx context.Context, slot int64, keys []string) error { + result, err := LuaGetBatch(ctx, c.rdb, keys) + if err != nil { + return err } - - seqMsgs = append(seqMsgs, &msg) - } - - return -} - -func (c *msgCache) ParallelGetMessagesBySeq(ctx context.Context, conversationID string, seqs []int64) (seqMsgs []*sdkws.MsgData, failedSeqs []int64, err error) { - type entry struct { - err error - msg *sdkws.MsgData - } - - wg := errgroup.Group{} - wg.SetLimit(concurrentLimit) - - results := make([]entry, len(seqs)) // set slice len/cap to length of seqs. - for idx, seq := range seqs { - // closure safe var - idx := idx - seq := seq - - wg.Go(func() error { - res, err := c.rdb.Get(ctx, c.getMessageCacheKey(conversationID, seq)).Result() - if err != nil { - log.ZError(ctx, "GetMessagesBySeq failed", err, "conversationID", conversationID, "seq", seq) - results[idx] = entry{err: err} - return nil - } - - msg := sdkws.MsgData{} - if err = msgprocessor.String2Pb(res, &msg); err != nil { - log.ZError(ctx, "GetMessagesBySeq Unmarshal failed", err, "res", res, "conversationID", conversationID, "seq", seq) - results[idx] = entry{err: err} - return nil + for i, value := range result { + seq := keySeqMap[keys[i]] + if value == nil { + failedSeqs = append(failedSeqs, seq) + continue } - if msg.Status == constant.MsgDeleted { - results[idx] = entry{err: err} - return nil + msg := &sdkws.MsgData{} + msgString, ok := value.(string) + if !ok || msgprocessor.String2Pb(msgString, msg) != nil { + failedSeqs = append(failedSeqs, seq) + continue } + seqMsgs = append(seqMsgs, msg) - results[idx] = entry{msg: &msg} - return nil - }) - } - - _ = wg.Wait() - - for idx, res := range results { - if res.err != nil { - failedSeqs = append(failedSeqs, seqs[idx]) - continue } - - seqMsgs = append(seqMsgs, res.msg) + return nil + }) + if err != nil { + return nil, nil, err } + return seqMsgs, failedSeqs, nil - return } diff --git a/pkg/common/storage/cache/redis/msg_test.go b/pkg/common/storage/cache/redis/msg_test.go index d47fa18e18..10b9ce18b0 100644 --- a/pkg/common/storage/cache/redis/msg_test.go +++ b/pkg/common/storage/cache/redis/msg_test.go @@ -4,14 +4,13 @@ // 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 +// 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 redis import ( @@ -20,381 +19,115 @@ import ( "github.com/openimsdk/protocol/sdkws" "github.com/redis/go-redis/v9" "github.com/stretchr/testify/assert" - "math/rand" + "google.golang.org/protobuf/proto" "testing" ) -func TestParallelSetMessageToCache(t *testing.T) { - var ( - cid = fmt.Sprintf("cid-%v", rand.Int63()) - seqFirst = rand.Int63() - msgs = []*sdkws.MsgData{} - ) - - for i := 0; i < 100; i++ { - msgs = append(msgs, &sdkws.MsgData{ - Seq: seqFirst + int64(i), - }) - } - - testParallelSetMessageToCache(t, cid, msgs) -} - -func testParallelSetMessageToCache(t *testing.T, cid string, msgs []*sdkws.MsgData) { - rdb := redis.NewClient(&redis.Options{}) - defer rdb.Close() - - cacher := msgCache{rdb: rdb} - - ret, err := cacher.ParallelSetMessageToCache(context.Background(), cid, msgs) - assert.Nil(t, err) - assert.Equal(t, len(msgs), ret) - - // validate - for _, msg := range msgs { - key := cacher.getMessageCacheKey(cid, msg.Seq) - val, err := rdb.Exists(context.Background(), key).Result() - assert.Nil(t, err) - assert.EqualValues(t, 1, val) - } -} - -func TestPipeSetMessageToCache(t *testing.T) { - var ( - cid = fmt.Sprintf("cid-%v", rand.Int63()) - seqFirst = rand.Int63() - msgs = []*sdkws.MsgData{} - ) - - for i := 0; i < 100; i++ { - msgs = append(msgs, &sdkws.MsgData{ - Seq: seqFirst + int64(i), +func Test_msgCache_SetMessagesToCache(t *testing.T) { + type fields struct { + rdb redis.UniversalClient + } + type args struct { + ctx context.Context + conversationID string + msgs []*sdkws.MsgData + } + tests := []struct { + name string + fields fields + args args + want int + wantErr assert.ErrorAssertionFunc + }{ + {"test1", fields{rdb: redis.NewClient(&redis.Options{Addr: "localhost:16379", Username: "", Password: "openIM123", DB: 0})}, args{context.Background(), + "cid", []*sdkws.MsgData{{Seq: 1}, {Seq: 2}, {Seq: 3}}}, 3, assert.NoError}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + c := &msgCache{ + rdb: tt.fields.rdb, + } + got, err := c.SetMessagesToCache(tt.args.ctx, tt.args.conversationID, tt.args.msgs) + if !tt.wantErr(t, err, fmt.Sprintf("SetMessagesToCache(%v, %v, %v)", tt.args.ctx, tt.args.conversationID, tt.args.msgs)) { + return + } + assert.Equalf(t, tt.want, got, "SetMessagesToCache(%v, %v, %v)", tt.args.ctx, tt.args.conversationID, tt.args.msgs) }) } - - testPipeSetMessageToCache(t, cid, msgs) -} - -func testPipeSetMessageToCache(t *testing.T, cid string, msgs []*sdkws.MsgData) { - rdb := redis.NewClient(&redis.Options{}) - defer rdb.Close() - - cacher := msgCache{rdb: rdb} - - ret, err := cacher.PipeSetMessageToCache(context.Background(), cid, msgs) - assert.Nil(t, err) - assert.Equal(t, len(msgs), ret) - - // validate - for _, msg := range msgs { - key := cacher.getMessageCacheKey(cid, msg.Seq) - val, err := rdb.Exists(context.Background(), key).Result() - assert.Nil(t, err) - assert.EqualValues(t, 1, val) - } -} - -func TestGetMessagesBySeq(t *testing.T) { - var ( - cid = fmt.Sprintf("cid-%v", rand.Int63()) - seqFirst = rand.Int63() - msgs = []*sdkws.MsgData{} - ) - - seqs := []int64{} - for i := 0; i < 100; i++ { - msgs = append(msgs, &sdkws.MsgData{ - Seq: seqFirst + int64(i), - SendID: fmt.Sprintf("fake-sendid-%v", i), - }) - seqs = append(seqs, seqFirst+int64(i)) - } - - // set data to cache - testPipeSetMessageToCache(t, cid, msgs) - - // get data from cache with parallet mode - testParallelGetMessagesBySeq(t, cid, seqs, msgs) - - // get data from cache with pipeline mode - testPipeGetMessagesBySeq(t, cid, seqs, msgs) -} - -func testParallelGetMessagesBySeq(t *testing.T, cid string, seqs []int64, inputMsgs []*sdkws.MsgData) { - rdb := redis.NewClient(&redis.Options{}) - defer rdb.Close() - - cacher := msgCache{rdb: rdb} - - respMsgs, failedSeqs, err := cacher.ParallelGetMessagesBySeq(context.Background(), cid, seqs) - assert.Nil(t, err) - assert.Equal(t, 0, len(failedSeqs)) - assert.Equal(t, len(respMsgs), len(seqs)) - - // validate - for idx, msg := range respMsgs { - assert.Equal(t, msg.Seq, inputMsgs[idx].Seq) - assert.Equal(t, msg.SendID, inputMsgs[idx].SendID) - } -} - -func testPipeGetMessagesBySeq(t *testing.T, cid string, seqs []int64, inputMsgs []*sdkws.MsgData) { - rdb := redis.NewClient(&redis.Options{}) - defer rdb.Close() - - cacher := msgCache{rdb: rdb} - - respMsgs, failedSeqs, err := cacher.PipeGetMessagesBySeq(context.Background(), cid, seqs) - assert.Nil(t, err) - assert.Equal(t, 0, len(failedSeqs)) - assert.Equal(t, len(respMsgs), len(seqs)) - - // validate - for idx, msg := range respMsgs { - assert.Equal(t, msg.Seq, inputMsgs[idx].Seq) - assert.Equal(t, msg.SendID, inputMsgs[idx].SendID) - } -} - -func TestGetMessagesBySeqWithEmptySeqs(t *testing.T) { - var ( - cid = fmt.Sprintf("cid-%v", rand.Int63()) - seqFirst int64 = 0 - msgs = []*sdkws.MsgData{} - ) - - seqs := []int64{} - for i := 0; i < 100; i++ { - msgs = append(msgs, &sdkws.MsgData{ - Seq: seqFirst + int64(i), - SendID: fmt.Sprintf("fake-sendid-%v", i), - }) - seqs = append(seqs, seqFirst+int64(i)) - } - - // don't set cache, only get data from cache. - - // get data from cache with parallet mode - testParallelGetMessagesBySeqWithEmptry(t, cid, seqs, msgs) - - // get data from cache with pipeline mode - testPipeGetMessagesBySeqWithEmptry(t, cid, seqs, msgs) -} - -func testParallelGetMessagesBySeqWithEmptry(t *testing.T, cid string, seqs []int64, inputMsgs []*sdkws.MsgData) { - rdb := redis.NewClient(&redis.Options{}) - defer rdb.Close() - - cacher := msgCache{rdb: rdb} - - respMsgs, failedSeqs, err := cacher.ParallelGetMessagesBySeq(context.Background(), cid, seqs) - assert.Nil(t, err) - assert.Equal(t, len(seqs), len(failedSeqs)) - assert.Equal(t, 0, len(respMsgs)) } -func testPipeGetMessagesBySeqWithEmptry(t *testing.T, cid string, seqs []int64, inputMsgs []*sdkws.MsgData) { - rdb := redis.NewClient(&redis.Options{}) - defer rdb.Close() - - cacher := msgCache{rdb: rdb} - - respMsgs, failedSeqs, err := cacher.PipeGetMessagesBySeq(context.Background(), cid, seqs) - assert.Equal(t, err, redis.Nil) - assert.Equal(t, len(seqs), len(failedSeqs)) - assert.Equal(t, 0, len(respMsgs)) -} - -func TestGetMessagesBySeqWithLostHalfSeqs(t *testing.T) { - var ( - cid = fmt.Sprintf("cid-%v", rand.Int63()) - seqFirst int64 = 0 - msgs = []*sdkws.MsgData{} - ) - - seqs := []int64{} - for i := 0; i < 100; i++ { - msgs = append(msgs, &sdkws.MsgData{ - Seq: seqFirst + int64(i), - SendID: fmt.Sprintf("fake-sendid-%v", i), +func Test_msgCache_GetMessagesBySeq(t *testing.T) { + type fields struct { + rdb redis.UniversalClient + } + type args struct { + ctx context.Context + conversationID string + seqs []int64 + } + var failedSeq []int64 + tests := []struct { + name string + fields fields + args args + wantSeqMsgs []*sdkws.MsgData + wantFailedSeqs []int64 + wantErr assert.ErrorAssertionFunc + }{ + {"test1", fields{rdb: redis.NewClient(&redis.Options{Addr: "localhost:16379", Password: "openIM123", DB: 0})}, + args{context.Background(), "cid", []int64{1, 2, 3}}, + []*sdkws.MsgData{{Seq: 1}, {Seq: 2}, {Seq: 3}}, failedSeq, assert.NoError}, + {"test2", fields{rdb: redis.NewClient(&redis.Options{Addr: "localhost:16379", Password: "openIM123", DB: 0})}, + args{context.Background(), "cid", []int64{4, 5, 6}}, + nil, []int64{4, 5, 6}, assert.NoError}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + c := &msgCache{ + rdb: tt.fields.rdb, + } + gotSeqMsgs, gotFailedSeqs, err := c.GetMessagesBySeq(tt.args.ctx, tt.args.conversationID, tt.args.seqs) + if !tt.wantErr(t, err, fmt.Sprintf("GetMessagesBySeq(%v, %v, %v)", tt.args.ctx, tt.args.conversationID, tt.args.seqs)) { + return + } + equalMsgDataSlices(t, tt.wantSeqMsgs, gotSeqMsgs) + assert.Equalf(t, tt.wantFailedSeqs, gotFailedSeqs, "GetMessagesBySeq(%v, %v, %v)", tt.args.ctx, tt.args.conversationID, tt.args.seqs) }) - seqs = append(seqs, seqFirst+int64(i)) } - - // Only set half the number of messages. - testParallelSetMessageToCache(t, cid, msgs[:50]) - - // get data from cache with parallet mode - testParallelGetMessagesBySeqWithLostHalfSeqs(t, cid, seqs, msgs) - - // get data from cache with pipeline mode - testPipeGetMessagesBySeqWithLostHalfSeqs(t, cid, seqs, msgs) } -func testParallelGetMessagesBySeqWithLostHalfSeqs(t *testing.T, cid string, seqs []int64, inputMsgs []*sdkws.MsgData) { - rdb := redis.NewClient(&redis.Options{}) - defer rdb.Close() - - cacher := msgCache{rdb: rdb} - - respMsgs, failedSeqs, err := cacher.ParallelGetMessagesBySeq(context.Background(), cid, seqs) - assert.Nil(t, err) - assert.Equal(t, len(seqs)/2, len(failedSeqs)) - assert.Equal(t, len(seqs)/2, len(respMsgs)) - - for idx, msg := range respMsgs { - assert.Equal(t, msg.Seq, seqs[idx]) +func equalMsgDataSlices(t *testing.T, expected, actual []*sdkws.MsgData) { + assert.Equal(t, len(expected), len(actual), "Slices have different lengths") + for i := range expected { + assert.True(t, proto.Equal(expected[i], actual[i]), "Element %d not equal: expected %v, got %v", i, expected[i], actual[i]) } } -func testPipeGetMessagesBySeqWithLostHalfSeqs(t *testing.T, cid string, seqs []int64, inputMsgs []*sdkws.MsgData) { - rdb := redis.NewClient(&redis.Options{}) - defer rdb.Close() - - cacher := msgCache{rdb: rdb} - - respMsgs, failedSeqs, err := cacher.PipeGetMessagesBySeq(context.Background(), cid, seqs) - assert.Nil(t, err) - assert.Equal(t, len(seqs)/2, len(failedSeqs)) - assert.Equal(t, len(seqs)/2, len(respMsgs)) - - for idx, msg := range respMsgs { - assert.Equal(t, msg.Seq, seqs[idx]) +func Test_msgCache_DeleteMessagesFromCache(t *testing.T) { + type fields struct { + rdb redis.UniversalClient } -} - -func TestPipeDeleteMessages(t *testing.T) { - var ( - cid = fmt.Sprintf("cid-%v", rand.Int63()) - seqFirst = rand.Int63() - msgs = []*sdkws.MsgData{} - ) - - var seqs []int64 - for i := 0; i < 100; i++ { - msgs = append(msgs, &sdkws.MsgData{ - Seq: seqFirst + int64(i), - }) - seqs = append(seqs, msgs[i].Seq) + type args struct { + ctx context.Context + conversationID string + seqs []int64 } - - testPipeSetMessageToCache(t, cid, msgs) - testPipeDeleteMessagesOK(t, cid, seqs, msgs) - - // set again - testPipeSetMessageToCache(t, cid, msgs) - testPipeDeleteMessagesMix(t, cid, seqs[:90], msgs) -} - -func testPipeDeleteMessagesOK(t *testing.T, cid string, seqs []int64, inputMsgs []*sdkws.MsgData) { - rdb := redis.NewClient(&redis.Options{}) - defer rdb.Close() - - cacher := msgCache{rdb: rdb} - - err := cacher.PipeDeleteMessages(context.Background(), cid, seqs) - assert.Nil(t, err) - - // validate - for _, msg := range inputMsgs { - key := cacher.getMessageCacheKey(cid, msg.Seq) - val := rdb.Exists(context.Background(), key).Val() - assert.EqualValues(t, 0, val) + tests := []struct { + name string + fields fields + args args + wantErr assert.ErrorAssertionFunc + }{ + {"test1", fields{rdb: redis.NewClient(&redis.Options{Addr: "localhost:16379", Password: "openIM123"})}, + args{context.Background(), "cid", []int64{1, 2, 3}}, assert.NoError}, } -} - -func testPipeDeleteMessagesMix(t *testing.T, cid string, seqs []int64, inputMsgs []*sdkws.MsgData) { - rdb := redis.NewClient(&redis.Options{}) - defer rdb.Close() - - cacher := msgCache{rdb: rdb} - - err := cacher.PipeDeleteMessages(context.Background(), cid, seqs) - assert.Nil(t, err) - - // validate - for idx, msg := range inputMsgs { - key := cacher.getMessageCacheKey(cid, msg.Seq) - val, err := rdb.Exists(context.Background(), key).Result() - assert.Nil(t, err) - if idx < 90 { - assert.EqualValues(t, 0, val) // not exists - continue - } - - assert.EqualValues(t, 1, val) // exists - } -} - -func TestParallelDeleteMessages(t *testing.T) { - var ( - cid = fmt.Sprintf("cid-%v", rand.Int63()) - seqFirst = rand.Int63() - msgs = []*sdkws.MsgData{} - ) - - var seqs []int64 - for i := 0; i < 100; i++ { - msgs = append(msgs, &sdkws.MsgData{ - Seq: seqFirst + int64(i), + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + c := &msgCache{ + rdb: tt.fields.rdb, + } + tt.wantErr(t, c.DeleteMessagesFromCache(tt.args.ctx, tt.args.conversationID, tt.args.seqs), + fmt.Sprintf("DeleteMessagesFromCache(%v, %v, %v)", tt.args.ctx, tt.args.conversationID, tt.args.seqs)) }) - seqs = append(seqs, msgs[i].Seq) - } - - randSeqs := []int64{} - for i := seqFirst + 100; i < seqFirst+200; i++ { - randSeqs = append(randSeqs, i) - } - - testParallelSetMessageToCache(t, cid, msgs) - testParallelDeleteMessagesOK(t, cid, seqs, msgs) - - // set again - testParallelSetMessageToCache(t, cid, msgs) - testParallelDeleteMessagesMix(t, cid, seqs[:90], msgs, 90) - testParallelDeleteMessagesOK(t, cid, seqs[90:], msgs[:90]) - - // set again - testParallelSetMessageToCache(t, cid, msgs) - testParallelDeleteMessagesMix(t, cid, randSeqs, msgs, 0) -} - -func testParallelDeleteMessagesOK(t *testing.T, cid string, seqs []int64, inputMsgs []*sdkws.MsgData) { - rdb := redis.NewClient(&redis.Options{}) - defer rdb.Close() - - cacher := msgCache{rdb: rdb} - - err := cacher.PipeDeleteMessages(context.Background(), cid, seqs) - assert.Nil(t, err) - - // validate - for _, msg := range inputMsgs { - key := cacher.getMessageCacheKey(cid, msg.Seq) - val := rdb.Exists(context.Background(), key).Val() - assert.EqualValues(t, 0, val) - } -} - -func testParallelDeleteMessagesMix(t *testing.T, cid string, seqs []int64, inputMsgs []*sdkws.MsgData, lessValNonExists int) { - rdb := redis.NewClient(&redis.Options{}) - defer rdb.Close() - - cacher := msgCache{rdb: rdb} - - err := cacher.PipeDeleteMessages(context.Background(), cid, seqs) - assert.Nil(t, err) - - // validate - for idx, msg := range inputMsgs { - key := cacher.getMessageCacheKey(cid, msg.Seq) - val, err := rdb.Exists(context.Background(), key).Result() - assert.Nil(t, err) - if idx < lessValNonExists { - assert.EqualValues(t, 0, val) // not exists - continue - } - - assert.EqualValues(t, 1, val) // exists } } diff --git a/pkg/common/storage/cache/redis/redis_shard_manager.go b/pkg/common/storage/cache/redis/redis_shard_manager.go new file mode 100644 index 0000000000..98d70dabf9 --- /dev/null +++ b/pkg/common/storage/cache/redis/redis_shard_manager.go @@ -0,0 +1,197 @@ +package redis + +import ( + "context" + "github.com/openimsdk/tools/errs" + "github.com/openimsdk/tools/log" + "github.com/redis/go-redis/v9" + "golang.org/x/sync/errgroup" +) + +const ( + defaultBatchSize = 50 + defaultConcurrentLimit = 3 +) + +// RedisShardManager is a class for sharding and processing keys +type RedisShardManager struct { + redisClient redis.UniversalClient + config *Config +} +type Config struct { + batchSize int + continueOnError bool + concurrentLimit int +} + +// Option is a function type for configuring Config +type Option func(c *Config) + +// NewRedisShardManager creates a new RedisShardManager instance +func NewRedisShardManager(redisClient redis.UniversalClient, opts ...Option) *RedisShardManager { + config := &Config{ + batchSize: defaultBatchSize, // Default batch size is 50 keys + continueOnError: false, + concurrentLimit: defaultConcurrentLimit, // Default concurrent limit is 3 + } + for _, opt := range opts { + opt(config) + } + rsm := &RedisShardManager{ + redisClient: redisClient, + config: config, + } + return rsm +} + +// WithBatchSize sets the number of keys to process per batch +func WithBatchSize(size int) Option { + return func(c *Config) { + c.batchSize = size + } +} + +// WithContinueOnError sets whether to continue processing on error +func WithContinueOnError(continueOnError bool) Option { + return func(c *Config) { + c.continueOnError = continueOnError + } +} + +// WithConcurrentLimit sets the concurrency limit +func WithConcurrentLimit(limit int) Option { + return func(c *Config) { + c.concurrentLimit = limit + } +} + +// ProcessKeysBySlot groups keys by their Redis cluster hash slots and processes them using the provided function. +func (rsm *RedisShardManager) ProcessKeysBySlot( + ctx context.Context, + keys []string, + processFunc func(ctx context.Context, slot int64, keys []string) error, +) error { + + // Group keys by slot + slots, err := groupKeysBySlot(ctx, rsm.redisClient, keys) + if err != nil { + return err + } + + g, ctx := errgroup.WithContext(ctx) + g.SetLimit(rsm.config.concurrentLimit) + + // Process keys in each slot using the provided function + for slot, singleSlotKeys := range slots { + batches := splitIntoBatches(singleSlotKeys, rsm.config.batchSize) + for _, batch := range batches { + slot, batch := slot, batch // Avoid closure capture issue + g.Go(func() error { + err := processFunc(ctx, slot, batch) + if err != nil { + log.ZWarn(ctx, "Batch processFunc failed", err, "slot", slot, "keys", batch) + if !rsm.config.continueOnError { + return err + } + } + return nil + }) + } + } + + if err := g.Wait(); err != nil { + return err + } + return nil +} + +// groupKeysBySlot groups keys by their Redis cluster hash slots. +func groupKeysBySlot(ctx context.Context, redisClient redis.UniversalClient, keys []string) (map[int64][]string, error) { + slots := make(map[int64][]string) + clusterClient, isCluster := redisClient.(*redis.ClusterClient) + if isCluster { + pipe := clusterClient.Pipeline() + cmds := make([]*redis.IntCmd, len(keys)) + for i, key := range keys { + cmds[i] = pipe.ClusterKeySlot(ctx, key) + } + _, err := pipe.Exec(ctx) + if err != nil { + return nil, errs.WrapMsg(err, "get slot err") + } + + for i, cmd := range cmds { + slot, err := cmd.Result() + if err != nil { + log.ZWarn(ctx, "some key get slot err", err, "key", keys[i]) + return nil, errs.WrapMsg(err, "get slot err", "key", keys[i]) + } + slots[slot] = append(slots[slot], keys[i]) + } + } else { + // If not a cluster client, put all keys in the same slot (0) + slots[0] = keys + } + + return slots, nil +} + +// splitIntoBatches splits keys into batches of the specified size +func splitIntoBatches(keys []string, batchSize int) [][]string { + var batches [][]string + for batchSize < len(keys) { + keys, batches = keys[batchSize:], append(batches, keys[0:batchSize:batchSize]) + } + return append(batches, keys) +} + +// ProcessKeysBySlot groups keys by their Redis cluster hash slots and processes them using the provided function. +func ProcessKeysBySlot( + ctx context.Context, + redisClient redis.UniversalClient, + keys []string, + processFunc func(ctx context.Context, slot int64, keys []string) error, + opts ...Option, +) error { + + config := &Config{ + batchSize: defaultBatchSize, + continueOnError: false, + concurrentLimit: defaultConcurrentLimit, + } + for _, opt := range opts { + opt(config) + } + + // Group keys by slot + slots, err := groupKeysBySlot(ctx, redisClient, keys) + if err != nil { + return err + } + + g, ctx := errgroup.WithContext(ctx) + g.SetLimit(config.concurrentLimit) + + // Process keys in each slot using the provided function + for slot, singleSlotKeys := range slots { + batches := splitIntoBatches(singleSlotKeys, config.batchSize) + for _, batch := range batches { + slot, batch := slot, batch // Avoid closure capture issue + g.Go(func() error { + err := processFunc(ctx, slot, batch) + if err != nil { + log.ZWarn(ctx, "Batch processFunc failed", err, "slot", slot, "keys", batch) + if !config.continueOnError { + return err + } + } + return nil + }) + } + } + + if err := g.Wait(); err != nil { + return err + } + return nil +} diff --git a/pkg/common/storage/cache/user.go b/pkg/common/storage/cache/user.go index 4a129ddd18..5101c0b6ce 100644 --- a/pkg/common/storage/cache/user.go +++ b/pkg/common/storage/cache/user.go @@ -16,15 +16,15 @@ package cache import ( "context" - relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model" "github.com/openimsdk/protocol/user" ) type UserCache interface { BatchDeleter CloneUserCache() UserCache - GetUserInfo(ctx context.Context, userID string) (userInfo *relationtb.User, err error) - GetUsersInfo(ctx context.Context, userIDs []string) ([]*relationtb.User, error) + GetUserInfo(ctx context.Context, userID string) (userInfo *model.User, err error) + GetUsersInfo(ctx context.Context, userIDs []string) ([]*model.User, error) DelUsersInfo(userIDs ...string) UserCache GetUserGlobalRecvMsgOpt(ctx context.Context, userID string) (opt int, err error) DelUsersGlobalRecvMsgOpt(userIDs ...string) UserCache diff --git a/pkg/common/storage/controller/msg.go b/pkg/common/storage/controller/msg.go index ce107e9237..8eb9e8e6fd 100644 --- a/pkg/common/storage/controller/msg.go +++ b/pkg/common/storage/controller/msg.go @@ -54,8 +54,6 @@ type CommonMsgDatabase interface { MarkSingleChatMsgsAsRead(ctx context.Context, userID string, conversationID string, seqs []int64) error // DeleteMessagesFromCache deletes message caches from Redis by sequence numbers. DeleteMessagesFromCache(ctx context.Context, conversationID string, seqs []int64) error - // DelUserDeleteMsgsList deletes user's message deletion list. - DelUserDeleteMsgsList(ctx context.Context, conversationID string, seqs []int64) // BatchInsertChat2Cache increments the sequence number and then batch inserts messages into the cache. BatchInsertChat2Cache(ctx context.Context, conversationID string, msgs []*sdkws.MsgData) (seq int64, isNewConversation bool, err error) // GetMsgBySeqsRange retrieves messages from MongoDB by a range of sequence numbers. @@ -98,7 +96,6 @@ type CommonMsgDatabase interface { // to mq MsgToMQ(ctx context.Context, key string, msg2mq *sdkws.MsgData) error - MsgToModifyMQ(ctx context.Context, key, conversarionID string, msgs []*sdkws.MsgData) error MsgToPushMQ(ctx context.Context, key, conversarionID string, msg2mq *sdkws.MsgData) (int32, int64, error) MsgToMongoMQ(ctx context.Context, key, conversarionID string, msgs []*sdkws.MsgData, lastSeq int64) error @@ -150,14 +147,13 @@ func NewCommonMsgDatabase(msgDocModel database.Msg, msg cache.MsgCache, seq cach //} type commonMsgDatabase struct { - msgDocDatabase database.Msg - msgTable model.MsgDocModel - msg cache.MsgCache - seq cache.SeqCache - producer *kafka.Producer - producerToMongo *kafka.Producer - producerToModify *kafka.Producer - producerToPush *kafka.Producer + msgDocDatabase database.Msg + msgTable model.MsgDocModel + msg cache.MsgCache + seq cache.SeqCache + producer *kafka.Producer + producerToMongo *kafka.Producer + producerToPush *kafka.Producer } func (db *commonMsgDatabase) MsgToMQ(ctx context.Context, key string, msg2mq *sdkws.MsgData) error { @@ -165,14 +161,6 @@ func (db *commonMsgDatabase) MsgToMQ(ctx context.Context, key string, msg2mq *sd return err } -func (db *commonMsgDatabase) MsgToModifyMQ(ctx context.Context, key, conversationID string, messages []*sdkws.MsgData) error { - if len(messages) > 0 { - _, _, err := db.producerToModify.SendMessage(ctx, key, &pbmsg.MsgDataToModifyByMQ{ConversationID: conversationID, Messages: messages}) - return err - } - return nil -} - func (db *commonMsgDatabase) MsgToPushMQ(ctx context.Context, key, conversationID string, msg2mq *sdkws.MsgData) (int32, int64, error) { partition, offset, err := db.producerToPush.SendMessage(ctx, key, &pbmsg.PushMsgDataToMQ{MsgData: msg2mq, ConversationID: conversationID}) if err != nil { @@ -357,11 +345,7 @@ func (db *commonMsgDatabase) MarkSingleChatMsgsAsRead(ctx context.Context, userI } func (db *commonMsgDatabase) DeleteMessagesFromCache(ctx context.Context, conversationID string, seqs []int64) error { - return db.msg.DeleteMessages(ctx, conversationID, seqs) -} - -func (db *commonMsgDatabase) DelUserDeleteMsgsList(ctx context.Context, conversationID string, seqs []int64) { - db.msg.DelUserDeleteMsgsList(ctx, conversationID, seqs) + return db.msg.DeleteMessagesFromCache(ctx, conversationID, seqs) } func (db *commonMsgDatabase) BatchInsertChat2Cache(ctx context.Context, conversationID string, msgs []*sdkws.MsgData) (seq int64, isNew bool, err error) { @@ -388,7 +372,7 @@ func (db *commonMsgDatabase) BatchInsertChat2Cache(ctx context.Context, conversa userSeqMap[m.SendID] = m.Seq } - failedNum, err := db.msg.SetMessageToCache(ctx, conversationID, msgs) + failedNum, err := db.msg.SetMessagesToCache(ctx, conversationID, msgs) if err != nil { prommetrics.MsgInsertRedisFailedCounter.Add(float64(failedNum)) log.ZError(ctx, "setMessageToCache error", err, "len", len(msgs), "conversationID", conversationID) @@ -584,6 +568,7 @@ func (db *commonMsgDatabase) GetMsgBySeqsRange(ctx context.Context, userID strin } newBegin := seqs[0] newEnd := seqs[len(seqs)-1] + var successMsgs []*sdkws.MsgData log.ZDebug(ctx, "GetMsgBySeqsRange", "first seqs", seqs, "newBegin", newBegin, "newEnd", newEnd) cachedMsgs, failedSeqs, err := db.msg.GetMessagesBySeq(ctx, conversationID, seqs) if err != nil { @@ -592,54 +577,12 @@ func (db *commonMsgDatabase) GetMsgBySeqsRange(ctx context.Context, userID strin log.ZError(ctx, "get message from redis exception", err, "conversationID", conversationID, "seqs", seqs) } } - var successMsgs []*sdkws.MsgData - if len(cachedMsgs) > 0 { - delSeqs, err := db.msg.GetUserDelList(ctx, userID, conversationID) - if err != nil && errs.Unwrap(err) != redis.Nil { - return 0, 0, nil, err - } - var cacheDelNum int - for _, msg := range cachedMsgs { - if !datautil.Contain(msg.Seq, delSeqs...) { - successMsgs = append(successMsgs, msg) - } else { - cacheDelNum += 1 - } - } - log.ZDebug(ctx, "get delSeqs from redis", "delSeqs", delSeqs, "userID", userID, "conversationID", conversationID, "cacheDelNum", cacheDelNum) - var reGetSeqsCache []int64 - for i := 1; i <= cacheDelNum; { - newSeq := newBegin - int64(i) - if newSeq >= begin { - if !datautil.Contain(newSeq, delSeqs...) { - log.ZDebug(ctx, "seq del in cache, a new seq in range append", "new seq", newSeq) - reGetSeqsCache = append(reGetSeqsCache, newSeq) - i++ - } - } else { - break - } - } - if len(reGetSeqsCache) > 0 { - log.ZDebug(ctx, "reGetSeqsCache", "reGetSeqsCache", reGetSeqsCache) - cachedMsgs, failedSeqs2, err := db.msg.GetMessagesBySeq(ctx, conversationID, reGetSeqsCache) - if err != nil { - if err != redis.Nil { - - log.ZError(ctx, "get message from redis exception", err, "conversationID", conversationID, "seqs", reGetSeqsCache) - } - } - failedSeqs = append(failedSeqs, failedSeqs2...) - successMsgs = append(successMsgs, cachedMsgs...) - } - } - log.ZDebug(ctx, "get msgs from cache", "successMsgs", successMsgs) - if len(failedSeqs) != 0 { - log.ZDebug(ctx, "msgs not exist in redis", "seqs", failedSeqs) - } - // get from cache or storage + successMsgs = append(successMsgs, cachedMsgs...) + log.ZDebug(ctx, "get msgs from cache", "cachedMsgs", cachedMsgs) + // get from cache or db if len(failedSeqs) > 0 { + log.ZDebug(ctx, "msgs not exist in redis", "seqs", failedSeqs) mongoMsgs, err := db.getMsgBySeqsRange(ctx, userID, conversationID, failedSeqs, begin, end) if err != nil { @@ -679,7 +622,7 @@ func (db *commonMsgDatabase) GetMsgBySeqs(ctx context.Context, userID string, co log.ZError(ctx, "get message from redis exception", err, "failedSeqs", failedSeqs, "conversationID", conversationID) } } - log.ZDebug(ctx, "storage.seq.GetMessagesBySeq", "userID", userID, "conversationID", conversationID, "seqs", + log.ZDebug(ctx, "db.seq.GetMessagesBySeq", "userID", userID, "conversationID", conversationID, "seqs", seqs, "len(successMsgs)", len(successMsgs), "failedSeqs", failedSeqs) if len(failedSeqs) > 0 { @@ -705,12 +648,6 @@ func (db *commonMsgDatabase) DeleteConversationMsgsAndSetMinSeq(ctx context.Cont if minSeq == 0 { return nil } - if remainTime == 0 { - err = db.msg.CleanUpOneConversationAllMsg(ctx, conversationID) - if err != nil { - log.ZWarn(ctx, "CleanUpOneUserAllMsg", err, "conversationID", conversationID) - } - } return db.seq.SetMinSeq(ctx, conversationID, minSeq) } @@ -830,7 +767,7 @@ func (db *commonMsgDatabase) deleteMsgRecursion(ctx context.Context, conversatio } func (db *commonMsgDatabase) DeleteMsgsPhysicalBySeqs(ctx context.Context, conversationID string, allSeqs []int64) error { - if err := db.msg.DeleteMessages(ctx, conversationID, allSeqs); err != nil { + if err := db.msg.DeleteMessagesFromCache(ctx, conversationID, allSeqs); err != nil { return err } for docID, seqs := range db.msgTable.GetDocIDSeqsMap(conversationID, allSeqs) { @@ -846,21 +783,9 @@ func (db *commonMsgDatabase) DeleteMsgsPhysicalBySeqs(ctx context.Context, conve } func (db *commonMsgDatabase) DeleteUserMsgsBySeqs(ctx context.Context, userID string, conversationID string, seqs []int64) error { - cachedMsgs, _, err := db.msg.GetMessagesBySeq(ctx, conversationID, seqs) - if err != nil && errs.Unwrap(err) != redis.Nil { - log.ZWarn(ctx, "DeleteUserMsgsBySeqs", err, "conversationID", conversationID, "seqs", seqs) + if err := db.msg.DeleteMessagesFromCache(ctx, conversationID, seqs); err != nil { return err } - if len(cachedMsgs) > 0 { - var cacheSeqs []int64 - for _, msg := range cachedMsgs { - cacheSeqs = append(cacheSeqs, msg.Seq) - } - if err := db.msg.UserDeleteMsgs(ctx, conversationID, cacheSeqs, userID); err != nil { - return err - } - } - for docID, seqs := range db.msgTable.GetDocIDSeqsMap(conversationID, seqs) { for _, seq := range seqs { if _, err := db.msgDocDatabase.PushUnique(ctx, docID, db.msgTable.GetMsgIndex(seq), "del_list", []string{userID}); err != nil { @@ -1085,14 +1010,14 @@ func (db *commonMsgDatabase) DeleteDocMsgBefore(ctx context.Context, ts int64, d } } -//func (storage *commonMsgDatabase) ClearMsg(ctx context.Context, ts int64) (err error) { +//func (db *commonMsgDatabase) ClearMsg(ctx context.Context, ts int64) (err error) { // var ( // docNum int // msgNum int // start = time.Now() // ) // for { -// msgs, err := storage.msgDocDatabase.GetBeforeMsg(ctx, ts, 100) +// msgs, err := db.msgDocDatabase.GetBeforeMsg(ctx, ts, 100) // if err != nil { // return err // } @@ -1100,7 +1025,7 @@ func (db *commonMsgDatabase) DeleteDocMsgBefore(ctx context.Context, ts int64, d // return nil // } // for _, msg := range msgs { -// num, err := storage.deleteOneMsg(ctx, ts, msg) +// num, err := db.deleteOneMsg(ctx, ts, msg) // if err != nil { // return err // } diff --git a/pkg/common/storage/database/mgo/msg.go b/pkg/common/storage/database/mgo/msg.go index f676c1f59c..a7291fcc8f 100644 --- a/pkg/common/storage/database/mgo/msg.go +++ b/pkg/common/storage/database/mgo/msg.go @@ -5,6 +5,7 @@ import ( "fmt" "github.com/openimsdk/open-im-server/v3/pkg/common/storage/database" "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model" + "github.com/openimsdk/tools/utils/datautil" "time" "github.com/openimsdk/protocol/constant" @@ -108,29 +109,11 @@ func (m *MsgMgo) GetMsgBySeqIndexIn1Doc(ctx context.Context, userID, docID strin {Key: "input", Value: indexs}, {Key: "as", Value: "index"}, {Key: "in", Value: bson.D{ - {Key: "$let", Value: bson.D{ - {Key: "vars", Value: bson.D{ - {Key: "currentMsg", Value: bson.D{ - {Key: "$arrayElemAt", Value: bson.A{"$msgs", "$$index"}}, - }}, - }}, - {Key: "in", Value: bson.D{ - {Key: "$cond", Value: bson.D{ - {Key: "if", Value: bson.D{ - {Key: "$in", Value: bson.A{userID, "$$currentMsg.del_list"}}, - }}, - {Key: "then", Value: nil}, - {Key: "else", Value: "$$currentMsg"}, - }}, - }}, - }}, + {Key: "$arrayElemAt", Value: bson.A{"$msgs", "$$index"}}, }}, }}, }}, }}}, - bson.D{{Key: "$project", Value: bson.D{ - {Key: "msgs.del_list", Value: 0}, - }}}, } msgDocModel, err := mongoutil.Aggregate[*model.MsgDocModel](ctx, m.coll, pipeline) if err != nil { @@ -145,6 +128,10 @@ func (m *MsgMgo) GetMsgBySeqIndexIn1Doc(ctx context.Context, userID, docID strin if msg == nil || msg.Msg == nil { continue } + if datautil.Contain(userID, msg.DelList...) { + msg.Msg.Content = "" + msg.Msg.Status = constant.MsgDeleted + } if msg.Revoke != nil { revokeContent := sdkws.MessageRevokedContent{ RevokerID: msg.Revoke.UserID, diff --git a/pkg/tools/batcher/batcher.go b/pkg/tools/batcher/batcher.go new file mode 100644 index 0000000000..163aeed399 --- /dev/null +++ b/pkg/tools/batcher/batcher.go @@ -0,0 +1,272 @@ +package batcher + +import ( + "context" + "fmt" + "github.com/openimsdk/tools/errs" + "github.com/openimsdk/tools/utils/idutil" + "strings" + "sync" + "time" +) + +var ( + DefaultDataChanSize = 1000 + DefaultSize = 100 + DefaultBuffer = 100 + DefaultWorker = 5 + DefaultInterval = time.Second +) + +type Config struct { + size int // Number of message aggregations + buffer int // The number of caches running in a single coroutine + dataBuffer int // The size of the main data channel + worker int // Number of coroutines processed in parallel + interval time.Duration // Time of message aggregations + syncWait bool // Whether to wait synchronously after distributing messages have been consumed +} + +type Option func(c *Config) + +func WithSize(s int) Option { + return func(c *Config) { + c.size = s + } +} + +func WithBuffer(b int) Option { + return func(c *Config) { + c.buffer = b + } +} + +func WithWorker(w int) Option { + return func(c *Config) { + c.worker = w + } +} + +func WithInterval(i time.Duration) Option { + return func(c *Config) { + c.interval = i + } +} + +func WithSyncWait(wait bool) Option { + return func(c *Config) { + c.syncWait = wait + } +} + +func WithDataBuffer(size int) Option { + return func(c *Config) { + c.dataBuffer = size + } +} + +type Batcher[T any] struct { + config *Config + + globalCtx context.Context + cancel context.CancelFunc + Do func(ctx context.Context, channelID int, val *Msg[T]) + OnComplete func(lastMessage *T, totalCount int) + Sharding func(key string) int + Key func(data *T) string + HookFunc func(triggerID string, messages map[string][]*T, totalCount int, lastMessage *T) + data chan *T + chArrays []chan *Msg[T] + wait sync.WaitGroup + counter sync.WaitGroup +} + +func emptyOnComplete[T any](*T, int) {} +func emptyHookFunc[T any](string, map[string][]*T, int, *T) { +} + +func New[T any](opts ...Option) *Batcher[T] { + b := &Batcher[T]{ + OnComplete: emptyOnComplete[T], + HookFunc: emptyHookFunc[T], + } + config := &Config{ + size: DefaultSize, + buffer: DefaultBuffer, + worker: DefaultWorker, + interval: DefaultInterval, + } + for _, opt := range opts { + opt(config) + } + b.config = config + b.data = make(chan *T, DefaultDataChanSize) + b.globalCtx, b.cancel = context.WithCancel(context.Background()) + + b.chArrays = make([]chan *Msg[T], b.config.worker) + for i := 0; i < b.config.worker; i++ { + b.chArrays[i] = make(chan *Msg[T], b.config.buffer) + } + return b +} + +func (b *Batcher[T]) Worker() int { + return b.config.worker +} + +func (b *Batcher[T]) Start() error { + if b.Sharding == nil { + return errs.New("Sharding function is required").Wrap() + } + if b.Do == nil { + return errs.New("Do function is required").Wrap() + } + if b.Key == nil { + return errs.New("Key function is required").Wrap() + } + b.wait.Add(b.config.worker) + for i := 0; i < b.config.worker; i++ { + go b.run(i, b.chArrays[i]) + } + b.wait.Add(1) + go b.scheduler() + return nil +} + +func (b *Batcher[T]) Put(ctx context.Context, data *T) error { + if data == nil { + return errs.New("data can not be nil").Wrap() + } + select { + case <-b.globalCtx.Done(): + return errs.New("data channel is closed").Wrap() + case <-ctx.Done(): + return ctx.Err() + case b.data <- data: + return nil + } +} + +func (b *Batcher[T]) scheduler() { + ticker := time.NewTicker(b.config.interval) + defer func() { + ticker.Stop() + for _, ch := range b.chArrays { + close(ch) + } + close(b.data) + b.wait.Done() + }() + + vals := make(map[string][]*T) + count := 0 + var lastAny *T + + for { + select { + case data, ok := <-b.data: + if !ok { + // If the data channel is closed unexpectedly + return + } + if data == nil { + if count > 0 { + b.distributeMessage(vals, count, lastAny) + } + return + } + + key := b.Key(data) + vals[key] = append(vals[key], data) + lastAny = data + + count++ + if count >= b.config.size { + + b.distributeMessage(vals, count, lastAny) + vals = make(map[string][]*T) + count = 0 + } + + case <-ticker.C: + if count > 0 { + + b.distributeMessage(vals, count, lastAny) + vals = make(map[string][]*T) + count = 0 + } + } + } +} + +type Msg[T any] struct { + key string + triggerID string + val []*T +} + +func (m Msg[T]) Key() string { + return m.key +} + +func (m Msg[T]) TriggerID() string { + return m.triggerID +} + +func (m Msg[T]) Val() []*T { + return m.val +} + +func (m Msg[T]) String() string { + var sb strings.Builder + sb.WriteString("Key: ") + sb.WriteString(m.key) + sb.WriteString(", Values: [") + for i, v := range m.val { + if i > 0 { + sb.WriteString(", ") + } + sb.WriteString(fmt.Sprintf("%v", *v)) + } + sb.WriteString("]") + return sb.String() +} + +func (b *Batcher[T]) distributeMessage(messages map[string][]*T, totalCount int, lastMessage *T) { + triggerID := idutil.OperationIDGenerator() + b.HookFunc(triggerID, messages, totalCount, lastMessage) + for key, data := range messages { + if b.config.syncWait { + b.counter.Add(1) + } + channelID := b.Sharding(key) + b.chArrays[channelID] <- &Msg[T]{key: key, triggerID: triggerID, val: data} + } + if b.config.syncWait { + b.counter.Wait() + } + b.OnComplete(lastMessage, totalCount) +} + +func (b *Batcher[T]) run(channelID int, ch <-chan *Msg[T]) { + defer b.wait.Done() + for { + select { + case messages, ok := <-ch: + if !ok { + return + } + b.Do(context.Background(), channelID, messages) + if b.config.syncWait { + b.counter.Done() + } + } + } +} + +func (b *Batcher[T]) Close() { + b.cancel() // Signal to stop put data + b.data <- nil + //wait all goroutines exit + b.wait.Wait() +} diff --git a/pkg/tools/batcher/batcher_test.go b/pkg/tools/batcher/batcher_test.go new file mode 100644 index 0000000000..90e0284490 --- /dev/null +++ b/pkg/tools/batcher/batcher_test.go @@ -0,0 +1,66 @@ +package batcher + +import ( + "context" + "fmt" + "github.com/openimsdk/tools/utils/stringutil" + "testing" + "time" +) + +func TestBatcher(t *testing.T) { + config := Config{ + size: 1000, + buffer: 10, + worker: 10, + interval: 5 * time.Millisecond, + } + + b := New[string]( + WithSize(config.size), + WithBuffer(config.buffer), + WithWorker(config.worker), + WithInterval(config.interval), + WithSyncWait(true), + ) + + // Mock Do function to simply print values for demonstration + b.Do = func(ctx context.Context, channelID int, vals *Msg[string]) { + t.Logf("Channel %d Processed batch: %v", channelID, vals) + } + b.OnComplete = func(lastMessage *string, totalCount int) { + t.Logf("Completed processing with last message: %v, total count: %d", *lastMessage, totalCount) + } + b.Sharding = func(key string) int { + hashCode := stringutil.GetHashCode(key) + return int(hashCode) % config.worker + } + b.Key = func(data *string) string { + return *data + } + + err := b.Start() + if err != nil { + t.Fatal(err) + } + + // Test normal data processing + for i := 0; i < 10000; i++ { + data := "data" + fmt.Sprintf("%d", i) + if err := b.Put(context.Background(), &data); err != nil { + t.Fatal(err) + } + } + + time.Sleep(time.Duration(1) * time.Second) + start := time.Now() + // Wait for all processing to finish + b.Close() + + elapsed := time.Since(start) + t.Logf("Close took %s", elapsed) + + if len(b.data) != 0 { + t.Error("Data channel should be empty after closing") + } +} From e32d30f2870c9bdd742012eb9fd44b1962d48c76 Mon Sep 17 00:00:00 2001 From: skiffer-git <72860476+skiffer-git@users.noreply.github.com> Date: Mon, 3 Jun 2024 20:27:43 +0800 Subject: [PATCH 180/188] Add a retry mechanism to mongo init (#2328) --- scripts/mongo-init.sh | 62 ++++++++++++++++++++++++++++--------------- 1 file changed, 40 insertions(+), 22 deletions(-) diff --git a/scripts/mongo-init.sh b/scripts/mongo-init.sh index 01199c4806..25bb2d654c 100755 --- a/scripts/mongo-init.sh +++ b/scripts/mongo-init.sh @@ -11,38 +11,56 @@ # 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. - mongosh < 0) { + try { + db = connect('mongodb://127.0.0.1:27017/admin'); + var authResult = db.auth(rootUsername, rootPassword); + if (authResult) { + print('Authentication successful for root user: ' + rootUsername); + connected = true; + } else { + print('Authentication failed for root user: ' + rootUsername + ' with password: ' + rootPassword); + quit(1); + } + } catch (e) { + maxRetries--; + print('Connection failed, retrying... Remaining attempts: ' + maxRetries); + sleep(1000); // Sleep for 1 second + } +} + +if (connected) { + db = db.getSiblingDB(dbName); + var createUserResult = db.createUser({ + user: openimUsername, + pwd: openimPassword, + roles: [{ + role: 'readWrite', + db: dbName + }] + }); + + if (createUserResult.ok == 1) { + print('User creation successful. User: ' + openimUsername + ', Database: ' + dbName); + } else { + print('User creation failed for user: ' + openimUsername + ' in database: ' + dbName); + quit(1); + } } else { - print('User creation failed for user: ' + openimUsername + ' in database: ' + dbName); - quit(1); + print('Failed to connect to MongoDB after 300 retries.'); + quit(1); } EOF + From a8d5ec314a28c122999b2dc9d13b5222a105d74b Mon Sep 17 00:00:00 2001 From: Monet Lee Date: Thu, 13 Jun 2024 09:55:07 +0800 Subject: [PATCH 181/188] feat: implement to invalid token when forceKickOff user. (#2345) * feat: implement to invalid token when forceKickOff user. * fix uncorrect contents. * fix: remove unnecessary contents. --- internal/rpc/auth/auth.go | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/internal/rpc/auth/auth.go b/internal/rpc/auth/auth.go index 6270b39b3a..320fb1d525 100644 --- a/internal/rpc/auth/auth.go +++ b/internal/rpc/auth/auth.go @@ -16,6 +16,7 @@ package auth import ( "context" + "github.com/openimsdk/open-im-server/v3/pkg/common/config" redis2 "github.com/openimsdk/open-im-server/v3/pkg/common/storage/cache/redis" "github.com/openimsdk/tools/db/redisutil" @@ -32,7 +33,6 @@ import ( "github.com/openimsdk/tools/discovery" "github.com/openimsdk/tools/errs" "github.com/openimsdk/tools/log" - "github.com/openimsdk/tools/mcontext" "github.com/openimsdk/tools/tokenverify" "google.golang.org/grpc" ) @@ -153,21 +153,19 @@ func (s *authServer) ForceLogout(ctx context.Context, req *pbauth.ForceLogoutReq if err := authverify.CheckAdmin(ctx, s.config.Share.IMAdminUserID); err != nil { return nil, err } - if err := s.forceKickOff(ctx, req.UserID, req.PlatformID, mcontext.GetOperationID(ctx)); err != nil { + if err := s.forceKickOff(ctx, req.UserID, req.PlatformID); err != nil { return nil, err } return &pbauth.ForceLogoutResp{}, nil } -func (s *authServer) forceKickOff(ctx context.Context, userID string, platformID int32, operationID string) error { +func (s *authServer) forceKickOff(ctx context.Context, userID string, platformID int32) error { conns, err := s.RegisterCenter.GetConns(ctx, s.config.Share.RpcRegisterName.MessageGateway) if err != nil { return err } for _, v := range conns { log.ZDebug(ctx, "forceKickOff", "conn", v.Target()) - } - for _, v := range conns { client := msggateway.NewMsgGatewayClient(v) kickReq := &msggateway.KickUserOfflineReq{KickUserIDList: []string{userID}, PlatformID: platformID} _, err := client.KickUserOffline(ctx, kickReq) @@ -175,8 +173,24 @@ func (s *authServer) forceKickOff(ctx context.Context, userID string, platformID log.ZError(ctx, "forceKickOff", err, "kickReq", kickReq) } } + + m, err := s.authDatabase.GetTokensWithoutError(ctx, userID, int(platformID)) + if err != nil && err != redis.Nil { + return err + } + for k := range m { + m[k] = constant.KickedToken + log.ZDebug(ctx, "set token map is ", "token map", m, "userID", + userID, "token", k) + + err = s.authDatabase.SetTokenMapByUidPid(ctx, userID, int(platformID), m) + if err != nil { + return err + } + } return nil } + func (s *authServer) InvalidateToken(ctx context.Context, req *pbauth.InvalidateTokenReq) (*pbauth.InvalidateTokenResp, error) { m, err := s.authDatabase.GetTokensWithoutError(ctx, req.UserID, int(req.PlatformID)) if err != nil && err != redis.Nil { From 180532317ee4d686c285fffab41d071eb4a3e339 Mon Sep 17 00:00:00 2001 From: icey-yu <119291641+icey-yu@users.noreply.github.com> Date: Thu, 13 Jun 2024 12:09:00 +0800 Subject: [PATCH 182/188] fix:FCM push failed will return error (#2347) * fix:FCM push failed will return error * fix:change error delimiter --- internal/push/offlinepush/fcm/push.go | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/internal/push/offlinepush/fcm/push.go b/internal/push/offlinepush/fcm/push.go index ec973008e3..7ce5b18e5b 100644 --- a/internal/push/offlinepush/fcm/push.go +++ b/internal/push/offlinepush/fcm/push.go @@ -16,8 +16,10 @@ package fcm import ( "context" + "fmt" "github.com/openimsdk/open-im-server/v3/internal/push/offlinepush/options" "path/filepath" + "strings" firebase "firebase.google.com/go" "firebase.google.com/go/messaging" @@ -79,6 +81,8 @@ func (f *Fcm) Push(ctx context.Context, userIDs []string, title, content string, notification.Body = content notification.Title = title var messages []*messaging.Message + var sendErrBuilder strings.Builder + var msgErrBuilder strings.Builder for userID, personTokens := range allTokens { apns := &messaging.APNSConfig{Payload: &messaging.APNSPayload{Aps: &messaging.Aps{Sound: opts.IOSPushSound}}} messageCount := len(messages) @@ -86,9 +90,21 @@ func (f *Fcm) Push(ctx context.Context, userIDs []string, title, content string, response, err := f.fcmMsgCli.SendAll(ctx, messages) if err != nil { Fail = Fail + messageCount + // Record push error + sendErrBuilder.WriteString(err.Error()) + sendErrBuilder.WriteByte('.') } else { Success = Success + response.SuccessCount Fail = Fail + response.FailureCount + if response.FailureCount != 0 { + // Record message error + for i := range response.Responses { + if !response.Responses[i].Success { + msgErrBuilder.WriteString(response.Responses[i].Error.Error()) + msgErrBuilder.WriteByte('.') + } + } + } } messages = messages[0:0] } @@ -134,5 +150,9 @@ func (f *Fcm) Push(ctx context.Context, userIDs []string, title, content string, Fail = Fail + response.FailureCount } } + if Fail != 0 { + return errs.New(fmt.Sprintf("%d message send failed;send err:%s;message err:%s", + Fail, sendErrBuilder.String(), msgErrBuilder.String())).Wrap() + } return nil } From 877abfe7cea5cc69e9dec03e899d415400800fec Mon Sep 17 00:00:00 2001 From: icey-yu <119291641+icey-yu@users.noreply.github.com> Date: Thu, 13 Jun 2024 12:13:13 +0800 Subject: [PATCH 183/188] Fix group and config (#2341) * fix:fcm config path * update:go mod(only one can create group) * feat:get fcm config from url * fix:err and name * fix:config name and annotation * refactor:change FCM config name * refactor:change standardized URL * Update openim-push.yml --------- Co-authored-by: skiffer-git <72860476+skiffer-git@users.noreply.github.com> --- config/openim-push.yml | 4 +++- go.mod | 2 +- go.sum | 4 ++-- internal/push/offlinepush/fcm/push.go | 26 ++++++++++++++++------ internal/push/offlinepush/offlinepusher.go | 4 ++-- internal/push/push.go | 3 ++- pkg/common/cmd/push.go | 1 + pkg/common/cmd/root.go | 6 +++++ pkg/common/config/config.go | 3 ++- 9 files changed, 38 insertions(+), 15 deletions(-) diff --git a/config/openim-push.yml b/config/openim-push.yml index a1abfcf889..9384008a04 100644 --- a/config/openim-push.yml +++ b/config/openim-push.yml @@ -23,7 +23,9 @@ geTui: channelID: '' channelName: '' fcm: - serviceAccount: "x.json" + # Prioritize using file paths. If the file path is empty, use URL + filePath: "" # File path is concatenated with the parameters passed in through - c(`mage` default pass in `config/`) and filePath. + authURL: "" # Must start with https or http. jpns: appKey: '' masterSecret: '' diff --git a/go.mod b/go.mod index e34e3e4bd8..5e17e866cd 100644 --- a/go.mod +++ b/go.mod @@ -13,7 +13,7 @@ require ( github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible // indirect github.com/mitchellh/mapstructure v1.5.0 - github.com/openimsdk/protocol v0.0.65 + github.com/openimsdk/protocol v0.0.66-alpha.1 github.com/openimsdk/tools v0.0.49-alpha.19 github.com/pkg/errors v0.9.1 // indirect github.com/prometheus/client_golang v1.18.0 diff --git a/go.sum b/go.sum index b2fa7f318d..7c5e024495 100644 --- a/go.sum +++ b/go.sum @@ -270,8 +270,8 @@ github.com/onsi/gomega v1.25.0 h1:Vw7br2PCDYijJHSfBOWhov+8cAnUf8MfMaIOV323l6Y= github.com/onsi/gomega v1.25.0/go.mod h1:r+zV744Re+DiYCIPRlYOTxn0YkOLcAnW8k1xXdMPGhM= github.com/openimsdk/gomake v0.0.13 h1:xLDe/moqgWpRoptHzI4packAWzs4C16b+sVY+txNJp0= github.com/openimsdk/gomake v0.0.13/go.mod h1:PndCozNc2IsQIciyn9mvEblYWZwJmAI+06z94EY+csI= -github.com/openimsdk/protocol v0.0.65 h1:SPT9qyUsFRTTKSKb/FjpS+xr6sxz/Kbnu+su1bxYagc= -github.com/openimsdk/protocol v0.0.65/go.mod h1:OZQA9FR55lseYoN2Ql1XAHYKHJGu7OMNkUbuekrKCM8= +github.com/openimsdk/protocol v0.0.66-alpha.1 h1:/8y+aXQeX6+IgfFxujHbRgJylqJRkwF5gMrwNhWMsiU= +github.com/openimsdk/protocol v0.0.66-alpha.1/go.mod h1:OZQA9FR55lseYoN2Ql1XAHYKHJGu7OMNkUbuekrKCM8= github.com/openimsdk/tools v0.0.49-alpha.19 h1:CbASL0yefRSVAmWPVeRnhF7wZKd6umLfz31CIhEgrBs= github.com/openimsdk/tools v0.0.49-alpha.19/go.mod h1:g7mkHXYUPi0/8aAX8VPMHpnb3hqdV69Jph+bXOGvvNM= github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4= diff --git a/internal/push/offlinepush/fcm/push.go b/internal/push/offlinepush/fcm/push.go index 7ce5b18e5b..f015ca4e51 100644 --- a/internal/push/offlinepush/fcm/push.go +++ b/internal/push/offlinepush/fcm/push.go @@ -18,6 +18,7 @@ import ( "context" "fmt" "github.com/openimsdk/open-im-server/v3/internal/push/offlinepush/options" + "github.com/openimsdk/tools/utils/httputil" "path/filepath" "strings" @@ -42,13 +43,25 @@ type Fcm struct { // NewClient initializes a new FCM client using the Firebase Admin SDK. // It requires the FCM service account credentials file located within the project's configuration directory. -func NewClient(pushConf *config.Push, cache cache.ThirdCache) (*Fcm, error) { - projectRoot, err := config.GetProjectRoot() - if err != nil { - return nil, err +func NewClient(pushConf *config.Push, cache cache.ThirdCache, fcmConfigPath string) (*Fcm, error) { + var opt option.ClientOption + switch { + case len(pushConf.FCM.FilePath) != 0: + // with file path + credentialsFilePath := filepath.Join(fcmConfigPath, pushConf.FCM.FilePath) + opt = option.WithCredentialsFile(credentialsFilePath) + case len(pushConf.FCM.AuthURL) != 0: + // with authentication URL + client := httputil.NewHTTPClient(httputil.NewClientConfig()) + resp, err := client.Get(pushConf.FCM.AuthURL) + if err != nil { + return nil, err + } + opt = option.WithCredentialsJSON(resp) + default: + return nil, errs.New("no FCM config").Wrap() } - credentialsFilePath := filepath.Join(projectRoot, "config", pushConf.FCM.ServiceAccount) - opt := option.WithCredentialsFile(credentialsFilePath) + fcmApp, err := firebase.NewApp(context.Background(), nil, opt) if err != nil { return nil, errs.Wrap(err) @@ -58,7 +71,6 @@ func NewClient(pushConf *config.Push, cache cache.ThirdCache) (*Fcm, error) { if err != nil { return nil, errs.Wrap(err) } - return &Fcm{fcmMsgCli: fcmMsgClient, cache: cache}, nil } diff --git a/internal/push/offlinepush/offlinepusher.go b/internal/push/offlinepush/offlinepusher.go index 8dc8a0bc6b..9aa6625deb 100644 --- a/internal/push/offlinepush/offlinepusher.go +++ b/internal/push/offlinepush/offlinepusher.go @@ -36,13 +36,13 @@ type OfflinePusher interface { Push(ctx context.Context, userIDs []string, title, content string, opts *options.Opts) error } -func NewOfflinePusher(pushConf *config.Push, cache cache.ThirdCache) (OfflinePusher, error) { +func NewOfflinePusher(pushConf *config.Push, cache cache.ThirdCache, fcmConfigPath string) (OfflinePusher, error) { var offlinePusher OfflinePusher switch pushConf.Enable { case geTUI: offlinePusher = getui.NewClient(pushConf, cache) case firebase: - return fcm.NewClient(pushConf, cache) + return fcm.NewClient(pushConf, cache, fcmConfigPath) case jPush: offlinePusher = jpush.NewClient(pushConf) default: diff --git a/internal/push/push.go b/internal/push/push.go index c7e245dfe2..1a04bbea26 100644 --- a/internal/push/push.go +++ b/internal/push/push.go @@ -29,6 +29,7 @@ type Config struct { WebhooksConfig config.Webhooks LocalCacheConfig config.LocalCache Discovery config.Discovery + FcmConfigPath string } func (p pushServer) PushMsg(ctx context.Context, req *pbpush.PushMsgReq) (*pbpush.PushMsgResp, error) { @@ -50,7 +51,7 @@ func Start(ctx context.Context, config *Config, client discovery.SvcDiscoveryReg return err } cacheModel := redis.NewThirdCache(rdb) - offlinePusher, err := offlinepush.NewOfflinePusher(&config.RpcConfig, cacheModel) + offlinePusher, err := offlinepush.NewOfflinePusher(&config.RpcConfig, cacheModel, config.FcmConfigPath) if err != nil { return err } diff --git a/pkg/common/cmd/push.go b/pkg/common/cmd/push.go index 3e7c4c2492..6e6014021e 100644 --- a/pkg/common/cmd/push.go +++ b/pkg/common/cmd/push.go @@ -47,6 +47,7 @@ func NewPushRpcCmd() *PushRpcCmd { 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.pushConfig.FcmConfigPath = ret.ConfigPath() return ret.runE() } return ret diff --git a/pkg/common/cmd/root.go b/pkg/common/cmd/root.go index 9002813676..08bb6d0642 100644 --- a/pkg/common/cmd/root.go +++ b/pkg/common/cmd/root.go @@ -31,6 +31,11 @@ type RootCmd struct { prometheusPort int log config.Log index int + configPath string +} + +func (r *RootCmd) ConfigPath() string { + return r.configPath } func (r *RootCmd) Index() int { @@ -153,6 +158,7 @@ func (r *RootCmd) getFlag(cmd *cobra.Command) (string, int, error) { if err != nil { return "", 0, errs.Wrap(err) } + r.configPath = configDirectory index, err := cmd.Flags().GetInt(FlagTransferIndex) if err != nil { return "", 0, errs.Wrap(err) diff --git a/pkg/common/config/config.go b/pkg/common/config/config.go index 5313c196ac..6260dc00f5 100644 --- a/pkg/common/config/config.go +++ b/pkg/common/config/config.go @@ -202,7 +202,8 @@ type Push struct { ChannelName string `mapstructure:"channelName"` } `mapstructure:"geTui"` FCM struct { - ServiceAccount string `mapstructure:"serviceAccount"` + FilePath string `mapstructure:"filePath"` + AuthURL string `mapstructure:"authURL"` } `mapstructure:"fcm"` JPNS struct { AppKey string `mapstructure:"appKey"` From d6606152eeda91be293a66e669b223b2891f21d6 Mon Sep 17 00:00:00 2001 From: icey-yu <119291641+icey-yu@users.noreply.github.com> Date: Mon, 24 Jun 2024 16:11:19 +0800 Subject: [PATCH 184/188] fix:create auth token can add expire time (#2352) * fix:create auth token can add expire time * refactor:move expire time calculate into cache from controller --- internal/rpc/auth/auth.go | 2 +- pkg/common/storage/cache/redis/token.go | 30 ++++++++++++++++++++----- pkg/common/storage/cache/token.go | 4 +++- pkg/common/storage/controller/auth.go | 18 ++++++++++++++- 4 files changed, 45 insertions(+), 9 deletions(-) diff --git a/internal/rpc/auth/auth.go b/internal/rpc/auth/auth.go index 320fb1d525..804375e4fb 100644 --- a/internal/rpc/auth/auth.go +++ b/internal/rpc/auth/auth.go @@ -61,7 +61,7 @@ func Start(ctx context.Context, config *Config, client discovery.SvcDiscoveryReg userRpcClient: &userRpcClient, RegisterCenter: client, authDatabase: controller.NewAuthDatabase( - redis2.NewTokenCacheModel(rdb), + redis2.NewTokenCacheModel(rdb, config.RpcConfig.TokenPolicy.Expire), config.Share.Secret, config.RpcConfig.TokenPolicy.Expire, ), diff --git a/pkg/common/storage/cache/redis/token.go b/pkg/common/storage/cache/redis/token.go index 6098a666cf..b822596582 100644 --- a/pkg/common/storage/cache/redis/token.go +++ b/pkg/common/storage/cache/redis/token.go @@ -21,22 +21,36 @@ import ( "github.com/openimsdk/tools/errs" "github.com/openimsdk/tools/utils/stringutil" "github.com/redis/go-redis/v9" + "time" ) type tokenCache struct { - rdb redis.UniversalClient + rdb redis.UniversalClient + accessExpire time.Duration } -func NewTokenCacheModel(rdb redis.UniversalClient) cache.TokenModel { - return &tokenCache{ - rdb: rdb, - } +func NewTokenCacheModel(rdb redis.UniversalClient, accessExpire int64) cache.TokenModel { + c := &tokenCache{rdb: rdb} + c.accessExpire = c.getExpireTime(accessExpire) + return c } -func (c *tokenCache) AddTokenFlag(ctx context.Context, userID string, platformID int, token string, flag int) error { +func (c *tokenCache) SetTokenFlag(ctx context.Context, userID string, platformID int, token string, flag int) error { return errs.Wrap(c.rdb.HSet(ctx, cachekey.GetTokenKey(userID, platformID), token, flag).Err()) } +// SetTokenFlagEx set token and flag with expire time +func (c *tokenCache) SetTokenFlagEx(ctx context.Context, userID string, platformID int, token string, flag int) error { + key := cachekey.GetTokenKey(userID, platformID) + if err := c.rdb.HSet(ctx, key, token, flag).Err(); err != nil { + return errs.Wrap(err) + } + if err := c.rdb.Expire(ctx, key, c.accessExpire).Err(); err != nil { + return errs.Wrap(err) + } + return nil +} + func (c *tokenCache) GetTokensWithoutError(ctx context.Context, userID string, platformID int) (map[string]int, error) { m, err := c.rdb.HGetAll(ctx, cachekey.GetTokenKey(userID, platformID)).Result() if err != nil { @@ -61,3 +75,7 @@ func (c *tokenCache) SetTokenMapByUidPid(ctx context.Context, userID string, pla func (c *tokenCache) DeleteTokenByUidPid(ctx context.Context, userID string, platformID int, fields []string) error { return errs.Wrap(c.rdb.HDel(ctx, cachekey.GetTokenKey(userID, platformID), fields...).Err()) } + +func (c *tokenCache) getExpireTime(t int64) time.Duration { + return time.Hour * 24 * time.Duration(t) +} diff --git a/pkg/common/storage/cache/token.go b/pkg/common/storage/cache/token.go index 55b3321ef6..4a0fee087d 100644 --- a/pkg/common/storage/cache/token.go +++ b/pkg/common/storage/cache/token.go @@ -5,7 +5,9 @@ import ( ) type TokenModel interface { - AddTokenFlag(ctx context.Context, userID string, platformID int, token string, flag int) error + SetTokenFlag(ctx context.Context, userID string, platformID int, token string, flag int) error + // SetTokenFlagEx set token and flag with expire time + SetTokenFlagEx(ctx context.Context, userID string, platformID int, token string, flag int) error GetTokensWithoutError(ctx context.Context, userID string, platformID int) (map[string]int, error) SetTokenMapByUidPid(ctx context.Context, userID string, platformID int, m map[string]int) error DeleteTokenByUidPid(ctx context.Context, userID string, platformID int, fields []string) error diff --git a/pkg/common/storage/controller/auth.go b/pkg/common/storage/controller/auth.go index 321583743a..fbfe30836a 100644 --- a/pkg/common/storage/controller/auth.go +++ b/pkg/common/storage/controller/auth.go @@ -55,6 +55,7 @@ func (a *authDatabase) SetTokenMapByUidPid(ctx context.Context, userID string, p // Create Token. func (a *authDatabase) CreateToken(ctx context.Context, userID string, platformID int) (string, error) { + isCreate := true // flag is create or update tokens, err := a.cache.GetTokensWithoutError(ctx, userID, platformID) if err != nil { return "", err @@ -65,6 +66,9 @@ func (a *authDatabase) CreateToken(ctx context.Context, userID string, platformI if err != nil || v != constant.NormalToken { deleteTokenKey = append(deleteTokenKey, k) } + if v == constant.NormalToken { + isCreate = false + } } if len(deleteTokenKey) != 0 { err = a.cache.DeleteTokenByUidPid(ctx, userID, platformID, deleteTokenKey) @@ -79,5 +83,17 @@ func (a *authDatabase) CreateToken(ctx context.Context, userID string, platformI if err != nil { return "", errs.WrapMsg(err, "token.SignedString") } - return tokenString, a.cache.AddTokenFlag(ctx, userID, platformID, tokenString, constant.NormalToken) + + if isCreate { + // should create,should specify expiration time + if err = a.cache.SetTokenFlagEx(ctx, userID, platformID, tokenString, constant.NormalToken); err != nil { + return "", err + } + } else { + // should update + if err = a.cache.SetTokenFlag(ctx, userID, platformID, tokenString, constant.NormalToken); err != nil { + return "", err + } + } + return tokenString, nil } From e6f1232582b0e7e01f5ca5594ae9d4c2c2948611 Mon Sep 17 00:00:00 2001 From: icey-yu <119291641+icey-yu@users.noreply.github.com> Date: Thu, 27 Jun 2024 17:54:42 +0800 Subject: [PATCH 185/188] fix: message can store Ex (#2371) --- internal/api/msg.go | 1 + pkg/apistruct/manage.go | 3 +++ 2 files changed, 4 insertions(+) diff --git a/internal/api/msg.go b/internal/api/msg.go index 180342e591..ba63fbb66f 100644 --- a/internal/api/msg.go +++ b/internal/api/msg.go @@ -101,6 +101,7 @@ func (m MessageApi) newUserSendMsgReq(_ *gin.Context, params *apistruct.SendMsg) SendTime: params.SendTime, Options: options, OfflinePushInfo: params.OfflinePushInfo, + Ex: params.Ex, }, } return &pbData diff --git a/pkg/apistruct/manage.go b/pkg/apistruct/manage.go index e79b477222..6ea6a29ed6 100644 --- a/pkg/apistruct/manage.go +++ b/pkg/apistruct/manage.go @@ -55,6 +55,9 @@ type SendMsg struct { // OfflinePushInfo contains information for offline push notifications. OfflinePushInfo *sdkws.OfflinePushInfo `json:"offlinePushInfo"` + + // Ex stores extended fields + Ex string `json:"ex"` } // SendMsgReq extends SendMsg with the requirement of RecvID when SessionType indicates a one-on-one or notification chat. From 118c5f56f3e671d28248ff3d90529eb9cb1d5376 Mon Sep 17 00:00:00 2001 From: printlin <32053356+printlin@users.noreply.github.com> Date: Thu, 27 Jun 2024 18:10:06 +0800 Subject: [PATCH 186/188] feature: add webhook AttentionIds (#2370) --- config/webhooks.yml | 3 +++ internal/rpc/msg/callback.go | 5 +++++ pkg/common/config/config.go | 5 +++-- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/config/webhooks.yml b/config/webhooks.yml index c7839d4f21..11a85ba0c4 100644 --- a/config/webhooks.yml +++ b/config/webhooks.yml @@ -13,6 +13,9 @@ afterUpdateUserInfoEx: afterSendSingleMsg: enable: false timeout: 5 + # Only the senID/recvID specified in attentionIds will send the callback + # if not set, all user messages will be callback + attentionIds: [] beforeSendGroupMsg: enable: false timeout: 5 diff --git a/internal/rpc/msg/callback.go b/internal/rpc/msg/callback.go index 10404675eb..be58d75047 100644 --- a/internal/rpc/msg/callback.go +++ b/internal/rpc/msg/callback.go @@ -83,6 +83,11 @@ func (m *msgServer) webhookAfterSendSingleMsg(ctx context.Context, after *config if msg.MsgData.ContentType == constant.Typing { return } + // According to the attentionIds configuration, only some users are sent + attentionIds := after.AttentionIds + if attentionIds != nil && !datautil.Contain(msg.MsgData.RecvID, attentionIds...) && !datautil.Contain(msg.MsgData.SendID, attentionIds...) { + return + } cbReq := &cbapi.CallbackAfterSendSingleMsgReq{ CommonCallbackReq: toCommonCallback(ctx, msg, cbapi.CallbackAfterSendSingleMsgCommand), RecvID: msg.MsgData.RecvID, diff --git a/pkg/common/config/config.go b/pkg/common/config/config.go index 6260dc00f5..0b6176fb74 100644 --- a/pkg/common/config/config.go +++ b/pkg/common/config/config.go @@ -339,8 +339,9 @@ type BeforeConfig struct { } type AfterConfig struct { - Enable bool `mapstructure:"enable"` - Timeout int `mapstructure:"timeout"` + Enable bool `mapstructure:"enable"` + Timeout int `mapstructure:"timeout"` + AttentionIds []string `mapstructure:"attentionIds"` } type Share struct { From fe7c029c2a7562fac400279cb0b41b8110cbf818 Mon Sep 17 00:00:00 2001 From: icey-yu <119291641+icey-yu@users.noreply.github.com> Date: Thu, 27 Jun 2024 18:16:03 +0800 Subject: [PATCH 187/188] fix: group application (#2367) * fix: group application * feat: constant --- internal/rpc/group/notification.go | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/internal/rpc/group/notification.go b/internal/rpc/group/notification.go index cfa62c85db..a9abb03e6a 100644 --- a/internal/rpc/group/notification.go +++ b/internal/rpc/group/notification.go @@ -17,13 +17,13 @@ package group import ( "context" "fmt" - "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model" - "github.com/openimsdk/open-im-server/v3/pkg/rpcclient/notification" "github.com/openimsdk/open-im-server/v3/pkg/authverify" "github.com/openimsdk/open-im-server/v3/pkg/common/servererrs" "github.com/openimsdk/open-im-server/v3/pkg/common/storage/controller" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" + "github.com/openimsdk/open-im-server/v3/pkg/rpcclient/notification" "github.com/openimsdk/protocol/constant" pbgroup "github.com/openimsdk/protocol/group" "github.com/openimsdk/protocol/sdkws" @@ -34,6 +34,12 @@ import ( "github.com/openimsdk/tools/utils/stringutil" ) +// GroupApplicationReceiver +const ( + applicantReceiver = iota + adminReceiver +) + func NewGroupNotificationSender(db controller.GroupDatabase, msgRpcClient *rpcclient.MessageRpcClient, userRpcClient *rpcclient.UserRpcClient, config *Config, fn func(ctx context.Context, userIDs []string) ([]notification.CommonUser, error)) *GroupNotificationSender { return &GroupNotificationSender{ NotificationSender: rpcclient.NewNotificationSender(&config.NotificationConfig, rpcclient.WithRpcClient(msgRpcClient), rpcclient.WithUserRpcClient(userRpcClient)), @@ -400,15 +406,17 @@ func (g *GroupNotificationSender) GroupApplicationAcceptedNotification(ctx conte if err != nil { return } - tips := &sdkws.GroupApplicationAcceptedTips{Group: group, HandleMsg: req.HandledMsg} - if err = g.fillOpUser(ctx, &tips.OpUser, tips.Group.GroupID); err != nil { + + var opUser *sdkws.GroupMemberFullInfo + if err = g.fillOpUser(ctx, &opUser, group.GroupID); err != nil { return } for _, userID := range append(userIDs, req.FromUserID) { + tips := &sdkws.GroupApplicationAcceptedTips{Group: group, OpUser: opUser, HandleMsg: req.HandledMsg} if userID == req.FromUserID { - tips.ReceiverAs = 0 + tips.ReceiverAs = applicantReceiver } else { - tips.ReceiverAs = 1 + tips.ReceiverAs = adminReceiver } g.Notification(ctx, mcontext.GetOpUserID(ctx), userID, constant.GroupApplicationAcceptedNotification, tips) } @@ -431,15 +439,17 @@ func (g *GroupNotificationSender) GroupApplicationRejectedNotification(ctx conte if err != nil { return } - tips := &sdkws.GroupApplicationRejectedTips{Group: group, HandleMsg: req.HandledMsg} - if err = g.fillOpUser(ctx, &tips.OpUser, tips.Group.GroupID); err != nil { + + var opUser *sdkws.GroupMemberFullInfo + if err = g.fillOpUser(ctx, &opUser, group.GroupID); err != nil { return } for _, userID := range append(userIDs, req.FromUserID) { + tips := &sdkws.GroupApplicationAcceptedTips{Group: group, OpUser: opUser, HandleMsg: req.HandledMsg} if userID == req.FromUserID { - tips.ReceiverAs = 0 + tips.ReceiverAs = applicantReceiver } else { - tips.ReceiverAs = 1 + tips.ReceiverAs = adminReceiver } g.Notification(ctx, mcontext.GetOpUserID(ctx), userID, constant.GroupApplicationRejectedNotification, tips) } From 88c0d5f5adb03fc2856d886a4763f6fe17d157d2 Mon Sep 17 00:00:00 2001 From: chao <48119764+withchao@users.noreply.github.com> Date: Mon, 1 Jul 2024 17:38:14 +0800 Subject: [PATCH 188/188] feat: support incremental synchronization (#2379) * fix: GroupApplicationAcceptedNotification * fix: GroupApplicationAcceptedNotification * fix: NotificationUserInfoUpdate * cicd: robot automated Change * fix: component * fix: getConversationInfo * feat: cron task * feat: cron task * feat: cron task * feat: cron task * feat: cron task * fix: minio config url recognition error * new mongo * new mongo * new mongo * new mongo * new mongo * new mongo * new mongo * new mongo * friend incr sync * friend incr sync * friend incr sync * friend incr sync * friend incr sync * mage * optimization version log * optimization version log * sync * sync * sync * group sync * sync option * sync option * refactor: replace `friend` package with `realtion`. * refactor: update lastest commit to relation. * sync option * sync option * sync option * sync * sync * go.mod * update: go mod * refactor: change incremental to full * feat: get full friend user ids * feat: api and config * group version * merge * fix: sort by id avoid unstable sort friends. * group * group * group * fix: sort by id avoid unstable sort friends. * fix: sort by id avoid unstable sort friends. * fix: sort by id avoid unstable sort friends. * user version * fix: sort by id avoid unstable sort friends. * test: test log add. * test: debug log remove. * fix: transfer group owner incr version more than 1. * fix: add condition to kick owner. * feat: replace resp nil * feat: replace nil * fix: delete cache of max group joined version avoid sync joined group failed. * fix: nil * fix: delete cache of max group joined version avoid sync joined group failed. * fix: delete cache of max group joined version avoid sync joined group failed. * return group information for any changes * online cache --------- Co-authored-by: withchao Co-authored-by: Monet Lee Co-authored-by: OpenIM-Gordon <46924906+FGadvancer@users.noreply.github.com> Co-authored-by: icey-yu <1186114839@qq.com> --- config/redis.yml | 2 +- go.mod | 6 +- go.sum | 8 +- internal/api/friend.go | 50 ++-- internal/api/group.go | 62 ++++ internal/api/router.go | 13 +- internal/push/push_handler.go | 2 +- internal/rpc/friend/black.go | 21 +- internal/rpc/friend/callback.go | 24 +- internal/rpc/friend/friend.go | 145 ++++++---- internal/rpc/friend/notification.go | 15 +- internal/rpc/friend/sync.go | 78 ++++++ internal/rpc/group/convert.go | 4 + internal/rpc/group/group.go | 85 ++++-- internal/rpc/group/notification.go | 42 ++- internal/rpc/group/sync.go | 149 ++++++++++ internal/rpc/incrversion/option.go | 156 +++++++++++ internal/rpc/msg/seq.go | 4 +- internal/rpc/user/user.go | 107 +++++-- pkg/common/cmd/group.go | 3 +- pkg/common/cmd/msg_gateway_test.go | 7 + pkg/common/convert/user.go | 28 +- pkg/common/storage/cache/cachekey/friend.go | 10 + pkg/common/storage/cache/cachekey/group.go | 10 + pkg/common/storage/cache/friend.go | 12 + pkg/common/storage/cache/group.go | 9 +- pkg/common/storage/cache/redis/friend.go | 60 +++- pkg/common/storage/cache/redis/group.go | 93 ++++-- pkg/common/storage/controller/friend.go | 55 +++- pkg/common/storage/controller/group.go | 149 +++++++--- pkg/common/storage/controller/user.go | 6 + pkg/common/storage/database/friend.go | 11 + pkg/common/storage/database/group.go | 4 + pkg/common/storage/database/group_member.go | 5 + pkg/common/storage/database/mgo/black.go | 2 +- .../storage/database/mgo/conversation.go | 3 +- pkg/common/storage/database/mgo/friend.go | 138 +++++++-- .../storage/database/mgo/friend_request.go | 2 +- pkg/common/storage/database/mgo/group.go | 35 ++- .../storage/database/mgo/group_member.go | 127 +++++++-- .../storage/database/mgo/group_request.go | 2 +- pkg/common/storage/database/mgo/log.go | 2 +- pkg/common/storage/database/mgo/object.go | 2 +- pkg/common/storage/database/mgo/user.go | 68 ++++- .../storage/database/mgo/version_log.go | 265 ++++++++++++++++++ .../storage/database/mgo/version_test.go | 39 +++ pkg/common/storage/database/name.go | 17 ++ pkg/common/storage/database/user.go | 3 + pkg/common/storage/database/version_log.go | 19 ++ pkg/common/storage/model/friend.go | 18 +- pkg/common/storage/model/user.go | 4 +- pkg/common/storage/model/version_log.go | 69 +++++ pkg/common/storage/versionctx/rpc.go | 14 + pkg/common/storage/versionctx/version.go | 48 ++++ pkg/rpcclient/friend.go | 20 +- pkg/util/hashutil/id.go | 16 ++ 56 files changed, 2023 insertions(+), 325 deletions(-) create mode 100644 internal/rpc/friend/sync.go create mode 100644 internal/rpc/group/sync.go create mode 100644 internal/rpc/incrversion/option.go create mode 100644 pkg/common/storage/database/mgo/version_log.go create mode 100644 pkg/common/storage/database/mgo/version_test.go create mode 100644 pkg/common/storage/database/name.go create mode 100644 pkg/common/storage/database/version_log.go create mode 100644 pkg/common/storage/model/version_log.go create mode 100644 pkg/common/storage/versionctx/rpc.go create mode 100644 pkg/common/storage/versionctx/version.go create mode 100644 pkg/util/hashutil/id.go diff --git a/config/redis.yml b/config/redis.yml index 6fe0dd02d4..87abed0e1c 100644 --- a/config/redis.yml +++ b/config/redis.yml @@ -3,4 +3,4 @@ username: '' password: openIM123 clusterMode: false db: 0 -maxRetry: 10 \ No newline at end of file +maxRetry: 10 diff --git a/go.mod b/go.mod index 5e17e866cd..245214b932 100644 --- a/go.mod +++ b/go.mod @@ -13,8 +13,8 @@ require ( github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible // indirect github.com/mitchellh/mapstructure v1.5.0 - github.com/openimsdk/protocol v0.0.66-alpha.1 - github.com/openimsdk/tools v0.0.49-alpha.19 + github.com/openimsdk/protocol v0.0.69-alpha.17 + github.com/openimsdk/tools v0.0.49-alpha.28 github.com/pkg/errors v0.9.1 // indirect github.com/prometheus/client_golang v1.18.0 github.com/stretchr/testify v1.9.0 @@ -176,3 +176,5 @@ require ( golang.org/x/crypto v0.21.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect ) + +//replace github.com/openimsdk/protocol => /Users/chao/Desktop/project/protocol diff --git a/go.sum b/go.sum index 7c5e024495..664f2366a7 100644 --- a/go.sum +++ b/go.sum @@ -270,10 +270,10 @@ github.com/onsi/gomega v1.25.0 h1:Vw7br2PCDYijJHSfBOWhov+8cAnUf8MfMaIOV323l6Y= github.com/onsi/gomega v1.25.0/go.mod h1:r+zV744Re+DiYCIPRlYOTxn0YkOLcAnW8k1xXdMPGhM= github.com/openimsdk/gomake v0.0.13 h1:xLDe/moqgWpRoptHzI4packAWzs4C16b+sVY+txNJp0= github.com/openimsdk/gomake v0.0.13/go.mod h1:PndCozNc2IsQIciyn9mvEblYWZwJmAI+06z94EY+csI= -github.com/openimsdk/protocol v0.0.66-alpha.1 h1:/8y+aXQeX6+IgfFxujHbRgJylqJRkwF5gMrwNhWMsiU= -github.com/openimsdk/protocol v0.0.66-alpha.1/go.mod h1:OZQA9FR55lseYoN2Ql1XAHYKHJGu7OMNkUbuekrKCM8= -github.com/openimsdk/tools v0.0.49-alpha.19 h1:CbASL0yefRSVAmWPVeRnhF7wZKd6umLfz31CIhEgrBs= -github.com/openimsdk/tools v0.0.49-alpha.19/go.mod h1:g7mkHXYUPi0/8aAX8VPMHpnb3hqdV69Jph+bXOGvvNM= +github.com/openimsdk/protocol v0.0.69-alpha.17 h1:pEag4ZdlovE+AyLsw1VYFU/3sk6ayvGdPzgufQfKf9M= +github.com/openimsdk/protocol v0.0.69-alpha.17/go.mod h1:OZQA9FR55lseYoN2Ql1XAHYKHJGu7OMNkUbuekrKCM8= +github.com/openimsdk/tools v0.0.49-alpha.28 h1:1CfdFxvKzyOIvgNMVMq4ZB2upAJ0evLbbigOhWQzhu8= +github.com/openimsdk/tools v0.0.49-alpha.28/go.mod h1:rwsFI1G/nBHNfiNapbven41akRDPBbH4df0Cgy6xueU= 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/pierrec/lz4/v4 v4.1.21 h1:yOVMLb6qSIDP67pl/5F7RepeKYu/VmTyEXvuMI5d9mQ= diff --git a/internal/api/friend.go b/internal/api/friend.go index 1fea38b313..11d7375fa3 100644 --- a/internal/api/friend.go +++ b/internal/api/friend.go @@ -17,7 +17,7 @@ package api import ( "github.com/gin-gonic/gin" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" - "github.com/openimsdk/protocol/friend" + "github.com/openimsdk/protocol/relation" "github.com/openimsdk/tools/a2r" ) @@ -28,68 +28,82 @@ func NewFriendApi(client rpcclient.Friend) FriendApi { } func (o *FriendApi) ApplyToAddFriend(c *gin.Context) { - a2r.Call(friend.FriendClient.ApplyToAddFriend, o.Client, c) + a2r.Call(relation.FriendClient.ApplyToAddFriend, o.Client, c) } func (o *FriendApi) RespondFriendApply(c *gin.Context) { - a2r.Call(friend.FriendClient.RespondFriendApply, o.Client, c) + a2r.Call(relation.FriendClient.RespondFriendApply, o.Client, c) } func (o *FriendApi) DeleteFriend(c *gin.Context) { - a2r.Call(friend.FriendClient.DeleteFriend, o.Client, c) + a2r.Call(relation.FriendClient.DeleteFriend, o.Client, c) } func (o *FriendApi) GetFriendApplyList(c *gin.Context) { - a2r.Call(friend.FriendClient.GetPaginationFriendsApplyTo, o.Client, c) + a2r.Call(relation.FriendClient.GetPaginationFriendsApplyTo, o.Client, c) } func (o *FriendApi) GetDesignatedFriendsApply(c *gin.Context) { - a2r.Call(friend.FriendClient.GetDesignatedFriendsApply, o.Client, c) + a2r.Call(relation.FriendClient.GetDesignatedFriendsApply, o.Client, c) } func (o *FriendApi) GetSelfApplyList(c *gin.Context) { - a2r.Call(friend.FriendClient.GetPaginationFriendsApplyFrom, o.Client, c) + a2r.Call(relation.FriendClient.GetPaginationFriendsApplyFrom, o.Client, c) } func (o *FriendApi) GetFriendList(c *gin.Context) { - a2r.Call(friend.FriendClient.GetPaginationFriends, o.Client, c) + a2r.Call(relation.FriendClient.GetPaginationFriends, o.Client, c) } func (o *FriendApi) GetDesignatedFriends(c *gin.Context) { - a2r.Call(friend.FriendClient.GetDesignatedFriends, o.Client, c) + a2r.Call(relation.FriendClient.GetDesignatedFriends, o.Client, c) + //a2r.Call(relation.FriendClient.GetDesignatedFriends, o.Client, c, a2r.NewNilReplaceOption(relation.FriendClient.GetDesignatedFriends)) } func (o *FriendApi) SetFriendRemark(c *gin.Context) { - a2r.Call(friend.FriendClient.SetFriendRemark, o.Client, c) + a2r.Call(relation.FriendClient.SetFriendRemark, o.Client, c) } func (o *FriendApi) AddBlack(c *gin.Context) { - a2r.Call(friend.FriendClient.AddBlack, o.Client, c) + a2r.Call(relation.FriendClient.AddBlack, o.Client, c) } func (o *FriendApi) GetPaginationBlacks(c *gin.Context) { - a2r.Call(friend.FriendClient.GetPaginationBlacks, o.Client, c) + a2r.Call(relation.FriendClient.GetPaginationBlacks, o.Client, c) } func (o *FriendApi) RemoveBlack(c *gin.Context) { - a2r.Call(friend.FriendClient.RemoveBlack, o.Client, c) + a2r.Call(relation.FriendClient.RemoveBlack, o.Client, c) } func (o *FriendApi) ImportFriends(c *gin.Context) { - a2r.Call(friend.FriendClient.ImportFriends, o.Client, c) + a2r.Call(relation.FriendClient.ImportFriends, o.Client, c) } func (o *FriendApi) IsFriend(c *gin.Context) { - a2r.Call(friend.FriendClient.IsFriend, o.Client, c) + a2r.Call(relation.FriendClient.IsFriend, o.Client, c) } func (o *FriendApi) GetFriendIDs(c *gin.Context) { - a2r.Call(friend.FriendClient.GetFriendIDs, o.Client, c) + a2r.Call(relation.FriendClient.GetFriendIDs, o.Client, c) } func (o *FriendApi) GetSpecifiedFriendsInfo(c *gin.Context) { - a2r.Call(friend.FriendClient.GetSpecifiedFriendsInfo, o.Client, c) + a2r.Call(relation.FriendClient.GetSpecifiedFriendsInfo, o.Client, c) } + func (o *FriendApi) UpdateFriends(c *gin.Context) { - a2r.Call(friend.FriendClient.UpdateFriends, o.Client, c) + a2r.Call(relation.FriendClient.UpdateFriends, o.Client, c) +} + +func (o *FriendApi) GetIncrementalFriends(c *gin.Context) { + a2r.Call(relation.FriendClient.GetIncrementalFriends, o.Client, c) +} + +func (o *FriendApi) GetIncrementalBlacks(c *gin.Context) { + a2r.Call(relation.FriendClient.GetIncrementalBlacks, o.Client, c) +} + +func (o *FriendApi) GetFullFriendUserIDs(c *gin.Context) { + a2r.Call(relation.FriendClient.GetFullFriendUserIDs, o.Client, c) } diff --git a/internal/api/group.go b/internal/api/group.go index 6079c53437..e48191ee15 100644 --- a/internal/api/group.go +++ b/internal/api/group.go @@ -19,6 +19,8 @@ import ( "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" "github.com/openimsdk/protocol/group" "github.com/openimsdk/tools/a2r" + "github.com/openimsdk/tools/apiresp" + "github.com/openimsdk/tools/log" ) type GroupApi rpcclient.Group @@ -65,6 +67,7 @@ func (o *GroupApi) GetGroupUsersReqApplicationList(c *gin.Context) { func (o *GroupApi) GetGroupsInfo(c *gin.Context) { a2r.Call(group.GroupClient.GetGroupsInfo, o.Client, c) + //a2r.Call(group.GroupClient.GetGroupsInfo, o.Client, c, a2r.NewNilReplaceOption(group.GroupClient.GetGroupsInfo)) } func (o *GroupApi) KickGroupMember(c *gin.Context) { @@ -73,6 +76,7 @@ func (o *GroupApi) KickGroupMember(c *gin.Context) { func (o *GroupApi) GetGroupMembersInfo(c *gin.Context) { a2r.Call(group.GroupClient.GetGroupMembersInfo, o.Client, c) + //a2r.Call(group.GroupClient.GetGroupMembersInfo, o.Client, c, a2r.NewNilReplaceOption(group.GroupClient.GetGroupMembersInfo)) } func (o *GroupApi) GetGroupMemberList(c *gin.Context) { @@ -134,3 +138,61 @@ func (o *GroupApi) GetGroups(c *gin.Context) { func (o *GroupApi) GetGroupMemberUserIDs(c *gin.Context) { a2r.Call(group.GroupClient.GetGroupMemberUserIDs, o.Client, c) } + +func (o *GroupApi) GetIncrementalJoinGroup(c *gin.Context) { + a2r.Call(group.GroupClient.GetIncrementalJoinGroup, o.Client, c) +} + +func (o *GroupApi) GetIncrementalGroupMember(c *gin.Context) { + a2r.Call(group.GroupClient.GetIncrementalGroupMember, o.Client, c) +} + +func (o *GroupApi) GetIncrementalGroupMemberBatch(c *gin.Context) { + type BatchIncrementalReq struct { + UserID string `json:"user_id"` + List []*group.GetIncrementalGroupMemberReq `json:"list"` + } + type BatchIncrementalResp struct { + List map[string]*group.GetIncrementalGroupMemberResp `json:"list"` + } + req, err := a2r.ParseRequestNotCheck[BatchIncrementalReq](c) + if err != nil { + apiresp.GinError(c, err) + return + } + resp := &BatchIncrementalResp{ + List: make(map[string]*group.GetIncrementalGroupMemberResp), + } + var ( + changeCount int + ) + for _, req := range req.List { + if _, ok := resp.List[req.GroupID]; ok { + continue + } + res, err := o.Client.GetIncrementalGroupMember(c, req) + if err != nil { + if len(resp.List) == 0 { + apiresp.GinError(c, err) + } else { + log.ZError(c, "group incr sync versopn", err, "groupID", req.GroupID, "success", len(resp.List)) + apiresp.GinSuccess(c, resp) + } + return + } + resp.List[req.GroupID] = res + changeCount += len(res.Insert) + len(res.Delete) + len(res.Update) + if changeCount >= 200 { + break + } + } + apiresp.GinSuccess(c, resp) +} + +func (o *GroupApi) GetFullGroupMemberUserIDs(c *gin.Context) { + a2r.Call(group.GroupClient.GetFullGroupMemberUserIDs, o.Client, c) +} + +func (o *GroupApi) GetFullJoinGroupIDs(c *gin.Context) { + a2r.Call(group.GroupClient.GetFullJoinGroupIDs, o.Client, c) +} diff --git a/internal/api/router.go b/internal/api/router.go index 6005671785..0f46f26baf 100644 --- a/internal/api/router.go +++ b/internal/api/router.go @@ -2,6 +2,9 @@ package api import ( "fmt" + "net/http" + "strings" + "github.com/gin-gonic/gin" "github.com/gin-gonic/gin/binding" "github.com/go-playground/validator/v10" @@ -14,8 +17,6 @@ import ( "github.com/openimsdk/tools/mw" "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" - "net/http" - "strings" ) func newGinRouter(disCov discovery.SvcDiscoveryRegistry, config *Config) *gin.Engine { @@ -81,11 +82,14 @@ func newGinRouter(disCov discovery.SvcDiscoveryRegistry, config *Config) *gin.En friendRouterGroup.POST("/add_black", f.AddBlack) friendRouterGroup.POST("/get_black_list", f.GetPaginationBlacks) friendRouterGroup.POST("/remove_black", f.RemoveBlack) + friendRouterGroup.POST("/get_incremental_blacks", f.GetIncrementalBlacks) friendRouterGroup.POST("/import_friend", f.ImportFriends) friendRouterGroup.POST("/is_friend", f.IsFriend) friendRouterGroup.POST("/get_friend_id", f.GetFriendIDs) friendRouterGroup.POST("/get_specified_friends_info", f.GetSpecifiedFriendsInfo) friendRouterGroup.POST("/update_friends", f.UpdateFriends) + friendRouterGroup.POST("/get_incremental_friends", f.GetIncrementalFriends) + friendRouterGroup.POST("/get_full_friend_user_ids", f.GetFullFriendUserIDs) } g := NewGroupApi(*groupRpc) groupRouterGroup := r.Group("/group") @@ -114,6 +118,11 @@ func newGinRouter(disCov discovery.SvcDiscoveryRegistry, config *Config) *gin.En groupRouterGroup.POST("/get_group_abstract_info", g.GetGroupAbstractInfo) groupRouterGroup.POST("/get_groups", g.GetGroups) groupRouterGroup.POST("/get_group_member_user_id", g.GetGroupMemberUserIDs) + groupRouterGroup.POST("/get_incremental_join_group", g.GetIncrementalJoinGroup) + groupRouterGroup.POST("/get_incremental_group_member", g.GetIncrementalGroupMember) + groupRouterGroup.POST("/get_incremental_group_member_batch", g.GetIncrementalGroupMemberBatch) + groupRouterGroup.POST("/get_full_group_member_user_ids", g.GetFullGroupMemberUserIDs) + groupRouterGroup.POST("/get_full_join_group_ids", g.GetFullJoinGroupIDs) } // certificate authRouterGroup := r.Group("/auth") diff --git a/internal/push/push_handler.go b/internal/push/push_handler.go index 03c299b7ab..dfe0e7b55d 100644 --- a/internal/push/push_handler.go +++ b/internal/push/push_handler.go @@ -180,7 +180,7 @@ func (c *ConsumerHandler) shouldPushOffline(_ context.Context, msg *sdkws.MsgDat } func (c *ConsumerHandler) Push2Group(ctx context.Context, groupID string, msg *sdkws.MsgData) (err error) { - log.ZDebug(ctx, "Get super group msg from msg_transfer and push msg", "msg", msg.String(), "groupID", groupID) + log.ZDebug(ctx, "Get group msg from msg_transfer and push msg", "msg", msg.String(), "groupID", groupID) var pushToUserIDs []string if err = c.webhookBeforeGroupOnlinePush(ctx, &c.config.WebhooksConfig.BeforeGroupOnlinePush, groupID, msg, &pushToUserIDs); err != nil { diff --git a/internal/rpc/friend/black.go b/internal/rpc/friend/black.go index caec08b7ac..218d1e7f85 100644 --- a/internal/rpc/friend/black.go +++ b/internal/rpc/friend/black.go @@ -16,16 +16,17 @@ package friend import ( "context" - "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model" "time" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model" + "github.com/openimsdk/open-im-server/v3/pkg/authverify" "github.com/openimsdk/open-im-server/v3/pkg/common/convert" - pbfriend "github.com/openimsdk/protocol/friend" + "github.com/openimsdk/protocol/relation" "github.com/openimsdk/tools/mcontext" ) -func (s *friendServer) GetPaginationBlacks(ctx context.Context, req *pbfriend.GetPaginationBlacksReq) (resp *pbfriend.GetPaginationBlacksResp, err error) { +func (s *friendServer) GetPaginationBlacks(ctx context.Context, req *relation.GetPaginationBlacksReq) (resp *relation.GetPaginationBlacksResp, err error) { if err := s.userRpcClient.Access(ctx, req.UserID); err != nil { return nil, err } @@ -33,7 +34,7 @@ func (s *friendServer) GetPaginationBlacks(ctx context.Context, req *pbfriend.Ge if err != nil { return nil, err } - resp = &pbfriend.GetPaginationBlacksResp{} + resp = &relation.GetPaginationBlacksResp{} resp.Blacks, err = convert.BlackDB2Pb(ctx, blacks, s.userRpcClient.GetUsersInfoMap) if err != nil { return nil, err @@ -42,18 +43,18 @@ func (s *friendServer) GetPaginationBlacks(ctx context.Context, req *pbfriend.Ge return resp, nil } -func (s *friendServer) IsBlack(ctx context.Context, req *pbfriend.IsBlackReq) (*pbfriend.IsBlackResp, error) { +func (s *friendServer) IsBlack(ctx context.Context, req *relation.IsBlackReq) (*relation.IsBlackResp, error) { in1, in2, err := s.blackDatabase.CheckIn(ctx, req.UserID1, req.UserID2) if err != nil { return nil, err } - resp := &pbfriend.IsBlackResp{} + resp := &relation.IsBlackResp{} resp.InUser1Blacks = in1 resp.InUser2Blacks = in2 return resp, nil } -func (s *friendServer) RemoveBlack(ctx context.Context, req *pbfriend.RemoveBlackReq) (*pbfriend.RemoveBlackResp, error) { +func (s *friendServer) RemoveBlack(ctx context.Context, req *relation.RemoveBlackReq) (*relation.RemoveBlackResp, error) { if err := s.userRpcClient.Access(ctx, req.OwnerUserID); err != nil { return nil, err } @@ -64,10 +65,10 @@ func (s *friendServer) RemoveBlack(ctx context.Context, req *pbfriend.RemoveBlac s.notificationSender.BlackDeletedNotification(ctx, req) - return &pbfriend.RemoveBlackResp{}, nil + return &relation.RemoveBlackResp{}, nil } -func (s *friendServer) AddBlack(ctx context.Context, req *pbfriend.AddBlackReq) (*pbfriend.AddBlackResp, error) { +func (s *friendServer) AddBlack(ctx context.Context, req *relation.AddBlackReq) (*relation.AddBlackResp, error) { if err := authverify.CheckAccessV3(ctx, req.OwnerUserID, s.config.Share.IMAdminUserID); err != nil { return nil, err } @@ -87,5 +88,5 @@ func (s *friendServer) AddBlack(ctx context.Context, req *pbfriend.AddBlackReq) return nil, err } s.notificationSender.BlackAddedNotification(ctx, req) - return &pbfriend.AddBlackResp{}, nil + return &relation.AddBlackResp{}, nil } diff --git a/internal/rpc/friend/callback.go b/internal/rpc/friend/callback.go index 0610cdb78a..746ad21fa1 100644 --- a/internal/rpc/friend/callback.go +++ b/internal/rpc/friend/callback.go @@ -16,14 +16,15 @@ package friend import ( "context" + "github.com/openimsdk/open-im-server/v3/pkg/common/webhook" cbapi "github.com/openimsdk/open-im-server/v3/pkg/callbackstruct" "github.com/openimsdk/open-im-server/v3/pkg/common/config" - pbfriend "github.com/openimsdk/protocol/friend" + "github.com/openimsdk/protocol/relation" ) -func (s *friendServer) webhookAfterDeleteFriend(ctx context.Context, after *config.AfterConfig, req *pbfriend.DeleteFriendReq) { +func (s *friendServer) webhookAfterDeleteFriend(ctx context.Context, after *config.AfterConfig, req *relation.DeleteFriendReq) { cbReq := &cbapi.CallbackAfterDeleteFriendReq{ CallbackCommand: cbapi.CallbackAfterDeleteFriendCommand, OwnerUserID: req.OwnerUserID, @@ -32,7 +33,7 @@ func (s *friendServer) webhookAfterDeleteFriend(ctx context.Context, after *conf s.webhookClient.AsyncPost(ctx, cbReq.GetCallbackCommand(), cbReq, &cbapi.CallbackAfterDeleteFriendResp{}, after) } -func (s *friendServer) webhookBeforeAddFriend(ctx context.Context, before *config.BeforeConfig, req *pbfriend.ApplyToAddFriendReq) error { +func (s *friendServer) webhookBeforeAddFriend(ctx context.Context, before *config.BeforeConfig, req *relation.ApplyToAddFriendReq) error { return webhook.WithCondition(ctx, before, func(ctx context.Context) error { cbReq := &cbapi.CallbackBeforeAddFriendReq{ CallbackCommand: cbapi.CallbackBeforeAddFriendCommand, @@ -50,7 +51,7 @@ func (s *friendServer) webhookBeforeAddFriend(ctx context.Context, before *confi }) } -func (s *friendServer) webhookAfterAddFriend(ctx context.Context, after *config.AfterConfig, req *pbfriend.ApplyToAddFriendReq) { +func (s *friendServer) webhookAfterAddFriend(ctx context.Context, after *config.AfterConfig, req *relation.ApplyToAddFriendReq) { cbReq := &cbapi.CallbackAfterAddFriendReq{ CallbackCommand: cbapi.CallbackAfterAddFriendCommand, FromUserID: req.FromUserID, @@ -61,8 +62,7 @@ func (s *friendServer) webhookAfterAddFriend(ctx context.Context, after *config. s.webhookClient.AsyncPost(ctx, cbReq.GetCallbackCommand(), cbReq, resp, after) } -func (s *friendServer) webhookAfterSetFriendRemark(ctx context.Context, after *config.AfterConfig, req *pbfriend.SetFriendRemarkReq) { - +func (s *friendServer) webhookAfterSetFriendRemark(ctx context.Context, after *config.AfterConfig, req *relation.SetFriendRemarkReq) { cbReq := &cbapi.CallbackAfterSetFriendRemarkReq{ CallbackCommand: cbapi.CallbackAfterSetFriendRemarkCommand, OwnerUserID: req.OwnerUserID, @@ -73,7 +73,7 @@ func (s *friendServer) webhookAfterSetFriendRemark(ctx context.Context, after *c s.webhookClient.AsyncPost(ctx, cbReq.GetCallbackCommand(), cbReq, resp, after) } -func (s *friendServer) webhookAfterImportFriends(ctx context.Context, after *config.AfterConfig, req *pbfriend.ImportFriendReq) { +func (s *friendServer) webhookAfterImportFriends(ctx context.Context, after *config.AfterConfig, req *relation.ImportFriendReq) { cbReq := &cbapi.CallbackAfterImportFriendsReq{ CallbackCommand: cbapi.CallbackAfterImportFriendsCommand, OwnerUserID: req.OwnerUserID, @@ -83,7 +83,7 @@ func (s *friendServer) webhookAfterImportFriends(ctx context.Context, after *con s.webhookClient.AsyncPost(ctx, cbReq.GetCallbackCommand(), cbReq, resp, after) } -func (s *friendServer) webhookAfterRemoveBlack(ctx context.Context, after *config.AfterConfig, req *pbfriend.RemoveBlackReq) { +func (s *friendServer) webhookAfterRemoveBlack(ctx context.Context, after *config.AfterConfig, req *relation.RemoveBlackReq) { cbReq := &cbapi.CallbackAfterRemoveBlackReq{ CallbackCommand: cbapi.CallbackAfterRemoveBlackCommand, OwnerUserID: req.OwnerUserID, @@ -93,7 +93,7 @@ func (s *friendServer) webhookAfterRemoveBlack(ctx context.Context, after *confi s.webhookClient.AsyncPost(ctx, cbReq.GetCallbackCommand(), cbReq, resp, after) } -func (s *friendServer) webhookBeforeSetFriendRemark(ctx context.Context, before *config.BeforeConfig, req *pbfriend.SetFriendRemarkReq) error { +func (s *friendServer) webhookBeforeSetFriendRemark(ctx context.Context, before *config.BeforeConfig, req *relation.SetFriendRemarkReq) error { return webhook.WithCondition(ctx, before, func(ctx context.Context) error { cbReq := &cbapi.CallbackBeforeSetFriendRemarkReq{ CallbackCommand: cbapi.CallbackBeforeSetFriendRemarkCommand, @@ -112,7 +112,7 @@ func (s *friendServer) webhookBeforeSetFriendRemark(ctx context.Context, before }) } -func (s *friendServer) webhookBeforeAddBlack(ctx context.Context, before *config.BeforeConfig, req *pbfriend.AddBlackReq) error { +func (s *friendServer) webhookBeforeAddBlack(ctx context.Context, before *config.BeforeConfig, req *relation.AddBlackReq) error { return webhook.WithCondition(ctx, before, func(ctx context.Context) error { cbReq := &cbapi.CallbackBeforeAddBlackReq{ CallbackCommand: cbapi.CallbackBeforeAddBlackCommand, @@ -124,7 +124,7 @@ func (s *friendServer) webhookBeforeAddBlack(ctx context.Context, before *config }) } -func (s *friendServer) webhookBeforeAddFriendAgree(ctx context.Context, before *config.BeforeConfig, req *pbfriend.RespondFriendApplyReq) error { +func (s *friendServer) webhookBeforeAddFriendAgree(ctx context.Context, before *config.BeforeConfig, req *relation.RespondFriendApplyReq) error { return webhook.WithCondition(ctx, before, func(ctx context.Context) error { cbReq := &cbapi.CallbackBeforeAddFriendAgreeReq{ CallbackCommand: cbapi.CallbackBeforeAddFriendAgreeCommand, @@ -138,7 +138,7 @@ func (s *friendServer) webhookBeforeAddFriendAgree(ctx context.Context, before * }) } -func (s *friendServer) webhookBeforeImportFriends(ctx context.Context, before *config.BeforeConfig, req *pbfriend.ImportFriendReq) error { +func (s *friendServer) webhookBeforeImportFriends(ctx context.Context, before *config.BeforeConfig, req *relation.ImportFriendReq) error { return webhook.WithCondition(ctx, before, func(ctx context.Context) error { cbReq := &cbapi.CallbackBeforeImportFriendsReq{ CallbackCommand: cbapi.CallbackBeforeImportFriendsCommand, diff --git a/internal/rpc/friend/friend.go b/internal/rpc/friend/friend.go index 8b2dea995f..622e19f422 100644 --- a/internal/rpc/friend/friend.go +++ b/internal/rpc/friend/friend.go @@ -16,6 +16,7 @@ package friend import ( "context" + "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/storage/cache/redis" "github.com/openimsdk/open-im-server/v3/pkg/common/storage/database/mgo" @@ -30,7 +31,7 @@ import ( "github.com/openimsdk/open-im-server/v3/pkg/common/storage/controller" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" "github.com/openimsdk/protocol/constant" - pbfriend "github.com/openimsdk/protocol/friend" + "github.com/openimsdk/protocol/relation" "github.com/openimsdk/protocol/sdkws" "github.com/openimsdk/tools/db/mongoutil" "github.com/openimsdk/tools/discovery" @@ -40,7 +41,7 @@ import ( ) type friendServer struct { - friendDatabase controller.FriendDatabase + db controller.FriendDatabase blackDatabase controller.BlackDatabase userRpcClient *rpcclient.UserRpcClient notificationSender *FriendNotificationSender @@ -54,7 +55,7 @@ type Config struct { RpcConfig config.Friend RedisConfig config.Redis MongodbConfig config.Mongo - //ZookeeperConfig config.ZooKeeper + // ZookeeperConfig config.ZooKeeper NotificationConfig config.Notification Share config.Share WebhooksConfig config.Webhooks @@ -100,8 +101,8 @@ func Start(ctx context.Context, config *Config, client discovery.SvcDiscoveryReg localcache.InitLocalCache(&config.LocalCacheConfig) // Register Friend server with refactored MongoDB and Redis integrations - pbfriend.RegisterFriendServer(server, &friendServer{ - friendDatabase: controller.NewFriendDatabase( + relation.RegisterFriendServer(server, &friendServer{ + db: controller.NewFriendDatabase( friendMongoDB, friendRequestMongoDB, redis.NewFriendCacheRedis(rdb, &config.LocalCacheConfig, friendMongoDB, redis.GetRocksCacheOptions()), @@ -123,8 +124,8 @@ func Start(ctx context.Context, config *Config, client discovery.SvcDiscoveryReg } // ok. -func (s *friendServer) ApplyToAddFriend(ctx context.Context, req *pbfriend.ApplyToAddFriendReq) (resp *pbfriend.ApplyToAddFriendResp, err error) { - resp = &pbfriend.ApplyToAddFriendResp{} +func (s *friendServer) ApplyToAddFriend(ctx context.Context, req *relation.ApplyToAddFriendReq) (resp *relation.ApplyToAddFriendResp, err error) { + resp = &relation.ApplyToAddFriendResp{} if err := authverify.CheckAccessV3(ctx, req.FromUserID, s.config.Share.IMAdminUserID); err != nil { return nil, err } @@ -138,14 +139,14 @@ func (s *friendServer) ApplyToAddFriend(ctx context.Context, req *pbfriend.Apply return nil, err } - in1, in2, err := s.friendDatabase.CheckIn(ctx, req.FromUserID, req.ToUserID) + in1, in2, err := s.db.CheckIn(ctx, req.FromUserID, req.ToUserID) if err != nil { return nil, err } if in1 && in2 { return nil, servererrs.ErrRelationshipAlready.WrapMsg("already friends has f") } - if err = s.friendDatabase.AddFriendRequest(ctx, req.FromUserID, req.ToUserID, req.ReqMsg, req.Ex); err != nil { + if err = s.db.AddFriendRequest(ctx, req.FromUserID, req.ToUserID, req.ReqMsg, req.Ex); err != nil { return nil, err } s.notificationSender.FriendApplicationAddNotification(ctx, req) @@ -154,7 +155,7 @@ func (s *friendServer) ApplyToAddFriend(ctx context.Context, req *pbfriend.Apply } // ok. -func (s *friendServer) ImportFriends(ctx context.Context, req *pbfriend.ImportFriendReq) (resp *pbfriend.ImportFriendResp, err error) { +func (s *friendServer) ImportFriends(ctx context.Context, req *relation.ImportFriendReq) (resp *relation.ImportFriendResp, err error) { if err := authverify.CheckAdmin(ctx, s.config.Share.IMAdminUserID); err != nil { return nil, err } @@ -172,11 +173,11 @@ func (s *friendServer) ImportFriends(ctx context.Context, req *pbfriend.ImportFr return nil, err } - if err := s.friendDatabase.BecomeFriends(ctx, req.OwnerUserID, req.FriendUserIDs, constant.BecomeFriendByImport); err != nil { + if err := s.db.BecomeFriends(ctx, req.OwnerUserID, req.FriendUserIDs, constant.BecomeFriendByImport); err != nil { return nil, err } for _, userID := range req.FriendUserIDs { - s.notificationSender.FriendApplicationAgreedNotification(ctx, &pbfriend.RespondFriendApplyReq{ + s.notificationSender.FriendApplicationAgreedNotification(ctx, &relation.RespondFriendApplyReq{ FromUserID: req.OwnerUserID, ToUserID: userID, HandleResult: constant.FriendResponseAgree, @@ -184,12 +185,12 @@ func (s *friendServer) ImportFriends(ctx context.Context, req *pbfriend.ImportFr } s.webhookAfterImportFriends(ctx, &s.config.WebhooksConfig.AfterImportFriends, req) - return &pbfriend.ImportFriendResp{}, nil + return &relation.ImportFriendResp{}, nil } // ok. -func (s *friendServer) RespondFriendApply(ctx context.Context, req *pbfriend.RespondFriendApplyReq) (resp *pbfriend.RespondFriendApplyResp, err error) { - resp = &pbfriend.RespondFriendApplyResp{} +func (s *friendServer) RespondFriendApply(ctx context.Context, req *relation.RespondFriendApplyReq) (resp *relation.RespondFriendApplyResp, err error) { + resp = &relation.RespondFriendApplyResp{} if err := authverify.CheckAccessV3(ctx, req.ToUserID, s.config.Share.IMAdminUserID); err != nil { return nil, err } @@ -204,7 +205,7 @@ func (s *friendServer) RespondFriendApply(ctx context.Context, req *pbfriend.Res if err := s.webhookBeforeAddFriendAgree(ctx, &s.config.WebhooksConfig.BeforeAddFriendAgree, req); err != nil && err != servererrs.ErrCallbackContinue { return nil, err } - err := s.friendDatabase.AgreeFriendRequest(ctx, &friendRequest) + err := s.db.AgreeFriendRequest(ctx, &friendRequest) if err != nil { return nil, err } @@ -212,7 +213,7 @@ func (s *friendServer) RespondFriendApply(ctx context.Context, req *pbfriend.Res return resp, nil } if req.HandleResult == constant.FriendResponseRefuse { - err := s.friendDatabase.RefuseFriendRequest(ctx, &friendRequest) + err := s.db.RefuseFriendRequest(ctx, &friendRequest) if err != nil { return nil, err } @@ -223,16 +224,16 @@ func (s *friendServer) RespondFriendApply(ctx context.Context, req *pbfriend.Res } // ok. -func (s *friendServer) DeleteFriend(ctx context.Context, req *pbfriend.DeleteFriendReq) (resp *pbfriend.DeleteFriendResp, err error) { - resp = &pbfriend.DeleteFriendResp{} +func (s *friendServer) DeleteFriend(ctx context.Context, req *relation.DeleteFriendReq) (resp *relation.DeleteFriendResp, err error) { + resp = &relation.DeleteFriendResp{} if err := s.userRpcClient.Access(ctx, req.OwnerUserID); err != nil { return nil, err } - _, err = s.friendDatabase.FindFriendsWithError(ctx, req.OwnerUserID, []string{req.FriendUserID}) + _, err = s.db.FindFriendsWithError(ctx, req.OwnerUserID, []string{req.FriendUserID}) if err != nil { return nil, err } - if err := s.friendDatabase.Delete(ctx, req.OwnerUserID, []string{req.FriendUserID}); err != nil { + if err := s.db.Delete(ctx, req.OwnerUserID, []string{req.FriendUserID}); err != nil { return nil, err } s.notificationSender.FriendDeletedNotification(ctx, req) @@ -241,19 +242,19 @@ func (s *friendServer) DeleteFriend(ctx context.Context, req *pbfriend.DeleteFri } // ok. -func (s *friendServer) SetFriendRemark(ctx context.Context, req *pbfriend.SetFriendRemarkReq) (resp *pbfriend.SetFriendRemarkResp, err error) { +func (s *friendServer) SetFriendRemark(ctx context.Context, req *relation.SetFriendRemarkReq) (resp *relation.SetFriendRemarkResp, err error) { if err = s.webhookBeforeSetFriendRemark(ctx, &s.config.WebhooksConfig.BeforeSetFriendRemark, req); err != nil && err != servererrs.ErrCallbackContinue { return nil, err } - resp = &pbfriend.SetFriendRemarkResp{} + resp = &relation.SetFriendRemarkResp{} if err := s.userRpcClient.Access(ctx, req.OwnerUserID); err != nil { return nil, err } - _, err = s.friendDatabase.FindFriendsWithError(ctx, req.OwnerUserID, []string{req.FriendUserID}) + _, err = s.db.FindFriendsWithError(ctx, req.OwnerUserID, []string{req.FriendUserID}) if err != nil { return nil, err } - if err := s.friendDatabase.UpdateRemark(ctx, req.OwnerUserID, req.FriendUserID, req.Remark); err != nil { + if err := s.db.UpdateRemark(ctx, req.OwnerUserID, req.FriendUserID, req.Remark); err != nil { return nil, err } s.webhookAfterSetFriendRemark(ctx, &s.config.WebhooksConfig.AfterSetFriendRemark, req) @@ -262,29 +263,40 @@ func (s *friendServer) SetFriendRemark(ctx context.Context, req *pbfriend.SetFri } // ok. -func (s *friendServer) GetDesignatedFriends(ctx context.Context, req *pbfriend.GetDesignatedFriendsReq) (resp *pbfriend.GetDesignatedFriendsResp, err error) { - resp = &pbfriend.GetDesignatedFriendsResp{} +func (s *friendServer) GetDesignatedFriends(ctx context.Context, req *relation.GetDesignatedFriendsReq) (resp *relation.GetDesignatedFriendsResp, err error) { + resp = &relation.GetDesignatedFriendsResp{} if datautil.Duplicate(req.FriendUserIDs) { return nil, errs.ErrArgs.WrapMsg("friend userID repeated") } - friends, err := s.friendDatabase.FindFriendsWithError(ctx, req.OwnerUserID, req.FriendUserIDs) + friends, err := s.getFriend(ctx, req.OwnerUserID, req.FriendUserIDs) if err != nil { return nil, err } - if resp.FriendsInfo, err = convert.FriendsDB2Pb(ctx, friends, s.userRpcClient.GetUsersInfoMap); err != nil { + return &relation.GetDesignatedFriendsResp{ + FriendsInfo: friends, + }, nil +} + +func (s *friendServer) getFriend(ctx context.Context, ownerUserID string, friendUserIDs []string) ([]*sdkws.FriendInfo, error) { + if len(friendUserIDs) == 0 { + return nil, nil + } + friends, err := s.db.FindFriendsWithError(ctx, ownerUserID, friendUserIDs) + if err != nil { return nil, err } - return resp, nil + return convert.FriendsDB2Pb(ctx, friends, s.userRpcClient.GetUsersInfoMap) } // Get the list of friend requests sent out proactively. func (s *friendServer) GetDesignatedFriendsApply(ctx context.Context, - req *pbfriend.GetDesignatedFriendsApplyReq) (resp *pbfriend.GetDesignatedFriendsApplyResp, err error) { - friendRequests, err := s.friendDatabase.FindBothFriendRequests(ctx, req.FromUserID, req.ToUserID) + req *relation.GetDesignatedFriendsApplyReq, +) (resp *relation.GetDesignatedFriendsApplyResp, err error) { + friendRequests, err := s.db.FindBothFriendRequests(ctx, req.FromUserID, req.ToUserID) if err != nil { return nil, err } - resp = &pbfriend.GetDesignatedFriendsApplyResp{} + resp = &relation.GetDesignatedFriendsApplyResp{} resp.FriendRequests, err = convert.FriendRequestDB2Pb(ctx, friendRequests, s.userRpcClient.GetUsersInfoMap) if err != nil { return nil, err @@ -293,15 +305,15 @@ func (s *friendServer) GetDesignatedFriendsApply(ctx context.Context, } // Get received friend requests (i.e., those initiated by others). -func (s *friendServer) GetPaginationFriendsApplyTo(ctx context.Context, req *pbfriend.GetPaginationFriendsApplyToReq) (resp *pbfriend.GetPaginationFriendsApplyToResp, err error) { +func (s *friendServer) GetPaginationFriendsApplyTo(ctx context.Context, req *relation.GetPaginationFriendsApplyToReq) (resp *relation.GetPaginationFriendsApplyToResp, err error) { if err := s.userRpcClient.Access(ctx, req.UserID); err != nil { return nil, err } - total, friendRequests, err := s.friendDatabase.PageFriendRequestToMe(ctx, req.UserID, req.Pagination) + total, friendRequests, err := s.db.PageFriendRequestToMe(ctx, req.UserID, req.Pagination) if err != nil { return nil, err } - resp = &pbfriend.GetPaginationFriendsApplyToResp{} + resp = &relation.GetPaginationFriendsApplyToResp{} resp.FriendRequests, err = convert.FriendRequestDB2Pb(ctx, friendRequests, s.userRpcClient.GetUsersInfoMap) if err != nil { return nil, err @@ -310,12 +322,12 @@ func (s *friendServer) GetPaginationFriendsApplyTo(ctx context.Context, req *pbf return resp, nil } -func (s *friendServer) GetPaginationFriendsApplyFrom(ctx context.Context, req *pbfriend.GetPaginationFriendsApplyFromReq) (resp *pbfriend.GetPaginationFriendsApplyFromResp, err error) { - resp = &pbfriend.GetPaginationFriendsApplyFromResp{} +func (s *friendServer) GetPaginationFriendsApplyFrom(ctx context.Context, req *relation.GetPaginationFriendsApplyFromReq) (resp *relation.GetPaginationFriendsApplyFromResp, err error) { + resp = &relation.GetPaginationFriendsApplyFromResp{} if err := s.userRpcClient.Access(ctx, req.UserID); err != nil { return nil, err } - total, friendRequests, err := s.friendDatabase.PageFriendRequestFromMe(ctx, req.UserID, req.Pagination) + total, friendRequests, err := s.db.PageFriendRequestFromMe(ctx, req.UserID, req.Pagination) if err != nil { return nil, err } @@ -328,24 +340,24 @@ func (s *friendServer) GetPaginationFriendsApplyFrom(ctx context.Context, req *p } // ok. -func (s *friendServer) IsFriend(ctx context.Context, req *pbfriend.IsFriendReq) (resp *pbfriend.IsFriendResp, err error) { - resp = &pbfriend.IsFriendResp{} - resp.InUser1Friends, resp.InUser2Friends, err = s.friendDatabase.CheckIn(ctx, req.UserID1, req.UserID2) +func (s *friendServer) IsFriend(ctx context.Context, req *relation.IsFriendReq) (resp *relation.IsFriendResp, err error) { + resp = &relation.IsFriendResp{} + resp.InUser1Friends, resp.InUser2Friends, err = s.db.CheckIn(ctx, req.UserID1, req.UserID2) if err != nil { return nil, err } return resp, nil } -func (s *friendServer) GetPaginationFriends(ctx context.Context, req *pbfriend.GetPaginationFriendsReq) (resp *pbfriend.GetPaginationFriendsResp, err error) { +func (s *friendServer) GetPaginationFriends(ctx context.Context, req *relation.GetPaginationFriendsReq) (resp *relation.GetPaginationFriendsResp, err error) { if err := s.userRpcClient.Access(ctx, req.UserID); err != nil { return nil, err } - total, friends, err := s.friendDatabase.PageOwnerFriends(ctx, req.UserID, req.Pagination) + total, friends, err := s.db.PageOwnerFriends(ctx, req.UserID, req.Pagination) if err != nil { return nil, err } - resp = &pbfriend.GetPaginationFriendsResp{} + resp = &relation.GetPaginationFriendsResp{} resp.FriendsInfo, err = convert.FriendsDB2Pb(ctx, friends, s.userRpcClient.GetUsersInfoMap) if err != nil { return nil, err @@ -354,19 +366,19 @@ func (s *friendServer) GetPaginationFriends(ctx context.Context, req *pbfriend.G return resp, nil } -func (s *friendServer) GetFriendIDs(ctx context.Context, req *pbfriend.GetFriendIDsReq) (resp *pbfriend.GetFriendIDsResp, err error) { +func (s *friendServer) GetFriendIDs(ctx context.Context, req *relation.GetFriendIDsReq) (resp *relation.GetFriendIDsResp, err error) { if err := s.userRpcClient.Access(ctx, req.UserID); err != nil { return nil, err } - resp = &pbfriend.GetFriendIDsResp{} - resp.FriendIDs, err = s.friendDatabase.FindFriendUserIDs(ctx, req.UserID) + resp = &relation.GetFriendIDsResp{} + resp.FriendIDs, err = s.db.FindFriendUserIDs(ctx, req.UserID) if err != nil { return nil, err } return resp, nil } -func (s *friendServer) GetSpecifiedFriendsInfo(ctx context.Context, req *pbfriend.GetSpecifiedFriendsInfoReq) (*pbfriend.GetSpecifiedFriendsInfoResp, error) { +func (s *friendServer) GetSpecifiedFriendsInfo(ctx context.Context, req *relation.GetSpecifiedFriendsInfoReq) (*relation.GetSpecifiedFriendsInfoResp, error) { if len(req.UserIDList) == 0 { return nil, errs.ErrArgs.WrapMsg("userIDList is empty") } @@ -377,7 +389,7 @@ func (s *friendServer) GetSpecifiedFriendsInfo(ctx context.Context, req *pbfrien if err != nil { return nil, err } - friends, err := s.friendDatabase.FindFriendsWithError(ctx, req.OwnerUserID, req.UserIDList) + friends, err := s.db.FindFriendsWithError(ctx, req.OwnerUserID, req.UserIDList) if err != nil { return nil, err } @@ -391,8 +403,8 @@ func (s *friendServer) GetSpecifiedFriendsInfo(ctx context.Context, req *pbfrien blackMap := datautil.SliceToMap(blacks, func(e *model.Black) string { return e.BlockUserID }) - resp := &pbfriend.GetSpecifiedFriendsInfoResp{ - Infos: make([]*pbfriend.GetSpecifiedFriendsInfoInfo, 0, len(req.UserIDList)), + resp := &relation.GetSpecifiedFriendsInfoResp{ + Infos: make([]*relation.GetSpecifiedFriendsInfoInfo, 0, len(req.UserIDList)), } for _, userID := range req.UserIDList { user := userMap[userID] @@ -401,7 +413,6 @@ func (s *friendServer) GetSpecifiedFriendsInfo(ctx context.Context, req *pbfrien } var friendInfo *sdkws.FriendInfo if friend := friendMap[userID]; friend != nil { - friendInfo = &sdkws.FriendInfo{ OwnerUserID: friend.OwnerUserID, Remark: friend.Remark, @@ -422,7 +433,7 @@ func (s *friendServer) GetSpecifiedFriendsInfo(ctx context.Context, req *pbfrien Ex: black.Ex, } } - resp.Infos = append(resp.Infos, &pbfriend.GetSpecifiedFriendsInfoInfo{ + resp.Infos = append(resp.Infos, &relation.GetSpecifiedFriendsInfoInfo{ UserInfo: user, FriendInfo: friendInfo, BlackInfo: blackInfo, @@ -430,10 +441,11 @@ func (s *friendServer) GetSpecifiedFriendsInfo(ctx context.Context, req *pbfrien } return resp, nil } + func (s *friendServer) UpdateFriends( ctx context.Context, - req *pbfriend.UpdateFriendsReq, -) (*pbfriend.UpdateFriendsResp, error) { + req *relation.UpdateFriendsReq, +) (*relation.UpdateFriendsResp, error) { if len(req.FriendUserIDs) == 0 { return nil, errs.ErrArgs.WrapMsg("friendIDList is empty") } @@ -441,7 +453,7 @@ func (s *friendServer) UpdateFriends( return nil, errs.ErrArgs.WrapMsg("friendIDList repeated") } - _, err := s.friendDatabase.FindFriendsWithError(ctx, req.OwnerUserID, req.FriendUserIDs) + _, err := s.db.FindFriendsWithError(ctx, req.OwnerUserID, req.FriendUserIDs) if err != nil { return nil, err } @@ -457,12 +469,27 @@ func (s *friendServer) UpdateFriends( if req.Ex != nil { val["ex"] = req.Ex.Value } - if err = s.friendDatabase.UpdateFriends(ctx, req.OwnerUserID, req.FriendUserIDs, val); err != nil { + if err = s.db.UpdateFriends(ctx, req.OwnerUserID, req.FriendUserIDs, val); err != nil { return nil, err } - resp := &pbfriend.UpdateFriendsResp{} + resp := &relation.UpdateFriendsResp{} s.notificationSender.FriendsInfoUpdateNotification(ctx, req.OwnerUserID, req.FriendUserIDs) return resp, nil } + +func (s *friendServer) GetIncrementalFriendsApplyTo(ctx context.Context, req *relation.GetIncrementalFriendsApplyToReq) (*relation.GetIncrementalFriendsApplyToResp, error) { + // TODO implement me + return nil, nil +} + +func (s *friendServer) GetIncrementalFriendsApplyFrom(ctx context.Context, req *relation.GetIncrementalFriendsApplyFromReq) (*relation.GetIncrementalFriendsApplyFromResp, error) { + // TODO implement me + return nil, nil +} + +func (s *friendServer) GetIncrementalBlacks(ctx context.Context, req *relation.GetIncrementalBlacksReq) (*relation.GetIncrementalBlacksResp, error) { + // TODO implement me + return nil, nil +} diff --git a/internal/rpc/friend/notification.go b/internal/rpc/friend/notification.go index 8089a9bdc8..ddee025bb6 100644 --- a/internal/rpc/friend/notification.go +++ b/internal/rpc/friend/notification.go @@ -16,6 +16,7 @@ package friend import ( "context" + relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model" "github.com/openimsdk/open-im-server/v3/pkg/common/config" @@ -24,7 +25,7 @@ import ( "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient/notification" "github.com/openimsdk/protocol/constant" - pbfriend "github.com/openimsdk/protocol/friend" + "github.com/openimsdk/protocol/relation" "github.com/openimsdk/protocol/sdkws" "github.com/openimsdk/tools/mcontext" ) @@ -127,7 +128,7 @@ func (f *FriendNotificationSender) UserInfoUpdatedNotification(ctx context.Conte f.Notification(ctx, mcontext.GetOpUserID(ctx), changedUserID, constant.UserInfoUpdatedNotification, &tips) } -func (f *FriendNotificationSender) FriendApplicationAddNotification(ctx context.Context, req *pbfriend.ApplyToAddFriendReq) { +func (f *FriendNotificationSender) FriendApplicationAddNotification(ctx context.Context, req *relation.ApplyToAddFriendReq) { tips := sdkws.FriendApplicationTips{FromToUserID: &sdkws.FromToUserID{ FromUserID: req.FromUserID, ToUserID: req.ToUserID, @@ -137,7 +138,7 @@ func (f *FriendNotificationSender) FriendApplicationAddNotification(ctx context. func (f *FriendNotificationSender) FriendApplicationAgreedNotification( ctx context.Context, - req *pbfriend.RespondFriendApplyReq, + req *relation.RespondFriendApplyReq, ) { tips := sdkws.FriendApplicationApprovedTips{FromToUserID: &sdkws.FromToUserID{ FromUserID: req.FromUserID, @@ -148,7 +149,7 @@ func (f *FriendNotificationSender) FriendApplicationAgreedNotification( func (f *FriendNotificationSender) FriendApplicationRefusedNotification( ctx context.Context, - req *pbfriend.RespondFriendApplyReq, + req *relation.RespondFriendApplyReq, ) { tips := sdkws.FriendApplicationApprovedTips{FromToUserID: &sdkws.FromToUserID{ FromUserID: req.FromUserID, @@ -182,7 +183,7 @@ func (f *FriendNotificationSender) FriendAddedNotification( return nil } -func (f *FriendNotificationSender) FriendDeletedNotification(ctx context.Context, req *pbfriend.DeleteFriendReq) { +func (f *FriendNotificationSender) FriendDeletedNotification(ctx context.Context, req *relation.DeleteFriendReq) { tips := sdkws.FriendDeletedTips{FromToUserID: &sdkws.FromToUserID{ FromUserID: req.OwnerUserID, ToUserID: req.FriendUserID, @@ -204,14 +205,14 @@ func (f *FriendNotificationSender) FriendsInfoUpdateNotification(ctx context.Con f.Notification(ctx, toUserID, toUserID, constant.FriendsInfoUpdateNotification, &tips) } -func (f *FriendNotificationSender) BlackAddedNotification(ctx context.Context, req *pbfriend.AddBlackReq) { +func (f *FriendNotificationSender) BlackAddedNotification(ctx context.Context, req *relation.AddBlackReq) { tips := sdkws.BlackAddedTips{FromToUserID: &sdkws.FromToUserID{}} tips.FromToUserID.FromUserID = req.OwnerUserID tips.FromToUserID.ToUserID = req.BlackUserID f.Notification(ctx, req.OwnerUserID, req.BlackUserID, constant.BlackAddedNotification, &tips) } -func (f *FriendNotificationSender) BlackDeletedNotification(ctx context.Context, req *pbfriend.RemoveBlackReq) { +func (f *FriendNotificationSender) BlackDeletedNotification(ctx context.Context, req *relation.RemoveBlackReq) { blackDeletedTips := sdkws.BlackDeletedTips{FromToUserID: &sdkws.FromToUserID{ FromUserID: req.OwnerUserID, ToUserID: req.BlackUserID, diff --git a/internal/rpc/friend/sync.go b/internal/rpc/friend/sync.go new file mode 100644 index 0000000000..684894609c --- /dev/null +++ b/internal/rpc/friend/sync.go @@ -0,0 +1,78 @@ +package friend + +import ( + "context" + "github.com/openimsdk/open-im-server/v3/pkg/util/hashutil" + "github.com/openimsdk/protocol/sdkws" + + "github.com/openimsdk/open-im-server/v3/internal/rpc/incrversion" + "github.com/openimsdk/open-im-server/v3/pkg/authverify" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model" + "github.com/openimsdk/protocol/relation" +) + +func (s *friendServer) NotificationUserInfoUpdate(ctx context.Context, req *relation.NotificationUserInfoUpdateReq) (*relation.NotificationUserInfoUpdateResp, error) { + userIDs, err := s.db.FindFriendUserIDs(ctx, req.UserID) + if err != nil { + return nil, err + } + for _, userID := range userIDs { + if err := s.db.OwnerIncrVersion(ctx, userID, []string{req.UserID}, model.VersionStateUpdate); err != nil { + return nil, err + } + } + for _, userID := range userIDs { + s.notificationSender.FriendInfoUpdatedNotification(ctx, req.UserID, userID) + } + return &relation.NotificationUserInfoUpdateResp{}, nil +} + +func (s *friendServer) GetFullFriendUserIDs(ctx context.Context, req *relation.GetFullFriendUserIDsReq) (*relation.GetFullFriendUserIDsResp, error) { + vl, err := s.db.FindMaxFriendVersionCache(ctx, req.UserID) + if err != nil { + return nil, err + } + userIDs, err := s.db.FindFriendUserIDs(ctx, req.UserID) + if err != nil { + return nil, err + } + idHash := hashutil.IdHash(userIDs) + if req.IdHash == idHash { + userIDs = nil + } + return &relation.GetFullFriendUserIDsResp{ + Version: idHash, + VersionID: vl.ID.Hex(), + Equal: req.IdHash == idHash, + UserIDs: userIDs, + }, nil +} + +func (s *friendServer) GetIncrementalFriends(ctx context.Context, req *relation.GetIncrementalFriendsReq) (*relation.GetIncrementalFriendsResp, error) { + if err := authverify.CheckAccessV3(ctx, req.UserID, s.config.Share.IMAdminUserID); err != nil { + return nil, err + } + opt := incrversion.Option[*sdkws.FriendInfo, relation.GetIncrementalFriendsResp]{ + Ctx: ctx, + VersionKey: req.UserID, + VersionID: req.VersionID, + VersionNumber: req.Version, + Version: s.db.FindFriendIncrVersion, + CacheMaxVersion: s.db.FindMaxFriendVersionCache, + Find: func(ctx context.Context, ids []string) ([]*sdkws.FriendInfo, error) { + return s.getFriend(ctx, req.UserID, ids) + }, + ID: func(elem *sdkws.FriendInfo) string { return elem.FriendUser.UserID }, + Resp: func(version *model.VersionLog, deleteIds []string, insertList, updateList []*sdkws.FriendInfo, full bool) *relation.GetIncrementalFriendsResp { + return &relation.GetIncrementalFriendsResp{ + VersionID: version.ID.Hex(), + Version: uint64(version.Version), + Full: full, + Delete: deleteIds, + Insert: insertList, + Update: updateList, + } + }, + } + return opt.Build() +} diff --git a/internal/rpc/group/convert.go b/internal/rpc/group/convert.go index a75693904d..8026430c30 100644 --- a/internal/rpc/group/convert.go +++ b/internal/rpc/group/convert.go @@ -57,3 +57,7 @@ func (s *groupServer) groupMemberDB2PB(member *model.GroupMember, appMangerLevel InviterUserID: member.InviterUserID, } } + +func (s *groupServer) groupMemberDB2PB2(member *model.GroupMember) *sdkws.GroupMemberFullInfo { + return s.groupMemberDB2PB(member, 0) +} diff --git a/internal/rpc/group/group.go b/internal/rpc/group/group.go index a9cea4ff22..e3d1d4dfe6 100644 --- a/internal/rpc/group/group.go +++ b/internal/rpc/group/group.go @@ -17,17 +17,18 @@ package group import ( "context" "fmt" + "math/big" + "math/rand" + "strconv" + "strings" + "time" + "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/storage/common" "github.com/openimsdk/open-im-server/v3/pkg/common/storage/database/mgo" "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model" "github.com/openimsdk/open-im-server/v3/pkg/common/webhook" "github.com/openimsdk/open-im-server/v3/pkg/localcache" - "math/big" - "math/rand" - "strconv" - "strings" - "time" "github.com/openimsdk/open-im-server/v3/pkg/authverify" "github.com/openimsdk/open-im-server/v3/pkg/callbackstruct" @@ -132,13 +133,17 @@ func (s *groupServer) NotificationUserInfoUpdate(ctx context.Context, req *pbgro } groupIDs = append(groupIDs, member.GroupID) } + for _, groupID := range groupIDs { + if err := s.db.MemberGroupIncrVersion(ctx, groupID, []string{req.UserID}, model.VersionStateUpdate); err != nil { + return nil, err + } + } for _, groupID := range groupIDs { s.notification.GroupMemberInfoSetNotification(ctx, groupID, req.UserID) } if err = s.db.DeleteGroupMemberHash(ctx, groupIDs); err != nil { return nil, err } - return &pbgroup.NotificationUserInfoUpdateResp{}, nil } @@ -527,6 +532,14 @@ func (s *groupServer) KickGroupMember(ctx context.Context, req *pbgroup.KickGrou if datautil.Contain(opUserID, req.KickedUserIDs...) { return nil, errs.ErrArgs.WrapMsg("opUserID in KickedUserIDs") } + owner, err := s.db.TakeGroupOwner(ctx, req.GroupID) + if err != nil { + return nil, err + } + if datautil.Contain(owner.UserID, req.KickedUserIDs...) { + return nil, errs.ErrArgs.WrapMsg("ownerUID can not Kick") + } + members, err := s.db.FindGroupMembers(ctx, req.GroupID, append(req.KickedUserIDs, opUserID)) if err != nil { return nil, err @@ -586,7 +599,7 @@ func (s *groupServer) KickGroupMember(ctx context.Context, req *pbgroup.KickGrou FaceURL: group.FaceURL, OwnerUserID: ownerUserID, CreateTime: group.CreateTime.UnixMilli(), - MemberCount: num, + MemberCount: num - uint32(len(req.KickedUserIDs)), Ex: group.Ex, Status: group.Status, CreatorUserID: group.CreatorUserID, @@ -621,18 +634,29 @@ func (s *groupServer) GetGroupMembersInfo(ctx context.Context, req *pbgroup.GetG if req.GroupID == "" { return nil, errs.ErrArgs.WrapMsg("groupID empty") } - members, err := s.db.FindGroupMembers(ctx, req.GroupID, req.UserIDs) + members, err := s.getGroupMembersInfo(ctx, req.GroupID, req.UserIDs) + if err != nil { + return nil, err + } + return &pbgroup.GetGroupMembersInfoResp{ + Members: members, + }, nil +} + +func (s *groupServer) getGroupMembersInfo(ctx context.Context, groupID string, userIDs []string) ([]*sdkws.GroupMemberFullInfo, error) { + if len(userIDs) == 0 { + return nil, nil + } + members, err := s.db.FindGroupMembers(ctx, groupID, userIDs) if err != nil { return nil, err } if err := s.PopulateGroupMember(ctx, members...); err != nil { return nil, err } - return &pbgroup.GetGroupMembersInfoResp{ - Members: datautil.Slice(members, func(e *model.GroupMember) *sdkws.GroupMemberFullInfo { - return convert.Db2PbGroupMember(e) - }), - }, nil + return datautil.Slice(members, func(e *model.GroupMember) *sdkws.GroupMemberFullInfo { + return convert.Db2PbGroupMember(e) + }), nil } // GetGroupApplicationList handles functions that get a list of group requests. @@ -701,15 +725,28 @@ func (s *groupServer) GetGroupsInfo(ctx context.Context, req *pbgroup.GetGroupsI if len(req.GroupIDs) == 0 { return nil, errs.ErrArgs.WrapMsg("groupID is empty") } - groups, err := s.db.FindGroup(ctx, req.GroupIDs) + groups, err := s.getGroupsInfo(ctx, req.GroupIDs) if err != nil { return nil, err } - groupMemberNumMap, err := s.db.MapGroupMemberNum(ctx, req.GroupIDs) + return &pbgroup.GetGroupsInfoResp{ + GroupInfos: groups, + }, nil +} + +func (s *groupServer) getGroupsInfo(ctx context.Context, groupIDs []string) ([]*sdkws.GroupInfo, error) { + if len(groupIDs) == 0 { + return nil, nil + } + groups, err := s.db.FindGroup(ctx, groupIDs) if err != nil { return nil, err } - owners, err := s.db.FindGroupsOwner(ctx, req.GroupIDs) + groupMemberNumMap, err := s.db.MapGroupMemberNum(ctx, groupIDs) + if err != nil { + return nil, err + } + owners, err := s.db.FindGroupsOwner(ctx, groupIDs) if err != nil { return nil, err } @@ -719,15 +756,13 @@ func (s *groupServer) GetGroupsInfo(ctx context.Context, req *pbgroup.GetGroupsI ownerMap := datautil.SliceToMap(owners, func(e *model.GroupMember) string { return e.GroupID }) - return &pbgroup.GetGroupsInfoResp{ - GroupInfos: datautil.Slice(groups, func(e *model.Group) *sdkws.GroupInfo { - var ownerUserID string - if owner, ok := ownerMap[e.GroupID]; ok { - ownerUserID = owner.UserID - } - return convert.Db2PbGroupInfo(e, ownerUserID, groupMemberNumMap[e.GroupID]) - }), - }, nil + return datautil.Slice(groups, func(e *model.Group) *sdkws.GroupInfo { + var ownerUserID string + if owner, ok := ownerMap[e.GroupID]; ok { + ownerUserID = owner.UserID + } + return convert.Db2PbGroupInfo(e, ownerUserID, groupMemberNumMap[e.GroupID]) + }), nil } func (s *groupServer) GroupApplicationResponse(ctx context.Context, req *pbgroup.GroupApplicationResponseReq) (*pbgroup.GroupApplicationResponseResp, error) { diff --git a/internal/rpc/group/notification.go b/internal/rpc/group/notification.go index a9abb03e6a..a8824962dc 100644 --- a/internal/rpc/group/notification.go +++ b/internal/rpc/group/notification.go @@ -17,13 +17,15 @@ package group import ( "context" "fmt" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/database" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/versionctx" + "github.com/openimsdk/open-im-server/v3/pkg/rpcclient/notification" "github.com/openimsdk/open-im-server/v3/pkg/authverify" "github.com/openimsdk/open-im-server/v3/pkg/common/servererrs" "github.com/openimsdk/open-im-server/v3/pkg/common/storage/controller" - "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" - "github.com/openimsdk/open-im-server/v3/pkg/rpcclient/notification" "github.com/openimsdk/protocol/constant" pbgroup "github.com/openimsdk/protocol/group" "github.com/openimsdk/protocol/sdkws" @@ -293,6 +295,17 @@ func (g *GroupNotificationSender) fillOpUser(ctx context.Context, opUser **sdkws return nil } +func (g *GroupNotificationSender) setVersion(ctx context.Context, version *uint64, versionID *string, collName string, id string) { + versions := versionctx.GetVersionLog(ctx).Get() + for _, coll := range versions { + if coll.Name == collName && coll.Doc.DID == id { + *version = uint64(coll.Doc.Version) + *versionID = coll.Doc.ID.Hex() + return + } + } +} + func (g *GroupNotificationSender) GroupCreatedNotification(ctx context.Context, tips *sdkws.GroupCreatedTips) { var err error defer func() { @@ -303,6 +316,7 @@ func (g *GroupNotificationSender) GroupCreatedNotification(ctx context.Context, if err = g.fillOpUser(ctx, &tips.OpUser, tips.Group.GroupID); err != nil { return } + g.setVersion(ctx, &tips.GroupMemberVersion, &tips.GroupMemberVersionID, database.GroupMemberVersionName, tips.Group.GroupID) g.Notification(ctx, mcontext.GetOpUserID(ctx), tips.Group.GroupID, constant.GroupCreatedNotification, tips) } @@ -316,6 +330,7 @@ func (g *GroupNotificationSender) GroupInfoSetNotification(ctx context.Context, if err = g.fillOpUser(ctx, &tips.OpUser, tips.Group.GroupID); err != nil { return } + g.setVersion(ctx, &tips.GroupMemberVersion, &tips.GroupMemberVersionID, database.GroupMemberVersionName, tips.Group.GroupID) g.Notification(ctx, mcontext.GetOpUserID(ctx), tips.Group.GroupID, constant.GroupInfoSetNotification, tips, rpcclient.WithRpcGetUserName()) } @@ -329,6 +344,7 @@ func (g *GroupNotificationSender) GroupInfoSetNameNotification(ctx context.Conte if err = g.fillOpUser(ctx, &tips.OpUser, tips.Group.GroupID); err != nil { return } + g.setVersion(ctx, &tips.GroupMemberVersion, &tips.GroupMemberVersionID, database.GroupMemberVersionName, tips.Group.GroupID) g.Notification(ctx, mcontext.GetOpUserID(ctx), tips.Group.GroupID, constant.GroupInfoSetNameNotification, tips) } @@ -342,6 +358,7 @@ func (g *GroupNotificationSender) GroupInfoSetAnnouncementNotification(ctx conte if err = g.fillOpUser(ctx, &tips.OpUser, tips.Group.GroupID); err != nil { return } + g.setVersion(ctx, &tips.GroupMemberVersion, &tips.GroupMemberVersionID, database.GroupMemberVersionName, tips.Group.GroupID) g.Notification(ctx, mcontext.GetOpUserID(ctx), tips.Group.GroupID, constant.GroupInfoSetAnnouncementNotification, tips, rpcclient.WithRpcGetUserName()) } @@ -386,6 +403,7 @@ func (g *GroupNotificationSender) MemberQuitNotification(ctx context.Context, me return } tips := &sdkws.MemberQuitTips{Group: group, QuitUser: member} + g.setVersion(ctx, &tips.GroupMemberVersion, &tips.GroupMemberVersionID, database.GroupMemberVersionName, member.GroupID) g.Notification(ctx, mcontext.GetOpUserID(ctx), member.GroupID, constant.MemberQuitNotification, tips) } @@ -469,14 +487,20 @@ func (g *GroupNotificationSender) GroupOwnerTransferredNotification(ctx context. } opUserID := mcontext.GetOpUserID(ctx) var member map[string]*sdkws.GroupMemberFullInfo - member, err = g.getGroupMemberMap(ctx, req.GroupID, []string{opUserID, req.NewOwnerUserID}) + member, err = g.getGroupMemberMap(ctx, req.GroupID, []string{opUserID, req.NewOwnerUserID, req.OldOwnerUserID}) if err != nil { return } - tips := &sdkws.GroupOwnerTransferredTips{Group: group, OpUser: member[opUserID], NewGroupOwner: member[req.NewOwnerUserID]} + tips := &sdkws.GroupOwnerTransferredTips{ + Group: group, + OpUser: member[opUserID], + NewGroupOwner: member[req.NewOwnerUserID], + OldGroupOwnerInfo: member[req.OldOwnerUserID], + } if err = g.fillOpUser(ctx, &tips.OpUser, tips.Group.GroupID); err != nil { return } + g.setVersion(ctx, &tips.GroupMemberVersion, &tips.GroupMemberVersionID, database.GroupMemberVersionName, req.GroupID) g.Notification(ctx, mcontext.GetOpUserID(ctx), group.GroupID, constant.GroupOwnerTransferredNotification, tips) } @@ -490,6 +514,7 @@ func (g *GroupNotificationSender) MemberKickedNotification(ctx context.Context, if err = g.fillOpUser(ctx, &tips.OpUser, tips.Group.GroupID); err != nil { return } + g.setVersion(ctx, &tips.GroupMemberVersion, &tips.GroupMemberVersionID, database.GroupMemberVersionName, tips.Group.GroupID) g.Notification(ctx, mcontext.GetOpUserID(ctx), tips.Group.GroupID, constant.MemberKickedNotification, tips) } @@ -513,6 +538,7 @@ func (g *GroupNotificationSender) MemberInvitedNotification(ctx context.Context, } tips := &sdkws.MemberInvitedTips{Group: group, InvitedUserList: users} err = g.fillOpUser(ctx, &tips.OpUser, tips.Group.GroupID) + g.setVersion(ctx, &tips.GroupMemberVersion, &tips.GroupMemberVersionID, database.GroupMemberVersionName, tips.Group.GroupID) g.Notification(ctx, mcontext.GetOpUserID(ctx), group.GroupID, constant.MemberInvitedNotification, tips) } @@ -534,6 +560,7 @@ func (g *GroupNotificationSender) MemberEnterNotification(ctx context.Context, g return } tips := &sdkws.MemberEnterTips{Group: group, EntrantUser: user} + g.setVersion(ctx, &tips.GroupMemberVersion, &tips.GroupMemberVersionID, database.GroupMemberVersionName, tips.Group.GroupID) g.Notification(ctx, mcontext.GetOpUserID(ctx), group.GroupID, constant.MemberEnterNotification, tips) } @@ -574,6 +601,7 @@ func (g *GroupNotificationSender) GroupMemberMutedNotification(ctx context.Conte if err = g.fillOpUser(ctx, &tips.OpUser, tips.Group.GroupID); err != nil { return } + g.setVersion(ctx, &tips.GroupMemberVersion, &tips.GroupMemberVersionID, database.GroupMemberVersionName, tips.Group.GroupID) g.Notification(ctx, mcontext.GetOpUserID(ctx), group.GroupID, constant.GroupMemberMutedNotification, tips) } @@ -598,6 +626,7 @@ func (g *GroupNotificationSender) GroupMemberCancelMutedNotification(ctx context if err = g.fillOpUser(ctx, &tips.OpUser, tips.Group.GroupID); err != nil { return } + g.setVersion(ctx, &tips.GroupMemberVersion, &tips.GroupMemberVersionID, database.GroupMemberVersionName, tips.Group.GroupID) g.Notification(ctx, mcontext.GetOpUserID(ctx), group.GroupID, constant.GroupMemberCancelMutedNotification, tips) } @@ -625,6 +654,7 @@ func (g *GroupNotificationSender) GroupMutedNotification(ctx context.Context, gr if err = g.fillOpUser(ctx, &tips.OpUser, tips.Group.GroupID); err != nil { return } + g.setVersion(ctx, &tips.GroupMemberVersion, &tips.GroupMemberVersionID, database.GroupMemberVersionName, groupID) g.Notification(ctx, mcontext.GetOpUserID(ctx), group.GroupID, constant.GroupMutedNotification, tips) } @@ -652,6 +682,7 @@ func (g *GroupNotificationSender) GroupCancelMutedNotification(ctx context.Conte if err = g.fillOpUser(ctx, &tips.OpUser, tips.Group.GroupID); err != nil { return } + g.setVersion(ctx, &tips.GroupMemberVersion, &tips.GroupMemberVersionID, database.GroupMemberVersionName, groupID) g.Notification(ctx, mcontext.GetOpUserID(ctx), group.GroupID, constant.GroupCancelMutedNotification, tips) } @@ -676,6 +707,7 @@ func (g *GroupNotificationSender) GroupMemberInfoSetNotification(ctx context.Con if err = g.fillOpUser(ctx, &tips.OpUser, tips.Group.GroupID); err != nil { return } + g.setVersion(ctx, &tips.GroupMemberVersion, &tips.GroupMemberVersionID, database.GroupMemberVersionName, tips.Group.GroupID) g.Notification(ctx, mcontext.GetOpUserID(ctx), group.GroupID, constant.GroupMemberInfoSetNotification, tips) } @@ -699,6 +731,7 @@ func (g *GroupNotificationSender) GroupMemberSetToAdminNotification(ctx context. if err = g.fillOpUser(ctx, &tips.OpUser, tips.Group.GroupID); err != nil { return } + g.setVersion(ctx, &tips.GroupMemberVersion, &tips.GroupMemberVersionID, database.GroupMemberVersionName, tips.Group.GroupID) g.Notification(ctx, mcontext.GetOpUserID(ctx), group.GroupID, constant.GroupMemberSetToAdminNotification, tips) } @@ -723,5 +756,6 @@ func (g *GroupNotificationSender) GroupMemberSetToOrdinaryUserNotification(ctx c if err = g.fillOpUser(ctx, &tips.OpUser, tips.Group.GroupID); err != nil { return } + g.setVersion(ctx, &tips.GroupMemberVersion, &tips.GroupMemberVersionID, database.GroupMemberVersionName, tips.Group.GroupID) g.Notification(ctx, mcontext.GetOpUserID(ctx), group.GroupID, constant.GroupMemberSetToOrdinaryUserNotification, tips) } diff --git a/internal/rpc/group/sync.go b/internal/rpc/group/sync.go new file mode 100644 index 0000000000..75d060c0e5 --- /dev/null +++ b/internal/rpc/group/sync.go @@ -0,0 +1,149 @@ +package group + +import ( + "context" + "github.com/openimsdk/open-im-server/v3/internal/rpc/incrversion" + "github.com/openimsdk/open-im-server/v3/pkg/authverify" + "github.com/openimsdk/open-im-server/v3/pkg/common/servererrs" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model" + "github.com/openimsdk/open-im-server/v3/pkg/util/hashutil" + "github.com/openimsdk/protocol/constant" + pbgroup "github.com/openimsdk/protocol/group" + "github.com/openimsdk/protocol/sdkws" + "slices" +) + +func (s *groupServer) GetFullGroupMemberUserIDs(ctx context.Context, req *pbgroup.GetFullGroupMemberUserIDsReq) (*pbgroup.GetFullGroupMemberUserIDsResp, error) { + vl, err := s.db.FindMaxGroupMemberVersionCache(ctx, req.GroupID) + if err != nil { + return nil, err + } + userIDs, err := s.db.FindGroupMemberUserID(ctx, req.GroupID) + if err != nil { + return nil, err + } + idHash := hashutil.IdHash(userIDs) + if req.IdHash == idHash { + userIDs = nil + } + return &pbgroup.GetFullGroupMemberUserIDsResp{ + Version: idHash, + VersionID: vl.ID.Hex(), + Equal: req.IdHash == idHash, + UserIDs: userIDs, + }, nil +} + +func (s *groupServer) GetFullJoinGroupIDs(ctx context.Context, req *pbgroup.GetFullJoinGroupIDsReq) (*pbgroup.GetFullJoinGroupIDsResp, error) { + vl, err := s.db.FindMaxJoinGroupVersionCache(ctx, req.UserID) + if err != nil { + return nil, err + } + groupIDs, err := s.db.FindJoinGroupID(ctx, req.UserID) + if err != nil { + return nil, err + } + idHash := hashutil.IdHash(groupIDs) + if req.IdHash == idHash { + groupIDs = nil + } + return &pbgroup.GetFullJoinGroupIDsResp{ + Version: idHash, + VersionID: vl.ID.Hex(), + Equal: req.IdHash == idHash, + GroupIDs: groupIDs, + }, nil +} + +func (s *groupServer) GetIncrementalGroupMember(ctx context.Context, req *pbgroup.GetIncrementalGroupMemberReq) (*pbgroup.GetIncrementalGroupMemberResp, error) { + group, err := s.db.TakeGroup(ctx, req.GroupID) + if err != nil { + return nil, err + } + if group.Status == constant.GroupStatusDismissed { + return nil, servererrs.ErrDismissedAlready.Wrap() + } + var hasGroupUpdate bool + opt := incrversion.Option[*sdkws.GroupMemberFullInfo, pbgroup.GetIncrementalGroupMemberResp]{ + Ctx: ctx, + VersionKey: req.GroupID, + VersionID: req.VersionID, + VersionNumber: req.Version, + Version: func(ctx context.Context, groupID string, version uint, limit int) (*model.VersionLog, error) { + vl, err := s.db.FindMemberIncrVersion(ctx, groupID, version, limit) + if err != nil { + return nil, err + } + vl.Logs = slices.DeleteFunc(vl.Logs, func(elem model.VersionLogElem) bool { + if elem.EID == "" { + vl.LogLen-- + hasGroupUpdate = true + return true + } + return false + }) + if vl.LogLen > 0 { + hasGroupUpdate = true + } + return vl, nil + }, + CacheMaxVersion: s.db.FindMaxGroupMemberVersionCache, + Find: func(ctx context.Context, ids []string) ([]*sdkws.GroupMemberFullInfo, error) { + return s.getGroupMembersInfo(ctx, req.GroupID, ids) + }, + ID: func(elem *sdkws.GroupMemberFullInfo) string { return elem.UserID }, + Resp: func(version *model.VersionLog, delIDs []string, insertList, updateList []*sdkws.GroupMemberFullInfo, full bool) *pbgroup.GetIncrementalGroupMemberResp { + return &pbgroup.GetIncrementalGroupMemberResp{ + VersionID: version.ID.Hex(), + Version: uint64(version.Version), + Full: full, + Delete: delIDs, + Insert: insertList, + Update: updateList, + } + }, + } + resp, err := opt.Build() + if err != nil { + return nil, err + } + if resp.Full || hasGroupUpdate { + count, err := s.db.FindGroupMemberNum(ctx, group.GroupID) + if err != nil { + return nil, err + } + owner, err := s.db.TakeGroupOwner(ctx, group.GroupID) + if err != nil { + return nil, err + } + resp.Group = s.groupDB2PB(group, owner.UserID, count) + } + return resp, nil +} + +func (s *groupServer) GetIncrementalJoinGroup(ctx context.Context, req *pbgroup.GetIncrementalJoinGroupReq) (*pbgroup.GetIncrementalJoinGroupResp, error) { + if err := authverify.CheckAccessV3(ctx, req.UserID, s.config.Share.IMAdminUserID); err != nil { + return nil, err + } + opt := incrversion.Option[*sdkws.GroupInfo, pbgroup.GetIncrementalJoinGroupResp]{ + Ctx: ctx, + VersionKey: req.UserID, + VersionID: req.VersionID, + VersionNumber: req.Version, + Version: s.db.FindJoinIncrVersion, + CacheMaxVersion: s.db.FindMaxJoinGroupVersionCache, + Find: s.getGroupsInfo, + ID: func(elem *sdkws.GroupInfo) string { return elem.GroupID }, + Resp: func(version *model.VersionLog, delIDs []string, insertList, updateList []*sdkws.GroupInfo, full bool) *pbgroup.GetIncrementalJoinGroupResp { + return &pbgroup.GetIncrementalJoinGroupResp{ + VersionID: version.ID.Hex(), + Version: uint64(version.Version), + Full: full, + Delete: delIDs, + Insert: insertList, + Update: updateList, + } + }, + } + return opt.Build() +} diff --git a/internal/rpc/incrversion/option.go b/internal/rpc/incrversion/option.go new file mode 100644 index 0000000000..f7a71244a0 --- /dev/null +++ b/internal/rpc/incrversion/option.go @@ -0,0 +1,156 @@ +package incrversion + +import ( + "context" + "fmt" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model" + "github.com/openimsdk/tools/errs" + "go.mongodb.org/mongo-driver/bson/primitive" +) + +//func Limit(maxSync int, version uint64) int { +// if version == 0 { +// return 0 +// } +// return maxSync +//} + +const syncLimit = 200 + +const ( + tagQuery = iota + 1 + tagFull + tageEqual +) + +type Option[A, B any] struct { + Ctx context.Context + VersionKey string + VersionID string + VersionNumber uint64 + //SyncLimit int + CacheMaxVersion func(ctx context.Context, dId string) (*model.VersionLog, error) + Version func(ctx context.Context, dId string, version uint, limit int) (*model.VersionLog, error) + //SortID func(ctx context.Context, dId string) ([]string, error) + Find func(ctx context.Context, ids []string) ([]A, error) + ID func(elem A) string + Resp func(version *model.VersionLog, deleteIds []string, insertList, updateList []A, full bool) *B +} + +func (o *Option[A, B]) newError(msg string) error { + return errs.ErrInternalServer.WrapMsg(msg) +} + +func (o *Option[A, B]) check() error { + if o.Ctx == nil { + return o.newError("opt ctx is nil") + } + if o.VersionKey == "" { + return o.newError("versionKey is empty") + } + //if o.SyncLimit <= 0 { + // return o.newError("invalid synchronization quantity") + //} + if o.Version == nil { + return o.newError("func version is nil") + } + //if o.SortID == nil { + // return o.newError("func allID is nil") + //} + if o.Find == nil { + return o.newError("func find is nil") + } + if o.ID == nil { + return o.newError("func id is nil") + } + if o.Resp == nil { + return o.newError("func resp is nil") + } + return nil +} + +func (o *Option[A, B]) validVersion() bool { + objID, err := primitive.ObjectIDFromHex(o.VersionID) + return err == nil && (!objID.IsZero()) && o.VersionNumber > 0 +} + +func (o *Option[A, B]) equalID(objID primitive.ObjectID) bool { + return o.VersionID == objID.Hex() +} + +func (o *Option[A, B]) getVersion(tag *int) (*model.VersionLog, error) { + if o.CacheMaxVersion == nil { + if o.validVersion() { + *tag = tagQuery + return o.Version(o.Ctx, o.VersionKey, uint(o.VersionNumber), syncLimit) + } + *tag = tagFull + return o.Version(o.Ctx, o.VersionKey, 0, 0) + } else { + cache, err := o.CacheMaxVersion(o.Ctx, o.VersionKey) + if err != nil { + return nil, err + } + if !o.validVersion() { + *tag = tagFull + return cache, nil + } + if !o.equalID(cache.ID) { + *tag = tagFull + return cache, nil + } + if o.VersionNumber == uint64(cache.Version) { + *tag = tageEqual + return cache, nil + } + *tag = tagQuery + return o.Version(o.Ctx, o.VersionKey, uint(o.VersionNumber), syncLimit) + } +} + +func (o *Option[A, B]) Build() (*B, error) { + if err := o.check(); err != nil { + return nil, err + } + var tag int + version, err := o.getVersion(&tag) + if err != nil { + return nil, err + } + var full bool + switch tag { + case tagQuery: + full = version.ID.Hex() != o.VersionID || uint64(version.Version) < o.VersionNumber || len(version.Logs) != version.LogLen + case tagFull: + full = true + case tageEqual: + full = false + default: + panic(fmt.Errorf("undefined tag %d", tag)) + } + var ( + insertIds []string + deleteIds []string + updateIds []string + ) + if !full { + insertIds, deleteIds, updateIds = version.DeleteAndChangeIDs() + } + var ( + insertList []A + updateList []A + ) + if len(insertIds) > 0 { + insertList, err = o.Find(o.Ctx, insertIds) + if err != nil { + return nil, err + } + } + if len(updateIds) > 0 { + updateList, err = o.Find(o.Ctx, updateIds) + if err != nil { + return nil, err + } + } + return o.Resp(version, deleteIds, insertList, updateList, full), nil +} diff --git a/internal/rpc/msg/seq.go b/internal/rpc/msg/seq.go index 27465c2105..1ebec4a719 100644 --- a/internal/rpc/msg/seq.go +++ b/internal/rpc/msg/seq.go @@ -16,13 +16,15 @@ package msg import ( "context" + "github.com/openimsdk/tools/errs" + "github.com/redis/go-redis/v9" pbmsg "github.com/openimsdk/protocol/msg" ) func (m *msgServer) GetConversationMaxSeq(ctx context.Context, req *pbmsg.GetConversationMaxSeqReq) (*pbmsg.GetConversationMaxSeqResp, error) { maxSeq, err := m.MsgDatabase.GetMaxSeq(ctx, req.ConversationID) - if err != nil { + if err != nil && errs.Unwrap(err) != redis.Nil { return nil, err } return &pbmsg.GetConversationMaxSeqResp{MaxSeq: maxSeq}, nil diff --git a/internal/rpc/user/user.go b/internal/rpc/user/user.go index d0d3dbf603..211b360b7b 100644 --- a/internal/rpc/user/user.go +++ b/internal/rpc/user/user.go @@ -16,6 +16,7 @@ package user import ( "context" + "errors" "github.com/openimsdk/open-im-server/v3/internal/rpc/friend" "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/storage/cache/redis" @@ -23,9 +24,12 @@ import ( tablerelation "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model" "github.com/openimsdk/open-im-server/v3/pkg/common/webhook" "github.com/openimsdk/open-im-server/v3/pkg/localcache" + "github.com/openimsdk/protocol/group" + friendpb "github.com/openimsdk/protocol/relation" "github.com/openimsdk/tools/db/redisutil" "math/rand" "strings" + "sync" "time" "github.com/openimsdk/open-im-server/v3/pkg/authverify" @@ -131,26 +135,29 @@ func (s *userServer) UpdateUserInfo(ctx context.Context, req *pbuser.UpdateUserI if err := s.webhookBeforeUpdateUserInfo(ctx, &s.config.WebhooksConfig.BeforeUpdateUserInfo, req); err != nil { return nil, err } - data := convert.UserPb2DBMap(req.UserInfo) - if err := s.db.UpdateByMap(ctx, req.UserInfo.UserID, data); err != nil { - return nil, err - } - s.friendNotificationSender.UserInfoUpdatedNotification(ctx, req.UserInfo.UserID) - friends, err := s.friendRpcClient.GetFriendIDs(ctx, req.UserInfo.UserID) + oldUser, err := s.db.GetUserByID(ctx, req.UserInfo.UserID) if err != nil { return nil, err } - if req.UserInfo.Nickname != "" || req.UserInfo.FaceURL != "" { - if err = s.groupRpcClient.NotificationUserInfoUpdate(ctx, req.UserInfo.UserID); err != nil { - return nil, err - } - } - for _, friendID := range friends { - s.friendNotificationSender.FriendInfoUpdatedNotification(ctx, req.UserInfo.UserID, friendID) + if err := s.db.UpdateByMap(ctx, req.UserInfo.UserID, data); err != nil { + return nil, err } + s.friendNotificationSender.UserInfoUpdatedNotification(ctx, req.UserInfo.UserID) + //friends, err := s.friendRpcClient.GetFriendIDs(ctx, req.UserInfo.UserID) + //if err != nil { + // return nil, err + //} + //if req.UserInfo.Nickname != "" || req.UserInfo.FaceURL != "" { + // if err = s.NotificationUserInfoUpdate(ctx, req.UserInfo.UserID,oldUser); err != nil { + // return nil, err + // } + //} + //for _, friendID := range friends { + // s.friendNotificationSender.FriendInfoUpdatedNotification(ctx, req.UserInfo.UserID, friendID) + //} s.webhookAfterUpdateUserInfo(ctx, &s.config.WebhooksConfig.AfterUpdateUserInfo, req) - if err = s.groupRpcClient.NotificationUserInfoUpdate(ctx, req.UserInfo.UserID); err != nil { + if err = s.NotificationUserInfoUpdate(ctx, req.UserInfo.UserID, oldUser); err != nil { return nil, err } return resp, nil @@ -164,25 +171,29 @@ func (s *userServer) UpdateUserInfoEx(ctx context.Context, req *pbuser.UpdateUse if err = s.webhookBeforeUpdateUserInfoEx(ctx, &s.config.WebhooksConfig.BeforeUpdateUserInfoEx, req); err != nil { return nil, err } + oldUser, err := s.db.GetUserByID(ctx, req.UserInfo.UserID) + if err != nil { + return nil, err + } data := convert.UserPb2DBMapEx(req.UserInfo) if err = s.db.UpdateByMap(ctx, req.UserInfo.UserID, data); err != nil { return nil, err } s.friendNotificationSender.UserInfoUpdatedNotification(ctx, req.UserInfo.UserID) - friends, err := s.friendRpcClient.GetFriendIDs(ctx, req.UserInfo.UserID) - if err != nil { - return nil, err - } - if req.UserInfo.Nickname != nil || req.UserInfo.FaceURL != nil { - if err := s.groupRpcClient.NotificationUserInfoUpdate(ctx, req.UserInfo.UserID); err != nil { - return nil, err - } - } - for _, friendID := range friends { - s.friendNotificationSender.FriendInfoUpdatedNotification(ctx, req.UserInfo.UserID, friendID) - } + //friends, err := s.friendRpcClient.GetFriendIDs(ctx, req.UserInfo.UserID) + //if err != nil { + // return nil, err + //} + //if req.UserInfo.Nickname != nil || req.UserInfo.FaceURL != nil { + // if err := s.NotificationUserInfoUpdate(ctx, req.UserInfo.UserID); err != nil { + // return nil, err + // } + //} + //for _, friendID := range friends { + // s.friendNotificationSender.FriendInfoUpdatedNotification(ctx, req.UserInfo.UserID, friendID) + //} s.webhookAfterUpdateUserInfoEx(ctx, &s.config.WebhooksConfig.AfterUpdateUserInfoEx, req) - if err := s.groupRpcClient.NotificationUserInfoUpdate(ctx, req.UserInfo.UserID); err != nil { + if err := s.NotificationUserInfoUpdate(ctx, req.UserInfo.UserID, oldUser); err != nil { return nil, err } return resp, nil @@ -683,3 +694,45 @@ func (s *userServer) userModelToResp(users []*tablerelation.User, pagination pag return &pbuser.SearchNotificationAccountResp{Total: total, NotificationAccounts: notificationAccounts} } + +func (s *userServer) NotificationUserInfoUpdate(ctx context.Context, userID string, oldUser *tablerelation.User) error { + user, err := s.db.GetUserByID(ctx, userID) + if err != nil { + return err + } + if user.Nickname == oldUser.Nickname && user.FaceURL == oldUser.FaceURL { + return nil + } + oldUserInfo := convert.UserDB2Pb(oldUser) + newUserInfo := convert.UserDB2Pb(user) + var wg sync.WaitGroup + var es [2]error + wg.Add(len(es)) + go func() { + defer wg.Done() + _, es[0] = s.groupRpcClient.Client.NotificationUserInfoUpdate(ctx, &group.NotificationUserInfoUpdateReq{ + UserID: userID, + OldUserInfo: oldUserInfo, + NewUserInfo: newUserInfo, + }) + }() + + go func() { + defer wg.Done() + _, es[1] = s.friendRpcClient.Client.NotificationUserInfoUpdate(ctx, &friendpb.NotificationUserInfoUpdateReq{ + UserID: userID, + OldUserInfo: oldUserInfo, + NewUserInfo: newUserInfo, + }) + }() + wg.Wait() + return errors.Join(es[:]...) +} + +func (s *userServer) SortQuery(ctx context.Context, req *pbuser.SortQueryReq) (*pbuser.SortQueryResp, error) { + users, err := s.db.SortQuery(ctx, req.UserIDName, req.Asc) + if err != nil { + return nil, err + } + return &pbuser.SortQueryResp{Users: convert.UsersDB2Pb(users)}, nil +} diff --git a/pkg/common/cmd/group.go b/pkg/common/cmd/group.go index f158b8c626..20124be957 100644 --- a/pkg/common/cmd/group.go +++ b/pkg/common/cmd/group.go @@ -19,6 +19,7 @@ import ( "github.com/openimsdk/open-im-server/v3/internal/rpc/group" "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/startrpc" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/versionctx" "github.com/openimsdk/tools/system/program" "github.com/spf13/cobra" ) @@ -58,5 +59,5 @@ func (a *GroupRpcCmd) Exec() error { func (a *GroupRpcCmd) runE() error { return startrpc.Start(a.ctx, &a.groupConfig.Discovery, &a.groupConfig.RpcConfig.Prometheus, a.groupConfig.RpcConfig.RPC.ListenIP, a.groupConfig.RpcConfig.RPC.RegisterIP, a.groupConfig.RpcConfig.RPC.Ports, - a.Index(), a.groupConfig.Share.RpcRegisterName.Group, &a.groupConfig.Share, a.groupConfig, group.Start) + a.Index(), a.groupConfig.Share.RpcRegisterName.Group, &a.groupConfig.Share, a.groupConfig, group.Start, versionctx.EnableVersionCtx()) } diff --git a/pkg/common/cmd/msg_gateway_test.go b/pkg/common/cmd/msg_gateway_test.go index d820627b50..2b68a3e3ab 100644 --- a/pkg/common/cmd/msg_gateway_test.go +++ b/pkg/common/cmd/msg_gateway_test.go @@ -19,6 +19,7 @@ import ( "github.com/openimsdk/tools/apiresp" "github.com/openimsdk/tools/utils/jsonutil" "github.com/stretchr/testify/mock" + "go.mongodb.org/mongo-driver/bson/primitive" "math" "testing" ) @@ -59,3 +60,9 @@ func TestName(t *testing.T) { t.Logf("%+v\n", rReso) } + +func TestName1(t *testing.T) { + t.Log(primitive.NewObjectID().String()) + t.Log(primitive.NewObjectID().Hex()) + +} diff --git a/pkg/common/convert/user.go b/pkg/common/convert/user.go index ccc574f51b..d824fa68e0 100644 --- a/pkg/common/convert/user.go +++ b/pkg/common/convert/user.go @@ -16,26 +16,26 @@ package convert import ( relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model" + "github.com/openimsdk/tools/utils/datautil" "time" "github.com/openimsdk/protocol/sdkws" ) -func UsersDB2Pb(users []*relationtb.User) []*sdkws.UserInfo { - result := make([]*sdkws.UserInfo, 0, len(users)) - for _, user := range users { - userPb := &sdkws.UserInfo{ - UserID: user.UserID, - Nickname: user.Nickname, - FaceURL: user.FaceURL, - Ex: user.Ex, - CreateTime: user.CreateTime.UnixMilli(), - AppMangerLevel: user.AppMangerLevel, - GlobalRecvMsgOpt: user.GlobalRecvMsgOpt, - } - result = append(result, userPb) +func UserDB2Pb(user *relationtb.User) *sdkws.UserInfo { + return &sdkws.UserInfo{ + UserID: user.UserID, + Nickname: user.Nickname, + FaceURL: user.FaceURL, + Ex: user.Ex, + CreateTime: user.CreateTime.UnixMilli(), + AppMangerLevel: user.AppMangerLevel, + GlobalRecvMsgOpt: user.GlobalRecvMsgOpt, } - return result +} + +func UsersDB2Pb(users []*relationtb.User) []*sdkws.UserInfo { + return datautil.Slice(users, UserDB2Pb) } func UserPb2DB(user *sdkws.UserInfo) *relationtb.User { diff --git a/pkg/common/storage/cache/cachekey/friend.go b/pkg/common/storage/cache/cachekey/friend.go index 9691b1f5c9..8a053ca324 100644 --- a/pkg/common/storage/cache/cachekey/friend.go +++ b/pkg/common/storage/cache/cachekey/friend.go @@ -19,6 +19,8 @@ const ( TwoWayFriendsIDsKey = "COMMON_FRIENDS_IDS:" FriendKey = "FRIEND_INFO:" IsFriendKey = "IS_FRIEND:" // local cache key + //FriendSyncSortUserIDsKey = "FRIEND_SYNC_SORT_USER_IDS:" + FriendMaxVersionKey = "FRIEND_MAX_VERSION:" ) func GetFriendIDsKey(ownerUserID string) string { @@ -33,6 +35,14 @@ func GetFriendKey(ownerUserID, friendUserID string) string { return FriendKey + ownerUserID + "-" + friendUserID } +func GetFriendMaxVersionKey(ownerUserID string) string { + return FriendMaxVersionKey + ownerUserID +} + func GetIsFriendKey(possibleFriendUserID, userID string) string { return IsFriendKey + possibleFriendUserID + "-" + userID } + +//func GetFriendSyncSortUserIDsKey(ownerUserID string, count int) string { +// return FriendSyncSortUserIDsKey + strconv.Itoa(count) + ":" + ownerUserID +//} diff --git a/pkg/common/storage/cache/cachekey/group.go b/pkg/common/storage/cache/cachekey/group.go index 681121ecba..2ef42c0ff4 100644 --- a/pkg/common/storage/cache/cachekey/group.go +++ b/pkg/common/storage/cache/cachekey/group.go @@ -28,6 +28,8 @@ const ( JoinedGroupsKey = "JOIN_GROUPS_KEY:" GroupMemberNumKey = "GROUP_MEMBER_NUM_CACHE:" GroupRoleLevelMemberIDsKey = "GROUP_ROLE_LEVEL_MEMBER_IDS:" + GroupMemberMaxVersionKey = "GROUP_MEMBER_MAX_VERSION:" + GroupJoinMaxVersionKey = "GROUP_JOIN_MAX_VERSION:" ) func GetGroupInfoKey(groupID string) string { @@ -57,3 +59,11 @@ func GetGroupMemberNumKey(groupID string) string { func GetGroupRoleLevelMemberIDsKey(groupID string, roleLevel int32) string { return GroupRoleLevelMemberIDsKey + groupID + "-" + strconv.Itoa(int(roleLevel)) } + +func GetGroupMemberMaxVersionKey(groupID string) string { + return GroupMemberMaxVersionKey + groupID +} + +func GetJoinGroupMaxVersionKey(userID string) string { + return GroupJoinMaxVersionKey + userID +} diff --git a/pkg/common/storage/cache/friend.go b/pkg/common/storage/cache/friend.go index acff829f86..b451d36757 100644 --- a/pkg/common/storage/cache/friend.go +++ b/pkg/common/storage/cache/friend.go @@ -32,4 +32,16 @@ type FriendCache interface { DelFriend(ownerUserID, friendUserID string) FriendCache // Delete friends when friends' info changed DelFriends(ownerUserID string, friendUserIDs []string) FriendCache + + DelOwner(friendUserID string, ownerUserIDs []string) FriendCache + + DelMaxFriendVersion(ownerUserIDs ...string) FriendCache + + //DelSortFriendUserIDs(ownerUserIDs ...string) FriendCache + + //FindSortFriendUserIDs(ctx context.Context, ownerUserID string) ([]string, error) + + //FindFriendIncrVersion(ctx context.Context, ownerUserID string, version uint, limit int) (*relationtb.VersionLog, error) + + FindMaxFriendVersion(ctx context.Context, ownerUserID string) (*relationtb.VersionLog, error) } diff --git a/pkg/common/storage/cache/group.go b/pkg/common/storage/cache/group.go index 53e2cd1c74..73479bb1bb 100644 --- a/pkg/common/storage/cache/group.go +++ b/pkg/common/storage/cache/group.go @@ -46,7 +46,6 @@ type GroupCache interface { GetGroupMemberInfo(ctx context.Context, groupID, userID string) (groupMember *model.GroupMember, err error) GetGroupMembersInfo(ctx context.Context, groupID string, userID []string) (groupMembers []*model.GroupMember, err error) GetAllGroupMembersInfo(ctx context.Context, groupID string) (groupMembers []*model.GroupMember, err error) - GetGroupMembersPage(ctx context.Context, groupID string, userID []string, showNumber, pageNumber int32) (total uint32, groupMembers []*model.GroupMember, err error) FindGroupMemberUser(ctx context.Context, groupIDs []string, userID string) ([]*model.GroupMember, error) GetGroupRoleLevelMemberIDs(ctx context.Context, groupID string, roleLevel int32) ([]string, error) @@ -59,4 +58,12 @@ type GroupCache interface { GetGroupRolesLevelMemberInfo(ctx context.Context, groupID string, roleLevels []int32) ([]*model.GroupMember, error) GetGroupMemberNum(ctx context.Context, groupID string) (memberNum int64, err error) DelGroupsMemberNum(groupID ...string) GroupCache + + //FindSortGroupMemberUserIDs(ctx context.Context, groupID string) ([]string, error) + //FindSortJoinGroupIDs(ctx context.Context, userID string) ([]string, error) + + DelMaxGroupMemberVersion(groupIDs ...string) GroupCache + DelMaxJoinGroupVersion(userIDs ...string) GroupCache + FindMaxGroupMemberVersion(ctx context.Context, groupID string) (*model.VersionLog, error) + FindMaxJoinGroupVersion(ctx context.Context, userID string) (*model.VersionLog, error) } diff --git a/pkg/common/storage/cache/redis/friend.go b/pkg/common/storage/cache/redis/friend.go index f76e5ff6ba..01988310c9 100644 --- a/pkg/common/storage/cache/redis/friend.go +++ b/pkg/common/storage/cache/redis/friend.go @@ -16,6 +16,8 @@ package redis import ( "context" + "time" + "github.com/dtm-labs/rockscache" "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/storage/cache" @@ -25,7 +27,6 @@ import ( "github.com/openimsdk/tools/log" "github.com/openimsdk/tools/utils/datautil" "github.com/redis/go-redis/v9" - "time" ) const ( @@ -38,6 +39,7 @@ type FriendCacheRedis struct { friendDB database.Friend expireTime time.Duration rcClient *rockscache.Client + syncCount int } // NewFriendCacheRedis creates a new instance of FriendCacheRedis. @@ -68,6 +70,14 @@ func (f *FriendCacheRedis) getFriendIDsKey(ownerUserID string) string { return cachekey.GetFriendIDsKey(ownerUserID) } +//func (f *FriendCacheRedis) getFriendSyncSortUserIDsKey(ownerUserID string) string { +// return cachekey.GetFriendSyncSortUserIDsKey(ownerUserID, f.syncCount) +//} + +func (f *FriendCacheRedis) getFriendMaxVersionKey(ownerUserID string) string { + return cachekey.GetFriendMaxVersionKey(ownerUserID) +} + // getTwoWayFriendsIDsKey returns the key for storing two-way friend IDs in the cache. func (f *FriendCacheRedis) getTwoWayFriendsIDsKey(ownerUserID string) string { return cachekey.GetTwoWayFriendsIDsKey(ownerUserID) @@ -97,6 +107,16 @@ func (f *FriendCacheRedis) DelFriendIDs(ownerUserIDs ...string) cache.FriendCach return newFriendCache } +//func (f *FriendCacheRedis) DelSortFriendUserIDs(ownerUserIDs ...string) cache.FriendCache { +// newGroupCache := f.CloneFriendCache() +// keys := make([]string, 0, len(ownerUserIDs)) +// for _, userID := range ownerUserIDs { +// keys = append(keys, f.getFriendSyncSortUserIDsKey(userID)) +// } +// newGroupCache.AddKeys(keys...) +// return newGroupCache +//} + // GetTwoWayFriendIDs retrieves two-way friend IDs from the cache. func (f *FriendCacheRedis) GetTwoWayFriendIDs(ctx context.Context, ownerUserID string) (twoWayFriendIDs []string, err error) { friendIDs, err := f.GetFriendIDs(ctx, ownerUserID) @@ -151,3 +171,41 @@ func (f *FriendCacheRedis) DelFriends(ownerUserID string, friendUserIDs []string return newFriendCache } + +func (f *FriendCacheRedis) DelOwner(friendUserID string, ownerUserIDs []string) cache.FriendCache { + newFriendCache := f.CloneFriendCache() + + for _, ownerUserID := range ownerUserIDs { + key := f.getFriendKey(ownerUserID, friendUserID) + newFriendCache.AddKeys(key) // Assuming AddKeys marks the keys for deletion + } + + return newFriendCache +} + +func (f *FriendCacheRedis) DelMaxFriendVersion(ownerUserIDs ...string) cache.FriendCache { + newFriendCache := f.CloneFriendCache() + for _, ownerUserID := range ownerUserIDs { + key := f.getFriendMaxVersionKey(ownerUserID) + newFriendCache.AddKeys(key) // Assuming AddKeys marks the keys for deletion + } + + return newFriendCache +} + +//func (f *FriendCacheRedis) FindSortFriendUserIDs(ctx context.Context, ownerUserID string) ([]string, error) { +// userIDs, err := f.GetFriendIDs(ctx, ownerUserID) +// if err != nil { +// return nil, err +// } +// if len(userIDs) > f.syncCount { +// userIDs = userIDs[:f.syncCount] +// } +// return userIDs, nil +//} + +func (f *FriendCacheRedis) FindMaxFriendVersion(ctx context.Context, ownerUserID string) (*model.VersionLog, error) { + return getCache(ctx, f.rcClient, f.getFriendMaxVersionKey(ownerUserID), f.expireTime, func(ctx context.Context) (*model.VersionLog, error) { + return f.friendDB.FindIncrVersion(ctx, ownerUserID, 0, 0) + }) +} diff --git a/pkg/common/storage/cache/redis/group.go b/pkg/common/storage/cache/redis/group.go index 2de03906f1..589678c506 100644 --- a/pkg/common/storage/cache/redis/group.go +++ b/pkg/common/storage/cache/redis/group.go @@ -27,7 +27,6 @@ import ( "github.com/openimsdk/protocol/constant" "github.com/openimsdk/tools/errs" "github.com/openimsdk/tools/log" - "github.com/openimsdk/tools/utils/datautil" "github.com/redis/go-redis/v9" "time" ) @@ -111,6 +110,14 @@ func (g *GroupCacheRedis) getGroupRoleLevelMemberIDsKey(groupID string, roleLeve return cachekey.GetGroupRoleLevelMemberIDsKey(groupID, roleLevel) } +func (g *GroupCacheRedis) getGroupMemberMaxVersionKey(groupID string) string { + return cachekey.GetGroupMemberMaxVersionKey(groupID) +} + +func (g *GroupCacheRedis) getJoinGroupMaxVersionKey(userID string) string { + return cachekey.GetJoinGroupMaxVersionKey(userID) +} + func (g *GroupCacheRedis) GetGroupIndex(group *model.Group, keys []string) (int, error) { key := g.getGroupInfoKey(group.GroupID) for i, _key := range keys { @@ -246,9 +253,17 @@ func (g *GroupCacheRedis) DelGroupMemberIDs(groupID string) cache.GroupCache { return cache } +func (g *GroupCacheRedis) findUserJoinedGroupID(ctx context.Context, userID string) ([]string, error) { + groupIDs, err := g.groupMemberDB.FindUserJoinedGroupID(ctx, userID) + if err != nil { + return nil, err + } + return g.groupDB.FindJoinSortGroupID(ctx, groupIDs) +} + func (g *GroupCacheRedis) GetJoinedGroupIDs(ctx context.Context, userID string) (joinedGroupIDs []string, err error) { return getCache(ctx, g.rcClient, g.getJoinedGroupsKey(userID), g.expireTime, func(ctx context.Context) ([]string, error) { - return g.groupMemberDB.FindUserJoinedGroupID(ctx, userID) + return g.findUserJoinedGroupID(ctx, userID) }) } @@ -277,26 +292,6 @@ func (g *GroupCacheRedis) GetGroupMembersInfo(ctx context.Context, groupID strin }) } -func (g *GroupCacheRedis) GetGroupMembersPage( - ctx context.Context, - groupID string, - userIDs []string, - showNumber, pageNumber int32, -) (total uint32, groupMembers []*model.GroupMember, err error) { - groupMemberIDs, err := g.GetGroupMemberIDs(ctx, groupID) - if err != nil { - return 0, nil, err - } - if userIDs != nil { - userIDs = datautil.BothExist(userIDs, groupMemberIDs) - } else { - userIDs = groupMemberIDs - } - groupMembers, err = g.GetGroupMembersInfo(ctx, groupID, datautil.Paginate(userIDs, int(showNumber), int(showNumber))) - - return uint32(len(userIDs)), groupMembers, err -} - func (g *GroupCacheRedis) GetAllGroupMembersInfo(ctx context.Context, groupID string) (groupMembers []*model.GroupMember, err error) { groupMemberIDs, err := g.GetGroupMemberIDs(ctx, groupID) if err != nil { @@ -406,3 +401,57 @@ func (g *GroupCacheRedis) FindGroupMemberUser(ctx context.Context, groupIDs []st return g.groupMemberDB.Take(ctx, groupID, userID) }) } + +//func (g *GroupCacheRedis) FindSortGroupMemberUserIDs(ctx context.Context, groupID string) ([]string, error) { +// userIDs, err := g.GetGroupMemberIDs(ctx, groupID) +// if err != nil { +// return nil, err +// } +// if len(userIDs) > g.syncCount { +// userIDs = userIDs[:g.syncCount] +// } +// return userIDs, nil +//} +// +//func (g *GroupCacheRedis) FindSortJoinGroupIDs(ctx context.Context, userID string) ([]string, error) { +// groupIDs, err := g.GetJoinedGroupIDs(ctx, userID) +// if err != nil { +// return nil, err +// } +// if len(groupIDs) > g.syncCount { +// groupIDs = groupIDs[:g.syncCount] +// } +// return groupIDs, nil +//} + +func (g *GroupCacheRedis) DelMaxGroupMemberVersion(groupIDs ...string) cache.GroupCache { + keys := make([]string, 0, len(groupIDs)) + for _, groupID := range groupIDs { + keys = append(keys, g.getGroupMemberMaxVersionKey(groupID)) + } + cache := g.CloneGroupCache() + cache.AddKeys(keys...) + return cache +} + +func (g *GroupCacheRedis) DelMaxJoinGroupVersion(userIDs ...string) cache.GroupCache { + keys := make([]string, 0, len(userIDs)) + for _, userID := range userIDs { + keys = append(keys, g.getJoinGroupMaxVersionKey(userID)) + } + cache := g.CloneGroupCache() + cache.AddKeys(keys...) + return cache +} + +func (g *GroupCacheRedis) FindMaxGroupMemberVersion(ctx context.Context, groupID string) (*model.VersionLog, error) { + return getCache(ctx, g.rcClient, g.getGroupMemberMaxVersionKey(groupID), g.expireTime, func(ctx context.Context) (*model.VersionLog, error) { + return g.groupMemberDB.FindMemberIncrVersion(ctx, groupID, 0, 0) + }) +} + +func (g *GroupCacheRedis) FindMaxJoinGroupVersion(ctx context.Context, userID string) (*model.VersionLog, error) { + return getCache(ctx, g.rcClient, g.getJoinGroupMaxVersionKey(userID), g.expireTime, func(ctx context.Context) (*model.VersionLog, error) { + return g.groupMemberDB.FindJoinIncrVersion(ctx, userID, 0, 0) + }) +} diff --git a/pkg/common/storage/controller/friend.go b/pkg/common/storage/controller/friend.go index 1c3d9f139a..e402f5980b 100644 --- a/pkg/common/storage/controller/friend.go +++ b/pkg/common/storage/controller/friend.go @@ -77,6 +77,16 @@ type FriendDatabase interface { // UpdateFriends updates fields for friends UpdateFriends(ctx context.Context, ownerUserID string, friendUserIDs []string, val map[string]any) (err error) + + //FindSortFriendUserIDs(ctx context.Context, ownerUserID string) ([]string, error) + + FindFriendIncrVersion(ctx context.Context, ownerUserID string, version uint, limit int) (*model.VersionLog, error) + + FindMaxFriendVersionCache(ctx context.Context, ownerUserID string) (*model.VersionLog, error) + + FindFriendUserID(ctx context.Context, friendUserID string) ([]string, error) + + OwnerIncrVersion(ctx context.Context, ownerUserID string, friendUserIDs []string, state int32) error } type friendDatabase struct { @@ -175,7 +185,7 @@ func (f *friendDatabase) BecomeFriends(ctx context.Context, ownerUserID string, return err } newFriendIDs = append(newFriendIDs, ownerUserID) - cache = cache.DelFriendIDs(newFriendIDs...) + cache = cache.DelFriendIDs(newFriendIDs...).DelMaxFriendVersion(newFriendIDs...) return cache.ChainExecDel(ctx) }) @@ -278,7 +288,7 @@ func (f *friendDatabase) AgreeFriendRequest(ctx context.Context, friendRequest * return err } } - return f.cache.DelFriendIDs(friendRequest.ToUserID, friendRequest.FromUserID).ChainExecDel(ctx) + return f.cache.DelFriendIDs(friendRequest.ToUserID, friendRequest.FromUserID).DelMaxFriendVersion(friendRequest.ToUserID, friendRequest.FromUserID).ChainExecDel(ctx) }) } @@ -287,7 +297,8 @@ func (f *friendDatabase) Delete(ctx context.Context, ownerUserID string, friendU if err := f.friend.Delete(ctx, ownerUserID, friendUserIDs); err != nil { return err } - return f.cache.DelFriendIDs(append(friendUserIDs, ownerUserID)...).ChainExecDel(ctx) + userIds := append(friendUserIDs, ownerUserID) + return f.cache.DelFriendIDs(userIds...).DelMaxFriendVersion(userIds...).ChainExecDel(ctx) } // UpdateRemark updates the remark for a friend. Zero value for remark is also supported. @@ -295,7 +306,7 @@ func (f *friendDatabase) UpdateRemark(ctx context.Context, ownerUserID, friendUs if err := f.friend.UpdateRemark(ctx, ownerUserID, friendUserID, remark); err != nil { return err } - return f.cache.DelFriend(ownerUserID, friendUserID).ChainExecDel(ctx) + return f.cache.DelFriend(ownerUserID, friendUserID).DelMaxFriendVersion(ownerUserID).ChainExecDel(ctx) } // PageOwnerFriends retrieves the list of friends for the ownerUserID. It does not return an error if the result is empty. @@ -324,9 +335,6 @@ func (f *friendDatabase) FindFriendsWithError(ctx context.Context, ownerUserID s if err != nil { return } - if len(friends) != len(friendUserIDs) { - err = errs.ErrRecordNotFound.Wrap() - } return } @@ -341,8 +349,37 @@ func (f *friendDatabase) UpdateFriends(ctx context.Context, ownerUserID string, if len(val) == 0 { return nil } - if err := f.friend.UpdateFriends(ctx, ownerUserID, friendUserIDs, val); err != nil { + return f.tx.Transaction(ctx, func(ctx context.Context) error { + if err := f.friend.UpdateFriends(ctx, ownerUserID, friendUserIDs, val); err != nil { + return err + } + return f.cache.DelFriends(ownerUserID, friendUserIDs).DelMaxFriendVersion(ownerUserID).ChainExecDel(ctx) + }) +} + +//func (f *friendDatabase) FindSortFriendUserIDs(ctx context.Context, ownerUserID string) ([]string, error) { +// return f.cache.FindSortFriendUserIDs(ctx, ownerUserID) +//} + +func (f *friendDatabase) FindFriendIncrVersion(ctx context.Context, ownerUserID string, version uint, limit int) (*model.VersionLog, error) { + return f.friend.FindIncrVersion(ctx, ownerUserID, version, limit) +} + +func (f *friendDatabase) FindMaxFriendVersionCache(ctx context.Context, ownerUserID string) (*model.VersionLog, error) { + return f.cache.FindMaxFriendVersion(ctx, ownerUserID) +} + +func (f *friendDatabase) FindFriendUserID(ctx context.Context, friendUserID string) ([]string, error) { + return f.friend.FindFriendUserID(ctx, friendUserID) +} + +//func (f *friendDatabase) SearchFriend(ctx context.Context, ownerUserID, keyword string, pagination pagination.Pagination) (int64, []*model.Friend, error) { +// return f.friend.SearchFriend(ctx, ownerUserID, keyword, pagination) +//} + +func (f *friendDatabase) OwnerIncrVersion(ctx context.Context, ownerUserID string, friendUserIDs []string, state int32) error { + if err := f.friend.IncrVersion(ctx, ownerUserID, friendUserIDs, state); err != nil { return err } - return f.cache.DelFriends(ownerUserID, friendUserIDs).ChainExecDel(ctx) + return f.cache.DelMaxFriendVersion(ownerUserID).ChainExecDel(ctx) } diff --git a/pkg/common/storage/controller/group.go b/pkg/common/storage/controller/group.go index f2a1358357..3a5f48d4c6 100644 --- a/pkg/common/storage/controller/group.go +++ b/pkg/common/storage/controller/group.go @@ -106,6 +106,20 @@ type GroupDatabase interface { CountRangeEverydayTotal(ctx context.Context, start time.Time, end time.Time) (map[string]int64, error) // DeleteGroupMemberHash deletes the hash entries for group members in specified groups. DeleteGroupMemberHash(ctx context.Context, groupIDs []string) error + + FindMemberIncrVersion(ctx context.Context, groupID string, version uint, limit int) (*model.VersionLog, error) + FindJoinIncrVersion(ctx context.Context, userID string, version uint, limit int) (*model.VersionLog, error) + MemberGroupIncrVersion(ctx context.Context, groupID string, userIDs []string, state int32) error + + //FindSortGroupMemberUserIDs(ctx context.Context, groupID string) ([]string, error) + //FindSortJoinGroupIDs(ctx context.Context, userID string) ([]string, error) + + FindMaxGroupMemberVersionCache(ctx context.Context, groupID string) (*model.VersionLog, error) + FindMaxJoinGroupVersionCache(ctx context.Context, userID string) (*model.VersionLog, error) + + SearchJoinGroup(ctx context.Context, userID string, keyword string, pagination pagination.Pagination) (int64, []*model.Group, error) + + FindJoinGroupID(ctx context.Context, userID string) ([]string, error) } func NewGroupDatabase( @@ -134,6 +148,10 @@ type groupDatabase struct { cache cache.GroupCache } +func (g *groupDatabase) FindJoinGroupID(ctx context.Context, userID string) ([]string, error) { + return g.cache.GetJoinedGroupIDs(ctx, userID) +} + func (g *groupDatabase) FindGroupMembers(ctx context.Context, groupID string, userIDs []string) ([]*model.GroupMember, error) { return g.cache.GetGroupMembersInfo(ctx, groupID, userIDs) } @@ -174,7 +192,8 @@ func (g *groupDatabase) CreateGroup(ctx context.Context, groups []*model.Group, DelGroupMembersHash(group.GroupID). DelGroupsMemberNum(group.GroupID). DelGroupMemberIDs(group.GroupID). - DelGroupAllRoleLevel(group.GroupID) + DelGroupAllRoleLevel(group.GroupID). + DelMaxGroupMemberVersion(group.GroupID) } } if len(groupMembers) > 0 { @@ -187,7 +206,9 @@ func (g *groupDatabase) CreateGroup(ctx context.Context, groups []*model.Group, DelGroupMemberIDs(groupMember.GroupID). DelJoinedGroupID(groupMember.UserID). DelGroupMembersInfo(groupMember.GroupID, groupMember.UserID). - DelGroupAllRoleLevel(groupMember.GroupID) + DelGroupAllRoleLevel(groupMember.GroupID). + DelMaxJoinGroupVersion(groupMember.UserID). + DelMaxGroupMemberVersion(groupMember.GroupID) } } return c.ChainExecDel(ctx) @@ -219,10 +240,15 @@ func (g *groupDatabase) SearchGroup(ctx context.Context, keyword string, paginat } func (g *groupDatabase) UpdateGroup(ctx context.Context, groupID string, data map[string]any) error { - if err := g.groupDB.UpdateMap(ctx, groupID, data); err != nil { - return err - } - return g.cache.DelGroupsInfo(groupID).ChainExecDel(ctx) + return g.ctxTx.Transaction(ctx, func(ctx context.Context) error { + if err := g.groupDB.UpdateMap(ctx, groupID, data); err != nil { + return err + } + if err := g.groupMemberDB.MemberGroupIncrVersion(ctx, groupID, []string{""}, model.VersionStateUpdate); err != nil { + return err + } + return g.cache.CloneGroupCache().DelGroupsInfo(groupID).DelMaxGroupMemberVersion(groupID).ChainExecDel(ctx) + }) } func (g *groupDatabase) DismissGroup(ctx context.Context, groupID string, deleteMember bool) error { @@ -244,7 +270,19 @@ func (g *groupDatabase) DismissGroup(ctx context.Context, groupID string, delete DelGroupsMemberNum(groupID). DelGroupMembersHash(groupID). DelGroupAllRoleLevel(groupID). - DelGroupMembersInfo(groupID, userIDs...) + DelGroupMembersInfo(groupID, userIDs...). + DelMaxGroupMemberVersion(groupID). + DelMaxJoinGroupVersion(userIDs...) + for _, userID := range userIDs { + if err := g.groupMemberDB.JoinGroupIncrVersion(ctx, userID, []string{groupID}, model.VersionStateDelete); err != nil { + return err + } + } + } else { + if err := g.groupMemberDB.MemberGroupIncrVersion(ctx, groupID, []string{""}, model.VersionStateUpdate); err != nil { + return err + } + c = c.DelMaxGroupMemberVersion(groupID) } return c.DelGroupsInfo(groupID).ChainExecDel(ctx) }) @@ -316,7 +354,9 @@ func (g *groupDatabase) HandlerGroupRequest(ctx context.Context, groupID string, DelGroupMemberIDs(groupID). DelGroupsMemberNum(groupID). DelJoinedGroupID(member.UserID). - DelGroupRoleLevel(groupID, []int32{member.RoleLevel}) + DelGroupRoleLevel(groupID, []int32{member.RoleLevel}). + DelMaxJoinGroupVersion(userID). + DelMaxGroupMemberVersion(groupID) if err := c.ChainExecDel(ctx); err != nil { return err } @@ -326,17 +366,21 @@ func (g *groupDatabase) HandlerGroupRequest(ctx context.Context, groupID string, } func (g *groupDatabase) DeleteGroupMember(ctx context.Context, groupID string, userIDs []string) error { - if err := g.groupMemberDB.Delete(ctx, groupID, userIDs); err != nil { - return err - } - c := g.cache.CloneGroupCache() - return c.DelGroupMembersHash(groupID). - DelGroupMemberIDs(groupID). - DelGroupsMemberNum(groupID). - DelJoinedGroupID(userIDs...). - DelGroupMembersInfo(groupID, userIDs...). - DelGroupAllRoleLevel(groupID). - ChainExecDel(ctx) + return g.ctxTx.Transaction(ctx, func(ctx context.Context) error { + if err := g.groupMemberDB.Delete(ctx, groupID, userIDs); err != nil { + return err + } + c := g.cache.CloneGroupCache() + return c.DelGroupMembersHash(groupID). + DelGroupMemberIDs(groupID). + DelGroupsMemberNum(groupID). + DelJoinedGroupID(userIDs...). + DelGroupMembersInfo(groupID, userIDs...). + DelGroupAllRoleLevel(groupID). + DelMaxGroupMemberVersion(groupID). + DelMaxJoinGroupVersion(userIDs...). + ChainExecDel(ctx) + }) } func (g *groupDatabase) MapGroupMemberUserID(ctx context.Context, groupIDs []string) (map[string]*common.GroupSimpleUserID, error) { @@ -357,29 +401,35 @@ func (g *groupDatabase) MapGroupMemberNum(ctx context.Context, groupIDs []string func (g *groupDatabase) TransferGroupOwner(ctx context.Context, groupID string, oldOwnerUserID, newOwnerUserID string, roleLevel int32) error { return g.ctxTx.Transaction(ctx, func(ctx context.Context) error { - if err := g.groupMemberDB.UpdateRoleLevel(ctx, groupID, oldOwnerUserID, roleLevel); err != nil { - return err - } - if err := g.groupMemberDB.UpdateRoleLevel(ctx, groupID, newOwnerUserID, constant.GroupOwner); err != nil { + if err := g.groupMemberDB.UpdateUserRoleLevels(ctx, groupID, oldOwnerUserID, roleLevel, newOwnerUserID, constant.GroupOwner); err != nil { return err } c := g.cache.CloneGroupCache() return c.DelGroupMembersInfo(groupID, oldOwnerUserID, newOwnerUserID). DelGroupAllRoleLevel(groupID). - DelGroupMembersHash(groupID).ChainExecDel(ctx) + DelGroupMembersHash(groupID). + DelMaxGroupMemberVersion(groupID). + DelGroupMemberIDs(groupID). + ChainExecDel(ctx) }) } func (g *groupDatabase) UpdateGroupMember(ctx context.Context, groupID string, userID string, data map[string]any) error { - if err := g.groupMemberDB.Update(ctx, groupID, userID, data); err != nil { - return err - } - c := g.cache.CloneGroupCache() - c = c.DelGroupMembersInfo(groupID, userID) - if g.groupMemberDB.IsUpdateRoleLevel(data) { - c = c.DelGroupAllRoleLevel(groupID) + if len(data) == 0 { + return nil } - return c.ChainExecDel(ctx) + return g.ctxTx.Transaction(ctx, func(ctx context.Context) error { + if err := g.groupMemberDB.Update(ctx, groupID, userID, data); err != nil { + return err + } + c := g.cache.CloneGroupCache() + c = c.DelGroupMembersInfo(groupID, userID) + if g.groupMemberDB.IsUpdateRoleLevel(data) { + c = c.DelGroupAllRoleLevel(groupID).DelGroupMemberIDs(groupID) + } + c = c.DelMaxGroupMemberVersion(groupID) + return c.ChainExecDel(ctx) + }) } func (g *groupDatabase) UpdateGroupMembers(ctx context.Context, data []*common.BatchUpdateGroupMember) error { @@ -390,9 +440,9 @@ func (g *groupDatabase) UpdateGroupMembers(ctx context.Context, data []*common.B return err } if g.groupMemberDB.IsUpdateRoleLevel(item.Map) { - c = c.DelGroupAllRoleLevel(item.GroupID) + c = c.DelGroupAllRoleLevel(item.GroupID).DelGroupMemberIDs(item.GroupID) } - c = c.DelGroupMembersInfo(item.GroupID, item.UserID).DelGroupMembersHash(item.GroupID) + c = c.DelGroupMembersInfo(item.GroupID, item.UserID).DelMaxGroupMemberVersion(item.GroupID).DelGroupMembersHash(item.GroupID) } return c.ChainExecDel(ctx) }) @@ -443,3 +493,34 @@ func (g *groupDatabase) DeleteGroupMemberHash(ctx context.Context, groupIDs []st } return c.ChainExecDel(ctx) } + +func (g *groupDatabase) FindMemberIncrVersion(ctx context.Context, groupID string, version uint, limit int) (*model.VersionLog, error) { + return g.groupMemberDB.FindMemberIncrVersion(ctx, groupID, version, limit) +} + +func (g *groupDatabase) FindJoinIncrVersion(ctx context.Context, userID string, version uint, limit int) (*model.VersionLog, error) { + return g.groupMemberDB.FindJoinIncrVersion(ctx, userID, version, limit) +} + +func (g *groupDatabase) FindMaxGroupMemberVersionCache(ctx context.Context, groupID string) (*model.VersionLog, error) { + return g.cache.FindMaxGroupMemberVersion(ctx, groupID) +} + +func (g *groupDatabase) FindMaxJoinGroupVersionCache(ctx context.Context, userID string) (*model.VersionLog, error) { + return g.cache.FindMaxJoinGroupVersion(ctx, userID) +} + +func (g *groupDatabase) SearchJoinGroup(ctx context.Context, userID string, keyword string, pagination pagination.Pagination) (int64, []*model.Group, error) { + groupIDs, err := g.cache.GetJoinedGroupIDs(ctx, userID) + if err != nil { + return 0, nil, err + } + return g.groupDB.SearchJoin(ctx, groupIDs, keyword, pagination) +} + +func (g *groupDatabase) MemberGroupIncrVersion(ctx context.Context, groupID string, userIDs []string, state int32) error { + if err := g.groupMemberDB.MemberGroupIncrVersion(ctx, groupID, userIDs, state); err != nil { + return err + } + return g.cache.DelMaxGroupMemberVersion(groupID).ChainExecDel(ctx) +} diff --git a/pkg/common/storage/controller/user.go b/pkg/common/storage/controller/user.go index 09dc2db22b..9efe535c01 100644 --- a/pkg/common/storage/controller/user.go +++ b/pkg/common/storage/controller/user.go @@ -60,6 +60,8 @@ type UserDatabase interface { CountTotal(ctx context.Context, before *time.Time) (int64, error) // CountRangeEverydayTotal Get the user increment in the range CountRangeEverydayTotal(ctx context.Context, start time.Time, end time.Time) (map[string]int64, error) + + SortQuery(ctx context.Context, userIDName map[string]string, asc bool) ([]*model.User, error) // SubscribeUsersStatus Subscribe a user's presence status SubscribeUsersStatus(ctx context.Context, userID string, userIDs []string) error // UnsubscribeUsersStatus unsubscribe a user's presence status @@ -210,6 +212,10 @@ func (u *userDatabase) CountRangeEverydayTotal(ctx context.Context, start time.T return u.userDB.CountRangeEverydayTotal(ctx, start, end) } +func (u *userDatabase) SortQuery(ctx context.Context, userIDName map[string]string, asc bool) ([]*model.User, error) { + return u.userDB.SortQuery(ctx, userIDName, asc) +} + // SubscribeUsersStatus Subscribe or unsubscribe a user's presence status. func (u *userDatabase) SubscribeUsersStatus(ctx context.Context, userID string, userIDs []string) error { err := u.mongoDB.AddSubscriptionList(ctx, userID, userIDs) diff --git a/pkg/common/storage/database/friend.go b/pkg/common/storage/database/friend.go index 33d9c17bc5..b596411fce 100644 --- a/pkg/common/storage/database/friend.go +++ b/pkg/common/storage/database/friend.go @@ -16,6 +16,7 @@ package database import ( "context" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model" "github.com/openimsdk/tools/db/pagination" ) @@ -46,4 +47,14 @@ type Friend interface { FindFriendUserIDs(ctx context.Context, ownerUserID string) (friendUserIDs []string, err error) // UpdateFriends update friends' fields UpdateFriends(ctx context.Context, ownerUserID string, friendUserIDs []string, val map[string]any) (err error) + + FindIncrVersion(ctx context.Context, ownerUserID string, version uint, limit int) (*model.VersionLog, error) + + FindFriendUserID(ctx context.Context, friendUserID string) ([]string, error) + + //SearchFriend(ctx context.Context, ownerUserID, keyword string, pagination pagination.Pagination) (int64, []*model.Friend, error) + + FindOwnerFriendUserIds(ctx context.Context, ownerUserID string, limit int) ([]string, error) + + IncrVersion(ctx context.Context, ownerUserID string, friendUserIDs []string, state int32) error } diff --git a/pkg/common/storage/database/group.go b/pkg/common/storage/database/group.go index 712db09d2d..7ef22f6c9a 100644 --- a/pkg/common/storage/database/group.go +++ b/pkg/common/storage/database/group.go @@ -32,4 +32,8 @@ type Group interface { CountTotal(ctx context.Context, before *time.Time) (count int64, err error) // Get Group total quantity every day CountRangeEverydayTotal(ctx context.Context, start time.Time, end time.Time) (map[string]int64, error) + + FindJoinSortGroupID(ctx context.Context, groupIDs []string) ([]string, error) + + SearchJoin(ctx context.Context, groupIDs []string, keyword string, pagination pagination.Pagination) (int64, []*model.Group, error) } diff --git a/pkg/common/storage/database/group_member.go b/pkg/common/storage/database/group_member.go index f57f2c3173..c272b6ef6f 100644 --- a/pkg/common/storage/database/group_member.go +++ b/pkg/common/storage/database/group_member.go @@ -25,6 +25,7 @@ type GroupMember interface { Delete(ctx context.Context, groupID string, userIDs []string) (err error) Update(ctx context.Context, groupID string, userID string, data map[string]any) (err error) UpdateRoleLevel(ctx context.Context, groupID string, userID string, roleLevel int32) error + UpdateUserRoleLevels(ctx context.Context, groupID string, firstUserID string, firstUserRoleLevel int32, secondUserID string, secondUserRoleLevel int32) error FindMemberUserID(ctx context.Context, groupID string) (userIDs []string, err error) Take(ctx context.Context, groupID string, userID string) (groupMember *model.GroupMember, err error) TakeOwner(ctx context.Context, groupID string) (groupMember *model.GroupMember, err error) @@ -34,4 +35,8 @@ type GroupMember interface { TakeGroupMemberNum(ctx context.Context, groupID string) (count int64, err error) FindUserManagedGroupID(ctx context.Context, userID string) (groupIDs []string, err error) IsUpdateRoleLevel(data map[string]any) bool + JoinGroupIncrVersion(ctx context.Context, userID string, groupIDs []string, state int32) error + MemberGroupIncrVersion(ctx context.Context, groupID string, userIDs []string, state int32) error + FindMemberIncrVersion(ctx context.Context, groupID string, version uint, limit int) (*model.VersionLog, error) + FindJoinIncrVersion(ctx context.Context, userID string, version uint, limit int) (*model.VersionLog, error) } diff --git a/pkg/common/storage/database/mgo/black.go b/pkg/common/storage/database/mgo/black.go index cf74cfab14..4a7a35e6f1 100644 --- a/pkg/common/storage/database/mgo/black.go +++ b/pkg/common/storage/database/mgo/black.go @@ -27,7 +27,7 @@ import ( ) func NewBlackMongo(db *mongo.Database) (database.Black, error) { - coll := db.Collection("black") + coll := db.Collection(database.BlackName) _, err := coll.Indexes().CreateOne(context.Background(), mongo.IndexModel{ Keys: bson.D{ {Key: "owner_user_id", Value: 1}, diff --git a/pkg/common/storage/database/mgo/conversation.go b/pkg/common/storage/database/mgo/conversation.go index 9c35f841b6..b462d39583 100644 --- a/pkg/common/storage/database/mgo/conversation.go +++ b/pkg/common/storage/database/mgo/conversation.go @@ -16,6 +16,7 @@ package mgo import ( "context" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/database" "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model" "time" @@ -29,7 +30,7 @@ import ( ) func NewConversationMongo(db *mongo.Database) (*ConversationMgo, error) { - coll := db.Collection("conversation") + coll := db.Collection(database.ConversationName) _, err := coll.Indexes().CreateOne(context.Background(), mongo.IndexModel{ Keys: bson.D{ {Key: "owner_user_id", Value: 1}, diff --git a/pkg/common/storage/database/mgo/friend.go b/pkg/common/storage/database/mgo/friend.go index ffa006d013..7f456fbdab 100644 --- a/pkg/common/storage/database/mgo/friend.go +++ b/pkg/common/storage/database/mgo/friend.go @@ -18,6 +18,8 @@ import ( "context" "github.com/openimsdk/open-im-server/v3/pkg/common/storage/database" "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model" + "go.mongodb.org/mongo-driver/bson/primitive" + "time" "github.com/openimsdk/tools/db/mongoutil" "github.com/openimsdk/tools/db/pagination" @@ -28,12 +30,13 @@ import ( // FriendMgo implements Friend using MongoDB as the storage backend. type FriendMgo struct { - coll *mongo.Collection + coll *mongo.Collection + owner database.VersionLog } // NewFriendMongo creates a new instance of FriendMgo with the provided MongoDB database. func NewFriendMongo(db *mongo.Database) (database.Friend, error) { - coll := db.Collection("friend") + coll := db.Collection(database.FriendName) _, err := coll.Indexes().CreateOne(context.Background(), mongo.IndexModel{ Keys: bson.D{ {Key: "owner_user_id", Value: 1}, @@ -44,12 +47,41 @@ func NewFriendMongo(db *mongo.Database) (database.Friend, error) { if err != nil { return nil, err } - return &FriendMgo{coll: coll}, nil + owner, err := NewVersionLog(db.Collection(database.FriendVersionName)) + if err != nil { + return nil, err + } + return &FriendMgo{coll: coll, owner: owner}, nil +} + +func (f *FriendMgo) friendSort() any { + return bson.D{{"is_pinned", -1}, {"_id", 1}} } // Create inserts multiple friend records. func (f *FriendMgo) Create(ctx context.Context, friends []*model.Friend) error { - return mongoutil.InsertMany(ctx, f.coll, friends) + for i, friend := range friends { + if friend.ID.IsZero() { + friends[i].ID = primitive.NewObjectID() + } + if friend.CreateTime.IsZero() { + friends[i].CreateTime = time.Now() + } + } + return mongoutil.IncrVersion(func() error { + return mongoutil.InsertMany(ctx, f.coll, friends) + }, func() error { + mp := make(map[string][]string) + for _, friend := range friends { + mp[friend.OwnerUserID] = append(mp[friend.OwnerUserID], friend.FriendUserID) + } + for ownerUserID, friendUserIDs := range mp { + if err := f.owner.IncrVersion(ctx, ownerUserID, friendUserIDs, model.VersionStateInsert); err != nil { + return err + } + } + return nil + }) } // Delete removes specified friends of the owner user. @@ -58,11 +90,15 @@ func (f *FriendMgo) Delete(ctx context.Context, ownerUserID string, friendUserID "owner_user_id": ownerUserID, "friend_user_id": bson.M{"$in": friendUserIDs}, } - return mongoutil.DeleteOne(ctx, f.coll, filter) + return mongoutil.IncrVersion(func() error { + return mongoutil.DeleteOne(ctx, f.coll, filter) + }, func() error { + return f.owner.IncrVersion(ctx, ownerUserID, friendUserIDs, model.VersionStateDelete) + }) } // UpdateByMap updates specific fields of a friend document using a map. -func (f *FriendMgo) UpdateByMap(ctx context.Context, ownerUserID string, friendUserID string, args map[string]interface{}) error { +func (f *FriendMgo) UpdateByMap(ctx context.Context, ownerUserID string, friendUserID string, args map[string]any) error { if len(args) == 0 { return nil } @@ -70,30 +106,55 @@ func (f *FriendMgo) UpdateByMap(ctx context.Context, ownerUserID string, friendU "owner_user_id": ownerUserID, "friend_user_id": friendUserID, } - return mongoutil.UpdateOne(ctx, f.coll, filter, bson.M{"$set": args}, true) + return mongoutil.IncrVersion(func() error { + return mongoutil.UpdateOne(ctx, f.coll, filter, bson.M{"$set": args}, true) + }, func() error { + return f.owner.IncrVersion(ctx, ownerUserID, []string{friendUserID}, model.VersionStateUpdate) + }) } -// Update modifies multiple friend documents. -// func (f *FriendMgo) Update(ctx context.Context, friends []*relation.Friend) error { -// filter := bson.M{ -// "owner_user_id": ownerUserID, -// "friend_user_id": friendUserID, -// } -// return mgotool.UpdateMany(ctx, f.coll, filter, friends) -// } - // UpdateRemark updates the remark for a specific friend. func (f *FriendMgo) UpdateRemark(ctx context.Context, ownerUserID, friendUserID, remark string) error { return f.UpdateByMap(ctx, ownerUserID, friendUserID, map[string]any{"remark": remark}) } +func (f *FriendMgo) fillTime(friends ...*model.Friend) { + for i, friend := range friends { + if friend.CreateTime.IsZero() { + friends[i].CreateTime = friend.ID.Timestamp() + } + } +} + +func (f *FriendMgo) findOne(ctx context.Context, filter any) (*model.Friend, error) { + friend, err := mongoutil.FindOne[*model.Friend](ctx, f.coll, filter) + if err != nil { + return nil, err + } + f.fillTime(friend) + return friend, nil +} + +func (f *FriendMgo) find(ctx context.Context, filter any) ([]*model.Friend, error) { + friends, err := mongoutil.Find[*model.Friend](ctx, f.coll, filter) + if err != nil { + return nil, err + } + f.fillTime(friends...) + return friends, nil +} + +func (f *FriendMgo) findPage(ctx context.Context, filter any, pagination pagination.Pagination, opts ...*options.FindOptions) (int64, []*model.Friend, error) { + return mongoutil.FindPage[*model.Friend](ctx, f.coll, filter, pagination, opts...) +} + // Take retrieves a single friend document. Returns an error if not found. func (f *FriendMgo) Take(ctx context.Context, ownerUserID, friendUserID string) (*model.Friend, error) { filter := bson.M{ "owner_user_id": ownerUserID, "friend_user_id": friendUserID, } - return mongoutil.FindOne[*model.Friend](ctx, f.coll, filter) + return f.findOne(ctx, filter) } // FindUserState finds the friendship status between two users. @@ -104,7 +165,7 @@ func (f *FriendMgo) FindUserState(ctx context.Context, userID1, userID2 string) {"owner_user_id": userID2, "friend_user_id": userID1}, }, } - return mongoutil.Find[*model.Friend](ctx, f.coll, filter) + return f.find(ctx, filter) } // FindFriends retrieves a list of friends for a given owner. Missing friends do not cause an error. @@ -113,7 +174,7 @@ func (f *FriendMgo) FindFriends(ctx context.Context, ownerUserID string, friendU "owner_user_id": ownerUserID, "friend_user_id": bson.M{"$in": friendUserIDs}, } - return mongoutil.Find[*model.Friend](ctx, f.coll, filter) + return f.find(ctx, filter) } // FindReversalFriends finds users who have added the specified user as a friend. @@ -122,25 +183,33 @@ func (f *FriendMgo) FindReversalFriends(ctx context.Context, friendUserID string "owner_user_id": bson.M{"$in": ownerUserIDs}, "friend_user_id": friendUserID, } - return mongoutil.Find[*model.Friend](ctx, f.coll, filter) + return f.find(ctx, filter) } // FindOwnerFriends retrieves a paginated list of friends for a given owner. func (f *FriendMgo) FindOwnerFriends(ctx context.Context, ownerUserID string, pagination pagination.Pagination) (int64, []*model.Friend, error) { filter := bson.M{"owner_user_id": ownerUserID} - return mongoutil.FindPage[*model.Friend](ctx, f.coll, filter, pagination) + opt := options.Find().SetSort(f.friendSort()) + return f.findPage(ctx, filter, pagination, opt) +} + +func (f *FriendMgo) FindOwnerFriendUserIds(ctx context.Context, ownerUserID string, limit int) ([]string, error) { + filter := bson.M{"owner_user_id": ownerUserID} + opt := options.Find().SetProjection(bson.M{"_id": 0, "friend_user_id": 1}).SetSort(f.friendSort()).SetLimit(int64(limit)) + return mongoutil.Find[string](ctx, f.coll, filter, opt) } // FindInWhoseFriends finds users who have added the specified user as a friend, with pagination. func (f *FriendMgo) FindInWhoseFriends(ctx context.Context, friendUserID string, pagination pagination.Pagination) (int64, []*model.Friend, error) { filter := bson.M{"friend_user_id": friendUserID} - return mongoutil.FindPage[*model.Friend](ctx, f.coll, filter, pagination) + opt := options.Find().SetSort(f.friendSort()) + return f.findPage(ctx, filter, pagination, opt) } // FindFriendUserIDs retrieves a list of friend user IDs for a given owner. func (f *FriendMgo) FindFriendUserIDs(ctx context.Context, ownerUserID string) ([]string, error) { filter := bson.M{"owner_user_id": ownerUserID} - return mongoutil.Find[string](ctx, f.coll, filter, options.Find().SetProjection(bson.M{"_id": 0, "friend_user_id": 1})) + return mongoutil.Find[string](ctx, f.coll, filter, options.Find().SetProjection(bson.M{"_id": 0, "friend_user_id": 1}).SetSort(f.friendSort())) } func (f *FriendMgo) UpdateFriends(ctx context.Context, ownerUserID string, friendUserIDs []string, val map[string]any) error { @@ -158,7 +227,24 @@ func (f *FriendMgo) UpdateFriends(ctx context.Context, ownerUserID string, frien // Create an update document update := bson.M{"$set": val} - // Perform the update operation for all matching documents - _, err := mongoutil.UpdateMany(ctx, f.coll, filter, update) - return err + return mongoutil.IncrVersion(func() error { + return mongoutil.Ignore(mongoutil.UpdateMany(ctx, f.coll, filter, update)) + }, func() error { + return f.owner.IncrVersion(ctx, ownerUserID, friendUserIDs, model.VersionStateUpdate) + }) +} + +func (f *FriendMgo) FindIncrVersion(ctx context.Context, ownerUserID string, version uint, limit int) (*model.VersionLog, error) { + return f.owner.FindChangeLog(ctx, ownerUserID, version, limit) +} + +func (f *FriendMgo) FindFriendUserID(ctx context.Context, friendUserID string) ([]string, error) { + filter := bson.M{ + "friend_user_id": friendUserID, + } + return mongoutil.Find[string](ctx, f.coll, filter, options.Find().SetProjection(bson.M{"_id": 0, "owner_user_id": 1}).SetSort(f.friendSort())) +} + +func (f *FriendMgo) IncrVersion(ctx context.Context, ownerUserID string, friendUserIDs []string, state int32) error { + return f.owner.IncrVersion(ctx, ownerUserID, friendUserIDs, state) } diff --git a/pkg/common/storage/database/mgo/friend_request.go b/pkg/common/storage/database/mgo/friend_request.go index 0d60b213dd..4eed2f4a26 100644 --- a/pkg/common/storage/database/mgo/friend_request.go +++ b/pkg/common/storage/database/mgo/friend_request.go @@ -27,7 +27,7 @@ import ( ) func NewFriendRequestMongo(db *mongo.Database) (database.FriendRequest, error) { - coll := db.Collection("friend_request") + coll := db.Collection(database.FriendRequestName) _, err := coll.Indexes().CreateOne(context.Background(), mongo.IndexModel{ Keys: bson.D{ {Key: "from_user_id", Value: 1}, diff --git a/pkg/common/storage/database/mgo/group.go b/pkg/common/storage/database/mgo/group.go index 48d24560bc..3be7883af9 100644 --- a/pkg/common/storage/database/mgo/group.go +++ b/pkg/common/storage/database/mgo/group.go @@ -30,7 +30,7 @@ import ( ) func NewGroupMongo(db *mongo.Database) (database.Group, error) { - coll := db.Collection("group") + coll := db.Collection(database.GroupName) _, err := coll.Indexes().CreateOne(context.Background(), mongo.IndexModel{ Keys: bson.D{ {Key: "group_id", Value: 1}, @@ -47,6 +47,10 @@ type GroupMgo struct { coll *mongo.Collection } +func (g *GroupMgo) sortGroup() any { + return bson.D{{"group_name", 1}, {"create_time", 1}} +} + func (g *GroupMgo) Create(ctx context.Context, groups []*model.Group) (err error) { return mongoutil.InsertMany(ctx, g.coll, groups) } @@ -126,3 +130,32 @@ func (g *GroupMgo) CountRangeEverydayTotal(ctx context.Context, start time.Time, } return res, nil } + +func (g *GroupMgo) FindJoinSortGroupID(ctx context.Context, groupIDs []string) ([]string, error) { + if len(groupIDs) < 2 { + return groupIDs, nil + } + filter := bson.M{ + "group_id": bson.M{"$in": groupIDs}, + "status": bson.M{"$ne": constant.GroupStatusDismissed}, + } + opt := options.Find().SetSort(g.sortGroup()).SetProjection(bson.M{"_id": 0, "group_id": 1}) + return mongoutil.Find[string](ctx, g.coll, filter, opt) +} + +func (g *GroupMgo) SearchJoin(ctx context.Context, groupIDs []string, keyword string, pagination pagination.Pagination) (int64, []*model.Group, error) { + if len(groupIDs) == 0 { + return 0, nil, nil + } + filter := bson.M{ + "group_id": bson.M{"$in": groupIDs}, + "status": bson.M{"$ne": constant.GroupStatusDismissed}, + } + if keyword != "" { + filter["group_name"] = bson.M{"$regex": keyword} + } + // Define the sorting options + opts := options.Find().SetSort(g.sortGroup()) + // Perform the search with pagination and sorting + return mongoutil.FindPage[*model.Group](ctx, g.coll, filter, pagination, opts) +} diff --git a/pkg/common/storage/database/mgo/group_member.go b/pkg/common/storage/database/mgo/group_member.go index ccca386e57..3eb93a10ec 100644 --- a/pkg/common/storage/database/mgo/group_member.go +++ b/pkg/common/storage/database/mgo/group_member.go @@ -18,6 +18,7 @@ import ( "context" "github.com/openimsdk/open-im-server/v3/pkg/common/storage/database" "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model" + "github.com/openimsdk/tools/log" "github.com/openimsdk/protocol/constant" "github.com/openimsdk/tools/db/mongoutil" @@ -29,7 +30,7 @@ import ( ) func NewGroupMember(db *mongo.Database) (database.GroupMember, error) { - coll := db.Collection("group_member") + coll := db.Collection(database.GroupMemberName) _, err := coll.Indexes().CreateOne(context.Background(), mongo.IndexModel{ Keys: bson.D{ {Key: "group_id", Value: 1}, @@ -40,15 +41,53 @@ func NewGroupMember(db *mongo.Database) (database.GroupMember, error) { if err != nil { return nil, errs.Wrap(err) } - return &GroupMemberMgo{coll: coll}, nil + member, err := NewVersionLog(db.Collection(database.GroupMemberVersionName)) + if err != nil { + return nil, err + } + join, err := NewVersionLog(db.Collection(database.GroupJoinVersionName)) + if err != nil { + return nil, err + } + return &GroupMemberMgo{coll: coll, member: member, join: join}, nil } type GroupMemberMgo struct { - coll *mongo.Collection + coll *mongo.Collection + member database.VersionLog + join database.VersionLog +} + +func (g *GroupMemberMgo) memberSort() any { + return bson.D{{"role_level", -1}, {"create_time", -1}} } func (g *GroupMemberMgo) Create(ctx context.Context, groupMembers []*model.GroupMember) (err error) { - return mongoutil.InsertMany(ctx, g.coll, groupMembers) + return mongoutil.IncrVersion(func() error { + return mongoutil.InsertMany(ctx, g.coll, groupMembers) + }, func() error { + gms := make(map[string][]string) + for _, member := range groupMembers { + gms[member.GroupID] = append(gms[member.GroupID], member.UserID) + } + for groupID, userIDs := range gms { + if err := g.member.IncrVersion(ctx, groupID, userIDs, model.VersionStateInsert); err != nil { + return err + } + } + return nil + }, func() error { + gms := make(map[string][]string) + for _, member := range groupMembers { + gms[member.UserID] = append(gms[member.UserID], member.GroupID) + } + for userID, groupIDs := range gms { + if err := g.join.IncrVersion(ctx, userID, groupIDs, model.VersionStateInsert); err != nil { + return err + } + } + return nil + }) } func (g *GroupMemberMgo) Delete(ctx context.Context, groupID string, userIDs []string) (err error) { @@ -56,24 +95,62 @@ func (g *GroupMemberMgo) Delete(ctx context.Context, groupID string, userIDs []s if len(userIDs) > 0 { filter["user_id"] = bson.M{"$in": userIDs} } - return mongoutil.DeleteMany(ctx, g.coll, filter) + return mongoutil.IncrVersion(func() error { + return mongoutil.DeleteMany(ctx, g.coll, filter) + }, func() error { + if len(userIDs) == 0 { + return g.member.Delete(ctx, groupID) + } else { + return g.member.IncrVersion(ctx, groupID, userIDs, model.VersionStateDelete) + } + }, func() error { + for _, userID := range userIDs { + if err := g.join.IncrVersion(ctx, userID, []string{groupID}, model.VersionStateDelete); err != nil { + return err + } + } + return nil + }) } func (g *GroupMemberMgo) UpdateRoleLevel(ctx context.Context, groupID string, userID string, roleLevel int32) error { - return g.Update(ctx, groupID, userID, bson.M{"role_level": roleLevel}) + return mongoutil.IncrVersion(func() error { + return mongoutil.UpdateOne(ctx, g.coll, bson.M{"group_id": groupID, "user_id": userID}, + bson.M{"$set": bson.M{"role_level": roleLevel}}, true) + }, func() error { + return g.member.IncrVersion(ctx, groupID, []string{userID}, model.VersionStateUpdate) + }) } - -func (g *GroupMemberMgo) Update(ctx context.Context, groupID string, userID string, data map[string]any) (err error) { - return mongoutil.UpdateOne(ctx, g.coll, bson.M{"group_id": groupID, "user_id": userID}, bson.M{"$set": data}, true) +func (g *GroupMemberMgo) UpdateUserRoleLevels(ctx context.Context, groupID string, firstUserID string, firstUserRoleLevel int32, secondUserID string, secondUserRoleLevel int32) error { + return mongoutil.IncrVersion(func() error { + if err := mongoutil.UpdateOne(ctx, g.coll, bson.M{"group_id": groupID, "user_id": firstUserID}, + bson.M{"$set": bson.M{"role_level": firstUserRoleLevel}}, true); err != nil { + return err + } + if err := mongoutil.UpdateOne(ctx, g.coll, bson.M{"group_id": groupID, "user_id": secondUserID}, + bson.M{"$set": bson.M{"role_level": secondUserRoleLevel}}, true); err != nil { + return err + } + + return nil + }, func() error { + return g.member.IncrVersion(ctx, groupID, []string{firstUserID, secondUserID}, model.VersionStateUpdate) + }) } -func (g *GroupMemberMgo) Find(ctx context.Context, groupIDs []string, userIDs []string, roleLevels []int32) (groupMembers []*model.GroupMember, err error) { - // TODO implement me - panic("implement me") +func (g *GroupMemberMgo) Update(ctx context.Context, groupID string, userID string, data map[string]any) (err error) { + if len(data) == 0 { + return nil + } + return mongoutil.IncrVersion(func() error { + return mongoutil.UpdateOne(ctx, g.coll, bson.M{"group_id": groupID, "user_id": userID}, bson.M{"$set": data}, true) + }, func() error { + return g.member.IncrVersion(ctx, groupID, []string{userID}, model.VersionStateUpdate) + }) } func (g *GroupMemberMgo) FindMemberUserID(ctx context.Context, groupID string) (userIDs []string, err error) { - return mongoutil.Find[string](ctx, g.coll, bson.M{"group_id": groupID}, options.Find().SetProjection(bson.M{"_id": 0, "user_id": 1})) + return mongoutil.Find[string](ctx, g.coll, bson.M{"group_id": groupID}, options.Find().SetProjection(bson.M{"_id": 0, "user_id": 1}).SetSort(g.memberSort())) } func (g *GroupMemberMgo) Take(ctx context.Context, groupID string, userID string) (groupMember *model.GroupMember, err error) { @@ -88,13 +165,13 @@ func (g *GroupMemberMgo) FindRoleLevelUserIDs(ctx context.Context, groupID strin return mongoutil.Find[string](ctx, g.coll, bson.M{"group_id": groupID, "role_level": roleLevel}, options.Find().SetProjection(bson.M{"_id": 0, "user_id": 1})) } -func (g *GroupMemberMgo) SearchMember(ctx context.Context, keyword string, groupID string, pagination pagination.Pagination) (total int64, groupList []*model.GroupMember, err error) { +func (g *GroupMemberMgo) SearchMember(ctx context.Context, keyword string, groupID string, pagination pagination.Pagination) (int64, []*model.GroupMember, error) { filter := bson.M{"group_id": groupID, "nickname": bson.M{"$regex": keyword}} - return mongoutil.FindPage[*model.GroupMember](ctx, g.coll, filter, pagination) + return mongoutil.FindPage[*model.GroupMember](ctx, g.coll, filter, pagination, options.Find().SetSort(g.memberSort())) } func (g *GroupMemberMgo) FindUserJoinedGroupID(ctx context.Context, userID string) (groupIDs []string, err error) { - return mongoutil.Find[string](ctx, g.coll, bson.M{"user_id": userID}, options.Find().SetProjection(bson.M{"_id": 0, "group_id": 1})) + return mongoutil.Find[string](ctx, g.coll, bson.M{"user_id": userID}, options.Find().SetProjection(bson.M{"_id": 0, "group_id": 1}).SetSort(g.memberSort())) } func (g *GroupMemberMgo) TakeGroupMemberNum(ctx context.Context, groupID string) (count int64, err error) { @@ -118,3 +195,21 @@ func (g *GroupMemberMgo) IsUpdateRoleLevel(data map[string]any) bool { _, ok := data["role_level"] return ok } + +func (g *GroupMemberMgo) JoinGroupIncrVersion(ctx context.Context, userID string, groupIDs []string, state int32) error { + return g.join.IncrVersion(ctx, userID, groupIDs, state) +} + +func (g *GroupMemberMgo) MemberGroupIncrVersion(ctx context.Context, groupID string, userIDs []string, state int32) error { + return g.member.IncrVersion(ctx, groupID, userIDs, state) +} + +func (g *GroupMemberMgo) FindMemberIncrVersion(ctx context.Context, groupID string, version uint, limit int) (*model.VersionLog, error) { + log.ZDebug(ctx, "find member incr version", "groupID", groupID, "version", version) + return g.member.FindChangeLog(ctx, groupID, version, limit) +} + +func (g *GroupMemberMgo) FindJoinIncrVersion(ctx context.Context, userID string, version uint, limit int) (*model.VersionLog, error) { + log.ZDebug(ctx, "find join incr version", "userID", userID, "version", version) + return g.join.FindChangeLog(ctx, userID, version, limit) +} diff --git a/pkg/common/storage/database/mgo/group_request.go b/pkg/common/storage/database/mgo/group_request.go index 4ae7785276..b1942b7083 100644 --- a/pkg/common/storage/database/mgo/group_request.go +++ b/pkg/common/storage/database/mgo/group_request.go @@ -28,7 +28,7 @@ import ( ) func NewGroupRequestMgo(db *mongo.Database) (database.GroupRequest, error) { - coll := db.Collection("group_request") + coll := db.Collection(database.GroupRequestName) _, err := coll.Indexes().CreateOne(context.Background(), mongo.IndexModel{ Keys: bson.D{ {Key: "group_id", Value: 1}, diff --git a/pkg/common/storage/database/mgo/log.go b/pkg/common/storage/database/mgo/log.go index 51715bd771..6ff4c60395 100644 --- a/pkg/common/storage/database/mgo/log.go +++ b/pkg/common/storage/database/mgo/log.go @@ -28,7 +28,7 @@ import ( ) func NewLogMongo(db *mongo.Database) (database.Log, error) { - coll := db.Collection("log") + coll := db.Collection(database.LogName) _, err := coll.Indexes().CreateMany(context.Background(), []mongo.IndexModel{ { Keys: bson.D{ diff --git a/pkg/common/storage/database/mgo/object.go b/pkg/common/storage/database/mgo/object.go index 8ed7b3a561..df4d10ec4f 100644 --- a/pkg/common/storage/database/mgo/object.go +++ b/pkg/common/storage/database/mgo/object.go @@ -27,7 +27,7 @@ import ( ) func NewS3Mongo(db *mongo.Database) (database.ObjectInfo, error) { - coll := db.Collection("s3") + coll := db.Collection(database.ObjectName) _, err := coll.Indexes().CreateOne(context.Background(), mongo.IndexModel{ Keys: bson.D{ {Key: "name", Value: 1}, diff --git a/pkg/common/storage/database/mgo/user.go b/pkg/common/storage/database/mgo/user.go index 96cb18882b..8978e64ebf 100644 --- a/pkg/common/storage/database/mgo/user.go +++ b/pkg/common/storage/database/mgo/user.go @@ -31,7 +31,7 @@ import ( ) func NewUserMongo(db *mongo.Database) (database.User, error) { - coll := db.Collection("user") + coll := db.Collection(database.UserName) _, err := coll.Indexes().CreateOne(context.Background(), mongo.IndexModel{ Keys: bson.D{ {Key: "user_id", Value: 1}, @@ -319,3 +319,69 @@ func (u *UserMgo) CountRangeEverydayTotal(ctx context.Context, start time.Time, } return res, nil } + +func (u *UserMgo) SortQuery(ctx context.Context, userIDName map[string]string, asc bool) ([]*model.User, error) { + if len(userIDName) == 0 { + return nil, nil + } + userIDs := make([]string, 0, len(userIDName)) + attached := make(map[string]string) + for userID, name := range userIDName { + userIDs = append(userIDs, userID) + if name == "" { + continue + } + attached[userID] = name + } + var sortValue int + if asc { + sortValue = 1 + } else { + sortValue = -1 + } + if len(attached) == 0 { + filter := bson.M{"user_id": bson.M{"$in": userIDs}} + opt := options.Find().SetSort(bson.M{"nickname": sortValue}) + return mongoutil.Find[*model.User](ctx, u.coll, filter, opt) + } + pipeline := []bson.M{ + { + "$match": bson.M{ + "user_id": bson.M{"$in": userIDs}, + }, + }, + { + "$addFields": bson.M{ + "_query_sort_name": bson.M{ + "$arrayElemAt": []any{ + bson.M{ + "$filter": bson.M{ + "input": bson.M{ + "$objectToArray": attached, + }, + "as": "item", + "cond": bson.M{ + "$eq": []any{"$$item.k", "$user_id"}, + }, + }, + }, + 0, + }, + }, + }, + }, + { + "$addFields": bson.M{ + "_query_sort_name": bson.M{ + "$ifNull": []any{"$_query_sort_name.v", "$nickname"}, + }, + }, + }, + { + "$sort": bson.M{ + "_query_sort_name": sortValue, + }, + }, + } + return mongoutil.Aggregate[*model.User](ctx, u.coll, pipeline) +} diff --git a/pkg/common/storage/database/mgo/version_log.go b/pkg/common/storage/database/mgo/version_log.go new file mode 100644 index 0000000000..8836742f08 --- /dev/null +++ b/pkg/common/storage/database/mgo/version_log.go @@ -0,0 +1,265 @@ +package mgo + +import ( + "context" + "errors" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/database" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/versionctx" + "github.com/openimsdk/tools/db/mongoutil" + "github.com/openimsdk/tools/errs" + "github.com/openimsdk/tools/log" + "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" + "time" +) + +func NewVersionLog(coll *mongo.Collection) (database.VersionLog, error) { + lm := &VersionLogMgo{coll: coll} + if lm.initIndex(context.Background()) != nil { + return nil, errs.ErrInternalServer.WrapMsg("init index failed", "coll", coll.Name()) + } + return lm, nil +} + +type VersionLogMgo struct { + coll *mongo.Collection +} + +func (l *VersionLogMgo) initIndex(ctx context.Context) error { + _, err := l.coll.Indexes().CreateOne(ctx, mongo.IndexModel{ + Keys: bson.M{ + "d_id": 1, + }, + }) + return err +} + +func (l *VersionLogMgo) IncrVersion(ctx context.Context, dId string, eIds []string, state int32) error { + _, err := l.IncrVersionResult(ctx, dId, eIds, state) + return err +} + +func (l *VersionLogMgo) IncrVersionResult(ctx context.Context, dId string, eIds []string, state int32) (*model.VersionLog, error) { + vl, err := l.incrVersionResult(ctx, dId, eIds, state) + if err != nil { + return nil, err + } + versionctx.GetVersionLog(ctx).Append(versionctx.Collection{ + Name: l.coll.Name(), + Doc: vl, + }) + return vl, nil +} + +func (l *VersionLogMgo) incrVersionResult(ctx context.Context, dId string, eIds []string, state int32) (*model.VersionLog, error) { + if len(eIds) == 0 { + return nil, errs.ErrArgs.WrapMsg("elem id is empty", "dId", dId) + } + now := time.Now() + if res, err := l.writeLogBatch2(ctx, dId, eIds, state, now); err == nil { + return res, nil + } else if !errors.Is(err, mongo.ErrNoDocuments) { + return nil, err + } + if res, err := l.initDoc(ctx, dId, eIds, state, now); err == nil { + return res, nil + } else if !mongo.IsDuplicateKeyError(err) { + return nil, err + } + return l.writeLogBatch2(ctx, dId, eIds, state, now) +} + +func (l *VersionLogMgo) initDoc(ctx context.Context, dId string, eIds []string, state int32, now time.Time) (*model.VersionLog, error) { + wl := model.VersionLogTable{ + ID: primitive.NewObjectID(), + DID: dId, + Logs: make([]model.VersionLogElem, 0, len(eIds)), + Version: database.FirstVersion, + Deleted: database.DefaultDeleteVersion, + LastUpdate: now, + } + for _, eId := range eIds { + wl.Logs = append(wl.Logs, model.VersionLogElem{ + EID: eId, + State: state, + Version: database.FirstVersion, + LastUpdate: now, + }) + } + if _, err := l.coll.InsertOne(ctx, &wl); err != nil { + return nil, err + } + return wl.VersionLog(), nil +} + +func (l *VersionLogMgo) writeLogBatch2(ctx context.Context, dId string, eIds []string, state int32, now time.Time) (*model.VersionLog, error) { + if eIds == nil { + eIds = []string{} + } + filter := bson.M{ + "d_id": dId, + } + elems := make([]bson.M, 0, len(eIds)) + for _, eId := range eIds { + elems = append(elems, bson.M{ + "e_id": eId, + "version": "$version", + "state": state, + "last_update": now, + }) + } + pipeline := []bson.M{ + { + "$addFields": bson.M{ + "delete_e_ids": eIds, + }, + }, + { + "$set": bson.M{ + "version": bson.M{"$add": []any{"$version", 1}}, + "last_update": now, + }, + }, + { + "$set": bson.M{ + "logs": bson.M{ + "$filter": bson.M{ + "input": "$logs", + "as": "log", + "cond": bson.M{ + "$not": bson.M{ + "$in": []any{"$$log.e_id", "$delete_e_ids"}, + }, + }, + }, + }, + }, + }, + { + "$set": bson.M{ + "logs": bson.M{ + "$concatArrays": []any{ + "$logs", + elems, + }, + }, + }, + }, + { + "$unset": "delete_e_ids", + }, + } + opt := options.FindOneAndUpdate().SetUpsert(false).SetReturnDocument(options.After).SetProjection(bson.M{"logs": 0}) + return mongoutil.FindOneAndUpdate[*model.VersionLog](ctx, l.coll, filter, pipeline, opt) +} + +func (l *VersionLogMgo) findDoc(ctx context.Context, dId string) (*model.VersionLog, error) { + vl, err := mongoutil.FindOne[*model.VersionLogTable](ctx, l.coll, bson.M{"d_id": dId}, options.FindOne().SetProjection(bson.M{"logs": 0})) + if err != nil { + return nil, err + } + return vl.VersionLog(), nil +} + +func (l *VersionLogMgo) FindChangeLog(ctx context.Context, dId string, version uint, limit int) (*model.VersionLog, error) { + if wl, err := l.findChangeLog(ctx, dId, version, limit); err == nil { + return wl, nil + } else if !errors.Is(err, mongo.ErrNoDocuments) { + return nil, err + } + log.ZDebug(ctx, "init doc", "dId", dId) + if res, err := l.initDoc(ctx, dId, nil, 0, time.Now()); err == nil { + log.ZDebug(ctx, "init doc success", "dId", dId) + return res, nil + } else if mongo.IsDuplicateKeyError(err) { + return l.findChangeLog(ctx, dId, version, limit) + } else { + return nil, err + } +} + +func (l *VersionLogMgo) findChangeLog(ctx context.Context, dId string, version uint, limit int) (*model.VersionLog, error) { + if version == 0 && limit == 0 { + return l.findDoc(ctx, dId) + } + pipeline := []bson.M{ + { + "$match": bson.M{ + "d_id": dId, + }, + }, + { + "$addFields": bson.M{ + "logs": bson.M{ + "$cond": bson.M{ + "if": bson.M{ + "$or": []bson.M{ + {"$lt": []any{"$version", version}}, + {"$gte": []any{"$deleted", version}}, + }, + }, + "then": []any{}, + "else": "$logs", + }, + }, + }, + }, + { + "$addFields": bson.M{ + "logs": bson.M{ + "$filter": bson.M{ + "input": "$logs", + "as": "l", + "cond": bson.M{ + "$gt": []any{"$$l.version", version}, + }, + }, + }, + }, + }, + { + "$addFields": bson.M{ + "log_len": bson.M{"$size": "$logs"}, + }, + }, + { + "$addFields": bson.M{ + "logs": bson.M{ + "$cond": bson.M{ + "if": bson.M{ + "$gt": []any{"$log_len", limit}, + }, + "then": []any{}, + "else": "$logs", + }, + }, + }, + }, + } + if limit <= 0 { + pipeline = pipeline[:len(pipeline)-1] + } + vl, err := mongoutil.Aggregate[*model.VersionLog](ctx, l.coll, pipeline) + if err != nil { + return nil, err + } + if len(vl) == 0 { + return nil, mongo.ErrNoDocuments + } + return vl[0], nil +} + +func (l *VersionLogMgo) DeleteAfterUnchangedLog(ctx context.Context, deadline time.Time) error { + return mongoutil.DeleteMany(ctx, l.coll, bson.M{ + "last_update": bson.M{ + "$lt": deadline, + }, + }) +} + +func (l *VersionLogMgo) Delete(ctx context.Context, dId string) error { + return mongoutil.DeleteOne(ctx, l.coll, bson.M{"d_id": dId}) +} diff --git a/pkg/common/storage/database/mgo/version_test.go b/pkg/common/storage/database/mgo/version_test.go new file mode 100644 index 0000000000..236c61a2ce --- /dev/null +++ b/pkg/common/storage/database/mgo/version_test.go @@ -0,0 +1,39 @@ +package mgo + +import ( + "context" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model" + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" + "testing" + "time" +) + +func Result[V any](val V, err error) V { + if err != nil { + panic(err) + } + return val +} + +func Check(err error) { + if err != nil { + panic(err) + } +} + +func TestName(t *testing.T) { + cli := Result(mongo.Connect(context.Background(), options.Client().ApplyURI("mongodb://openIM:openIM123@172.16.8.48:37017/openim_v3?maxPoolSize=100").SetConnectTimeout(5*time.Second))) + coll := cli.Database("openim_v3").Collection("version_test") + tmp, err := NewVersionLog(coll) + if err != nil { + panic(err) + } + vl := tmp.(*VersionLogMgo) + res, err := vl.writeLogBatch2(context.Background(), "100", []string{"1000", "1001", "1003"}, model.VersionStateInsert, time.Now()) + if err != nil { + t.Log(err) + return + } + t.Logf("%+v", res) +} diff --git a/pkg/common/storage/database/name.go b/pkg/common/storage/database/name.go new file mode 100644 index 0000000000..986f22a1a2 --- /dev/null +++ b/pkg/common/storage/database/name.go @@ -0,0 +1,17 @@ +package database + +const ( + BlackName = "black" + ConversationName = "conversation" + FriendName = "friend" + FriendVersionName = "friend_version" + FriendRequestName = "friend_request" + GroupName = "group" + GroupMemberName = "group_member" + GroupMemberVersionName = "group_member_version" + GroupJoinVersionName = "group_join_version" + GroupRequestName = "group_request" + LogName = "log" + ObjectName = "s3" + UserName = "user" +) diff --git a/pkg/common/storage/database/user.go b/pkg/common/storage/database/user.go index 2e40886205..4ddc8285f6 100644 --- a/pkg/common/storage/database/user.go +++ b/pkg/common/storage/database/user.go @@ -39,6 +39,9 @@ type User interface { CountTotal(ctx context.Context, before *time.Time) (count int64, err error) // Get user total quantity every day CountRangeEverydayTotal(ctx context.Context, start time.Time, end time.Time) (map[string]int64, error) + + SortQuery(ctx context.Context, userIDName map[string]string, asc bool) ([]*model.User, error) + // CRUD user command AddUserCommand(ctx context.Context, userID string, Type int32, UUID string, value string, ex string) error DeleteUserCommand(ctx context.Context, userID string, Type int32, UUID string) error diff --git a/pkg/common/storage/database/version_log.go b/pkg/common/storage/database/version_log.go new file mode 100644 index 0000000000..9d7bcc1724 --- /dev/null +++ b/pkg/common/storage/database/version_log.go @@ -0,0 +1,19 @@ +package database + +import ( + "context" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model" + "time" +) + +const ( + FirstVersion = 1 + DefaultDeleteVersion = 0 +) + +type VersionLog interface { + IncrVersion(ctx context.Context, dId string, eIds []string, state int32) error + FindChangeLog(ctx context.Context, dId string, version uint, limit int) (*model.VersionLog, error) + DeleteAfterUnchangedLog(ctx context.Context, deadline time.Time) error + Delete(ctx context.Context, dId string) error +} diff --git a/pkg/common/storage/model/friend.go b/pkg/common/storage/model/friend.go index 60a40d9c2a..abcca2f2b9 100644 --- a/pkg/common/storage/model/friend.go +++ b/pkg/common/storage/model/friend.go @@ -15,17 +15,19 @@ package model import ( + "go.mongodb.org/mongo-driver/bson/primitive" "time" ) // Friend represents the data structure for a friend relationship in MongoDB. type Friend struct { - OwnerUserID string `bson:"owner_user_id"` - FriendUserID string `bson:"friend_user_id"` - Remark string `bson:"remark"` - CreateTime time.Time `bson:"create_time"` - AddSource int32 `bson:"add_source"` - OperatorUserID string `bson:"operator_user_id"` - Ex string `bson:"ex"` - IsPinned bool `bson:"is_pinned"` + ID primitive.ObjectID `bson:"_id"` + OwnerUserID string `bson:"owner_user_id"` + FriendUserID string `bson:"friend_user_id"` + Remark string `bson:"remark"` + CreateTime time.Time `bson:"create_time"` + AddSource int32 `bson:"add_source"` + OperatorUserID string `bson:"operator_user_id"` + Ex string `bson:"ex"` + IsPinned bool `bson:"is_pinned"` } diff --git a/pkg/common/storage/model/user.go b/pkg/common/storage/model/user.go index c6a4f952c2..f64d09e797 100644 --- a/pkg/common/storage/model/user.go +++ b/pkg/common/storage/model/user.go @@ -36,10 +36,10 @@ func (u *User) GetFaceURL() string { return u.FaceURL } -func (u User) GetUserID() string { +func (u *User) GetUserID() string { return u.UserID } -func (u User) GetEx() string { +func (u *User) GetEx() string { return u.Ex } diff --git a/pkg/common/storage/model/version_log.go b/pkg/common/storage/model/version_log.go new file mode 100644 index 0000000000..11a40ef24f --- /dev/null +++ b/pkg/common/storage/model/version_log.go @@ -0,0 +1,69 @@ +package model + +import ( + "context" + "errors" + "github.com/openimsdk/tools/log" + "go.mongodb.org/mongo-driver/bson/primitive" + "time" +) + +const ( + VersionStateInsert = iota + 1 + VersionStateDelete + VersionStateUpdate +) + +type VersionLogElem struct { + EID string `bson:"e_id"` + State int32 `bson:"state"` + Version uint `bson:"version"` + LastUpdate time.Time `bson:"last_update"` +} + +type VersionLogTable struct { + ID primitive.ObjectID `bson:"_id"` + DID string `bson:"d_id"` + Logs []VersionLogElem `bson:"logs"` + Version uint `bson:"version"` + Deleted uint `bson:"deleted"` + LastUpdate time.Time `bson:"last_update"` +} + +func (v *VersionLogTable) VersionLog() *VersionLog { + return &VersionLog{ + ID: v.ID, + DID: v.DID, + Logs: v.Logs, + Version: v.Version, + Deleted: v.Deleted, + LastUpdate: v.LastUpdate, + LogLen: len(v.Logs), + } +} + +type VersionLog struct { + ID primitive.ObjectID `bson:"_id"` + DID string `bson:"d_id"` + Logs []VersionLogElem `bson:"logs"` + Version uint `bson:"version"` + Deleted uint `bson:"deleted"` + LastUpdate time.Time `bson:"last_update"` + LogLen int `bson:"log_len"` +} + +func (v *VersionLog) DeleteAndChangeIDs() (insertIds, deleteIds, updateIds []string) { + for _, l := range v.Logs { + switch l.State { + case VersionStateInsert: + insertIds = append(insertIds, l.EID) + case VersionStateDelete: + deleteIds = append(deleteIds, l.EID) + case VersionStateUpdate: + updateIds = append(updateIds, l.EID) + default: + log.ZError(context.Background(), "invalid version status found", errors.New("dirty database data"), "objID", v.ID.Hex(), "did", v.DID, "elem", l) + } + } + return +} diff --git a/pkg/common/storage/versionctx/rpc.go b/pkg/common/storage/versionctx/rpc.go new file mode 100644 index 0000000000..67b95aebd5 --- /dev/null +++ b/pkg/common/storage/versionctx/rpc.go @@ -0,0 +1,14 @@ +package versionctx + +import ( + "context" + "google.golang.org/grpc" +) + +func EnableVersionCtx() grpc.ServerOption { + return grpc.ChainUnaryInterceptor(enableVersionCtxInterceptor) +} + +func enableVersionCtxInterceptor(ctx context.Context, req any, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (any, error) { + return handler(WithVersionLog(ctx), req) +} diff --git a/pkg/common/storage/versionctx/version.go b/pkg/common/storage/versionctx/version.go new file mode 100644 index 0000000000..5db8856401 --- /dev/null +++ b/pkg/common/storage/versionctx/version.go @@ -0,0 +1,48 @@ +package versionctx + +import ( + "context" + tablerelation "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model" + "sync" +) + +type Collection struct { + Name string + Doc *tablerelation.VersionLog +} + +type versionKey struct{} + +func WithVersionLog(ctx context.Context) context.Context { + return context.WithValue(ctx, versionKey{}, &VersionLog{}) +} + +func GetVersionLog(ctx context.Context) *VersionLog { + if v, ok := ctx.Value(versionKey{}).(*VersionLog); ok { + return v + } + return nil +} + +type VersionLog struct { + lock sync.Mutex + data []Collection +} + +func (v *VersionLog) Append(data ...Collection) { + if v == nil || len(data) == 0 { + return + } + v.lock.Lock() + defer v.lock.Unlock() + v.data = append(v.data, data...) +} + +func (v *VersionLog) Get() []Collection { + if v == nil { + return nil + } + v.lock.Lock() + defer v.lock.Unlock() + return v.data +} diff --git a/pkg/rpcclient/friend.go b/pkg/rpcclient/friend.go index 5543afe4f7..fd00be3292 100644 --- a/pkg/rpcclient/friend.go +++ b/pkg/rpcclient/friend.go @@ -17,7 +17,7 @@ package rpcclient import ( "context" - "github.com/openimsdk/protocol/friend" + "github.com/openimsdk/protocol/relation" sdkws "github.com/openimsdk/protocol/sdkws" "github.com/openimsdk/tools/discovery" "github.com/openimsdk/tools/system/program" @@ -26,7 +26,7 @@ import ( type Friend struct { conn grpc.ClientConnInterface - Client friend.FriendClient + Client relation.FriendClient discov discovery.SvcDiscoveryRegistry } @@ -35,7 +35,7 @@ func NewFriend(discov discovery.SvcDiscoveryRegistry, rpcRegisterName string) *F if err != nil { program.ExitWithError(err) } - client := friend.NewFriendClient(conn) + client := relation.NewFriendClient(conn) return &Friend{discov: discov, conn: conn, Client: client} } @@ -47,11 +47,11 @@ func NewFriendRpcClient(discov discovery.SvcDiscoveryRegistry, rpcRegisterName s func (f *FriendRpcClient) GetFriendsInfo( ctx context.Context, - ownerUserID, friendUserID string, + ownerUserID, relationUserID string, ) (resp *sdkws.FriendInfo, err error) { r, err := f.Client.GetDesignatedFriends( ctx, - &friend.GetDesignatedFriendsReq{OwnerUserID: ownerUserID, FriendUserIDs: []string{friendUserID}}, + &relation.GetDesignatedFriendsReq{OwnerUserID: ownerUserID, FriendUserIDs: []string{relationUserID}}, ) if err != nil { return nil, err @@ -60,17 +60,17 @@ func (f *FriendRpcClient) GetFriendsInfo( return } -// possibleFriendUserID Is PossibleFriendUserId's friends. +// possibleFriendUserID Is PossibleFriendUserId's relations. func (f *FriendRpcClient) IsFriend(ctx context.Context, possibleFriendUserID, userID string) (bool, error) { - resp, err := f.Client.IsFriend(ctx, &friend.IsFriendReq{UserID1: userID, UserID2: possibleFriendUserID}) + resp, err := f.Client.IsFriend(ctx, &relation.IsFriendReq{UserID1: userID, UserID2: possibleFriendUserID}) if err != nil { return false, err } return resp.InUser1Friends, nil } -func (f *FriendRpcClient) GetFriendIDs(ctx context.Context, ownerUserID string) (friendIDs []string, err error) { - req := friend.GetFriendIDsReq{UserID: ownerUserID} +func (f *FriendRpcClient) GetFriendIDs(ctx context.Context, ownerUserID string) (relationIDs []string, err error) { + req := relation.GetFriendIDsReq{UserID: ownerUserID} resp, err := f.Client.GetFriendIDs(ctx, &req) if err != nil { return nil, err @@ -79,7 +79,7 @@ func (f *FriendRpcClient) GetFriendIDs(ctx context.Context, ownerUserID string) } func (b *FriendRpcClient) IsBlack(ctx context.Context, possibleBlackUserID, userID string) (bool, error) { - r, err := b.Client.IsBlack(ctx, &friend.IsBlackReq{UserID1: possibleBlackUserID, UserID2: userID}) + r, err := b.Client.IsBlack(ctx, &relation.IsBlackReq{UserID1: possibleBlackUserID, UserID2: userID}) if err != nil { return false, err } diff --git a/pkg/util/hashutil/id.go b/pkg/util/hashutil/id.go new file mode 100644 index 0000000000..52e7f4c6f2 --- /dev/null +++ b/pkg/util/hashutil/id.go @@ -0,0 +1,16 @@ +package hashutil + +import ( + "crypto/md5" + "encoding/binary" + "encoding/json" +) + +func IdHash(ids []string) uint64 { + if len(ids) == 0 { + return 0 + } + data, _ := json.Marshal(ids) + sum := md5.Sum(data) + return binary.BigEndian.Uint64(sum[:]) +}