diff --git a/.github/workflows/auto-assign-issue.yml b/.github/workflows/auto-assign-issue.yml index 320174d8c..875432a46 100644 --- a/.github/workflows/auto-assign-issue.yml +++ b/.github/workflows/auto-assign-issue.yml @@ -5,23 +5,23 @@ on: jobs: assign-issue: if: | - contains(github.event.comment.body, '/assign') || contains(github.event.comment.body, '/accept') && + (contains(github.event.comment.body, '/assign') || contains(github.event.comment.body, '/accept')) && !contains(github.event.comment.user.login, 'openim-robot') runs-on: ubuntu-latest permissions: issues: write steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@v7.0.0 - name: Assign the issue run: | - export LETASE_MILESTONES=$(curl 'https://api.github.com/repos/$OWNER/$PEPO/milestones' | jq -r 'last(.[]).title') + export LATEST_MILESTONE=$(curl "https://api.github.com/repos/$OWNER/$REPO/milestones" | jq -r 'last(.[]).title') gh issue edit ${{ github.event.issue.number }} --add-assignee "${{ github.event.comment.user.login }}" gh issue edit ${{ github.event.issue.number }} --add-label "accepted" - gh issue comment $ISSUE --body "@${{ github.event.comment.user.login }} Glad to see you accepted this issue🤲, this issue has been assigned to you. I set the milestones for this issue to [$LETASE_MILESTONES](https://github.com/$OWNER/$PEPO/milestones), We are looking forward to your PR!" + gh issue comment $ISSUE --body "@${{ github.event.comment.user.login }} Glad to see you accepted this issue🤲, this issue has been assigned to you. I set the milestones for this issue to [$LATEST_MILESTONE](https://github.com/$OWNER/$REPO/milestones), We are looking forward to your PR!" - # gh issue edit ${{ github.event.issue.number }} --milestone "$LETASE_MILESTONES" + # gh issue edit ${{ github.event.issue.number }} --milestone "$LATEST_MILESTONE" env: GH_TOKEN: ${{ secrets.BOT_TOKEN }} ISSUE: ${{ github.event.issue.html_url }} diff --git a/.github/workflows/auto-invite-comment.yml b/.github/workflows/auto-invite-comment.yml index 76fbcdfd3..ed086bcf0 100644 --- a/.github/workflows/auto-invite-comment.yml +++ b/.github/workflows/auto-invite-comment.yml @@ -13,7 +13,7 @@ jobs: steps: - name: Invite user to join OpenIM Community - uses: peter-evans/create-or-update-comment@v4 + uses: peter-evans/create-or-update-comment@v5.0.0 with: token: ${{ secrets.BOT_GITHUB_TOKEN }} issue-number: ${{ github.event.issue.number }} diff --git a/.github/workflows/changelog.yml b/.github/workflows/changelog.yml index b97036d91..09584ffa1 100644 --- a/.github/workflows/changelog.yml +++ b/.github/workflows/changelog.yml @@ -13,7 +13,12 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@v7.0.0 + + - name: Set up Go + uses: actions/setup-go@v6.5.0 + with: + go-version-file: go.mod - name: Run Go Changelog Generator run: | @@ -66,7 +71,7 @@ jobs: rm -f "${{ github.event.release.tag_name }}-changelog.md" - name: Create Pull Request - uses: peter-evans/create-pull-request@v7.0.5 + uses: peter-evans/create-pull-request@v8.1.1 with: token: ${{ secrets.GITHUB_TOKEN }} commit-message: "Update CHANGELOG for release ${{ github.event.release.tag_name }}" diff --git a/.github/workflows/cla-assistant.yml b/.github/workflows/cla-assistant.yml index 7d44b05eb..88c16c8c7 100644 --- a/.github/workflows/cla-assistant.yml +++ b/.github/workflows/cla-assistant.yml @@ -18,7 +18,7 @@ jobs: steps: - name: "CLA Assistant" if: (github.event.comment.body == 'recheck' || github.event.comment.body == 'I have read the CLA Document and I hereby sign the CLA') || github.event_name == 'pull_request_target' - uses: contributor-assistant/github-action@v2.4.0 + uses: contributor-assistant/github-action@v2.6.1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} PERSONAL_ACCESS_TOKEN: ${{ secrets.BOT_TOKEN }} diff --git a/.github/workflows/cleanup-after-milestone-prs-merged.yml b/.github/workflows/cleanup-after-milestone-prs-merged.yml index 8a3e381d6..8d7868de4 100644 --- a/.github/workflows/cleanup-after-milestone-prs-merged.yml +++ b/.github/workflows/cleanup-after-milestone-prs-merged.yml @@ -11,14 +11,13 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v4.2.0 + uses: actions/checkout@v7.0.0 - name: Get the PR title and extract PR numbers id: extract_pr_numbers + env: + PR_TITLE: ${{ github.event.pull_request.title }} run: | - # Get the PR title - PR_TITLE="${{ github.event.pull_request.title }}" - echo "PR Title: $PR_TITLE" # Extract PR numbers from the title @@ -57,9 +56,8 @@ jobs: - name: Delete branch after PR close if: steps.extract_pr_numbers.outputs.proceed == 'true' || contains(github.event.pull_request.labels.*.name, 'milestone-merge') + env: + BRANCH_NAME: ${{ github.event.pull_request.head.ref }} run: | - BRANCH_NAME="${{ github.event.pull_request.head.ref }}" echo "Branch to delete: $BRANCH_NAME" git push origin --delete "$BRANCH_NAME" - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index fd871e2b5..340d23614 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -35,11 +35,11 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v7.0.0 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@v3 + uses: github/codeql-action/init@v4.36.2 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -50,7 +50,7 @@ jobs: # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@v3 + uses: github/codeql-action/autobuild@v4.36.2 # ℹ️ Command-line programs to run using the OS shell. # 📚 https://git.io/JvXDl @@ -64,4 +64,4 @@ jobs: # make release - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v3 \ No newline at end of file + uses: github/codeql-action/analyze@v4.36.2 diff --git a/.github/workflows/comment-check.yml b/.github/workflows/comment-check.yml index e994b5259..ec4a1e3ac 100644 --- a/.github/workflows/comment-check.yml +++ b/.github/workflows/comment-check.yml @@ -17,7 +17,7 @@ jobs: EXCLUDE_FILES: "*.md *.txt *.html *.css *.min.js *.mdx" steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v7.0.0 - name: Search for Non-English comments run: | diff --git a/.github/workflows/docker-build-and-release-services-images.yml b/.github/workflows/docker-build-and-release-services-images.yml index 1d085e153..941f83cfa 100644 --- a/.github/workflows/docker-build-and-release-services-images.yml +++ b/.github/workflows/docker-build-and-release-services-images.yml @@ -22,29 +22,29 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v7.0.0 - name: Set up QEMU - uses: docker/setup-qemu-action@v3.3.0 + uses: docker/setup-qemu-action@v4.1.0 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3.8.0 + uses: docker/setup-buildx-action@v4.1.0 - name: Log in to Docker Hub - uses: docker/login-action@v3.3.0 + uses: docker/login-action@v4.2.0 with: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_PASSWORD }} - name: Log in to GitHub Container Registry - uses: docker/login-action@v3.3.0 + uses: docker/login-action@v4.2.0 with: registry: ghcr.io username: ${{ github.repository_owner }} password: ${{ secrets.GITHUB_TOKEN }} - name: Log in to Aliyun Container Registry - uses: docker/login-action@v3.3.0 + uses: docker/login-action@v4.2.0 with: registry: registry.cn-hangzhou.aliyuncs.com username: ${{ secrets.ALIREGISTRY_USERNAME }} diff --git a/.github/workflows/go-build-test.yml b/.github/workflows/go-build-test.yml index 8425293e9..98995ecce 100644 --- a/.github/workflows/go-build-test.yml +++ b/.github/workflows/go-build-test.yml @@ -22,14 +22,14 @@ jobs: strategy: matrix: os: [ubuntu-latest] - go_version: ["1.25.x"] + go_version: ["stable"] steps: - name: Checkout Server repository - uses: actions/checkout@v4 + uses: actions/checkout@v7.0.0 - name: Set up Go ${{ matrix.go_version }} - uses: actions/setup-go@v5 + uses: actions/setup-go@v6.5.0 with: go-version: ${{ matrix.go_version }} @@ -40,7 +40,7 @@ jobs: go mod download - name: Set up infra services - uses: hoverkraft-tech/compose-action@v2.0.1 + uses: hoverkraft-tech/compose-action@v3.0.0 with: compose-file: "./docker-compose.yml" @@ -67,7 +67,7 @@ jobs: mage check - name: Checkout Chat repository - uses: actions/checkout@v4 + uses: actions/checkout@v7.0.0 with: repository: "openimsdk/chat" path: "chat-repo" @@ -188,21 +188,21 @@ jobs: strategy: matrix: os: [ubuntu-latest] - go_version: ["1.25.x"] + go_version: ["stable"] steps: - name: Checkout Server repository - uses: actions/checkout@v4 + uses: actions/checkout@v7.0.0 - name: Checkout SDK repository - uses: actions/checkout@v4 + uses: actions/checkout@v7.0.0 with: repository: "openimsdk/openim-sdk-core" ref: "main" path: ${{ env.SDK_DIR }} - name: Set up Go ${{ matrix.go_version }} - uses: actions/setup-go@v5 + uses: actions/setup-go@v6.5.0 with: go-version: ${{ matrix.go_version }} @@ -237,14 +237,14 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - go_version: ["1.25.x"] + go_version: ["stable"] steps: - name: Checkout Repository - uses: actions/checkout@v4 + uses: actions/checkout@v7.0.0 - name: Set up Go ${{ matrix.go_version }} - uses: actions/setup-go@v5 + uses: actions/setup-go@v6.5.0 with: go-version: ${{ matrix.go_version }} diff --git a/.github/workflows/help-comment-issue.yml b/.github/workflows/help-comment-issue.yml index b1cc62182..7d0e9d4a0 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@v4 + uses: peter-evans/create-or-update-comment@v5.0.0 with: issue-number: ${{ github.event.issue.number }} token: ${{ secrets.BOT_TOKEN }} diff --git a/.github/workflows/merge-from-milestone.yml b/.github/workflows/merge-from-milestone.yml index 44b4f81f4..3a1aca728 100644 --- a/.github/workflows/merge-from-milestone.yml +++ b/.github/workflows/merge-from-milestone.yml @@ -40,7 +40,7 @@ jobs: touch ${{ env.TEMP_DIR }}/created_pr_number.txt - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v7.0.0 with: fetch-depth: 0 token: ${{ secrets.BOT_TOKEN }} diff --git a/.github/workflows/publish-docker-image.yml b/.github/workflows/publish-docker-image.yml index 4cd3316dd..db4c1976b 100644 --- a/.github/workflows/publish-docker-image.yml +++ b/.github/workflows/publish-docker-image.yml @@ -14,7 +14,6 @@ on: default: "v3.8.3" env: - GO_VERSION: "1.22" IMAGE_NAME: "openim-server" # IMAGE_NAME: ${{ github.event.repository.name }} DOCKER_BUILDKIT: 1 @@ -25,22 +24,22 @@ jobs: if: ${{ !(github.event_name == 'pull_request' && github.event.pull_request.merged == false) }} steps: - name: Checkout main repository - uses: actions/checkout@v4 + uses: actions/checkout@v7.0.0 with: path: main-repo - name: Set up QEMU - uses: docker/setup-qemu-action@v3.3.0 + uses: docker/setup-qemu-action@v4.1.0 - name: Set up Docker Buildx id: buildx - uses: docker/setup-buildx-action@v3 + uses: docker/setup-buildx-action@v4.1.0 with: driver-opts: network=host - name: Extract metadata for Docker id: meta - uses: docker/metadata-action@v5.6.0 + uses: docker/metadata-action@v6.1.0 with: images: | ${{ secrets.DOCKER_USERNAME }}/${{ env.IMAGE_NAME }} @@ -80,7 +79,7 @@ jobs: docker image ls | grep openim - name: Checkout compose repository - uses: actions/checkout@v4 + uses: actions/checkout@v7.0.0 with: repository: "openimsdk/openim-docker" path: "compose-repo" @@ -134,20 +133,20 @@ jobs: # fi - name: Log in to Docker Hub - uses: docker/login-action@v3.3.0 + uses: docker/login-action@v4.2.0 with: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_PASSWORD }} - name: Log in to GitHub Container Registry - uses: docker/login-action@v3.3.0 + uses: docker/login-action@v4.2.0 with: registry: ghcr.io username: ${{ github.repository_owner }} password: ${{ secrets.GITHUB_TOKEN }} - name: Log in to Aliyun Container Registry - uses: docker/login-action@v3.3.0 + uses: docker/login-action@v4.2.0 with: registry: registry.cn-hangzhou.aliyuncs.com username: ${{ secrets.ALIREGISTRY_USERNAME }} diff --git a/.github/workflows/remove-unused-labels.yml b/.github/workflows/remove-unused-labels.yml index ab80b1f96..dd75c0cdf 100644 --- a/.github/workflows/remove-unused-labels.yml +++ b/.github/workflows/remove-unused-labels.yml @@ -11,11 +11,11 @@ jobs: contents: read steps: - name: Checkout Repository - uses: actions/checkout@v4 + uses: actions/checkout@v7.0.0 - name: Fetch All Issues and PRs id: fetch_issues_prs - uses: actions/github-script@v7.0.1 + uses: actions/github-script@v9.0.0 with: github-token: ${{ secrets.GITHUB_TOKEN }} script: | @@ -38,7 +38,7 @@ jobs: - name: Fetch All Labels id: fetch_labels - uses: actions/github-script@v7.0.1 + uses: actions/github-script@v9.0.0 with: github-token: ${{ secrets.GITHUB_TOKEN }} script: | @@ -52,7 +52,7 @@ jobs: result-encoding: string - name: Remove Unused Labels - uses: actions/github-script@v7.0.1 + uses: actions/github-script@v9.0.0 with: github-token: ${{ secrets.GITHUB_TOKEN }} script: | diff --git a/.github/workflows/reopen-issue.yml b/.github/workflows/reopen-issue.yml index 32f838ba4..345f09c87 100644 --- a/.github/workflows/reopen-issue.yml +++ b/.github/workflows/reopen-issue.yml @@ -12,11 +12,11 @@ jobs: steps: - name: Checkout Repository - uses: actions/checkout@v4 + uses: actions/checkout@v7.0.0 - name: Fetch Closed Issues with lifecycle/stale Label id: fetch_issues - uses: actions/github-script@v7 + uses: actions/github-script@v9.0.0 with: github-token: ${{ secrets.GITHUB_TOKEN }} script: | @@ -40,7 +40,7 @@ jobs: echo "Issue numbers: ${{ steps.fetch_issues.outputs.result }}" - name: Reopen Issues - uses: actions/github-script@v7 + uses: actions/github-script@v9.0.0 with: github-token: ${{ secrets.GITHUB_TOKEN }} script: | @@ -59,7 +59,7 @@ jobs: } - name: Remove lifecycle/stale Label - uses: actions/github-script@v7 + uses: actions/github-script@v9.0.0 with: github-token: ${{ secrets.GITHUB_TOKEN }} script: | diff --git a/.github/workflows/update-version-file-on-release.yml b/.github/workflows/update-version-file-on-release.yml index b7e2a4409..ca3de2309 100644 --- a/.github/workflows/update-version-file-on-release.yml +++ b/.github/workflows/update-version-file-on-release.yml @@ -12,7 +12,7 @@ jobs: steps: # Step 1: Checkout the original repository's code - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@v7.0.0 with: fetch-depth: 0 # submodules: "recursive" @@ -73,7 +73,7 @@ jobs: # Step 7: Find and Publish Draft Release - name: Find and Publish Draft Release - uses: actions/github-script@v7 + uses: actions/github-script@v9.0.0 with: github-token: ${{ secrets.GITHUB_TOKEN }} script: | diff --git a/.github/workflows/user-first-interaction.yml b/.github/workflows/user-first-interaction.yml index 6999889eb..317fc449e 100644 --- a/.github/workflows/user-first-interaction.yml +++ b/.github/workflows/user-first-interaction.yml @@ -11,11 +11,11 @@ jobs: check_for_first_interaction: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - - uses: actions/first-interaction@v1.3.0 + - uses: actions/checkout@v7.0.0 + - uses: actions/first-interaction@v3.1.0 with: - repo-token: ${{ secrets.BOT_TOKEN }} - pr-message: | + repo_token: ${{ secrets.BOT_TOKEN }} + pr_message: | Hello! Thank you for your contribution. If you are fixing a bug, please reference the issue number in the description. @@ -26,7 +26,7 @@ jobs: Please leave your information in the [✨ discussions](https://github.com/orgs/OpenIMSDK/discussions/426), we expect anyone to join OpenIM developer community. - issue-message: | + issue_message: | Hello! Thank you for filing an issue. If this is a bug report, please include relevant logs to help us debug the problem. diff --git a/Dockerfile b/Dockerfile index 30af8f7ee..c1fceefb5 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.25-alpine AS builder +FROM golang:alpine AS builder ARG RELEASE=false ARG COMPRESS=false diff --git a/build/build.sh b/build/build.sh index 354cd3945..e61b228a3 100755 --- a/build/build.sh +++ b/build/build.sh @@ -24,19 +24,13 @@ fi cd "$BASE_DIR/.." || exit 1 split_values() { - printf '%s\n' "$1" | tr ', ' '\n\n' | while IFS= read -r value; do - [[ -n "$value" ]] && printf '%s\n' "$value" - done -} - -print_command() { - printf '%q ' "$@" - printf '\n' + echo "$1" | grep -o '[^, ]\+' } run_or_print() { if [[ "$DRY_RUN" == "true" ]]; then - print_command "$@" + printf '%q ' "$@" + printf '\n' else "$@" fi @@ -44,7 +38,9 @@ run_or_print() { build_local() { echo -e "${CYAN}Building all services...${NO_COLOR}" - RELEASE="$RELEASE" docker compose -f "$COMPOSE_FILE" build + while IFS= read -r service; do + RELEASE="$RELEASE" docker compose -f "$COMPOSE_FILE" build "$service" + done < <(docker compose -f "$COMPOSE_FILE" config --services) echo -e "${CYAN}Tagging compatibility images for Kubernetes...${NO_COLOR}" while IFS= read -r built_image; do diff --git a/build/images/openim-server/Dockerfile b/build/images/openim-server/Dockerfile index e821260a6..6adecf484 100644 --- a/build/images/openim-server/Dockerfile +++ b/build/images/openim-server/Dockerfile @@ -1,8 +1,4 @@ -FROM golang:1.25-alpine AS builder - -ARG CMD_PATH -ARG BINARY_NAME -ARG RELEASE=false +FROM golang:alpine AS builder ENV SERVER_DIR=/openim-server WORKDIR $SERVER_DIR @@ -10,6 +6,10 @@ WORKDIR $SERVER_DIR COPY . . RUN go mod tidy +ARG CMD_PATH +ARG BINARY_NAME +ARG RELEASE=false + RUN if [ "$RELEASE" = "true" ]; then \ go build -trimpath -ldflags "-s -w" -o _output/${BINARY_NAME} ./${CMD_PATH}; \ else \ diff --git a/build/images/openim-server/docker-compose.build.override.yml b/build/images/openim-server/docker-compose.build.override.yml deleted file mode 100644 index 7ef19f988..000000000 --- a/build/images/openim-server/docker-compose.build.override.yml +++ /dev/null @@ -1,72 +0,0 @@ -services: - openim-api: - build: - platforms: - - linux/amd64 - - linux/arm64 - - openim-crontask: - build: - platforms: - - linux/amd64 - - linux/arm64 - - openim-msggateway: - build: - platforms: - - linux/amd64 - - linux/arm64 - - openim-msgtransfer: - build: - platforms: - - linux/amd64 - - linux/arm64 - - openim-push: - build: - platforms: - - linux/amd64 - - linux/arm64 - - openim-rpc-auth: - build: - platforms: - - linux/amd64 - - linux/arm64 - - openim-rpc-conversation: - build: - platforms: - - linux/amd64 - - linux/arm64 - - openim-rpc-friend: - build: - platforms: - - linux/amd64 - - linux/arm64 - - openim-rpc-group: - build: - platforms: - - linux/amd64 - - linux/arm64 - - openim-rpc-msg: - build: - platforms: - - linux/amd64 - - linux/arm64 - - openim-rpc-third: - build: - platforms: - - linux/amd64 - - linux/arm64 - - openim-rpc-user: - build: - platforms: - - linux/amd64 - - linux/arm64 diff --git a/go.mod b/go.mod index 2fe0631e8..4caa277da 100644 --- a/go.mod +++ b/go.mod @@ -13,7 +13,7 @@ require ( github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 github.com/mitchellh/mapstructure v1.5.0 github.com/openimsdk/protocol v0.0.73-alpha.12 - github.com/openimsdk/tools v0.0.50-alpha.117 + github.com/openimsdk/tools v0.0.50-alpha.119 github.com/pkg/errors v0.9.1 // indirect github.com/prometheus/client_golang v1.18.0 github.com/stretchr/testify v1.11.1 diff --git a/go.sum b/go.sum index c6f331882..47059e30d 100644 --- a/go.sum +++ b/go.sum @@ -365,6 +365,8 @@ github.com/openimsdk/protocol v0.0.73-alpha.12 h1:2NYawXeHChYUeSme6QJ9pOLh+Empce github.com/openimsdk/protocol v0.0.73-alpha.12/go.mod h1:WF7EuE55vQvpyUAzDXcqg+B+446xQyEba0X35lTINmw= github.com/openimsdk/tools v0.0.50-alpha.117 h1:ACfijEVCeBcttT7OOkNGOOOvq14pJtb9szNIMHLm6Vc= github.com/openimsdk/tools v0.0.50-alpha.117/go.mod h1:I0WESSa7ghPIo9BL+ETlH/qEIbO6+KZioM1jwNuDwz0= +github.com/openimsdk/tools v0.0.50-alpha.119 h1:S/RjRtL0ciwiG6pZKssbU//qVSWi7AuKHOPCHsQgz68= +github.com/openimsdk/tools v0.0.50-alpha.119/go.mod h1:I0WESSa7ghPIo9BL+ETlH/qEIbO6+KZioM1jwNuDwz0= github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM= github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= github.com/pierrec/lz4/v4 v4.1.21 h1:yOVMLb6qSIDP67pl/5F7RepeKYu/VmTyEXvuMI5d9mQ= diff --git a/internal/msggateway/ws_server.go b/internal/msggateway/ws_server.go index 404751df3..e3ab26f2d 100644 --- a/internal/msggateway/ws_server.go +++ b/internal/msggateway/ws_server.go @@ -14,6 +14,7 @@ import ( "github.com/openimsdk/tools/apiresp" "github.com/go-playground/validator/v10" + "github.com/openimsdk/open-im-server/v3/pkg/common/config" "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/webhook" @@ -288,25 +289,12 @@ func (ws *WsServer) registerClient(client *Client) { } } - wg := sync.WaitGroup{} log.ZDebug(client.ctx, "ws.msgGatewayConfig.Discovery.Enable", "discoveryEnable", ws.msgGatewayConfig.Discovery.Enable) - if ws.msgGatewayConfig.Discovery.Enable != "k8s" { - wg.Add(1) - go func() { - defer wg.Done() - _ = ws.sendUserOnlineInfoToOtherNode(client.ctx, client) - }() + if ws.msgGatewayConfig.Discovery.Enable != config.KUBERNETES { + _ = ws.sendUserOnlineInfoToOtherNode(client.ctx, client) } - //wg.Add(1) - //go func() { - // defer wg.Done() - // ws.SetUserOnlineStatus(client.ctx, client, constant.Online) - //}() - - wg.Wait() - log.ZDebug(client.ctx, "user online", "online user Num", ws.onlineUserNum.Load(), "online user conn Num", ws.onlineUserConnNum.Load()) } diff --git a/internal/push/onlinepusher.go b/internal/push/onlinepusher.go index 2393c3567..6db61059a 100644 --- a/internal/push/onlinepusher.go +++ b/internal/push/onlinepusher.go @@ -4,6 +4,7 @@ import ( "context" "sync" + conf "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/protocol/msggateway" "github.com/openimsdk/protocol/sdkws" "github.com/openimsdk/tools/discovery" @@ -39,11 +40,11 @@ func (u emptyOnlinePusher) GetOnlinePushFailedUserIDs(ctx context.Context, msg * func NewOnlinePusher(disCov discovery.SvcDiscoveryRegistry, config *Config) OnlinePusher { switch config.Discovery.Enable { - case "k8s": - return NewK8sStaticConsistentHash(disCov, config) + case conf.KUBERNETES: + return NewDefaultAllNode(disCov, config) case "zookeeper": return NewDefaultAllNode(disCov, config) - case "etcd": + case conf.ETCD: return NewDefaultAllNode(disCov, config) default: return newEmptyOnlinePusher() diff --git a/internal/rpc/conversation/conversation.go b/internal/rpc/conversation/conversation.go index 707a67b14..194b1b6ad 100644 --- a/internal/rpc/conversation/conversation.go +++ b/internal/rpc/conversation/conversation.go @@ -24,7 +24,6 @@ import ( "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" dbModel "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model" "github.com/openimsdk/open-im-server/v3/pkg/localcache" "github.com/openimsdk/open-im-server/v3/pkg/msgprocessor" @@ -233,9 +232,28 @@ func (c *conversationServer) getConversations(ctx context.Context, ownerUserID s // Deprecated func (c *conversationServer) SetConversation(ctx context.Context, req *pbconversation.SetConversationReq) (*pbconversation.SetConversationResp, error) { + if req.Conversation == nil { + return nil, errs.ErrArgs.WrapMsg("conversation must not be nil") + } var conversation dbModel.Conversation - if err := datautil.CopyStructFields(&conversation, req.Conversation); err != nil { - return nil, err + conversation.OwnerUserID = req.Conversation.OwnerUserID + conversation.ConversationID = req.Conversation.ConversationID + conversation.RecvMsgOpt = req.Conversation.RecvMsgOpt + conversation.ConversationType = req.Conversation.ConversationType + conversation.UserID = req.Conversation.UserID + conversation.GroupID = req.Conversation.GroupID + conversation.IsPinned = req.Conversation.IsPinned + conversation.AttachedInfo = req.Conversation.AttachedInfo + conversation.IsPrivateChat = req.Conversation.IsPrivateChat + conversation.GroupAtType = req.Conversation.GroupAtType + conversation.Ex = req.Conversation.Ex + conversation.BurnDuration = req.Conversation.BurnDuration + conversation.MinSeq = req.Conversation.MinSeq + conversation.MaxSeq = req.Conversation.MaxSeq + conversation.MsgDestructTime = req.Conversation.MsgDestructTime + conversation.IsMsgDestruct = req.Conversation.IsMsgDestruct + if req.Conversation.LatestMsgDestructTime != 0 { + conversation.LatestMsgDestructTime = time.UnixMilli(req.Conversation.LatestMsgDestructTime) } err := c.conversationDatabase.SetUserConversations(ctx, req.Conversation.OwnerUserID, []*dbModel.Conversation{&conversation}) if err != nil { @@ -506,17 +524,6 @@ func (c *conversationServer) GetUserConversationIDsHash(ctx context.Context, req return &pbconversation.GetUserConversationIDsHashResp{Hash: hash}, nil } -func (c *conversationServer) GetConversationsByConversationID( - ctx context.Context, - req *pbconversation.GetConversationsByConversationIDReq, -) (*pbconversation.GetConversationsByConversationIDResp, error) { - conversations, err := c.conversationDatabase.GetConversationsByConversationID(ctx, req.ConversationIDs) - if err != nil { - return nil, err - } - return &pbconversation.GetConversationsByConversationIDResp{Conversations: convert.ConversationsDB2Pb(conversations)}, nil -} - func (c *conversationServer) GetConversationOfflinePushUserIDs(ctx context.Context, req *pbconversation.GetConversationOfflinePushUserIDsReq) (*pbconversation.GetConversationOfflinePushUserIDsResp, error) { if req.ConversationID == "" { return nil, errs.ErrArgs.WrapMsg("conversationID is empty") @@ -606,9 +613,17 @@ func (c *conversationServer) getConversationInfo( } for conversationID, chatLog := range chatLogs { pbchatLog := &pbconversation.ConversationElem{} - msgInfo := &pbconversation.MsgInfo{} - if err := datautil.CopyStructFields(msgInfo, chatLog); err != nil { - return nil, err + msgInfo := &pbconversation.MsgInfo{ + ServerMsgID: chatLog.ServerMsgID, + ClientMsgID: chatLog.ClientMsgID, + SessionType: chatLog.SessionType, + SendID: chatLog.SendID, + RecvID: chatLog.RecvID, + GroupID: chatLog.GroupID, + MsgFrom: chatLog.MsgFrom, + ContentType: chatLog.ContentType, + Content: string(chatLog.Content), + Ex: chatLog.Ex, } switch chatLog.SessionType { case constant.SingleChatType: @@ -708,56 +723,6 @@ func (c *conversationServer) GetOwnerConversation(ctx context.Context, req *pbco }, nil } -func (c *conversationServer) GetConversationsNeedClearMsg(ctx context.Context, _ *pbconversation.GetConversationsNeedClearMsgReq) (*pbconversation.GetConversationsNeedClearMsgResp, error) { - num, err := c.conversationDatabase.GetAllConversationIDsNumber(ctx) - if err != nil { - log.ZError(ctx, "GetAllConversationIDsNumber failed", err) - return nil, err - } - const batchNum = 100 - - if num == 0 { - return nil, errs.New("Need Destruct Msg is nil").Wrap() - } - - maxPage := (num + batchNum - 1) / batchNum - - temp := make([]*model.Conversation, 0, maxPage*batchNum) - - for pageNumber := 0; pageNumber < int(maxPage); pageNumber++ { - 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 success", "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 - } - - for _, conversation := range conversations { - if conversation.IsMsgDestruct && conversation.MsgDestructTime != 0 && ((time.Now().UnixMilli() > (conversation.MsgDestructTime + conversation.LatestMsgDestructTime.UnixMilli() + 8*60*60)) || // 8*60*60 is UTC+8 - conversation.LatestMsgDestructTime.IsZero()) { - temp = append(temp, conversation) - } - } - } - - return &pbconversation.GetConversationsNeedClearMsgResp{Conversations: convert.ConversationsDB2Pb(temp)}, nil -} - func (c *conversationServer) GetNotNotifyConversationIDs(ctx context.Context, req *pbconversation.GetNotNotifyConversationIDsReq) (*pbconversation.GetNotNotifyConversationIDsResp, error) { conversationIDs, err := c.conversationDatabase.GetNotNotifyConversationIDs(ctx, req.UserID) if err != nil { diff --git a/internal/rpc/msg/delete.go b/internal/rpc/msg/delete.go index d3485faaa..621fbca28 100644 --- a/internal/rpc/msg/delete.go +++ b/internal/rpc/msg/delete.go @@ -19,7 +19,6 @@ import ( "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" @@ -74,7 +73,7 @@ func (m *msgServer) DeleteMsgs(ctx context.Context, req *msg.DeleteMsgsReq) (*ms if err := m.MsgDatabase.DeleteMsgsPhysicalBySeqs(ctx, req.ConversationID, req.Seqs); err != nil { return nil, err } - conv, err := m.conversationClient.GetConversationsByConversationID(ctx, req.ConversationID) + conv, err := m.conversationClient.GetConversation(ctx, req.ConversationID, req.UserID) if err != nil { return nil, err } @@ -113,14 +112,12 @@ func (m *msgServer) DeleteMsgPhysical(ctx context.Context, req *msg.DeleteMsgPhy } func (m *msgServer) clearConversation(ctx context.Context, conversationIDs []string, userID string, deleteSyncOpt *msg.DeleteSyncOpt) error { - conversations, err := m.conversationClient.GetConversationsByConversationIDs(ctx, conversationIDs) + conversations, err := m.conversationClient.GetConversations(ctx, conversationIDs, userID) if err != nil { return err } - var existConversations []*conversation.Conversation var existConversationIDs []string for _, conversation := range conversations { - existConversations = append(existConversations, conversation) existConversationIDs = append(existConversationIDs, conversation.ConversationID) } log.ZDebug(ctx, "ClearConversationsMsg", "existConversationIDs", existConversationIDs) @@ -149,7 +146,7 @@ func (m *msgServer) clearConversation(ctx context.Context, conversationIDs []str if err := m.MsgDatabase.SetMinSeqs(ctx, m.getMinSeqs(maxSeqs)); err != nil { return err } - for _, conversation := range existConversations { + for _, conversation := range conversations { tips := &sdkws.ClearConversationTips{UserID: userID, ConversationIDs: []string{conversation.ConversationID}} m.notificationSender.NotificationWithSessionType(ctx, userID, m.conversationAndGetRecvID(conversation, userID), constant.ClearConversationNotification, conversation.ConversationType, tips) } diff --git a/internal/rpc/msg/sync_msg.go b/internal/rpc/msg/sync_msg.go index 6cf1c21d3..aa11817e6 100644 --- a/internal/rpc/msg/sync_msg.go +++ b/internal/rpc/msg/sync_msg.go @@ -24,7 +24,6 @@ import ( "github.com/openimsdk/protocol/msg" "github.com/openimsdk/protocol/sdkws" "github.com/openimsdk/tools/log" - "github.com/openimsdk/tools/utils/datautil" "github.com/openimsdk/tools/utils/timeutil" ) @@ -216,9 +215,24 @@ func (m *msgServer) SearchMessage(ctx context.Context, req *msg.SearchMessageReq // Construct response with updated information for _, chatLog := range chatLogs { pbchatLog := &msg.ChatLog{} - datautil.CopyStructFields(pbchatLog, chatLog.MsgData) - pbchatLog.SendTime = chatLog.MsgData.SendTime - pbchatLog.CreateTime = chatLog.MsgData.CreateTime + msgData := chatLog.MsgData + pbchatLog.ServerMsgID = msgData.ServerMsgID + pbchatLog.ClientMsgID = msgData.ClientMsgID + pbchatLog.SendID = msgData.SendID + pbchatLog.RecvID = msgData.RecvID + pbchatLog.GroupID = msgData.GroupID + pbchatLog.SenderPlatformID = msgData.SenderPlatformID + pbchatLog.SenderNickname = msgData.SenderNickname + pbchatLog.SenderFaceURL = msgData.SenderFaceURL + pbchatLog.SessionType = msgData.SessionType + pbchatLog.MsgFrom = msgData.MsgFrom + pbchatLog.ContentType = msgData.ContentType + pbchatLog.Content = string(msgData.Content) + pbchatLog.Status = msgData.Status + pbchatLog.SendTime = msgData.SendTime + pbchatLog.CreateTime = msgData.CreateTime + pbchatLog.Ex = msgData.Ex + pbchatLog.Seq = msgData.Seq if chatLog.MsgData.SenderNickname == "" { pbchatLog.SenderNickname = sendMap[chatLog.MsgData.SendID] } diff --git a/internal/tools/cron_test.go b/internal/tools/cron_test.go index 890349069..8aa830935 100644 --- a/internal/tools/cron_test.go +++ b/internal/tools/cron_test.go @@ -23,7 +23,7 @@ func TestName(t *testing.T) { Address: []string{"localhost:12379"}, }, } - client, err := kdisc.NewDiscoveryRegister(conf, "source") + client, err := kdisc.NewDiscoveryRegister(conf, &config.Share{}, nil) if err != nil { panic(err) } diff --git a/pkg/common/config/config.go b/pkg/common/config/config.go index 4cd202db4..7e54bf4d4 100644 --- a/pkg/common/config/config.go +++ b/pkg/common/config/config.go @@ -484,9 +484,14 @@ type ZooKeeper struct { } type Discovery struct { - Enable string `mapstructure:"enable"` - Etcd Etcd `mapstructure:"etcd"` - ZooKeeper ZooKeeper `mapstructure:"zooKeeper"` + Enable string `mapstructure:"enable"` + Etcd Etcd `mapstructure:"etcd"` + Kubernetes Kubernetes `mapstructure:"kubernetes"` + ZooKeeper ZooKeeper `mapstructure:"zooKeeper"` +} + +type Kubernetes struct { + Namespace string `mapstructure:"namespace"` } type Etcd struct { diff --git a/pkg/common/config/load_config_test.go b/pkg/common/config/load_config_test.go index 763bffd9f..fab85c3a6 100644 --- a/pkg/common/config/load_config_test.go +++ b/pkg/common/config/load_config_test.go @@ -1,8 +1,12 @@ package config import ( - "github.com/stretchr/testify/assert" + "os" + "path/filepath" + "testing" + + "github.com/stretchr/testify/assert" ) func TestLoadLogConfig(t *testing.T) { @@ -27,6 +31,24 @@ func TestLoadWebhooksConfig(t *testing.T) { } +func TestLoadDiscoveryKubernetesConfig(t *testing.T) { + path := filepath.Join(t.TempDir(), "discovery.yml") + err := os.WriteFile(path, []byte(`enable: kubernetes +kubernetes: + namespace: openim +etcd: + rootDirectory: openim + address: [localhost:12379] +`), 0600) + assert.Nil(t, err) + + var discovery Discovery + err = LoadConfig(path, "IMENV_DISCOVERY", &discovery) + assert.Nil(t, err) + assert.Equal(t, KUBERNETES, discovery.Enable) + assert.Equal(t, "openim", discovery.Kubernetes.Namespace) +} + func TestLoadOpenIMRpcUserConfig(t *testing.T) { var user User err := LoadConfig("../../../config/openim-rpc-user.yml", "IMENV_OPENIM_RPC_USER", &user) diff --git a/pkg/common/convert/conversation.go b/pkg/common/convert/conversation.go index 9389b0252..9da7b9205 100644 --- a/pkg/common/convert/conversation.go +++ b/pkg/common/convert/conversation.go @@ -15,46 +15,120 @@ package convert import ( + "time" + "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 *model.Conversation) *conversation.Conversation { - conversationPB := &conversation.Conversation{} - conversationPB.LatestMsgDestructTime = conversationDB.LatestMsgDestructTime.UnixMilli() - if err := datautil.CopyStructFields(conversationPB, conversationDB); err != nil { + if conversationDB == nil { return nil } - return conversationPB + return &conversation.Conversation{ + OwnerUserID: conversationDB.OwnerUserID, + ConversationID: conversationDB.ConversationID, + RecvMsgOpt: conversationDB.RecvMsgOpt, + ConversationType: conversationDB.ConversationType, + UserID: conversationDB.UserID, + GroupID: conversationDB.GroupID, + IsPinned: conversationDB.IsPinned, + AttachedInfo: conversationDB.AttachedInfo, + IsPrivateChat: conversationDB.IsPrivateChat, + GroupAtType: conversationDB.GroupAtType, + Ex: conversationDB.Ex, + BurnDuration: conversationDB.BurnDuration, + MinSeq: conversationDB.MinSeq, + MaxSeq: conversationDB.MaxSeq, + MsgDestructTime: conversationDB.MsgDestructTime, + LatestMsgDestructTime: conversationDB.LatestMsgDestructTime.UnixMilli(), + IsMsgDestruct: conversationDB.IsMsgDestruct, + } } func ConversationsDB2Pb(conversationsDB []*model.Conversation) (conversationsPB []*conversation.Conversation) { for _, conversationDB := range conversationsDB { - conversationPB := &conversation.Conversation{} - if err := datautil.CopyStructFields(conversationPB, conversationDB); err != nil { + if conversationDB == nil { continue } - conversationPB.LatestMsgDestructTime = conversationDB.LatestMsgDestructTime.UnixMilli() + conversationPB := &conversation.Conversation{ + OwnerUserID: conversationDB.OwnerUserID, + ConversationID: conversationDB.ConversationID, + RecvMsgOpt: conversationDB.RecvMsgOpt, + ConversationType: conversationDB.ConversationType, + UserID: conversationDB.UserID, + GroupID: conversationDB.GroupID, + IsPinned: conversationDB.IsPinned, + AttachedInfo: conversationDB.AttachedInfo, + IsPrivateChat: conversationDB.IsPrivateChat, + GroupAtType: conversationDB.GroupAtType, + Ex: conversationDB.Ex, + BurnDuration: conversationDB.BurnDuration, + MinSeq: conversationDB.MinSeq, + MaxSeq: conversationDB.MaxSeq, + MsgDestructTime: conversationDB.MsgDestructTime, + LatestMsgDestructTime: conversationDB.LatestMsgDestructTime.UnixMilli(), + IsMsgDestruct: conversationDB.IsMsgDestruct, + } conversationsPB = append(conversationsPB, conversationPB) } return conversationsPB } func ConversationPb2DB(conversationPB *conversation.Conversation) *model.Conversation { - conversationDB := &model.Conversation{} - if err := datautil.CopyStructFields(conversationDB, conversationPB); err != nil { + if conversationPB == nil { return nil } + conversationDB := &model.Conversation{ + OwnerUserID: conversationPB.OwnerUserID, + ConversationID: conversationPB.ConversationID, + RecvMsgOpt: conversationPB.RecvMsgOpt, + ConversationType: conversationPB.ConversationType, + UserID: conversationPB.UserID, + GroupID: conversationPB.GroupID, + IsPinned: conversationPB.IsPinned, + AttachedInfo: conversationPB.AttachedInfo, + IsPrivateChat: conversationPB.IsPrivateChat, + GroupAtType: conversationPB.GroupAtType, + Ex: conversationPB.Ex, + BurnDuration: conversationPB.BurnDuration, + MinSeq: conversationPB.MinSeq, + MaxSeq: conversationPB.MaxSeq, + MsgDestructTime: conversationPB.MsgDestructTime, + IsMsgDestruct: conversationPB.IsMsgDestruct, + } + if conversationPB.LatestMsgDestructTime != 0 { + conversationDB.LatestMsgDestructTime = time.UnixMilli(conversationPB.LatestMsgDestructTime) + } return conversationDB } func ConversationsPb2DB(conversationsPB []*conversation.Conversation) (conversationsDB []*model.Conversation) { for _, conversationPB := range conversationsPB { - conversationDB := &model.Conversation{} - if err := datautil.CopyStructFields(conversationDB, conversationPB); err != nil { + if conversationPB == nil { continue } + conversationDB := &model.Conversation{ + OwnerUserID: conversationPB.OwnerUserID, + ConversationID: conversationPB.ConversationID, + RecvMsgOpt: conversationPB.RecvMsgOpt, + ConversationType: conversationPB.ConversationType, + UserID: conversationPB.UserID, + GroupID: conversationPB.GroupID, + IsPinned: conversationPB.IsPinned, + AttachedInfo: conversationPB.AttachedInfo, + IsPrivateChat: conversationPB.IsPrivateChat, + GroupAtType: conversationPB.GroupAtType, + Ex: conversationPB.Ex, + BurnDuration: conversationPB.BurnDuration, + MinSeq: conversationPB.MinSeq, + MaxSeq: conversationPB.MaxSeq, + MsgDestructTime: conversationPB.MsgDestructTime, + IsMsgDestruct: conversationPB.IsMsgDestruct, + } + if conversationPB.LatestMsgDestructTime != 0 { + conversationDB.LatestMsgDestructTime = time.UnixMilli(conversationPB.LatestMsgDestructTime) + } conversationsDB = append(conversationsDB, conversationDB) } return conversationsDB diff --git a/pkg/common/convert/friend.go b/pkg/common/convert/friend.go index e783ecb24..e9002d744 100644 --- a/pkg/common/convert/friend.go +++ b/pkg/common/convert/friend.go @@ -21,18 +21,22 @@ import ( "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model" "github.com/openimsdk/open-im-server/v3/pkg/notification/common_user" "github.com/openimsdk/protocol/relation" - "github.com/openimsdk/protocol/sdkws" "github.com/openimsdk/tools/utils/datautil" "github.com/openimsdk/tools/utils/timeutil" ) func FriendPb2DB(friend *sdkws.FriendInfo) *model.Friend { - dbFriend := &model.Friend{} - err := datautil.CopyStructFields(dbFriend, friend) - if err != nil { + if friend == nil { return nil } + dbFriend := &model.Friend{} + dbFriend.OwnerUserID = friend.OwnerUserID + dbFriend.Remark = friend.Remark + dbFriend.AddSource = friend.AddSource + dbFriend.OperatorUserID = friend.OperatorUserID + dbFriend.Ex = friend.Ex + dbFriend.IsPinned = friend.IsPinned dbFriend.FriendUserID = friend.FriendUser.UserID dbFriend.CreateTime = timeutil.UnixSecondToTime(friend.CreateTime) return dbFriend @@ -69,10 +73,12 @@ func FriendsDB2Pb(ctx context.Context, friendsDB []*model.Friend, getUsers func( } for _, friend := range friendsDB { friendPb := &sdkws.FriendInfo{FriendUser: &sdkws.UserInfo{}} - err := datautil.CopyStructFields(friendPb, friend) - if err != nil { - return nil, err - } + friendPb.OwnerUserID = friend.OwnerUserID + friendPb.Remark = friend.Remark + friendPb.AddSource = friend.AddSource + friendPb.OperatorUserID = friend.OperatorUserID + friendPb.Ex = friend.Ex + friendPb.IsPinned = friend.IsPinned friendPb.FriendUser.UserID = users[friend.FriendUserID].UserID friendPb.FriendUser.Nickname = users[friend.FriendUserID].Nickname diff --git a/pkg/common/discoveryregister/discoveryregister.go b/pkg/common/discoveryregister/discoveryregister.go index 110a08aa8..ec444defb 100644 --- a/pkg/common/discoveryregister/discoveryregister.go +++ b/pkg/common/discoveryregister/discoveryregister.go @@ -22,19 +22,26 @@ import ( "github.com/openimsdk/tools/discovery/etcd" "github.com/openimsdk/tools/discovery/kubernetes" "github.com/openimsdk/tools/errs" + "github.com/openimsdk/tools/utils/runtimeenv" "google.golang.org/grpc" ) // NewDiscoveryRegister creates a new service discovery and registry client based on the provided environment type. func NewDiscoveryRegister(discovery *config.Discovery, share *config.Share, watchNames []string) (discovery.SvcDiscoveryRegistry, error) { - switch discovery.Enable { - case "k8s": - return kubernetes.NewConnManager("default", watchNames, + if runtimeenv.RuntimeEnvironment() == config.KUBERNETES { + namespace := discovery.Kubernetes.Namespace + if namespace == "" { + namespace = "default" + } + return kubernetes.NewConnManager(namespace, watchNames, grpc.WithDefaultCallOptions( grpc.MaxCallSendMsgSize(1024*1024*20), ), ) - case "etcd": + } + + switch discovery.Enable { + case config.ETCD: return etcd.NewSvcDiscoveryRegistry( discovery.Etcd.RootDirectory, discovery.Etcd.Address, diff --git a/pkg/common/discoveryregister/discoveryregister_test.go b/pkg/common/discoveryregister/discoveryregister_test.go index 417226645..3e90e324a 100644 --- a/pkg/common/discoveryregister/discoveryregister_test.go +++ b/pkg/common/discoveryregister/discoveryregister_test.go @@ -15,16 +15,12 @@ package discoveryregister import ( - "os" -) + "strings" + "testing" -func setupTestEnvironment() { - os.Setenv("ZOOKEEPER_SCHEMA", "openim") - os.Setenv("ZOOKEEPER_ADDRESS", "172.28.0.1") - os.Setenv("ZOOKEEPER_PORT", "12181") - os.Setenv("ZOOKEEPER_USERNAME", "") - os.Setenv("ZOOKEEPER_PASSWORD", "") -} + "github.com/openimsdk/open-im-server/v3/pkg/common/config" + "github.com/openimsdk/tools/utils/runtimeenv" +) //func TestNewDiscoveryRegister(t *testing.T) { // setupTestEnvironment() @@ -58,3 +54,23 @@ func setupTestEnvironment() { // } // } //} + +func TestNewDiscoveryRegisterRejectsKubernetesOutsideCluster(t *testing.T) { + if runtimeenv.RuntimeEnvironment() == config.KUBERNETES { + t.Skip("outside-cluster fallback is only relevant outside Kubernetes") + } + discovery := &config.Discovery{ + Enable: config.KUBERNETES, + Kubernetes: config.Kubernetes{ + Namespace: "default", + }, + } + + client, err := NewDiscoveryRegister(discovery, &config.Share{}, nil) + if err == nil && client != nil { + client.Close() + } + if err == nil || !strings.Contains(err.Error(), "unsupported discovery type") { + t.Fatalf("%q outside Kubernetes should not select Kubernetes discovery: %v", config.KUBERNETES, err) + } +} diff --git a/pkg/common/storage/controller/conversation.go b/pkg/common/storage/controller/conversation.go index d4088e0c0..b35eadf1e 100644 --- a/pkg/common/storage/controller/conversation.go +++ b/pkg/common/storage/controller/conversation.go @@ -59,8 +59,6 @@ type ConversationDatabase interface { 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) - // GetConversationsByConversationID retrieves conversations by their IDs. - 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.Conversation, error) // GetConversationNotReceiveMessageUserIDs gets user IDs for users in a conversation who have not received messages. @@ -127,13 +125,10 @@ func (c *conversationDatabase) SetUsersConversationFieldTx(ctx context.Context, var conversations []*relationtb.Conversation now := time.Now() for _, v := range NotUserIDs { - temp := new(relationtb.Conversation) - if err = datautil.CopyStructFields(temp, conversation); err != nil { - return err - } + temp := *conversation temp.OwnerUserID = v temp.CreateTime = now - conversations = append(conversations, temp) + conversations = append(conversations, &temp) } if len(conversations) > 0 { err = c.conversationDB.Create(ctx, conversations) @@ -351,10 +346,6 @@ func (c *conversationDatabase) PageConversationIDs(ctx context.Context, paginati return c.conversationDB.PageConversationIDs(ctx, pagination) } -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.Conversation, error) { return c.conversationDB.GetConversationIDsNeedDestruct(ctx) } diff --git a/pkg/common/storage/database/conversation.go b/pkg/common/storage/database/conversation.go index 1fb53cfed..155c698f6 100644 --- a/pkg/common/storage/database/conversation.go +++ b/pkg/common/storage/database/conversation.go @@ -38,7 +38,6 @@ type Conversation interface { 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) ([]*model.Conversation, error) GetConversationIDsNeedDestruct(ctx context.Context) ([]*model.Conversation, error) GetConversationNotReceiveMessageUserIDs(ctx context.Context, conversationID string) ([]string, error) FindConversationUserVersion(ctx context.Context, userID string, version uint, limit int) (*model.VersionLog, error) diff --git a/pkg/common/storage/database/mgo/conversation.go b/pkg/common/storage/database/mgo/conversation.go index 536827450..b6436e1c8 100644 --- a/pkg/common/storage/database/mgo/conversation.go +++ b/pkg/common/storage/database/mgo/conversation.go @@ -32,12 +32,25 @@ import ( func NewConversationMongo(db *mongo.Database) (*ConversationMgo, error) { coll := db.Collection(database.ConversationName) - _, err := coll.Indexes().CreateOne(context.Background(), mongo.IndexModel{ - Keys: bson.D{ - {Key: "owner_user_id", Value: 1}, - {Key: "conversation_id", Value: 1}, + _, err := coll.Indexes().CreateMany(context.Background(), []mongo.IndexModel{ + { + Keys: bson.D{ + {Key: "owner_user_id", Value: 1}, + {Key: "conversation_id", Value: 1}, + }, + Options: options.Index().SetUnique(true), + }, + { + Keys: bson.D{ + {Key: "user_id", Value: 1}, + }, + Options: options.Index(), + }, + { + Keys: bson.D{ + {Key: "conversation_id", Value: 1}, + }, }, - Options: options.Index().SetUnique(true), }) if err != nil { return nil, errs.Wrap(err) @@ -191,10 +204,6 @@ 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) ([]*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) ([]*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[*model.Conversation](ctx, c.coll, bson.M{ diff --git a/pkg/rpccache/online.go b/pkg/rpccache/online.go index 87823c1c0..61ba584d6 100644 --- a/pkg/rpccache/online.go +++ b/pkg/rpccache/online.go @@ -202,8 +202,6 @@ func (o *OnlineCache) GetUserOnlinePlatform(ctx context.Context, userID string) if err != nil { return nil, err } - tmp := make([]int32, len(platformIDs)) - copy(tmp, platformIDs) return platformIDs, nil } diff --git a/pkg/rpcli/conversation.go b/pkg/rpcli/conversation.go index ba5b90cb3..a5b7446a1 100644 --- a/pkg/rpcli/conversation.go +++ b/pkg/rpcli/conversation.go @@ -2,6 +2,7 @@ package rpcli import ( "context" + "github.com/openimsdk/protocol/conversation" "google.golang.org/grpc" ) @@ -30,18 +31,6 @@ func (x *ConversationClient) SetConversations(ctx context.Context, ownerUserIDs return ignoreResp(x.ConversationClient.SetConversations(ctx, req)) } -func (x *ConversationClient) GetConversationsByConversationIDs(ctx context.Context, conversationIDs []string) ([]*conversation.Conversation, error) { - if len(conversationIDs) == 0 { - return nil, nil - } - req := &conversation.GetConversationsByConversationIDReq{ConversationIDs: conversationIDs} - return extractField(ctx, x.ConversationClient.GetConversationsByConversationID, req, (*conversation.GetConversationsByConversationIDResp).GetConversations) -} - -func (x *ConversationClient) GetConversationsByConversationID(ctx context.Context, conversationID string) (*conversation.Conversation, error) { - return firstValue(x.GetConversationsByConversationIDs(ctx, []string{conversationID})) -} - func (x *ConversationClient) SetConversationMinSeq(ctx context.Context, conversationID string, ownerUserIDs []string, minSeq int64) error { if len(ownerUserIDs) == 0 { return nil diff --git a/pkg/tools/batcher/batcher.go b/pkg/tools/batcher/batcher.go index 163aeed39..93b447f77 100644 --- a/pkg/tools/batcher/batcher.go +++ b/pkg/tools/batcher/batcher.go @@ -149,12 +149,21 @@ func (b *Batcher[T]) Put(ctx context.Context, data *T) error { func (b *Batcher[T]) scheduler() { ticker := time.NewTicker(b.config.interval) + // Track whether b.data was closed by an external caller so the + // cleanup below does not close it a second time. The only routes + // out of this function that leave b.data open are the nil-message + // and ticker paths; the ok == false branch means someone already + // closed the channel, and calling close(b.data) again there would + // panic with "close of closed channel" (#3653). + externallyClosed := false defer func() { ticker.Stop() for _, ch := range b.chArrays { close(ch) } - close(b.data) + if !externallyClosed { + close(b.data) + } b.wait.Done() }() @@ -167,6 +176,7 @@ func (b *Batcher[T]) scheduler() { case data, ok := <-b.data: if !ok { // If the data channel is closed unexpectedly + externallyClosed = true return } if data == nil { diff --git a/tools/changelog/changelog.go b/tools/changelog/changelog.go index 75d914a27..b76dc6e1d 100644 --- a/tools/changelog/changelog.go +++ b/tools/changelog/changelog.go @@ -2,6 +2,7 @@ package main import ( "encoding/json" + "errors" "fmt" "io" "net/http" @@ -35,6 +36,10 @@ type ReleaseData struct { Published string `json:"published_at"` } +type GitHubError struct { + Message string `json:"message"` +} + // Method to classify and format release notes. func (g *GitHubRepo) classifyReleaseNotes(body string) map[string][]string { result := map[string][]string{ @@ -49,10 +54,7 @@ func (g *GitHubRepo) classifyReleaseNotes(body string) map[string][]string { // Regular expression to extract PR number and URL (case insensitive) rePR := regexp.MustCompile(`(?i)in (https://github\.com/[^\s]+/pull/(\d+))`) - // Split the body into individual lines. - lines := strings.Split(body, "\n") - - for _, line := range lines { + for line := range strings.SplitSeq(body, "\n") { // Skip lines that contain "deps: Merge" if strings.Contains(strings.ToLower(line), "deps: merge #") { continue @@ -108,7 +110,17 @@ func (g *GitHubRepo) classifyReleaseNotes(body string) map[string][]string { } // Method to generate the final changelog. -func (g *GitHubRepo) generateChangelog(tag, date, htmlURL, body string) string { +func (g *GitHubRepo) generateChangelog(tag, date, htmlURL, body string) (string, error) { + if tag == "" { + return "", errors.New("release tag is empty") + } + if len(date) < 10 { + return "", fmt.Errorf("release published_at is invalid: %q", date) + } + if htmlURL == "" { + return "", errors.New("release html_url is empty") + } + sections := g.classifyReleaseNotes(body) // Convert ISO 8601 date to simpler format (YYYY-MM-DD) @@ -140,7 +152,7 @@ func (g *GitHubRepo) generateChangelog(tag, date, htmlURL, body string) string { changelog += fmt.Sprintf("**Full Changelog**: %s\n", g.FullChangelog) } - return changelog + return changelog, nil } // Method to fetch release data from GitHub API. @@ -165,6 +177,13 @@ func (g *GitHubRepo) fetchReleaseData(version string) (*ReleaseData, error) { if err != nil { return nil, err } + if resp.StatusCode < http.StatusOK || resp.StatusCode >= http.StatusMultipleChoices { + var githubError GitHubError + if err := json.Unmarshal(body, &githubError); err == nil && githubError.Message != "" { + return nil, fmt.Errorf("github api returned %s: %s", resp.Status, githubError.Message) + } + return nil, fmt.Errorf("github api returned %s", resp.Status) + } var releaseData ReleaseData err = json.Unmarshal(body, &releaseData) @@ -188,11 +207,15 @@ func main() { // Fetch release data (either for latest or specific version) releaseData, err := repo.fetchReleaseData(version) if err != nil { - fmt.Println("Error fetching release data:", err) - return + fmt.Fprintln(os.Stderr, "Error fetching release data:", err) + os.Exit(1) } // Generate and print the formatted changelog - changelog := repo.generateChangelog(releaseData.TagName, releaseData.Published, releaseData.HtmlUrl, releaseData.Body) + changelog, err := repo.generateChangelog(releaseData.TagName, releaseData.Published, releaseData.HtmlUrl, releaseData.Body) + if err != nil { + fmt.Fprintln(os.Stderr, "Error generating changelog:", err) + os.Exit(1) + } fmt.Println(changelog) }