Merge branch 'openimsdk:main' into main

pull/3735/head
chao 2 weeks ago committed by GitHub
commit 75ebca4ff8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -16,11 +16,17 @@ on:
jobs:
build-and-push:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up QEMU
uses: docker/setup-qemu-action@v3.3.0
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3.8.0
@ -44,48 +50,63 @@ jobs:
username: ${{ secrets.ALIREGISTRY_USERNAME }}
password: ${{ secrets.ALIREGISTRY_TOKEN }}
- name: Extract metadata for Docker (tags, labels)
id: meta
uses: docker/metadata-action@v5.6.0
with:
tags: |
type=ref,event=tag
type=schedule
type=ref,event=branch
type=semver,pattern={{version}}
type=semver,pattern=v{{version}}
type=semver,pattern=release-{{raw}}
type=sha
type=raw,value=${{ github.event.inputs.tag }}
- name: Resolve Docker image tags
id: tags
env:
INPUT_TAG: ${{ github.event.inputs.tag }}
RELEASE_TAG: ${{ github.event.release.tag_name }}
run: |
set -euo pipefail
tags=()
declare -A seen=()
add_tag() {
local tag="$1"
[[ -n "$tag" ]] || return 0
tag="${tag//\//-}"
if [[ -z "${seen[$tag]+x}" ]]; then
tags+=("$tag")
seen["$tag"]=1
fi
}
add_tag_with_semver_alias() {
local tag="$1"
add_tag "$tag"
if [[ "$tag" =~ ^v([0-9]+\.[0-9]+\.[0-9]+.*)$ ]]; then
add_tag "${BASH_REMATCH[1]}"
add_tag "release-$tag"
fi
}
add_tag_with_semver_alias "${INPUT_TAG:-}"
add_tag_with_semver_alias "${RELEASE_TAG:-}"
if [[ "${GITHUB_REF_TYPE:-}" == "tag" ]]; then
add_tag_with_semver_alias "${GITHUB_REF_NAME}"
elif [[ "${GITHUB_REF_TYPE:-}" == "branch" ]]; then
add_tag "${GITHUB_REF_NAME}"
fi
add_tag "sha-${GITHUB_SHA::7}"
{
echo "tags<<EOF"
printf '%s\n' "${tags[@]}"
echo "EOF"
} >> "$GITHUB_OUTPUT"
- name: Build and push Docker images
env:
RELEASE: "true"
PUSH: "true"
PLATFORMS: linux/amd64,linux/arm64
IMAGE_TAGS: ${{ steps.tags.outputs.tags }}
IMAGE_REGISTRIES: |
${{ secrets.DOCKER_USERNAME }}
ghcr.io/${{ github.repository_owner }}
registry.cn-hangzhou.aliyuncs.com/openimsdk
run: |
IMG_DIR="build/images"
for dir in "$IMG_DIR"/*/; do
# Find Dockerfile or *.dockerfile in a case-insensitive manner
dockerfile=$(find "$dir" -maxdepth 1 -type f \( -iname 'dockerfile' -o -iname '*.dockerfile' \) | head -n 1)
if [ -n "$dockerfile" ] && [ -f "$dockerfile" ]; then
IMAGE_NAME=$(basename "$dir")
echo "Building Docker image for $IMAGE_NAME with tags:"
# Initialize tag arguments
tag_args=()
# Read each tag and append --tag arguments
while IFS= read -r tag; do
tag_args+=(--tag "${{ secrets.DOCKER_USERNAME }}/$IMAGE_NAME:$tag")
tag_args+=(--tag "ghcr.io/${{ github.repository_owner }}/$IMAGE_NAME:$tag")
tag_args+=(--tag "registry.cn-hangzhou.aliyuncs.com/openimsdk/$IMAGE_NAME:$tag")
done <<< "${{ steps.meta.outputs.tags }}"
# Build and push the Docker image with all tags
docker buildx build --platform linux/amd64,linux/arm64 \
--file "$dockerfile" \
"${tag_args[@]}" \
--push \
"."
else
echo "No valid Dockerfile found in $dir"
fi
done
bash build/build.sh

@ -22,7 +22,7 @@ jobs:
strategy:
matrix:
os: [ubuntu-latest]
go_version: ["1.22.x"]
go_version: ["1.25.x"]
steps:
- name: Checkout Server repository
@ -188,7 +188,7 @@ jobs:
strategy:
matrix:
os: [ubuntu-latest]
go_version: ["1.22.x"]
go_version: ["1.25.x"]
steps:
- name: Checkout Server repository
@ -237,7 +237,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
go_version: ["1.22"]
go_version: ["1.25.x"]
steps:
- name: Checkout Repository

@ -1,49 +1,25 @@
# Use Go 1.22 Alpine as the base image for building the application
FROM golang:1.22-alpine AS builder
FROM golang:1.25-alpine AS builder
# Define the base directory for the application as an environment variable
ENV SERVER_DIR=/openim-server
ARG RELEASE=false
ARG COMPRESS=false
WORKDIR /openim-server
# Set the working directory inside the container based on the environment variable
WORKDIR $SERVER_DIR
RUN apk add --no-cache upx
# Set the Go proxy to improve dependency resolution speed
# ENV GOPROXY=https://goproxy.io,direct
RUN go install github.com/magefile/mage@latest
# Copy all files from the current directory into the container
COPY . .
RUN go mod download
RUN RELEASE=${RELEASE} COMPRESS=${COMPRESS} mage build
RUN mage -compile ./mage -ldflags "-s -w"
# Install Mage to use for building the application
RUN go install github.com/magefile/mage@v1.15.0
# Optionally build your application if needed
RUN mage build
# Using Alpine Linux with Go environment for the final image
FROM golang:1.22-alpine
# Install necessary packages, such as bash
RUN apk add --no-cache bash
# Set the environment and work directory
ENV SERVER_DIR=/openim-server
WORKDIR $SERVER_DIR
FROM alpine:latest
# 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/
WORKDIR /openim-server
RUN go get github.com/openimsdk/gomake@v0.0.15-alpha.1
COPY --from=builder /openim-server/_output ./_output
COPY --from=builder /openim-server/config ./config
COPY --from=builder /openim-server/start-config.yml ./start-config.yml
COPY --from=builder /openim-server/mage ./mage
# Set the command to run when the container starts
ENTRYPOINT ["sh", "-c", "mage start && tail -f /dev/null"]
ENTRYPOINT ["sh", "-c", "./mage start && sleep infinity"]

@ -0,0 +1,133 @@
#!/usr/bin/env bash
set -euo pipefail
CYAN='\033[0;36m'
GREEN='\033[0;32m'
RED='\033[0;31m'
NO_COLOR='\033[0m'
BASE_DIR="$(cd "$(dirname "$0")" && pwd)"
COMPOSE_FILE="$BASE_DIR/images/openim-server/docker-compose.build.yml"
RELEASE="${RELEASE:-false}"
PUSH="${PUSH:-false}"
DRY_RUN="${DRY_RUN:-false}"
PLATFORMS="${PLATFORMS:-linux/amd64,linux/arm64}"
IMAGE_TAGS="${IMAGE_TAGS:-}"
IMAGE_REGISTRIES="${IMAGE_REGISTRIES:-}"
if [[ ! -f "$COMPOSE_FILE" ]]; then
echo -e "${RED}docker-compose.build.yml not found: $COMPOSE_FILE${NO_COLOR}"
exit 1
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'
}
run_or_print() {
if [[ "$DRY_RUN" == "true" ]]; then
print_command "$@"
else
"$@"
fi
}
build_local() {
echo -e "${CYAN}Building all services...${NO_COLOR}"
RELEASE="$RELEASE" docker compose -f "$COMPOSE_FILE" build
echo -e "${CYAN}Tagging compatibility images for Kubernetes...${NO_COLOR}"
while IFS= read -r built_image; do
[[ -n "$built_image" ]] || continue
compatibility_tag="${built_image##*/}"
if [[ "$built_image" != "$compatibility_tag" ]]; then
docker tag "$built_image" "$compatibility_tag"
fi
done < <(docker compose -f "$COMPOSE_FILE" config --images)
echo -e "${GREEN}Successfully built all services${NO_COLOR}"
}
build_push() {
if ! command -v jq >/dev/null 2>&1; then
echo -e "${RED}jq is required for PUSH=true${NO_COLOR}"
exit 1
fi
if [[ -z "$IMAGE_TAGS" || -z "$IMAGE_REGISTRIES" ]]; then
echo -e "${RED}IMAGE_TAGS and IMAGE_REGISTRIES are required for PUSH=true${NO_COLOR}"
exit 1
fi
image_tags=()
while IFS= read -r tag; do
image_tags+=("$tag")
done < <(split_values "$IMAGE_TAGS")
image_registries=()
while IFS= read -r registry; do
image_registries+=("$registry")
done < <(split_values "$IMAGE_REGISTRIES")
if [[ ${#image_tags[@]} -eq 0 || ${#image_registries[@]} -eq 0 ]]; then
echo -e "${RED}IMAGE_TAGS and IMAGE_REGISTRIES must contain at least one value${NO_COLOR}"
exit 1
fi
compose_config=$(docker compose -f "$COMPOSE_FILE" config --format json)
echo -e "${CYAN}Building and pushing service images...${NO_COLOR}"
while IFS= read -r service; do
context=$(jq -r --arg service "$service" '.services[$service].build.context // empty' <<< "$compose_config")
dockerfile=$(jq -r --arg service "$service" '.services[$service].build.dockerfile // empty' <<< "$compose_config")
cmd_path=$(jq -r --arg service "$service" '.services[$service].build.args.CMD_PATH // empty' <<< "$compose_config")
binary_name=$(jq -r --arg service "$service" '.services[$service].build.args.BINARY_NAME // empty' <<< "$compose_config")
if [[ -z "$context" || -z "$dockerfile" || -z "$cmd_path" || -z "$binary_name" ]]; then
echo -e "${RED}Invalid build config for $service${NO_COLOR}"
exit 1
fi
if [[ ! -d "$cmd_path" && ! -f "$cmd_path/main.go" ]]; then
echo -e "${CYAN}Skipping $service because $cmd_path does not exist${NO_COLOR}"
continue
fi
tag_args=()
for registry in "${image_registries[@]}"; do
for tag in "${image_tags[@]}"; do
tag_args+=(--tag "$registry/$binary_name:$tag")
done
done
echo -e "${CYAN}Building $binary_name for $PLATFORMS...${NO_COLOR}"
run_or_print docker buildx build \
--platform "$PLATFORMS" \
--file "$dockerfile" \
--build-arg "CMD_PATH=$cmd_path" \
--build-arg "BINARY_NAME=$binary_name" \
--build-arg "RELEASE=$RELEASE" \
"${tag_args[@]}" \
--push \
"$context"
done < <(jq -r '.services | keys[]' <<< "$compose_config" | sort)
echo -e "${GREEN}Successfully pushed service images${NO_COLOR}"
}
if [[ "$PUSH" == "true" ]]; then
build_push
else
build_local
fi

@ -1,24 +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.
# FROM BASE_IMAGE
# WORKDIR ${SERVER_WORKDIR}
# # Set HTTP proxy
# ARG BINARY_NAME
# COPY BINARY_NAME ./bin/BINARY_NAME
# ENTRYPOINT ["./bin/BINARY_NAME"]

@ -1,36 +0,0 @@
# Use Go 1.22 Alpine as the base image for building the application
FROM golang:1.22-alpine AS builder
# Define the base directory for the application as an environment variable
ENV SERVER_DIR=/openim-server
# Set the working directory inside the container based on the environment variable
WORKDIR $SERVER_DIR
# Set the Go proxy to improve dependency resolution speed
#ENV GOPROXY=https://goproxy.io,direct
# Copy all files from the current directory into the container
COPY . .
RUN go mod tidy
RUN go build -o _output/openim-api ./cmd/openim-api
# Using Alpine Linux for the final image
FROM alpine:latest
# Install necessary packages, such as bash
RUN apk add --no-cache bash
# Set the environment and work directory
ENV 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
# Set the command to run when the container starts
ENTRYPOINT ["sh", "-c", "_output/openim-api"]

@ -1,39 +0,0 @@
# Use Go 1.22 Alpine as the base image for building the application
FROM golang:1.22-alpine AS builder
# Define the base directory for the application as an environment variable
ENV SERVER_DIR=/openim-server
# Set the working directory inside the container based on the environment variable
WORKDIR $SERVER_DIR
# Set the Go proxy to improve dependency resolution speed
#ENV GOPROXY=https://goproxy.io,direct
# Copy all files from the current directory into the container
COPY . .
RUN go mod tidy
RUN go build -o _output/openim-crontask ./cmd/openim-crontask
# Using Alpine Linux for the final image
FROM alpine:latest
# Install necessary packages, such as bash
RUN apk add --no-cache bash
# Set the environment and work directory
ENV 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
# Set the command to run when the container starts
ENTRYPOINT ["sh", "-c", "_output/openim-crontask"]

@ -1,39 +0,0 @@
# Use Go 1.22 Alpine as the base image for building the application
FROM golang:1.22-alpine AS builder
# Define the base directory for the application as an environment variable
ENV SERVER_DIR=/openim-server
# Set the working directory inside the container based on the environment variable
WORKDIR $SERVER_DIR
# Set the Go proxy to improve dependency resolution speed
#ENV GOPROXY=https://goproxy.io,direct
# Copy all files from the current directory into the container
COPY . .
RUN go mod tidy
RUN go build -o _output/openim-msggateway ./cmd/openim-msggateway
# Using Alpine Linux for the final image
FROM alpine:latest
# Install necessary packages, such as bash
RUN apk add --no-cache bash
# Set the environment and work directory
ENV 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
# Set the command to run when the container starts
ENTRYPOINT ["sh", "-c", "_output/openim-msggateway"]

@ -1,39 +0,0 @@
# Use Go 1.22 Alpine as the base image for building the application
FROM golang:1.22-alpine AS builder
# Define the base directory for the application as an environment variable
ENV SERVER_DIR=/openim-server
# Set the working directory inside the container based on the environment variable
WORKDIR $SERVER_DIR
# Set the Go proxy to improve dependency resolution speed
#ENV GOPROXY=https://goproxy.io,direct
# Copy all files from the current directory into the container
COPY . .
RUN go mod tidy
RUN go build -o _output/openim-msgtransfer ./cmd/openim-msgtransfer
# Using Alpine Linux for the final image
FROM alpine:latest
# Install necessary packages, such as bash
RUN apk add --no-cache bash
# Set the environment and work directory
ENV 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
# Set the command to run when the container starts
ENTRYPOINT ["sh", "-c", "_output/openim-msgtransfer"]

@ -1,39 +0,0 @@
# Use Go 1.22 Alpine as the base image for building the application
FROM golang:1.22-alpine AS builder
# Define the base directory for the application as an environment variable
ENV SERVER_DIR=/openim-server
# Set the working directory inside the container based on the environment variable
WORKDIR $SERVER_DIR
# Set the Go proxy to improve dependency resolution speed
#ENV GOPROXY=https://goproxy.io,direct
# Copy all files from the current directory into the container
COPY . .
RUN go mod tidy
RUN go build -o _output/openim-push ./cmd/openim-push
# Using Alpine Linux for the final image
FROM alpine:latest
# Install necessary packages, such as bash
RUN apk add --no-cache bash
# Set the environment and work directory
ENV 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
# Set the command to run when the container starts
ENTRYPOINT ["sh", "-c", "_output/openim-push"]

@ -1,39 +0,0 @@
# Use Go 1.22 Alpine as the base image for building the application
FROM golang:1.22-alpine AS builder
# Define the base directory for the application as an environment variable
ENV SERVER_DIR=/openim-server
# Set the working directory inside the container based on the environment variable
WORKDIR $SERVER_DIR
# Set the Go proxy to improve dependency resolution speed
#ENV GOPROXY=https://goproxy.io,direct
# Copy all files from the current directory into the container
COPY . .
RUN go mod tidy
RUN go build -o _output/openim-rpc-auth ./cmd/openim-rpc/openim-rpc-auth
# Using Alpine Linux for the final image
FROM alpine:latest
# Install necessary packages, such as bash
RUN apk add --no-cache bash
# Set the environment and work directory
ENV 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
# Set the command to run when the container starts
ENTRYPOINT ["sh", "-c", "_output/openim-rpc-auth"]

@ -1,39 +0,0 @@
# Use Go 1.22 Alpine as the base image for building the application
FROM golang:1.22-alpine AS builder
# Define the base directory for the application as an environment variable
ENV SERVER_DIR=/openim-server
# Set the working directory inside the container based on the environment variable
WORKDIR $SERVER_DIR
# Set the Go proxy to improve dependency resolution speed
#ENV GOPROXY=https://goproxy.io,direct
# Copy all files from the current directory into the container
COPY . .
RUN go mod tidy
RUN go build -o _output/openim-rpc-conversation ./cmd/openim-rpc/openim-rpc-conversation
# Using Alpine Linux for the final image
FROM alpine:latest
# Install necessary packages, such as bash
RUN apk add --no-cache bash
# Set the environment and work directory
ENV 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
# Set the command to run when the container starts
ENTRYPOINT ["sh", "-c", "_output/openim-rpc-conversation"]

@ -1,39 +0,0 @@
# Use Go 1.22 Alpine as the base image for building the application
FROM golang:1.22-alpine AS builder
# Define the base directory for the application as an environment variable
ENV SERVER_DIR=/openim-server
# Set the working directory inside the container based on the environment variable
WORKDIR $SERVER_DIR
# Set the Go proxy to improve dependency resolution speed
#ENV GOPROXY=https://goproxy.io,direct
# Copy all files from the current directory into the container
COPY . .
RUN go mod tidy
RUN go build -o _output/openim-rpc-friend ./cmd/openim-rpc/openim-rpc-friend
# Using Alpine Linux for the final image
FROM alpine:latest
# Install necessary packages, such as bash
RUN apk add --no-cache bash
# Set the environment and work directory
ENV 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
# Set the command to run when the container starts
ENTRYPOINT ["sh", "-c", "_output/openim-rpc-friend"]

@ -1,39 +0,0 @@
# Use Go 1.22 Alpine as the base image for building the application
FROM golang:1.22-alpine AS builder
# Define the base directory for the application as an environment variable
ENV SERVER_DIR=/openim-server
# Set the working directory inside the container based on the environment variable
WORKDIR $SERVER_DIR
# Set the Go proxy to improve dependency resolution speed
#ENV GOPROXY=https://goproxy.io,direct
# Copy all files from the current directory into the container
COPY . .
RUN go mod tidy
RUN go build -o _output/openim-rpc-group ./cmd/openim-rpc/openim-rpc-group
# Using Alpine Linux for the final image
FROM alpine:latest
# Install necessary packages, such as bash
RUN apk add --no-cache bash
# Set the environment and work directory
ENV 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
# Set the command to run when the container starts
ENTRYPOINT ["sh", "-c", "_output/openim-rpc-group"]

@ -1,39 +0,0 @@
# Use Go 1.22 Alpine as the base image for building the application
FROM golang:1.22-alpine AS builder
# Define the base directory for the application as an environment variable
ENV SERVER_DIR=/openim-server
# Set the working directory inside the container based on the environment variable
WORKDIR $SERVER_DIR
# Set the Go proxy to improve dependency resolution speed
#ENV GOPROXY=https://goproxy.io,direct
# Copy all files from the current directory into the container
COPY . .
RUN go mod tidy
RUN go build -o _output/openim-rpc-msg ./cmd/openim-rpc/openim-rpc-msg
# Using Alpine Linux for the final image
FROM alpine:latest
# Install necessary packages, such as bash
RUN apk add --no-cache bash
# Set the environment and work directory
ENV 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
# Set the command to run when the container starts
ENTRYPOINT ["sh", "-c", "_output/openim-rpc-msg"]

@ -1,39 +0,0 @@
# Use Go 1.22 Alpine as the base image for building the application
FROM golang:1.22-alpine AS builder
# Define the base directory for the application as an environment variable
ENV SERVER_DIR=/openim-server
# Set the working directory inside the container based on the environment variable
WORKDIR $SERVER_DIR
# Set the Go proxy to improve dependency resolution speed
#ENV GOPROXY=https://goproxy.io,direct
# Copy all files from the current directory into the container
COPY . .
RUN go mod tidy
RUN go build -o _output/openim-rpc-third ./cmd/openim-rpc/openim-rpc-third
# Using Alpine Linux for the final image
FROM alpine:latest
# Install necessary packages, such as bash
RUN apk add --no-cache bash
# Set the environment and work directory
ENV 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
# Set the command to run when the container starts
ENTRYPOINT ["sh", "-c", "_output/openim-rpc-third"]

@ -1,37 +0,0 @@
# Use Go 1.22 Alpine as the base image for building the application
FROM golang:1.22-alpine AS builder
# Define the base directory for the application as an environment variable
ENV SERVER_DIR=/openim-server
# Set the working directory inside the container based on the environment variable
WORKDIR $SERVER_DIR
# Set the Go proxy to improve dependency resolution speed
#ENV GOPROXY=https://goproxy.io,direct
# Copy all files from the current directory into the container
COPY . .
RUN go mod tidy
RUN go build -o _output/openim-rpc-user ./cmd/openim-rpc/openim-rpc-user
# Using Alpine Linux for the final image
FROM alpine:latest
# Install necessary packages, such as bash
RUN apk add --no-cache bash
# Set the environment and work directory
ENV 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
# Set the command to run when the container starts
ENTRYPOINT ["sh", "-c", "_output/openim-rpc-user"]

@ -0,0 +1,30 @@
FROM golang:1.25-alpine AS builder
ARG CMD_PATH
ARG BINARY_NAME
ARG RELEASE=false
ENV SERVER_DIR=/openim-server
WORKDIR $SERVER_DIR
COPY . .
RUN go mod tidy
RUN if [ "$RELEASE" = "true" ]; then \
go build -trimpath -ldflags "-s -w" -o _output/${BINARY_NAME} ./${CMD_PATH}; \
else \
go build -o _output/${BINARY_NAME} ./${CMD_PATH}; \
fi
FROM alpine:latest
RUN apk add --no-cache bash
ARG BINARY_NAME
ENV BINARY_NAME=${BINARY_NAME}
ENV SERVER_DIR=/openim-server
WORKDIR $SERVER_DIR
COPY --from=builder $SERVER_DIR/_output $SERVER_DIR/_output
ENTRYPOINT ["sh", "-c", "_output/${BINARY_NAME}"]

@ -0,0 +1,72 @@
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

@ -0,0 +1,120 @@
services:
openim-api:
build:
context: ../../..
dockerfile: build/images/openim-server/Dockerfile
args:
CMD_PATH: cmd/openim-api
BINARY_NAME: openim-api
RELEASE: ${RELEASE:-false}
image: openim-api:test
openim-crontask:
build:
context: ../../..
dockerfile: build/images/openim-server/Dockerfile
args:
CMD_PATH: cmd/openim-crontask
BINARY_NAME: openim-crontask
RELEASE: ${RELEASE:-false}
image: openim-crontask:test
openim-msggateway:
build:
context: ../../..
dockerfile: build/images/openim-server/Dockerfile
args:
CMD_PATH: cmd/openim-msggateway
BINARY_NAME: openim-msggateway
RELEASE: ${RELEASE:-false}
image: openim-msggateway:test
openim-msgtransfer:
build:
context: ../../..
dockerfile: build/images/openim-server/Dockerfile
args:
CMD_PATH: cmd/openim-msgtransfer
BINARY_NAME: openim-msgtransfer
RELEASE: ${RELEASE:-false}
image: openim-msgtransfer:test
openim-push:
build:
context: ../../..
dockerfile: build/images/openim-server/Dockerfile
args:
CMD_PATH: cmd/openim-push
BINARY_NAME: openim-push
RELEASE: ${RELEASE:-false}
image: openim-push:test
openim-rpc-auth:
build:
context: ../../..
dockerfile: build/images/openim-server/Dockerfile
args:
CMD_PATH: cmd/openim-rpc/openim-rpc-auth
BINARY_NAME: openim-rpc-auth
RELEASE: ${RELEASE:-false}
image: openim-rpc-auth:test
openim-rpc-conversation:
build:
context: ../../..
dockerfile: build/images/openim-server/Dockerfile
args:
CMD_PATH: cmd/openim-rpc/openim-rpc-conversation
BINARY_NAME: openim-rpc-conversation
RELEASE: ${RELEASE:-false}
image: openim-rpc-conversation:test
openim-rpc-friend:
build:
context: ../../..
dockerfile: build/images/openim-server/Dockerfile
args:
CMD_PATH: cmd/openim-rpc/openim-rpc-friend
BINARY_NAME: openim-rpc-friend
RELEASE: ${RELEASE:-false}
image: openim-rpc-friend:test
openim-rpc-group:
build:
context: ../../..
dockerfile: build/images/openim-server/Dockerfile
args:
CMD_PATH: cmd/openim-rpc/openim-rpc-group
BINARY_NAME: openim-rpc-group
RELEASE: ${RELEASE:-false}
image: openim-rpc-group:test
openim-rpc-msg:
build:
context: ../../..
dockerfile: build/images/openim-server/Dockerfile
args:
CMD_PATH: cmd/openim-rpc/openim-rpc-msg
BINARY_NAME: openim-rpc-msg
RELEASE: ${RELEASE:-false}
image: openim-rpc-msg:test
openim-rpc-third:
build:
context: ../../..
dockerfile: build/images/openim-server/Dockerfile
args:
CMD_PATH: cmd/openim-rpc/openim-rpc-third
BINARY_NAME: openim-rpc-third
RELEASE: ${RELEASE:-false}
image: openim-rpc-third:test
openim-rpc-user:
build:
context: ../../..
dockerfile: build/images/openim-server/Dockerfile
args:
CMD_PATH: cmd/openim-rpc/openim-rpc-user
BINARY_NAME: openim-rpc-user
RELEASE: ${RELEASE:-false}
image: openim-rpc-user:test

@ -1,108 +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
#
# WORKDIR /openim/openim-server
#
# ENV GOPROXY=$GOPROXY
# COPY go.mod go.sum ./
# RUN go mod download
# COPY . .
# RUN make clean
# RUN make build BINS=component
# # 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 /openim/openim-server/_output/bin/tools /openim/openim-server/_output/bin/tools/
# COPY --from=builder /openim/openim-server/config /openim/openim-server/config
# ENV OPENIM_SERVER_CONFIG_NAME=/openim/openim-server/config
# RUN mv ${OPENIM_SERVER_BINDIR}/platforms/$(get_os)/$(get_arch)/component /usr/bin/component
# ENTRYPOINT ["bash", "-c", "component -c $OPENIM_SERVER_CONFIG_NAME"]
# Use Go 1.22 Alpine as the base image for building the application
FROM golang:1.22-alpine AS builder
# Define the base directory for the application as an environment variable
ENV SERVER_DIR=/openim-server
# Set the working directory inside the container based on the environment variable
WORKDIR $SERVER_DIR
# Set the Go proxy to improve dependency resolution speed
#ENV GOPROXY=https://goproxy.io,direct
# Copy all files from the current directory into the container
COPY . .
RUN go mod download
# Install Mage to use for building the application
RUN go install github.com/magefile/mage@v1.15.0
# ENV BINS=openim-rpc-user
# Optionally build your application if needed
# RUN mage build ${BINS} check-free-memory seq || true
RUN mage build check-free-memory seq || true
# Using Alpine Linux with Go environment for the final image
FROM golang:1.22-alpine
# Install necessary packages, such as bash
RUN apk add bash
# 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 echo -e "serviceBinaries:\n \n" \
> $SERVER_DIR/start-config.yml && \
echo -e "toolBinaries:\n - check-free-memory\n - seq\n" >> $SERVER_DIR/start-config.yml && \
echo "maxFileDescriptors: 10000" >> $SERVER_DIR/start-config.yml
RUN go get github.com/openimsdk/gomake@v0.0.15-alpha.1
# Set the command to run when the container starts
ENTRYPOINT ["sh", "-c", "mage start && tail -f /dev/null"]

@ -1,6 +1,6 @@
module github.com/openimsdk/open-im-server/v3
go 1.22.7
go 1.25.0
require (
firebase.google.com/go/v4 v4.14.1
@ -8,19 +8,19 @@ require (
github.com/gin-gonic/gin v1.9.1
github.com/go-playground/validator/v10 v10.20.0
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang-jwt/jwt/v4 v4.5.1
github.com/golang-jwt/jwt/v4 v4.5.2
github.com/gorilla/websocket v1.5.1
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.18
github.com/openimsdk/tools v0.0.50-alpha.106
github.com/openimsdk/protocol v0.0.73-alpha.19
github.com/openimsdk/tools v0.0.50-alpha.117
github.com/pkg/errors v0.9.1 // indirect
github.com/prometheus/client_golang v1.18.0
github.com/stretchr/testify v1.10.0
github.com/stretchr/testify v1.11.1
go.mongodb.org/mongo-driver v1.14.0
google.golang.org/api v0.170.0
google.golang.org/grpc v1.71.0
google.golang.org/protobuf v1.36.4
google.golang.org/grpc v1.79.3
google.golang.org/protobuf v1.36.10
gopkg.in/yaml.v3 v3.0.1
)
@ -35,14 +35,14 @@ 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.15-alpha.11
github.com/openimsdk/gomake v0.0.17
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
github.com/spf13/viper v1.18.2
go.etcd.io/etcd/client/v3 v3.5.13
go.uber.org/automaxprocs v1.5.3
golang.org/x/sync v0.10.0
golang.org/x/sync v0.20.0
k8s.io/api v0.31.2
k8s.io/apimachinery v0.31.2
k8s.io/client-go v0.31.2
@ -50,7 +50,7 @@ require (
require (
cloud.google.com/go v0.112.1 // indirect
cloud.google.com/go/compute/metadata v0.6.0 // indirect
cloud.google.com/go/compute/metadata v0.9.0 // indirect
cloud.google.com/go/firestore v1.15.0 // indirect
cloud.google.com/go/iam v1.1.7 // indirect
cloud.google.com/go/longrunning v0.5.5 // indirect
@ -76,6 +76,7 @@ require (
github.com/aws/aws-sdk-go-v2/service/sts v1.33.1 // indirect
github.com/aws/smithy-go v1.22.1 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/bmatcuk/doublestar/v4 v4.10.0 // indirect
github.com/bytedance/sonic v1.11.6 // indirect
github.com/bytedance/sonic/loader v0.1.1 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
@ -90,15 +91,16 @@ require (
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/ebitengine/purego v0.10.0 // indirect
github.com/emicklei/go-restful/v3 v3.11.0 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/fsnotify/fsnotify v1.9.0 // indirect
github.com/fxamacker/cbor/v2 v2.7.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.3 // indirect
github.com/gin-contrib/sse v0.1.0 // indirect
github.com/go-logr/logr v1.4.2 // indirect
github.com/go-logr/logr v1.4.3 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-ole/go-ole v1.2.6 // indirect
github.com/go-ole/go-ole v1.3.0 // indirect
github.com/go-openapi/jsonpointer v0.19.6 // indirect
github.com/go-openapi/jsonreference v0.20.2 // indirect
github.com/go-openapi/swag v0.22.4 // indirect
@ -108,7 +110,7 @@ require (
github.com/golang/protobuf v1.5.4 // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/google/gnostic-models v0.6.8 // indirect
github.com/google/go-cmp v0.6.0 // indirect
github.com/google/go-cmp v0.7.0 // indirect
github.com/google/go-querystring v1.1.0 // indirect
github.com/google/gofuzz v1.2.0 // indirect
github.com/google/s2a-go v0.1.7 // indirect
@ -135,7 +137,7 @@ require (
github.com/leodido/go-urn v1.4.0 // indirect
github.com/lestrrat-go/strftime v1.0.6 // indirect
github.com/lithammer/shortuuid v3.0.0+incompatible // indirect
github.com/lufia/plan9stats v0.0.0-20230110061619-bbe2e5e100de // indirect
github.com/lufia/plan9stats v0.0.0-20260216142805-b3301c5f2a88 // indirect
github.com/magefile/mage v1.15.0 // indirect
github.com/magiconair/properties v1.8.7 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
@ -152,7 +154,7 @@ require (
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
github.com/pierrec/lz4/v4 v4.1.21 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b // indirect
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // 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
@ -163,6 +165,7 @@ require (
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
github.com/sercand/kuberesolver/v6 v6.0.1 // indirect
github.com/shirou/gopsutil/v3 v3.24.5 // indirect
github.com/shirou/gopsutil/v4 v4.26.2 // indirect
github.com/shoenig/go-m1cpu v0.1.6 // indirect
github.com/sourcegraph/conc v0.3.0 // indirect
github.com/spf13/afero v1.11.0 // indirect
@ -171,8 +174,8 @@ require (
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/tklauser/go-sysconf v0.3.16 // indirect
github.com/tklauser/numcpus v0.11.0 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/x448/float16 v0.8.4 // indirect
github.com/xdg-go/pbkdf2 v1.0.0 // indirect
@ -183,27 +186,27 @@ require (
go.etcd.io/etcd/api/v3 v3.5.13 // indirect
go.etcd.io/etcd/client/pkg/v3 v3.5.13 // indirect
go.opencensus.io v0.24.0 // indirect
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 // indirect
go.opentelemetry.io/otel v1.34.0 // indirect
go.opentelemetry.io/otel/metric v1.34.0 // indirect
go.opentelemetry.io/otel/trace v1.34.0 // indirect
go.opentelemetry.io/otel v1.39.0 // indirect
go.opentelemetry.io/otel/metric v1.39.0 // indirect
go.opentelemetry.io/otel/trace v1.39.0 // indirect
go.uber.org/atomic v1.9.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
golang.org/x/arch v0.7.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.34.0 // indirect
golang.org/x/oauth2 v0.25.0 // indirect
golang.org/x/sys v0.29.0 // indirect
golang.org/x/term v0.28.0 // indirect
golang.org/x/text v0.21.0 // indirect
golang.org/x/image v0.39.0 // indirect
golang.org/x/net v0.55.0 // indirect
golang.org/x/oauth2 v0.34.0 // indirect
golang.org/x/sys v0.45.0 // indirect
golang.org/x/term v0.43.0 // indirect
golang.org/x/text v0.37.0 // indirect
golang.org/x/time v0.5.0 // indirect
google.golang.org/appengine/v2 v2.0.2 // indirect
google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20250106144421-5f5ef82da422 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20251202230838-ff82c1b0f217 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gorm.io/gorm v1.25.8 // indirect
@ -222,6 +225,6 @@ require (
github.com/spf13/cobra v1.8.0
github.com/ugorji/go/codec v1.2.12 // indirect
go.uber.org/zap v1.24.0 // indirect
golang.org/x/crypto v0.32.0 // indirect
golang.org/x/crypto v0.52.0 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
)

148
go.sum

@ -1,8 +1,8 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.112.1 h1:uJSeirPke5UNZHIb4SxfZklVSiWWVqW4oXlETwZziwM=
cloud.google.com/go v0.112.1/go.mod h1:+Vbu+Y1UU+I1rjmzeMOb/8RfkKJK2Gyxi1X6jJCZLo4=
cloud.google.com/go/compute/metadata v0.6.0 h1:A6hENjEsCDtC1k8byVsgwvVcioamEHvZ4j01OwKxG9I=
cloud.google.com/go/compute/metadata v0.6.0/go.mod h1:FjyFAW1MW0C203CEOMDTu3Dk1FlqW3Rga40jzHL4hfg=
cloud.google.com/go/compute/metadata v0.9.0 h1:pDUj4QMoPejqq20dK0Pg2N4yG9zIkYGdBtwLoEkH9Zs=
cloud.google.com/go/compute/metadata v0.9.0/go.mod h1:E0bWwX5wTnLPedCKqk3pJmVgCBSM6qQI1yTBdEb3C10=
cloud.google.com/go/firestore v1.15.0 h1:/k8ppuWOtNuDHt2tsRV42yI21uaGnKDEQnRFeBpbFF8=
cloud.google.com/go/firestore v1.15.0/go.mod h1:GWOxFXcv8GZUtYpWHw/w6IuYNux/BtmeVTMmjrm4yhk=
cloud.google.com/go/iam v1.1.7 h1:z4VHOhwKLF/+UYXAJDFwGtNF0b6gjsW1Pk9Ml0U/IoM=
@ -61,6 +61,8 @@ github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLj
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/bmatcuk/doublestar/v4 v4.10.0 h1:zU9WiOla1YA122oLM6i4EXvGW62DvKZVxIe6TYWexEs=
github.com/bmatcuk/doublestar/v4 v4.10.0/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc=
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=
@ -80,6 +82,8 @@ github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJ
github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg=
github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cncf/xds/go v0.0.0-20251210132809-ee656c7534f5 h1:6xNmx7iTtyBRev0+D/Tv1FZd4SCg8axKApyNyRsAt/w=
github.com/cncf/xds/go v0.0.0-20251210132809-ee656c7534f5/go.mod h1:KdCmV+x/BuvyMxRnYBlmVaq4OLiKW6iRQfvC62cvdkI=
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=
@ -103,12 +107,19 @@ github.com/eapache/go-xerial-snappy v0.0.0-20230731223053-c322873962e3 h1:Oy0F4A
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/ebitengine/purego v0.10.0 h1:QIw4xfpWT6GWTzaW5XEKy3HXoqrJGx1ijYHzTF0/ISU=
github.com/ebitengine/purego v0.10.0/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g=
github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
github.com/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/go-control-plane v0.14.0 h1:hbG2kr4RuFj222B6+7T83thSPqLjwBIfQawTkC++2HA=
github.com/envoyproxy/go-control-plane/envoy v1.36.0 h1:yg/JjO5E7ubRyKX3m07GF3reDNEnfOboJ0QySbH736g=
github.com/envoyproxy/go-control-plane/envoy v1.36.0/go.mod h1:ty89S1YCCVruQAm9OtKeEkQLTb+Lkz0k8v9W0Oxsv98=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/envoyproxy/protoc-gen-validate v1.3.0 h1:TvGH1wof4H33rezVKWSpqKz5NXWg5VPuZ0uONDT6eb4=
github.com/envoyproxy/protoc-gen-validate v1.3.0/go.mod h1:HvYl7zwPa5mffgyeTUHA9zHIH36nmrm7oCbo4YKoSWA=
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=
@ -130,12 +141,13 @@ github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm
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-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
github.com/go-logr/logr v1.4.3/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-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=
github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE=
github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs=
github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE=
@ -171,8 +183,8 @@ github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5x
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.4.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
github.com/golang-jwt/jwt/v4 v4.5.1 h1:JdqV9zKUdtaa9gdPlywC3aeoEsR681PlKC+4F5gQgeo=
github.com/golang-jwt/jwt/v4 v4.5.1/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
github.com/golang-jwt/jwt/v4 v4.5.2 h1:YtQM7lnr8iZ+j5q71MGKkNw9Mn7AjHM68uc9g5fXeUI=
github.com/golang-jwt/jwt/v4 v4.5.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
@ -202,8 +214,8 @@ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
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=
@ -303,8 +315,8 @@ github.com/likexian/gokit v0.25.13 h1:p2Uw3+6fGG53CwdU2Dz0T6bOycdb2+bAFAa3ymwWVk
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/lufia/plan9stats v0.0.0-20230110061619-bbe2e5e100de h1:V53FWzU6KAZVi1tPp5UIsMoUWJ2/PNwYIDXnu7QuBCE=
github.com/lufia/plan9stats v0.0.0-20230110061619-bbe2e5e100de/go.mod h1:JKx41uQRwqlTZabZc+kILPrO/3jlKnQ2Z8b7YiVw5cE=
github.com/lufia/plan9stats v0.0.0-20260216142805-b3301c5f2a88 h1:PTw+yKnXcOFCR6+8hHTyWBeQ/P4Nb7dd4/0ohEcWQuM=
github.com/lufia/plan9stats v0.0.0-20260216142805-b3301c5f2a88/go.mod h1:autxFIvghDt3jPTLoqZ9OZ7s9qTGNAWmYCjVFWPX/zg=
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=
@ -347,12 +359,12 @@ github.com/onsi/ginkgo/v2 v2.19.0 h1:9Cnnf7UHo57Hy3k6/m5k3dRfGTMXGvxhHFvkDTCTpvA
github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To=
github.com/onsi/gomega v1.25.0 h1:Vw7br2PCDYijJHSfBOWhov+8cAnUf8MfMaIOV323l6Y=
github.com/onsi/gomega v1.25.0/go.mod h1:r+zV744Re+DiYCIPRlYOTxn0YkOLcAnW8k1xXdMPGhM=
github.com/openimsdk/gomake v0.0.15-alpha.11 h1:PQudYDRESYeYlUYrrLLJhYIlUPO5x7FAx+o5El9U/Bw=
github.com/openimsdk/gomake v0.0.15-alpha.11/go.mod h1:PndCozNc2IsQIciyn9mvEblYWZwJmAI+06z94EY+csI=
github.com/openimsdk/protocol v0.0.73-alpha.18 h1:LXmDFx3KnMd2mN0/S3Q2U33Ft/DHvplSsINO0/bto/c=
github.com/openimsdk/protocol v0.0.73-alpha.18/go.mod h1:WF7EuE55vQvpyUAzDXcqg+B+446xQyEba0X35lTINmw=
github.com/openimsdk/tools v0.0.50-alpha.106 h1:gaqU08IbRxOdL16ZEQNyYLhCTf7K1HNkrik8KZLA+BM=
github.com/openimsdk/tools v0.0.50-alpha.106/go.mod h1:x9i/e+WJFW4tocy6RNJQ9NofQiP3KJ1Y576/06TqOG4=
github.com/openimsdk/gomake v0.0.17 h1:q8haP48VOH45WhJRiLj1YSBJyUFJqD8CTedH65i1YH8=
github.com/openimsdk/gomake v0.0.17/go.mod h1:nnjS8yCtrPJAt1knMbyPiUwCH2gpyBzj/EZAONfUOXg=
github.com/openimsdk/protocol v0.0.73-alpha.19 h1:CvXoDF2U73UcMhLnrtMFks2Aw+bXiDgH8AITEt783/s=
github.com/openimsdk/protocol v0.0.73-alpha.19/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/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=
@ -360,11 +372,13 @@ github.com/pierrec/lz4/v4 v4.1.21/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFu
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 h1:GFCKgmp0tecUJ0sJuv4pzYCqS9+RGSn52M3FUwPs+uo=
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8=
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/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b h1:0LFwY6Q3gMACTjAbMZBjXAqTOzOwFaj2Ld6cjeQ7Rig=
github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU=
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
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=
@ -388,8 +402,8 @@ 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.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
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=
@ -403,6 +417,8 @@ github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKl
github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
github.com/shirou/gopsutil/v3 v3.24.5 h1:i0t8kL+kQTvpAYToeuiVk3TgDeKOFioZO3Ztz/iZ9pI=
github.com/shirou/gopsutil/v3 v3.24.5/go.mod h1:bsoOS1aStSs9ErQ1WWfxllSeS1K5D+U30r2NfcubMVk=
github.com/shirou/gopsutil/v4 v4.26.2 h1:X8i6sicvUFih4BmYIGT1m2wwgw2VG9YgrDTi7cIRGUI=
github.com/shirou/gopsutil/v4 v4.26.2/go.mod h1:LZ6ewCSkBqUpvSOf+LsTGnRinC6iaNUNMGBtDkJBaLQ=
github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM=
github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ=
github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU=
@ -433,18 +449,18 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
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.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/tklauser/go-sysconf v0.3.16 h1:frioLaCQSsF5Cy1jgRBrzr6t502KIIwQ0MArYICU0nA=
github.com/tklauser/go-sysconf v0.3.16/go.mod h1:/qNL9xxDhc7tx3HSRsLWNnuzbVfh3e7gh/BmM179nYI=
github.com/tklauser/numcpus v0.11.0 h1:nSTwhKH5e1dMNsCdVBukSZrURJRoHbSEQjdEbY+9RXw=
github.com/tklauser/numcpus v0.11.0/go.mod h1:z+LwcLq54uWZTX0u/bGobaV34u6V7KNlTZejzM6/3MQ=
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.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE=
@ -474,22 +490,22 @@ go.mongodb.org/mongo-driver v1.14.0 h1:P98w8egYRjYe3XDjxhYJagTokP/H6HzlsnojRgZRd
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/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 h1:4Pp6oUg3+e/6M4C0A/3kJ2VYa++dsWVTtGgLVj5xtHg=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0/go.mod h1:Mjt1i1INqiaoZOMGR1RIUJN+i3ChKoFRqzrRQhlkbs0=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 h1:jq9TW8u3so/bN+JPT166wjOI6/vQPF6Xe7nMNIltagk=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw=
go.opentelemetry.io/otel v1.34.0 h1:zRLXxLCgL1WyKsPVrgbSdMN4c0FMkDAskSTQP+0hdUY=
go.opentelemetry.io/otel v1.34.0/go.mod h1:OWFPOQ+h4G8xpyjgqo4SxJYdDQ/qmRH+wivy7zzx9oI=
go.opentelemetry.io/otel/metric v1.34.0 h1:+eTR3U0MyfWjRDhmFMxe2SsW64QrZ84AOhvqS7Y+PoQ=
go.opentelemetry.io/otel/metric v1.34.0/go.mod h1:CEDrp0fy2D0MvkXE+dPV7cMi8tWZwX3dmaIhwPOaqHE=
go.opentelemetry.io/otel/sdk v1.34.0 h1:95zS4k/2GOy069d321O8jWgYsW3MzVV+KuSPKp7Wr1A=
go.opentelemetry.io/otel/sdk v1.34.0/go.mod h1:0e/pNiaMAqaykJGKbi+tSjWfNNHMTxoC9qANsCzbyxU=
go.opentelemetry.io/otel/sdk/metric v1.34.0 h1:5CeK9ujjbFVL5c1PhLuStg1wxA7vQv7ce1EK0Gyvahk=
go.opentelemetry.io/otel/sdk/metric v1.34.0/go.mod h1:jQ/r8Ze28zRKoNRdkjCZxfs6YvBTG1+YIqyFVFYec5w=
go.opentelemetry.io/otel/trace v1.34.0 h1:+ouXS2V8Rd4hp4580a8q23bg0azF2nI8cqLYnC8mh/k=
go.opentelemetry.io/otel/trace v1.34.0/go.mod h1:Svm7lSjQD7kG7KJ/MUHPVXSDGz2OX4h0M2jHBhmSfRE=
go.opentelemetry.io/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48=
go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8=
go.opentelemetry.io/otel/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0=
go.opentelemetry.io/otel/metric v1.39.0/go.mod h1:jrZSWL33sD7bBxg1xjrqyDjnuzTUB0x1nBERXd7Ftcs=
go.opentelemetry.io/otel/sdk v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18=
go.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE=
go.opentelemetry.io/otel/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2WKg+sEJTtB8=
go.opentelemetry.io/otel/sdk/metric v1.39.0/go.mod h1:xq9HEVH7qeX69/JnwEfp6fVq5wosJsY1mt4lLfYdVew=
go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI=
go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA=
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=
@ -510,13 +526,13 @@ golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5y
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc=
golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc=
golang.org/x/crypto v0.52.0 h1:RMs7fP2rXdep0CftQlK8Uf+kibLm7qkCcradZWYz988=
golang.org/x/crypto v0.52.0/go.mod h1:1QgfPxDqh0T2M/elOJtp9RvuR95kVjir0e6/BvEmGbc=
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/image v0.39.0 h1:skVYidAEVKgn8lZ602XO75asgXBgLj9G/FE3RbuPFww=
golang.org/x/image v0.39.0/go.mod h1:sIbmppfU+xFLPIG0FoVUTvyBMmgng1/XAMhQ2ft0hpA=
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=
@ -539,19 +555,19 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
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.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0=
golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k=
golang.org/x/net v0.55.0 h1:bcvxaJn3e1U6InsFWt1JUq1aSjnRxLzT2rtD2KfkDF8=
golang.org/x/net v0.55.0/go.mod h1:L5U2KuzuOe1lY7Z+aWVIKK6qEeJXnXV9yzGA+WCHJww=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.25.0 h1:CY4y7XT9v0cRI9oupztF8AgiIu99L/ksR/Xp/6jrZ70=
golang.org/x/oauth2 v0.25.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
golang.org/x/oauth2 v0.34.0 h1:hqK/t4AKgbqWkdkcAeI8XLmbK+4m4G5YeQRrmiotGlw=
golang.org/x/oauth2 v0.34.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA=
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-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.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4=
golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/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=
@ -567,14 +583,14 @@ golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.1.0/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.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.45.0 h1:dO4czNzziLiiXplLQgBCEpCvXQ3dnkn0SdaZSYdQ+FY=
golang.org/x/sys v0.45.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
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.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.28.0 h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg=
golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek=
golang.org/x/term v0.43.0 h1:S4RLU2sB31O/NCl+zFN9Aru9A/Cq2aqKpTZJ6B+DwT4=
golang.org/x/term v0.43.0/go.mod h1:lrhlHNdQJHO+1qVYiHfFKVuVioJIheAc3fBSMFYEIsk=
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=
@ -583,8 +599,8 @@ 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.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
golang.org/x/text v0.37.0 h1:Cqjiwd9eSg8e0QAkyCaQTNHFIIzWtidPahFWR83rTrc=
golang.org/x/text v0.37.0/go.mod h1:a5sjxXGs9hsn/AJVwuElvCAo9v8QYLzvavO5z2PiM38=
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
@ -596,14 +612,16 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg=
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
golang.org/x/tools v0.44.0 h1:UP4ajHPIcuMjT1GqzDWRlalUEoY+uzoZKnhOjbIPD2c=
golang.org/x/tools v0.44.0/go.mod h1:KA0AfVErSdxRZIsOVipbv3rQhVXTnlU6UhKxHd1seDI=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 h1:+cNy6SZtPcJQH3LJVLOSmiC7MMxXNOb3PU/VUEz+EhU=
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90=
gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
google.golang.org/api v0.170.0 h1:zMaruDePM88zxZBG+NG8+reALO2rfLhe/JShitLyT48=
google.golang.org/api v0.170.0/go.mod h1:/xql9M2btF85xac/VAm4PsLMTLVGUOpq4BE9R8jyNy8=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
@ -615,17 +633,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-20240213162025-012b6fc9bca9 h1:9+tzLLstTlPTRyJTh+ah5wIMsBW5c4tQwGTN3thOW9Y=
google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9/go.mod h1:mqHbVIp48Muh7Ywss/AD6I5kNVKZMmAa/QEW58Gxp2s=
google.golang.org/genproto/googleapis/api v0.0.0-20250106144421-5f5ef82da422 h1:GVIKPyP/kLIyVOgOnTwFOrvQaQUzOzGMCxgFUOEmm24=
google.golang.org/genproto/googleapis/api v0.0.0-20250106144421-5f5ef82da422/go.mod h1:b6h1vNKhxaSoEI+5jc3PJUCustfli/mRab7295pY7rw=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f h1:OxYkA3wjPsZyBylwymxSHa7ViiW1Sml4ToBrncvFehI=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f/go.mod h1:+2Yz8+CLJbIfL9z73EW45avw8Lmge3xVElCP9zEKi50=
google.golang.org/genproto/googleapis/api v0.0.0-20251202230838-ff82c1b0f217 h1:fCvbg86sFXwdrl5LgVcTEvNC+2txB5mgROGmRL5mrls=
google.golang.org/genproto/googleapis/api v0.0.0-20251202230838-ff82c1b0f217/go.mod h1:+rXWjjaukWZun3mLfjmVnQi18E1AsFbDN9QdJ5YXLto=
google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217 h1:gRkg/vSppuSQoDjxyiGfN4Upv/h/DQmIR10ZU8dh4Ww=
google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk=
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.71.0 h1:kF77BGdPTQ4/JZWMlb9VpJ5pa25aqvVqogsxNHHdeBg=
google.golang.org/grpc v1.71.0/go.mod h1:H0GRtasmQOh9LkFoCPDu3ZrwUtD1YGE+b2vYBYd/8Ec=
google.golang.org/grpc v1.79.3 h1:sybAEdRIEtvcD68Gx7dmnwjZKlyfuc61Dyo9pGXXkKE=
google.golang.org/grpc v1.79.3/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
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=
@ -635,8 +653,8 @@ google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.36.4 h1:6A3ZDJHn/eNqc1i+IdefRzy/9PokBTPvcqMySR7NNIM=
google.golang.org/protobuf v1.36.4/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE=
google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
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=

@ -208,7 +208,11 @@ func (c *websocketClientConn) pingHandler(appData string) error {
return nil
}
func (c *websocketClientConn) pongHandler(string) error {
func (c *websocketClientConn) pongHandler(appData string) error {
log.ZDebug(context.Background(), "pong handler recv pong", "remoteAddr", c.conn.RemoteAddr(), "appData", appData)
if err := c.setReadDeadline(); err != nil {
return err
}
return nil
}

@ -23,9 +23,11 @@ import (
"strings"
"time"
"github.com/openimsdk/tools/utils/stringutil"
"google.golang.org/grpc"
"github.com/openimsdk/open-im-server/v3/pkg/dbbuild"
"github.com/openimsdk/open-im-server/v3/pkg/rpcli"
"google.golang.org/grpc"
"github.com/openimsdk/open-im-server/v3/pkg/authverify"
"github.com/openimsdk/open-im-server/v3/pkg/callbackstruct"
@ -143,8 +145,8 @@ func (g *groupServer) NotificationUserInfoUpdate(ctx context.Context, req *pbgro
return nil, err
}
}
for _, groupID := range groupIDs {
g.notification.GroupMemberInfoSetNotification(ctx, groupID, req.UserID)
if err = g.notification.GroupMemberInfoSetNotificationBulk(ctx, groupIDs, req.NewUserInfo); err != nil {
log.ZError(ctx, stringutil.GetFuncName(1)+" failed", err)
}
if err = g.db.DeleteGroupMemberHash(ctx, groupIDs); err != nil {
return nil, err

@ -802,6 +802,182 @@ func (g *NotificationSender) GroupCancelMutedNotification(ctx context.Context, g
g.Notification(ctx, mcontext.GetOpUserID(ctx), group.GroupID, constant.GroupCancelMutedNotification, tips)
}
func (g *NotificationSender) getPublicUserInfos(ctx context.Context, userIDs []string) ([]*sdkws.PublicUserInfo, error) {
users, err := g.getUsersInfo(ctx, userIDs)
if err != nil {
return nil, err
}
userMap := make(map[string]common_user.CommonUser)
for _, user := range users {
userMap[user.GetUserID()] = user
}
for _, userID := range userIDs {
if _, ok := userMap[userID]; !ok {
return nil, servererrs.ErrUserIDNotFound.WrapMsg(fmt.Sprintf("user %s not found", userID))
}
}
return datautil.Slice(users, func(e common_user.CommonUser) *sdkws.PublicUserInfo {
return &sdkws.PublicUserInfo{
UserID: e.GetUserID(),
Nickname: e.GetNickname(),
FaceURL: e.GetFaceURL(),
Ex: e.GetEx(),
}
}), nil
}
func (g *NotificationSender) getGroupMembersForUser(ctx context.Context, groupIDs []string, userID string) ([]*sdkws.GroupMemberFullInfo, error) {
members, err := g.db.FindGroupMemberUser(ctx, groupIDs, userID)
if err != nil {
return nil, err
}
if err := g.PopulateGroupMember(ctx, members...); err != nil {
return nil, err
}
log.ZDebug(ctx, "getGroupMembers", "members", members)
return datautil.Slice(members, func(e *model.GroupMember) *sdkws.GroupMemberFullInfo { return g.groupMemberDB2PB(e, 0) }), nil
}
func (g *NotificationSender) getGroupMemberMapForUser(ctx context.Context, groupIDs []string, userID string) (map[string]*sdkws.GroupMemberFullInfo, error) {
members, err := g.getGroupMembersForUser(ctx, groupIDs, userID)
if err != nil {
return nil, err
}
m := make(map[string]*sdkws.GroupMemberFullInfo)
for i, member := range members {
m[member.GroupID] = members[i]
}
return m, nil
}
func (g *NotificationSender) migrateFallbackToGroupMemberFullInfo(groupMemberFullInfo *sdkws.GroupMemberFullInfo, publicUserInfo *sdkws.PublicUserInfo) *sdkws.GroupMemberFullInfo {
if groupMemberFullInfo == nil {
groupMemberFullInfo = &sdkws.GroupMemberFullInfo{}
}
if publicUserInfo == nil {
publicUserInfo = &sdkws.PublicUserInfo{}
}
firstNotEmpty := func(s ...string) string {
for _, s := range s {
if s != "" {
return s
}
}
return ""
}
return &sdkws.GroupMemberFullInfo{
GroupID: groupMemberFullInfo.GroupID,
UserID: firstNotEmpty(groupMemberFullInfo.UserID, publicUserInfo.UserID),
RoleLevel: groupMemberFullInfo.RoleLevel,
JoinTime: groupMemberFullInfo.JoinTime,
Nickname: firstNotEmpty(groupMemberFullInfo.Nickname, publicUserInfo.Nickname),
FaceURL: firstNotEmpty(groupMemberFullInfo.FaceURL, publicUserInfo.FaceURL),
AppMangerLevel: groupMemberFullInfo.AppMangerLevel,
JoinSource: groupMemberFullInfo.JoinSource,
OperatorUserID: firstNotEmpty(groupMemberFullInfo.OperatorUserID, publicUserInfo.UserID),
InviterUserID: groupMemberFullInfo.InviterUserID,
Ex: groupMemberFullInfo.Ex,
MuteEndTime: groupMemberFullInfo.MuteEndTime,
}
}
func (g *NotificationSender) getGroupInfos(ctx context.Context, groupIDs []string) ([]*sdkws.GroupInfo, error) {
var err error
defer func() {
if err != nil {
log.ZError(ctx, stringutil.GetFuncName(1)+" failed", err)
}
}()
groups, err := g.db.FindGroup(ctx, groupIDs)
if err != nil {
return nil, err
}
numMap, err := g.db.FindGroupMemberNums(ctx, groupIDs)
if err != nil {
return nil, err
}
owners, err := g.db.FindGroupsOwner(ctx, groupIDs)
if err != nil {
return nil, err
}
ownerMap := make(map[string]string)
for _, owner := range owners {
ownerMap[owner.GroupID] = owner.UserID
}
return datautil.Slice(groups, func(group *model.Group) *sdkws.GroupInfo {
return convert.Db2PbGroupInfo(group, ownerMap[group.GroupID], numMap[group.GroupID])
}), nil
}
func (g *NotificationSender) GroupMemberInfoSetNotificationBulk(ctx context.Context, groupIDs []string, changedUserInfo *sdkws.UserInfo) error {
opUserID := mcontext.GetOpUserID(ctx)
opIsAdmin := authverify.CheckUserIsAdmin(ctx, opUserID)
groupInfos, err := g.getGroupInfos(ctx, groupIDs)
if err != nil {
return err
}
groupMemberMap, err := g.getGroupMemberMapForUser(ctx, groupIDs, changedUserInfo.UserID)
if err != nil {
return err
}
opMemberMap := groupMemberMap
if opUserID != changedUserInfo.UserID {
opMemberMap, err = g.getGroupMemberMapForUser(ctx, groupIDs, opUserID)
if err != nil {
return err
}
}
opPublicUser := &sdkws.PublicUserInfo{
UserID: changedUserInfo.GetUserID(),
Nickname: changedUserInfo.GetNickname(),
FaceURL: changedUserInfo.GetFaceURL(),
Ex: changedUserInfo.GetEx(),
}
if opUserID != changedUserInfo.UserID {
opPublicUser, err = g.getUser(ctx, opUserID)
if err != nil {
return err
}
}
for _, groupInfo := range groupInfos {
if groupMemberMap[groupInfo.GroupID] == nil {
continue
}
opUserGroupMemberFullInfo := datautil.If(opIsAdmin, &sdkws.GroupMemberFullInfo{
GroupID: groupInfo.GroupID,
UserID: opUserID,
RoleLevel: constant.GroupAdmin,
AppMangerLevel: constant.AppAdmin,
}, opMemberMap[groupInfo.GroupID])
if opUserGroupMemberFullInfo == nil {
opUserGroupMemberFullInfo = &sdkws.GroupMemberFullInfo{}
}
opUserGroupMemberFullInfo.GroupID = groupInfo.GroupID
tips := &sdkws.GroupMemberInfoSetTips{
Group: groupInfo,
OpUser: g.migrateFallbackToGroupMemberFullInfo(opUserGroupMemberFullInfo, opPublicUser),
ChangedUser: groupMemberMap[groupInfo.GroupID],
}
g.setSortVersion(ctx, &tips.GroupMemberVersion, &tips.GroupMemberVersionID, database.GroupMemberVersionName, tips.Group.GroupID, &tips.GroupSortVersion)
g.Notification(ctx, opUserID, groupInfo.GroupID, constant.GroupMemberInfoSetNotification, tips)
}
return nil
}
func (g *NotificationSender) GroupMemberInfoSetNotification(ctx context.Context, groupID, groupMemberUserID string) {
var err error
defer func() {
@ -809,13 +985,11 @@ func (g *NotificationSender) GroupMemberInfoSetNotification(ctx context.Context,
log.ZError(ctx, stringutil.GetFuncName(1)+" failed", err)
}
}()
var group *sdkws.GroupInfo
group, err = g.getGroupInfo(ctx, groupID)
group, err := g.getGroupInfo(ctx, groupID)
if err != nil {
return
}
var user map[string]*sdkws.GroupMemberFullInfo
user, err = g.getGroupMemberMap(ctx, groupID, []string{groupMemberUserID})
user, err := g.getGroupMemberMap(ctx, groupID, []string{groupMemberUserID})
if err != nil {
return
}
@ -834,8 +1008,7 @@ func (g *NotificationSender) GroupMemberSetToAdminNotification(ctx context.Conte
log.ZError(ctx, stringutil.GetFuncName(1)+" failed", err)
}
}()
var group *sdkws.GroupInfo
group, err = g.getGroupInfo(ctx, groupID)
group, err := g.getGroupInfo(ctx, groupID)
if err != nil {
return
}
@ -858,13 +1031,11 @@ func (g *NotificationSender) GroupMemberSetToOrdinaryUserNotification(ctx contex
log.ZError(ctx, stringutil.GetFuncName(1)+" failed", err)
}
}()
var group *sdkws.GroupInfo
group, err = g.getGroupInfo(ctx, groupID)
group, err := g.getGroupInfo(ctx, groupID)
if err != nil {
return
}
var user map[string]*sdkws.GroupMemberFullInfo
user, err = g.getGroupMemberMap(ctx, groupID, []string{mcontext.GetOpUserID(ctx), groupMemberUserID})
user, err := g.getGroupMemberMap(ctx, groupID, []string{mcontext.GetOpUserID(ctx), groupMemberUserID})
if err != nil {
return
}

@ -5,9 +5,12 @@ package main
import (
"flag"
"fmt"
"os"
"github.com/openimsdk/gomake/mageutil"
"github.com/openimsdk/open-im-server/v3/version"
"github.com/openimsdk/tools/utils/datautil"
)
var Default = Build
@ -25,7 +28,6 @@ var (
customToolsDir = "tools" // tools source code directory, default is "tools"
)
// Build support specifical binary build.
//
// Example: `mage build openim-api openim-rpc-user seq`
@ -35,8 +37,7 @@ func Build() {
if len(bin) != 0 {
bin = bin[1:]
}
mageutil.Build(bin, nil)
mageutil.WithSpinner("Building binaries...", func() { mageutil.Build(bin, nil, nil) })
}
func BuildWithCustomConfig() {
@ -53,7 +54,9 @@ func BuildWithCustomConfig() {
ToolsDir: &customToolsDir,
}
mageutil.Build(bin, config)
mageutil.WithSpinner("Building binaries with custom config...", func() {
mageutil.Build(bin, config, nil)
})
}
func Start() {
@ -70,7 +73,9 @@ func Start() {
bin = bin[1:]
}
mageutil.StartToolsAndServices(bin, nil)
mageutil.WithSpinner("Starting...", func() {
mageutil.StartToolsAndServices(bin, nil)
})
}
func StartWithCustomConfig() {
@ -93,13 +98,42 @@ func StartWithCustomConfig() {
ConfigDir: &customConfigDir,
}
mageutil.StartToolsAndServices(bin, config)
mageutil.WithSpinner("Starting with custom config...", func() {
mageutil.StartToolsAndServices(bin, config)
})
}
func Stop() {
mageutil.StopAndCheckBinaries()
mageutil.WithSpinner("Stopping...", mageutil.StopAndCheckBinaries)
}
func Check() {
mageutil.CheckAndReportBinariesStatus()
mageutil.WithSpinner("Checking binaries...", mageutil.CheckAndReportBinariesStatus)
}
func Export() {
mappingPaths, err := mageutil.GetDefaultExportMappingPaths([]string{
"cmd",
"internal",
"pkg",
"test",
"tools",
"**/*.go",
"go.mod",
"go.work",
})
if err != nil {
mageutil.PrintRed("GetDefaultExportMappingPaths failed " + err.Error())
os.Exit(1)
}
mageutil.WithSpinner("Exporting...", func() {
mageutil.ExportMageLauncherArchived(mappingPaths, &mageutil.ExportOptions{
ProjectName: datautil.ToPtr(fmt.Sprintf("open-im-server_%s", version.Version)),
BuildOpt: &mageutil.BuildOptions{
Release: datautil.ToPtr(true),
Compress: datautil.ToPtr(true),
},
})
})
}

@ -100,11 +100,11 @@ type RespTarget struct {
}
func BuildDiscoveryKeyPrefix(name string) string {
return fmt.Sprintf("%s/%s/%s", "openim", "prometheus_discovery", name)
return fmt.Sprintf("%s/%s", "prometheus_discovery", name)
}
func BuildDiscoveryKey(name string, index int) string {
return fmt.Sprintf("%s/%s/%s/%d", "openim", "prometheus_discovery", name, index)
return fmt.Sprintf("%s/%s/%d", "prometheus_discovery", name, index)
}
func BuildDefaultTarget(host string, ip int) Target {

@ -57,6 +57,7 @@ type GroupCache interface {
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)
GetGroupMemberNums(ctx context.Context, groupIDs []string) (memberNumMap map[string]int64, err error)
DelGroupsMemberNum(groupID ...string) GroupCache
//FindSortGroupMemberUserIDs(ctx context.Context, groupID string) ([]string, error)

@ -32,7 +32,7 @@ func (x *seqConversationCache) GetMinSeq(ctx context.Context, conversationID str
func (x *seqConversationCache) GetMaxSeqs(ctx context.Context, conversationIDs []string) (map[string]int64, error) {
res := make(map[string]int64)
for _, conversationID := range conversationIDs {
seq, err := x.GetMinSeq(ctx, conversationID)
seq, err := x.GetMaxSeq(ctx, conversationID)
if err != nil {
return nil, err
}
@ -44,7 +44,7 @@ func (x *seqConversationCache) GetMaxSeqs(ctx context.Context, conversationIDs [
func (x *seqConversationCache) GetMaxSeqsWithTime(ctx context.Context, conversationIDs []string) (map[string]database.SeqTime, error) {
res := make(map[string]database.SeqTime)
for _, conversationID := range conversationIDs {
seq, err := x.GetMinSeq(ctx, conversationID)
seq, err := x.GetMaxSeq(ctx, conversationID)
if err != nil {
return nil, err
}

@ -2,9 +2,13 @@ package redis
import (
"context"
"encoding/json"
"fmt"
"time"
"github.com/openimsdk/tools/utils/datautil"
"github.com/redis/go-redis/v9"
"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"
@ -14,7 +18,6 @@ import (
"github.com/openimsdk/protocol/constant"
"github.com/openimsdk/tools/errs"
"github.com/openimsdk/tools/log"
"github.com/redis/go-redis/v9"
)
const (
@ -258,6 +261,57 @@ func (g *GroupCacheRedis) GetGroupMemberNum(ctx context.Context, groupID string)
})
}
type groupMemberNumCache struct {
GroupID string `json:"group_id"`
MemberNum int64 `json:"member_num"`
}
type groupMemberNumBatchCache struct {
GroupID string
MemberNum int64
}
func (r *groupMemberNumBatchCache) BatchCache(groupID string) {
r.GroupID = groupID
}
func (r *groupMemberNumBatchCache) UnmarshalJSON(bytes []byte) error {
return json.Unmarshal(bytes, &r.MemberNum)
}
func (r *groupMemberNumBatchCache) MarshalJSON() ([]byte, error) {
return json.Marshal(r.MemberNum)
}
func (g *GroupCacheRedis) GetGroupMemberNums(ctx context.Context, groupIDs []string) (map[string]int64, error) {
items, err := batchGetCache2(
ctx,
g.rcClient,
g.expireTime,
groupIDs,
func(groupID string) string { return g.getGroupMemberNumKey(groupID) },
func(v *groupMemberNumBatchCache) string { return v.GroupID },
func(ctx context.Context, ids []string) ([]*groupMemberNumBatchCache, error) {
res := make([]*groupMemberNumBatchCache, 0, len(ids))
for _, groupID := range ids {
num, err := g.groupMemberDB.TakeGroupMemberNum(ctx, groupID)
if err != nil {
return nil, err
}
res = append(res, &groupMemberNumBatchCache{
GroupID: groupID,
MemberNum: num,
})
}
return res, nil
},
)
if err != nil {
return nil, err
}
return datautil.SliceToMapAny(items, func(item *groupMemberNumBatchCache) (string, int64) {
return item.GroupID, item.MemberNum
}), nil
}
func (g *GroupCacheRedis) DelGroupsMemberNum(groupID ...string) cache.GroupCache {
keys := make([]string, 0, len(groupID))
for _, groupID := range groupID {
@ -280,18 +334,111 @@ func (g *GroupCacheRedis) GetGroupOwner(ctx context.Context, groupID string) (*m
return members[0], nil
}
type groupRoleLevelMemberIDsBatchCache struct {
GroupID string
UserIDs []string
}
func (r *groupRoleLevelMemberIDsBatchCache) BatchCache(groupID string) {
r.GroupID = groupID
}
func (r *groupRoleLevelMemberIDsBatchCache) UnmarshalJSON(bytes []byte) (err error) {
return json.Unmarshal(bytes, &r.UserIDs)
}
func (r *groupRoleLevelMemberIDsBatchCache) MarshalJSON() ([]byte, error) {
return json.Marshal(r.UserIDs)
}
func (g *GroupCacheRedis) batchGetGroupRoleLevelMemberIDs(ctx context.Context, groupIDs []string, roleLevel int32) (map[string][]string, error) {
items, err := batchGetCache2(
ctx,
g.rcClient,
g.expireTime,
groupIDs,
func(groupID string) string {
return g.getGroupRoleLevelMemberIDsKey(groupID, roleLevel)
},
func(v *groupRoleLevelMemberIDsBatchCache) string {
return v.GroupID
},
func(ctx context.Context, ids []string) ([]*groupRoleLevelMemberIDsBatchCache, error) {
res := make([]*groupRoleLevelMemberIDsBatchCache, 0, len(ids))
for _, groupID := range ids {
userIDs, err := g.groupMemberDB.FindRoleLevelUserIDs(ctx, groupID, roleLevel)
if err != nil {
return nil, err
}
res = append(res, &groupRoleLevelMemberIDsBatchCache{
GroupID: groupID,
UserIDs: userIDs,
})
}
return res, nil
},
)
if err != nil {
return nil, err
}
return datautil.SliceToMapAny(items, func(item *groupRoleLevelMemberIDsBatchCache) (string, []string) {
return item.GroupID, item.UserIDs
}), nil
}
type groupUserIDPair struct {
GroupID string
UserID string
}
func (g *GroupCacheRedis) batchGetGroupMembersByPairs(ctx context.Context, ids []groupUserIDPair) ([]*model.GroupMember, error) {
return batchGetCache2(ctx, g.rcClient, g.expireTime, ids, func(id groupUserIDPair) string {
return g.getGroupMemberInfoKey(id.GroupID, id.UserID)
}, func(member *model.GroupMember) groupUserIDPair {
return groupUserIDPair{GroupID: member.GroupID, UserID: member.UserID}
}, func(ctx context.Context, ids []groupUserIDPair) ([]*model.GroupMember, error) {
groupIDsByUser := make(map[string][]string)
for _, id := range ids {
groupIDsByUser[id.UserID] = append(groupIDsByUser[id.UserID], id.GroupID)
}
members := make([]*model.GroupMember, 0, len(ids))
for userID, groupIDs := range groupIDsByUser {
items, err := g.groupMemberDB.FindInGroup(ctx, userID, groupIDs)
if err != nil {
return nil, err
}
members = append(members, items...)
}
return members, nil
})
}
func (g *GroupCacheRedis) GetGroupsOwner(ctx context.Context, groupIDs []string) ([]*model.GroupMember, error) {
members := make([]*model.GroupMember, 0, len(groupIDs))
ownerIDs, err := g.batchGetGroupRoleLevelMemberIDs(ctx, groupIDs, constant.GroupOwner)
if err != nil {
return nil, err
}
pairs := make([]groupUserIDPair, 0, len(groupIDs))
for _, groupID := range groupIDs {
items, err := g.GetGroupRoleLevelMemberInfo(ctx, groupID, constant.GroupOwner)
if err != nil {
return nil, err
ids := ownerIDs[groupID]
if len(ids) == 0 {
continue
}
if len(items) > 0 {
members = append(members, items[0])
pairs = append(pairs, groupUserIDPair{GroupID: groupID, UserID: ids[0]})
}
members, err := g.batchGetGroupMembersByPairs(ctx, pairs)
if err != nil {
return nil, err
}
memberMap := datautil.SliceToMapAny(members, func(member *model.GroupMember) (groupUserIDPair, *model.GroupMember) {
return groupUserIDPair{GroupID: member.GroupID, UserID: member.UserID}, member
})
result := make([]*model.GroupMember, 0, len(pairs))
for _, pair := range pairs {
if member, ok := memberMap[pair]; ok {
result = append(result, member)
}
}
return members, nil
return result, nil
}
func (g *GroupCacheRedis) GetGroupRoleLevelMemberIDs(ctx context.Context, groupID string, roleLevel int32) ([]string, error) {

@ -65,6 +65,8 @@ type GroupDatabase interface {
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)
// FindGroupMemberNums retrieves the number of members for multiple groups.
FindGroupMemberNums(ctx context.Context, groupIDs []string) (map[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.
@ -232,6 +234,18 @@ func (g *groupDatabase) FindGroupMemberNum(ctx context.Context, groupID string)
return uint32(num), nil
}
func (g *groupDatabase) FindGroupMemberNums(ctx context.Context, groupIDs []string) (map[string]uint32, error) {
nums, err := g.cache.GetGroupMemberNums(ctx, groupIDs)
if err != nil {
return nil, err
}
result := make(map[string]uint32, len(nums))
for groupID, num := range nums {
result[groupID] = uint32(num)
}
return result, nil
}
func (g *groupDatabase) TakeGroup(ctx context.Context, groupID string) (*model.Group, error) {
return g.cache.GetGroupInfo(ctx, groupID)
}

@ -51,7 +51,7 @@ func NewConversationMongo(db *mongo.Database) (*ConversationMgo, error) {
Keys: bson.D{
{Key: "conversation_id", Value: 1},
},
Options: options.Index().SetUnique(true),
Options: options.Index(),
},
})
if err != nil {

Loading…
Cancel
Save