mirror of
https://github.com/openimsdk/open-im-server.git
synced 2025-04-06 04:15:46 +08:00
Compare commits
133 Commits
main
...
v3.8.4-alp
Author | SHA1 | Date | |
---|---|---|---|
|
1f5f98ef6f | ||
|
7286a7f66d | ||
|
cfded3fb24 | ||
|
1bf3087dc0 | ||
|
2c04970e49 | ||
|
ca671a0e8e | ||
|
22d19fd6b7 | ||
|
811615aaa4 | ||
|
5ad72fa24c | ||
|
67e3bb2b0c | ||
|
53316b8ad8 | ||
|
48291faefb | ||
|
63df09cc5d | ||
|
8edb3ff000 | ||
|
9b672f793e | ||
|
202afc8b88 | ||
|
456ef4742b | ||
|
476252fc36 | ||
|
0c2bd363f9 | ||
|
f4999cc1fc | ||
|
dbe1575e73 | ||
|
a140e7c91b | ||
|
836a947442 | ||
|
f28a1264ab | ||
|
08e231b6de | ||
|
1755cb3c9c | ||
|
5a97e8b096 | ||
|
febbbade67 | ||
|
a4b3cdaac1 | ||
|
1bf70aa2d8 | ||
|
5464636695 | ||
|
623628ded6 | ||
|
0247fcda5a | ||
|
3e12bf3d49 | ||
|
5c192d05ee | ||
|
5312089069 | ||
|
602b4983ac | ||
|
cb4ac19968 | ||
|
3fec3b4321 | ||
|
0f8d4d0943 | ||
|
e20e52b779 | ||
|
28f00a8ffb | ||
|
376c1b87ee | ||
|
c0a0b4da62 | ||
|
89503aa529 | ||
|
1e68f99d11 | ||
|
7912ac0623 | ||
|
ade108d656 | ||
|
222a2f0029 | ||
|
8c6d734f88 | ||
|
1339121e29 | ||
|
382e5947ac | ||
|
12800c1421 | ||
|
d0cd40aae6 | ||
|
36c18ce7ea | ||
|
4b20286a96 | ||
|
3b3ce0d8f5 | ||
|
34c6fe5838 | ||
|
7415dff32c | ||
|
66edc76c54 | ||
|
0b78948f62 | ||
|
a395c82e0d | ||
|
3d064d66f2 | ||
|
5f333426a3 | ||
|
9a122d2eb3 | ||
|
b805113870 | ||
|
2676295a4c | ||
|
d3b2587743 | ||
|
f9e6d07581 | ||
|
52052a9165 | ||
|
3e872d6c5a | ||
|
9ac35c9059 | ||
|
de42eb1f11 | ||
|
b26b0a422c | ||
|
248cb5c107 | ||
|
035baff1b5 | ||
|
de94014b1b | ||
|
aa35155ccb | ||
|
1542a0c98d | ||
|
716e06f3ad | ||
|
3fe2053d4f | ||
|
5430bc4569 | ||
|
01c0d9ca89 | ||
|
3c6fbabded | ||
|
7f471c44bf | ||
|
f3a78260a8 | ||
|
be4061da85 | ||
|
c62945ed05 | ||
|
7d2fd64429 | ||
|
1f91c756a4 | ||
|
573b400af6 | ||
|
22820fa189 | ||
|
645a5925bd | ||
|
c328d39cae | ||
|
7d517970ec | ||
|
d8afbb82fc | ||
|
3e220a3519 | ||
|
3a30479b73 | ||
|
687b2ebc07 | ||
|
23966f3155 | ||
|
674b288654 | ||
|
a4287309ae | ||
|
ce140beddc | ||
|
0e07ad70c3 | ||
|
c9e2f7d375 | ||
|
1e749b6217 | ||
|
4698446050 | ||
|
624ae99a12 | ||
|
453c426ab5 | ||
|
0266dc830d | ||
|
9490d8f8ee | ||
|
0d84190ed6 | ||
|
5089568004 | ||
|
9e4cad1815 | ||
|
d4d626606b | ||
|
058eeaefd0 | ||
|
0ac6668a50 | ||
|
404a9048e2 | ||
|
7881c8c89a | ||
|
eb598ec0e6 | ||
|
625fa77e89 | ||
|
f707069089 | ||
|
2bbd1bcfe9 | ||
|
e53ae33e39 | ||
|
3914dc1435 | ||
|
047fa33704 | ||
|
caf5d5c2f3 | ||
|
7fa2d08636 | ||
|
7b5c18b549 | ||
|
0a565070b8 | ||
|
43bc87ce99 | ||
|
c4fe659c69 | ||
|
59c4c7575d |
18
.env
18
.env
@ -1,19 +1,25 @@
|
|||||||
MONGO_IMAGE=mongo:6.0.2
|
MONGO_IMAGE=mongo:7.0
|
||||||
REDIS_IMAGE=redis:7.0.0
|
REDIS_IMAGE=redis:7.0.0
|
||||||
ZOOKEEPER_IMAGE=bitnami/zookeeper:3.8
|
|
||||||
KAFKA_IMAGE=bitnami/kafka:3.5.1
|
KAFKA_IMAGE=bitnami/kafka:3.5.1
|
||||||
MINIO_IMAGE=minio/minio:RELEASE.2024-01-11T07-46-16Z
|
MINIO_IMAGE=minio/minio:RELEASE.2024-01-11T07-46-16Z
|
||||||
ETCD_IMAGE=quay.io/coreos/etcd:v3.5.13
|
ETCD_IMAGE=quay.io/coreos/etcd:v3.5.13
|
||||||
PROMETHEUS_IMAGE=prom/prometheus:v2.45.6
|
PROMETHEUS_IMAGE=prom/prometheus:v2.45.6
|
||||||
ALERTMANAGER_IMAGE=prom/alertmanager:v0.27.0
|
ALERTMANAGER_IMAGE=prom/alertmanager:v0.27.0
|
||||||
GRAFANA_IMAGE=grafana/grafana:11.0.1
|
GRAFANA_IMAGE=grafana/grafana:11.0.1
|
||||||
|
NODE_EXPORTER_IMAGE=prom/node-exporter:v1.7.0
|
||||||
|
|
||||||
OPENIM_WEB_FRONT_IMAGE=openim/openim-web-front:release-v3.8.1
|
OPENIM_WEB_FRONT_IMAGE=openim/openim-web-front:release-v3.8.3
|
||||||
OPENIM_ADMIN_FRONT_IMAGE=openim/openim-admin-front:release-v1.8.2
|
OPENIM_ADMIN_FRONT_IMAGE=openim/openim-admin-front:release-v1.8.4
|
||||||
|
|
||||||
#FRONT_IMAGE: use aliyun images
|
#FRONT_IMAGE: use aliyun images
|
||||||
#OPENIM_WEB_FRONT_IMAGE=registry.cn-hangzhou.aliyuncs.com/openimsdk/openim-web-front:release-v3.8.1
|
#OPENIM_WEB_FRONT_IMAGE=registry.cn-hangzhou.aliyuncs.com/openimsdk/openim-web-front:release-v3.8.3
|
||||||
#OPENIM_ADMIN_FRONT_IMAGE=registry.cn-hangzhou.aliyuncs.com/openimsdk/openim-admin-front:release-v1.8.2
|
#OPENIM_ADMIN_FRONT_IMAGE=registry.cn-hangzhou.aliyuncs.com/openimsdk/openim-admin-front:release-v1.8.4
|
||||||
|
|
||||||
DATA_DIR=./
|
DATA_DIR=./
|
||||||
|
|
||||||
|
MONGO_BACKUP_DIR=${DATA_DIR}components/backup/mongo/
|
||||||
|
|
||||||
|
PROMETHEUS_PORT=19091
|
||||||
|
ALERTMANAGER_PORT=19093
|
||||||
|
GRAFANA_PORT=13000
|
||||||
|
NODE_EXPORTER_PORT=19100
|
78
.github/workflows/changelog.yml
vendored
Normal file
78
.github/workflows/changelog.yml
vendored
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
name: Release Changelog
|
||||||
|
|
||||||
|
on:
|
||||||
|
release:
|
||||||
|
types: [released]
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
pull-requests: write
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
update-changelog:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Run Go Changelog Generator
|
||||||
|
run: |
|
||||||
|
# Run the Go changelog generator, passing the release tag if available
|
||||||
|
if [ "${{ github.event.release.tag_name }}" = "latest" ]; then
|
||||||
|
go run tools/changelog/changelog.go > "${{ github.event.release.tag_name }}-changelog.md"
|
||||||
|
else
|
||||||
|
go run tools/changelog/changelog.go "${{ github.event.release.tag_name }}" > "${{ github.event.release.tag_name }}-changelog.md"
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Handle changelog files
|
||||||
|
run: |
|
||||||
|
# Ensure that the CHANGELOG directory exists
|
||||||
|
mkdir -p CHANGELOG
|
||||||
|
|
||||||
|
# Extract Major.Minor version by removing the 'v' prefix from the tag name
|
||||||
|
TAG_NAME=${{ github.event.release.tag_name }}
|
||||||
|
CHANGELOG_VERSION_NUMBER=$(echo "$TAG_NAME" | sed 's/^v//' | grep -oP '^\d+\.\d+')
|
||||||
|
|
||||||
|
# Define the new changelog file path
|
||||||
|
CHANGELOG_FILENAME="CHANGELOG-$CHANGELOG_VERSION_NUMBER.md"
|
||||||
|
CHANGELOG_PATH="CHANGELOG/$CHANGELOG_FILENAME"
|
||||||
|
|
||||||
|
# Check if the changelog file for the current release already exists
|
||||||
|
if [ -f "$CHANGELOG_PATH" ]; then
|
||||||
|
# If the file exists, append the new changelog to the existing one
|
||||||
|
cat "$CHANGELOG_PATH" >> "${TAG_NAME}-changelog.md"
|
||||||
|
# Overwrite the existing changelog with the updated content
|
||||||
|
mv "${TAG_NAME}-changelog.md" "$CHANGELOG_PATH"
|
||||||
|
else
|
||||||
|
# If the changelog file doesn't exist, rename the temp changelog file to the new changelog file
|
||||||
|
mv "${TAG_NAME}-changelog.md" "$CHANGELOG_PATH"
|
||||||
|
|
||||||
|
# Ensure that README.md exists
|
||||||
|
if [ ! -f "CHANGELOG/README.md" ]; then
|
||||||
|
echo -e "# CHANGELOGs\n\n" > CHANGELOG/README.md
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Add the new changelog entry at the top of the README.md
|
||||||
|
if ! grep -q "\[$CHANGELOG_FILENAME\]" CHANGELOG/README.md; then
|
||||||
|
sed -i "3i- [$CHANGELOG_FILENAME](./$CHANGELOG_FILENAME)" CHANGELOG/README.md
|
||||||
|
# Remove the extra newline character added by sed
|
||||||
|
# sed -i '4d' CHANGELOG/README.md
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Clean up
|
||||||
|
run: |
|
||||||
|
# Remove any temporary files that were created during the process
|
||||||
|
rm -f "${{ github.event.release.tag_name }}-changelog.md"
|
||||||
|
|
||||||
|
- name: Create Pull Request
|
||||||
|
uses: peter-evans/create-pull-request@v7.0.5
|
||||||
|
with:
|
||||||
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
commit-message: "Update CHANGELOG for release ${{ github.event.release.tag_name }}"
|
||||||
|
title: "Update CHANGELOG for release ${{ github.event.release.tag_name }}"
|
||||||
|
body: "This PR updates the CHANGELOG files for release ${{ github.event.release.tag_name }}"
|
||||||
|
branch: changelog-${{ github.event.release.tag_name }}
|
||||||
|
base: main
|
||||||
|
delete-branch: true
|
||||||
|
labels: changelog
|
65
.github/workflows/cleanup-after-milestone-prs-merged.yml
vendored
Normal file
65
.github/workflows/cleanup-after-milestone-prs-merged.yml
vendored
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
name: Cleanup After Milestone PRs Merged
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
types:
|
||||||
|
- closed
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
handle_pr:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4.2.0
|
||||||
|
|
||||||
|
- name: Get the PR title and extract PR numbers
|
||||||
|
id: extract_pr_numbers
|
||||||
|
run: |
|
||||||
|
# Get the PR title
|
||||||
|
PR_TITLE="${{ github.event.pull_request.title }}"
|
||||||
|
|
||||||
|
echo "PR Title: $PR_TITLE"
|
||||||
|
|
||||||
|
# Extract PR numbers from the title
|
||||||
|
PR_NUMBERS=$(echo "$PR_TITLE" | grep -oE "#[0-9]+" | tr -d '#' | tr '\n' ' ')
|
||||||
|
echo "Extracted PR Numbers: $PR_NUMBERS"
|
||||||
|
|
||||||
|
# Save PR numbers to a file
|
||||||
|
echo "$PR_NUMBERS" > pr_numbers.txt
|
||||||
|
echo "Saved PR Numbers to pr_numbers.txt"
|
||||||
|
|
||||||
|
# Check if the title matches a specific pattern
|
||||||
|
if echo "$PR_TITLE" | grep -qE "^deps: Merge( #[0-9]+)+ PRs into .+"; then
|
||||||
|
echo "proceed=true" >> $GITHUB_OUTPUT
|
||||||
|
else
|
||||||
|
echo "proceed=false" >> $GITHUB_OUTPUT
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Use extracted PR numbers and label PRs
|
||||||
|
if: (steps.extract_pr_numbers.outputs.proceed == 'true' || contains(github.event.pull_request.labels.*.name, 'milestone-merge')) && github.event.pull_request.merged == true
|
||||||
|
run: |
|
||||||
|
# Read the previously saved PR numbers
|
||||||
|
PR_NUMBERS=$(cat pr_numbers.txt)
|
||||||
|
echo "Using extracted PR Numbers: $PR_NUMBERS"
|
||||||
|
|
||||||
|
# Loop through each PR number and add label
|
||||||
|
for PR_NUMBER in $PR_NUMBERS; do
|
||||||
|
echo "Adding 'cherry-picked' label to PR #$PR_NUMBER"
|
||||||
|
curl -X POST \
|
||||||
|
-H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \
|
||||||
|
-H "Accept: application/vnd.github+json" \
|
||||||
|
https://api.github.com/repos/${{ github.repository }}/issues/$PR_NUMBER/labels \
|
||||||
|
-d '{"labels":["cherry-picked"]}'
|
||||||
|
done
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
- name: Delete branch after PR close
|
||||||
|
if: steps.extract_pr_numbers.outputs.proceed == 'true' || contains(github.event.pull_request.labels.*.name, 'milestone-merge')
|
||||||
|
run: |
|
||||||
|
BRANCH_NAME="${{ github.event.pull_request.head.ref }}"
|
||||||
|
echo "Branch to delete: $BRANCH_NAME"
|
||||||
|
git push origin --delete "$BRANCH_NAME"
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
91
.github/workflows/docker-build-and-release-services-images.yml
vendored
Normal file
91
.github/workflows/docker-build-and-release-services-images.yml
vendored
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
name: Build and release services Docker Images
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- release-*
|
||||||
|
release:
|
||||||
|
types: [published]
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
tag:
|
||||||
|
description: "Tag version to be used for Docker image"
|
||||||
|
required: true
|
||||||
|
default: "v3.8.3"
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build-and-push:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Set up Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@v3.8.0
|
||||||
|
|
||||||
|
- name: Log in to Docker Hub
|
||||||
|
uses: docker/login-action@v3.3.0
|
||||||
|
with:
|
||||||
|
username: ${{ secrets.DOCKER_USERNAME }}
|
||||||
|
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||||
|
|
||||||
|
- name: Log in to GitHub Container Registry
|
||||||
|
uses: docker/login-action@v3.3.0
|
||||||
|
with:
|
||||||
|
registry: ghcr.io
|
||||||
|
username: ${{ github.repository_owner }}
|
||||||
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
- name: Log in to Aliyun Container Registry
|
||||||
|
uses: docker/login-action@v3.3.0
|
||||||
|
with:
|
||||||
|
registry: registry.cn-hangzhou.aliyuncs.com
|
||||||
|
username: ${{ secrets.ALIREGISTRY_USERNAME }}
|
||||||
|
password: ${{ secrets.ALIREGISTRY_TOKEN }}
|
||||||
|
|
||||||
|
- name: Extract metadata for Docker (tags, labels)
|
||||||
|
id: meta
|
||||||
|
uses: docker/metadata-action@v5.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: Build and push Docker images
|
||||||
|
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
|
147
.github/workflows/go-build-test.yml
vendored
147
.github/workflows/go-build-test.yml
vendored
@ -2,13 +2,9 @@ name: Go Build Test
|
|||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
pull_request:
|
pull_request:
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
paths-ignore:
|
paths-ignore:
|
||||||
- '**/*.md'
|
- "**/*.md"
|
||||||
|
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
@ -22,7 +18,7 @@ jobs:
|
|||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
os: [ubuntu-latest]
|
os: [ubuntu-latest]
|
||||||
go_version: ["1.21.x", "1.22.x"]
|
go_version: ["1.22.x"]
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout Server repository
|
- name: Checkout Server repository
|
||||||
@ -41,27 +37,20 @@ jobs:
|
|||||||
|
|
||||||
- name: Set up infra services
|
- name: Set up infra services
|
||||||
uses: hoverkraft-tech/compose-action@v2.0.1
|
uses: hoverkraft-tech/compose-action@v2.0.1
|
||||||
# Uncomment and set the correct path to your docker-compose file
|
|
||||||
with:
|
with:
|
||||||
compose-file: "./docker-compose.yml"
|
compose-file: "./docker-compose.yml"
|
||||||
|
|
||||||
# run: |
|
# - name: Get Internal IP Address
|
||||||
# sudo docker compose up -d
|
# id: get-ip
|
||||||
# sudo sleep 30 # Increased sleep time for better stability
|
# run: |
|
||||||
# timeout-minutes: 60 # Increased timeout for Docker setup
|
# IP=$(hostname -I | awk '{print $1}')
|
||||||
|
# echo "The IP Address is: $IP"
|
||||||
|
# echo "::set-output name=ip::$IP"
|
||||||
|
|
||||||
|
# - name: Update .env
|
||||||
# - name: Get Internal IP Address
|
# run: |
|
||||||
# id: get-ip
|
# sed -i 's|externalAddress:.*|externalAddress: "http://${{ steps.get-ip.outputs.ip }}:10005"|' config/minio.yml
|
||||||
# run: |
|
# cat config/minio.yml
|
||||||
# IP=$(hostname -I | awk '{print $1}')
|
|
||||||
# echo "The IP Address is: $IP"
|
|
||||||
# echo "::set-output name=ip::$IP"
|
|
||||||
|
|
||||||
# - name: Update .env
|
|
||||||
# run: |
|
|
||||||
# sed -i 's|externalAddress:.*|externalAddress: "http://${{ steps.get-ip.outputs.ip }}:10005"|' config/minio.yml
|
|
||||||
# cat config/minio.yml
|
|
||||||
|
|
||||||
- name: Build and test Server Services
|
- name: Build and test Server Services
|
||||||
run: |
|
run: |
|
||||||
@ -89,6 +78,90 @@ jobs:
|
|||||||
mage start
|
mage start
|
||||||
mage check
|
mage check
|
||||||
|
|
||||||
|
- name: Test Server and Chat
|
||||||
|
run: |
|
||||||
|
check_error() {
|
||||||
|
echo "Response: $1"
|
||||||
|
errCode=$(echo $1 | jq -r '.errCode')
|
||||||
|
if [ "$errCode" != "0" ]; then
|
||||||
|
errMsg=$(echo $1 | jq -r '.errMsg')
|
||||||
|
echo "Error: $errMsg"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Test register
|
||||||
|
response1=$(curl -X POST -H "Content-Type: application/json" -H "operationID: imAdmin" -d '{
|
||||||
|
"verifyCode": "666666",
|
||||||
|
"platform": 3,
|
||||||
|
"autoLogin": true,
|
||||||
|
"user":{
|
||||||
|
"nickname": "test12312",
|
||||||
|
"areaCode":"+86",
|
||||||
|
"phoneNumber": "12345678190",
|
||||||
|
"password":"test123456"
|
||||||
|
}
|
||||||
|
}' http://127.0.0.1:10008/account/register)
|
||||||
|
check_error "$response1"
|
||||||
|
userID1=$(echo $response1 | jq -r '.data.userID')
|
||||||
|
echo "userID1: $userID1"
|
||||||
|
|
||||||
|
response2=$(curl -X POST -H "Content-Type: application/json" -H "operationID: imAdmin" -d '{
|
||||||
|
"verifyCode": "666666",
|
||||||
|
"platform": 3,
|
||||||
|
"autoLogin": true,
|
||||||
|
"user":{
|
||||||
|
"nickname": "test22312",
|
||||||
|
"areaCode":"+86",
|
||||||
|
"phoneNumber": "12345678290",
|
||||||
|
"password":"test123456"
|
||||||
|
}
|
||||||
|
}' http://127.0.0.1:10008/account/register)
|
||||||
|
check_error "$response2"
|
||||||
|
userID2=$(echo $response2 | jq -r '.data.userID')
|
||||||
|
echo "userID2: $userID2"
|
||||||
|
|
||||||
|
# Test login
|
||||||
|
login_response=$(curl -X POST -H "Content-Type: application/json" -H "operationID: imAdmin" -d '{
|
||||||
|
"platform": 3,
|
||||||
|
"areaCode":"+86",
|
||||||
|
"phoneNumber": "12345678190",
|
||||||
|
"password":"test123456"
|
||||||
|
}' http://localhost:10008/account/login)
|
||||||
|
check_error "$login_response"
|
||||||
|
|
||||||
|
# Test get admin token
|
||||||
|
get_admin_token_response=$(curl -X POST -H "Content-Type: application/json" -H "operationID: imAdmin" -d '{
|
||||||
|
"secret": "openIM123",
|
||||||
|
"platformID": 2,
|
||||||
|
"userID": "imAdmin"
|
||||||
|
}' http://127.0.0.1:10002/auth/get_admin_token)
|
||||||
|
check_error "$get_admin_token_response"
|
||||||
|
adminToken=$(echo $get_admin_token_response | jq -r '.data.token')
|
||||||
|
echo "adminToken: $adminToken"
|
||||||
|
|
||||||
|
# Test send message
|
||||||
|
send_msg_response=$(curl -X POST -H "Content-Type: application/json" -H "operationID: imAdmin" -H "token: $adminToken" -d '{
|
||||||
|
"sendID": "'$userID1'",
|
||||||
|
"recvID": "'$userID2'",
|
||||||
|
"senderPlatformID": 3,
|
||||||
|
"content": {
|
||||||
|
"content": "hello!!"
|
||||||
|
},
|
||||||
|
"contentType": 101,
|
||||||
|
"sessionType": 1
|
||||||
|
}' http://127.0.0.1:10002/msg/send_msg)
|
||||||
|
check_error "$send_msg_response"
|
||||||
|
|
||||||
|
# Test get users
|
||||||
|
get_users_response=$(curl -X POST -H "Content-Type: application/json" -H "operationID: imAdmin" -H "token: $adminToken" -d '{
|
||||||
|
"pagination": {
|
||||||
|
"pageNumber": 1,
|
||||||
|
"showNumber": 100
|
||||||
|
}
|
||||||
|
}' http://127.0.0.1:10002/user/get_users)
|
||||||
|
check_error "$get_users_response"
|
||||||
|
|
||||||
go-test:
|
go-test:
|
||||||
name: Benchmark Test with go ${{ matrix.go_version }} on ${{ matrix.os }}
|
name: Benchmark Test with go ${{ matrix.go_version }} on ${{ matrix.os }}
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
@ -97,11 +170,11 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
SDK_DIR: openim-sdk-core
|
SDK_DIR: openim-sdk-core
|
||||||
CONFIG_PATH: config/notification.yml
|
CONFIG_PATH: config/notification.yml
|
||||||
# pull-requests: write
|
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
os: [ ubuntu-latest ]
|
os: [ubuntu-latest]
|
||||||
go_version: [ "1.22.x" ]
|
go_version: ["1.22.x"]
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout Server repository
|
- name: Checkout Server repository
|
||||||
@ -110,7 +183,8 @@ jobs:
|
|||||||
- name: Checkout SDK repository
|
- name: Checkout SDK repository
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
repository: 'openimsdk/openim-sdk-core'
|
repository: "openimsdk/openim-sdk-core"
|
||||||
|
ref: "release-v3.8"
|
||||||
path: ${{ env.SDK_DIR }}
|
path: ${{ env.SDK_DIR }}
|
||||||
|
|
||||||
- name: Set up Go ${{ matrix.go_version }}
|
- name: Set up Go ${{ matrix.go_version }}
|
||||||
@ -123,15 +197,10 @@ jobs:
|
|||||||
go install github.com/magefile/mage@latest
|
go install github.com/magefile/mage@latest
|
||||||
go mod download
|
go mod download
|
||||||
|
|
||||||
- name: Install yq
|
|
||||||
run: |
|
|
||||||
sudo wget https://github.com/mikefarah/yq/releases/download/v4.34.1/yq_linux_amd64 -O /usr/bin/yq
|
|
||||||
sudo chmod +x /usr/bin/yq
|
|
||||||
|
|
||||||
- name: Modify Server Configuration
|
- name: Modify Server Configuration
|
||||||
run: |
|
run: |
|
||||||
yq e '.groupCreated.unreadCount = true' -i ${{ env.CONFIG_PATH }}
|
yq e '.groupCreated.isSendMsg = true' -i ${{ env.CONFIG_PATH }}
|
||||||
yq e '.friendApplicationApproved.unreadCount = true' -i ${{ env.CONFIG_PATH }}
|
yq e '.friendApplicationApproved.isSendMsg = true' -i ${{ env.CONFIG_PATH }}
|
||||||
|
|
||||||
- name: Start Server Services
|
- name: Start Server Services
|
||||||
run: |
|
run: |
|
||||||
@ -153,7 +222,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
go_version: ["1.21"]
|
go_version: ["1.22"]
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout Repository
|
- name: Checkout Repository
|
||||||
@ -187,11 +256,3 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
CONTAINER_NAME="${{ github.event.repository.name }}-container"
|
CONTAINER_NAME="${{ github.event.repository.name }}-container"
|
||||||
docker logs $CONTAINER_NAME
|
docker logs $CONTAINER_NAME
|
||||||
|
|
||||||
# - name: Cleanup Docker Container
|
|
||||||
# run: |
|
|
||||||
# CONTAINER_NAME="${{ github.event.repository.name }}-container"
|
|
||||||
# IMAGE_NAME="${{ github.event.repository.name }}-test"
|
|
||||||
# docker stop $CONTAINER_NAME
|
|
||||||
# docker rm $CONTAINER_NAME
|
|
||||||
# docker rmi $IMAGE_NAME
|
|
||||||
|
146
.github/workflows/merge-from-milestone.yml
vendored
Normal file
146
.github/workflows/merge-from-milestone.yml
vendored
Normal file
@ -0,0 +1,146 @@
|
|||||||
|
name: Create Individual PRs from Milestone
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
pull-requests: write
|
||||||
|
issues: write
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
milestone_name:
|
||||||
|
description: "Milestone name to collect closed PRs from"
|
||||||
|
required: true
|
||||||
|
default: "v3.8.4"
|
||||||
|
target_branch:
|
||||||
|
description: "Target branch to merge the consolidated PR"
|
||||||
|
required: true
|
||||||
|
default: "pre-release-v3.8.4"
|
||||||
|
|
||||||
|
env:
|
||||||
|
MILESTONE_NAME: ${{ github.event.inputs.milestone_name || 'v3.8.4' }}
|
||||||
|
TARGET_BRANCH: ${{ github.event.inputs.target_branch || 'pre-release-v3.8.4' }}
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
BOT_TOKEN: ${{ secrets.BOT_TOKEN }}
|
||||||
|
LABEL_NAME: cherry-picked
|
||||||
|
TEMP_DIR: /tmp
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
merge_milestone_prs:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Setup temp directory
|
||||||
|
run: |
|
||||||
|
# Create the temporary directory and initialize necessary files
|
||||||
|
mkdir -p ${{ env.TEMP_DIR }}
|
||||||
|
touch ${{ env.TEMP_DIR }}/pr_numbers.txt
|
||||||
|
touch ${{ env.TEMP_DIR }}/commit_hashes.txt
|
||||||
|
touch ${{ env.TEMP_DIR }}/pr_title.txt
|
||||||
|
touch ${{ env.TEMP_DIR }}/pr_body.txt
|
||||||
|
touch ${{ env.TEMP_DIR }}/created_pr_number.txt
|
||||||
|
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
token: ${{ secrets.BOT_TOKEN }}
|
||||||
|
|
||||||
|
- name: Setup Git User for OpenIM-Robot
|
||||||
|
run: |
|
||||||
|
git config --global user.email "OpenIM-Robot@users.noreply.github.com"
|
||||||
|
git config --global user.name "OpenIM-Robot"
|
||||||
|
|
||||||
|
- name: Fetch Milestone ID and Filter PR Numbers
|
||||||
|
env:
|
||||||
|
MILESTONE_NAME: ${{ env.MILESTONE_NAME }}
|
||||||
|
run: |
|
||||||
|
# Fetch milestone details and extract milestone ID
|
||||||
|
milestones=$(curl -s -H "Authorization: token $BOT_TOKEN" \
|
||||||
|
-H "Accept: application/vnd.github+json" \
|
||||||
|
"https://api.github.com/repos/${{ github.repository }}/milestones")
|
||||||
|
milestone_id=$(echo "$milestones" | grep -B3 "\"title\": \"$MILESTONE_NAME\"" | grep '"number":' | head -n1 | grep -o '[0-9]\+')
|
||||||
|
if [ -z "$milestone_id" ]; then
|
||||||
|
echo "Milestone '$MILESTONE_NAME' not found. Exiting."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "Milestone ID: $milestone_id"
|
||||||
|
echo "MILESTONE_ID=$milestone_id" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
# Fetch issues for the milestone
|
||||||
|
issues=$(curl -s -H "Authorization: token $BOT_TOKEN" \
|
||||||
|
-H "Accept: application/vnd.github+json" \
|
||||||
|
"https://api.github.com/repos/${{ github.repository }}/issues?milestone=$milestone_id&state=closed&per_page=100")
|
||||||
|
|
||||||
|
> ${{ env.TEMP_DIR }}/pr_numbers.txt
|
||||||
|
|
||||||
|
# Filter PRs that do not have the 'cherry-picked' label
|
||||||
|
for pr_number in $(echo "$issues" | jq -r '.[] | select(.pull_request != null) | .number'); do
|
||||||
|
labels=$(curl -s -H "Authorization: token $BOT_TOKEN" \
|
||||||
|
-H "Accept: application/vnd.github+json" \
|
||||||
|
"https://api.github.com/repos/${{ github.repository }}/issues/$pr_number/labels" | jq -r '.[].name')
|
||||||
|
|
||||||
|
if ! echo "$labels" | grep -q "${LABEL_NAME}"; then
|
||||||
|
echo "PR #$pr_number does not have the 'cherry-picked' label. Adding to the list."
|
||||||
|
echo "$pr_number" >> ${{ env.TEMP_DIR }}/pr_numbers.txt
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
sort -n ${{ env.TEMP_DIR }}/pr_numbers.txt -o ${{ env.TEMP_DIR }}/pr_numbers.txt
|
||||||
|
|
||||||
|
- name: Create Individual PRs
|
||||||
|
run: |
|
||||||
|
for pr_number in $(cat ${{ env.TEMP_DIR }}/pr_numbers.txt); do
|
||||||
|
pr_details=$(curl -s -H "Authorization: token $BOT_TOKEN" \
|
||||||
|
-H "Accept: application/vnd.github+json" \
|
||||||
|
"https://api.github.com/repos/${{ github.repository }}/pulls/$pr_number")
|
||||||
|
pr_title=$(echo "$pr_details" | jq -r '.title')
|
||||||
|
pr_body=$(echo "$pr_details" | jq -r '.body')
|
||||||
|
pr_creator=$(echo "$pr_details" | jq -r '.user.login')
|
||||||
|
merge_commit=$(echo "$pr_details" | jq -r '.merge_commit_sha')
|
||||||
|
short_commit_hash=$(echo "$merge_commit" | cut -c 1-7)
|
||||||
|
|
||||||
|
if [ "$merge_commit" != "null" ]; then
|
||||||
|
git fetch origin
|
||||||
|
|
||||||
|
echo "Checking out target branch: $TARGET_BRANCH"
|
||||||
|
git checkout $TARGET_BRANCH
|
||||||
|
|
||||||
|
echo "Pulling latest changes from target branch: $TARGET_BRANCH"
|
||||||
|
git pull origin $TARGET_BRANCH
|
||||||
|
|
||||||
|
cherry_pick_branch="cherry-pick-${short_commit_hash}"
|
||||||
|
git checkout -b $cherry_pick_branch
|
||||||
|
|
||||||
|
echo "Cherry-picking commit: $merge_commit"
|
||||||
|
if ! git cherry-pick "$merge_commit" --strategy=recursive -X theirs; then
|
||||||
|
echo "Cherry-pick encountered conflicts, attempting to continue..."
|
||||||
|
git cherry-pick --continue || { echo "Cherry-pick failed"; exit 1; }
|
||||||
|
fi
|
||||||
|
|
||||||
|
git remote set-url origin "https://${BOT_TOKEN}@github.com/${{ github.repository }}.git"
|
||||||
|
|
||||||
|
echo "Pushing branch: $cherry_pick_branch"
|
||||||
|
git push origin $cherry_pick_branch --force || { echo "Push failed"; exit 1; }
|
||||||
|
|
||||||
|
new_pr_title="$pr_title [Created by @$pr_creator from #$pr_number]"
|
||||||
|
new_pr_body="$pr_body
|
||||||
|
> This PR is created from original PR #$pr_number."
|
||||||
|
|
||||||
|
response=$(curl -s -X POST -H "Authorization: token $BOT_TOKEN" \
|
||||||
|
-H "Accept: application/vnd.github+json" \
|
||||||
|
https://api.github.com/repos/${{ github.repository }}/pulls \
|
||||||
|
-d "$(jq -n --arg title "$new_pr_title" \
|
||||||
|
--arg head "$cherry_pick_branch" \
|
||||||
|
--arg base "$TARGET_BRANCH" \
|
||||||
|
--arg body "$new_pr_body" \
|
||||||
|
'{title: $title, head: $head, base: $base, body: $body}')")
|
||||||
|
|
||||||
|
new_pr_number=$(echo "$response" | jq -r '.number')
|
||||||
|
echo "Created PR #$new_pr_number"
|
||||||
|
|
||||||
|
curl -s -X POST -H "Authorization: token $GITHUB_TOKEN" \
|
||||||
|
-H "Accept: application/vnd.github+json" \
|
||||||
|
-d '{"labels": ["milestone-merge"]}' \
|
||||||
|
"https://api.github.com/repos/${{ github.repository }}/issues/$new_pr_number/labels"
|
||||||
|
fi
|
||||||
|
done
|
83
.github/workflows/publish-docker-image.yml
vendored
83
.github/workflows/publish-docker-image.yml
vendored
@ -25,11 +25,11 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
path: main-repo
|
path: main-repo
|
||||||
|
|
||||||
- name: Set up QEMU
|
# - name: Set up QEMU
|
||||||
uses: docker/setup-qemu-action@v3
|
# uses: docker/setup-qemu-action@v3.3.0
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v3
|
uses: docker/setup-buildx-action@v3.8.0
|
||||||
|
|
||||||
- name: Build Docker image
|
- name: Build Docker image
|
||||||
id: build
|
id: build
|
||||||
@ -38,11 +38,8 @@ jobs:
|
|||||||
context: ./main-repo
|
context: ./main-repo
|
||||||
load: true
|
load: true
|
||||||
tags: "openim/openim-server:local"
|
tags: "openim/openim-server:local"
|
||||||
cache-from: type=gha
|
cache-from: type=gha,scope=build
|
||||||
cache-to: type=gha,mode=max
|
cache-to: type=gha,mode=max,scope=build
|
||||||
|
|
||||||
- name: Save Docker image to file
|
|
||||||
run: docker save -o image.tar openim/openim-server:local
|
|
||||||
|
|
||||||
- name: Checkout compose repository
|
- name: Checkout compose repository
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
@ -66,43 +63,12 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
cd ${{ github.workspace }}/compose-repo
|
cd ${{ github.workspace }}/compose-repo
|
||||||
docker compose up -d
|
docker compose up -d
|
||||||
sleep 60
|
|
||||||
|
|
||||||
# - name: Check openim-server health
|
docker compose ps
|
||||||
# run: |
|
|
||||||
# timeout=300
|
|
||||||
# interval=30
|
|
||||||
# elapsed=0
|
|
||||||
# while [[ $elapsed -le $timeout ]]; do
|
|
||||||
# if ! docker exec openim-server mage check; then
|
|
||||||
# echo "openim-server is not ready, waiting..."
|
|
||||||
# sleep $interval
|
|
||||||
# elapsed=$(($elapsed + $interval))
|
|
||||||
# else
|
|
||||||
# echo "Health check successful"
|
|
||||||
# exit 0
|
|
||||||
# fi
|
|
||||||
# done
|
|
||||||
# echo "Health check failed after 5 minutes"
|
|
||||||
# exit 1
|
|
||||||
|
|
||||||
# - name: Check openim-chat health
|
|
||||||
# if: success()
|
|
||||||
# run: |
|
|
||||||
# if ! docker exec openim-chat mage check; then
|
|
||||||
# echo "openim-chat check failed"
|
|
||||||
# exit 1
|
|
||||||
# else
|
|
||||||
# echo "Health check successful"
|
|
||||||
# exit 0
|
|
||||||
# fi
|
|
||||||
|
|
||||||
- name: Load Docker image from file
|
|
||||||
run: docker load -i image.tar
|
|
||||||
|
|
||||||
- name: Extract metadata for Docker (tags, labels)
|
- name: Extract metadata for Docker (tags, labels)
|
||||||
id: meta
|
id: meta
|
||||||
uses: docker/metadata-action@v5.5.1
|
uses: docker/metadata-action@v5.6.0
|
||||||
with:
|
with:
|
||||||
images: |
|
images: |
|
||||||
openim/openim-server
|
openim/openim-server
|
||||||
@ -112,29 +78,27 @@ jobs:
|
|||||||
type=ref,event=tag
|
type=ref,event=tag
|
||||||
type=schedule
|
type=schedule
|
||||||
type=ref,event=branch
|
type=ref,event=branch
|
||||||
type=semver,pattern={{version}}
|
# type=semver,pattern={{version}}
|
||||||
type=semver,pattern=v{{version}}
|
type=semver,pattern=v{{version}}
|
||||||
type=semver,pattern={{major}}.{{minor}}
|
|
||||||
type=semver,pattern={{major}}
|
|
||||||
type=semver,pattern=release-{{raw}}
|
type=semver,pattern=release-{{raw}}
|
||||||
type=sha
|
type=sha
|
||||||
type=raw,value=${{ github.event.inputs.tag }}
|
type=raw,value=${{ github.event.inputs.tag }}
|
||||||
|
|
||||||
- name: Log in to Docker Hub
|
- name: Log in to Docker Hub
|
||||||
uses: docker/login-action@v2
|
uses: docker/login-action@v3.3.0
|
||||||
with:
|
with:
|
||||||
username: ${{ secrets.DOCKER_USERNAME }}
|
username: ${{ secrets.DOCKER_USERNAME }}
|
||||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||||
|
|
||||||
- name: Log in to GitHub Container Registry
|
- name: Log in to GitHub Container Registry
|
||||||
uses: docker/login-action@v2
|
uses: docker/login-action@v3.3.0
|
||||||
with:
|
with:
|
||||||
registry: ghcr.io
|
registry: ghcr.io
|
||||||
username: ${{ github.repository_owner }}
|
username: ${{ github.repository_owner }}
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Log in to Aliyun Container Registry
|
- name: Log in to Aliyun Container Registry
|
||||||
uses: docker/login-action@v2
|
uses: docker/login-action@v3.3.0
|
||||||
with:
|
with:
|
||||||
registry: registry.cn-hangzhou.aliyuncs.com
|
registry: registry.cn-hangzhou.aliyuncs.com
|
||||||
username: ${{ secrets.ALIREGISTRY_USERNAME }}
|
username: ${{ secrets.ALIREGISTRY_USERNAME }}
|
||||||
@ -148,3 +112,28 @@ jobs:
|
|||||||
platforms: linux/amd64,linux/arm64
|
platforms: linux/amd64,linux/arm64
|
||||||
tags: ${{ steps.meta.outputs.tags }}
|
tags: ${{ steps.meta.outputs.tags }}
|
||||||
labels: ${{ steps.meta.outputs.labels }}
|
labels: ${{ steps.meta.outputs.labels }}
|
||||||
|
cache-from: type=gha,scope=build
|
||||||
|
cache-to: type=gha,mode=max,scope=build
|
||||||
|
|
||||||
|
- name: Verify multi-platform support
|
||||||
|
run: |
|
||||||
|
images=("openim/openim-server" "ghcr.io/openimsdk/openim-server" "registry.cn-hangzhou.aliyuncs.com/openimsdk/openim-server")
|
||||||
|
for image in "${images[@]}"; do
|
||||||
|
for tag in $(echo "${{ steps.meta.outputs.tags }}" | tr ',' '\n'); do
|
||||||
|
manifest=$(docker manifest inspect "$image:$tag" || echo "error")
|
||||||
|
if [[ "$manifest" == "error" ]]; then
|
||||||
|
echo "Manifest not found for $image:$tag"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
amd64_found=$(echo "$manifest" | jq '.manifests[] | select(.platform.architecture == "amd64")')
|
||||||
|
arm64_found=$(echo "$manifest" | jq '.manifests[] | select(.platform.architecture == "arm64")')
|
||||||
|
if [[ -z "$amd64_found" ]]; then
|
||||||
|
echo "Multi-platform support check failed for $image:$tag - missing amd64"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if [[ -z "$arm64_found" ]]; then
|
||||||
|
echo "Multi-platform support check failed for $image:$tag - missing arm64"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
done
|
||||||
|
84
.github/workflows/update-version-file-on-release.yml
vendored
Normal file
84
.github/workflows/update-version-file-on-release.yml
vendored
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
name: Update Version File on Release
|
||||||
|
|
||||||
|
on:
|
||||||
|
release:
|
||||||
|
types: [created]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
update-version:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
env:
|
||||||
|
TAG_VERSION: ${{ github.event.release.tag_name }}
|
||||||
|
steps:
|
||||||
|
# Step 1: Checkout the original repository's code
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
# Step 2: Set up Git with official account
|
||||||
|
- name: Set up Git
|
||||||
|
run: |
|
||||||
|
git config user.name "github-actions[bot]"
|
||||||
|
git config user.email "github-actions[bot]@users.noreply.github.com"
|
||||||
|
|
||||||
|
# Step 3: Check and delete existing tag
|
||||||
|
- name: Check and delete existing tag
|
||||||
|
run: |
|
||||||
|
if git rev-parse ${{ env.TAG_VERSION }} >/dev/null 2>&1; then
|
||||||
|
git tag -d ${{ env.TAG_VERSION }}
|
||||||
|
git push --delete origin ${{ env.TAG_VERSION }}
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Step 4: Update version file
|
||||||
|
- name: Update version file
|
||||||
|
run: |
|
||||||
|
echo "${{ env.TAG_VERSION }}" > version/version
|
||||||
|
|
||||||
|
# Step 5: Commit and push changes
|
||||||
|
- name: Commit and push changes
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
run: |
|
||||||
|
git add version/version
|
||||||
|
git commit -m "Update version to ${{ env.TAG_VERSION }}"
|
||||||
|
git push origin HEAD:${{ github.ref }}
|
||||||
|
|
||||||
|
# Step 6: Create and push tag
|
||||||
|
- name: Create and push tag
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
run: |
|
||||||
|
git tag ${{ env.TAG_VERSION }}
|
||||||
|
git push origin ${{ env.TAG_VERSION }}
|
||||||
|
|
||||||
|
# Step 7: Find and Publish Draft Release
|
||||||
|
- name: Find and Publish Draft Release
|
||||||
|
uses: actions/github-script@v6
|
||||||
|
with:
|
||||||
|
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
script: |
|
||||||
|
// Get the list of releases
|
||||||
|
const releases = await github.rest.repos.listReleases({
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo
|
||||||
|
});
|
||||||
|
|
||||||
|
// Find the draft release where the title and tag_name are the same
|
||||||
|
const draftRelease = releases.data.find(release =>
|
||||||
|
release.draft && release.name === release.tag_name
|
||||||
|
);
|
||||||
|
|
||||||
|
if (draftRelease) {
|
||||||
|
// Publish the draft release using the release_id
|
||||||
|
await github.rest.repos.updateRelease({
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
release_id: draftRelease.id, // Use release_id
|
||||||
|
draft: false
|
||||||
|
});
|
||||||
|
|
||||||
|
core.info(`Draft Release ${draftRelease.tag_name} published successfully.`);
|
||||||
|
} else {
|
||||||
|
core.info("No matching draft release found.");
|
||||||
|
}
|
@ -1,62 +0,0 @@
|
|||||||
# Version logging for OpenIM
|
|
||||||
|
|
||||||
<!-- BEGIN MUNGE: GENERATED_TOC -->
|
|
||||||
|
|
||||||
<!-- END MUNGE: GENERATED_TOC -->
|
|
||||||
|
|
||||||
{{ if .Versions -}}
|
|
||||||
<a name="unreleased"></a>
|
|
||||||
## [Unreleased]
|
|
||||||
|
|
||||||
{{ if .Unreleased.CommitGroups -}}
|
|
||||||
{{ range .Unreleased.CommitGroups -}}
|
|
||||||
### {{ .Title }}
|
|
||||||
{{ range .Commits -}}
|
|
||||||
- {{ if .Scope }}**{{ .Scope }}:** {{ end }}{{ .Subject }}
|
|
||||||
{{ end }}
|
|
||||||
{{ end -}}
|
|
||||||
{{ end -}}
|
|
||||||
{{ end -}}
|
|
||||||
|
|
||||||
{{ range .Versions }}
|
|
||||||
<a name="{{ .Tag.Name }}"></a>
|
|
||||||
## {{ if .Tag.Previous }}[{{ .Tag.Name }}]{{ else }}{{ .Tag.Name }}{{ end }} - {{ datetime "2006-01-02" .Tag.Date }}
|
|
||||||
{{ range .CommitGroups -}}
|
|
||||||
### {{ .Title }}
|
|
||||||
{{ range .Commits -}}
|
|
||||||
- {{ if .Scope }}**{{ .Scope }}:** {{ end }}{{ .Subject }}
|
|
||||||
{{ end }}
|
|
||||||
{{ end -}}
|
|
||||||
|
|
||||||
{{- if .RevertCommits -}}
|
|
||||||
### Reverts
|
|
||||||
{{ range .RevertCommits -}}
|
|
||||||
- {{ .Revert.Header }}
|
|
||||||
{{ end }}
|
|
||||||
{{ end -}}
|
|
||||||
|
|
||||||
{{- if .MergeCommits -}}
|
|
||||||
### Pull Requests
|
|
||||||
{{ range .MergeCommits -}}
|
|
||||||
- {{ .Header }}
|
|
||||||
{{ end }}
|
|
||||||
{{ end -}}
|
|
||||||
|
|
||||||
{{- if .NoteGroups -}}
|
|
||||||
{{ range .NoteGroups -}}
|
|
||||||
### {{ .Title }}
|
|
||||||
{{ range .Notes }}
|
|
||||||
{{ .Body }}
|
|
||||||
{{ end }}
|
|
||||||
{{ end -}}
|
|
||||||
{{ end -}}
|
|
||||||
{{ end -}}
|
|
||||||
|
|
||||||
{{- if .Versions }}
|
|
||||||
[Unreleased]: {{ .Info.RepositoryURL }}/compare/{{ $latest := index .Versions 0 }}{{ $latest.Tag.Name }}...HEAD
|
|
||||||
{{ range .Versions -}}
|
|
||||||
{{ if .Tag.Previous -}}
|
|
||||||
[{{ .Tag.Name }}]: {{ $.Info.RepositoryURL }}/compare/{{ .Tag.Previous.Name }}...{{ .Tag.Name }}
|
|
||||||
{{ end -}}
|
|
||||||
{{ end -}}
|
|
||||||
{{ end -}}
|
|
@ -1,67 +0,0 @@
|
|||||||
bin: git
|
|
||||||
style: github
|
|
||||||
template: CHANGELOG.tpl.md
|
|
||||||
info:
|
|
||||||
title: CHANGELOG
|
|
||||||
repository_url: https://github.com/openimsdk/open-im-server
|
|
||||||
options:
|
|
||||||
tag_filter_pattern: '^v'
|
|
||||||
sort: "date"
|
|
||||||
|
|
||||||
commits:
|
|
||||||
filters:
|
|
||||||
Type:
|
|
||||||
- feat
|
|
||||||
- fix
|
|
||||||
- perf
|
|
||||||
- refactor
|
|
||||||
- docs
|
|
||||||
- test
|
|
||||||
- chore
|
|
||||||
- ci
|
|
||||||
- build
|
|
||||||
sort_by: Scope
|
|
||||||
|
|
||||||
commit_groups:
|
|
||||||
group_by: Type
|
|
||||||
sort_by: Title
|
|
||||||
title_order:
|
|
||||||
- feat
|
|
||||||
- fix
|
|
||||||
- perf
|
|
||||||
- refactor
|
|
||||||
- docs
|
|
||||||
- test
|
|
||||||
- chore
|
|
||||||
- ci
|
|
||||||
- build
|
|
||||||
title_maps:
|
|
||||||
feat: Features
|
|
||||||
|
|
||||||
header:
|
|
||||||
pattern: "<regexp>"
|
|
||||||
pattern_maps:
|
|
||||||
- PropName
|
|
||||||
|
|
||||||
issues:
|
|
||||||
prefix:
|
|
||||||
- #
|
|
||||||
|
|
||||||
refs:
|
|
||||||
actions:
|
|
||||||
- Closes
|
|
||||||
- Fixes
|
|
||||||
|
|
||||||
merges:
|
|
||||||
pattern: "^Merge branch '(\\w+)'$"
|
|
||||||
pattern_maps:
|
|
||||||
- Source
|
|
||||||
|
|
||||||
reverts:
|
|
||||||
pattern: "^Revert \"([\\s\\S]*)\"$"
|
|
||||||
pattern_maps:
|
|
||||||
- Header
|
|
||||||
|
|
||||||
notes:
|
|
||||||
keywords:
|
|
||||||
- BREAKING CHANGE
|
|
@ -1,5 +1,5 @@
|
|||||||
# Use Go 1.21 Alpine as the base image for building the application
|
# Use Go 1.22 Alpine as the base image for building the application
|
||||||
FROM golang:1.21-alpine AS builder
|
FROM golang:1.22-alpine AS builder
|
||||||
|
|
||||||
# Define the base directory for the application as an environment variable
|
# Define the base directory for the application as an environment variable
|
||||||
ENV SERVER_DIR=/openim-server
|
ENV SERVER_DIR=/openim-server
|
||||||
@ -8,7 +8,7 @@ ENV SERVER_DIR=/openim-server
|
|||||||
WORKDIR $SERVER_DIR
|
WORKDIR $SERVER_DIR
|
||||||
|
|
||||||
# Set the Go proxy to improve dependency resolution speed
|
# Set the Go proxy to improve dependency resolution speed
|
||||||
ENV GOPROXY=https://goproxy.io,direct
|
# ENV GOPROXY=https://goproxy.io,direct
|
||||||
|
|
||||||
# Copy all files from the current directory into the container
|
# Copy all files from the current directory into the container
|
||||||
COPY . .
|
COPY . .
|
||||||
@ -22,7 +22,7 @@ RUN go install github.com/magefile/mage@v1.15.0
|
|||||||
RUN mage build
|
RUN mage build
|
||||||
|
|
||||||
# Using Alpine Linux with Go environment for the final image
|
# Using Alpine Linux with Go environment for the final image
|
||||||
FROM golang:1.21-alpine
|
FROM golang:1.22-alpine
|
||||||
|
|
||||||
# Install necessary packages, such as bash
|
# Install necessary packages, such as bash
|
||||||
RUN apk add --no-cache bash
|
RUN apk add --no-cache bash
|
||||||
|
@ -53,15 +53,8 @@ builds:
|
|||||||
- windows
|
- windows
|
||||||
- linux
|
- linux
|
||||||
goarch:
|
goarch:
|
||||||
- s390x
|
|
||||||
- mips64
|
|
||||||
- mips64le
|
|
||||||
- amd64
|
- amd64
|
||||||
- ppc64le
|
|
||||||
- arm64
|
- arm64
|
||||||
goarm:
|
|
||||||
- "6"
|
|
||||||
- "7"
|
|
||||||
|
|
||||||
- binary: openim-cmdutils
|
- binary: openim-cmdutils
|
||||||
id: openim-cmdutils
|
id: openim-cmdutils
|
||||||
@ -71,15 +64,8 @@ builds:
|
|||||||
- windows
|
- windows
|
||||||
- linux
|
- linux
|
||||||
goarch:
|
goarch:
|
||||||
- s390x
|
|
||||||
- mips64
|
|
||||||
- mips64le
|
|
||||||
- amd64
|
- amd64
|
||||||
- ppc64le
|
|
||||||
- arm64
|
- arm64
|
||||||
goarm:
|
|
||||||
- "6"
|
|
||||||
- "7"
|
|
||||||
|
|
||||||
- binary: openim-crontask
|
- binary: openim-crontask
|
||||||
id: openim-crontask
|
id: openim-crontask
|
||||||
@ -89,15 +75,8 @@ builds:
|
|||||||
- windows
|
- windows
|
||||||
- linux
|
- linux
|
||||||
goarch:
|
goarch:
|
||||||
- s390x
|
|
||||||
- mips64
|
|
||||||
- mips64le
|
|
||||||
- amd64
|
- amd64
|
||||||
- ppc64le
|
|
||||||
- arm64
|
- arm64
|
||||||
goarm:
|
|
||||||
- "6"
|
|
||||||
- "7"
|
|
||||||
|
|
||||||
- binary: openim-msggateway
|
- binary: openim-msggateway
|
||||||
id: openim-msggateway
|
id: openim-msggateway
|
||||||
@ -107,15 +86,8 @@ builds:
|
|||||||
- windows
|
- windows
|
||||||
- linux
|
- linux
|
||||||
goarch:
|
goarch:
|
||||||
- s390x
|
|
||||||
- mips64
|
|
||||||
- mips64le
|
|
||||||
- amd64
|
- amd64
|
||||||
- ppc64le
|
|
||||||
- arm64
|
- arm64
|
||||||
goarm:
|
|
||||||
- "6"
|
|
||||||
- "7"
|
|
||||||
|
|
||||||
- binary: openim-msgtransfer
|
- binary: openim-msgtransfer
|
||||||
id: openim-msgtransfer
|
id: openim-msgtransfer
|
||||||
@ -125,15 +97,8 @@ builds:
|
|||||||
- windows
|
- windows
|
||||||
- linux
|
- linux
|
||||||
goarch:
|
goarch:
|
||||||
- s390x
|
|
||||||
- mips64
|
|
||||||
- mips64le
|
|
||||||
- amd64
|
- amd64
|
||||||
- ppc64le
|
|
||||||
- arm64
|
- arm64
|
||||||
goarm:
|
|
||||||
- "6"
|
|
||||||
- "7"
|
|
||||||
|
|
||||||
- binary: openim-push
|
- binary: openim-push
|
||||||
id: openim-push
|
id: openim-push
|
||||||
@ -143,15 +108,8 @@ builds:
|
|||||||
- windows
|
- windows
|
||||||
- linux
|
- linux
|
||||||
goarch:
|
goarch:
|
||||||
- s390x
|
|
||||||
- mips64
|
|
||||||
- mips64le
|
|
||||||
- amd64
|
- amd64
|
||||||
- ppc64le
|
|
||||||
- arm64
|
- arm64
|
||||||
goarm:
|
|
||||||
- "6"
|
|
||||||
- "7"
|
|
||||||
|
|
||||||
- binary: openim-rpc-auth
|
- binary: openim-rpc-auth
|
||||||
id: openim-rpc-auth
|
id: openim-rpc-auth
|
||||||
@ -161,15 +119,8 @@ builds:
|
|||||||
- windows
|
- windows
|
||||||
- linux
|
- linux
|
||||||
goarch:
|
goarch:
|
||||||
- s390x
|
|
||||||
- mips64
|
|
||||||
- mips64le
|
|
||||||
- amd64
|
- amd64
|
||||||
- ppc64le
|
|
||||||
- arm64
|
- arm64
|
||||||
goarm:
|
|
||||||
- "6"
|
|
||||||
- "7"
|
|
||||||
|
|
||||||
- binary: openim-rpc-conversation
|
- binary: openim-rpc-conversation
|
||||||
id: openim-rpc-conversation
|
id: openim-rpc-conversation
|
||||||
@ -179,15 +130,8 @@ builds:
|
|||||||
- windows
|
- windows
|
||||||
- linux
|
- linux
|
||||||
goarch:
|
goarch:
|
||||||
- s390x
|
|
||||||
- mips64
|
|
||||||
- mips64le
|
|
||||||
- amd64
|
- amd64
|
||||||
- ppc64le
|
|
||||||
- arm64
|
- arm64
|
||||||
goarm:
|
|
||||||
- "6"
|
|
||||||
- "7"
|
|
||||||
|
|
||||||
- binary: openim-rpc-friend
|
- binary: openim-rpc-friend
|
||||||
id: openim-rpc-friend
|
id: openim-rpc-friend
|
||||||
@ -197,15 +141,8 @@ builds:
|
|||||||
- windows
|
- windows
|
||||||
- linux
|
- linux
|
||||||
goarch:
|
goarch:
|
||||||
- s390x
|
|
||||||
- mips64
|
|
||||||
- mips64le
|
|
||||||
- amd64
|
- amd64
|
||||||
- ppc64le
|
|
||||||
- arm64
|
- arm64
|
||||||
goarm:
|
|
||||||
- "6"
|
|
||||||
- "7"
|
|
||||||
|
|
||||||
- binary: openim-rpc-group
|
- binary: openim-rpc-group
|
||||||
id: openim-rpc-group
|
id: openim-rpc-group
|
||||||
@ -215,15 +152,8 @@ builds:
|
|||||||
- windows
|
- windows
|
||||||
- linux
|
- linux
|
||||||
goarch:
|
goarch:
|
||||||
- s390x
|
|
||||||
- mips64
|
|
||||||
- mips64le
|
|
||||||
- amd64
|
- amd64
|
||||||
- ppc64le
|
|
||||||
- arm64
|
- arm64
|
||||||
goarm:
|
|
||||||
- "6"
|
|
||||||
- "7"
|
|
||||||
|
|
||||||
- binary: openim-rpc-msg
|
- binary: openim-rpc-msg
|
||||||
id: openim-rpc-msg
|
id: openim-rpc-msg
|
||||||
@ -233,15 +163,8 @@ builds:
|
|||||||
- windows
|
- windows
|
||||||
- linux
|
- linux
|
||||||
goarch:
|
goarch:
|
||||||
- s390x
|
|
||||||
- mips64
|
|
||||||
- mips64le
|
|
||||||
- amd64
|
- amd64
|
||||||
- ppc64le
|
|
||||||
- arm64
|
- arm64
|
||||||
goarm:
|
|
||||||
- "6"
|
|
||||||
- "7"
|
|
||||||
|
|
||||||
- binary: openim-rpc-third
|
- binary: openim-rpc-third
|
||||||
id: openim-rpc-third
|
id: openim-rpc-third
|
||||||
@ -251,15 +174,8 @@ builds:
|
|||||||
- windows
|
- windows
|
||||||
- linux
|
- linux
|
||||||
goarch:
|
goarch:
|
||||||
- s390x
|
|
||||||
- mips64
|
|
||||||
- mips64le
|
|
||||||
- amd64
|
- amd64
|
||||||
- ppc64le
|
|
||||||
- arm64
|
- arm64
|
||||||
goarm:
|
|
||||||
- "6"
|
|
||||||
- "7"
|
|
||||||
|
|
||||||
- binary: openim-rpc-user
|
- binary: openim-rpc-user
|
||||||
id: openim-rpc-user
|
id: openim-rpc-user
|
||||||
@ -269,15 +185,8 @@ builds:
|
|||||||
- windows
|
- windows
|
||||||
- linux
|
- linux
|
||||||
goarch:
|
goarch:
|
||||||
- s390x
|
|
||||||
- mips64
|
|
||||||
- mips64le
|
|
||||||
- amd64
|
- amd64
|
||||||
- ppc64le
|
|
||||||
- arm64
|
- arm64
|
||||||
goarm:
|
|
||||||
- "6"
|
|
||||||
- "7"
|
|
||||||
|
|
||||||
|
|
||||||
# TODO:Need a script, such as the init - release to help binary to find the right directory
|
# TODO:Need a script, such as the init - release to help binary to find the right directory
|
||||||
|
@ -15,10 +15,9 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
_ "net/http/pprof"
|
|
||||||
|
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/common/cmd"
|
"github.com/openimsdk/open-im-server/v3/pkg/common/cmd"
|
||||||
"github.com/openimsdk/tools/system/program"
|
"github.com/openimsdk/tools/system/program"
|
||||||
|
_ "net/http/pprof"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
@ -5,9 +5,13 @@ etcd:
|
|||||||
username: ''
|
username: ''
|
||||||
password: ''
|
password: ''
|
||||||
|
|
||||||
zookeeper:
|
rpcService:
|
||||||
schema: openim
|
user: user-rpc-service
|
||||||
address: [ localhost:12181 ]
|
friend: friend-rpc-service
|
||||||
username: ''
|
msg: msg-rpc-service
|
||||||
password: ''
|
push: push-rpc-service
|
||||||
|
messageGateway: messagegateway-rpc-service
|
||||||
|
group: group-rpc-service
|
||||||
|
auth: auth-rpc-service
|
||||||
|
conversation: conversation-rpc-service
|
||||||
|
third: third-rpc-service
|
@ -8,6 +8,8 @@ database: openim_v3
|
|||||||
username: openIM
|
username: openIM
|
||||||
# Password for database authentication
|
# Password for database authentication
|
||||||
password: openIM123
|
password: openIM123
|
||||||
|
# Authentication source for database authentication, if use root user, set it to admin
|
||||||
|
authSource: openim_v3
|
||||||
# Maximum number of connections in the connection pool
|
# Maximum number of connections in the connection pool
|
||||||
maxPoolSize: 100
|
maxPoolSize: 100
|
||||||
# Maximum number of retry attempts for a failed database connection
|
# Maximum number of retry attempts for a failed database connection
|
||||||
|
@ -1,29 +1,10 @@
|
|||||||
# Copyright © 2023 OpenIM. All rights reserved.
|
|
||||||
#
|
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
# you may not use this file except in compliance with the License.
|
|
||||||
# You may obtain a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
# See the License for the specific language governing permissions and
|
|
||||||
# limitations under the License.
|
|
||||||
|
|
||||||
# Determines if a message should be sent. If set to false, it triggers a silent sync without a message. If true, it requires triggering a conversation.
|
|
||||||
# For rpc notification, send twice: once as a message and once as a notification.
|
|
||||||
# The options field 'isNotification' indicates if it's a notification.
|
|
||||||
groupCreated:
|
groupCreated:
|
||||||
isSendMsg: true
|
isSendMsg: true
|
||||||
# Reliability level of the message sending.
|
# Deprecated. Fixed as 1.
|
||||||
# Set to 1 to send only when online, 2 for guaranteed delivery.
|
|
||||||
reliabilityLevel: 1
|
reliabilityLevel: 1
|
||||||
# This setting is effective only when 'isSendMsg' is true.
|
# Deprecated. Fixed as false.
|
||||||
# It controls whether to count unread messages.
|
|
||||||
unreadCount: false
|
unreadCount: false
|
||||||
# Configuration for offline push notifications.
|
# Configuration for offline push notifications.
|
||||||
offlinePush:
|
offlinePush:
|
||||||
# Enables or disables offline push notifications.
|
# Enables or disables offline push notifications.
|
||||||
enable: false
|
enable: false
|
||||||
@ -309,9 +290,9 @@ userInfoUpdated:
|
|||||||
unreadCount: false
|
unreadCount: false
|
||||||
offlinePush:
|
offlinePush:
|
||||||
enable: true
|
enable: true
|
||||||
title: Remove a blocked user
|
title: userInfo updated
|
||||||
desc: Remove a blocked user
|
desc: userInfo updated
|
||||||
ext: Remove a blocked user
|
ext: userInfo updated
|
||||||
|
|
||||||
userStatusChanged:
|
userStatusChanged:
|
||||||
isSendMsg: false
|
isSendMsg: false
|
||||||
|
@ -10,7 +10,10 @@ api:
|
|||||||
prometheus:
|
prometheus:
|
||||||
# Whether to enable prometheus
|
# Whether to enable prometheus
|
||||||
enable: true
|
enable: true
|
||||||
|
# autoSetPorts indicates whether to automatically set the ports
|
||||||
|
autoSetPorts: true
|
||||||
# Prometheus listening ports, must match the number of api.ports
|
# Prometheus listening ports, must match the number of api.ports
|
||||||
|
# It will only take effect when autoSetPorts is set to false.
|
||||||
ports: [ 12002 ]
|
ports: [ 12002 ]
|
||||||
# This address can be accessed via a browser
|
# This address can be accessed via a browser
|
||||||
grafanaURL: http://127.0.0.1:13000/
|
grafanaURL: http://127.0.0.1:13000/
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
cronExecuteTime: 0 2 * * *
|
cronExecuteTime: 0 2 * * *
|
||||||
retainChatRecords: 365
|
retainChatRecords: 365
|
||||||
fileExpireTime: 90
|
fileExpireTime: 180
|
||||||
|
deleteObjectType: ["msg-picture","msg-file", "msg-voice","msg-video","msg-video-snapshot","sdklog"]
|
@ -1,13 +1,17 @@
|
|||||||
rpc:
|
rpc:
|
||||||
# The IP address where this RPC service registers itself; if left blank, it defaults to the internal network IP
|
# The IP address where this RPC service registers itself; if left blank, it defaults to the internal network IP
|
||||||
registerIP:
|
registerIP:
|
||||||
|
# autoSetPorts indicates whether to automatically set the ports
|
||||||
|
autoSetPorts: true
|
||||||
# List of ports that the RPC service listens on; configuring multiple ports will launch multiple instances. These must match the number of configured prometheus ports
|
# List of ports that the RPC service listens on; configuring multiple ports will launch multiple instances. These must match the number of configured prometheus ports
|
||||||
|
# It will only take effect when autoSetPorts is set to false.
|
||||||
ports: [ 10140, 10141, 10142, 10143, 10144, 10145, 10146, 10147, 10148, 10149, 10150, 10151, 10152, 10153, 10154, 10155 ]
|
ports: [ 10140, 10141, 10142, 10143, 10144, 10145, 10146, 10147, 10148, 10149, 10150, 10151, 10152, 10153, 10154, 10155 ]
|
||||||
|
|
||||||
prometheus:
|
prometheus:
|
||||||
# Enable or disable Prometheus monitoring
|
# Enable or disable Prometheus monitoring
|
||||||
enable: true
|
enable: true
|
||||||
# List of ports that Prometheus listens on; these must match the number of rpc.ports to ensure correct monitoring setup
|
# List of ports that Prometheus listens on; these must match the number of rpc.ports to ensure correct monitoring setup
|
||||||
|
# It will only take effect when autoSetPorts is set to false.
|
||||||
ports: [ 12140, 12141, 12142, 12143, 12144, 12145, 12146, 12147, 12148, 12149, 12150, 12151, 12152, 12153, 12154, 12155 ]
|
ports: [ 12140, 12141, 12142, 12143, 12144, 12145, 12146, 12147, 12148, 12149, 12150, 12151, 12152, 12153, 12154, 12155 ]
|
||||||
|
|
||||||
# IP address that the RPC/WebSocket service listens on; setting to 0.0.0.0 listens on both internal and external IPs. If left blank, it automatically uses the internal network IP
|
# IP address that the RPC/WebSocket service listens on; setting to 0.0.0.0 listens on both internal and external IPs. If left blank, it automatically uses the internal network IP
|
||||||
@ -22,5 +26,3 @@ longConnSvr:
|
|||||||
websocketMaxMsgLen: 4096
|
websocketMaxMsgLen: 4096
|
||||||
# WebSocket connection handshake timeout in seconds
|
# WebSocket connection handshake timeout in seconds
|
||||||
websocketTimeout: 10
|
websocketTimeout: 10
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
prometheus:
|
prometheus:
|
||||||
# Enable or disable Prometheus monitoring
|
# Enable or disable Prometheus monitoring
|
||||||
enable: true
|
enable: true
|
||||||
|
# autoSetPorts indicates whether to automatically set the ports
|
||||||
|
autoSetPorts: true
|
||||||
# List of ports that Prometheus listens on; each port corresponds to an instance of monitoring. Ensure these are managed accordingly
|
# List of ports that Prometheus listens on; each port corresponds to an instance of monitoring. Ensure these are managed accordingly
|
||||||
# Because four instances have been launched, four ports need to be specified
|
# It will only take effect when autoSetPorts is set to false.
|
||||||
ports: [ 12020, 12021, 12022, 12023, 12024, 12025, 12026, 12027, 12028, 12029, 12030, 12031, 12032, 12033, 12034, 12035 ]
|
ports: [ 12020, 12021, 12022, 12023, 12024, 12025, 12026, 12027, 12028, 12029, 12030, 12031, 12032, 12033, 12034, 12035 ]
|
||||||
|
@ -3,17 +3,21 @@ rpc:
|
|||||||
registerIP:
|
registerIP:
|
||||||
# IP address that the RPC service listens on; setting to 0.0.0.0 listens on both internal and external IPs. If left blank, it automatically uses the internal network IP
|
# IP address that the RPC service listens on; setting to 0.0.0.0 listens on both internal and external IPs. If left blank, it automatically uses the internal network IP
|
||||||
listenIP: 0.0.0.0
|
listenIP: 0.0.0.0
|
||||||
|
# autoSetPorts indicates whether to automatically set the ports
|
||||||
|
autoSetPorts: true
|
||||||
# List of ports that the RPC service listens on; configuring multiple ports will launch multiple instances. These must match the number of configured prometheus ports
|
# List of ports that the RPC service listens on; configuring multiple ports will launch multiple instances. These must match the number of configured prometheus ports
|
||||||
|
# It will only take effect when autoSetPorts is set to false.
|
||||||
ports: [ 10170, 10171, 10172, 10173, 10174, 10175, 10176, 10177, 10178, 10179, 10180, 10181, 10182, 10183, 10184, 10185 ]
|
ports: [ 10170, 10171, 10172, 10173, 10174, 10175, 10176, 10177, 10178, 10179, 10180, 10181, 10182, 10183, 10184, 10185 ]
|
||||||
|
|
||||||
prometheus:
|
prometheus:
|
||||||
# Enable or disable Prometheus monitoring
|
# Enable or disable Prometheus monitoring
|
||||||
enable: true
|
enable: true
|
||||||
# List of ports that Prometheus listens on; these must match the number of rpc.ports to ensure correct monitoring setup
|
# List of ports that Prometheus listens on; these must match the number of rpc.ports to ensure correct monitoring setup
|
||||||
|
# It will only take effect when autoSetPorts is set to false.
|
||||||
ports: [ 12170, 12171, 12172, 12173, 12174, 12175, 12176, 12177, 12178, 12179, 12180, 12182, 12183, 12184, 12185, 12186 ]
|
ports: [ 12170, 12171, 12172, 12173, 12174, 12175, 12176, 12177, 12178, 12179, 12180, 12182, 12183, 12184, 12185, 12186 ]
|
||||||
|
|
||||||
maxConcurrentWorkers: 3
|
maxConcurrentWorkers: 3
|
||||||
#Use geTui for offline push notifications, or choose fcm or jpns; corresponding configuration settings must be specified.
|
#Use geTui for offline push notifications, or choose fcm or jpush; corresponding configuration settings must be specified.
|
||||||
enable: geTui
|
enable: geTui
|
||||||
geTui:
|
geTui:
|
||||||
pushUrl: https://restapi.getui.com/v2/$appId
|
pushUrl: https://restapi.getui.com/v2/$appId
|
||||||
@ -26,7 +30,7 @@ fcm:
|
|||||||
# Prioritize using file paths. If the file path is empty, use URL
|
# Prioritize using file paths. If the file path is empty, use URL
|
||||||
filePath: # File path is concatenated with the parameters passed in through - c(`mage` default pass in `config/`) and filePath.
|
filePath: # File path is concatenated with the parameters passed in through - c(`mage` default pass in `config/`) and filePath.
|
||||||
authURL: # Must start with https or http.
|
authURL: # Must start with https or http.
|
||||||
jpns:
|
jpush:
|
||||||
appKey:
|
appKey:
|
||||||
masterSecret:
|
masterSecret:
|
||||||
pushURL:
|
pushURL:
|
||||||
@ -34,8 +38,8 @@ jpns:
|
|||||||
|
|
||||||
# iOS system push sound and badge count
|
# iOS system push sound and badge count
|
||||||
iosPush:
|
iosPush:
|
||||||
pushSound: xxx
|
pushSound: xxx
|
||||||
badgeCount: true
|
badgeCount: true
|
||||||
production: false
|
production: false
|
||||||
|
|
||||||
fullUserCache: true
|
fullUserCache: true
|
||||||
|
@ -3,13 +3,17 @@ rpc:
|
|||||||
registerIP:
|
registerIP:
|
||||||
# IP address that the RPC service listens on; setting to 0.0.0.0 listens on both internal and external IPs. If left blank, it automatically uses the internal network IP
|
# IP address that the RPC service listens on; setting to 0.0.0.0 listens on both internal and external IPs. If left blank, it automatically uses the internal network IP
|
||||||
listenIP: 0.0.0.0
|
listenIP: 0.0.0.0
|
||||||
|
# autoSetPorts indicates whether to automatically set the ports
|
||||||
|
autoSetPorts: true
|
||||||
# List of ports that the RPC service listens on; configuring multiple ports will launch multiple instances. These must match the number of configured prometheus ports
|
# List of ports that the RPC service listens on; configuring multiple ports will launch multiple instances. These must match the number of configured prometheus ports
|
||||||
|
# It will only take effect when autoSetPorts is set to false.
|
||||||
ports: [ 10200 ]
|
ports: [ 10200 ]
|
||||||
|
|
||||||
prometheus:
|
prometheus:
|
||||||
# Enable or disable Prometheus monitoring
|
# Enable or disable Prometheus monitoring
|
||||||
enable: true
|
enable: true
|
||||||
# List of ports that Prometheus listens on; these must match the number of rpc.ports to ensure correct monitoring setup
|
# List of ports that Prometheus listens on; these must match the number of rpc.ports to ensure correct monitoring setup
|
||||||
|
# It will only take effect when autoSetPorts is set to false.
|
||||||
ports: [ 12200 ]
|
ports: [ 12200 ]
|
||||||
|
|
||||||
tokenPolicy:
|
tokenPolicy:
|
||||||
|
@ -3,11 +3,15 @@ rpc:
|
|||||||
registerIP:
|
registerIP:
|
||||||
# IP address that the RPC service listens on; setting to 0.0.0.0 listens on both internal and external IPs. If left blank, it automatically uses the internal network IP
|
# IP address that the RPC service listens on; setting to 0.0.0.0 listens on both internal and external IPs. If left blank, it automatically uses the internal network IP
|
||||||
listenIP: 0.0.0.0
|
listenIP: 0.0.0.0
|
||||||
|
# autoSetPorts indicates whether to automatically set the ports
|
||||||
|
autoSetPorts: true
|
||||||
# List of ports that the RPC service listens on; configuring multiple ports will launch multiple instances. These must match the number of configured prometheus ports
|
# List of ports that the RPC service listens on; configuring multiple ports will launch multiple instances. These must match the number of configured prometheus ports
|
||||||
|
# It will only take effect when autoSetPorts is set to false.
|
||||||
ports: [ 10220 ]
|
ports: [ 10220 ]
|
||||||
|
|
||||||
prometheus:
|
prometheus:
|
||||||
# Enable or disable Prometheus monitoring
|
# Enable or disable Prometheus monitoring
|
||||||
enable: true
|
enable: true
|
||||||
# List of ports that Prometheus listens on; these must match the number of rpc.ports to ensure correct monitoring setup
|
# List of ports that Prometheus listens on; these must match the number of rpc.ports to ensure correct monitoring setup
|
||||||
|
# It will only take effect when autoSetPorts is set to false.
|
||||||
ports: [ 12220 ]
|
ports: [ 12220 ]
|
||||||
|
@ -3,11 +3,15 @@ rpc:
|
|||||||
registerIP:
|
registerIP:
|
||||||
# IP address that the RPC service listens on; setting to 0.0.0.0 listens on both internal and external IPs. If left blank, it automatically uses the internal network IP
|
# IP address that the RPC service listens on; setting to 0.0.0.0 listens on both internal and external IPs. If left blank, it automatically uses the internal network IP
|
||||||
listenIP: 0.0.0.0
|
listenIP: 0.0.0.0
|
||||||
|
# autoSetPorts indicates whether to automatically set the ports
|
||||||
|
autoSetPorts: true
|
||||||
# List of ports that the RPC service listens on; configuring multiple ports will launch multiple instances. These must match the number of configured prometheus ports
|
# List of ports that the RPC service listens on; configuring multiple ports will launch multiple instances. These must match the number of configured prometheus ports
|
||||||
|
# It will only take effect when autoSetPorts is set to false.
|
||||||
ports: [ 10240 ]
|
ports: [ 10240 ]
|
||||||
|
|
||||||
prometheus:
|
prometheus:
|
||||||
# Enable or disable Prometheus monitoring
|
# Enable or disable Prometheus monitoring
|
||||||
enable: true
|
enable: true
|
||||||
# List of ports that Prometheus listens on; these must match the number of rpc.ports to ensure correct monitoring setup
|
# List of ports that Prometheus listens on; these must match the number of rpc.ports to ensure correct monitoring setup
|
||||||
|
# It will only take effect when autoSetPorts is set to false.
|
||||||
ports: [ 12240 ]
|
ports: [ 12240 ]
|
||||||
|
@ -3,13 +3,17 @@ rpc:
|
|||||||
registerIP:
|
registerIP:
|
||||||
# IP address that the RPC service listens on; setting to 0.0.0.0 listens on both internal and external IPs. If left blank, it automatically uses the internal network IP
|
# IP address that the RPC service listens on; setting to 0.0.0.0 listens on both internal and external IPs. If left blank, it automatically uses the internal network IP
|
||||||
listenIP: 0.0.0.0
|
listenIP: 0.0.0.0
|
||||||
|
# autoSetPorts indicates whether to automatically set the ports
|
||||||
|
autoSetPorts: true
|
||||||
# List of ports that the RPC service listens on; configuring multiple ports will launch multiple instances. These must match the number of configured prometheus ports
|
# List of ports that the RPC service listens on; configuring multiple ports will launch multiple instances. These must match the number of configured prometheus ports
|
||||||
|
# It will only take effect when autoSetPorts is set to false.
|
||||||
ports: [ 10260 ]
|
ports: [ 10260 ]
|
||||||
|
|
||||||
prometheus:
|
prometheus:
|
||||||
# Enable or disable Prometheus monitoring
|
# Enable or disable Prometheus monitoring
|
||||||
enable: true
|
enable: true
|
||||||
# List of ports that Prometheus listens on; these must match the number of rpc.ports to ensure correct monitoring setup
|
# List of ports that Prometheus listens on; these must match the number of rpc.ports to ensure correct monitoring setup
|
||||||
|
# It will only take effect when autoSetPorts is set to false.
|
||||||
ports: [ 12260 ]
|
ports: [ 12260 ]
|
||||||
|
|
||||||
|
|
||||||
|
@ -3,13 +3,17 @@ rpc:
|
|||||||
registerIP:
|
registerIP:
|
||||||
# IP address that the RPC service listens on; setting to 0.0.0.0 listens on both internal and external IPs. If left blank, it automatically uses the internal network IP
|
# IP address that the RPC service listens on; setting to 0.0.0.0 listens on both internal and external IPs. If left blank, it automatically uses the internal network IP
|
||||||
listenIP: 0.0.0.0
|
listenIP: 0.0.0.0
|
||||||
|
# autoSetPorts indicates whether to automatically set the ports
|
||||||
|
autoSetPorts: true
|
||||||
# List of ports that the RPC service listens on; configuring multiple ports will launch multiple instances. These must match the number of configured prometheus ports
|
# List of ports that the RPC service listens on; configuring multiple ports will launch multiple instances. These must match the number of configured prometheus ports
|
||||||
|
# It will only take effect when autoSetPorts is set to false.
|
||||||
ports: [ 10280 ]
|
ports: [ 10280 ]
|
||||||
|
|
||||||
prometheus:
|
prometheus:
|
||||||
# Enable or disable Prometheus monitoring
|
# Enable or disable Prometheus monitoring
|
||||||
enable: true
|
enable: true
|
||||||
# List of ports that Prometheus listens on; these must match the number of rpc.ports to ensure correct monitoring setup
|
# List of ports that Prometheus listens on; these must match the number of rpc.ports to ensure correct monitoring setup
|
||||||
|
# It will only take effect when autoSetPorts is set to false.
|
||||||
ports: [ 12280 ]
|
ports: [ 12280 ]
|
||||||
|
|
||||||
|
|
||||||
|
@ -3,13 +3,17 @@ rpc:
|
|||||||
registerIP:
|
registerIP:
|
||||||
# IP address that the RPC service listens on; setting to 0.0.0.0 listens on both internal and external IPs. If left blank, it automatically uses the internal network IP
|
# IP address that the RPC service listens on; setting to 0.0.0.0 listens on both internal and external IPs. If left blank, it automatically uses the internal network IP
|
||||||
listenIP: 0.0.0.0
|
listenIP: 0.0.0.0
|
||||||
|
# autoSetPorts indicates whether to automatically set the ports
|
||||||
|
autoSetPorts: true
|
||||||
# List of ports that the RPC service listens on; configuring multiple ports will launch multiple instances. These must match the number of configured prometheus ports
|
# List of ports that the RPC service listens on; configuring multiple ports will launch multiple instances. These must match the number of configured prometheus ports
|
||||||
|
# It will only take effect when autoSetPorts is set to false.
|
||||||
ports: [ 10300 ]
|
ports: [ 10300 ]
|
||||||
|
|
||||||
prometheus:
|
prometheus:
|
||||||
# Enable or disable Prometheus monitoring
|
# Enable or disable Prometheus monitoring
|
||||||
enable: true
|
enable: true
|
||||||
# List of ports that Prometheus listens on; these must match the number of rpc.ports to ensure correct monitoring setup
|
# List of ports that Prometheus listens on; these must match the number of rpc.ports to ensure correct monitoring setup
|
||||||
|
# It will only take effect when autoSetPorts is set to false.
|
||||||
ports: [ 12300 ]
|
ports: [ 12300 ]
|
||||||
|
|
||||||
|
|
||||||
@ -38,3 +42,10 @@ object:
|
|||||||
accessKeySecret:
|
accessKeySecret:
|
||||||
sessionToken:
|
sessionToken:
|
||||||
publicRead: false
|
publicRead: false
|
||||||
|
aws:
|
||||||
|
region: ap-southeast-2
|
||||||
|
bucket: testdemo832234
|
||||||
|
accessKeyID:
|
||||||
|
secretAccessKey:
|
||||||
|
sessionToken:
|
||||||
|
publicRead: false
|
||||||
|
@ -3,11 +3,15 @@ rpc:
|
|||||||
registerIP:
|
registerIP:
|
||||||
# Listening IP; 0.0.0.0 means both internal and external IPs are listened to, if blank, the internal network IP is automatically obtained by default
|
# Listening IP; 0.0.0.0 means both internal and external IPs are listened to, if blank, the internal network IP is automatically obtained by default
|
||||||
listenIP: 0.0.0.0
|
listenIP: 0.0.0.0
|
||||||
# Listening ports; if multiple are configured, multiple instances will be launched, and must be consistent with the number of prometheus.ports
|
# autoSetPorts indicates whether to automatically set the ports
|
||||||
|
autoSetPorts: true
|
||||||
|
# List of ports that the RPC service listens on; configuring multiple ports will launch multiple instances. These must match the number of configured prometheus ports
|
||||||
|
# It will only take effect when autoSetPorts is set to false.
|
||||||
ports: [ 10320 ]
|
ports: [ 10320 ]
|
||||||
|
|
||||||
prometheus:
|
prometheus:
|
||||||
# Whether to enable prometheus
|
# Whether to enable prometheus
|
||||||
enable: true
|
enable: true
|
||||||
# Prometheus listening ports, must be consistent with the number of rpc.ports
|
# Prometheus listening ports, must be consistent with the number of rpc.ports
|
||||||
|
# It will only take effect when autoSetPorts is set to false.
|
||||||
ports: [ 12320 ]
|
ports: [ 12320 ]
|
||||||
|
@ -8,7 +8,7 @@ global:
|
|||||||
alerting:
|
alerting:
|
||||||
alertmanagers:
|
alertmanagers:
|
||||||
- static_configs:
|
- static_configs:
|
||||||
- targets: [internal_ip:19093]
|
- targets: [127.0.0.1:19093]
|
||||||
|
|
||||||
# Load rules once and periodically evaluate them according to the global evaluation_interval.
|
# Load rules once and periodically evaluate them according to the global evaluation_interval.
|
||||||
rule_files:
|
rule_files:
|
||||||
@ -25,62 +25,95 @@ scrape_configs:
|
|||||||
# prometheus fetches application services
|
# prometheus fetches application services
|
||||||
- job_name: node_exporter
|
- job_name: node_exporter
|
||||||
static_configs:
|
static_configs:
|
||||||
- targets: [ internal_ip:20500 ]
|
- targets: [ 127.0.0.1:19100 ]
|
||||||
|
|
||||||
- job_name: openimserver-openim-api
|
- job_name: openimserver-openim-api
|
||||||
static_configs:
|
http_sd_configs:
|
||||||
- targets: [ internal_ip:12002 ]
|
- url: "http://127.0.0.1:10002/prometheus_discovery/api"
|
||||||
labels:
|
# static_configs:
|
||||||
namespace: default
|
# - targets: [ 127.0.0.1:12002 ]
|
||||||
|
# labels:
|
||||||
|
# namespace: default
|
||||||
|
|
||||||
- job_name: openimserver-openim-msggateway
|
- job_name: openimserver-openim-msggateway
|
||||||
static_configs:
|
http_sd_configs:
|
||||||
- targets: [ internal_ip:12140 ]
|
- url: "http://127.0.0.1:10002/prometheus_discovery/msg_gateway"
|
||||||
# - targets: [ internal_ip:12140, internal_ip:12141, internal_ip:12142, internal_ip:12143, internal_ip:12144, internal_ip:12145, internal_ip:12146, internal_ip:12147, internal_ip:12148, internal_ip:12149, internal_ip:12150, internal_ip:12151, internal_ip:12152, internal_ip:12153, internal_ip:12154, internal_ip:12155 ]
|
# static_configs:
|
||||||
labels:
|
# - targets: [ 127.0.0.1:12140 ]
|
||||||
namespace: default
|
# # - targets: [ 127.0.0.1:12140, 127.0.0.1:12141, 127.0.0.1:12142, 127.0.0.1:12143, 127.0.0.1:12144, 127.0.0.1:12145, 127.0.0.1:12146, 127.0.0.1:12147, 127.0.0.1:12148, 127.0.0.1:12149, 127.0.0.1:12150, 127.0.0.1:12151, 127.0.0.1:12152, 127.0.0.1:12153, 127.0.0.1:12154, 127.0.0.1:12155 ]
|
||||||
|
# labels:
|
||||||
|
# namespace: default
|
||||||
|
|
||||||
- job_name: openimserver-openim-msgtransfer
|
- job_name: openimserver-openim-msgtransfer
|
||||||
static_configs:
|
http_sd_configs:
|
||||||
- targets: [ internal_ip:12020, internal_ip:12021, internal_ip:12022, internal_ip:12023, internal_ip:12024, internal_ip:12025, internal_ip:12026, internal_ip:12027 ]
|
- url: "http://127.0.0.1:10002/prometheus_discovery/msg_transfer"
|
||||||
# - targets: [ internal_ip:12020, internal_ip:12021, internal_ip:12022, internal_ip:12023, internal_ip:12024, internal_ip:12025, internal_ip:12026, internal_ip:12027, internal_ip:12028, internal_ip:12029, internal_ip:12030, internal_ip:12031, internal_ip:12032, internal_ip:12033, internal_ip:12034, internal_ip:12035 ]
|
# static_configs:
|
||||||
labels:
|
# - targets: [ 127.0.0.1:12020, 127.0.0.1:12021, 127.0.0.1:12022, 127.0.0.1:12023, 127.0.0.1:12024, 127.0.0.1:12025, 127.0.0.1:12026, 127.0.0.1:12027 ]
|
||||||
namespace: default
|
# # - targets: [ 127.0.0.1:12020, 127.0.0.1:12021, 127.0.0.1:12022, 127.0.0.1:12023, 127.0.0.1:12024, 127.0.0.1:12025, 127.0.0.1:12026, 127.0.0.1:12027, 127.0.0.1:12028, 127.0.0.1:12029, 127.0.0.1:12030, 127.0.0.1:12031, 127.0.0.1:12032, 127.0.0.1:12033, 127.0.0.1:12034, 127.0.0.1:12035 ]
|
||||||
|
# labels:
|
||||||
|
# namespace: default
|
||||||
|
|
||||||
- job_name: openimserver-openim-push
|
- job_name: openimserver-openim-push
|
||||||
static_configs:
|
http_sd_configs:
|
||||||
- targets: [ internal_ip:12170, internal_ip:12171, internal_ip:12172, internal_ip:12173, internal_ip:12174, internal_ip:12175, internal_ip:12176, internal_ip:12177 ]
|
- url: "http://127.0.0.1:10002/prometheus_discovery/push"
|
||||||
# - targets: [ internal_ip:12170, internal_ip:12171, internal_ip:12172, internal_ip:12173, internal_ip:12174, internal_ip:12175, internal_ip:12176, internal_ip:12177, internal_ip:12178, internal_ip:12179, internal_ip:12180, internal_ip:12182, internal_ip:12183, internal_ip:12184, internal_ip:12185, internal_ip:12186 ]
|
# static_configs:
|
||||||
labels:
|
# - targets: [ 127.0.0.1:12170, 127.0.0.1:12171, 127.0.0.1:12172, 127.0.0.1:12173, 127.0.0.1:12174, 127.0.0.1:12175, 127.0.0.1:12176, 127.0.0.1:12177 ]
|
||||||
namespace: default
|
## - targets: [ 127.0.0.1:12170, 127.0.0.1:12171, 127.0.0.1:12172, 127.0.0.1:12173, 127.0.0.1:12174, 127.0.0.1:12175, 127.0.0.1:12176, 127.0.0.1:12177, 127.0.0.1:12178, 127.0.0.1:12179, 127.0.0.1:12180, 127.0.0.1:12182, 127.0.0.1:12183, 127.0.0.1:12184, 127.0.0.1:12185, 127.0.0.1:12186 ]
|
||||||
|
# labels:
|
||||||
|
# namespace: default
|
||||||
|
|
||||||
- job_name: openimserver-openim-rpc-auth
|
- job_name: openimserver-openim-rpc-auth
|
||||||
static_configs:
|
http_sd_configs:
|
||||||
- targets: [ internal_ip:12200 ]
|
- url: "http://127.0.0.1:10002/prometheus_discovery/auth"
|
||||||
labels:
|
# static_configs:
|
||||||
namespace: default
|
# - targets: [ 127.0.0.1:12200 ]
|
||||||
|
# labels:
|
||||||
|
# namespace: default
|
||||||
|
|
||||||
- job_name: openimserver-openim-rpc-conversation
|
- job_name: openimserver-openim-rpc-conversation
|
||||||
static_configs:
|
http_sd_configs:
|
||||||
- targets: [ internal_ip:12220 ]
|
- url: "http://127.0.0.1:10002/prometheus_discovery/conversation"
|
||||||
labels:
|
# static_configs:
|
||||||
namespace: default
|
# - targets: [ 127.0.0.1:12220 ]
|
||||||
|
# labels:
|
||||||
|
# namespace: default
|
||||||
|
|
||||||
- job_name: openimserver-openim-rpc-friend
|
- job_name: openimserver-openim-rpc-friend
|
||||||
static_configs:
|
http_sd_configs:
|
||||||
- targets: [ internal_ip:12240 ]
|
- url: "http://127.0.0.1:10002/prometheus_discovery/friend"
|
||||||
labels:
|
# static_configs:
|
||||||
namespace: default
|
# - targets: [ 127.0.0.1:12240 ]
|
||||||
|
# labels:
|
||||||
|
# namespace: default
|
||||||
|
|
||||||
- job_name: openimserver-openim-rpc-group
|
- job_name: openimserver-openim-rpc-group
|
||||||
static_configs:
|
http_sd_configs:
|
||||||
- targets: [ internal_ip:12260 ]
|
- url: "http://127.0.0.1:10002/prometheus_discovery/group"
|
||||||
labels:
|
# static_configs:
|
||||||
namespace: default
|
# - targets: [ 127.0.0.1:12260 ]
|
||||||
|
# labels:
|
||||||
|
# namespace: default.
|
||||||
|
|
||||||
- job_name: openimserver-openim-rpc-msg
|
- job_name: openimserver-openim-rpc-msg
|
||||||
static_configs:
|
http_sd_configs:
|
||||||
- targets: [ internal_ip:12280 ]
|
- url: "http://127.0.0.1:10002/prometheus_discovery/msg"
|
||||||
labels:
|
# static_configs:
|
||||||
namespace: default
|
# - targets: [ 127.0.0.1:12280 ]
|
||||||
|
# labels:
|
||||||
|
# namespace: default
|
||||||
|
|
||||||
- job_name: openimserver-openim-rpc-third
|
- job_name: openimserver-openim-rpc-third
|
||||||
static_configs:
|
http_sd_configs:
|
||||||
- targets: [ internal_ip:12300 ]
|
- url: "http://127.0.0.1:10002/prometheus_discovery/third"
|
||||||
labels:
|
# static_configs:
|
||||||
namespace: default
|
# - targets: [ 127.0.0.1:12300 ]
|
||||||
|
# labels:
|
||||||
|
# namespace: default
|
||||||
|
|
||||||
- job_name: openimserver-openim-rpc-user
|
- job_name: openimserver-openim-rpc-user
|
||||||
static_configs:
|
http_sd_configs:
|
||||||
- targets: [ internal_ip:12320 ]
|
- url: "http://127.0.0.1:10002/prometheus_discovery/user"
|
||||||
labels:
|
# static_configs:
|
||||||
namespace: default
|
# - targets: [ 127.0.0.1:12320 ]
|
||||||
|
# labels:
|
||||||
|
# namespace: default
|
@ -1,16 +1,9 @@
|
|||||||
secret: openIM123
|
secret: openIM123
|
||||||
rpcRegisterName:
|
|
||||||
user: user
|
|
||||||
friend: friend
|
|
||||||
msg: msg
|
|
||||||
push: push
|
|
||||||
messageGateway: messageGateway
|
|
||||||
group: group
|
|
||||||
auth: auth
|
|
||||||
conversation: conversation
|
|
||||||
third: third
|
|
||||||
|
|
||||||
imAdminUserID: [ imAdmin ]
|
imAdminUserID: [ imAdmin ]
|
||||||
|
|
||||||
# 1: For Android, iOS, Windows, Mac, and web platforms, only one instance can be online at a time
|
# 1: For Android, iOS, Windows, Mac, and web platforms, only one instance can be online at a time
|
||||||
multiLoginPolicy: 1
|
multiLogin:
|
||||||
|
policy: 1
|
||||||
|
# max num of tokens in one end
|
||||||
|
maxNumOneEnd: 30
|
@ -1,175 +1,188 @@
|
|||||||
# OpenIM Application Containerization Deployment Guide
|
# Kubernetes Deployment
|
||||||
|
|
||||||
OpenIM supports a variety of cluster deployment methods, including but not limited to `helm`, `sealos`, `kustomize`
|
## Resource Requests
|
||||||
|
|
||||||
Various contributors, as well as previous official releases, have provided some referenceable solutions:
|
- CPU: 2 cores
|
||||||
|
- Memory: 4 GiB
|
||||||
|
- Disk usage: 20 GiB (on Node)
|
||||||
|
|
||||||
+ [k8s-jenkins Repository](https://github.com/OpenIMSDK/k8s-jenkins)
|
## Preconditions
|
||||||
+ [open-im-server-k8s-deploy Repository](https://github.com/openimsdk/open-im-server-k8s-deploy)
|
|
||||||
+ [openim-charts Repository](https://github.com/OpenIMSDK/openim-charts)
|
|
||||||
+ [deploy-openim Repository](https://github.com/showurl/deploy-openim)
|
|
||||||
|
|
||||||
### Dependency Check
|
ensure that you have already deployed the following components:
|
||||||
|
|
||||||
```bash
|
- Redis
|
||||||
Kubernetes: >= 1.16.0-0
|
- MongoDB
|
||||||
Helm: >= 3.0
|
- Kafka
|
||||||
```
|
- MinIO
|
||||||
|
|
||||||
### Minimum Configuration
|
## Origin Deploy
|
||||||
|
|
||||||
The recommended minimum configuration for a production environment is as follows:
|
### Enter the target dir
|
||||||
|
|
||||||
|
`cd ./deployments/deploy/`
|
||||||
|
|
||||||
|
### Deploy configs and dependencies
|
||||||
|
|
||||||
|
Upate your configMap `openim-config.yml`. **You can check the official docs for more details.**
|
||||||
|
|
||||||
|
In `openim-config.yml`, you need modify the following configurations:
|
||||||
|
|
||||||
|
**discovery.yml**
|
||||||
|
|
||||||
|
- `kubernetes.namespace`: default is `default`, you can change it to your namespace.
|
||||||
|
|
||||||
|
**mongodb.yml**
|
||||||
|
|
||||||
|
- `address`: set to your already mongodb address or mongo Service name and port in your deployed.
|
||||||
|
- `database`: set to your mongodb database name.(Need have a created database.)
|
||||||
|
- `authSource`: set to your mongodb authSource. (authSource is specify the database name associated with the user's credentials, user need create in this database.)
|
||||||
|
|
||||||
|
**kafka.yml**
|
||||||
|
|
||||||
|
- `address`: set to your already kafka address or kafka Service name and port in your deployed.
|
||||||
|
|
||||||
|
**redis.yml**
|
||||||
|
|
||||||
|
- `address`: set to your already redis address or redis Service name and port in your deployed.
|
||||||
|
|
||||||
|
**minio.yml**
|
||||||
|
|
||||||
|
- `internalAddress`: set to your minio Service name and port in your deployed.
|
||||||
|
- `externalAddress`: set to your already expose minio external address.
|
||||||
|
|
||||||
|
### Set the secret
|
||||||
|
|
||||||
|
A Secret is an object that contains a small amount of sensitive data. Such as password and secret. Secret is similar to ConfigMaps.
|
||||||
|
|
||||||
|
#### Redis:
|
||||||
|
|
||||||
|
Update the `redis-password` value in `redis-secret.yml` to your Redis password encoded in base64.
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
CPU: 4
|
apiVersion: v1
|
||||||
Memory: 8G
|
kind: Secret
|
||||||
Disk: 100G
|
metadata:
|
||||||
|
name: openim-redis-secret
|
||||||
|
type: Opaque
|
||||||
|
data:
|
||||||
|
redis-password: b3BlbklNMTIz # update to your redis password encoded in base64, if need empty, you can set to ""
|
||||||
```
|
```
|
||||||
|
|
||||||
## Configuration File Generation
|
#### Mongo:
|
||||||
|
|
||||||
We have automated all the files, making the generation of configuration files optional for OpenIM. However, if you desire custom configurations, you can follow the steps below:
|
Update the `mongo_openim_username`, `mongo_openim_password` value in `mongo-secret.yml` to your Mongo username and password encoded in base64.
|
||||||
|
|
||||||
```bash
|
```yaml
|
||||||
$ make init
|
apiVersion: v1
|
||||||
# Alternatively, use script:
|
kind: Secret
|
||||||
# ./scripts/init-config.sh
|
metadata:
|
||||||
|
name: openim-mongo-secret
|
||||||
|
type: Opaque
|
||||||
|
data:
|
||||||
|
mongo_openim_username: b3BlbklN # update to your mongo username encoded in base64, if need empty, you can set to "" (this user credentials need in authSource database).
|
||||||
|
mongo_openim_password: b3BlbklNMTIz # update to your mongo password encoded in base64, if need empty, you can set to ""
|
||||||
```
|
```
|
||||||
|
|
||||||
At this point, configuration files will be generated under `deployments/openim/config`, which you can modify as per your requirements.
|
#### Minio:
|
||||||
|
|
||||||
## Cluster Setup
|
Update the `minio-root-user` and `minio-root-password` value in `minio-secret.yml` to your MinIO accessKeyID and secretAccessKey encoded in base64.
|
||||||
|
|
||||||
If you already have a `kubernetes` cluster, or if you wish to build a `kubernetes` cluster from scratch, you can skip this step.
|
```yaml
|
||||||
|
apiVersion: v1
|
||||||
For a quick start, I used [sealos](https://github.com/labring/sealos) to rapidly set up the cluster, with sealos also being a wrapper for kubeadm at its core:
|
kind: Secret
|
||||||
|
metadata:
|
||||||
```bash
|
name: openim-minio-secret
|
||||||
$ SEALOS_VERSION=`curl -s https://api.github.com/repos/labring/sealos/releases/latest | grep -oE '"tag_name": "[^"]+"' | head -n1 | cut -d'"' -f4` && \
|
type: Opaque
|
||||||
curl -sfL https://raw.githubusercontent.com/labring/sealos/${SEALOS_VERSION}/scripts/install.sh |
|
data:
|
||||||
sh -s ${SEALOS_VERSION} labring/sealos
|
minio-root-user: cm9vdA== # update to your minio accessKeyID encoded in base64, if need empty, you can set to ""
|
||||||
|
minio-root-password: b3BlbklNMTIz # update to your minio secretAccessKey encoded in base64, if need empty, you can set to ""
|
||||||
```
|
```
|
||||||
|
|
||||||
**Supported Versions:**
|
#### Kafka:
|
||||||
|
|
||||||
+ docker: `labring/kubernetes-docker`:(v1.24.0~v1.27.0)
|
Update the `kafka-password` value in `kafka-secret.yml` to your Kafka password encoded in base64.
|
||||||
+ containerd: `labring/kubernetes`:(v1.24.0~v1.27.0)
|
|
||||||
|
|
||||||
#### Cluster Installation:
|
```yaml
|
||||||
|
apiVersion: v1
|
||||||
Cluster details are as follows:
|
kind: Secret
|
||||||
|
metadata:
|
||||||
| Hostname | IP Address | System Info |
|
name: openim-kafka-secret
|
||||||
| -------- | ---------- | ------------------------------------------------------------ |
|
type: Opaque
|
||||||
| master01 | 10.0.0.9 | `Linux VM-0-9-ubuntu 5.15.0-76-generic #83-Ubuntu SMP Thu Jun 15 19:16:32 UTC 2023 x86_64 x86_64 x86_64 GNU/Linux` |
|
data:
|
||||||
| node01 | 10.0.0.4 | Similar to master01 |
|
kafka-password: b3BlbklNMTIz # update to your kafka password encoded in base64, if need empty, you can set to ""
|
||||||
| node02 | 10.0.0.10 | Similar to master01 |
|
|
||||||
|
|
||||||
```bash
|
|
||||||
$ export CLUSTER_USERNAME=ubuntu
|
|
||||||
$ export CLUSTER_PASSWORD=123456
|
|
||||||
$ sudo sealos run labring/kubernetes:v1.25.0 labring/helm:v3.8.2 labring/calico:v3.24.1 \
|
|
||||||
--masters 10.0.0.9 \
|
|
||||||
--nodes 10.0.0.4,10.0.0.10 \
|
|
||||||
-u "$CLUSTER_USERNAME" \
|
|
||||||
-p "$CLUSTER_PASSWORD"
|
|
||||||
```
|
```
|
||||||
|
|
||||||
> **Node** Uninstallation method: using `kubeadm` for uninstallation does not remove `etcd` and `cni` related configurations. Manual clearance or using `sealos` for uninstallation is needed.
|
### Apply the secret.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
kubectl apply -f redis-secret.yml -f minio-secret.yml -f mongo-secret.yml -f kafka-secret.yml
|
||||||
|
```
|
||||||
|
|
||||||
|
### Apply all config
|
||||||
|
|
||||||
|
`kubectl apply -f ./openim-config.yml`
|
||||||
|
|
||||||
|
> Attation: If you use `default` namespace, you can excute `clusterRile.yml` to create a cluster role binding for default service account.
|
||||||
>
|
>
|
||||||
> ```bash
|
> Namespace is modify to `discovery.yml` in `openim-config.yml`, you can change `kubernetes.namespace` to your namespace.
|
||||||
> $ sealos reset
|
|
||||||
> ```
|
|
||||||
|
|
||||||
If you are local, you can also use Kind and Minikube to test, for example, using Kind:
|
**Excute `clusterRole.yml`**
|
||||||
|
|
||||||
|
`kubectl apply -f ./clusterRole.yml`
|
||||||
|
|
||||||
|
### run all deployments and services
|
||||||
|
|
||||||
|
> Note: Ensure that infrastructure services like MinIO, Redis, and Kafka are running before deploying the main applications.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
$ GO111MODULE="on" go get sigs.k8s.io/kind@v0.11.1
|
kubectl apply \
|
||||||
$ kind create cluster
|
-f openim-api-deployment.yml \
|
||||||
|
-f openim-api-service.yml \
|
||||||
|
-f openim-crontask-deployment.yml \
|
||||||
|
-f openim-rpc-user-deployment.yml \
|
||||||
|
-f openim-rpc-user-service.yml \
|
||||||
|
-f openim-msggateway-deployment.yml \
|
||||||
|
-f openim-msggateway-service.yml \
|
||||||
|
-f openim-push-deployment.yml \
|
||||||
|
-f openim-push-service.yml \
|
||||||
|
-f openim-msgtransfer-service.yml \
|
||||||
|
-f openim-msgtransfer-deployment.yml \
|
||||||
|
-f openim-rpc-conversation-deployment.yml \
|
||||||
|
-f openim-rpc-conversation-service.yml \
|
||||||
|
-f openim-rpc-auth-deployment.yml \
|
||||||
|
-f openim-rpc-auth-service.yml \
|
||||||
|
-f openim-rpc-group-deployment.yml \
|
||||||
|
-f openim-rpc-group-service.yml \
|
||||||
|
-f openim-rpc-friend-deployment.yml \
|
||||||
|
-f openim-rpc-friend-service.yml \
|
||||||
|
-f openim-rpc-msg-deployment.yml \
|
||||||
|
-f openim-rpc-msg-service.yml \
|
||||||
|
-f openim-rpc-third-deployment.yml \
|
||||||
|
-f openim-rpc-third-service.yml
|
||||||
```
|
```
|
||||||
|
|
||||||
### Installing helm
|
### Verification
|
||||||
|
|
||||||
Helm simplifies the deployment and management of Kubernetes applications to a large extent by offering version control and release management through packaging.
|
After deploying the services, verify that everything is running smoothly:
|
||||||
|
|
||||||
**Using Script:**
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
$ curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
|
# Check the status of all pods
|
||||||
|
kubectl get pods
|
||||||
|
|
||||||
|
# Check the status of services
|
||||||
|
kubectl get svc
|
||||||
|
|
||||||
|
# Check the status of deployments
|
||||||
|
kubectl get deployments
|
||||||
|
|
||||||
|
# View all resources
|
||||||
|
kubectl get all
|
||||||
```
|
```
|
||||||
|
|
||||||
**Adding Repository:**
|
### clean all
|
||||||
|
|
||||||
```bash
|
`kubectl delete -f ./`
|
||||||
$ helm repo add brigade https://openimsdk.github.io/openim-charts
|
|
||||||
```
|
|
||||||
|
|
||||||
### OpenIM Image Strategy
|
### Notes:
|
||||||
|
|
||||||
Automated offerings include aliyun, ghcr, docker hub: [Image Documentation](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/images.md)
|
- If you use a specific namespace for your deployment, be sure to append the -n <namespace> flag to your kubectl commands.
|
||||||
|
|
||||||
**Local Test Build Method:**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
$ make image
|
|
||||||
```
|
|
||||||
|
|
||||||
> This command assists in quickly building the required images locally. For a detailed build strategy, refer to the [Build Documentation](https://github.com/openimsdk/open-im-server/blob/main/build/README.md).
|
|
||||||
|
|
||||||
## Installation
|
|
||||||
|
|
||||||
Explore our Helm-Charts repository and read through: [Helm-Charts Repository](https://github.com/openimsdk/helm-charts)
|
|
||||||
|
|
||||||
|
|
||||||
Using the helm charts repository, you can ignore the following configuration, but if you want to just use the server and scale on top of it, you can go ahead:
|
|
||||||
|
|
||||||
**Use the Helm template to generate the deployment yaml file: `openim-charts.yaml`**
|
|
||||||
|
|
||||||
**Gen Image:**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
../scripts/genconfig.sh ../scripts/install/environment.sh ./templates/helm-image.yaml > ./charts/generated-configs/helm-image.yaml
|
|
||||||
```
|
|
||||||
|
|
||||||
**Gen Charts:**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
for chart in ./charts/*/; do
|
|
||||||
if [[ "$chart" == *"generated-configs"* || "$chart" == *"helmfile.yaml"* ]]; then
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -f "${chart}values.yaml" ]; then
|
|
||||||
helm template "$chart" -f "./charts/generated-configs/helm-image.yaml" -f "./charts/generated-configs/config.yaml" -f "./charts/generated-configs/notification.yaml" >> openim-charts.yaml
|
|
||||||
else
|
|
||||||
helm template "$chart" >> openim-charts.yaml
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
```
|
|
||||||
|
|
||||||
**Use Helmfile:**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
GO111MODULE=on go get github.com/roboll/helmfile@latest
|
|
||||||
```
|
|
||||||
|
|
||||||
```bash
|
|
||||||
export MONGO_ADDRESS=im-mongo
|
|
||||||
export MONGO_PORT=27017
|
|
||||||
export REDIS_ADDRESS=im-redis-master
|
|
||||||
export REDIS_PORT=6379
|
|
||||||
export KAFKA_ADDRESS=im-kafka
|
|
||||||
export KAFKA_PORT=9092
|
|
||||||
export OBJECT_APIURL="https://openim.server.com/api"
|
|
||||||
export MINIO_ENDPOINT="http://im-minio:9000"
|
|
||||||
export MINIO_SIGN_ENDPOINT="https://openim.server.com/im-minio-api"
|
|
||||||
|
|
||||||
mkdir ./charts/generated-configs
|
|
||||||
../scripts/genconfig.sh ../scripts/install/environment.sh ./templates/config.yaml > ./charts/generated-configs/config.yaml
|
|
||||||
cp ../config/notification.yaml ./charts/generated-configs/notification.yaml
|
|
||||||
../scripts/genconfig.sh ../scripts/install/environment.sh ./templates/helm-image.yaml > ./charts/generated-configs/helm-image.yaml
|
|
||||||
```
|
|
||||||
|
|
||||||
```bash
|
|
||||||
helmfile apply
|
|
||||||
```
|
|
||||||
|
7
deployments/deploy/kafka-secret.yml
Normal file
7
deployments/deploy/kafka-secret.yml
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: openim-kafka-secret
|
||||||
|
type: Opaque
|
||||||
|
data:
|
||||||
|
kafka-password: ""
|
8
deployments/deploy/minio-secret.yml
Normal file
8
deployments/deploy/minio-secret.yml
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: openim-minio-secret
|
||||||
|
type: Opaque
|
||||||
|
data:
|
||||||
|
minio-root-user: cm9vdA== # Base64 encoded "root"
|
||||||
|
minio-root-password: b3BlbklNMTIz # Base64 encoded "openIM123"
|
79
deployments/deploy/minio-statefulset.yml
Normal file
79
deployments/deploy/minio-statefulset.yml
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: minio
|
||||||
|
labels:
|
||||||
|
app: minio
|
||||||
|
spec:
|
||||||
|
replicas: 2
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: minio
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: minio
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: minio
|
||||||
|
image: minio/minio:RELEASE.2024-01-11T07-46-16Z
|
||||||
|
ports:
|
||||||
|
- containerPort: 9000 # MinIO service port
|
||||||
|
- containerPort: 9090 # MinIO console port
|
||||||
|
volumeMounts:
|
||||||
|
- name: minio-data
|
||||||
|
mountPath: /data
|
||||||
|
- name: minio-config
|
||||||
|
mountPath: /root/.minio
|
||||||
|
env:
|
||||||
|
- name: TZ
|
||||||
|
value: "Asia/Shanghai"
|
||||||
|
- name: MINIO_ROOT_USER
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: openim-minio-secret
|
||||||
|
key: minio-root-user
|
||||||
|
- name: MINIO_ROOT_PASSWORD
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: openim-minio-secret
|
||||||
|
key: minio-root-password
|
||||||
|
command:
|
||||||
|
- "/bin/sh"
|
||||||
|
- "-c"
|
||||||
|
- |
|
||||||
|
mkdir -p /data && \
|
||||||
|
minio server /data --console-address ":9090"
|
||||||
|
volumes:
|
||||||
|
- name: minio-data
|
||||||
|
persistentVolumeClaim:
|
||||||
|
claimName: minio-pvc
|
||||||
|
- name: minio-config
|
||||||
|
persistentVolumeClaim:
|
||||||
|
claimName: minio-config-pvc
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: PersistentVolumeClaim
|
||||||
|
metadata:
|
||||||
|
name: minio-pvc
|
||||||
|
spec:
|
||||||
|
accessModes:
|
||||||
|
- ReadWriteOnce
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
storage: 10Gi
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: PersistentVolumeClaim
|
||||||
|
metadata:
|
||||||
|
name: minio-config-pvc
|
||||||
|
spec:
|
||||||
|
accessModes:
|
||||||
|
- ReadWriteOnce
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
storage: 2Gi
|
||||||
|
|
||||||
|
|
8
deployments/deploy/mongo-secret.yml
Normal file
8
deployments/deploy/mongo-secret.yml
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: openim-mongo-secret
|
||||||
|
type: Opaque
|
||||||
|
data:
|
||||||
|
mongo_openim_username: b3BlbklN # base64 for "openIM", this user credentials need in authSource database.
|
||||||
|
mongo_openim_password: b3BlbklNMTIz # base64 for "openIM123"
|
108
deployments/deploy/mongo-statefulset.yml
Normal file
108
deployments/deploy/mongo-statefulset.yml
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
apiVersion: apps/v1
|
||||||
|
kind: StatefulSet
|
||||||
|
metadata:
|
||||||
|
name: mongo-statefulset
|
||||||
|
spec:
|
||||||
|
serviceName: "mongo"
|
||||||
|
replicas: 2
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: mongo
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: mongo
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: mongo
|
||||||
|
image: mongo:7.0
|
||||||
|
command: ["/bin/bash", "-c"]
|
||||||
|
args:
|
||||||
|
- >
|
||||||
|
docker-entrypoint.sh mongod --wiredTigerCacheSizeGB ${wiredTigerCacheSizeGB} --auth &
|
||||||
|
until mongosh -u ${MONGO_INITDB_ROOT_USERNAME} -p ${MONGO_INITDB_ROOT_PASSWORD} --authenticationDatabase admin --eval "db.runCommand({ ping: 1 })" &>/dev/null; do
|
||||||
|
echo "Waiting for MongoDB to start...";
|
||||||
|
sleep 1;
|
||||||
|
done &&
|
||||||
|
mongosh -u ${MONGO_INITDB_ROOT_USERNAME} -p ${MONGO_INITDB_ROOT_PASSWORD} --authenticationDatabase admin --eval "
|
||||||
|
db = db.getSiblingDB(\"${MONGO_INITDB_DATABASE}\");
|
||||||
|
if (!db.getUser(\"${MONGO_OPENIM_USERNAME}\")) {
|
||||||
|
db.createUser({
|
||||||
|
user: \"${MONGO_OPENIM_USERNAME}\",
|
||||||
|
pwd: \"${MONGO_OPENIM_PASSWORD}\",
|
||||||
|
roles: [{role: \"readWrite\", db: \"${MONGO_INITDB_DATABASE}\"}]
|
||||||
|
});
|
||||||
|
print(\"User created successfully: \");
|
||||||
|
print(\"Username: ${MONGO_OPENIM_USERNAME}\");
|
||||||
|
print(\"Password: ${MONGO_OPENIM_PASSWORD}\");
|
||||||
|
print(\"Database: ${MONGO_INITDB_DATABASE}\");
|
||||||
|
} else {
|
||||||
|
print(\"User already exists in database: ${MONGO_INITDB_DATABASE}, Username: ${MONGO_OPENIM_USERNAME}\");
|
||||||
|
}
|
||||||
|
" &&
|
||||||
|
tail -f /dev/null
|
||||||
|
ports:
|
||||||
|
- containerPort: 27017
|
||||||
|
env:
|
||||||
|
- name: MONGO_INITDB_ROOT_USERNAME
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: openim-mongo-init-secret
|
||||||
|
key: mongo_initdb_root_username
|
||||||
|
- name: MONGO_INITDB_ROOT_PASSWORD
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: openim-mongo-init-secret
|
||||||
|
key: mongo_initdb_root_password
|
||||||
|
- name: MONGO_INITDB_DATABASE
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: openim-mongo-init-secret
|
||||||
|
key: mongo_initdb_database
|
||||||
|
- name: MONGO_OPENIM_USERNAME
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: openim-mongo-init-secret
|
||||||
|
key: mongo_openim_username
|
||||||
|
- name: MONGO_OPENIM_PASSWORD
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: openim-mongo-init-secret
|
||||||
|
key: mongo_openim_password
|
||||||
|
- name: TZ
|
||||||
|
value: "Asia/Shanghai"
|
||||||
|
- name: wiredTigerCacheSizeGB
|
||||||
|
value: "1"
|
||||||
|
volumeMounts:
|
||||||
|
- name: mongo-storage
|
||||||
|
mountPath: /data/db
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
- name: mongo-storage
|
||||||
|
persistentVolumeClaim:
|
||||||
|
claimName: mongo-pvc
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: PersistentVolumeClaim
|
||||||
|
metadata:
|
||||||
|
name: mongo-pvc
|
||||||
|
spec:
|
||||||
|
accessModes:
|
||||||
|
- ReadWriteOnce
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
storage: 5Gi
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: openim-mongo-init-secret
|
||||||
|
type: Opaque
|
||||||
|
data:
|
||||||
|
mongo_initdb_root_username: cm9vdA== # base64 for "root"
|
||||||
|
mongo_initdb_root_password: b3BlbklNMTIz # base64 for "openIM123"
|
||||||
|
mongo_initdb_database: b3BlbmltX3Yz # base64 for "openim_v3"
|
||||||
|
mongo_openim_username: b3BlbklN # base64 for "openIM"
|
||||||
|
mongo_openim_password: b3BlbklNMTIz # base64 for "openIM123"
|
47
deployments/deploy/openim-api-deployment.yml
Normal file
47
deployments/deploy/openim-api-deployment.yml
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: openim-api
|
||||||
|
spec:
|
||||||
|
replicas: 2
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: openim-api
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: openim-api
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: openim-api-container
|
||||||
|
image: openim/openim-api:v3.8.3
|
||||||
|
env:
|
||||||
|
- name: CONFIG_PATH
|
||||||
|
value: "/config"
|
||||||
|
- name: IMENV_REDIS_PASSWORD
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: openim-redis-secret
|
||||||
|
key: redis-password
|
||||||
|
- name: IMENV_MONGODB_USERNAME
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: openim-mongo-secret
|
||||||
|
key: mongo_openim_username
|
||||||
|
- name: IMENV_MONGODB_PASSWORD
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: openim-mongo-secret
|
||||||
|
key: mongo_openim_password
|
||||||
|
|
||||||
|
volumeMounts:
|
||||||
|
- name: openim-config
|
||||||
|
mountPath: "/config"
|
||||||
|
readOnly: true
|
||||||
|
ports:
|
||||||
|
- containerPort: 10002
|
||||||
|
- containerPort: 12002
|
||||||
|
volumes:
|
||||||
|
- name: openim-config
|
||||||
|
configMap:
|
||||||
|
name: openim-config
|
1056
deployments/deploy/openim-config.yml
Normal file
1056
deployments/deploy/openim-config.yml
Normal file
File diff suppressed because it is too large
Load Diff
36
deployments/deploy/openim-msggateway-deployment.yml
Normal file
36
deployments/deploy/openim-msggateway-deployment.yml
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: messagegateway-rpc-server
|
||||||
|
spec:
|
||||||
|
replicas: 2
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: messagegateway-rpc-server
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: messagegateway-rpc-server
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: openim-msggateway-container
|
||||||
|
image: openim/openim-msggateway:v3.8.3
|
||||||
|
env:
|
||||||
|
- name: CONFIG_PATH
|
||||||
|
value: "/config"
|
||||||
|
- name: IMENV_REDIS_PASSWORD
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: openim-redis-secret
|
||||||
|
key: redis-password
|
||||||
|
volumeMounts:
|
||||||
|
- name: openim-config
|
||||||
|
mountPath: "/config"
|
||||||
|
readOnly: true
|
||||||
|
ports:
|
||||||
|
- containerPort: 10140
|
||||||
|
- containerPort: 12001
|
||||||
|
volumes:
|
||||||
|
- name: openim-config
|
||||||
|
configMap:
|
||||||
|
name: openim-config
|
50
deployments/deploy/openim-msgtransfer-deployment.yml
Normal file
50
deployments/deploy/openim-msgtransfer-deployment.yml
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: openim-msgtransfer-server
|
||||||
|
spec:
|
||||||
|
replicas: 2
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: openim-msgtransfer-server
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: openim-msgtransfer-server
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: openim-msgtransfer-container
|
||||||
|
image: openim/openim-msgtransfer:v3.8.3
|
||||||
|
env:
|
||||||
|
- name: CONFIG_PATH
|
||||||
|
value: "/config"
|
||||||
|
- name: IMENV_REDIS_PASSWORD
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: openim-redis-secret
|
||||||
|
key: redis-password
|
||||||
|
- name: IMENV_MONGODB_USERNAME
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: openim-mongo-secret
|
||||||
|
key: mongo_openim_username
|
||||||
|
- name: IMENV_MONGODB_PASSWORD
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: openim-mongo-secret
|
||||||
|
key: mongo_openim_password
|
||||||
|
- name: IMENV_KAFKA_PASSWORD
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: openim-kafka-secret
|
||||||
|
key: kafka-password
|
||||||
|
volumeMounts:
|
||||||
|
- name: openim-config
|
||||||
|
mountPath: "/config"
|
||||||
|
readOnly: true
|
||||||
|
ports:
|
||||||
|
- containerPort: 12020
|
||||||
|
volumes:
|
||||||
|
- name: openim-config
|
||||||
|
configMap:
|
||||||
|
name: openim-config
|
41
deployments/deploy/openim-push-deployment.yml
Normal file
41
deployments/deploy/openim-push-deployment.yml
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: push-rpc-server
|
||||||
|
spec:
|
||||||
|
replicas: 2
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: push-rpc-server
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: push-rpc-server
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: push-rpc-server-container
|
||||||
|
image: openim/openim-push:v3.8.3
|
||||||
|
env:
|
||||||
|
- name: CONFIG_PATH
|
||||||
|
value: "/config"
|
||||||
|
- name: IMENV_REDIS_PASSWORD
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: openim-redis-secret
|
||||||
|
key: redis-password
|
||||||
|
- name: IMENV_KAFKA_PASSWORD
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: openim-kafka-secret
|
||||||
|
key: kafka-password
|
||||||
|
volumeMounts:
|
||||||
|
- name: openim-config
|
||||||
|
mountPath: "/config"
|
||||||
|
readOnly: true
|
||||||
|
ports:
|
||||||
|
- containerPort: 10170
|
||||||
|
- containerPort: 12170
|
||||||
|
volumes:
|
||||||
|
- name: openim-config
|
||||||
|
configMap:
|
||||||
|
name: openim-config
|
37
deployments/deploy/openim-rpc-auth-deployment.yml
Normal file
37
deployments/deploy/openim-rpc-auth-deployment.yml
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: auth-rpc-server
|
||||||
|
spec:
|
||||||
|
replicas: 2
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: auth-rpc-server
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: auth-rpc-server
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: auth-rpc-server-container
|
||||||
|
image: openim/openim-rpc-auth:v3.8.3
|
||||||
|
imagePullPolicy: Never
|
||||||
|
env:
|
||||||
|
- name: CONFIG_PATH
|
||||||
|
value: "/config"
|
||||||
|
- name: IMENV_REDIS_PASSWORD
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: openim-redis-secret
|
||||||
|
key: redis-password
|
||||||
|
volumeMounts:
|
||||||
|
- name: openim-config
|
||||||
|
mountPath: "/config"
|
||||||
|
readOnly: true
|
||||||
|
ports:
|
||||||
|
- containerPort: 10200
|
||||||
|
- containerPort: 12200
|
||||||
|
volumes:
|
||||||
|
- name: openim-config
|
||||||
|
configMap:
|
||||||
|
name: openim-config
|
46
deployments/deploy/openim-rpc-conversation-deployment.yml
Normal file
46
deployments/deploy/openim-rpc-conversation-deployment.yml
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: conversation-rpc-server
|
||||||
|
spec:
|
||||||
|
replicas: 2
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: conversation-rpc-server
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: conversation-rpc-server
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: conversation-rpc-server-container
|
||||||
|
image: openim/openim-rpc-conversation:v3.8.3
|
||||||
|
env:
|
||||||
|
- name: CONFIG_PATH
|
||||||
|
value: "/config"
|
||||||
|
- name: IMENV_REDIS_PASSWORD
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: openim-redis-secret
|
||||||
|
key: redis-password
|
||||||
|
- name: IMENV_MONGODB_USERNAME
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: openim-mongo-secret
|
||||||
|
key: mongo_openim_username
|
||||||
|
- name: IMENV_MONGODB_PASSWORD
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: openim-mongo-secret
|
||||||
|
key: mongo_openim_password
|
||||||
|
volumeMounts:
|
||||||
|
- name: openim-config
|
||||||
|
mountPath: "/config"
|
||||||
|
readOnly: true
|
||||||
|
ports:
|
||||||
|
- containerPort: 10220
|
||||||
|
- containerPort: 12220
|
||||||
|
volumes:
|
||||||
|
- name: openim-config
|
||||||
|
configMap:
|
||||||
|
name: openim-config
|
46
deployments/deploy/openim-rpc-friend-deployment.yml
Normal file
46
deployments/deploy/openim-rpc-friend-deployment.yml
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: friend-rpc-server
|
||||||
|
spec:
|
||||||
|
replicas: 2
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: friend-rpc-server
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: friend-rpc-server
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: friend-rpc-server-container
|
||||||
|
image: openim/openim-rpc-friend:v3.8.3
|
||||||
|
env:
|
||||||
|
- name: CONFIG_PATH
|
||||||
|
value: "/config"
|
||||||
|
- name: IMENV_REDIS_PASSWORD
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: openim-redis-secret
|
||||||
|
key: redis-password
|
||||||
|
- name: IMENV_MONGODB_USERNAME
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: openim-mongo-secret
|
||||||
|
key: mongo_openim_username
|
||||||
|
- name: IMENV_MONGODB_PASSWORD
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: openim-mongo-secret
|
||||||
|
key: mongo_openim_password
|
||||||
|
volumeMounts:
|
||||||
|
- name: openim-config
|
||||||
|
mountPath: "/config"
|
||||||
|
readOnly: true
|
||||||
|
ports:
|
||||||
|
- containerPort: 10240
|
||||||
|
- containerPort: 12240
|
||||||
|
volumes:
|
||||||
|
- name: openim-config
|
||||||
|
configMap:
|
||||||
|
name: openim-config
|
46
deployments/deploy/openim-rpc-group-deployment.yml
Normal file
46
deployments/deploy/openim-rpc-group-deployment.yml
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: group-rpc-server
|
||||||
|
spec:
|
||||||
|
replicas: 2
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: group-rpc-server
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: group-rpc-server
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: group-rpc-server-container
|
||||||
|
image: openim/openim-rpc-group:v3.8.3
|
||||||
|
env:
|
||||||
|
- name: CONFIG_PATH
|
||||||
|
value: "/config"
|
||||||
|
- name: IMENV_REDIS_PASSWORD
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: openim-redis-secret
|
||||||
|
key: redis-password
|
||||||
|
- name: IMENV_MONGODB_USERNAME
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: openim-mongo-secret
|
||||||
|
key: mongo_openim_username
|
||||||
|
- name: IMENV_MONGODB_PASSWORD
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: openim-mongo-secret
|
||||||
|
key: mongo_openim_password
|
||||||
|
volumeMounts:
|
||||||
|
- name: openim-config
|
||||||
|
mountPath: "/config"
|
||||||
|
readOnly: true
|
||||||
|
ports:
|
||||||
|
- containerPort: 10260
|
||||||
|
- containerPort: 12260
|
||||||
|
volumes:
|
||||||
|
- name: openim-config
|
||||||
|
configMap:
|
||||||
|
name: openim-config
|
51
deployments/deploy/openim-rpc-msg-deployment.yml
Normal file
51
deployments/deploy/openim-rpc-msg-deployment.yml
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: msg-rpc-server
|
||||||
|
spec:
|
||||||
|
replicas: 2
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: msg-rpc-server
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: msg-rpc-server
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: msg-rpc-server-container
|
||||||
|
image: openim/openim-rpc-msg:v3.8.3
|
||||||
|
env:
|
||||||
|
- name: CONFIG_PATH
|
||||||
|
value: "/config"
|
||||||
|
- name: IMENV_REDIS_PASSWORD
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: openim-redis-secret
|
||||||
|
key: redis-password
|
||||||
|
- name: IMENV_MONGODB_USERNAME
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: openim-mongo-secret
|
||||||
|
key: mongo_openim_username
|
||||||
|
- name: IMENV_MONGODB_PASSWORD
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: openim-mongo-secret
|
||||||
|
key: mongo_openim_password
|
||||||
|
- name: IMENV_KAFKA_PASSWORD
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: openim-kafka-secret
|
||||||
|
key: kafka-password
|
||||||
|
volumeMounts:
|
||||||
|
- name: openim-config
|
||||||
|
mountPath: "/config"
|
||||||
|
readOnly: true
|
||||||
|
ports:
|
||||||
|
- containerPort: 10280
|
||||||
|
- containerPort: 12280
|
||||||
|
volumes:
|
||||||
|
- name: openim-config
|
||||||
|
configMap:
|
||||||
|
name: openim-config
|
56
deployments/deploy/openim-rpc-third-deployment.yml
Normal file
56
deployments/deploy/openim-rpc-third-deployment.yml
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: third-rpc-server
|
||||||
|
spec:
|
||||||
|
replicas: 2
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: third-rpc-server
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: third-rpc-server
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: third-rpc-server-container
|
||||||
|
image: openim/openim-rpc-third:v3.8.3
|
||||||
|
env:
|
||||||
|
- name: CONFIG_PATH
|
||||||
|
value: "/config"
|
||||||
|
- name: IMENV_MINIO_ACCESSKEYID
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: openim-minio-secret
|
||||||
|
key: minio-root-user
|
||||||
|
- name: IMENV_MINIO_SECRETACCESSKEY
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: openim-minio-secret
|
||||||
|
key: minio-root-password
|
||||||
|
- name: IMENV_REDIS_PASSWORD
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: openim-redis-secret
|
||||||
|
key: redis-password
|
||||||
|
- name: IMENV_MONGODB_USERNAME
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: openim-mongo-secret
|
||||||
|
key: mongo_openim_username
|
||||||
|
- name: IMENV_MONGODB_PASSWORD
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: openim-mongo-secret
|
||||||
|
key: mongo_openim_password
|
||||||
|
volumeMounts:
|
||||||
|
- name: openim-config
|
||||||
|
mountPath: "/config"
|
||||||
|
readOnly: true
|
||||||
|
ports:
|
||||||
|
- containerPort: 10300
|
||||||
|
- containerPort: 12300
|
||||||
|
volumes:
|
||||||
|
- name: openim-config
|
||||||
|
configMap:
|
||||||
|
name: openim-config
|
51
deployments/deploy/openim-rpc-user-deployment.yml
Normal file
51
deployments/deploy/openim-rpc-user-deployment.yml
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: user-rpc-server
|
||||||
|
spec:
|
||||||
|
replicas: 2
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: user-rpc-server
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: user-rpc-server
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: user-rpc-server-container
|
||||||
|
image: openim/openim-rpc-user:v3.8.3
|
||||||
|
env:
|
||||||
|
- name: CONFIG_PATH
|
||||||
|
value: "/config"
|
||||||
|
- name: IMENV_REDIS_PASSWORD
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: openim-redis-secret
|
||||||
|
key: redis-password
|
||||||
|
- name: IMENV_MONGODB_USERNAME
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: openim-mongo-secret
|
||||||
|
key: mongo_openim_username
|
||||||
|
- name: IMENV_MONGODB_PASSWORD
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: openim-mongo-secret
|
||||||
|
key: mongo_openim_password
|
||||||
|
- name: IMENV_KAFKA_PASSWORD
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: openim-kafka-secret
|
||||||
|
key: kafka-password
|
||||||
|
volumeMounts:
|
||||||
|
- name: openim-config
|
||||||
|
mountPath: "/config"
|
||||||
|
readOnly: true
|
||||||
|
ports:
|
||||||
|
- containerPort: 10320
|
||||||
|
- containerPort: 12320
|
||||||
|
volumes:
|
||||||
|
- name: openim-config
|
||||||
|
configMap:
|
||||||
|
name: openim-config
|
7
deployments/deploy/redis-secret.yml
Normal file
7
deployments/deploy/redis-secret.yml
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: openim-redis-secret
|
||||||
|
type: Opaque
|
||||||
|
data:
|
||||||
|
redis-password: b3BlbklNMTIz # "openIM123" in base64
|
55
deployments/deploy/redis-statefulset.yml
Normal file
55
deployments/deploy/redis-statefulset.yml
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
apiVersion: apps/v1
|
||||||
|
kind: StatefulSet
|
||||||
|
metadata:
|
||||||
|
name: redis-statefulset
|
||||||
|
spec:
|
||||||
|
serviceName: "redis"
|
||||||
|
replicas: 2
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: redis
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: redis
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: redis
|
||||||
|
image: redis:7.0.0
|
||||||
|
ports:
|
||||||
|
- containerPort: 6379
|
||||||
|
env:
|
||||||
|
- name: TZ
|
||||||
|
value: "Asia/Shanghai"
|
||||||
|
- name: REDIS_PASSWORD
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: redis-secret
|
||||||
|
key: redis-password
|
||||||
|
volumeMounts:
|
||||||
|
- name: redis-data
|
||||||
|
mountPath: /data
|
||||||
|
command:
|
||||||
|
[
|
||||||
|
"/bin/sh",
|
||||||
|
"-c",
|
||||||
|
'redis-server --requirepass "$REDIS_PASSWORD" --appendonly yes',
|
||||||
|
]
|
||||||
|
volumes:
|
||||||
|
- name: redis-config-volume
|
||||||
|
configMap:
|
||||||
|
name: openim-config
|
||||||
|
- name: redis-data
|
||||||
|
persistentVolumeClaim:
|
||||||
|
claimName: redis-pvc
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: PersistentVolumeClaim
|
||||||
|
metadata:
|
||||||
|
name: redis-pvc
|
||||||
|
spec:
|
||||||
|
accessModes:
|
||||||
|
- ReadWriteOnce
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
storage: 5Gi
|
@ -240,11 +240,11 @@ push:
|
|||||||
channelName: ${GETUI_CHANNEL_NAME}
|
channelName: ${GETUI_CHANNEL_NAME}
|
||||||
fcm:
|
fcm:
|
||||||
serviceAccount: "${FCM_SERVICE_ACCOUNT}"
|
serviceAccount: "${FCM_SERVICE_ACCOUNT}"
|
||||||
jpns:
|
jpush:
|
||||||
appKey: ${JPNS_APP_KEY}
|
appKey: ${JPUSH_APP_KEY}
|
||||||
masterSecret: ${JPNS_MASTER_SECRET}
|
masterSecret: ${JPUSH_MASTER_SECRET}
|
||||||
pushUrl: ${JPNS_PUSH_URL}
|
pushUrl: ${JPUSH_PUSH_URL}
|
||||||
pushIntent: ${JPNS_PUSH_INTENT}
|
pushIntent: ${JPUSH_PUSH_INTENT}
|
||||||
|
|
||||||
# App manager configuration
|
# App manager configuration
|
||||||
#
|
#
|
||||||
|
@ -8,12 +8,36 @@ services:
|
|||||||
ports:
|
ports:
|
||||||
- "37017:27017"
|
- "37017:27017"
|
||||||
container_name: mongo
|
container_name: mongo
|
||||||
command: ["/bin/bash", "-c", "/docker-entrypoint-initdb.d/mongo-init.sh; docker-entrypoint.sh mongod --wiredTigerCacheSizeGB 1 --auth"]
|
command: >
|
||||||
|
bash -c '
|
||||||
|
docker-entrypoint.sh mongod --wiredTigerCacheSizeGB $$wiredTigerCacheSizeGB --auth &
|
||||||
|
until mongosh -u $$MONGO_INITDB_ROOT_USERNAME -p $$MONGO_INITDB_ROOT_PASSWORD --authenticationDatabase admin --eval "db.runCommand({ ping: 1 })" &>/dev/null; do
|
||||||
|
echo "Waiting for MongoDB to start..."
|
||||||
|
sleep 1
|
||||||
|
done &&
|
||||||
|
mongosh -u $$MONGO_INITDB_ROOT_USERNAME -p $$MONGO_INITDB_ROOT_PASSWORD --authenticationDatabase admin --eval "
|
||||||
|
db = db.getSiblingDB(\"$$MONGO_INITDB_DATABASE\");
|
||||||
|
if (!db.getUser(\"$$MONGO_OPENIM_USERNAME\")) {
|
||||||
|
db.createUser({
|
||||||
|
user: \"$$MONGO_OPENIM_USERNAME\",
|
||||||
|
pwd: \"$$MONGO_OPENIM_PASSWORD\",
|
||||||
|
roles: [{role: \"readWrite\", db: \"$$MONGO_INITDB_DATABASE\"}]
|
||||||
|
});
|
||||||
|
print(\"User created successfully: \");
|
||||||
|
print(\"Username: $$MONGO_OPENIM_USERNAME\");
|
||||||
|
print(\"Password: $$MONGO_OPENIM_PASSWORD\");
|
||||||
|
print(\"Database: $$MONGO_INITDB_DATABASE\");
|
||||||
|
} else {
|
||||||
|
print(\"User already exists in database: $$MONGO_INITDB_DATABASE, Username: $$MONGO_OPENIM_USERNAME\");
|
||||||
|
}
|
||||||
|
" &&
|
||||||
|
tail -f /dev/null
|
||||||
|
'
|
||||||
volumes:
|
volumes:
|
||||||
- "${DATA_DIR}/components/mongodb/data/db:/data/db"
|
- "${DATA_DIR}/components/mongodb/data/db:/data/db"
|
||||||
- "${DATA_DIR}/components/mongodb/data/logs:/data/logs"
|
- "${DATA_DIR}/components/mongodb/data/logs:/data/logs"
|
||||||
- "${DATA_DIR}/components/mongodb/data/conf:/etc/mongo"
|
- "${DATA_DIR}/components/mongodb/data/conf:/etc/mongo"
|
||||||
- "./scripts/mongo-init.sh:/docker-entrypoint-initdb.d/mongo-init.sh:ro"
|
- "${MONGO_BACKUP_DIR}:/data/backup"
|
||||||
environment:
|
environment:
|
||||||
- TZ=Asia/Shanghai
|
- TZ=Asia/Shanghai
|
||||||
- wiredTigerCacheSizeGB=1
|
- wiredTigerCacheSizeGB=1
|
||||||
@ -43,19 +67,6 @@ services:
|
|||||||
networks:
|
networks:
|
||||||
- openim
|
- openim
|
||||||
|
|
||||||
zookeeper:
|
|
||||||
image: "${ZOOKEEPER_IMAGE}"
|
|
||||||
container_name: zookeeper
|
|
||||||
ports:
|
|
||||||
- "12181:2181"
|
|
||||||
environment:
|
|
||||||
#JVMFLAGS: "-Xms32m -Xmx128m"
|
|
||||||
TZ: "Asia/Shanghai"
|
|
||||||
ALLOW_ANONYMOUS_LOGIN: "yes"
|
|
||||||
restart: always
|
|
||||||
networks:
|
|
||||||
- openim
|
|
||||||
|
|
||||||
etcd:
|
etcd:
|
||||||
image: "${ETCD_IMAGE}"
|
image: "${ETCD_IMAGE}"
|
||||||
container_name: etcd
|
container_name: etcd
|
||||||
@ -84,10 +95,7 @@ services:
|
|||||||
ports:
|
ports:
|
||||||
- "19094:9094"
|
- "19094:9094"
|
||||||
volumes:
|
volumes:
|
||||||
- ./scripts/create-topic.sh:/opt/bitnami/kafka/create-topic.sh
|
|
||||||
- "${DATA_DIR}/components/kafka:/bitnami/kafka"
|
- "${DATA_DIR}/components/kafka:/bitnami/kafka"
|
||||||
command: >
|
|
||||||
bash -c "/opt/bitnami/scripts/kafka/run.sh & /opt/bitnami/kafka/create-topic.sh; wait"
|
|
||||||
environment:
|
environment:
|
||||||
#KAFKA_HEAP_OPTS: "-Xms128m -Xmx256m"
|
#KAFKA_HEAP_OPTS: "-Xms128m -Xmx256m"
|
||||||
TZ: Asia/Shanghai
|
TZ: Asia/Shanghai
|
||||||
@ -98,10 +106,11 @@ services:
|
|||||||
KAFKA_CFG_ADVERTISED_LISTENERS: PLAINTEXT://kafka:9092,EXTERNAL://localhost:19094
|
KAFKA_CFG_ADVERTISED_LISTENERS: PLAINTEXT://kafka:9092,EXTERNAL://localhost:19094
|
||||||
KAFKA_CFG_LISTENER_SECURITY_PROTOCOL_MAP: CONTROLLER:PLAINTEXT,EXTERNAL:PLAINTEXT,PLAINTEXT:PLAINTEXT
|
KAFKA_CFG_LISTENER_SECURITY_PROTOCOL_MAP: CONTROLLER:PLAINTEXT,EXTERNAL:PLAINTEXT,PLAINTEXT:PLAINTEXT
|
||||||
KAFKA_CFG_CONTROLLER_LISTENER_NAMES: CONTROLLER
|
KAFKA_CFG_CONTROLLER_LISTENER_NAMES: CONTROLLER
|
||||||
|
KAFKA_NUM_PARTITIONS: 8
|
||||||
|
KAFKA_CFG_AUTO_CREATE_TOPICS_ENABLE: "true"
|
||||||
networks:
|
networks:
|
||||||
- openim
|
- openim
|
||||||
|
|
||||||
|
|
||||||
minio:
|
minio:
|
||||||
image: "${MINIO_IMAGE}"
|
image: "${MINIO_IMAGE}"
|
||||||
ports:
|
ports:
|
||||||
@ -138,49 +147,68 @@ services:
|
|||||||
networks:
|
networks:
|
||||||
- openim
|
- openim
|
||||||
|
|
||||||
# prometheus:
|
prometheus:
|
||||||
# image: ${PROMETHEUS_IMAGE}
|
image: ${PROMETHEUS_IMAGE}
|
||||||
# container_name: prometheus
|
container_name: prometheus
|
||||||
# restart: always
|
restart: always
|
||||||
# volumes:
|
user: root
|
||||||
# - ./config/prometheus.yml:/etc/prometheus/prometheus.yml
|
profiles:
|
||||||
# - ./config/instance-down-rules.yml:/etc/prometheus/instance-down-rules.yml
|
- m
|
||||||
# - ${DATA_DIR}/components/prometheus/data:/prometheus
|
volumes:
|
||||||
# command:
|
- ./config/prometheus.yml:/etc/prometheus/prometheus.yml
|
||||||
# - '--config.file=/etc/prometheus/prometheus.yml'
|
- ./config/instance-down-rules.yml:/etc/prometheus/instance-down-rules.yml
|
||||||
# - '--storage.tsdb.path=/prometheus'
|
- ${DATA_DIR}/components/prometheus/data:/prometheus
|
||||||
# ports:
|
command:
|
||||||
# - "19091:9090"
|
- '--config.file=/etc/prometheus/prometheus.yml'
|
||||||
# networks:
|
- '--storage.tsdb.path=/prometheus'
|
||||||
# - openim
|
- '--web.listen-address=:${PROMETHEUS_PORT}'
|
||||||
#
|
network_mode: host
|
||||||
# alertmanager:
|
|
||||||
# image: ${ALERTMANAGER_IMAGE}
|
|
||||||
# container_name: alertmanager
|
|
||||||
# restart: always
|
|
||||||
# volumes:
|
|
||||||
# - ./config/alertmanager.yml:/etc/alertmanager/alertmanager.yml
|
|
||||||
# - ./config/email.tmpl:/etc/alertmanager/email.tmpl
|
|
||||||
# ports:
|
|
||||||
# - "19093:9093"
|
|
||||||
# networks:
|
|
||||||
# - openim
|
|
||||||
#
|
|
||||||
# grafana:
|
|
||||||
# image: ${GRAFANA_IMAGE}
|
|
||||||
# container_name: grafana
|
|
||||||
# user: root
|
|
||||||
# restart: always
|
|
||||||
# environment:
|
|
||||||
# - GF_SECURITY_ALLOW_EMBEDDING=true
|
|
||||||
# - GF_SESSION_COOKIE_SAMESITE=none
|
|
||||||
# - GF_SESSION_COOKIE_SECURE=true
|
|
||||||
# - GF_AUTH_ANONYMOUS_ENABLED=true
|
|
||||||
# - GF_AUTH_ANONYMOUS_ORG_ROLE=Admin
|
|
||||||
# ports:
|
|
||||||
# - "13000:3000"
|
|
||||||
# volumes:
|
|
||||||
# - ${DATA_DIR:-./}/components/grafana:/var/lib/grafana
|
|
||||||
# networks:
|
|
||||||
# - openim
|
|
||||||
|
|
||||||
|
alertmanager:
|
||||||
|
image: ${ALERTMANAGER_IMAGE}
|
||||||
|
container_name: alertmanager
|
||||||
|
restart: always
|
||||||
|
profiles:
|
||||||
|
- m
|
||||||
|
volumes:
|
||||||
|
- ./config/alertmanager.yml:/etc/alertmanager/alertmanager.yml
|
||||||
|
- ./config/email.tmpl:/etc/alertmanager/email.tmpl
|
||||||
|
command:
|
||||||
|
- '--config.file=/etc/alertmanager/alertmanager.yml'
|
||||||
|
- '--web.listen-address=:${ALERTMANAGER_PORT}'
|
||||||
|
network_mode: host
|
||||||
|
|
||||||
|
grafana:
|
||||||
|
image: ${GRAFANA_IMAGE}
|
||||||
|
container_name: grafana
|
||||||
|
user: root
|
||||||
|
restart: always
|
||||||
|
profiles:
|
||||||
|
- m
|
||||||
|
environment:
|
||||||
|
- GF_SECURITY_ALLOW_EMBEDDING=true
|
||||||
|
- GF_SESSION_COOKIE_SAMESITE=none
|
||||||
|
- GF_SESSION_COOKIE_SECURE=true
|
||||||
|
- GF_AUTH_ANONYMOUS_ENABLED=true
|
||||||
|
- GF_AUTH_ANONYMOUS_ORG_ROLE=Admin
|
||||||
|
- GF_SERVER_HTTP_PORT=${GRAFANA_PORT}
|
||||||
|
volumes:
|
||||||
|
- ${DATA_DIR:-./}/components/grafana:/var/lib/grafana
|
||||||
|
network_mode: host
|
||||||
|
|
||||||
|
node-exporter:
|
||||||
|
image: ${NODE_EXPORTER_IMAGE}
|
||||||
|
container_name: node-exporter
|
||||||
|
restart: always
|
||||||
|
profiles:
|
||||||
|
- m
|
||||||
|
volumes:
|
||||||
|
- /proc:/host/proc:ro
|
||||||
|
- /sys:/host/sys:ro
|
||||||
|
- /:/rootfs:ro
|
||||||
|
command:
|
||||||
|
- '--path.procfs=/host/proc'
|
||||||
|
- '--path.sysfs=/host/sys'
|
||||||
|
- '--path.rootfs=/rootfs'
|
||||||
|
- '--web.listen-address=:${NODE_EXPORTER_PORT}'
|
||||||
|
network_mode: host
|
||||||
|
@ -474,10 +474,10 @@ This section involves setting up additional configuration variables for Websocke
|
|||||||
| GETUI_CHANNEL_ID | [User Defined] | GeTui Channel ID |
|
| GETUI_CHANNEL_ID | [User Defined] | GeTui Channel ID |
|
||||||
| GETUI_CHANNEL_NAME | [User Defined] | GeTui Channel Name |
|
| GETUI_CHANNEL_NAME | [User Defined] | GeTui Channel Name |
|
||||||
| FCM_SERVICE_ACCOUNT | "x.json" | FCM Service Account |
|
| FCM_SERVICE_ACCOUNT | "x.json" | FCM Service Account |
|
||||||
| JPNS_APP_KEY | [User Defined] | JPNS Application Key |
|
| JPUSH_APP_KEY | [User Defined] | JPUSH Application Key |
|
||||||
| JPNS_MASTER_SECRET | [User Defined] | JPNS Master Secret |
|
| JPUSH_MASTER_SECRET | [User Defined] | JPUSH Master Secret |
|
||||||
| JPNS_PUSH_URL | [User Defined] | JPNS Push Notification URL |
|
| JPUSH_PUSH_URL | [User Defined] | JPUSH Push Notification URL |
|
||||||
| JPNS_PUSH_INTENT | [User Defined] | JPNS Push Intent |
|
| JPUSH_PUSH_INTENT | [User Defined] | JPUSH Push Intent |
|
||||||
| IM_ADMIN_USERID | "imAdmin" | IM Administrator ID |
|
| IM_ADMIN_USERID | "imAdmin" | IM Administrator ID |
|
||||||
| IM_ADMIN_NAME | "imAdmin" | IM Administrator Nickname |
|
| IM_ADMIN_NAME | "imAdmin" | IM Administrator Nickname |
|
||||||
| MULTILOGIN_POLICY | "1" | Multi-login Policy |
|
| MULTILOGIN_POLICY | "1" | Multi-login Policy |
|
||||||
|
76
go.mod
76
go.mod
@ -1,6 +1,6 @@
|
|||||||
module github.com/openimsdk/open-im-server/v3
|
module github.com/openimsdk/open-im-server/v3
|
||||||
|
|
||||||
go 1.21.2
|
go 1.22.7
|
||||||
|
|
||||||
require (
|
require (
|
||||||
firebase.google.com/go/v4 v4.14.1
|
firebase.google.com/go/v4 v4.14.1
|
||||||
@ -8,19 +8,19 @@ require (
|
|||||||
github.com/gin-gonic/gin v1.9.1
|
github.com/gin-gonic/gin v1.9.1
|
||||||
github.com/go-playground/validator/v10 v10.20.0
|
github.com/go-playground/validator/v10 v10.20.0
|
||||||
github.com/gogo/protobuf v1.3.2 // indirect
|
github.com/gogo/protobuf v1.3.2 // indirect
|
||||||
github.com/golang-jwt/jwt/v4 v4.5.0
|
github.com/golang-jwt/jwt/v4 v4.5.1
|
||||||
github.com/gorilla/websocket v1.5.1
|
github.com/gorilla/websocket v1.5.1
|
||||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0
|
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0
|
||||||
github.com/mitchellh/mapstructure v1.5.0
|
github.com/mitchellh/mapstructure v1.5.0
|
||||||
github.com/openimsdk/protocol v0.0.72
|
github.com/openimsdk/protocol v0.0.72-alpha.71
|
||||||
github.com/openimsdk/tools v0.0.50-alpha.16
|
github.com/openimsdk/tools v0.0.50-alpha.72
|
||||||
github.com/pkg/errors v0.9.1 // indirect
|
github.com/pkg/errors v0.9.1 // indirect
|
||||||
github.com/prometheus/client_golang v1.18.0
|
github.com/prometheus/client_golang v1.18.0
|
||||||
github.com/stretchr/testify v1.9.0
|
github.com/stretchr/testify v1.9.0
|
||||||
go.mongodb.org/mongo-driver v1.14.0
|
go.mongodb.org/mongo-driver v1.14.0
|
||||||
google.golang.org/api v0.170.0
|
google.golang.org/api v0.170.0
|
||||||
google.golang.org/grpc v1.66.2
|
google.golang.org/grpc v1.68.0
|
||||||
google.golang.org/protobuf v1.34.2
|
google.golang.org/protobuf v1.35.1
|
||||||
gopkg.in/yaml.v3 v3.0.1
|
gopkg.in/yaml.v3 v3.0.1
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -40,39 +40,41 @@ require (
|
|||||||
github.com/robfig/cron/v3 v3.0.1
|
github.com/robfig/cron/v3 v3.0.1
|
||||||
github.com/shirou/gopsutil v3.21.11+incompatible
|
github.com/shirou/gopsutil v3.21.11+incompatible
|
||||||
github.com/spf13/viper v1.18.2
|
github.com/spf13/viper v1.18.2
|
||||||
github.com/stathat/consistent v1.0.0
|
go.etcd.io/etcd/client/v3 v3.5.13
|
||||||
go.uber.org/automaxprocs v1.5.3
|
go.uber.org/automaxprocs v1.5.3
|
||||||
golang.org/x/exp v0.0.0-20230905200255-921286631fa9
|
|
||||||
golang.org/x/sync v0.8.0
|
golang.org/x/sync v0.8.0
|
||||||
|
k8s.io/api v0.31.2
|
||||||
|
k8s.io/apimachinery v0.31.2
|
||||||
|
k8s.io/client-go v0.31.2
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
cloud.google.com/go v0.112.1 // indirect
|
cloud.google.com/go v0.112.1 // indirect
|
||||||
cloud.google.com/go/compute/metadata v0.3.0 // indirect
|
cloud.google.com/go/compute/metadata v0.5.0 // indirect
|
||||||
cloud.google.com/go/firestore v1.15.0 // indirect
|
cloud.google.com/go/firestore v1.15.0 // indirect
|
||||||
cloud.google.com/go/iam v1.1.7 // indirect
|
cloud.google.com/go/iam v1.1.7 // indirect
|
||||||
cloud.google.com/go/longrunning v0.5.5 // indirect
|
cloud.google.com/go/longrunning v0.5.5 // indirect
|
||||||
cloud.google.com/go/storage v1.40.0 // indirect
|
cloud.google.com/go/storage v1.40.0 // indirect
|
||||||
github.com/MicahParks/keyfunc v1.9.0 // indirect
|
github.com/MicahParks/keyfunc v1.9.0 // indirect
|
||||||
github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible // indirect
|
github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible // indirect
|
||||||
github.com/aws/aws-sdk-go-v2 v1.23.1 // indirect
|
github.com/aws/aws-sdk-go-v2 v1.32.5 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.5.1 // indirect
|
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.5.1 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/config v1.25.4 // indirect
|
github.com/aws/aws-sdk-go-v2/config v1.28.5 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/credentials v1.16.3 // indirect
|
github.com/aws/aws-sdk-go-v2/credentials v1.17.46 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.5 // indirect
|
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.20 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.4 // indirect
|
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.24 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.4 // indirect
|
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.24 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.7.1 // indirect
|
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.2.4 // indirect
|
github.com/aws/aws-sdk-go-v2/internal/v4a v1.2.4 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.10.1 // indirect
|
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.1 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.2.4 // indirect
|
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.2.4 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.4 // indirect
|
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.5 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.16.4 // indirect
|
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.16.4 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.43.1 // indirect
|
github.com/aws/aws-sdk-go-v2/service/s3 v1.43.1 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/service/sso v1.17.3 // indirect
|
github.com/aws/aws-sdk-go-v2/service/sso v1.24.6 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.20.1 // indirect
|
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.5 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/service/sts v1.25.4 // indirect
|
github.com/aws/aws-sdk-go-v2/service/sts v1.33.1 // indirect
|
||||||
github.com/aws/smithy-go v1.17.0 // indirect
|
github.com/aws/smithy-go v1.22.1 // indirect
|
||||||
github.com/beorn7/perks v1.0.1 // indirect
|
github.com/beorn7/perks v1.0.1 // indirect
|
||||||
github.com/bytedance/sonic v1.11.6 // indirect
|
github.com/bytedance/sonic v1.11.6 // indirect
|
||||||
github.com/bytedance/sonic/loader v0.1.1 // indirect
|
github.com/bytedance/sonic/loader v0.1.1 // indirect
|
||||||
@ -88,19 +90,27 @@ require (
|
|||||||
github.com/eapache/go-resiliency v1.6.0 // indirect
|
github.com/eapache/go-resiliency v1.6.0 // indirect
|
||||||
github.com/eapache/go-xerial-snappy v0.0.0-20230731223053-c322873962e3 // indirect
|
github.com/eapache/go-xerial-snappy v0.0.0-20230731223053-c322873962e3 // indirect
|
||||||
github.com/eapache/queue v1.1.0 // indirect
|
github.com/eapache/queue v1.1.0 // indirect
|
||||||
|
github.com/emicklei/go-restful/v3 v3.11.0 // indirect
|
||||||
github.com/felixge/httpsnoop v1.0.4 // indirect
|
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||||
github.com/fsnotify/fsnotify v1.7.0 // indirect
|
github.com/fsnotify/fsnotify v1.7.0 // indirect
|
||||||
|
github.com/fxamacker/cbor/v2 v2.7.0 // indirect
|
||||||
github.com/gabriel-vasile/mimetype v1.4.3 // indirect
|
github.com/gabriel-vasile/mimetype v1.4.3 // indirect
|
||||||
github.com/gin-contrib/sse v0.1.0 // indirect
|
github.com/gin-contrib/sse v0.1.0 // indirect
|
||||||
github.com/go-logr/logr v1.4.1 // indirect
|
github.com/go-logr/logr v1.4.2 // indirect
|
||||||
github.com/go-logr/stdr v1.2.2 // 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.2.6 // indirect
|
||||||
|
github.com/go-openapi/jsonpointer v0.19.6 // indirect
|
||||||
|
github.com/go-openapi/jsonreference v0.20.2 // indirect
|
||||||
|
github.com/go-openapi/swag v0.22.4 // indirect
|
||||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||||
github.com/go-zookeeper/zk v1.0.3 // indirect
|
github.com/go-zookeeper/zk v1.0.3 // indirect
|
||||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||||
github.com/golang/protobuf v1.5.4 // indirect
|
github.com/golang/protobuf v1.5.4 // indirect
|
||||||
github.com/golang/snappy v0.0.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-querystring v1.1.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
|
github.com/google/s2a-go v0.1.7 // indirect
|
||||||
github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect
|
github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect
|
||||||
github.com/googleapis/gax-go/v2 v2.12.3 // indirect
|
github.com/googleapis/gax-go/v2 v2.12.3 // indirect
|
||||||
@ -117,6 +127,7 @@ require (
|
|||||||
github.com/jinzhu/copier v0.4.0 // indirect
|
github.com/jinzhu/copier v0.4.0 // indirect
|
||||||
github.com/jinzhu/inflection v1.0.0 // indirect
|
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||||
github.com/jinzhu/now v1.1.5 // indirect
|
github.com/jinzhu/now v1.1.5 // indirect
|
||||||
|
github.com/josharian/intern v1.0.0 // indirect
|
||||||
github.com/json-iterator/go v1.1.12 // indirect
|
github.com/json-iterator/go v1.1.12 // indirect
|
||||||
github.com/kelindar/simd v1.1.2 // indirect
|
github.com/kelindar/simd v1.1.2 // indirect
|
||||||
github.com/klauspost/compress v1.17.7 // indirect
|
github.com/klauspost/compress v1.17.7 // indirect
|
||||||
@ -126,6 +137,7 @@ require (
|
|||||||
github.com/lithammer/shortuuid v3.0.0+incompatible // indirect
|
github.com/lithammer/shortuuid v3.0.0+incompatible // indirect
|
||||||
github.com/magefile/mage v1.15.0 // indirect
|
github.com/magefile/mage v1.15.0 // indirect
|
||||||
github.com/magiconair/properties v1.8.7 // indirect
|
github.com/magiconair/properties v1.8.7 // indirect
|
||||||
|
github.com/mailru/easyjson v0.7.7 // indirect
|
||||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||||
github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect
|
github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect
|
||||||
github.com/minio/md5-simd v1.1.2 // indirect
|
github.com/minio/md5-simd v1.1.2 // indirect
|
||||||
@ -135,6 +147,7 @@ require (
|
|||||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||||
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe // indirect
|
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe // indirect
|
||||||
github.com/mozillazg/go-httpheader v0.4.0 // indirect
|
github.com/mozillazg/go-httpheader v0.4.0 // indirect
|
||||||
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||||
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
|
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
|
||||||
github.com/pierrec/lz4/v4 v4.1.21 // indirect
|
github.com/pierrec/lz4/v4 v4.1.21 // indirect
|
||||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||||
@ -156,6 +169,7 @@ require (
|
|||||||
github.com/tklauser/go-sysconf v0.3.13 // indirect
|
github.com/tklauser/go-sysconf v0.3.13 // indirect
|
||||||
github.com/tklauser/numcpus v0.7.0 // indirect
|
github.com/tklauser/numcpus v0.7.0 // indirect
|
||||||
github.com/twitchyliquid64/golang-asm v0.15.1 // 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
|
github.com/xdg-go/pbkdf2 v1.0.0 // indirect
|
||||||
github.com/xdg-go/scram v1.1.2 // indirect
|
github.com/xdg-go/scram v1.1.2 // indirect
|
||||||
github.com/xdg-go/stringprep v1.0.4 // indirect
|
github.com/xdg-go/stringprep v1.0.4 // indirect
|
||||||
@ -163,7 +177,6 @@ require (
|
|||||||
github.com/yusufpapurcu/wmi v1.2.4 // indirect
|
github.com/yusufpapurcu/wmi v1.2.4 // indirect
|
||||||
go.etcd.io/etcd/api/v3 v3.5.13 // indirect
|
go.etcd.io/etcd/api/v3 v3.5.13 // indirect
|
||||||
go.etcd.io/etcd/client/pkg/v3 v3.5.13 // indirect
|
go.etcd.io/etcd/client/pkg/v3 v3.5.13 // indirect
|
||||||
go.etcd.io/etcd/client/v3 v3.5.13 // indirect
|
|
||||||
go.opencensus.io v0.24.0 // indirect
|
go.opencensus.io v0.24.0 // indirect
|
||||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 // 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/contrib/instrumentation/net/http/otelhttp v0.49.0 // indirect
|
||||||
@ -173,18 +186,27 @@ require (
|
|||||||
go.uber.org/atomic v1.9.0 // indirect
|
go.uber.org/atomic v1.9.0 // indirect
|
||||||
go.uber.org/multierr v1.11.0 // indirect
|
go.uber.org/multierr v1.11.0 // indirect
|
||||||
golang.org/x/arch v0.7.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/image v0.15.0 // indirect
|
||||||
golang.org/x/net v0.29.0 // indirect
|
golang.org/x/net v0.29.0 // indirect
|
||||||
golang.org/x/oauth2 v0.21.0 // indirect
|
golang.org/x/oauth2 v0.23.0 // indirect
|
||||||
golang.org/x/sys v0.25.0 // indirect
|
golang.org/x/sys v0.25.0 // indirect
|
||||||
|
golang.org/x/term v0.24.0 // indirect
|
||||||
golang.org/x/text v0.18.0 // indirect
|
golang.org/x/text v0.18.0 // indirect
|
||||||
golang.org/x/time v0.5.0 // indirect
|
golang.org/x/time v0.5.0 // indirect
|
||||||
google.golang.org/appengine/v2 v2.0.2 // indirect
|
google.golang.org/appengine/v2 v2.0.2 // indirect
|
||||||
google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9 // indirect
|
google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9 // indirect
|
||||||
google.golang.org/genproto/googleapis/api v0.0.0-20240604185151-ef581f913117 // indirect
|
google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1 // indirect
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 // indirect
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 // indirect
|
||||||
|
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||||
|
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||||
gorm.io/gorm v1.25.8 // indirect
|
gorm.io/gorm v1.25.8 // indirect
|
||||||
stathat.com/c/consistent v1.0.0 // indirect
|
k8s.io/klog/v2 v2.130.1 // indirect
|
||||||
|
k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 // indirect
|
||||||
|
k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 // indirect
|
||||||
|
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
|
||||||
|
sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect
|
||||||
|
sigs.k8s.io/yaml v1.4.0 // indirect
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
155
go.sum
155
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.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 h1:uJSeirPke5UNZHIb4SxfZklVSiWWVqW4oXlETwZziwM=
|
||||||
cloud.google.com/go v0.112.1/go.mod h1:+Vbu+Y1UU+I1rjmzeMOb/8RfkKJK2Gyxi1X6jJCZLo4=
|
cloud.google.com/go v0.112.1/go.mod h1:+Vbu+Y1UU+I1rjmzeMOb/8RfkKJK2Gyxi1X6jJCZLo4=
|
||||||
cloud.google.com/go/compute/metadata v0.3.0 h1:Tz+eQXMEqDIKRsmY3cHTL6FVaynIjX2QxYC4trgAKZc=
|
cloud.google.com/go/compute/metadata v0.5.0 h1:Zr0eK8JbFv6+Wi4ilXAR8FJ3wyNdpxHKJNPos6LTZOY=
|
||||||
cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k=
|
cloud.google.com/go/compute/metadata v0.5.0/go.mod h1:aHnloV2TPI38yx4s9+wAZhHykWvVCfu7hQbF+9CWoiY=
|
||||||
cloud.google.com/go/firestore v1.15.0 h1:/k8ppuWOtNuDHt2tsRV42yI21uaGnKDEQnRFeBpbFF8=
|
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/firestore v1.15.0/go.mod h1:GWOxFXcv8GZUtYpWHw/w6IuYNux/BtmeVTMmjrm4yhk=
|
||||||
cloud.google.com/go/iam v1.1.7 h1:z4VHOhwKLF/+UYXAJDFwGtNF0b6gjsW1Pk9Ml0U/IoM=
|
cloud.google.com/go/iam v1.1.7 h1:z4VHOhwKLF/+UYXAJDFwGtNF0b6gjsW1Pk9Ml0U/IoM=
|
||||||
@ -21,42 +21,42 @@ github.com/MicahParks/keyfunc v1.9.0/go.mod h1:IdnCilugA0O/99dW+/MkvlyrsX8+L8+x9
|
|||||||
github.com/QcloudApi/qcloud_sign_golang v0.0.0-20141224014652-e4130a326409/go.mod h1:1pk82RBxDY/JZnPQrtqHlUFfCctgdorsd9M06fMynOM=
|
github.com/QcloudApi/qcloud_sign_golang v0.0.0-20141224014652-e4130a326409/go.mod h1:1pk82RBxDY/JZnPQrtqHlUFfCctgdorsd9M06fMynOM=
|
||||||
github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible h1:8psS8a+wKfiLt1iVDX79F7Y6wUM49Lcha2FMXt4UM8g=
|
github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible h1:8psS8a+wKfiLt1iVDX79F7Y6wUM49Lcha2FMXt4UM8g=
|
||||||
github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8=
|
github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8=
|
||||||
github.com/aws/aws-sdk-go-v2 v1.23.1 h1:qXaFsOOMA+HsZtX8WoCa+gJnbyW7qyFFBlPqvTSzbaI=
|
github.com/aws/aws-sdk-go-v2 v1.32.5 h1:U8vdWJuY7ruAkzaOdD7guwJjD06YSKmnKCJs7s3IkIo=
|
||||||
github.com/aws/aws-sdk-go-v2 v1.23.1/go.mod h1:i1XDttT4rnf6vxc9AuskLc6s7XBee8rlLilKlc03uAA=
|
github.com/aws/aws-sdk-go-v2 v1.32.5/go.mod h1:P5WJBrYqqbWVaOxgH0X/FYYD47/nooaPOZPlQdmiN2U=
|
||||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.5.1 h1:ZY3108YtBNq96jNZTICHxN1gSBSbnvIdYwwqnvCV4Mc=
|
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.5.1 h1:ZY3108YtBNq96jNZTICHxN1gSBSbnvIdYwwqnvCV4Mc=
|
||||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.5.1/go.mod h1:t8PYl/6LzdAqsU4/9tz28V/kU+asFePvpOMkdul0gEQ=
|
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.5.1/go.mod h1:t8PYl/6LzdAqsU4/9tz28V/kU+asFePvpOMkdul0gEQ=
|
||||||
github.com/aws/aws-sdk-go-v2/config v1.25.4 h1:r+X1x8QI6FEPdJDWCNBDZHyAcyFwSjHN8q8uuus+Axs=
|
github.com/aws/aws-sdk-go-v2/config v1.28.5 h1:Za41twdCXbuyyWv9LndXxZZv3QhTG1DinqlFsSuvtI0=
|
||||||
github.com/aws/aws-sdk-go-v2/config v1.25.4/go.mod h1:8GTjImECskr7D88P/Nn9uM4M4rLY9i77hLJZgkZEWV8=
|
github.com/aws/aws-sdk-go-v2/config v1.28.5/go.mod h1:4VsPbHP8JdcdUDmbTVgNL/8w9SqOkM5jyY8ljIxLO3o=
|
||||||
github.com/aws/aws-sdk-go-v2/credentials v1.16.3 h1:8PeI2krzzjDJ5etmgaMiD1JswsrLrWvKKu/uBUtNy1g=
|
github.com/aws/aws-sdk-go-v2/credentials v1.17.46 h1:AU7RcriIo2lXjUfHFnFKYsLCwgbz1E7Mm95ieIRDNUg=
|
||||||
github.com/aws/aws-sdk-go-v2/credentials v1.16.3/go.mod h1:Kdh/okh+//vQ/AjEt81CjvkTo64+/zIE4OewP7RpfXk=
|
github.com/aws/aws-sdk-go-v2/credentials v1.17.46/go.mod h1:1FmYyLGL08KQXQ6mcTlifyFXfJVCNJTVGuQP4m0d/UA=
|
||||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.5 h1:KehRNiVzIfAcj6gw98zotVbb/K67taJE0fkfgM6vzqU=
|
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.20 h1:sDSXIrlsFSFJtWKLQS4PUWRvrT580rrnuLydJrCQ/yA=
|
||||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.5/go.mod h1:VhnExhw6uXy9QzetvpXDolo1/hjhx4u9qukBGkuUwjs=
|
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.20/go.mod h1:WZ/c+w0ofps+/OUqMwWgnfrgzZH1DZO1RIkktICsqnY=
|
||||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.4 h1:LAm3Ycm9HJfbSCd5I+wqC2S9Ej7FPrgr5CQoOljJZcE=
|
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.24 h1:4usbeaes3yJnCFC7kfeyhkdkPtoRYPa/hTmCqMpKpLI=
|
||||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.4/go.mod h1:xEhvbJcyUf/31yfGSQBe01fukXwXJ0gxDp7rLfymWE0=
|
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.24/go.mod h1:5CI1JemjVwde8m2WG3cz23qHKPOxbpkq0HaoreEgLIY=
|
||||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.4 h1:4GV0kKZzUxiWxSVpn/9gwR0g21NF1Jsyduzo9rHgC/Q=
|
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.24 h1:N1zsICrQglfzaBnrfM0Ys00860C+QFwu6u/5+LomP+o=
|
||||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.4/go.mod h1:dYvTNAggxDZy6y1AF7YDwXsPuHFy/VNEpEI/2dWK9IU=
|
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.24/go.mod h1:dCn9HbJ8+K31i8IQ8EWmWj0EiIk0+vKiHNMxTTYveAg=
|
||||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.7.1 h1:uR9lXYjdPX0xY+NhvaJ4dD8rpSRz5VY81ccIIoNG+lw=
|
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 h1:VaRN3TlFdd6KxX1x3ILT5ynH6HvKgqdiXoTxAF4HQcQ=
|
||||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.7.1/go.mod h1:6fQQgfuGmw8Al/3M2IgIllycxV7ZW7WCdVSqfBeUiCY=
|
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1/go.mod h1:FbtygfRFze9usAadmnGJNc8KsP346kEe+y2/oyhGAGc=
|
||||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.2.4 h1:40Q4X5ebZruRtknEZH/bg91sT5pR853F7/1X9QRbI54=
|
github.com/aws/aws-sdk-go-v2/internal/v4a v1.2.4 h1:40Q4X5ebZruRtknEZH/bg91sT5pR853F7/1X9QRbI54=
|
||||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.2.4/go.mod h1:u77N7eEECzUv7F0xl2gcfK/vzc8wcjWobpy+DcrLJ5E=
|
github.com/aws/aws-sdk-go-v2/internal/v4a v1.2.4/go.mod h1:u77N7eEECzUv7F0xl2gcfK/vzc8wcjWobpy+DcrLJ5E=
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.10.1 h1:rpkF4n0CyFcrJUG/rNNohoTmhtWlFTRI4BsZOh9PvLs=
|
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.1 h1:iXtILhvDxB6kPvEXgsDhGaZCSC6LQET5ZHSdJozeI0Y=
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.10.1/go.mod h1:l9ymW25HOqymeU2m1gbUQ3rUIsTwKs8gYHXkqDQUhiI=
|
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.1/go.mod h1:9nu0fVANtYiAePIBh2/pFUSwtJ402hLnp854CNoDOeE=
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.2.4 h1:6DRKQc+9cChgzL5gplRGusI5dBGeiEod4m/pmGbcX48=
|
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.2.4 h1:6DRKQc+9cChgzL5gplRGusI5dBGeiEod4m/pmGbcX48=
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.2.4/go.mod h1:s8ORvrW4g4v7IvYKIAoBg17w3GQ+XuwXDXYrQ5SkzU0=
|
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.2.4/go.mod h1:s8ORvrW4g4v7IvYKIAoBg17w3GQ+XuwXDXYrQ5SkzU0=
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.4 h1:rdovz3rEu0vZKbzoMYPTehp0E8veoE9AyfzqCr5Eeao=
|
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.5 h1:wtpJ4zcwrSbwhECWQoI/g6WM9zqCcSpHDJIWSbMLOu4=
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.4/go.mod h1:aYCGNjyUCUelhofxlZyj63srdxWUSsBSGg5l6MCuXuE=
|
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.5/go.mod h1:qu/W9HXQbbQ4+1+JcZp0ZNPV31ym537ZJN+fiS7Ti8E=
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.16.4 h1:o3DcfCxGDIT20pTbVKVhp3vWXOj/VvgazNJvumWeYW0=
|
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.16.4 h1:o3DcfCxGDIT20pTbVKVhp3vWXOj/VvgazNJvumWeYW0=
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.16.4/go.mod h1:Uy0KVOxuTK2ne+/PKQ+VvEeWmjMMksE17k/2RK/r5oM=
|
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.16.4/go.mod h1:Uy0KVOxuTK2ne+/PKQ+VvEeWmjMMksE17k/2RK/r5oM=
|
||||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.43.1 h1:1w11lfXOa8HoHoSlNtt4mqv/N3HmDOa+OnUH3Y9DHm8=
|
github.com/aws/aws-sdk-go-v2/service/s3 v1.43.1 h1:1w11lfXOa8HoHoSlNtt4mqv/N3HmDOa+OnUH3Y9DHm8=
|
||||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.43.1/go.mod h1:dqJ5JBL0clzgHriH35Amx3LRFY6wNIPUX7QO/BerSBo=
|
github.com/aws/aws-sdk-go-v2/service/s3 v1.43.1/go.mod h1:dqJ5JBL0clzgHriH35Amx3LRFY6wNIPUX7QO/BerSBo=
|
||||||
github.com/aws/aws-sdk-go-v2/service/sso v1.17.3 h1:CdsSOGlFF3Pn+koXOIpTtvX7st0IuGsZ8kJqcWMlX54=
|
github.com/aws/aws-sdk-go-v2/service/sso v1.24.6 h1:3zu537oLmsPfDMyjnUS2g+F2vITgy5pB74tHI+JBNoM=
|
||||||
github.com/aws/aws-sdk-go-v2/service/sso v1.17.3/go.mod h1:oA6VjNsLll2eVuUoF2D+CMyORgNzPEW/3PyUdq6WQjI=
|
github.com/aws/aws-sdk-go-v2/service/sso v1.24.6/go.mod h1:WJSZH2ZvepM6t6jwu4w/Z45Eoi75lPN7DcydSRtJg6Y=
|
||||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.20.1 h1:cbRqFTVnJV+KRpwFl76GJdIZJKKCdTPnjUZ7uWh3pIU=
|
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.5 h1:K0OQAsDywb0ltlFrZm0JHPY3yZp/S9OaoLU33S7vPS8=
|
||||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.20.1/go.mod h1:hHL974p5auvXlZPIjJTblXJpbkfK4klBczlsEaMCGVY=
|
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.5/go.mod h1:ORITg+fyuMoeiQFiVGoqB3OydVTLkClw/ljbblMq6Cc=
|
||||||
github.com/aws/aws-sdk-go-v2/service/sts v1.25.4 h1:yEvZ4neOQ/KpUqyR+X0ycUTW/kVRNR4nDZ38wStHGAA=
|
github.com/aws/aws-sdk-go-v2/service/sts v1.33.1 h1:6SZUVRQNvExYlMLbHdlKB48x0fLbc2iVROyaNEwBHbU=
|
||||||
github.com/aws/aws-sdk-go-v2/service/sts v1.25.4/go.mod h1:feTnm2Tk/pJxdX+eooEsxvlvTWBvDm6CasRZ+JOs2IY=
|
github.com/aws/aws-sdk-go-v2/service/sts v1.33.1/go.mod h1:GqWyYCwLXnlUB1lOAXQyNSPqPLQJvmo8J0DWBzp9mtg=
|
||||||
github.com/aws/smithy-go v1.17.0 h1:wWJD7LX6PBV6etBUwO0zElG0nWN9rUhp0WdYeHSHAaI=
|
github.com/aws/smithy-go v1.22.1 h1:/HPHZQ0g7f4eUeK6HKglFz8uwVfZKgoI25rb/J+dnro=
|
||||||
github.com/aws/smithy-go v1.17.0/go.mod h1:NukqUGpCZIILqqiV0NIjeFh24kd/FAa4beRb6nbIUPE=
|
github.com/aws/smithy-go v1.22.1/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg=
|
||||||
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
|
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
|
||||||
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
|
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 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||||
@ -103,6 +103,8 @@ 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/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 h1:YOEu7KNc61ntiQlcEeUIoDTJ2o8mQznoNvUhiigpIqc=
|
||||||
github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
|
github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
|
||||||
|
github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g=
|
||||||
|
github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
|
||||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
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.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.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||||
@ -117,6 +119,8 @@ github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHk
|
|||||||
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
|
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
|
||||||
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
|
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
|
||||||
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
|
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
|
||||||
|
github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E=
|
||||||
|
github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ=
|
||||||
github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
|
github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
|
||||||
github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk=
|
github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk=
|
||||||
github.com/gin-contrib/gzip v1.0.1 h1:HQ8ENHODeLY7a4g1Au/46Z92bdGFl74OhxcZble9WJE=
|
github.com/gin-contrib/gzip v1.0.1 h1:HQ8ENHODeLY7a4g1Au/46Z92bdGFl74OhxcZble9WJE=
|
||||||
@ -126,12 +130,19 @@ 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 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg=
|
||||||
github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU=
|
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.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||||
github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
|
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
|
||||||
github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
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-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 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
|
||||||
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
||||||
|
github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE=
|
||||||
|
github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs=
|
||||||
|
github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE=
|
||||||
|
github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k=
|
||||||
|
github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
|
||||||
|
github.com/go-openapi/swag v0.22.4 h1:QLMzNJnMGPRNDCbySlcj1x01tzU8/9LTTL9hZZZogBU=
|
||||||
|
github.com/go-openapi/swag v0.22.4/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
|
||||||
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||||
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
|
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
|
||||||
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||||
@ -150,6 +161,8 @@ github.com/go-redis/redis v6.15.9+incompatible h1:K0pv1D7EQUjfyoMql+r/jZqCLizCGK
|
|||||||
github.com/go-redis/redis v6.15.9+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
|
github.com/go-redis/redis v6.15.9+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
|
||||||
github.com/go-redis/redismock/v9 v9.2.0 h1:ZrMYQeKPECZPjOj5u9eyOjg8Nnb0BS9lkVIZ6IpsKLw=
|
github.com/go-redis/redismock/v9 v9.2.0 h1:ZrMYQeKPECZPjOj5u9eyOjg8Nnb0BS9lkVIZ6IpsKLw=
|
||||||
github.com/go-redis/redismock/v9 v9.2.0/go.mod h1:18KHfGDK4Y6c2R0H38EUGWAdc7ZQS9gfYxc94k7rWT0=
|
github.com/go-redis/redismock/v9 v9.2.0/go.mod h1:18KHfGDK4Y6c2R0H38EUGWAdc7ZQS9gfYxc94k7rWT0=
|
||||||
|
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
|
||||||
|
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
|
||||||
github.com/go-zookeeper/zk v1.0.3 h1:7M2kwOsc//9VeeFiPtf+uSJlVpU66x9Ba5+8XK7/TDg=
|
github.com/go-zookeeper/zk v1.0.3 h1:7M2kwOsc//9VeeFiPtf+uSJlVpU66x9Ba5+8XK7/TDg=
|
||||||
github.com/go-zookeeper/zk v1.0.3/go.mod h1:nOB03cncLtlp4t+UAkGSV+9beXP/akpekBwL+UX1Qcw=
|
github.com/go-zookeeper/zk v1.0.3/go.mod h1:nOB03cncLtlp4t+UAkGSV+9beXP/akpekBwL+UX1Qcw=
|
||||||
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
|
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
|
||||||
@ -158,8 +171,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 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
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.4.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
|
||||||
github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg=
|
github.com/golang-jwt/jwt/v4 v4.5.1 h1:JdqV9zKUdtaa9gdPlywC3aeoEsR681PlKC+4F5gQgeo=
|
||||||
github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
|
github.com/golang-jwt/jwt/v4 v4.5.1/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
|
||||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
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-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
|
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
|
||||||
@ -179,6 +192,8 @@ github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek
|
|||||||
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
||||||
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
|
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
|
||||||
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||||
|
github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I=
|
||||||
|
github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U=
|
||||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
@ -186,14 +201,19 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
|
|||||||
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
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.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 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
|
github.com/google/go-querystring v1.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 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
|
||||||
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
|
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
|
||||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
|
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
|
||||||
|
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
github.com/google/martian/v3 v3.3.2 h1:IqNFLAmvJOgVlpdEBiQbDc2EwKW77amAycfTuWKdfvw=
|
github.com/google/martian/v3 v3.3.2 h1:IqNFLAmvJOgVlpdEBiQbDc2EwKW77amAycfTuWKdfvw=
|
||||||
github.com/google/martian/v3 v3.3.2/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk=
|
github.com/google/martian/v3 v3.3.2/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk=
|
||||||
|
github.com/google/pprof v0.0.0-20240525223248-4bfdf5a9a2af h1:kmjWCqn2qkEml422C2Rrd27c3VGxi6a/6HNq8QmHRKM=
|
||||||
|
github.com/google/pprof v0.0.0-20240525223248-4bfdf5a9a2af/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo=
|
||||||
github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o=
|
github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o=
|
||||||
github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw=
|
github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw=
|
||||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
@ -244,6 +264,8 @@ github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
|
|||||||
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||||
github.com/jonboulle/clockwork v0.4.0 h1:p4Cf1aMWXnXAUh8lVfewRBx1zaTSYKrKMF2g3ST4RZ4=
|
github.com/jonboulle/clockwork v0.4.0 h1:p4Cf1aMWXnXAUh8lVfewRBx1zaTSYKrKMF2g3ST4RZ4=
|
||||||
github.com/jonboulle/clockwork v0.4.0/go.mod h1:xgRqUGwRcjKCO1vbZUEtSLrqKoPSsUpK7fnezOII0kc=
|
github.com/jonboulle/clockwork v0.4.0/go.mod h1:xgRqUGwRcjKCO1vbZUEtSLrqKoPSsUpK7fnezOII0kc=
|
||||||
|
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
|
||||||
|
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
||||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||||
github.com/kelindar/bitmap v1.5.2 h1:XwX7CTvJtetQZ64zrOkApoZZHBJRkjE23NfqUALA/HE=
|
github.com/kelindar/bitmap v1.5.2 h1:XwX7CTvJtetQZ64zrOkApoZZHBJRkjE23NfqUALA/HE=
|
||||||
@ -285,6 +307,8 @@ github.com/magefile/mage v1.15.0 h1:BvGheCMAsG3bWUDbZ8AyXXpCNwU9u5CB6sM+HNb9HYg=
|
|||||||
github.com/magefile/mage v1.15.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A=
|
github.com/magefile/mage v1.15.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A=
|
||||||
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
|
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
|
||||||
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
|
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
|
||||||
|
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
|
||||||
|
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||||
@ -311,18 +335,22 @@ github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJ
|
|||||||
github.com/mozillazg/go-httpheader v0.2.1/go.mod h1:jJ8xECTlalr6ValeXYdOF8fFUISeBAdw6E61aqQma60=
|
github.com/mozillazg/go-httpheader v0.2.1/go.mod h1:jJ8xECTlalr6ValeXYdOF8fFUISeBAdw6E61aqQma60=
|
||||||
github.com/mozillazg/go-httpheader v0.4.0 h1:aBn6aRXtFzyDLZ4VIRLsZbbJloagQfMnCiYgOq6hK4w=
|
github.com/mozillazg/go-httpheader v0.4.0 h1:aBn6aRXtFzyDLZ4VIRLsZbbJloagQfMnCiYgOq6hK4w=
|
||||||
github.com/mozillazg/go-httpheader v0.4.0/go.mod h1:PuT8h0pw6efvp8ZeUec1Rs7dwjK08bt6gKSReGMqtdA=
|
github.com/mozillazg/go-httpheader v0.4.0/go.mod h1:PuT8h0pw6efvp8ZeUec1Rs7dwjK08bt6gKSReGMqtdA=
|
||||||
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
|
||||||
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||||
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
|
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
|
||||||
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
|
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
|
||||||
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
|
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
|
||||||
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
|
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
|
||||||
|
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 h1:Vw7br2PCDYijJHSfBOWhov+8cAnUf8MfMaIOV323l6Y=
|
||||||
github.com/onsi/gomega v1.25.0/go.mod h1:r+zV744Re+DiYCIPRlYOTxn0YkOLcAnW8k1xXdMPGhM=
|
github.com/onsi/gomega v1.25.0/go.mod h1:r+zV744Re+DiYCIPRlYOTxn0YkOLcAnW8k1xXdMPGhM=
|
||||||
github.com/openimsdk/gomake v0.0.14-alpha.5 h1:VY9c5x515lTfmdhhPjMvR3BBRrRquAUCFsz7t7vbv7Y=
|
github.com/openimsdk/gomake v0.0.14-alpha.5 h1:VY9c5x515lTfmdhhPjMvR3BBRrRquAUCFsz7t7vbv7Y=
|
||||||
github.com/openimsdk/gomake v0.0.14-alpha.5/go.mod h1:PndCozNc2IsQIciyn9mvEblYWZwJmAI+06z94EY+csI=
|
github.com/openimsdk/gomake v0.0.14-alpha.5/go.mod h1:PndCozNc2IsQIciyn9mvEblYWZwJmAI+06z94EY+csI=
|
||||||
github.com/openimsdk/protocol v0.0.72 h1:K+vslwaR7lDXyBzb07UuEQITaqsgighz7NyXVIWsu6A=
|
github.com/openimsdk/protocol v0.0.72-alpha.71 h1:R3utzOlqepaJWTAmnfJi4ccUM/XIoFasSyjQMOipM70=
|
||||||
github.com/openimsdk/protocol v0.0.72/go.mod h1:OZQA9FR55lseYoN2Ql1XAHYKHJGu7OMNkUbuekrKCM8=
|
github.com/openimsdk/protocol v0.0.72-alpha.71/go.mod h1:WF7EuE55vQvpyUAzDXcqg+B+446xQyEba0X35lTINmw=
|
||||||
github.com/openimsdk/tools v0.0.50-alpha.16 h1:bC1AQvJMuOHtZm8LZRvN8L5mH1Ws2VYdL+TLTs1iGSc=
|
github.com/openimsdk/tools v0.0.50-alpha.72 h1:d/vaZjIfvrNp3EeRJEIiamBO7HiPx6CP4wiuq8NpfzY=
|
||||||
github.com/openimsdk/tools v0.0.50-alpha.16/go.mod h1:h1cYmfyaVtgFbKmb1Cfsl8XwUOMTt8ubVUQrdGtsUh4=
|
github.com/openimsdk/tools v0.0.50-alpha.72/go.mod h1:B+oqV0zdewN7OiEHYJm+hW+8/Te7B8tHHgD8rK5ZLZk=
|
||||||
github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
|
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/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
|
||||||
github.com/pierrec/lz4/v4 v4.1.21 h1:yOVMLb6qSIDP67pl/5F7RepeKYu/VmTyEXvuMI5d9mQ=
|
github.com/pierrec/lz4/v4 v4.1.21 h1:yOVMLb6qSIDP67pl/5F7RepeKYu/VmTyEXvuMI5d9mQ=
|
||||||
@ -356,8 +384,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/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.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.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
|
||||||
github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
|
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
|
||||||
github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
|
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
|
||||||
github.com/rs/xid v1.5.0 h1:mKX4bl4iPYJtEIxp6CYiUuLQ/8DYMoz0PUdtGgMFRVc=
|
github.com/rs/xid v1.5.0 h1:mKX4bl4iPYJtEIxp6CYiUuLQ/8DYMoz0PUdtGgMFRVc=
|
||||||
github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
|
github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
|
||||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||||
@ -379,8 +407,6 @@ github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
|||||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||||
github.com/spf13/viper v1.18.2 h1:LUXCnvUvSM6FXAsj6nnfc8Q2tp1dIgUfY9Kc8GsSOiQ=
|
github.com/spf13/viper v1.18.2 h1:LUXCnvUvSM6FXAsj6nnfc8Q2tp1dIgUfY9Kc8GsSOiQ=
|
||||||
github.com/spf13/viper v1.18.2/go.mod h1:EKmWIqdnk5lOcmR72yw6hS+8OPYcwD0jteitLMVB+yk=
|
github.com/spf13/viper v1.18.2/go.mod h1:EKmWIqdnk5lOcmR72yw6hS+8OPYcwD0jteitLMVB+yk=
|
||||||
github.com/stathat/consistent v1.0.0 h1:ZFJ1QTRn8npNBKW065raSZ8xfOqhpb8vLOkfp4CcL/U=
|
|
||||||
github.com/stathat/consistent v1.0.0/go.mod h1:uajTPbgSygZBJ+V+0mY7meZ8i0XAcZs7AQ6V121XSxw=
|
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||||
@ -410,6 +436,8 @@ github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS
|
|||||||
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
|
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
|
||||||
github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE=
|
github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE=
|
||||||
github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
|
github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
|
||||||
|
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
|
||||||
|
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
|
||||||
github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c=
|
github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c=
|
||||||
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
|
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
|
||||||
github.com/xdg-go/scram v1.1.2 h1:FHX5I5B4i4hKRVRBCFRxq1iQRej7WO3hhBuJf+UUySY=
|
github.com/xdg-go/scram v1.1.2 h1:FHX5I5B4i4hKRVRBCFRxq1iQRej7WO3hhBuJf+UUySY=
|
||||||
@ -449,8 +477,8 @@ 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/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||||
go.uber.org/automaxprocs v1.5.3 h1:kWazyxZUrS3Gs4qUpbwo5kEIMGe/DAvi5Z4tl2NW4j8=
|
go.uber.org/automaxprocs v1.5.3 h1:kWazyxZUrS3Gs4qUpbwo5kEIMGe/DAvi5Z4tl2NW4j8=
|
||||||
go.uber.org/automaxprocs v1.5.3/go.mod h1:eRbA25aqJrxAbsLO0xy5jVwPt7FQnRgjW+efnwa1WM0=
|
go.uber.org/automaxprocs v1.5.3/go.mod h1:eRbA25aqJrxAbsLO0xy5jVwPt7FQnRgjW+efnwa1WM0=
|
||||||
go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI=
|
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||||
go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
|
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||||
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
||||||
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
||||||
go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60=
|
go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60=
|
||||||
@ -497,8 +525,8 @@ golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
|||||||
golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo=
|
golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo=
|
||||||
golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0=
|
golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0=
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
golang.org/x/oauth2 v0.21.0 h1:tsimM75w1tF/uws5rbeHzIWxEqElMehnc+iW793zsZs=
|
golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs=
|
||||||
golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
|
golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
|
||||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
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-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-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
@ -527,6 +555,8 @@ golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9sn
|
|||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
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.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.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||||
|
golang.org/x/term v0.24.0 h1:Mh5cbb+Zk2hqqXNO7S1iTjEphVL+jb8ZWaqh/g+JWkM=
|
||||||
|
golang.org/x/term v0.24.0/go.mod h1:lOBK/LVxemqiMij05LGJ0tzNr8xlmwBRJ81PX6wVLH8=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
@ -548,6 +578,8 @@ 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-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.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.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/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
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-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-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
@ -565,8 +597,8 @@ 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-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 h1:9+tzLLstTlPTRyJTh+ah5wIMsBW5c4tQwGTN3thOW9Y=
|
||||||
google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9/go.mod h1:mqHbVIp48Muh7Ywss/AD6I5kNVKZMmAa/QEW58Gxp2s=
|
google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9/go.mod h1:mqHbVIp48Muh7Ywss/AD6I5kNVKZMmAa/QEW58Gxp2s=
|
||||||
google.golang.org/genproto/googleapis/api v0.0.0-20240604185151-ef581f913117 h1:+rdxYoE3E5htTEWIe15GlN6IfvbURM//Jt0mmkmm6ZU=
|
google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1 h1:hjSy6tcFQZ171igDaN5QHOw2n6vx40juYbC/x67CEhc=
|
||||||
google.golang.org/genproto/googleapis/api v0.0.0-20240604185151-ef581f913117/go.mod h1:OimBR/bc1wPO9iV4NC2bpyjy3VnAwZh5EBPQdtaE5oo=
|
google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:qpvKtACPCQhAdu3PyQgV4l3LMXZEtft7y8QcarRsp9I=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 h1:pPJltXNxVzT4pK9yD8vR9X75DaWYYmLGMsEvBfFQZzQ=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 h1:pPJltXNxVzT4pK9yD8vR9X75DaWYYmLGMsEvBfFQZzQ=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU=
|
||||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||||
@ -574,8 +606,8 @@ google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyac
|
|||||||
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
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.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||||
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
|
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
|
||||||
google.golang.org/grpc v1.66.2 h1:3QdXkuq3Bkh7w+ywLdLvM56cmGvQHUMZpiCzt6Rqaoo=
|
google.golang.org/grpc v1.68.0 h1:aHQeeJbo8zAkAa3pRzrVjZlbz6uSfeOXlJNQM0RAbz0=
|
||||||
google.golang.org/grpc v1.66.2/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y=
|
google.golang.org/grpc v1.68.0/go.mod h1:fmSPC5AsjSBCK54MyHRx48kpOti1/jRfOlwEWywNjWA=
|
||||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
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-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||||
@ -585,18 +617,21 @@ 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.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.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.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||||
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
|
google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA=
|
||||||
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
|
google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
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-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||||
|
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
|
||||||
|
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
||||||
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
|
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
|
||||||
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
||||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
@ -607,7 +642,23 @@ gorm.io/gorm v1.25.8 h1:WAGEZ/aEcznN4D03laj8DKnehe1e9gYQAjW8xyPRdeo=
|
|||||||
gorm.io/gorm v1.25.8/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
|
gorm.io/gorm v1.25.8/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
|
||||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
k8s.io/api v0.31.2 h1:3wLBbL5Uom/8Zy98GRPXpJ254nEFpl+hwndmk9RwmL0=
|
||||||
|
k8s.io/api v0.31.2/go.mod h1:bWmGvrGPssSK1ljmLzd3pwCQ9MgoTsRCuK35u6SygUk=
|
||||||
|
k8s.io/apimachinery v0.31.2 h1:i4vUt2hPK56W6mlT7Ry+AO8eEsyxMD1U44NR22CLTYw=
|
||||||
|
k8s.io/apimachinery v0.31.2/go.mod h1:rsPdaZJfTfLsNJSQzNHQvYoTmxhoOEofxtOsF3rtsMo=
|
||||||
|
k8s.io/client-go v0.31.2 h1:Y2F4dxU5d3AQj+ybwSMqQnpZH9F30//1ObxOKlTI9yc=
|
||||||
|
k8s.io/client-go v0.31.2/go.mod h1:NPa74jSVR/+eez2dFsEIHNa+3o09vtNaWwWwb1qSxSs=
|
||||||
|
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
|
||||||
|
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
|
||||||
|
k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 h1:BZqlfIlq5YbRMFko6/PM7FjZpUb45WallggurYhKGag=
|
||||||
|
k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340/go.mod h1:yD4MZYeKMBwQKVht279WycxKyM84kkAx2DPrTXaeb98=
|
||||||
|
k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 h1:pUdcCO1Lk/tbT5ztQWOBi5HBgbBP1J8+AsQnQCKsi8A=
|
||||||
|
k8s.io/utils v0.0.0-20240711033017-18e509b52bc8/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
|
||||||
nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
|
nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
|
||||||
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
|
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
|
||||||
stathat.com/c/consistent v1.0.0 h1:ezyc51EGcRPJUxfHGSgJjWzJdj3NiMU9pNfLNGiXV0c=
|
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo=
|
||||||
stathat.com/c/consistent v1.0.0/go.mod h1:QkzMWzcbB+yQBL2AttO6sgsQS/JSTapcDISJalmCDS0=
|
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0=
|
||||||
|
sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4=
|
||||||
|
sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08=
|
||||||
|
sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E=
|
||||||
|
sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY=
|
||||||
|
@ -16,29 +16,30 @@ package api
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
|
|
||||||
"github.com/openimsdk/protocol/auth"
|
"github.com/openimsdk/protocol/auth"
|
||||||
"github.com/openimsdk/tools/a2r"
|
"github.com/openimsdk/tools/a2r"
|
||||||
)
|
)
|
||||||
|
|
||||||
type AuthApi rpcclient.Auth
|
type AuthApi struct {
|
||||||
|
Client auth.AuthClient
|
||||||
|
}
|
||||||
|
|
||||||
func NewAuthApi(client rpcclient.Auth) AuthApi {
|
func NewAuthApi(client auth.AuthClient) AuthApi {
|
||||||
return AuthApi(client)
|
return AuthApi{client}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *AuthApi) GetAdminToken(c *gin.Context) {
|
func (o *AuthApi) GetAdminToken(c *gin.Context) {
|
||||||
a2r.Call(auth.AuthClient.GetAdminToken, o.Client, c)
|
a2r.Call(c, auth.AuthClient.GetAdminToken, o.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *AuthApi) GetUserToken(c *gin.Context) {
|
func (o *AuthApi) GetUserToken(c *gin.Context) {
|
||||||
a2r.Call(auth.AuthClient.GetUserToken, o.Client, c)
|
a2r.Call(c, auth.AuthClient.GetUserToken, o.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *AuthApi) ParseToken(c *gin.Context) {
|
func (o *AuthApi) ParseToken(c *gin.Context) {
|
||||||
a2r.Call(auth.AuthClient.ParseToken, o.Client, c)
|
a2r.Call(c, auth.AuthClient.ParseToken, o.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *AuthApi) ForceLogout(c *gin.Context) {
|
func (o *AuthApi) ForceLogout(c *gin.Context) {
|
||||||
a2r.Call(auth.AuthClient.ForceLogout, o.Client, c)
|
a2r.Call(c, auth.AuthClient.ForceLogout, o.Client)
|
||||||
}
|
}
|
||||||
|
312
internal/api/config_manager.go
Normal file
312
internal/api/config_manager.go
Normal file
@ -0,0 +1,312 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"reflect"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/openimsdk/open-im-server/v3/pkg/apistruct"
|
||||||
|
"github.com/openimsdk/open-im-server/v3/pkg/authverify"
|
||||||
|
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
||||||
|
"github.com/openimsdk/open-im-server/v3/pkg/common/discovery/etcd"
|
||||||
|
"github.com/openimsdk/open-im-server/v3/version"
|
||||||
|
"github.com/openimsdk/tools/apiresp"
|
||||||
|
"github.com/openimsdk/tools/errs"
|
||||||
|
"github.com/openimsdk/tools/log"
|
||||||
|
"github.com/openimsdk/tools/utils/runtimeenv"
|
||||||
|
clientv3 "go.etcd.io/etcd/client/v3"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// wait for Restart http call return
|
||||||
|
waitHttp = time.Millisecond * 200
|
||||||
|
)
|
||||||
|
|
||||||
|
type ConfigManager struct {
|
||||||
|
imAdminUserID []string
|
||||||
|
config *config.AllConfig
|
||||||
|
client *clientv3.Client
|
||||||
|
|
||||||
|
configPath string
|
||||||
|
runtimeEnv string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewConfigManager(IMAdminUserID []string, cfg *config.AllConfig, client *clientv3.Client, configPath string, runtimeEnv string) *ConfigManager {
|
||||||
|
cm := &ConfigManager{
|
||||||
|
imAdminUserID: IMAdminUserID,
|
||||||
|
config: cfg,
|
||||||
|
client: client,
|
||||||
|
configPath: configPath,
|
||||||
|
runtimeEnv: runtimeEnv,
|
||||||
|
}
|
||||||
|
return cm
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cm *ConfigManager) CheckAdmin(c *gin.Context) {
|
||||||
|
if err := authverify.CheckAdmin(c, cm.imAdminUserID); err != nil {
|
||||||
|
apiresp.GinError(c, err)
|
||||||
|
c.Abort()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cm *ConfigManager) GetConfig(c *gin.Context) {
|
||||||
|
var req apistruct.GetConfigReq
|
||||||
|
if err := c.BindJSON(&req); err != nil {
|
||||||
|
apiresp.GinError(c, errs.ErrArgs.WithDetail(err.Error()).Wrap())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
conf := cm.config.Name2Config(req.ConfigName)
|
||||||
|
if conf == nil {
|
||||||
|
apiresp.GinError(c, errs.ErrArgs.WithDetail("config name not found").Wrap())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
b, err := json.Marshal(conf)
|
||||||
|
if err != nil {
|
||||||
|
apiresp.GinError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
apiresp.GinSuccess(c, string(b))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cm *ConfigManager) GetConfigList(c *gin.Context) {
|
||||||
|
var resp apistruct.GetConfigListResp
|
||||||
|
resp.ConfigNames = cm.config.GetConfigNames()
|
||||||
|
resp.Environment = runtimeenv.PrintRuntimeEnvironment()
|
||||||
|
resp.Version = version.Version
|
||||||
|
|
||||||
|
apiresp.GinSuccess(c, resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cm *ConfigManager) SetConfig(c *gin.Context) {
|
||||||
|
if cm.config.Discovery.Enable != config.ETCD {
|
||||||
|
apiresp.GinError(c, errs.New("only etcd support set config").Wrap())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var req apistruct.SetConfigReq
|
||||||
|
if err := c.BindJSON(&req); err != nil {
|
||||||
|
apiresp.GinError(c, errs.ErrArgs.WithDetail(err.Error()).Wrap())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var err error
|
||||||
|
switch req.ConfigName {
|
||||||
|
case cm.config.Discovery.GetConfigFileName():
|
||||||
|
err = compareAndSave[config.Discovery](c, cm.config.Name2Config(req.ConfigName), &req, cm)
|
||||||
|
case cm.config.Kafka.GetConfigFileName():
|
||||||
|
err = compareAndSave[config.Kafka](c, cm.config.Name2Config(req.ConfigName), &req, cm)
|
||||||
|
case cm.config.LocalCache.GetConfigFileName():
|
||||||
|
err = compareAndSave[config.LocalCache](c, cm.config.Name2Config(req.ConfigName), &req, cm)
|
||||||
|
case cm.config.Log.GetConfigFileName():
|
||||||
|
err = compareAndSave[config.Log](c, cm.config.Name2Config(req.ConfigName), &req, cm)
|
||||||
|
case cm.config.Minio.GetConfigFileName():
|
||||||
|
err = compareAndSave[config.Minio](c, cm.config.Name2Config(req.ConfigName), &req, cm)
|
||||||
|
case cm.config.Mongo.GetConfigFileName():
|
||||||
|
err = compareAndSave[config.Mongo](c, cm.config.Name2Config(req.ConfigName), &req, cm)
|
||||||
|
case cm.config.Notification.GetConfigFileName():
|
||||||
|
err = compareAndSave[config.Notification](c, cm.config.Name2Config(req.ConfigName), &req, cm)
|
||||||
|
case cm.config.API.GetConfigFileName():
|
||||||
|
err = compareAndSave[config.API](c, cm.config.Name2Config(req.ConfigName), &req, cm)
|
||||||
|
case cm.config.CronTask.GetConfigFileName():
|
||||||
|
err = compareAndSave[config.CronTask](c, cm.config.Name2Config(req.ConfigName), &req, cm)
|
||||||
|
case cm.config.MsgGateway.GetConfigFileName():
|
||||||
|
err = compareAndSave[config.MsgGateway](c, cm.config.Name2Config(req.ConfigName), &req, cm)
|
||||||
|
case cm.config.MsgTransfer.GetConfigFileName():
|
||||||
|
err = compareAndSave[config.MsgTransfer](c, cm.config.Name2Config(req.ConfigName), &req, cm)
|
||||||
|
case cm.config.Push.GetConfigFileName():
|
||||||
|
err = compareAndSave[config.Push](c, cm.config.Name2Config(req.ConfigName), &req, cm)
|
||||||
|
case cm.config.Auth.GetConfigFileName():
|
||||||
|
err = compareAndSave[config.Auth](c, cm.config.Name2Config(req.ConfigName), &req, cm)
|
||||||
|
case cm.config.Conversation.GetConfigFileName():
|
||||||
|
err = compareAndSave[config.Conversation](c, cm.config.Name2Config(req.ConfigName), &req, cm)
|
||||||
|
case cm.config.Friend.GetConfigFileName():
|
||||||
|
err = compareAndSave[config.Friend](c, cm.config.Name2Config(req.ConfigName), &req, cm)
|
||||||
|
case cm.config.Group.GetConfigFileName():
|
||||||
|
err = compareAndSave[config.Group](c, cm.config.Name2Config(req.ConfigName), &req, cm)
|
||||||
|
case cm.config.Msg.GetConfigFileName():
|
||||||
|
err = compareAndSave[config.Msg](c, cm.config.Name2Config(req.ConfigName), &req, cm)
|
||||||
|
case cm.config.Third.GetConfigFileName():
|
||||||
|
err = compareAndSave[config.Third](c, cm.config.Name2Config(req.ConfigName), &req, cm)
|
||||||
|
case cm.config.User.GetConfigFileName():
|
||||||
|
err = compareAndSave[config.User](c, cm.config.Name2Config(req.ConfigName), &req, cm)
|
||||||
|
case cm.config.Redis.GetConfigFileName():
|
||||||
|
err = compareAndSave[config.Redis](c, cm.config.Name2Config(req.ConfigName), &req, cm)
|
||||||
|
case cm.config.Share.GetConfigFileName():
|
||||||
|
err = compareAndSave[config.Share](c, cm.config.Name2Config(req.ConfigName), &req, cm)
|
||||||
|
case cm.config.Webhooks.GetConfigFileName():
|
||||||
|
err = compareAndSave[config.Webhooks](c, cm.config.Name2Config(req.ConfigName), &req, cm)
|
||||||
|
default:
|
||||||
|
apiresp.GinError(c, errs.ErrArgs.Wrap())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
apiresp.GinError(c, errs.ErrArgs.WithDetail(err.Error()).Wrap())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
apiresp.GinSuccess(c, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func compareAndSave[T any](c *gin.Context, old any, req *apistruct.SetConfigReq, cm *ConfigManager) error {
|
||||||
|
conf := new(T)
|
||||||
|
err := json.Unmarshal([]byte(req.Data), &conf)
|
||||||
|
if err != nil {
|
||||||
|
return errs.ErrArgs.WithDetail(err.Error()).Wrap()
|
||||||
|
}
|
||||||
|
eq := reflect.DeepEqual(old, conf)
|
||||||
|
if eq {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
data, err := json.Marshal(conf)
|
||||||
|
if err != nil {
|
||||||
|
return errs.ErrArgs.WithDetail(err.Error()).Wrap()
|
||||||
|
}
|
||||||
|
_, err = cm.client.Put(c, etcd.BuildKey(req.ConfigName), string(data))
|
||||||
|
if err != nil {
|
||||||
|
return errs.WrapMsg(err, "save to etcd failed")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cm *ConfigManager) ResetConfig(c *gin.Context) {
|
||||||
|
go func() {
|
||||||
|
if err := cm.resetConfig(c, true); err != nil {
|
||||||
|
log.ZError(c, "reset config err", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
apiresp.GinSuccess(c, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cm *ConfigManager) resetConfig(c *gin.Context, checkChange bool, ops ...clientv3.Op) error {
|
||||||
|
txn := cm.client.Txn(c)
|
||||||
|
type initConf struct {
|
||||||
|
old any
|
||||||
|
new any
|
||||||
|
}
|
||||||
|
configMap := map[string]*initConf{
|
||||||
|
cm.config.Discovery.GetConfigFileName(): {old: &cm.config.Discovery, new: new(config.Discovery)},
|
||||||
|
cm.config.Kafka.GetConfigFileName(): {old: &cm.config.Kafka, new: new(config.Kafka)},
|
||||||
|
cm.config.LocalCache.GetConfigFileName(): {old: &cm.config.LocalCache, new: new(config.LocalCache)},
|
||||||
|
cm.config.Log.GetConfigFileName(): {old: &cm.config.Log, new: new(config.Log)},
|
||||||
|
cm.config.Minio.GetConfigFileName(): {old: &cm.config.Minio, new: new(config.Minio)},
|
||||||
|
cm.config.Mongo.GetConfigFileName(): {old: &cm.config.Mongo, new: new(config.Mongo)},
|
||||||
|
cm.config.Notification.GetConfigFileName(): {old: &cm.config.Notification, new: new(config.Notification)},
|
||||||
|
cm.config.API.GetConfigFileName(): {old: &cm.config.API, new: new(config.API)},
|
||||||
|
cm.config.CronTask.GetConfigFileName(): {old: &cm.config.CronTask, new: new(config.CronTask)},
|
||||||
|
cm.config.MsgGateway.GetConfigFileName(): {old: &cm.config.MsgGateway, new: new(config.MsgGateway)},
|
||||||
|
cm.config.MsgTransfer.GetConfigFileName(): {old: &cm.config.MsgTransfer, new: new(config.MsgTransfer)},
|
||||||
|
cm.config.Push.GetConfigFileName(): {old: &cm.config.Push, new: new(config.Push)},
|
||||||
|
cm.config.Auth.GetConfigFileName(): {old: &cm.config.Auth, new: new(config.Auth)},
|
||||||
|
cm.config.Conversation.GetConfigFileName(): {old: &cm.config.Conversation, new: new(config.Conversation)},
|
||||||
|
cm.config.Friend.GetConfigFileName(): {old: &cm.config.Friend, new: new(config.Friend)},
|
||||||
|
cm.config.Group.GetConfigFileName(): {old: &cm.config.Group, new: new(config.Group)},
|
||||||
|
cm.config.Msg.GetConfigFileName(): {old: &cm.config.Msg, new: new(config.Msg)},
|
||||||
|
cm.config.Third.GetConfigFileName(): {old: &cm.config.Third, new: new(config.Third)},
|
||||||
|
cm.config.User.GetConfigFileName(): {old: &cm.config.User, new: new(config.User)},
|
||||||
|
cm.config.Redis.GetConfigFileName(): {old: &cm.config.Redis, new: new(config.Redis)},
|
||||||
|
cm.config.Share.GetConfigFileName(): {old: &cm.config.Share, new: new(config.Share)},
|
||||||
|
cm.config.Webhooks.GetConfigFileName(): {old: &cm.config.Webhooks, new: new(config.Webhooks)},
|
||||||
|
}
|
||||||
|
|
||||||
|
changedKeys := make([]string, 0, len(configMap))
|
||||||
|
for k, v := range configMap {
|
||||||
|
err := config.Load(
|
||||||
|
cm.configPath,
|
||||||
|
k,
|
||||||
|
config.EnvPrefixMap[k],
|
||||||
|
cm.runtimeEnv,
|
||||||
|
v.new,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
log.ZError(c, "load config failed", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
equal := reflect.DeepEqual(v.old, v.new)
|
||||||
|
if !checkChange || !equal {
|
||||||
|
changedKeys = append(changedKeys, k)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, k := range changedKeys {
|
||||||
|
data, err := json.Marshal(configMap[k].new)
|
||||||
|
if err != nil {
|
||||||
|
log.ZError(c, "marshal config failed", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
ops = append(ops, clientv3.OpPut(etcd.BuildKey(k), string(data)))
|
||||||
|
}
|
||||||
|
if len(ops) > 0 {
|
||||||
|
txn.Then(ops...)
|
||||||
|
_, err := txn.Commit()
|
||||||
|
if err != nil {
|
||||||
|
return errs.WrapMsg(err, "commit etcd txn failed")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cm *ConfigManager) Restart(c *gin.Context) {
|
||||||
|
go cm.restart(c)
|
||||||
|
apiresp.GinSuccess(c, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cm *ConfigManager) restart(c *gin.Context) {
|
||||||
|
time.Sleep(waitHttp) // wait for Restart http call return
|
||||||
|
t := time.Now().Unix()
|
||||||
|
_, err := cm.client.Put(c, etcd.BuildKey(etcd.RestartKey), strconv.Itoa(int(t)))
|
||||||
|
if err != nil {
|
||||||
|
log.ZError(c, "restart etcd put key failed", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cm *ConfigManager) SetEnableConfigManager(c *gin.Context) {
|
||||||
|
if cm.config.Discovery.Enable != config.ETCD {
|
||||||
|
apiresp.GinError(c, errs.New("only etcd support config manager").Wrap())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var req apistruct.SetEnableConfigManagerReq
|
||||||
|
if err := c.BindJSON(&req); err != nil {
|
||||||
|
apiresp.GinError(c, errs.ErrArgs.WithDetail(err.Error()).Wrap())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var enableStr string
|
||||||
|
if req.Enable {
|
||||||
|
enableStr = etcd.Enable
|
||||||
|
} else {
|
||||||
|
enableStr = etcd.Disable
|
||||||
|
}
|
||||||
|
resp, err := cm.client.Get(c, etcd.BuildKey(etcd.EnableConfigCenterKey))
|
||||||
|
if err != nil {
|
||||||
|
apiresp.GinError(c, errs.WrapMsg(err, "getEnableConfigManager failed"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !(resp.Count > 0 && string(resp.Kvs[0].Value) == etcd.Enable) && req.Enable {
|
||||||
|
go func() {
|
||||||
|
time.Sleep(waitHttp) // wait for Restart http call return
|
||||||
|
err := cm.resetConfig(c, false, clientv3.OpPut(etcd.BuildKey(etcd.EnableConfigCenterKey), enableStr))
|
||||||
|
if err != nil {
|
||||||
|
log.ZError(c, "resetConfig failed", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
} else {
|
||||||
|
_, err = cm.client.Put(c, etcd.BuildKey(etcd.EnableConfigCenterKey), enableStr)
|
||||||
|
if err != nil {
|
||||||
|
apiresp.GinError(c, errs.WrapMsg(err, "setEnableConfigManager failed"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
apiresp.GinSuccess(c, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cm *ConfigManager) GetEnableConfigManager(c *gin.Context) {
|
||||||
|
resp, err := cm.client.Get(c, etcd.BuildKey(etcd.EnableConfigCenterKey))
|
||||||
|
if err != nil {
|
||||||
|
apiresp.GinError(c, errs.WrapMsg(err, "getEnableConfigManager failed"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var enable bool
|
||||||
|
if resp.Count > 0 && string(resp.Kvs[0].Value) == etcd.Enable {
|
||||||
|
enable = true
|
||||||
|
}
|
||||||
|
apiresp.GinSuccess(c, &apistruct.GetEnableConfigManagerResp{Enable: enable})
|
||||||
|
}
|
@ -16,57 +16,58 @@ package api
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
|
|
||||||
"github.com/openimsdk/protocol/conversation"
|
"github.com/openimsdk/protocol/conversation"
|
||||||
"github.com/openimsdk/tools/a2r"
|
"github.com/openimsdk/tools/a2r"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ConversationApi rpcclient.Conversation
|
type ConversationApi struct {
|
||||||
|
Client conversation.ConversationClient
|
||||||
|
}
|
||||||
|
|
||||||
func NewConversationApi(client rpcclient.Conversation) ConversationApi {
|
func NewConversationApi(client conversation.ConversationClient) ConversationApi {
|
||||||
return ConversationApi(client)
|
return ConversationApi{client}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *ConversationApi) GetAllConversations(c *gin.Context) {
|
func (o *ConversationApi) GetAllConversations(c *gin.Context) {
|
||||||
a2r.Call(conversation.ConversationClient.GetAllConversations, o.Client, c)
|
a2r.Call(c, conversation.ConversationClient.GetAllConversations, o.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *ConversationApi) GetSortedConversationList(c *gin.Context) {
|
func (o *ConversationApi) GetSortedConversationList(c *gin.Context) {
|
||||||
a2r.Call(conversation.ConversationClient.GetSortedConversationList, o.Client, c)
|
a2r.Call(c, conversation.ConversationClient.GetSortedConversationList, o.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *ConversationApi) GetConversation(c *gin.Context) {
|
func (o *ConversationApi) GetConversation(c *gin.Context) {
|
||||||
a2r.Call(conversation.ConversationClient.GetConversation, o.Client, c)
|
a2r.Call(c, conversation.ConversationClient.GetConversation, o.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *ConversationApi) GetConversations(c *gin.Context) {
|
func (o *ConversationApi) GetConversations(c *gin.Context) {
|
||||||
a2r.Call(conversation.ConversationClient.GetConversations, o.Client, c)
|
a2r.Call(c, conversation.ConversationClient.GetConversations, o.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *ConversationApi) SetConversations(c *gin.Context) {
|
func (o *ConversationApi) SetConversations(c *gin.Context) {
|
||||||
a2r.Call(conversation.ConversationClient.SetConversations, o.Client, c)
|
a2r.Call(c, conversation.ConversationClient.SetConversations, o.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *ConversationApi) GetConversationOfflinePushUserIDs(c *gin.Context) {
|
func (o *ConversationApi) GetConversationOfflinePushUserIDs(c *gin.Context) {
|
||||||
a2r.Call(conversation.ConversationClient.GetConversationOfflinePushUserIDs, o.Client, c)
|
a2r.Call(c, conversation.ConversationClient.GetConversationOfflinePushUserIDs, o.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *ConversationApi) GetFullOwnerConversationIDs(c *gin.Context) {
|
func (o *ConversationApi) GetFullOwnerConversationIDs(c *gin.Context) {
|
||||||
a2r.Call(conversation.ConversationClient.GetFullOwnerConversationIDs, o.Client, c)
|
a2r.Call(c, conversation.ConversationClient.GetFullOwnerConversationIDs, o.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *ConversationApi) GetIncrementalConversation(c *gin.Context) {
|
func (o *ConversationApi) GetIncrementalConversation(c *gin.Context) {
|
||||||
a2r.Call(conversation.ConversationClient.GetIncrementalConversation, o.Client, c)
|
a2r.Call(c, conversation.ConversationClient.GetIncrementalConversation, o.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *ConversationApi) GetOwnerConversation(c *gin.Context) {
|
func (o *ConversationApi) GetOwnerConversation(c *gin.Context) {
|
||||||
a2r.Call(conversation.ConversationClient.GetOwnerConversation, o.Client, c)
|
a2r.Call(c, conversation.ConversationClient.GetOwnerConversation, o.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *ConversationApi) GetNotNotifyConversationIDs(c *gin.Context) {
|
func (o *ConversationApi) GetNotNotifyConversationIDs(c *gin.Context) {
|
||||||
a2r.Call(conversation.ConversationClient.GetNotNotifyConversationIDs, o.Client, c)
|
a2r.Call(c, conversation.ConversationClient.GetNotNotifyConversationIDs, o.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *ConversationApi) GetPinnedConversationIDs(c *gin.Context) {
|
func (o *ConversationApi) GetPinnedConversationIDs(c *gin.Context) {
|
||||||
a2r.Call(conversation.ConversationClient.GetPinnedConversationIDs, o.Client, c)
|
a2r.Call(c, conversation.ConversationClient.GetPinnedConversationIDs, o.Client)
|
||||||
}
|
}
|
||||||
|
@ -17,99 +17,100 @@ package api
|
|||||||
import (
|
import (
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
|
|
||||||
"github.com/openimsdk/protocol/relation"
|
"github.com/openimsdk/protocol/relation"
|
||||||
"github.com/openimsdk/tools/a2r"
|
"github.com/openimsdk/tools/a2r"
|
||||||
)
|
)
|
||||||
|
|
||||||
type FriendApi rpcclient.Friend
|
type FriendApi struct {
|
||||||
|
Client relation.FriendClient
|
||||||
|
}
|
||||||
|
|
||||||
func NewFriendApi(client rpcclient.Friend) FriendApi {
|
func NewFriendApi(client relation.FriendClient) FriendApi {
|
||||||
return FriendApi(client)
|
return FriendApi{client}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *FriendApi) ApplyToAddFriend(c *gin.Context) {
|
func (o *FriendApi) ApplyToAddFriend(c *gin.Context) {
|
||||||
a2r.Call(relation.FriendClient.ApplyToAddFriend, o.Client, c)
|
a2r.Call(c, relation.FriendClient.ApplyToAddFriend, o.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *FriendApi) RespondFriendApply(c *gin.Context) {
|
func (o *FriendApi) RespondFriendApply(c *gin.Context) {
|
||||||
a2r.Call(relation.FriendClient.RespondFriendApply, o.Client, c)
|
a2r.Call(c, relation.FriendClient.RespondFriendApply, o.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *FriendApi) DeleteFriend(c *gin.Context) {
|
func (o *FriendApi) DeleteFriend(c *gin.Context) {
|
||||||
a2r.Call(relation.FriendClient.DeleteFriend, o.Client, c)
|
a2r.Call(c, relation.FriendClient.DeleteFriend, o.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *FriendApi) GetFriendApplyList(c *gin.Context) {
|
func (o *FriendApi) GetFriendApplyList(c *gin.Context) {
|
||||||
a2r.Call(relation.FriendClient.GetPaginationFriendsApplyTo, o.Client, c)
|
a2r.Call(c, relation.FriendClient.GetPaginationFriendsApplyTo, o.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *FriendApi) GetDesignatedFriendsApply(c *gin.Context) {
|
func (o *FriendApi) GetDesignatedFriendsApply(c *gin.Context) {
|
||||||
a2r.Call(relation.FriendClient.GetDesignatedFriendsApply, o.Client, c)
|
a2r.Call(c, relation.FriendClient.GetDesignatedFriendsApply, o.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *FriendApi) GetSelfApplyList(c *gin.Context) {
|
func (o *FriendApi) GetSelfApplyList(c *gin.Context) {
|
||||||
a2r.Call(relation.FriendClient.GetPaginationFriendsApplyFrom, o.Client, c)
|
a2r.Call(c, relation.FriendClient.GetPaginationFriendsApplyFrom, o.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *FriendApi) GetFriendList(c *gin.Context) {
|
func (o *FriendApi) GetFriendList(c *gin.Context) {
|
||||||
a2r.Call(relation.FriendClient.GetPaginationFriends, o.Client, c)
|
a2r.Call(c, relation.FriendClient.GetPaginationFriends, o.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *FriendApi) GetDesignatedFriends(c *gin.Context) {
|
func (o *FriendApi) GetDesignatedFriends(c *gin.Context) {
|
||||||
a2r.Call(relation.FriendClient.GetDesignatedFriends, o.Client, c)
|
a2r.Call(c, relation.FriendClient.GetDesignatedFriends, o.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *FriendApi) SetFriendRemark(c *gin.Context) {
|
func (o *FriendApi) SetFriendRemark(c *gin.Context) {
|
||||||
a2r.Call(relation.FriendClient.SetFriendRemark, o.Client, c)
|
a2r.Call(c, relation.FriendClient.SetFriendRemark, o.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *FriendApi) AddBlack(c *gin.Context) {
|
func (o *FriendApi) AddBlack(c *gin.Context) {
|
||||||
a2r.Call(relation.FriendClient.AddBlack, o.Client, c)
|
a2r.Call(c, relation.FriendClient.AddBlack, o.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *FriendApi) GetPaginationBlacks(c *gin.Context) {
|
func (o *FriendApi) GetPaginationBlacks(c *gin.Context) {
|
||||||
a2r.Call(relation.FriendClient.GetPaginationBlacks, o.Client, c)
|
a2r.Call(c, relation.FriendClient.GetPaginationBlacks, o.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *FriendApi) GetSpecifiedBlacks(c *gin.Context) {
|
func (o *FriendApi) GetSpecifiedBlacks(c *gin.Context) {
|
||||||
a2r.Call(relation.FriendClient.GetSpecifiedBlacks, o.Client, c)
|
a2r.Call(c, relation.FriendClient.GetSpecifiedBlacks, o.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *FriendApi) RemoveBlack(c *gin.Context) {
|
func (o *FriendApi) RemoveBlack(c *gin.Context) {
|
||||||
a2r.Call(relation.FriendClient.RemoveBlack, o.Client, c)
|
a2r.Call(c, relation.FriendClient.RemoveBlack, o.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *FriendApi) ImportFriends(c *gin.Context) {
|
func (o *FriendApi) ImportFriends(c *gin.Context) {
|
||||||
a2r.Call(relation.FriendClient.ImportFriends, o.Client, c)
|
a2r.Call(c, relation.FriendClient.ImportFriends, o.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *FriendApi) IsFriend(c *gin.Context) {
|
func (o *FriendApi) IsFriend(c *gin.Context) {
|
||||||
a2r.Call(relation.FriendClient.IsFriend, o.Client, c)
|
a2r.Call(c, relation.FriendClient.IsFriend, o.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *FriendApi) GetFriendIDs(c *gin.Context) {
|
func (o *FriendApi) GetFriendIDs(c *gin.Context) {
|
||||||
a2r.Call(relation.FriendClient.GetFriendIDs, o.Client, c)
|
a2r.Call(c, relation.FriendClient.GetFriendIDs, o.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *FriendApi) GetSpecifiedFriendsInfo(c *gin.Context) {
|
func (o *FriendApi) GetSpecifiedFriendsInfo(c *gin.Context) {
|
||||||
a2r.Call(relation.FriendClient.GetSpecifiedFriendsInfo, o.Client, c)
|
a2r.Call(c, relation.FriendClient.GetSpecifiedFriendsInfo, o.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *FriendApi) UpdateFriends(c *gin.Context) {
|
func (o *FriendApi) UpdateFriends(c *gin.Context) {
|
||||||
a2r.Call(relation.FriendClient.UpdateFriends, o.Client, c)
|
a2r.Call(c, relation.FriendClient.UpdateFriends, o.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *FriendApi) GetIncrementalFriends(c *gin.Context) {
|
func (o *FriendApi) GetIncrementalFriends(c *gin.Context) {
|
||||||
a2r.Call(relation.FriendClient.GetIncrementalFriends, o.Client, c)
|
a2r.Call(c, relation.FriendClient.GetIncrementalFriends, o.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetIncrementalBlacks is temporarily unused.
|
// GetIncrementalBlacks is temporarily unused.
|
||||||
// Deprecated: This function is currently unused and may be removed in future versions.
|
// Deprecated: This function is currently unused and may be removed in future versions.
|
||||||
func (o *FriendApi) GetIncrementalBlacks(c *gin.Context) {
|
func (o *FriendApi) GetIncrementalBlacks(c *gin.Context) {
|
||||||
a2r.Call(relation.FriendClient.GetIncrementalBlacks, o.Client, c)
|
a2r.Call(c, relation.FriendClient.GetIncrementalBlacks, o.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *FriendApi) GetFullFriendUserIDs(c *gin.Context) {
|
func (o *FriendApi) GetFullFriendUserIDs(c *gin.Context) {
|
||||||
a2r.Call(relation.FriendClient.GetFullFriendUserIDs, o.Client, c)
|
a2r.Call(c, relation.FriendClient.GetFullFriendUserIDs, o.Client)
|
||||||
}
|
}
|
||||||
|
@ -16,151 +16,152 @@ package api
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
|
|
||||||
"github.com/openimsdk/protocol/group"
|
"github.com/openimsdk/protocol/group"
|
||||||
"github.com/openimsdk/tools/a2r"
|
"github.com/openimsdk/tools/a2r"
|
||||||
)
|
)
|
||||||
|
|
||||||
type GroupApi rpcclient.Group
|
type GroupApi struct {
|
||||||
|
Client group.GroupClient
|
||||||
|
}
|
||||||
|
|
||||||
func NewGroupApi(client rpcclient.Group) GroupApi {
|
func NewGroupApi(client group.GroupClient) GroupApi {
|
||||||
return GroupApi(client)
|
return GroupApi{client}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *GroupApi) CreateGroup(c *gin.Context) {
|
func (o *GroupApi) CreateGroup(c *gin.Context) {
|
||||||
a2r.Call(group.GroupClient.CreateGroup, o.Client, c)
|
a2r.Call(c, group.GroupClient.CreateGroup, o.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *GroupApi) SetGroupInfo(c *gin.Context) {
|
func (o *GroupApi) SetGroupInfo(c *gin.Context) {
|
||||||
a2r.Call(group.GroupClient.SetGroupInfo, o.Client, c)
|
a2r.Call(c, group.GroupClient.SetGroupInfo, o.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *GroupApi) SetGroupInfoEx(c *gin.Context) {
|
func (o *GroupApi) SetGroupInfoEx(c *gin.Context) {
|
||||||
a2r.Call(group.GroupClient.SetGroupInfoEx, o.Client, c)
|
a2r.Call(c, group.GroupClient.SetGroupInfoEx, o.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *GroupApi) JoinGroup(c *gin.Context) {
|
func (o *GroupApi) JoinGroup(c *gin.Context) {
|
||||||
a2r.Call(group.GroupClient.JoinGroup, o.Client, c)
|
a2r.Call(c, group.GroupClient.JoinGroup, o.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *GroupApi) QuitGroup(c *gin.Context) {
|
func (o *GroupApi) QuitGroup(c *gin.Context) {
|
||||||
a2r.Call(group.GroupClient.QuitGroup, o.Client, c)
|
a2r.Call(c, group.GroupClient.QuitGroup, o.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *GroupApi) ApplicationGroupResponse(c *gin.Context) {
|
func (o *GroupApi) ApplicationGroupResponse(c *gin.Context) {
|
||||||
a2r.Call(group.GroupClient.GroupApplicationResponse, o.Client, c)
|
a2r.Call(c, group.GroupClient.GroupApplicationResponse, o.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *GroupApi) TransferGroupOwner(c *gin.Context) {
|
func (o *GroupApi) TransferGroupOwner(c *gin.Context) {
|
||||||
a2r.Call(group.GroupClient.TransferGroupOwner, o.Client, c)
|
a2r.Call(c, group.GroupClient.TransferGroupOwner, o.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *GroupApi) GetRecvGroupApplicationList(c *gin.Context) {
|
func (o *GroupApi) GetRecvGroupApplicationList(c *gin.Context) {
|
||||||
a2r.Call(group.GroupClient.GetGroupApplicationList, o.Client, c)
|
a2r.Call(c, group.GroupClient.GetGroupApplicationList, o.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *GroupApi) GetUserReqGroupApplicationList(c *gin.Context) {
|
func (o *GroupApi) GetUserReqGroupApplicationList(c *gin.Context) {
|
||||||
a2r.Call(group.GroupClient.GetUserReqApplicationList, o.Client, c)
|
a2r.Call(c, group.GroupClient.GetUserReqApplicationList, o.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *GroupApi) GetGroupUsersReqApplicationList(c *gin.Context) {
|
func (o *GroupApi) GetGroupUsersReqApplicationList(c *gin.Context) {
|
||||||
a2r.Call(group.GroupClient.GetGroupUsersReqApplicationList, o.Client, c)
|
a2r.Call(c, group.GroupClient.GetGroupUsersReqApplicationList, o.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *GroupApi) GetSpecifiedUserGroupRequestInfo(c *gin.Context) {
|
func (o *GroupApi) GetSpecifiedUserGroupRequestInfo(c *gin.Context) {
|
||||||
a2r.Call(group.GroupClient.GetSpecifiedUserGroupRequestInfo, o.Client, c)
|
a2r.Call(c, group.GroupClient.GetSpecifiedUserGroupRequestInfo, o.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *GroupApi) GetGroupsInfo(c *gin.Context) {
|
func (o *GroupApi) GetGroupsInfo(c *gin.Context) {
|
||||||
a2r.Call(group.GroupClient.GetGroupsInfo, o.Client, c)
|
a2r.Call(c, group.GroupClient.GetGroupsInfo, o.Client)
|
||||||
//a2r.Call(group.GroupClient.GetGroupsInfo, o.Client, c, a2r.NewNilReplaceOption(group.GroupClient.GetGroupsInfo))
|
//a2r.Call(c, group.GroupClient.GetGroupsInfo, o.Client, c, a2r.NewNilReplaceOption(group.GroupClient.GetGroupsInfo))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *GroupApi) KickGroupMember(c *gin.Context) {
|
func (o *GroupApi) KickGroupMember(c *gin.Context) {
|
||||||
a2r.Call(group.GroupClient.KickGroupMember, o.Client, c)
|
a2r.Call(c, group.GroupClient.KickGroupMember, o.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *GroupApi) GetGroupMembersInfo(c *gin.Context) {
|
func (o *GroupApi) GetGroupMembersInfo(c *gin.Context) {
|
||||||
a2r.Call(group.GroupClient.GetGroupMembersInfo, o.Client, c)
|
a2r.Call(c, group.GroupClient.GetGroupMembersInfo, o.Client)
|
||||||
//a2r.Call(group.GroupClient.GetGroupMembersInfo, o.Client, c, a2r.NewNilReplaceOption(group.GroupClient.GetGroupMembersInfo))
|
//a2r.Call(c, group.GroupClient.GetGroupMembersInfo, o.Client, c, a2r.NewNilReplaceOption(group.GroupClient.GetGroupMembersInfo))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *GroupApi) GetGroupMemberList(c *gin.Context) {
|
func (o *GroupApi) GetGroupMemberList(c *gin.Context) {
|
||||||
a2r.Call(group.GroupClient.GetGroupMemberList, o.Client, c)
|
a2r.Call(c, group.GroupClient.GetGroupMemberList, o.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *GroupApi) InviteUserToGroup(c *gin.Context) {
|
func (o *GroupApi) InviteUserToGroup(c *gin.Context) {
|
||||||
a2r.Call(group.GroupClient.InviteUserToGroup, o.Client, c)
|
a2r.Call(c, group.GroupClient.InviteUserToGroup, o.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *GroupApi) GetJoinedGroupList(c *gin.Context) {
|
func (o *GroupApi) GetJoinedGroupList(c *gin.Context) {
|
||||||
a2r.Call(group.GroupClient.GetJoinedGroupList, o.Client, c)
|
a2r.Call(c, group.GroupClient.GetJoinedGroupList, o.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *GroupApi) DismissGroup(c *gin.Context) {
|
func (o *GroupApi) DismissGroup(c *gin.Context) {
|
||||||
a2r.Call(group.GroupClient.DismissGroup, o.Client, c)
|
a2r.Call(c, group.GroupClient.DismissGroup, o.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *GroupApi) MuteGroupMember(c *gin.Context) {
|
func (o *GroupApi) MuteGroupMember(c *gin.Context) {
|
||||||
a2r.Call(group.GroupClient.MuteGroupMember, o.Client, c)
|
a2r.Call(c, group.GroupClient.MuteGroupMember, o.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *GroupApi) CancelMuteGroupMember(c *gin.Context) {
|
func (o *GroupApi) CancelMuteGroupMember(c *gin.Context) {
|
||||||
a2r.Call(group.GroupClient.CancelMuteGroupMember, o.Client, c)
|
a2r.Call(c, group.GroupClient.CancelMuteGroupMember, o.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *GroupApi) MuteGroup(c *gin.Context) {
|
func (o *GroupApi) MuteGroup(c *gin.Context) {
|
||||||
a2r.Call(group.GroupClient.MuteGroup, o.Client, c)
|
a2r.Call(c, group.GroupClient.MuteGroup, o.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *GroupApi) CancelMuteGroup(c *gin.Context) {
|
func (o *GroupApi) CancelMuteGroup(c *gin.Context) {
|
||||||
a2r.Call(group.GroupClient.CancelMuteGroup, o.Client, c)
|
a2r.Call(c, group.GroupClient.CancelMuteGroup, o.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *GroupApi) SetGroupMemberInfo(c *gin.Context) {
|
func (o *GroupApi) SetGroupMemberInfo(c *gin.Context) {
|
||||||
a2r.Call(group.GroupClient.SetGroupMemberInfo, o.Client, c)
|
a2r.Call(c, group.GroupClient.SetGroupMemberInfo, o.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *GroupApi) GetGroupAbstractInfo(c *gin.Context) {
|
func (o *GroupApi) GetGroupAbstractInfo(c *gin.Context) {
|
||||||
a2r.Call(group.GroupClient.GetGroupAbstractInfo, o.Client, c)
|
a2r.Call(c, group.GroupClient.GetGroupAbstractInfo, o.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
// func (g *Group) SetGroupMemberNickname(c *gin.Context) {
|
// func (g *Group) SetGroupMemberNickname(c *gin.Context) {
|
||||||
// a2r.Call(group.GroupClient.SetGroupMemberNickname, g.userClient, c)
|
// a2r.Call(c, group.GroupClient.SetGroupMemberNickname, g.userClient)
|
||||||
//}
|
//}
|
||||||
//
|
//
|
||||||
// func (g *Group) GetGroupAllMemberList(c *gin.Context) {
|
// func (g *Group) GetGroupAllMemberList(c *gin.Context) {
|
||||||
// a2r.Call(group.GroupClient.GetGroupAllMember, g.userClient, c)
|
// a2r.Call(c, group.GroupClient.GetGroupAllMember, g.userClient)
|
||||||
//}
|
//}
|
||||||
|
|
||||||
func (o *GroupApi) GroupCreateCount(c *gin.Context) {
|
func (o *GroupApi) GroupCreateCount(c *gin.Context) {
|
||||||
a2r.Call(group.GroupClient.GroupCreateCount, o.Client, c)
|
a2r.Call(c, group.GroupClient.GroupCreateCount, o.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *GroupApi) GetGroups(c *gin.Context) {
|
func (o *GroupApi) GetGroups(c *gin.Context) {
|
||||||
a2r.Call(group.GroupClient.GetGroups, o.Client, c)
|
a2r.Call(c, group.GroupClient.GetGroups, o.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *GroupApi) GetGroupMemberUserIDs(c *gin.Context) {
|
func (o *GroupApi) GetGroupMemberUserIDs(c *gin.Context) {
|
||||||
a2r.Call(group.GroupClient.GetGroupMemberUserIDs, o.Client, c)
|
a2r.Call(c, group.GroupClient.GetGroupMemberUserIDs, o.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *GroupApi) GetIncrementalJoinGroup(c *gin.Context) {
|
func (o *GroupApi) GetIncrementalJoinGroup(c *gin.Context) {
|
||||||
a2r.Call(group.GroupClient.GetIncrementalJoinGroup, o.Client, c)
|
a2r.Call(c, group.GroupClient.GetIncrementalJoinGroup, o.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *GroupApi) GetIncrementalGroupMember(c *gin.Context) {
|
func (o *GroupApi) GetIncrementalGroupMember(c *gin.Context) {
|
||||||
a2r.Call(group.GroupClient.GetIncrementalGroupMember, o.Client, c)
|
a2r.Call(c, group.GroupClient.GetIncrementalGroupMember, o.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *GroupApi) GetIncrementalGroupMemberBatch(c *gin.Context) {
|
func (o *GroupApi) GetIncrementalGroupMemberBatch(c *gin.Context) {
|
||||||
a2r.Call(group.GroupClient.BatchGetIncrementalGroupMember, o.Client, c)
|
a2r.Call(c, group.GroupClient.BatchGetIncrementalGroupMember, o.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *GroupApi) GetFullGroupMemberUserIDs(c *gin.Context) {
|
func (o *GroupApi) GetFullGroupMemberUserIDs(c *gin.Context) {
|
||||||
a2r.Call(group.GroupClient.GetFullGroupMemberUserIDs, o.Client, c)
|
a2r.Call(c, group.GroupClient.GetFullGroupMemberUserIDs, o.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *GroupApi) GetFullJoinGroupIDs(c *gin.Context) {
|
func (o *GroupApi) GetFullJoinGroupIDs(c *gin.Context) {
|
||||||
a2r.Call(group.GroupClient.GetFullJoinGroupIDs, o.Client, c)
|
a2r.Call(c, group.GroupClient.GetFullJoinGroupIDs, o.Client)
|
||||||
}
|
}
|
||||||
|
@ -16,10 +16,8 @@ package api
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
|
||||||
"github.com/openimsdk/tools/utils/datautil"
|
|
||||||
"github.com/openimsdk/tools/utils/network"
|
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
@ -28,18 +26,28 @@ import (
|
|||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
kdisc "github.com/openimsdk/open-im-server/v3/pkg/common/discoveryregister"
|
conf "github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
||||||
|
kdisc "github.com/openimsdk/open-im-server/v3/pkg/common/discovery"
|
||||||
|
disetcd "github.com/openimsdk/open-im-server/v3/pkg/common/discovery/etcd"
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics"
|
"github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics"
|
||||||
"github.com/openimsdk/tools/discovery"
|
"github.com/openimsdk/tools/discovery/etcd"
|
||||||
"github.com/openimsdk/tools/errs"
|
"github.com/openimsdk/tools/errs"
|
||||||
"github.com/openimsdk/tools/log"
|
"github.com/openimsdk/tools/log"
|
||||||
|
"github.com/openimsdk/tools/mw"
|
||||||
"github.com/openimsdk/tools/system/program"
|
"github.com/openimsdk/tools/system/program"
|
||||||
|
"github.com/openimsdk/tools/utils/datautil"
|
||||||
|
"github.com/openimsdk/tools/utils/jsonutil"
|
||||||
|
"github.com/openimsdk/tools/utils/network"
|
||||||
|
"github.com/openimsdk/tools/utils/runtimeenv"
|
||||||
|
"google.golang.org/grpc"
|
||||||
|
"google.golang.org/grpc/credentials/insecure"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
API config.API
|
*conf.AllConfig
|
||||||
Share config.Share
|
|
||||||
Discovery config.Discovery
|
RuntimeEnv string
|
||||||
|
ConfigPath string
|
||||||
}
|
}
|
||||||
|
|
||||||
func Start(ctx context.Context, index int, config *Config) error {
|
func Start(ctx context.Context, index int, config *Config) error {
|
||||||
@ -48,13 +56,15 @@ func Start(ctx context.Context, index int, config *Config) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
var client discovery.SvcDiscoveryRegistry
|
config.RuntimeEnv = runtimeenv.PrintRuntimeEnvironment()
|
||||||
|
|
||||||
// Determine whether zk is passed according to whether it is a clustered deployment
|
client, err := kdisc.NewDiscoveryRegister(&config.Discovery, config.RuntimeEnv, []string{
|
||||||
client, err = kdisc.NewDiscoveryRegister(&config.Discovery, &config.Share)
|
config.Discovery.RpcService.MessageGateway,
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errs.WrapMsg(err, "failed to register discovery service")
|
return errs.WrapMsg(err, "failed to register discovery service")
|
||||||
}
|
}
|
||||||
|
client.AddOption(mw.GrpcClient(), grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithDefaultServiceConfig(fmt.Sprintf(`{"LoadBalancingPolicy": "%s"}`, "round_robin")))
|
||||||
|
|
||||||
var (
|
var (
|
||||||
netDone = make(chan struct{}, 1)
|
netDone = make(chan struct{}, 1)
|
||||||
@ -62,16 +72,60 @@ func Start(ctx context.Context, index int, config *Config) error {
|
|||||||
prometheusPort int
|
prometheusPort int
|
||||||
)
|
)
|
||||||
|
|
||||||
router := newGinRouter(client, config)
|
registerIP, err := network.GetRpcRegisterIP("")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
getAutoPort := func() (net.Listener, int, error) {
|
||||||
|
registerAddr := net.JoinHostPort(registerIP, "0")
|
||||||
|
listener, err := net.Listen("tcp", registerAddr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, errs.WrapMsg(err, "listen err", "registerAddr", registerAddr)
|
||||||
|
}
|
||||||
|
_, portStr, _ := net.SplitHostPort(listener.Addr().String())
|
||||||
|
port, _ := strconv.Atoi(portStr)
|
||||||
|
return listener, port, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if config.API.Prometheus.AutoSetPorts && config.Discovery.Enable != conf.ETCD {
|
||||||
|
return errs.New("only etcd support autoSetPorts", "RegisterName", "api").Wrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
router, err := newGinRouter(ctx, client, config)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
if config.API.Prometheus.Enable {
|
if config.API.Prometheus.Enable {
|
||||||
go func() {
|
var (
|
||||||
|
listener net.Listener
|
||||||
|
)
|
||||||
|
|
||||||
|
if config.API.Prometheus.AutoSetPorts {
|
||||||
|
listener, prometheusPort, err = getAutoPort()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
etcdClient := client.(*etcd.SvcDiscoveryRegistryImpl).GetClient()
|
||||||
|
|
||||||
|
_, err = etcdClient.Put(ctx, prommetrics.BuildDiscoveryKey(prommetrics.APIKeyName), jsonutil.StructToJsonString(prommetrics.BuildDefaultTarget(registerIP, prometheusPort)))
|
||||||
|
if err != nil {
|
||||||
|
return errs.WrapMsg(err, "etcd put err")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
prometheusPort, err = datautil.GetElemByIndex(config.API.Prometheus.Ports, index)
|
prometheusPort, err = datautil.GetElemByIndex(config.API.Prometheus.Ports, index)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
netErr = err
|
return err
|
||||||
netDone <- struct{}{}
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
if err := prommetrics.ApiInit(prometheusPort); err != nil && err != http.ErrServerClosed {
|
listener, err = net.Listen("tcp", fmt.Sprintf(":%d", prometheusPort))
|
||||||
|
if err != nil {
|
||||||
|
return errs.WrapMsg(err, "listen err", "addr", fmt.Sprintf(":%d", prometheusPort))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
if err := prommetrics.ApiInit(listener); err != nil && !errors.Is(err, http.ErrServerClosed) {
|
||||||
netErr = errs.WrapMsg(err, fmt.Sprintf("api prometheus start err: %d", prometheusPort))
|
netErr = errs.WrapMsg(err, fmt.Sprintf("api prometheus start err: %d", prometheusPort))
|
||||||
netDone <- struct{}{}
|
netDone <- struct{}{}
|
||||||
}
|
}
|
||||||
@ -81,28 +135,39 @@ func Start(ctx context.Context, index int, config *Config) error {
|
|||||||
address := net.JoinHostPort(network.GetListenIP(config.API.Api.ListenIP), strconv.Itoa(apiPort))
|
address := net.JoinHostPort(network.GetListenIP(config.API.Api.ListenIP), strconv.Itoa(apiPort))
|
||||||
|
|
||||||
server := http.Server{Addr: address, Handler: router}
|
server := http.Server{Addr: address, Handler: router}
|
||||||
log.CInfo(ctx, "API server is initializing", "address", address, "apiPort", apiPort, "prometheusPort", prometheusPort)
|
log.CInfo(ctx, "API server is initializing", "runtimeEnv", config.RuntimeEnv, "address", address, "apiPort", apiPort, "prometheusPort", prometheusPort)
|
||||||
go func() {
|
go func() {
|
||||||
err = server.ListenAndServe()
|
err = server.ListenAndServe()
|
||||||
if err != nil && err != http.ErrServerClosed {
|
if err != nil && !errors.Is(err, http.ErrServerClosed) {
|
||||||
netErr = errs.WrapMsg(err, fmt.Sprintf("api start err: %s", server.Addr))
|
netErr = errs.WrapMsg(err, fmt.Sprintf("api start err: %s", server.Addr))
|
||||||
netDone <- struct{}{}
|
netDone <- struct{}{}
|
||||||
|
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
if config.Discovery.Enable == conf.ETCD {
|
||||||
|
cm := disetcd.NewConfigManager(client.(*etcd.SvcDiscoveryRegistryImpl).GetClient(), config.GetConfigNames())
|
||||||
|
cm.Watch(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
sigs := make(chan os.Signal, 1)
|
sigs := make(chan os.Signal, 1)
|
||||||
signal.Notify(sigs, syscall.SIGTERM)
|
signal.Notify(sigs, syscall.SIGTERM)
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
|
shutdown := func() error {
|
||||||
defer cancel()
|
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
|
||||||
select {
|
defer cancel()
|
||||||
case <-sigs:
|
|
||||||
program.SIGTERMExit()
|
|
||||||
err := server.Shutdown(ctx)
|
err := server.Shutdown(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errs.WrapMsg(err, "shutdown err")
|
return errs.WrapMsg(err, "shutdown err")
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
disetcd.RegisterShutDown(shutdown)
|
||||||
|
select {
|
||||||
|
case <-sigs:
|
||||||
|
program.SIGTERMExit()
|
||||||
|
if err := shutdown(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
case <-netDone:
|
case <-netDone:
|
||||||
close(netDone)
|
close(netDone)
|
||||||
return netErr
|
return netErr
|
||||||
|
@ -1,14 +1,18 @@
|
|||||||
package jssdk
|
package jssdk
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
"github.com/openimsdk/open-im-server/v3/pkg/rpcli"
|
||||||
|
"sort"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/openimsdk/protocol/conversation"
|
"github.com/openimsdk/protocol/conversation"
|
||||||
|
"github.com/openimsdk/protocol/jssdk"
|
||||||
"github.com/openimsdk/protocol/msg"
|
"github.com/openimsdk/protocol/msg"
|
||||||
|
"github.com/openimsdk/protocol/relation"
|
||||||
"github.com/openimsdk/protocol/sdkws"
|
"github.com/openimsdk/protocol/sdkws"
|
||||||
"github.com/openimsdk/tools/a2r"
|
|
||||||
"github.com/openimsdk/tools/mcontext"
|
"github.com/openimsdk/tools/mcontext"
|
||||||
"github.com/openimsdk/tools/utils/datautil"
|
"github.com/openimsdk/tools/utils/datautil"
|
||||||
"sort"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -16,16 +20,23 @@ const (
|
|||||||
defaultGetActiveConversation = 100
|
defaultGetActiveConversation = 100
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewJSSdkApi(msg msg.MsgClient, conv conversation.ConversationClient) *JSSdk {
|
func NewJSSdkApi(userClient *rpcli.UserClient, relationClient *rpcli.RelationClient, groupClient *rpcli.GroupClient,
|
||||||
|
conversationClient *rpcli.ConversationClient, msgClient *rpcli.MsgClient) *JSSdk {
|
||||||
return &JSSdk{
|
return &JSSdk{
|
||||||
msg: msg,
|
userClient: userClient,
|
||||||
conv: conv,
|
relationClient: relationClient,
|
||||||
|
groupClient: groupClient,
|
||||||
|
conversationClient: conversationClient,
|
||||||
|
msgClient: msgClient,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type JSSdk struct {
|
type JSSdk struct {
|
||||||
msg msg.MsgClient
|
userClient *rpcli.UserClient
|
||||||
conv conversation.ConversationClient
|
relationClient *rpcli.RelationClient
|
||||||
|
groupClient *rpcli.GroupClient
|
||||||
|
conversationClient *rpcli.ConversationClient
|
||||||
|
msgClient *rpcli.MsgClient
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *JSSdk) GetActiveConversations(c *gin.Context) {
|
func (x *JSSdk) GetActiveConversations(c *gin.Context) {
|
||||||
@ -36,75 +47,110 @@ func (x *JSSdk) GetConversations(c *gin.Context) {
|
|||||||
call(c, x.getConversations)
|
call(c, x.getConversations)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *JSSdk) getActiveConversations(ctx *gin.Context) (*ConversationsResp, error) {
|
func (x *JSSdk) fillConversations(ctx context.Context, conversations []*jssdk.ConversationMsg) error {
|
||||||
req, err := a2r.ParseRequest[ActiveConversationsReq](ctx)
|
if len(conversations) == 0 {
|
||||||
if err != nil {
|
return nil
|
||||||
return nil, err
|
|
||||||
}
|
}
|
||||||
|
var (
|
||||||
|
userIDs []string
|
||||||
|
groupIDs []string
|
||||||
|
)
|
||||||
|
for _, c := range conversations {
|
||||||
|
if c.Conversation.GroupID == "" {
|
||||||
|
userIDs = append(userIDs, c.Conversation.UserID)
|
||||||
|
} else {
|
||||||
|
groupIDs = append(groupIDs, c.Conversation.GroupID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var (
|
||||||
|
userMap map[string]*sdkws.UserInfo
|
||||||
|
friendMap map[string]*relation.FriendInfoOnly
|
||||||
|
groupMap map[string]*sdkws.GroupInfo
|
||||||
|
)
|
||||||
|
if len(userIDs) > 0 {
|
||||||
|
users, err := x.userClient.GetUsersInfo(ctx, userIDs)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
friends, err := x.relationClient.GetFriendsInfo(ctx, conversations[0].Conversation.OwnerUserID, userIDs)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
userMap = datautil.SliceToMap(users, (*sdkws.UserInfo).GetUserID)
|
||||||
|
friendMap = datautil.SliceToMap(friends, (*relation.FriendInfoOnly).GetFriendUserID)
|
||||||
|
}
|
||||||
|
if len(groupIDs) > 0 {
|
||||||
|
groups, err := x.groupClient.GetGroupsInfo(ctx, groupIDs)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
groupMap = datautil.SliceToMap(groups, (*sdkws.GroupInfo).GetGroupID)
|
||||||
|
}
|
||||||
|
for _, c := range conversations {
|
||||||
|
if c.Conversation.GroupID == "" {
|
||||||
|
c.User = userMap[c.Conversation.UserID]
|
||||||
|
c.Friend = friendMap[c.Conversation.UserID]
|
||||||
|
} else {
|
||||||
|
c.Group = groupMap[c.Conversation.GroupID]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *JSSdk) getActiveConversations(ctx context.Context, req *jssdk.GetActiveConversationsReq) (*jssdk.GetActiveConversationsResp, error) {
|
||||||
if req.Count <= 0 || req.Count > maxGetActiveConversation {
|
if req.Count <= 0 || req.Count > maxGetActiveConversation {
|
||||||
req.Count = defaultGetActiveConversation
|
req.Count = defaultGetActiveConversation
|
||||||
}
|
}
|
||||||
opUserID := mcontext.GetOpUserID(ctx)
|
req.OwnerUserID = mcontext.GetOpUserID(ctx)
|
||||||
conversationIDs, err := field(ctx, x.conv.GetConversationIDs,
|
conversationIDs, err := x.conversationClient.GetConversationIDs(ctx, req.OwnerUserID)
|
||||||
&conversation.GetConversationIDsReq{UserID: opUserID}, (*conversation.GetConversationIDsResp).GetConversationIDs)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if len(conversationIDs) == 0 {
|
if len(conversationIDs) == 0 {
|
||||||
return &ConversationsResp{}, nil
|
return &jssdk.GetActiveConversationsResp{}, nil
|
||||||
}
|
}
|
||||||
readSeq, err := field(ctx, x.msg.GetHasReadSeqs,
|
readSeq, err := x.msgClient.GetHasReadSeqs(ctx, conversationIDs, req.OwnerUserID)
|
||||||
&msg.GetHasReadSeqsReq{UserID: opUserID, ConversationIDs: conversationIDs}, (*msg.SeqsInfoResp).GetMaxSeqs)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
activeConversation, err := field(ctx, x.msg.GetActiveConversation,
|
activeConversation, err := x.msgClient.GetActiveConversation(ctx, conversationIDs)
|
||||||
&msg.GetActiveConversationReq{ConversationIDs: conversationIDs}, (*msg.GetActiveConversationResp).GetConversations)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if len(activeConversation) == 0 {
|
if len(activeConversation) == 0 {
|
||||||
return &ConversationsResp{}, nil
|
return &jssdk.GetActiveConversationsResp{}, nil
|
||||||
}
|
}
|
||||||
sortConversations := sortActiveConversations{
|
sortConversations := sortActiveConversations{
|
||||||
Conversation: activeConversation,
|
Conversation: activeConversation,
|
||||||
}
|
}
|
||||||
if len(activeConversation) > 1 {
|
if len(activeConversation) > 1 {
|
||||||
pinnedConversationIDs, err := field(ctx, x.conv.GetPinnedConversationIDs,
|
pinnedConversationIDs, err := x.conversationClient.GetPinnedConversationIDs(ctx, req.OwnerUserID)
|
||||||
&conversation.GetPinnedConversationIDsReq{UserID: opUserID}, (*conversation.GetPinnedConversationIDsResp).GetConversationIDs)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
sortConversations.PinnedConversationIDs = datautil.SliceSet(pinnedConversationIDs)
|
sortConversations.PinnedConversationIDs = datautil.SliceSet(pinnedConversationIDs)
|
||||||
}
|
}
|
||||||
sort.Sort(&sortConversations)
|
sort.Sort(&sortConversations)
|
||||||
sortList := sortConversations.Top(req.Count)
|
sortList := sortConversations.Top(int(req.Count))
|
||||||
conversations, err := field(ctx, x.conv.GetConversations,
|
conversations, err := x.conversationClient.GetConversations(ctx, datautil.Slice(sortList, func(c *msg.ActiveConversation) string {
|
||||||
&conversation.GetConversationsReq{
|
return c.ConversationID
|
||||||
OwnerUserID: opUserID,
|
}), req.OwnerUserID)
|
||||||
ConversationIDs: datautil.Slice(sortList, func(c *msg.ActiveConversation) string {
|
|
||||||
return c.ConversationID
|
|
||||||
})}, (*conversation.GetConversationsResp).GetConversations)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
msgs, err := field(ctx, x.msg.GetSeqMessage,
|
msgs, err := x.msgClient.GetSeqMessage(ctx, req.OwnerUserID, datautil.Slice(sortList, func(c *msg.ActiveConversation) *msg.ConversationSeqs {
|
||||||
&msg.GetSeqMessageReq{
|
return &msg.ConversationSeqs{
|
||||||
UserID: opUserID,
|
ConversationID: c.ConversationID,
|
||||||
Conversations: datautil.Slice(sortList, func(c *msg.ActiveConversation) *msg.ConversationSeqs {
|
Seqs: []int64{c.MaxSeq},
|
||||||
return &msg.ConversationSeqs{
|
}
|
||||||
ConversationID: c.ConversationID,
|
}))
|
||||||
Seqs: []int64{c.MaxSeq},
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
}, (*msg.GetSeqMessageResp).GetMsgs)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
conversationMap := datautil.SliceToMap(conversations, func(c *conversation.Conversation) string {
|
conversationMap := datautil.SliceToMap(conversations, func(c *conversation.Conversation) string {
|
||||||
return c.ConversationID
|
return c.ConversationID
|
||||||
})
|
})
|
||||||
resp := make([]ConversationMsg, 0, len(sortList))
|
resp := make([]*jssdk.ConversationMsg, 0, len(sortList))
|
||||||
for _, c := range sortList {
|
for _, c := range sortList {
|
||||||
conv, ok := conversationMap[c.ConversationID]
|
conv, ok := conversationMap[c.ConversationID]
|
||||||
if !ok {
|
if !ok {
|
||||||
@ -114,13 +160,16 @@ func (x *JSSdk) getActiveConversations(ctx *gin.Context) (*ConversationsResp, er
|
|||||||
if msgList, ok := msgs[c.ConversationID]; ok && len(msgList.Msgs) > 0 {
|
if msgList, ok := msgs[c.ConversationID]; ok && len(msgList.Msgs) > 0 {
|
||||||
lastMsg = msgList.Msgs[0]
|
lastMsg = msgList.Msgs[0]
|
||||||
}
|
}
|
||||||
resp = append(resp, ConversationMsg{
|
resp = append(resp, &jssdk.ConversationMsg{
|
||||||
Conversation: conv,
|
Conversation: conv,
|
||||||
LastMsg: lastMsg,
|
LastMsg: lastMsg,
|
||||||
MaxSeq: c.MaxSeq,
|
MaxSeq: c.MaxSeq,
|
||||||
ReadSeq: readSeq[c.ConversationID],
|
ReadSeq: readSeq[c.ConversationID],
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
if err := x.fillConversations(ctx, resp); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
var unreadCount int64
|
var unreadCount int64
|
||||||
for _, c := range activeConversation {
|
for _, c := range activeConversation {
|
||||||
count := c.MaxSeq - readSeq[c.ConversationID]
|
count := c.MaxSeq - readSeq[c.ConversationID]
|
||||||
@ -128,35 +177,29 @@ func (x *JSSdk) getActiveConversations(ctx *gin.Context) (*ConversationsResp, er
|
|||||||
unreadCount += count
|
unreadCount += count
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return &ConversationsResp{
|
return &jssdk.GetActiveConversationsResp{
|
||||||
Conversations: resp,
|
Conversations: resp,
|
||||||
UnreadCount: unreadCount,
|
UnreadCount: unreadCount,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *JSSdk) getConversations(ctx *gin.Context) (*ConversationsResp, error) {
|
func (x *JSSdk) getConversations(ctx context.Context, req *jssdk.GetConversationsReq) (*jssdk.GetConversationsResp, error) {
|
||||||
req, err := a2r.ParseRequest[conversation.GetConversationsReq](ctx)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
req.OwnerUserID = mcontext.GetOpUserID(ctx)
|
req.OwnerUserID = mcontext.GetOpUserID(ctx)
|
||||||
conversations, err := field(ctx, x.conv.GetConversations, req, (*conversation.GetConversationsResp).GetConversations)
|
conversations, err := x.conversationClient.GetConversations(ctx, req.ConversationIDs, req.OwnerUserID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if len(conversations) == 0 {
|
if len(conversations) == 0 {
|
||||||
return &ConversationsResp{}, nil
|
return &jssdk.GetConversationsResp{}, nil
|
||||||
}
|
}
|
||||||
req.ConversationIDs = datautil.Slice(conversations, func(c *conversation.Conversation) string {
|
req.ConversationIDs = datautil.Slice(conversations, func(c *conversation.Conversation) string {
|
||||||
return c.ConversationID
|
return c.ConversationID
|
||||||
})
|
})
|
||||||
maxSeqs, err := field(ctx, x.msg.GetMaxSeqs,
|
maxSeqs, err := x.msgClient.GetMaxSeqs(ctx, req.ConversationIDs)
|
||||||
&msg.GetMaxSeqsReq{ConversationIDs: req.ConversationIDs}, (*msg.SeqsInfoResp).GetMaxSeqs)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
readSeqs, err := field(ctx, x.msg.GetHasReadSeqs,
|
readSeqs, err := x.msgClient.GetHasReadSeqs(ctx, req.ConversationIDs, req.OwnerUserID)
|
||||||
&msg.GetHasReadSeqsReq{UserID: req.OwnerUserID, ConversationIDs: req.ConversationIDs}, (*msg.SeqsInfoResp).GetMaxSeqs)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -171,25 +214,27 @@ func (x *JSSdk) getConversations(ctx *gin.Context) (*ConversationsResp, error) {
|
|||||||
}
|
}
|
||||||
var msgs map[string]*sdkws.PullMsgs
|
var msgs map[string]*sdkws.PullMsgs
|
||||||
if len(conversationSeqs) > 0 {
|
if len(conversationSeqs) > 0 {
|
||||||
msgs, err = field(ctx, x.msg.GetSeqMessage,
|
msgs, err = x.msgClient.GetSeqMessage(ctx, req.OwnerUserID, conversationSeqs)
|
||||||
&msg.GetSeqMessageReq{UserID: req.OwnerUserID, Conversations: conversationSeqs}, (*msg.GetSeqMessageResp).GetMsgs)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
resp := make([]ConversationMsg, 0, len(conversations))
|
resp := make([]*jssdk.ConversationMsg, 0, len(conversations))
|
||||||
for _, c := range conversations {
|
for _, c := range conversations {
|
||||||
var lastMsg *sdkws.MsgData
|
var lastMsg *sdkws.MsgData
|
||||||
if msgList, ok := msgs[c.ConversationID]; ok && len(msgList.Msgs) > 0 {
|
if msgList, ok := msgs[c.ConversationID]; ok && len(msgList.Msgs) > 0 {
|
||||||
lastMsg = msgList.Msgs[0]
|
lastMsg = msgList.Msgs[0]
|
||||||
}
|
}
|
||||||
resp = append(resp, ConversationMsg{
|
resp = append(resp, &jssdk.ConversationMsg{
|
||||||
Conversation: c,
|
Conversation: c,
|
||||||
LastMsg: lastMsg,
|
LastMsg: lastMsg,
|
||||||
MaxSeq: maxSeqs[c.ConversationID],
|
MaxSeq: maxSeqs[c.ConversationID],
|
||||||
ReadSeq: readSeqs[c.ConversationID],
|
ReadSeq: readSeqs[c.ConversationID],
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
if err := x.fillConversations(ctx, resp); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
var unreadCount int64
|
var unreadCount int64
|
||||||
for conversationID, maxSeq := range maxSeqs {
|
for conversationID, maxSeq := range maxSeqs {
|
||||||
count := maxSeq - readSeqs[conversationID]
|
count := maxSeq - readSeqs[conversationID]
|
||||||
@ -197,7 +242,7 @@ func (x *JSSdk) getConversations(ctx *gin.Context) (*ConversationsResp, error) {
|
|||||||
unreadCount += count
|
unreadCount += count
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return &ConversationsResp{
|
return &jssdk.GetConversationsResp{
|
||||||
Conversations: resp,
|
Conversations: resp,
|
||||||
UnreadCount: unreadCount,
|
UnreadCount: unreadCount,
|
||||||
}, nil
|
}, nil
|
||||||
|
@ -1,22 +0,0 @@
|
|||||||
package jssdk
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/openimsdk/protocol/conversation"
|
|
||||||
"github.com/openimsdk/protocol/sdkws"
|
|
||||||
)
|
|
||||||
|
|
||||||
type ActiveConversationsReq struct {
|
|
||||||
Count int `json:"count"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type ConversationMsg struct {
|
|
||||||
Conversation *conversation.Conversation `json:"conversation"`
|
|
||||||
LastMsg *sdkws.MsgData `json:"lastMsg"`
|
|
||||||
MaxSeq int64 `json:"maxSeq"`
|
|
||||||
ReadSeq int64 `json:"readSeq"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type ConversationsResp struct {
|
|
||||||
UnreadCount int64 `json:"unreadCount"`
|
|
||||||
Conversations []ConversationMsg `json:"conversations"`
|
|
||||||
}
|
|
@ -2,9 +2,16 @@ package jssdk
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"io"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/openimsdk/tools/a2r"
|
||||||
"github.com/openimsdk/tools/apiresp"
|
"github.com/openimsdk/tools/apiresp"
|
||||||
|
"github.com/openimsdk/tools/checker"
|
||||||
|
"github.com/openimsdk/tools/errs"
|
||||||
"google.golang.org/grpc"
|
"google.golang.org/grpc"
|
||||||
|
"google.golang.org/protobuf/proto"
|
||||||
)
|
)
|
||||||
|
|
||||||
func field[A, B, C any](ctx context.Context, fn func(ctx context.Context, req *A, opts ...grpc.CallOption) (*B, error), req *A, get func(*B) C) (C, error) {
|
func field[A, B, C any](ctx context.Context, fn func(ctx context.Context, req *A, opts ...grpc.CallOption) (*B, error), req *A, get func(*B) C) (C, error) {
|
||||||
@ -16,11 +23,56 @@ func field[A, B, C any](ctx context.Context, fn func(ctx context.Context, req *A
|
|||||||
return get(resp), nil
|
return get(resp), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func call[R any](c *gin.Context, fn func(ctx *gin.Context) (R, error)) {
|
func call[A, B any](c *gin.Context, fn func(ctx context.Context, req *A) (*B, error)) {
|
||||||
resp, err := fn(c)
|
var isJSON bool
|
||||||
|
switch contentType := c.GetHeader("Content-Type"); {
|
||||||
|
case contentType == "":
|
||||||
|
isJSON = true
|
||||||
|
case strings.Contains(contentType, "application/json"):
|
||||||
|
isJSON = true
|
||||||
|
case strings.Contains(contentType, "application/protobuf"):
|
||||||
|
case strings.Contains(contentType, "application/x-protobuf"):
|
||||||
|
default:
|
||||||
|
apiresp.GinError(c, errs.ErrArgs.WrapMsg("unsupported content type"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var req *A
|
||||||
|
if isJSON {
|
||||||
|
var err error
|
||||||
|
req, err = a2r.ParseRequest[A](c)
|
||||||
|
if err != nil {
|
||||||
|
apiresp.GinError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
body, err := io.ReadAll(c.Request.Body)
|
||||||
|
if err != nil {
|
||||||
|
apiresp.GinError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
req = new(A)
|
||||||
|
if err := proto.Unmarshal(body, any(req).(proto.Message)); err != nil {
|
||||||
|
apiresp.GinError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := checker.Validate(&req); err != nil {
|
||||||
|
apiresp.GinError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
resp, err := fn(c, req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
apiresp.GinError(c, err)
|
apiresp.GinError(c, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
apiresp.GinSuccess(c, resp)
|
if isJSON {
|
||||||
|
apiresp.GinSuccess(c, resp)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
body, err := proto.Marshal(any(resp).(proto.Message))
|
||||||
|
if err != nil {
|
||||||
|
apiresp.GinError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
apiresp.GinSuccess(c, body)
|
||||||
}
|
}
|
||||||
|
@ -1,37 +0,0 @@
|
|||||||
package api
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/openimsdk/protocol/msg"
|
|
||||||
"sort"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestName(t *testing.T) {
|
|
||||||
val := sortActiveConversations{
|
|
||||||
Conversation: []*msg.ActiveConversation{
|
|
||||||
{
|
|
||||||
ConversationID: "100",
|
|
||||||
LastTime: 100,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
ConversationID: "200",
|
|
||||||
LastTime: 200,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
ConversationID: "300",
|
|
||||||
LastTime: 300,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
ConversationID: "400",
|
|
||||||
LastTime: 400,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
//PinnedConversationIDs: map[string]struct{}{
|
|
||||||
// "100": {},
|
|
||||||
// "300": {},
|
|
||||||
//},
|
|
||||||
}
|
|
||||||
sort.Sort(&val)
|
|
||||||
t.Log(val)
|
|
||||||
|
|
||||||
}
|
|
@ -21,7 +21,7 @@ import (
|
|||||||
"github.com/openimsdk/open-im-server/v3/pkg/apistruct"
|
"github.com/openimsdk/open-im-server/v3/pkg/apistruct"
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/authverify"
|
"github.com/openimsdk/open-im-server/v3/pkg/authverify"
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
|
"github.com/openimsdk/open-im-server/v3/pkg/rpcli"
|
||||||
"github.com/openimsdk/protocol/constant"
|
"github.com/openimsdk/protocol/constant"
|
||||||
"github.com/openimsdk/protocol/msg"
|
"github.com/openimsdk/protocol/msg"
|
||||||
"github.com/openimsdk/protocol/sdkws"
|
"github.com/openimsdk/protocol/sdkws"
|
||||||
@ -37,16 +37,14 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type MessageApi struct {
|
type MessageApi struct {
|
||||||
*rpcclient.Message
|
Client msg.MsgClient
|
||||||
validate *validator.Validate
|
userClient *rpcli.UserClient
|
||||||
userRpcClient *rpcclient.UserRpcClient
|
|
||||||
imAdminUserID []string
|
imAdminUserID []string
|
||||||
|
validate *validator.Validate
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewMessageApi(msgRpcClient *rpcclient.Message, userRpcClient *rpcclient.User,
|
func NewMessageApi(client msg.MsgClient, userClient *rpcli.UserClient, imAdminUserID []string) MessageApi {
|
||||||
imAdminUserID []string) MessageApi {
|
return MessageApi{Client: client, userClient: userClient, imAdminUserID: imAdminUserID, validate: validator.New()}
|
||||||
return MessageApi{Message: msgRpcClient, validate: validator.New(),
|
|
||||||
userRpcClient: rpcclient.NewUserRpcClientByUser(userRpcClient), imAdminUserID: imAdminUserID}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (*MessageApi) SetOptions(options map[string]bool, value bool) {
|
func (*MessageApi) SetOptions(options map[string]bool, value bool) {
|
||||||
@ -108,51 +106,51 @@ func (m *MessageApi) newUserSendMsgReq(_ *gin.Context, params *apistruct.SendMsg
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *MessageApi) GetSeq(c *gin.Context) {
|
func (m *MessageApi) GetSeq(c *gin.Context) {
|
||||||
a2r.Call(msg.MsgClient.GetMaxSeq, m.Client, c)
|
a2r.Call(c, msg.MsgClient.GetMaxSeq, m.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MessageApi) PullMsgBySeqs(c *gin.Context) {
|
func (m *MessageApi) PullMsgBySeqs(c *gin.Context) {
|
||||||
a2r.Call(msg.MsgClient.PullMessageBySeqs, m.Client, c)
|
a2r.Call(c, msg.MsgClient.PullMessageBySeqs, m.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MessageApi) RevokeMsg(c *gin.Context) {
|
func (m *MessageApi) RevokeMsg(c *gin.Context) {
|
||||||
a2r.Call(msg.MsgClient.RevokeMsg, m.Client, c)
|
a2r.Call(c, msg.MsgClient.RevokeMsg, m.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MessageApi) MarkMsgsAsRead(c *gin.Context) {
|
func (m *MessageApi) MarkMsgsAsRead(c *gin.Context) {
|
||||||
a2r.Call(msg.MsgClient.MarkMsgsAsRead, m.Client, c)
|
a2r.Call(c, msg.MsgClient.MarkMsgsAsRead, m.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MessageApi) MarkConversationAsRead(c *gin.Context) {
|
func (m *MessageApi) MarkConversationAsRead(c *gin.Context) {
|
||||||
a2r.Call(msg.MsgClient.MarkConversationAsRead, m.Client, c)
|
a2r.Call(c, msg.MsgClient.MarkConversationAsRead, m.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MessageApi) GetConversationsHasReadAndMaxSeq(c *gin.Context) {
|
func (m *MessageApi) GetConversationsHasReadAndMaxSeq(c *gin.Context) {
|
||||||
a2r.Call(msg.MsgClient.GetConversationsHasReadAndMaxSeq, m.Client, c)
|
a2r.Call(c, msg.MsgClient.GetConversationsHasReadAndMaxSeq, m.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MessageApi) SetConversationHasReadSeq(c *gin.Context) {
|
func (m *MessageApi) SetConversationHasReadSeq(c *gin.Context) {
|
||||||
a2r.Call(msg.MsgClient.SetConversationHasReadSeq, m.Client, c)
|
a2r.Call(c, msg.MsgClient.SetConversationHasReadSeq, m.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MessageApi) ClearConversationsMsg(c *gin.Context) {
|
func (m *MessageApi) ClearConversationsMsg(c *gin.Context) {
|
||||||
a2r.Call(msg.MsgClient.ClearConversationsMsg, m.Client, c)
|
a2r.Call(c, msg.MsgClient.ClearConversationsMsg, m.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MessageApi) UserClearAllMsg(c *gin.Context) {
|
func (m *MessageApi) UserClearAllMsg(c *gin.Context) {
|
||||||
a2r.Call(msg.MsgClient.UserClearAllMsg, m.Client, c)
|
a2r.Call(c, msg.MsgClient.UserClearAllMsg, m.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MessageApi) DeleteMsgs(c *gin.Context) {
|
func (m *MessageApi) DeleteMsgs(c *gin.Context) {
|
||||||
a2r.Call(msg.MsgClient.DeleteMsgs, m.Client, c)
|
a2r.Call(c, msg.MsgClient.DeleteMsgs, m.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MessageApi) DeleteMsgPhysicalBySeq(c *gin.Context) {
|
func (m *MessageApi) DeleteMsgPhysicalBySeq(c *gin.Context) {
|
||||||
a2r.Call(msg.MsgClient.DeleteMsgPhysicalBySeq, m.Client, c)
|
a2r.Call(c, msg.MsgClient.DeleteMsgPhysicalBySeq, m.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MessageApi) DeleteMsgPhysical(c *gin.Context) {
|
func (m *MessageApi) DeleteMsgPhysical(c *gin.Context) {
|
||||||
a2r.Call(msg.MsgClient.DeleteMsgPhysical, m.Client, c)
|
a2r.Call(c, msg.MsgClient.DeleteMsgPhysical, m.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MessageApi) getSendMsgReq(c *gin.Context, req apistruct.SendMsg) (sendMsgReq *msg.SendMsgReq, err error) {
|
func (m *MessageApi) getSendMsgReq(c *gin.Context, req apistruct.SendMsg) (sendMsgReq *msg.SendMsgReq, err error) {
|
||||||
@ -176,7 +174,7 @@ func (m *MessageApi) getSendMsgReq(c *gin.Context, req apistruct.SendMsg) (sendM
|
|||||||
case constant.OANotification:
|
case constant.OANotification:
|
||||||
data = apistruct.OANotificationElem{}
|
data = apistruct.OANotificationElem{}
|
||||||
req.SessionType = constant.NotificationChatType
|
req.SessionType = constant.NotificationChatType
|
||||||
if err = m.userRpcClient.GetNotificationByID(c, req.SendID); err != nil {
|
if err = m.userClient.GetNotificationByID(c, req.SendID); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@ -250,24 +248,44 @@ func (m *MessageApi) SendMessage(c *gin.Context) {
|
|||||||
|
|
||||||
func (m *MessageApi) SendBusinessNotification(c *gin.Context) {
|
func (m *MessageApi) SendBusinessNotification(c *gin.Context) {
|
||||||
req := struct {
|
req := struct {
|
||||||
Key string `json:"key"`
|
Key string `json:"key"`
|
||||||
Data string `json:"data"`
|
Data string `json:"data"`
|
||||||
SendUserID string `json:"sendUserID" binding:"required"`
|
SendUserID string `json:"sendUserID" binding:"required"`
|
||||||
RecvUserID string `json:"recvUserID" binding:"required"`
|
RecvUserID string `json:"recvUserID"`
|
||||||
|
RecvGroupID string `json:"recvGroupID"`
|
||||||
|
SendMsg bool `json:"sendMsg"`
|
||||||
|
ReliabilityLevel *int `json:"reliabilityLevel"`
|
||||||
}{}
|
}{}
|
||||||
if err := c.BindJSON(&req); err != nil {
|
if err := c.BindJSON(&req); err != nil {
|
||||||
apiresp.GinError(c, errs.ErrArgs.WithDetail(err.Error()).Wrap())
|
apiresp.GinError(c, errs.ErrArgs.WithDetail(err.Error()).Wrap())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if req.RecvUserID == "" && req.RecvGroupID == "" {
|
||||||
|
apiresp.GinError(c, errs.ErrArgs.WrapMsg("recvUserID and recvGroupID cannot be empty at the same time"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if req.RecvUserID != "" && req.RecvGroupID != "" {
|
||||||
|
apiresp.GinError(c, errs.ErrArgs.WrapMsg("recvUserID and recvGroupID cannot be set at the same time"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var sessionType int32
|
||||||
|
if req.RecvUserID != "" {
|
||||||
|
sessionType = constant.SingleChatType
|
||||||
|
} else {
|
||||||
|
sessionType = constant.ReadGroupChatType
|
||||||
|
}
|
||||||
|
if req.ReliabilityLevel == nil {
|
||||||
|
req.ReliabilityLevel = datautil.ToPtr(1)
|
||||||
|
}
|
||||||
if !authverify.IsAppManagerUid(c, m.imAdminUserID) {
|
if !authverify.IsAppManagerUid(c, m.imAdminUserID) {
|
||||||
apiresp.GinError(c, errs.ErrNoPermission.WrapMsg("only app manager can send message"))
|
apiresp.GinError(c, errs.ErrNoPermission.WrapMsg("only app manager can send message"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
sendMsgReq := msg.SendMsgReq{
|
sendMsgReq := msg.SendMsgReq{
|
||||||
MsgData: &sdkws.MsgData{
|
MsgData: &sdkws.MsgData{
|
||||||
SendID: req.SendUserID,
|
SendID: req.SendUserID,
|
||||||
RecvID: req.RecvUserID,
|
RecvID: req.RecvUserID,
|
||||||
|
GroupID: req.RecvGroupID,
|
||||||
Content: []byte(jsonutil.StructToJsonString(&sdkws.NotificationElem{
|
Content: []byte(jsonutil.StructToJsonString(&sdkws.NotificationElem{
|
||||||
Detail: jsonutil.StructToJsonString(&struct {
|
Detail: jsonutil.StructToJsonString(&struct {
|
||||||
Key string `json:"key"`
|
Key string `json:"key"`
|
||||||
@ -276,12 +294,12 @@ func (m *MessageApi) SendBusinessNotification(c *gin.Context) {
|
|||||||
})),
|
})),
|
||||||
MsgFrom: constant.SysMsgType,
|
MsgFrom: constant.SysMsgType,
|
||||||
ContentType: constant.BusinessNotification,
|
ContentType: constant.BusinessNotification,
|
||||||
SessionType: constant.SingleChatType,
|
SessionType: sessionType,
|
||||||
CreateTime: timeutil.GetCurrentTimestampByMill(),
|
CreateTime: timeutil.GetCurrentTimestampByMill(),
|
||||||
ClientMsgID: idutil.GetMsgIDByMD5(mcontext.GetOpUserID(c)),
|
ClientMsgID: idutil.GetMsgIDByMD5(mcontext.GetOpUserID(c)),
|
||||||
Options: config.GetOptionsByNotification(config.NotificationConfig{
|
Options: config.GetOptionsByNotification(config.NotificationConfig{
|
||||||
IsSendMsg: false,
|
IsSendMsg: req.SendMsg,
|
||||||
ReliabilityLevel: 1,
|
ReliabilityLevel: *req.ReliabilityLevel,
|
||||||
UnreadCount: false,
|
UnreadCount: false,
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
@ -310,10 +328,10 @@ func (m *MessageApi) BatchSendMsg(c *gin.Context) {
|
|||||||
|
|
||||||
var recvIDs []string
|
var recvIDs []string
|
||||||
if req.IsSendAll {
|
if req.IsSendAll {
|
||||||
pageNumber := 1
|
var pageNumber int32 = 1
|
||||||
showNumber := 500
|
const showNumber = 500
|
||||||
for {
|
for {
|
||||||
recvIDsPart, err := m.userRpcClient.GetAllUserIDs(c, int32(pageNumber), int32(showNumber))
|
recvIDsPart, err := m.userClient.GetAllUserIDs(c, pageNumber, showNumber)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
apiresp.GinError(c, err)
|
apiresp.GinError(c, err)
|
||||||
return
|
return
|
||||||
@ -351,25 +369,25 @@ func (m *MessageApi) BatchSendMsg(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *MessageApi) CheckMsgIsSendSuccess(c *gin.Context) {
|
func (m *MessageApi) CheckMsgIsSendSuccess(c *gin.Context) {
|
||||||
a2r.Call(msg.MsgClient.GetSendMsgStatus, m.Client, c)
|
a2r.Call(c, msg.MsgClient.GetSendMsgStatus, m.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MessageApi) GetUsersOnlineStatus(c *gin.Context) {
|
func (m *MessageApi) GetUsersOnlineStatus(c *gin.Context) {
|
||||||
a2r.Call(msg.MsgClient.GetSendMsgStatus, m.Client, c)
|
a2r.Call(c, msg.MsgClient.GetSendMsgStatus, m.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MessageApi) GetActiveUser(c *gin.Context) {
|
func (m *MessageApi) GetActiveUser(c *gin.Context) {
|
||||||
a2r.Call(msg.MsgClient.GetActiveUser, m.Client, c)
|
a2r.Call(c, msg.MsgClient.GetActiveUser, m.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MessageApi) GetActiveGroup(c *gin.Context) {
|
func (m *MessageApi) GetActiveGroup(c *gin.Context) {
|
||||||
a2r.Call(msg.MsgClient.GetActiveGroup, m.Client, c)
|
a2r.Call(c, msg.MsgClient.GetActiveGroup, m.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MessageApi) SearchMsg(c *gin.Context) {
|
func (m *MessageApi) SearchMsg(c *gin.Context) {
|
||||||
a2r.Call(msg.MsgClient.SearchMessage, m.Client, c)
|
a2r.Call(c, msg.MsgClient.SearchMessage, m.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MessageApi) GetServerTime(c *gin.Context) {
|
func (m *MessageApi) GetServerTime(c *gin.Context) {
|
||||||
a2r.Call(msg.MsgClient.GetServerTime, m.Client, c)
|
a2r.Call(c, msg.MsgClient.GetServerTime, m.Client)
|
||||||
}
|
}
|
||||||
|
114
internal/api/prometheus_discovery.go
Normal file
114
internal/api/prometheus_discovery.go
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
conf "github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
||||||
|
"github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics"
|
||||||
|
"github.com/openimsdk/tools/apiresp"
|
||||||
|
"github.com/openimsdk/tools/discovery"
|
||||||
|
"github.com/openimsdk/tools/discovery/etcd"
|
||||||
|
"github.com/openimsdk/tools/errs"
|
||||||
|
"github.com/openimsdk/tools/log"
|
||||||
|
clientv3 "go.etcd.io/etcd/client/v3"
|
||||||
|
)
|
||||||
|
|
||||||
|
type PrometheusDiscoveryApi struct {
|
||||||
|
config *Config
|
||||||
|
client *clientv3.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewPrometheusDiscoveryApi(config *Config, client discovery.SvcDiscoveryRegistry) *PrometheusDiscoveryApi {
|
||||||
|
api := &PrometheusDiscoveryApi{
|
||||||
|
config: config,
|
||||||
|
}
|
||||||
|
if config.Discovery.Enable == conf.ETCD {
|
||||||
|
api.client = client.(*etcd.SvcDiscoveryRegistryImpl).GetClient()
|
||||||
|
}
|
||||||
|
return api
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *PrometheusDiscoveryApi) Enable(c *gin.Context) {
|
||||||
|
if p.config.Discovery.Enable != conf.ETCD {
|
||||||
|
c.JSON(http.StatusOK, []struct{}{})
|
||||||
|
c.Abort()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *PrometheusDiscoveryApi) discovery(c *gin.Context, key string) {
|
||||||
|
eResp, err := p.client.Get(c, prommetrics.BuildDiscoveryKey(key))
|
||||||
|
if err != nil {
|
||||||
|
// Log and respond with an error if preparation fails.
|
||||||
|
apiresp.GinError(c, errs.WrapMsg(err, "etcd get err"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if len(eResp.Kvs) == 0 {
|
||||||
|
c.JSON(http.StatusOK, []*prommetrics.Target{})
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
resp = &prommetrics.RespTarget{
|
||||||
|
Targets: make([]string, 0, len(eResp.Kvs)),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
for i := range eResp.Kvs {
|
||||||
|
var target prommetrics.Target
|
||||||
|
err = json.Unmarshal(eResp.Kvs[i].Value, &target)
|
||||||
|
if err != nil {
|
||||||
|
log.ZError(c, "prometheus unmarshal err", errs.Wrap(err))
|
||||||
|
}
|
||||||
|
resp.Targets = append(resp.Targets, target.Target)
|
||||||
|
if resp.Labels == nil {
|
||||||
|
resp.Labels = target.Labels
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
c.JSON(200, []*prommetrics.RespTarget{resp})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *PrometheusDiscoveryApi) Api(c *gin.Context) {
|
||||||
|
p.discovery(c, prommetrics.APIKeyName)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *PrometheusDiscoveryApi) User(c *gin.Context) {
|
||||||
|
p.discovery(c, p.config.Discovery.RpcService.User)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *PrometheusDiscoveryApi) Group(c *gin.Context) {
|
||||||
|
p.discovery(c, p.config.Discovery.RpcService.Group)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *PrometheusDiscoveryApi) Msg(c *gin.Context) {
|
||||||
|
p.discovery(c, p.config.Discovery.RpcService.Msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *PrometheusDiscoveryApi) Friend(c *gin.Context) {
|
||||||
|
p.discovery(c, p.config.Discovery.RpcService.Friend)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *PrometheusDiscoveryApi) Conversation(c *gin.Context) {
|
||||||
|
p.discovery(c, p.config.Discovery.RpcService.Conversation)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *PrometheusDiscoveryApi) Third(c *gin.Context) {
|
||||||
|
p.discovery(c, p.config.Discovery.RpcService.Third)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *PrometheusDiscoveryApi) Auth(c *gin.Context) {
|
||||||
|
p.discovery(c, p.config.Discovery.RpcService.Auth)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *PrometheusDiscoveryApi) Push(c *gin.Context) {
|
||||||
|
p.discovery(c, p.config.Discovery.RpcService.Push)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *PrometheusDiscoveryApi) MessageGateway(c *gin.Context) {
|
||||||
|
p.discovery(c, p.config.Discovery.RpcService.MessageGateway)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *PrometheusDiscoveryApi) MessageTransfer(c *gin.Context) {
|
||||||
|
p.discovery(c, prommetrics.MessageTransferKeyName)
|
||||||
|
}
|
@ -1,29 +1,33 @@
|
|||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"context"
|
||||||
|
|
||||||
"github.com/openimsdk/open-im-server/v3/internal/api/jssdk"
|
|
||||||
|
|
||||||
"github.com/gin-contrib/gzip"
|
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
|
||||||
"github.com/gin-gonic/gin/binding"
|
|
||||||
"github.com/go-playground/validator/v10"
|
|
||||||
"google.golang.org/grpc"
|
|
||||||
"google.golang.org/grpc/credentials/insecure"
|
|
||||||
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/gin-contrib/gzip"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/gin-gonic/gin/binding"
|
||||||
|
"github.com/go-playground/validator/v10"
|
||||||
|
"github.com/openimsdk/open-im-server/v3/internal/api/jssdk"
|
||||||
|
"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/prommetrics"
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/common/servererrs"
|
"github.com/openimsdk/open-im-server/v3/pkg/common/servererrs"
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
|
"github.com/openimsdk/open-im-server/v3/pkg/rpcli"
|
||||||
|
pbAuth "github.com/openimsdk/protocol/auth"
|
||||||
"github.com/openimsdk/protocol/constant"
|
"github.com/openimsdk/protocol/constant"
|
||||||
|
"github.com/openimsdk/protocol/conversation"
|
||||||
|
"github.com/openimsdk/protocol/group"
|
||||||
|
"github.com/openimsdk/protocol/msg"
|
||||||
|
"github.com/openimsdk/protocol/relation"
|
||||||
|
"github.com/openimsdk/protocol/third"
|
||||||
|
"github.com/openimsdk/protocol/user"
|
||||||
"github.com/openimsdk/tools/apiresp"
|
"github.com/openimsdk/tools/apiresp"
|
||||||
"github.com/openimsdk/tools/discovery"
|
"github.com/openimsdk/tools/discovery"
|
||||||
|
"github.com/openimsdk/tools/discovery/etcd"
|
||||||
"github.com/openimsdk/tools/log"
|
"github.com/openimsdk/tools/log"
|
||||||
"github.com/openimsdk/tools/mw"
|
"github.com/openimsdk/tools/mw"
|
||||||
|
clientv3 "go.etcd.io/etcd/client/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -48,24 +52,41 @@ func prommetricsGin() gin.HandlerFunc {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func newGinRouter(disCov discovery.SvcDiscoveryRegistry, config *Config) *gin.Engine {
|
func newGinRouter(ctx context.Context, client discovery.SvcDiscoveryRegistry, cfg *Config) (*gin.Engine, error) {
|
||||||
disCov.AddOption(mw.GrpcClient(), grpc.WithTransportCredentials(insecure.NewCredentials()),
|
authConn, err := client.GetConn(ctx, cfg.Discovery.RpcService.Auth)
|
||||||
grpc.WithDefaultServiceConfig(fmt.Sprintf(`{"LoadBalancingPolicy": "%s"}`, "round_robin")))
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
userConn, err := client.GetConn(ctx, cfg.Discovery.RpcService.User)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
groupConn, err := client.GetConn(ctx, cfg.Discovery.RpcService.Group)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
friendConn, err := client.GetConn(ctx, cfg.Discovery.RpcService.Friend)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
conversationConn, err := client.GetConn(ctx, cfg.Discovery.RpcService.Conversation)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
thirdConn, err := client.GetConn(ctx, cfg.Discovery.RpcService.Third)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
msgConn, err := client.GetConn(ctx, cfg.Discovery.RpcService.Msg)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
gin.SetMode(gin.ReleaseMode)
|
gin.SetMode(gin.ReleaseMode)
|
||||||
r := gin.New()
|
r := gin.New()
|
||||||
if v, ok := binding.Validator.Engine().(*validator.Validate); ok {
|
if v, ok := binding.Validator.Engine().(*validator.Validate); ok {
|
||||||
_ = v.RegisterValidation("required_if", RequiredIf)
|
_ = v.RegisterValidation("required_if", RequiredIf)
|
||||||
}
|
}
|
||||||
// init rpc client here
|
switch cfg.API.Api.CompressionLevel {
|
||||||
userRpc := rpcclient.NewUser(disCov, config.Share.RpcRegisterName.User, config.Share.RpcRegisterName.MessageGateway,
|
|
||||||
config.Share.IMAdminUserID)
|
|
||||||
groupRpc := rpcclient.NewGroup(disCov, config.Share.RpcRegisterName.Group)
|
|
||||||
friendRpc := rpcclient.NewFriend(disCov, config.Share.RpcRegisterName.Friend)
|
|
||||||
messageRpc := rpcclient.NewMessage(disCov, config.Share.RpcRegisterName.Msg)
|
|
||||||
conversationRpc := rpcclient.NewConversation(disCov, config.Share.RpcRegisterName.Conversation)
|
|
||||||
authRpc := rpcclient.NewAuth(disCov, config.Share.RpcRegisterName.Auth)
|
|
||||||
thirdRpc := rpcclient.NewThird(disCov, config.Share.RpcRegisterName.Third, config.API.Prometheus.GrafanaURL)
|
|
||||||
switch config.API.Api.CompressionLevel {
|
|
||||||
case NoCompression:
|
case NoCompression:
|
||||||
case DefaultCompression:
|
case DefaultCompression:
|
||||||
r.Use(gzip.Gzip(gzip.DefaultCompression))
|
r.Use(gzip.Gzip(gzip.DefaultCompression))
|
||||||
@ -74,12 +95,12 @@ func newGinRouter(disCov discovery.SvcDiscoveryRegistry, config *Config) *gin.En
|
|||||||
case BestSpeed:
|
case BestSpeed:
|
||||||
r.Use(gzip.Gzip(gzip.BestSpeed))
|
r.Use(gzip.Gzip(gzip.BestSpeed))
|
||||||
}
|
}
|
||||||
r.Use(prommetricsGin(), gin.Recovery(), mw.CorsHandler(), mw.GinParseOperationID(), GinParseToken(authRpc))
|
r.Use(prommetricsGin(), gin.RecoveryWithWriter(gin.DefaultErrorWriter, mw.GinPanicErr), mw.CorsHandler(),
|
||||||
u := NewUserApi(*userRpc)
|
mw.GinParseOperationID(), GinParseToken(rpcli.NewAuthClient(authConn)))
|
||||||
m := NewMessageApi(messageRpc, userRpc, config.Share.IMAdminUserID)
|
|
||||||
j := jssdk.NewJSSdkApi(messageRpc.Client, conversationRpc.Client)
|
u := NewUserApi(user.NewUserClient(userConn), client, cfg.Discovery.RpcService)
|
||||||
userRouterGroup := r.Group("/user")
|
|
||||||
{
|
{
|
||||||
|
userRouterGroup := r.Group("/user")
|
||||||
userRouterGroup.POST("/user_register", u.UserRegister)
|
userRouterGroup.POST("/user_register", u.UserRegister)
|
||||||
userRouterGroup.POST("/update_user_info", u.UpdateUserInfo)
|
userRouterGroup.POST("/update_user_info", u.UpdateUserInfo)
|
||||||
userRouterGroup.POST("/update_user_info_ex", u.UpdateUserInfoEx)
|
userRouterGroup.POST("/update_user_info_ex", u.UpdateUserInfoEx)
|
||||||
@ -105,9 +126,9 @@ func newGinRouter(disCov discovery.SvcDiscoveryRegistry, config *Config) *gin.En
|
|||||||
userRouterGroup.POST("/search_notification_account", u.SearchNotificationAccount)
|
userRouterGroup.POST("/search_notification_account", u.SearchNotificationAccount)
|
||||||
}
|
}
|
||||||
// friend routing group
|
// friend routing group
|
||||||
friendRouterGroup := r.Group("/friend")
|
|
||||||
{
|
{
|
||||||
f := NewFriendApi(*friendRpc)
|
f := NewFriendApi(relation.NewFriendClient(friendConn))
|
||||||
|
friendRouterGroup := r.Group("/friend")
|
||||||
friendRouterGroup.POST("/delete_friend", f.DeleteFriend)
|
friendRouterGroup.POST("/delete_friend", f.DeleteFriend)
|
||||||
friendRouterGroup.POST("/get_friend_apply_list", f.GetFriendApplyList)
|
friendRouterGroup.POST("/get_friend_apply_list", f.GetFriendApplyList)
|
||||||
friendRouterGroup.POST("/get_designated_friend_apply", f.GetDesignatedFriendsApply)
|
friendRouterGroup.POST("/get_designated_friend_apply", f.GetDesignatedFriendsApply)
|
||||||
@ -130,9 +151,10 @@ func newGinRouter(disCov discovery.SvcDiscoveryRegistry, config *Config) *gin.En
|
|||||||
friendRouterGroup.POST("/get_incremental_friends", f.GetIncrementalFriends)
|
friendRouterGroup.POST("/get_incremental_friends", f.GetIncrementalFriends)
|
||||||
friendRouterGroup.POST("/get_full_friend_user_ids", f.GetFullFriendUserIDs)
|
friendRouterGroup.POST("/get_full_friend_user_ids", f.GetFullFriendUserIDs)
|
||||||
}
|
}
|
||||||
g := NewGroupApi(*groupRpc)
|
|
||||||
groupRouterGroup := r.Group("/group")
|
g := NewGroupApi(group.NewGroupClient(groupConn))
|
||||||
{
|
{
|
||||||
|
groupRouterGroup := r.Group("/group")
|
||||||
groupRouterGroup.POST("/create_group", g.CreateGroup)
|
groupRouterGroup.POST("/create_group", g.CreateGroup)
|
||||||
groupRouterGroup.POST("/set_group_info", g.SetGroupInfo)
|
groupRouterGroup.POST("/set_group_info", g.SetGroupInfo)
|
||||||
groupRouterGroup.POST("/set_group_info_ex", g.SetGroupInfoEx)
|
groupRouterGroup.POST("/set_group_info_ex", g.SetGroupInfoEx)
|
||||||
@ -166,18 +188,19 @@ func newGinRouter(disCov discovery.SvcDiscoveryRegistry, config *Config) *gin.En
|
|||||||
groupRouterGroup.POST("/get_full_join_group_ids", g.GetFullJoinGroupIDs)
|
groupRouterGroup.POST("/get_full_join_group_ids", g.GetFullJoinGroupIDs)
|
||||||
}
|
}
|
||||||
// certificate
|
// certificate
|
||||||
authRouterGroup := r.Group("/auth")
|
|
||||||
{
|
{
|
||||||
a := NewAuthApi(*authRpc)
|
a := NewAuthApi(pbAuth.NewAuthClient(authConn))
|
||||||
|
authRouterGroup := r.Group("/auth")
|
||||||
authRouterGroup.POST("/get_admin_token", a.GetAdminToken)
|
authRouterGroup.POST("/get_admin_token", a.GetAdminToken)
|
||||||
authRouterGroup.POST("/get_user_token", a.GetUserToken)
|
authRouterGroup.POST("/get_user_token", a.GetUserToken)
|
||||||
authRouterGroup.POST("/parse_token", a.ParseToken)
|
authRouterGroup.POST("/parse_token", a.ParseToken)
|
||||||
authRouterGroup.POST("/force_logout", a.ForceLogout)
|
authRouterGroup.POST("/force_logout", a.ForceLogout)
|
||||||
|
|
||||||
}
|
}
|
||||||
// Third service
|
// Third service
|
||||||
thirdGroup := r.Group("/third")
|
|
||||||
{
|
{
|
||||||
t := NewThirdApi(*thirdRpc)
|
t := NewThirdApi(third.NewThirdClient(thirdConn), cfg.API.Prometheus.GrafanaURL)
|
||||||
|
thirdGroup := r.Group("/third")
|
||||||
thirdGroup.GET("/prometheus", t.GetPrometheus)
|
thirdGroup.GET("/prometheus", t.GetPrometheus)
|
||||||
thirdGroup.POST("/fcm_update_token", t.FcmUpdateToken)
|
thirdGroup.POST("/fcm_update_token", t.FcmUpdateToken)
|
||||||
thirdGroup.POST("/set_app_badge", t.SetAppBadge)
|
thirdGroup.POST("/set_app_badge", t.SetAppBadge)
|
||||||
@ -200,8 +223,9 @@ func newGinRouter(disCov discovery.SvcDiscoveryRegistry, config *Config) *gin.En
|
|||||||
objectGroup.GET("/*name", t.ObjectRedirect)
|
objectGroup.GET("/*name", t.ObjectRedirect)
|
||||||
}
|
}
|
||||||
// Message
|
// Message
|
||||||
msgGroup := r.Group("/msg")
|
m := NewMessageApi(msg.NewMsgClient(msgConn), rpcli.NewUserClient(userConn), cfg.Share.IMAdminUserID)
|
||||||
{
|
{
|
||||||
|
msgGroup := r.Group("/msg")
|
||||||
msgGroup.POST("/newest_seq", m.GetSeq)
|
msgGroup.POST("/newest_seq", m.GetSeq)
|
||||||
msgGroup.POST("/search_msg", m.SearchMsg)
|
msgGroup.POST("/search_msg", m.SearchMsg)
|
||||||
msgGroup.POST("/send_msg", m.SendMessage)
|
msgGroup.POST("/send_msg", m.SendMessage)
|
||||||
@ -224,9 +248,9 @@ func newGinRouter(disCov discovery.SvcDiscoveryRegistry, config *Config) *gin.En
|
|||||||
msgGroup.POST("/get_server_time", m.GetServerTime)
|
msgGroup.POST("/get_server_time", m.GetServerTime)
|
||||||
}
|
}
|
||||||
// Conversation
|
// Conversation
|
||||||
conversationGroup := r.Group("/conversation")
|
|
||||||
{
|
{
|
||||||
c := NewConversationApi(*conversationRpc)
|
c := NewConversationApi(conversation.NewConversationClient(conversationConn))
|
||||||
|
conversationGroup := r.Group("/conversation")
|
||||||
conversationGroup.POST("/get_sorted_conversation_list", c.GetSortedConversationList)
|
conversationGroup.POST("/get_sorted_conversation_list", c.GetSortedConversationList)
|
||||||
conversationGroup.POST("/get_all_conversations", c.GetAllConversations)
|
conversationGroup.POST("/get_all_conversations", c.GetAllConversations)
|
||||||
conversationGroup.POST("/get_conversation", c.GetConversation)
|
conversationGroup.POST("/get_conversation", c.GetConversation)
|
||||||
@ -240,22 +264,59 @@ func newGinRouter(disCov discovery.SvcDiscoveryRegistry, config *Config) *gin.En
|
|||||||
conversationGroup.POST("/get_pinned_conversation_ids", c.GetPinnedConversationIDs)
|
conversationGroup.POST("/get_pinned_conversation_ids", c.GetPinnedConversationIDs)
|
||||||
}
|
}
|
||||||
|
|
||||||
statisticsGroup := r.Group("/statistics")
|
|
||||||
{
|
{
|
||||||
|
statisticsGroup := r.Group("/statistics")
|
||||||
statisticsGroup.POST("/user/register", u.UserRegisterCount)
|
statisticsGroup.POST("/user/register", u.UserRegisterCount)
|
||||||
statisticsGroup.POST("/user/active", m.GetActiveUser)
|
statisticsGroup.POST("/user/active", m.GetActiveUser)
|
||||||
statisticsGroup.POST("/group/create", g.GroupCreateCount)
|
statisticsGroup.POST("/group/create", g.GroupCreateCount)
|
||||||
statisticsGroup.POST("/group/active", m.GetActiveGroup)
|
statisticsGroup.POST("/group/active", m.GetActiveGroup)
|
||||||
}
|
}
|
||||||
|
|
||||||
jssdk := r.Group("/jssdk")
|
{
|
||||||
jssdk.POST("/get_conversations", j.GetConversations)
|
j := jssdk.NewJSSdkApi(rpcli.NewUserClient(userConn), rpcli.NewRelationClient(friendConn),
|
||||||
jssdk.POST("/get_active_conversations", j.GetActiveConversations)
|
rpcli.NewGroupClient(groupConn), rpcli.NewConversationClient(conversationConn), rpcli.NewMsgClient(msgConn))
|
||||||
|
jssdk := r.Group("/jssdk")
|
||||||
|
jssdk.POST("/get_conversations", j.GetConversations)
|
||||||
|
jssdk.POST("/get_active_conversations", j.GetActiveConversations)
|
||||||
|
}
|
||||||
|
{
|
||||||
|
pd := NewPrometheusDiscoveryApi(cfg, client)
|
||||||
|
proDiscoveryGroup := r.Group("/prometheus_discovery", pd.Enable)
|
||||||
|
proDiscoveryGroup.GET("/api", pd.Api)
|
||||||
|
proDiscoveryGroup.GET("/user", pd.User)
|
||||||
|
proDiscoveryGroup.GET("/group", pd.Group)
|
||||||
|
proDiscoveryGroup.GET("/msg", pd.Msg)
|
||||||
|
proDiscoveryGroup.GET("/friend", pd.Friend)
|
||||||
|
proDiscoveryGroup.GET("/conversation", pd.Conversation)
|
||||||
|
proDiscoveryGroup.GET("/third", pd.Third)
|
||||||
|
proDiscoveryGroup.GET("/auth", pd.Auth)
|
||||||
|
proDiscoveryGroup.GET("/push", pd.Push)
|
||||||
|
proDiscoveryGroup.GET("/msg_gateway", pd.MessageGateway)
|
||||||
|
proDiscoveryGroup.GET("/msg_transfer", pd.MessageTransfer)
|
||||||
|
}
|
||||||
|
|
||||||
return r
|
var etcdClient *clientv3.Client
|
||||||
|
if cfg.Discovery.Enable == config.ETCD {
|
||||||
|
etcdClient = client.(*etcd.SvcDiscoveryRegistryImpl).GetClient()
|
||||||
|
}
|
||||||
|
cm := NewConfigManager(cfg.Share.IMAdminUserID, cfg.AllConfig, etcdClient, cfg.ConfigPath, cfg.RuntimeEnv)
|
||||||
|
{
|
||||||
|
|
||||||
|
configGroup := r.Group("/config", cm.CheckAdmin)
|
||||||
|
configGroup.POST("/get_config_list", cm.GetConfigList)
|
||||||
|
configGroup.POST("/get_config", cm.GetConfig)
|
||||||
|
configGroup.POST("/set_config", cm.SetConfig)
|
||||||
|
configGroup.POST("/reset_config", cm.ResetConfig)
|
||||||
|
configGroup.POST("/set_enable_config_manager", cm.SetEnableConfigManager)
|
||||||
|
configGroup.POST("/get_enable_config_manager", cm.GetEnableConfigManager)
|
||||||
|
}
|
||||||
|
{
|
||||||
|
r.POST("/restart", cm.CheckAdmin, cm.Restart)
|
||||||
|
}
|
||||||
|
return r, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func GinParseToken(authRPC *rpcclient.Auth) gin.HandlerFunc {
|
func GinParseToken(authClient *rpcli.AuthClient) gin.HandlerFunc {
|
||||||
return func(c *gin.Context) {
|
return func(c *gin.Context) {
|
||||||
switch c.Request.Method {
|
switch c.Request.Method {
|
||||||
case http.MethodPost:
|
case http.MethodPost:
|
||||||
@ -273,7 +334,7 @@ func GinParseToken(authRPC *rpcclient.Auth) gin.HandlerFunc {
|
|||||||
c.Abort()
|
c.Abort()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
resp, err := authRPC.ParseToken(c, token)
|
resp, err := authClient.ParseToken(c, token)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
apiresp.GinError(c, err)
|
apiresp.GinError(c, err)
|
||||||
c.Abort()
|
c.Abort()
|
||||||
|
@ -1,32 +0,0 @@
|
|||||||
// Copyright © 2023 OpenIM. All rights reserved.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package api
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/gin-gonic/gin"
|
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
|
|
||||||
"github.com/openimsdk/protocol/user"
|
|
||||||
"github.com/openimsdk/tools/a2r"
|
|
||||||
)
|
|
||||||
|
|
||||||
type StatisticsApi rpcclient.User
|
|
||||||
|
|
||||||
func NewStatisticsApi(client rpcclient.User) StatisticsApi {
|
|
||||||
return StatisticsApi(client)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *StatisticsApi) UserRegister(c *gin.Context) {
|
|
||||||
a2r.Call(user.UserClient.UserRegisterCount, s.Client, c)
|
|
||||||
}
|
|
@ -24,25 +24,27 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
|
|
||||||
"github.com/openimsdk/protocol/third"
|
"github.com/openimsdk/protocol/third"
|
||||||
"github.com/openimsdk/tools/a2r"
|
"github.com/openimsdk/tools/a2r"
|
||||||
"github.com/openimsdk/tools/errs"
|
"github.com/openimsdk/tools/errs"
|
||||||
"github.com/openimsdk/tools/mcontext"
|
"github.com/openimsdk/tools/mcontext"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ThirdApi rpcclient.Third
|
type ThirdApi struct {
|
||||||
|
GrafanaUrl string
|
||||||
|
Client third.ThirdClient
|
||||||
|
}
|
||||||
|
|
||||||
func NewThirdApi(client rpcclient.Third) ThirdApi {
|
func NewThirdApi(client third.ThirdClient, grafanaUrl string) ThirdApi {
|
||||||
return ThirdApi(client)
|
return ThirdApi{Client: client, GrafanaUrl: grafanaUrl}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *ThirdApi) FcmUpdateToken(c *gin.Context) {
|
func (o *ThirdApi) FcmUpdateToken(c *gin.Context) {
|
||||||
a2r.Call(third.ThirdClient.FcmUpdateToken, o.Client, c)
|
a2r.Call(c, third.ThirdClient.FcmUpdateToken, o.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *ThirdApi) SetAppBadge(c *gin.Context) {
|
func (o *ThirdApi) SetAppBadge(c *gin.Context) {
|
||||||
a2r.Call(third.ThirdClient.SetAppBadge, o.Client, c)
|
a2r.Call(c, third.ThirdClient.SetAppBadge, o.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
// #################### s3 ####################
|
// #################### s3 ####################
|
||||||
@ -77,44 +79,44 @@ func setURLPrefix(c *gin.Context, urlPrefix *string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (o *ThirdApi) PartLimit(c *gin.Context) {
|
func (o *ThirdApi) PartLimit(c *gin.Context) {
|
||||||
a2r.Call(third.ThirdClient.PartLimit, o.Client, c)
|
a2r.Call(c, third.ThirdClient.PartLimit, o.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *ThirdApi) PartSize(c *gin.Context) {
|
func (o *ThirdApi) PartSize(c *gin.Context) {
|
||||||
a2r.Call(third.ThirdClient.PartSize, o.Client, c)
|
a2r.Call(c, third.ThirdClient.PartSize, o.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *ThirdApi) InitiateMultipartUpload(c *gin.Context) {
|
func (o *ThirdApi) InitiateMultipartUpload(c *gin.Context) {
|
||||||
opt := setURLPrefixOption(third.ThirdClient.InitiateMultipartUpload, func(req *third.InitiateMultipartUploadReq) error {
|
opt := setURLPrefixOption(third.ThirdClient.InitiateMultipartUpload, func(req *third.InitiateMultipartUploadReq) error {
|
||||||
return setURLPrefix(c, &req.UrlPrefix)
|
return setURLPrefix(c, &req.UrlPrefix)
|
||||||
})
|
})
|
||||||
a2r.Call(third.ThirdClient.InitiateMultipartUpload, o.Client, c, opt)
|
a2r.Call(c, third.ThirdClient.InitiateMultipartUpload, o.Client, opt)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *ThirdApi) AuthSign(c *gin.Context) {
|
func (o *ThirdApi) AuthSign(c *gin.Context) {
|
||||||
a2r.Call(third.ThirdClient.AuthSign, o.Client, c)
|
a2r.Call(c, third.ThirdClient.AuthSign, o.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *ThirdApi) CompleteMultipartUpload(c *gin.Context) {
|
func (o *ThirdApi) CompleteMultipartUpload(c *gin.Context) {
|
||||||
opt := setURLPrefixOption(third.ThirdClient.CompleteMultipartUpload, func(req *third.CompleteMultipartUploadReq) error {
|
opt := setURLPrefixOption(third.ThirdClient.CompleteMultipartUpload, func(req *third.CompleteMultipartUploadReq) error {
|
||||||
return setURLPrefix(c, &req.UrlPrefix)
|
return setURLPrefix(c, &req.UrlPrefix)
|
||||||
})
|
})
|
||||||
a2r.Call(third.ThirdClient.CompleteMultipartUpload, o.Client, c, opt)
|
a2r.Call(c, third.ThirdClient.CompleteMultipartUpload, o.Client, opt)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *ThirdApi) AccessURL(c *gin.Context) {
|
func (o *ThirdApi) AccessURL(c *gin.Context) {
|
||||||
a2r.Call(third.ThirdClient.AccessURL, o.Client, c)
|
a2r.Call(c, third.ThirdClient.AccessURL, o.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *ThirdApi) InitiateFormData(c *gin.Context) {
|
func (o *ThirdApi) InitiateFormData(c *gin.Context) {
|
||||||
a2r.Call(third.ThirdClient.InitiateFormData, o.Client, c)
|
a2r.Call(c, third.ThirdClient.InitiateFormData, o.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *ThirdApi) CompleteFormData(c *gin.Context) {
|
func (o *ThirdApi) CompleteFormData(c *gin.Context) {
|
||||||
opt := setURLPrefixOption(third.ThirdClient.CompleteFormData, func(req *third.CompleteFormDataReq) error {
|
opt := setURLPrefixOption(third.ThirdClient.CompleteFormData, func(req *third.CompleteFormDataReq) error {
|
||||||
return setURLPrefix(c, &req.UrlPrefix)
|
return setURLPrefix(c, &req.UrlPrefix)
|
||||||
})
|
})
|
||||||
a2r.Call(third.ThirdClient.CompleteFormData, o.Client, c, opt)
|
a2r.Call(c, third.ThirdClient.CompleteFormData, o.Client, opt)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *ThirdApi) ObjectRedirect(c *gin.Context) {
|
func (o *ThirdApi) ObjectRedirect(c *gin.Context) {
|
||||||
@ -156,15 +158,15 @@ func (o *ThirdApi) ObjectRedirect(c *gin.Context) {
|
|||||||
|
|
||||||
// #################### logs ####################.
|
// #################### logs ####################.
|
||||||
func (o *ThirdApi) UploadLogs(c *gin.Context) {
|
func (o *ThirdApi) UploadLogs(c *gin.Context) {
|
||||||
a2r.Call(third.ThirdClient.UploadLogs, o.Client, c)
|
a2r.Call(c, third.ThirdClient.UploadLogs, o.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *ThirdApi) DeleteLogs(c *gin.Context) {
|
func (o *ThirdApi) DeleteLogs(c *gin.Context) {
|
||||||
a2r.Call(third.ThirdClient.DeleteLogs, o.Client, c)
|
a2r.Call(c, third.ThirdClient.DeleteLogs, o.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *ThirdApi) SearchLogs(c *gin.Context) {
|
func (o *ThirdApi) SearchLogs(c *gin.Context) {
|
||||||
a2r.Call(third.ThirdClient.SearchLogs, o.Client, c)
|
a2r.Call(c, third.ThirdClient.SearchLogs, o.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *ThirdApi) GetPrometheus(c *gin.Context) {
|
func (o *ThirdApi) GetPrometheus(c *gin.Context) {
|
||||||
|
@ -16,52 +16,57 @@ package api
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
|
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
||||||
"github.com/openimsdk/protocol/constant"
|
"github.com/openimsdk/protocol/constant"
|
||||||
"github.com/openimsdk/protocol/msggateway"
|
"github.com/openimsdk/protocol/msggateway"
|
||||||
"github.com/openimsdk/protocol/user"
|
"github.com/openimsdk/protocol/user"
|
||||||
"github.com/openimsdk/tools/a2r"
|
"github.com/openimsdk/tools/a2r"
|
||||||
"github.com/openimsdk/tools/apiresp"
|
"github.com/openimsdk/tools/apiresp"
|
||||||
|
"github.com/openimsdk/tools/discovery"
|
||||||
"github.com/openimsdk/tools/errs"
|
"github.com/openimsdk/tools/errs"
|
||||||
"github.com/openimsdk/tools/log"
|
"github.com/openimsdk/tools/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
type UserApi rpcclient.User
|
type UserApi struct {
|
||||||
|
Client user.UserClient
|
||||||
|
discov discovery.SvcDiscoveryRegistry
|
||||||
|
config config.RpcService
|
||||||
|
}
|
||||||
|
|
||||||
func NewUserApi(client rpcclient.User) UserApi {
|
func NewUserApi(client user.UserClient, discov discovery.SvcDiscoveryRegistry, config config.RpcService) UserApi {
|
||||||
return UserApi(client)
|
return UserApi{Client: client, discov: discov, config: config}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *UserApi) UserRegister(c *gin.Context) {
|
func (u *UserApi) UserRegister(c *gin.Context) {
|
||||||
a2r.Call(user.UserClient.UserRegister, u.Client, c)
|
a2r.Call(c, user.UserClient.UserRegister, u.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateUserInfo is deprecated. Use UpdateUserInfoEx
|
// UpdateUserInfo is deprecated. Use UpdateUserInfoEx
|
||||||
func (u *UserApi) UpdateUserInfo(c *gin.Context) {
|
func (u *UserApi) UpdateUserInfo(c *gin.Context) {
|
||||||
a2r.Call(user.UserClient.UpdateUserInfo, u.Client, c)
|
a2r.Call(c, user.UserClient.UpdateUserInfo, u.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *UserApi) UpdateUserInfoEx(c *gin.Context) {
|
func (u *UserApi) UpdateUserInfoEx(c *gin.Context) {
|
||||||
a2r.Call(user.UserClient.UpdateUserInfoEx, u.Client, c)
|
a2r.Call(c, user.UserClient.UpdateUserInfoEx, u.Client)
|
||||||
}
|
}
|
||||||
func (u *UserApi) SetGlobalRecvMessageOpt(c *gin.Context) {
|
func (u *UserApi) SetGlobalRecvMessageOpt(c *gin.Context) {
|
||||||
a2r.Call(user.UserClient.SetGlobalRecvMessageOpt, u.Client, c)
|
a2r.Call(c, user.UserClient.SetGlobalRecvMessageOpt, u.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *UserApi) GetUsersPublicInfo(c *gin.Context) {
|
func (u *UserApi) GetUsersPublicInfo(c *gin.Context) {
|
||||||
a2r.Call(user.UserClient.GetDesignateUsers, u.Client, c)
|
a2r.Call(c, user.UserClient.GetDesignateUsers, u.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *UserApi) GetAllUsersID(c *gin.Context) {
|
func (u *UserApi) GetAllUsersID(c *gin.Context) {
|
||||||
a2r.Call(user.UserClient.GetAllUserID, u.Client, c)
|
a2r.Call(c, user.UserClient.GetAllUserID, u.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *UserApi) AccountCheck(c *gin.Context) {
|
func (u *UserApi) AccountCheck(c *gin.Context) {
|
||||||
a2r.Call(user.UserClient.AccountCheck, u.Client, c)
|
a2r.Call(c, user.UserClient.AccountCheck, u.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *UserApi) GetUsers(c *gin.Context) {
|
func (u *UserApi) GetUsers(c *gin.Context) {
|
||||||
a2r.Call(user.UserClient.GetPaginationUsers, u.Client, c)
|
a2r.Call(c, user.UserClient.GetPaginationUsers, u.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetUsersOnlineStatus Get user online status.
|
// GetUsersOnlineStatus Get user online status.
|
||||||
@ -71,7 +76,7 @@ func (u *UserApi) GetUsersOnlineStatus(c *gin.Context) {
|
|||||||
apiresp.GinError(c, err)
|
apiresp.GinError(c, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
conns, err := u.Discov.GetConns(c, u.MessageGateWayRpcName)
|
conns, err := u.discov.GetConns(c, u.config.MessageGateway)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
apiresp.GinError(c, err)
|
apiresp.GinError(c, err)
|
||||||
return
|
return
|
||||||
@ -122,7 +127,7 @@ func (u *UserApi) GetUsersOnlineStatus(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (u *UserApi) UserRegisterCount(c *gin.Context) {
|
func (u *UserApi) UserRegisterCount(c *gin.Context) {
|
||||||
a2r.Call(user.UserClient.UserRegisterCount, u.Client, c)
|
a2r.Call(c, user.UserClient.UserRegisterCount, u.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetUsersOnlineTokenDetail Get user online token details.
|
// GetUsersOnlineTokenDetail Get user online token details.
|
||||||
@ -135,7 +140,7 @@ func (u *UserApi) GetUsersOnlineTokenDetail(c *gin.Context) {
|
|||||||
apiresp.GinError(c, errs.ErrArgs.WithDetail(err.Error()).Wrap())
|
apiresp.GinError(c, errs.ErrArgs.WithDetail(err.Error()).Wrap())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
conns, err := u.Discov.GetConns(c, u.MessageGateWayRpcName)
|
conns, err := u.discov.GetConns(c, u.config.MessageGateway)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
apiresp.GinError(c, err)
|
apiresp.GinError(c, err)
|
||||||
return
|
return
|
||||||
@ -188,52 +193,52 @@ func (u *UserApi) GetUsersOnlineTokenDetail(c *gin.Context) {
|
|||||||
|
|
||||||
// SubscriberStatus Presence status of subscribed users.
|
// SubscriberStatus Presence status of subscribed users.
|
||||||
func (u *UserApi) SubscriberStatus(c *gin.Context) {
|
func (u *UserApi) SubscriberStatus(c *gin.Context) {
|
||||||
a2r.Call(user.UserClient.SubscribeOrCancelUsersStatus, u.Client, c)
|
a2r.Call(c, user.UserClient.SubscribeOrCancelUsersStatus, u.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetUserStatus Get the online status of the user.
|
// GetUserStatus Get the online status of the user.
|
||||||
func (u *UserApi) GetUserStatus(c *gin.Context) {
|
func (u *UserApi) GetUserStatus(c *gin.Context) {
|
||||||
a2r.Call(user.UserClient.GetUserStatus, u.Client, c)
|
a2r.Call(c, user.UserClient.GetUserStatus, u.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetSubscribeUsersStatus Get the online status of subscribers.
|
// GetSubscribeUsersStatus Get the online status of subscribers.
|
||||||
func (u *UserApi) GetSubscribeUsersStatus(c *gin.Context) {
|
func (u *UserApi) GetSubscribeUsersStatus(c *gin.Context) {
|
||||||
a2r.Call(user.UserClient.GetSubscribeUsersStatus, u.Client, c)
|
a2r.Call(c, user.UserClient.GetSubscribeUsersStatus, u.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ProcessUserCommandAdd user general function add.
|
// ProcessUserCommandAdd user general function add.
|
||||||
func (u *UserApi) ProcessUserCommandAdd(c *gin.Context) {
|
func (u *UserApi) ProcessUserCommandAdd(c *gin.Context) {
|
||||||
a2r.Call(user.UserClient.ProcessUserCommandAdd, u.Client, c)
|
a2r.Call(c, user.UserClient.ProcessUserCommandAdd, u.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ProcessUserCommandDelete user general function delete.
|
// ProcessUserCommandDelete user general function delete.
|
||||||
func (u *UserApi) ProcessUserCommandDelete(c *gin.Context) {
|
func (u *UserApi) ProcessUserCommandDelete(c *gin.Context) {
|
||||||
a2r.Call(user.UserClient.ProcessUserCommandDelete, u.Client, c)
|
a2r.Call(c, user.UserClient.ProcessUserCommandDelete, u.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ProcessUserCommandUpdate user general function update.
|
// ProcessUserCommandUpdate user general function update.
|
||||||
func (u *UserApi) ProcessUserCommandUpdate(c *gin.Context) {
|
func (u *UserApi) ProcessUserCommandUpdate(c *gin.Context) {
|
||||||
a2r.Call(user.UserClient.ProcessUserCommandUpdate, u.Client, c)
|
a2r.Call(c, user.UserClient.ProcessUserCommandUpdate, u.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ProcessUserCommandGet user general function get.
|
// ProcessUserCommandGet user general function get.
|
||||||
func (u *UserApi) ProcessUserCommandGet(c *gin.Context) {
|
func (u *UserApi) ProcessUserCommandGet(c *gin.Context) {
|
||||||
a2r.Call(user.UserClient.ProcessUserCommandGet, u.Client, c)
|
a2r.Call(c, user.UserClient.ProcessUserCommandGet, u.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ProcessUserCommandGet user general function get all.
|
// ProcessUserCommandGet user general function get all.
|
||||||
func (u *UserApi) ProcessUserCommandGetAll(c *gin.Context) {
|
func (u *UserApi) ProcessUserCommandGetAll(c *gin.Context) {
|
||||||
a2r.Call(user.UserClient.ProcessUserCommandGetAll, u.Client, c)
|
a2r.Call(c, user.UserClient.ProcessUserCommandGetAll, u.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *UserApi) AddNotificationAccount(c *gin.Context) {
|
func (u *UserApi) AddNotificationAccount(c *gin.Context) {
|
||||||
a2r.Call(user.UserClient.AddNotificationAccount, u.Client, c)
|
a2r.Call(c, user.UserClient.AddNotificationAccount, u.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *UserApi) UpdateNotificationAccountInfo(c *gin.Context) {
|
func (u *UserApi) UpdateNotificationAccountInfo(c *gin.Context) {
|
||||||
a2r.Call(user.UserClient.UpdateNotificationAccountInfo, u.Client, c)
|
a2r.Call(c, user.UserClient.UpdateNotificationAccountInfo, u.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *UserApi) SearchNotificationAccount(c *gin.Context) {
|
func (u *UserApi) SearchNotificationAccount(c *gin.Context) {
|
||||||
a2r.Call(user.UserClient.SearchNotificationAccount, u.Client, c)
|
a2r.Call(c, user.UserClient.SearchNotificationAccount, u.Client)
|
||||||
}
|
}
|
||||||
|
@ -16,8 +16,8 @@ package msggateway
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"runtime/debug"
|
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
@ -69,6 +69,8 @@ type Client struct {
|
|||||||
IsCompress bool `json:"isCompress"`
|
IsCompress bool `json:"isCompress"`
|
||||||
UserID string `json:"userID"`
|
UserID string `json:"userID"`
|
||||||
IsBackground bool `json:"isBackground"`
|
IsBackground bool `json:"isBackground"`
|
||||||
|
SDKType string `json:"sdkType"`
|
||||||
|
Encoder Encoder
|
||||||
ctx *UserConnContext
|
ctx *UserConnContext
|
||||||
longConnServer LongConnServer
|
longConnServer LongConnServer
|
||||||
closed atomic.Bool
|
closed atomic.Bool
|
||||||
@ -94,11 +96,17 @@ func (c *Client) ResetClient(ctx *UserConnContext, conn LongConn, longConnServer
|
|||||||
c.closed.Store(false)
|
c.closed.Store(false)
|
||||||
c.closedErr = nil
|
c.closedErr = nil
|
||||||
c.token = ctx.GetToken()
|
c.token = ctx.GetToken()
|
||||||
|
c.SDKType = ctx.GetSDKType()
|
||||||
c.hbCtx, c.hbCancel = context.WithCancel(c.ctx)
|
c.hbCtx, c.hbCancel = context.WithCancel(c.ctx)
|
||||||
c.subLock = new(sync.Mutex)
|
c.subLock = new(sync.Mutex)
|
||||||
if c.subUserIDs != nil {
|
if c.subUserIDs != nil {
|
||||||
clear(c.subUserIDs)
|
clear(c.subUserIDs)
|
||||||
}
|
}
|
||||||
|
if c.SDKType == GoSDK {
|
||||||
|
c.Encoder = NewGobEncoder()
|
||||||
|
} else {
|
||||||
|
c.Encoder = NewJsonEncoder()
|
||||||
|
}
|
||||||
c.subUserIDs = make(map[string]struct{})
|
c.subUserIDs = make(map[string]struct{})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -123,7 +131,7 @@ func (c *Client) readMessage() {
|
|||||||
defer func() {
|
defer func() {
|
||||||
if r := recover(); r != nil {
|
if r := recover(); r != nil {
|
||||||
c.closedErr = ErrPanic
|
c.closedErr = ErrPanic
|
||||||
fmt.Println("socket have panic err:", r, string(debug.Stack()))
|
log.ZPanic(c.ctx, "socket have panic err:", errs.ErrPanic(r))
|
||||||
}
|
}
|
||||||
c.close()
|
c.close()
|
||||||
}()
|
}()
|
||||||
@ -159,9 +167,12 @@ func (c *Client) readMessage() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
case MessageText:
|
case MessageText:
|
||||||
c.closedErr = ErrNotSupportMessageProtocol
|
_ = c.conn.SetReadDeadline(pongWait)
|
||||||
return
|
parseDataErr := c.handlerTextMessage(message)
|
||||||
|
if parseDataErr != nil {
|
||||||
|
c.closedErr = parseDataErr
|
||||||
|
return
|
||||||
|
}
|
||||||
case PingMessage:
|
case PingMessage:
|
||||||
err := c.writePongMsg("")
|
err := c.writePongMsg("")
|
||||||
log.ZError(c.ctx, "writePongMsg", err)
|
log.ZError(c.ctx, "writePongMsg", err)
|
||||||
@ -188,7 +199,7 @@ func (c *Client) handleMessage(message []byte) error {
|
|||||||
var binaryReq = getReq()
|
var binaryReq = getReq()
|
||||||
defer freeReq(binaryReq)
|
defer freeReq(binaryReq)
|
||||||
|
|
||||||
err := c.longConnServer.Decode(message, binaryReq)
|
err := c.Encoder.Decode(message, binaryReq)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -225,6 +236,8 @@ func (c *Client) handleMessage(message []byte) error {
|
|||||||
resp, messageErr = c.longConnServer.GetSeqMessage(ctx, binaryReq)
|
resp, messageErr = c.longConnServer.GetSeqMessage(ctx, binaryReq)
|
||||||
case WSGetConvMaxReadSeq:
|
case WSGetConvMaxReadSeq:
|
||||||
resp, messageErr = c.longConnServer.GetConversationsHasReadAndMaxSeq(ctx, binaryReq)
|
resp, messageErr = c.longConnServer.GetConversationsHasReadAndMaxSeq(ctx, binaryReq)
|
||||||
|
case WsPullConvLastMessage:
|
||||||
|
resp, messageErr = c.longConnServer.GetLastMessage(ctx, binaryReq)
|
||||||
case WsLogoutMsg:
|
case WsLogoutMsg:
|
||||||
resp, messageErr = c.longConnServer.UserLogout(ctx, binaryReq)
|
resp, messageErr = c.longConnServer.UserLogout(ctx, binaryReq)
|
||||||
case WsSetBackgroundStatus:
|
case WsSetBackgroundStatus:
|
||||||
@ -335,7 +348,7 @@ func (c *Client) writeBinaryMsg(resp Resp) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
encodedBuf, err := c.longConnServer.Encode(resp)
|
encodedBuf, err := c.Encoder.Encode(resp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -363,6 +376,11 @@ func (c *Client) writeBinaryMsg(resp Resp) error {
|
|||||||
func (c *Client) activeHeartbeat(ctx context.Context) {
|
func (c *Client) activeHeartbeat(ctx context.Context) {
|
||||||
if c.PlatformID == constant.WebPlatformID {
|
if c.PlatformID == constant.WebPlatformID {
|
||||||
go func() {
|
go func() {
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
log.ZPanic(ctx, "activeHeartbeat Panic", errs.ErrPanic(r))
|
||||||
|
}
|
||||||
|
}()
|
||||||
log.ZDebug(ctx, "server initiative send heartbeat start.")
|
log.ZDebug(ctx, "server initiative send heartbeat start.")
|
||||||
ticker := time.NewTicker(pingPeriod)
|
ticker := time.NewTicker(pingPeriod)
|
||||||
defer ticker.Stop()
|
defer ticker.Stop()
|
||||||
@ -419,3 +437,28 @@ func (c *Client) writePongMsg(appData string) error {
|
|||||||
|
|
||||||
return errs.Wrap(err)
|
return errs.Wrap(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Client) handlerTextMessage(b []byte) error {
|
||||||
|
var msg TextMessage
|
||||||
|
if err := json.Unmarshal(b, &msg); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
switch msg.Type {
|
||||||
|
case TextPong:
|
||||||
|
return nil
|
||||||
|
case TextPing:
|
||||||
|
msg.Type = TextPong
|
||||||
|
msgData, err := json.Marshal(msg)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
c.w.Lock()
|
||||||
|
defer c.w.Unlock()
|
||||||
|
if err := c.conn.SetWriteDeadline(writeWait); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return c.conn.WriteMessage(MessageText, msgData)
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("not support message type %s", msg.Type)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -27,6 +27,12 @@ const (
|
|||||||
GzipCompressionProtocol = "gzip"
|
GzipCompressionProtocol = "gzip"
|
||||||
BackgroundStatus = "isBackground"
|
BackgroundStatus = "isBackground"
|
||||||
SendResponse = "isMsgResp"
|
SendResponse = "isMsgResp"
|
||||||
|
SDKType = "sdkType"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
GoSDK = "go"
|
||||||
|
JsSDK = "js"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -41,6 +47,7 @@ const (
|
|||||||
WSSendSignalMsg = 1004
|
WSSendSignalMsg = 1004
|
||||||
WSPullMsg = 1005
|
WSPullMsg = 1005
|
||||||
WSGetConvMaxReadSeq = 1006
|
WSGetConvMaxReadSeq = 1006
|
||||||
|
WsPullConvLastMessage = 1007
|
||||||
WSPushMsg = 2001
|
WSPushMsg = 2001
|
||||||
WSKickOnlineMsg = 2002
|
WSKickOnlineMsg = 2002
|
||||||
WsLogoutMsg = 2003
|
WsLogoutMsg = 2003
|
||||||
|
@ -153,6 +153,14 @@ func (c *UserConnContext) GetCompression() bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *UserConnContext) GetSDKType() string {
|
||||||
|
sdkType := c.Req.URL.Query().Get(SDKType)
|
||||||
|
if sdkType == "" {
|
||||||
|
sdkType = GoSDK
|
||||||
|
}
|
||||||
|
return sdkType
|
||||||
|
}
|
||||||
|
|
||||||
func (c *UserConnContext) ShouldSendResp() bool {
|
func (c *UserConnContext) ShouldSendResp() bool {
|
||||||
errResp, exists := c.Query(SendResponse)
|
errResp, exists := c.Query(SendResponse)
|
||||||
if exists {
|
if exists {
|
||||||
@ -193,7 +201,11 @@ func (c *UserConnContext) ParseEssentialArgs() error {
|
|||||||
_, err := strconv.Atoi(platformIDStr)
|
_, err := strconv.Atoi(platformIDStr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return servererrs.ErrConnArgsErr.WrapMsg("platformID is not int")
|
return servererrs.ErrConnArgsErr.WrapMsg("platformID is not int")
|
||||||
|
}
|
||||||
|
switch sdkType, _ := c.Query(SDKType); sdkType {
|
||||||
|
case "", GoSDK, JsSDK:
|
||||||
|
default:
|
||||||
|
return servererrs.ErrConnArgsErr.WrapMsg("sdkType is not go or js")
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@ package msggateway
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/gob"
|
"encoding/gob"
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
"github.com/openimsdk/tools/errs"
|
"github.com/openimsdk/tools/errs"
|
||||||
)
|
)
|
||||||
@ -28,12 +29,12 @@ type Encoder interface {
|
|||||||
|
|
||||||
type GobEncoder struct{}
|
type GobEncoder struct{}
|
||||||
|
|
||||||
func NewGobEncoder() *GobEncoder {
|
func NewGobEncoder() Encoder {
|
||||||
return &GobEncoder{}
|
return GobEncoder{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GobEncoder) Encode(data any) ([]byte, error) {
|
func (g GobEncoder) Encode(data any) ([]byte, error) {
|
||||||
buff := bytes.Buffer{}
|
var buff bytes.Buffer
|
||||||
enc := gob.NewEncoder(&buff)
|
enc := gob.NewEncoder(&buff)
|
||||||
if err := enc.Encode(data); err != nil {
|
if err := enc.Encode(data); err != nil {
|
||||||
return nil, errs.WrapMsg(err, "GobEncoder.Encode failed", "action", "encode")
|
return nil, errs.WrapMsg(err, "GobEncoder.Encode failed", "action", "encode")
|
||||||
@ -41,7 +42,7 @@ func (g *GobEncoder) Encode(data any) ([]byte, error) {
|
|||||||
return buff.Bytes(), nil
|
return buff.Bytes(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GobEncoder) Decode(encodeData []byte, decodeData any) error {
|
func (g GobEncoder) Decode(encodeData []byte, decodeData any) error {
|
||||||
buff := bytes.NewBuffer(encodeData)
|
buff := bytes.NewBuffer(encodeData)
|
||||||
dec := gob.NewDecoder(buff)
|
dec := gob.NewDecoder(buff)
|
||||||
if err := dec.Decode(decodeData); err != nil {
|
if err := dec.Decode(decodeData); err != nil {
|
||||||
@ -49,3 +50,25 @@ func (g *GobEncoder) Decode(encodeData []byte, decodeData any) error {
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type JsonEncoder struct{}
|
||||||
|
|
||||||
|
func NewJsonEncoder() Encoder {
|
||||||
|
return JsonEncoder{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g JsonEncoder) Encode(data any) ([]byte, error) {
|
||||||
|
b, err := json.Marshal(data)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errs.New("JsonEncoder.Encode failed", "action", "encode")
|
||||||
|
}
|
||||||
|
return b, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g JsonEncoder) Decode(encodeData []byte, decodeData any) error {
|
||||||
|
err := json.Unmarshal(encodeData, decodeData)
|
||||||
|
if err != nil {
|
||||||
|
return errs.New("JsonEncoder.Decode failed", "action", "decode")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
@ -18,10 +18,11 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
|
|
||||||
|
"github.com/openimsdk/open-im-server/v3/pkg/rpcli"
|
||||||
|
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/authverify"
|
"github.com/openimsdk/open-im-server/v3/pkg/authverify"
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/common/servererrs"
|
"github.com/openimsdk/open-im-server/v3/pkg/common/servererrs"
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/common/startrpc"
|
"github.com/openimsdk/open-im-server/v3/pkg/common/startrpc"
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
|
|
||||||
"github.com/openimsdk/protocol/constant"
|
"github.com/openimsdk/protocol/constant"
|
||||||
"github.com/openimsdk/protocol/msggateway"
|
"github.com/openimsdk/protocol/msggateway"
|
||||||
"github.com/openimsdk/protocol/sdkws"
|
"github.com/openimsdk/protocol/sdkws"
|
||||||
@ -35,9 +36,15 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func (s *Server) InitServer(ctx context.Context, config *Config, disCov discovery.SvcDiscoveryRegistry, server *grpc.Server) error {
|
func (s *Server) InitServer(ctx context.Context, config *Config, disCov discovery.SvcDiscoveryRegistry, server *grpc.Server) error {
|
||||||
s.LongConnServer.SetDiscoveryRegistry(disCov, config)
|
userConn, err := disCov.GetConn(ctx, config.Discovery.RpcService.User)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
s.userClient = rpcli.NewUserClient(userConn)
|
||||||
|
if err := s.LongConnServer.SetDiscoveryRegistry(ctx, disCov, config); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
msggateway.RegisterMsgGatewayServer(server, s)
|
msggateway.RegisterMsgGatewayServer(server, s)
|
||||||
s.userRcp = rpcclient.NewUserRpcClient(disCov, config.Share.RpcRegisterName.User, config.Share.IMAdminUserID)
|
|
||||||
if s.ready != nil {
|
if s.ready != nil {
|
||||||
return s.ready(s)
|
return s.ready(s)
|
||||||
}
|
}
|
||||||
@ -47,31 +54,41 @@ func (s *Server) InitServer(ctx context.Context, config *Config, disCov discover
|
|||||||
func (s *Server) Start(ctx context.Context, index int, conf *Config) error {
|
func (s *Server) Start(ctx context.Context, index int, conf *Config) error {
|
||||||
return startrpc.Start(ctx, &conf.Discovery, &conf.MsgGateway.Prometheus, conf.MsgGateway.ListenIP,
|
return startrpc.Start(ctx, &conf.Discovery, &conf.MsgGateway.Prometheus, conf.MsgGateway.ListenIP,
|
||||||
conf.MsgGateway.RPC.RegisterIP,
|
conf.MsgGateway.RPC.RegisterIP,
|
||||||
conf.MsgGateway.RPC.Ports, index,
|
conf.MsgGateway.RPC.AutoSetPorts, conf.MsgGateway.RPC.Ports, index,
|
||||||
conf.Share.RpcRegisterName.MessageGateway,
|
conf.Discovery.RpcService.MessageGateway,
|
||||||
&conf.Share,
|
nil,
|
||||||
conf,
|
conf,
|
||||||
|
[]string{
|
||||||
|
conf.Share.GetConfigFileName(),
|
||||||
|
conf.Discovery.GetConfigFileName(),
|
||||||
|
conf.MsgGateway.GetConfigFileName(),
|
||||||
|
conf.WebhooksConfig.GetConfigFileName(),
|
||||||
|
conf.RedisConfig.GetConfigFileName(),
|
||||||
|
},
|
||||||
|
[]string{
|
||||||
|
conf.Discovery.RpcService.MessageGateway,
|
||||||
|
},
|
||||||
s.InitServer,
|
s.InitServer,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
type Server struct {
|
type Server struct {
|
||||||
rpcPort int
|
msggateway.UnimplementedMsgGatewayServer
|
||||||
|
|
||||||
LongConnServer LongConnServer
|
LongConnServer LongConnServer
|
||||||
config *Config
|
config *Config
|
||||||
pushTerminal map[int]struct{}
|
pushTerminal map[int]struct{}
|
||||||
ready func(srv *Server) error
|
ready func(srv *Server) error
|
||||||
userRcp rpcclient.UserRpcClient
|
|
||||||
queue *memamq.MemoryQueue
|
queue *memamq.MemoryQueue
|
||||||
|
userClient *rpcli.UserClient
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) SetLongConnServer(LongConnServer LongConnServer) {
|
func (s *Server) SetLongConnServer(LongConnServer LongConnServer) {
|
||||||
s.LongConnServer = LongConnServer
|
s.LongConnServer = LongConnServer
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewServer(rpcPort int, longConnServer LongConnServer, conf *Config, ready func(srv *Server) error) *Server {
|
func NewServer(longConnServer LongConnServer, conf *Config, ready func(srv *Server) error) *Server {
|
||||||
s := &Server{
|
s := &Server{
|
||||||
rpcPort: rpcPort,
|
|
||||||
LongConnServer: longConnServer,
|
LongConnServer: longConnServer,
|
||||||
pushTerminal: make(map[int]struct{}),
|
pushTerminal: make(map[int]struct{}),
|
||||||
config: conf,
|
config: conf,
|
||||||
@ -83,17 +100,7 @@ func NewServer(rpcPort int, longConnServer LongConnServer, conf *Config, ready f
|
|||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) OnlinePushMsg(
|
func (s *Server) GetUsersOnlineStatus(ctx context.Context, req *msggateway.GetUsersOnlineStatusReq) (*msggateway.GetUsersOnlineStatusResp, error) {
|
||||||
context context.Context,
|
|
||||||
req *msggateway.OnlinePushMsgReq,
|
|
||||||
) (*msggateway.OnlinePushMsgResp, error) {
|
|
||||||
panic("implement me")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Server) GetUsersOnlineStatus(
|
|
||||||
ctx context.Context,
|
|
||||||
req *msggateway.GetUsersOnlineStatusReq,
|
|
||||||
) (*msggateway.GetUsersOnlineStatusResp, error) {
|
|
||||||
if !authverify.IsAppManagerUid(ctx, s.config.Share.IMAdminUserID) {
|
if !authverify.IsAppManagerUid(ctx, s.config.Share.IMAdminUserID) {
|
||||||
return nil, errs.ErrNoPermission.WrapMsg("only app manager")
|
return nil, errs.ErrNoPermission.WrapMsg("only app manager")
|
||||||
}
|
}
|
||||||
@ -126,11 +133,6 @@ func (s *Server) GetUsersOnlineStatus(
|
|||||||
return &resp, nil
|
return &resp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) OnlineBatchPushOneMsg(ctx context.Context, req *msggateway.OnlineBatchPushOneMsgReq) (*msggateway.OnlineBatchPushOneMsgResp, error) {
|
|
||||||
// todo implement
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Server) pushToUser(ctx context.Context, userID string, msgData *sdkws.MsgData) *msggateway.SingleMsgToUserResults {
|
func (s *Server) pushToUser(ctx context.Context, userID string, msgData *sdkws.MsgData) *msggateway.SingleMsgToUserResults {
|
||||||
clients, ok := s.LongConnServer.GetUserAllCons(userID)
|
clients, ok := s.LongConnServer.GetUserAllCons(userID)
|
||||||
if !ok {
|
if !ok {
|
||||||
@ -155,6 +157,7 @@ func (s *Server) pushToUser(ctx context.Context, userID string, msgData *sdkws.M
|
|||||||
(client.IsBackground && client.PlatformID != constant.IOSPlatformID) {
|
(client.IsBackground && client.PlatformID != constant.IOSPlatformID) {
|
||||||
err := client.PushMessage(ctx, msgData)
|
err := client.PushMessage(ctx, msgData)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
log.ZWarn(ctx, "online push msg failed", err, "userID", userID, "platformID", client.PlatformID)
|
||||||
userPlatform.ResultCode = int64(servererrs.ErrPushMsgErr.Code())
|
userPlatform.ResultCode = int64(servererrs.ErrPushMsgErr.Code())
|
||||||
} else {
|
} else {
|
||||||
if _, ok := s.pushTerminal[client.PlatformID]; ok {
|
if _, ok := s.pushTerminal[client.PlatformID]; ok {
|
||||||
@ -220,10 +223,7 @@ func (s *Server) SuperGroupOnlineBatchPushOneMsg(ctx context.Context, req *msgga
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) KickUserOffline(
|
func (s *Server) KickUserOffline(ctx context.Context, req *msggateway.KickUserOfflineReq) (*msggateway.KickUserOfflineResp, error) {
|
||||||
ctx context.Context,
|
|
||||||
req *msggateway.KickUserOfflineReq,
|
|
||||||
) (*msggateway.KickUserOfflineResp, error) {
|
|
||||||
for _, v := range req.KickUserIDList {
|
for _, v := range req.KickUserIDList {
|
||||||
clients, _, ok := s.LongConnServer.GetUserPlatformCons(v, int(req.PlatformID))
|
clients, _, ok := s.LongConnServer.GetUserPlatformCons(v, int(req.PlatformID))
|
||||||
if !ok {
|
if !ok {
|
||||||
|
@ -16,13 +16,13 @@ package msggateway
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/rpccache"
|
"github.com/openimsdk/open-im-server/v3/pkg/rpccache"
|
||||||
"github.com/openimsdk/tools/db/redisutil"
|
"github.com/openimsdk/tools/db/redisutil"
|
||||||
"github.com/openimsdk/tools/utils/datautil"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/openimsdk/tools/log"
|
"github.com/openimsdk/tools/log"
|
||||||
|
"github.com/openimsdk/tools/utils/datautil"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
@ -35,16 +35,13 @@ type Config struct {
|
|||||||
|
|
||||||
// Start run ws server.
|
// Start run ws server.
|
||||||
func Start(ctx context.Context, index int, conf *Config) error {
|
func Start(ctx context.Context, index int, conf *Config) error {
|
||||||
log.CInfo(ctx, "MSG-GATEWAY server is initializing", "rpcPorts", conf.MsgGateway.RPC.Ports,
|
log.CInfo(ctx, "MSG-GATEWAY server is initializing", "autoSetPorts", conf.MsgGateway.RPC.AutoSetPorts,
|
||||||
|
"rpcPorts", conf.MsgGateway.RPC.Ports,
|
||||||
"wsPort", conf.MsgGateway.LongConnSvr.Ports, "prometheusPorts", conf.MsgGateway.Prometheus.Ports)
|
"wsPort", conf.MsgGateway.LongConnSvr.Ports, "prometheusPorts", conf.MsgGateway.Prometheus.Ports)
|
||||||
wsPort, err := datautil.GetElemByIndex(conf.MsgGateway.LongConnSvr.Ports, index)
|
wsPort, err := datautil.GetElemByIndex(conf.MsgGateway.LongConnSvr.Ports, index)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
rpcPort, err := datautil.GetElemByIndex(conf.MsgGateway.RPC.Ports, index)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
rdb, err := redisutil.NewRedisClient(ctx, conf.RedisConfig.Build())
|
rdb, err := redisutil.NewRedisClient(ctx, conf.RedisConfig.Build())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -57,9 +54,10 @@ func Start(ctx context.Context, index int, conf *Config) error {
|
|||||||
WithMessageMaxMsgLength(conf.MsgGateway.LongConnSvr.WebsocketMaxMsgLen),
|
WithMessageMaxMsgLength(conf.MsgGateway.LongConnSvr.WebsocketMaxMsgLen),
|
||||||
)
|
)
|
||||||
|
|
||||||
hubServer := NewServer(rpcPort, longServer, conf, func(srv *Server) error {
|
hubServer := NewServer(longServer, conf, func(srv *Server) error {
|
||||||
longServer.online, _ = rpccache.NewOnlineCache(srv.userRcp, nil, rdb, false, longServer.subscriberUserOnlineStatusChanges)
|
var err error
|
||||||
return nil
|
longServer.online, err = rpccache.NewOnlineCache(srv.userClient, nil, rdb, false, longServer.subscriberUserOnlineStatusChanges)
|
||||||
|
return err
|
||||||
})
|
})
|
||||||
|
|
||||||
go longServer.ChangeOnlineStatus(4)
|
go longServer.ChangeOnlineStatus(4)
|
||||||
|
@ -16,21 +16,30 @@ package msggateway
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"github.com/openimsdk/open-im-server/v3/pkg/rpcli"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/go-playground/validator/v10"
|
"github.com/go-playground/validator/v10"
|
||||||
"google.golang.org/protobuf/proto"
|
"google.golang.org/protobuf/proto"
|
||||||
|
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
|
|
||||||
"github.com/openimsdk/protocol/msg"
|
"github.com/openimsdk/protocol/msg"
|
||||||
"github.com/openimsdk/protocol/push"
|
"github.com/openimsdk/protocol/push"
|
||||||
"github.com/openimsdk/protocol/sdkws"
|
"github.com/openimsdk/protocol/sdkws"
|
||||||
"github.com/openimsdk/tools/discovery"
|
|
||||||
"github.com/openimsdk/tools/errs"
|
"github.com/openimsdk/tools/errs"
|
||||||
"github.com/openimsdk/tools/utils/jsonutil"
|
"github.com/openimsdk/tools/utils/jsonutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
TextPing = "ping"
|
||||||
|
TextPong = "pong"
|
||||||
|
)
|
||||||
|
|
||||||
|
type TextMessage struct {
|
||||||
|
Type string `json:"type"`
|
||||||
|
Body json.RawMessage `json:"body"`
|
||||||
|
}
|
||||||
|
|
||||||
type Req struct {
|
type Req struct {
|
||||||
ReqIdentifier int32 `json:"reqIdentifier" validate:"required"`
|
ReqIdentifier int32 `json:"reqIdentifier" validate:"required"`
|
||||||
Token string `json:"token"`
|
Token string `json:"token"`
|
||||||
@ -91,34 +100,34 @@ func (r *Resp) String() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type MessageHandler interface {
|
type MessageHandler interface {
|
||||||
GetSeq(context context.Context, data *Req) ([]byte, error)
|
GetSeq(ctx context.Context, data *Req) ([]byte, error)
|
||||||
SendMessage(context context.Context, data *Req) ([]byte, error)
|
SendMessage(ctx context.Context, data *Req) ([]byte, error)
|
||||||
SendSignalMessage(context context.Context, data *Req) ([]byte, error)
|
SendSignalMessage(ctx context.Context, data *Req) ([]byte, error)
|
||||||
PullMessageBySeqList(context context.Context, data *Req) ([]byte, error)
|
PullMessageBySeqList(ctx context.Context, data *Req) ([]byte, error)
|
||||||
GetConversationsHasReadAndMaxSeq(context context.Context, data *Req) ([]byte, error)
|
GetConversationsHasReadAndMaxSeq(ctx context.Context, data *Req) ([]byte, error)
|
||||||
GetSeqMessage(context context.Context, data *Req) ([]byte, error)
|
GetSeqMessage(ctx context.Context, data *Req) ([]byte, error)
|
||||||
UserLogout(context context.Context, data *Req) ([]byte, error)
|
UserLogout(ctx context.Context, data *Req) ([]byte, error)
|
||||||
SetUserDeviceBackground(context context.Context, data *Req) ([]byte, bool, error)
|
SetUserDeviceBackground(ctx context.Context, data *Req) ([]byte, bool, error)
|
||||||
|
GetLastMessage(ctx context.Context, data *Req) ([]byte, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ MessageHandler = (*GrpcHandler)(nil)
|
var _ MessageHandler = (*GrpcHandler)(nil)
|
||||||
|
|
||||||
type GrpcHandler struct {
|
type GrpcHandler struct {
|
||||||
msgRpcClient *rpcclient.MessageRpcClient
|
validate *validator.Validate
|
||||||
pushClient *rpcclient.PushRpcClient
|
msgClient *rpcli.MsgClient
|
||||||
validate *validator.Validate
|
pushClient *rpcli.PushMsgServiceClient
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewGrpcHandler(validate *validator.Validate, client discovery.SvcDiscoveryRegistry, rpcRegisterName *config.RpcRegisterName) *GrpcHandler {
|
func NewGrpcHandler(validate *validator.Validate, msgClient *rpcli.MsgClient, pushClient *rpcli.PushMsgServiceClient) *GrpcHandler {
|
||||||
msgRpcClient := rpcclient.NewMessageRpcClient(client, rpcRegisterName.Msg)
|
|
||||||
pushRpcClient := rpcclient.NewPushRpcClient(client, rpcRegisterName.Push)
|
|
||||||
return &GrpcHandler{
|
return &GrpcHandler{
|
||||||
msgRpcClient: &msgRpcClient,
|
validate: validate,
|
||||||
pushClient: &pushRpcClient, validate: validate,
|
msgClient: msgClient,
|
||||||
|
pushClient: pushClient,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g GrpcHandler) GetSeq(ctx context.Context, data *Req) ([]byte, error) {
|
func (g *GrpcHandler) GetSeq(ctx context.Context, data *Req) ([]byte, error) {
|
||||||
req := sdkws.GetMaxSeqReq{}
|
req := sdkws.GetMaxSeqReq{}
|
||||||
if err := proto.Unmarshal(data.Data, &req); err != nil {
|
if err := proto.Unmarshal(data.Data, &req); err != nil {
|
||||||
return nil, errs.WrapMsg(err, "GetSeq: error unmarshaling request", "action", "unmarshal", "dataType", "GetMaxSeqReq")
|
return nil, errs.WrapMsg(err, "GetSeq: error unmarshaling request", "action", "unmarshal", "dataType", "GetMaxSeqReq")
|
||||||
@ -126,7 +135,7 @@ func (g GrpcHandler) GetSeq(ctx context.Context, data *Req) ([]byte, error) {
|
|||||||
if err := g.validate.Struct(&req); err != nil {
|
if err := g.validate.Struct(&req); err != nil {
|
||||||
return nil, errs.WrapMsg(err, "GetSeq: validation failed", "action", "validate", "dataType", "GetMaxSeqReq")
|
return nil, errs.WrapMsg(err, "GetSeq: validation failed", "action", "validate", "dataType", "GetMaxSeqReq")
|
||||||
}
|
}
|
||||||
resp, err := g.msgRpcClient.GetMaxSeq(ctx, &req)
|
resp, err := g.msgClient.MsgClient.GetMaxSeq(ctx, &req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -139,7 +148,7 @@ func (g GrpcHandler) GetSeq(ctx context.Context, data *Req) ([]byte, error) {
|
|||||||
|
|
||||||
// SendMessage handles the sending of messages through gRPC. It unmarshals the request data,
|
// SendMessage handles the sending of messages through gRPC. It unmarshals the request data,
|
||||||
// validates the message, and then sends it using the message RPC client.
|
// validates the message, and then sends it using the message RPC client.
|
||||||
func (g GrpcHandler) SendMessage(ctx context.Context, data *Req) ([]byte, error) {
|
func (g *GrpcHandler) SendMessage(ctx context.Context, data *Req) ([]byte, error) {
|
||||||
var msgData sdkws.MsgData
|
var msgData sdkws.MsgData
|
||||||
if err := proto.Unmarshal(data.Data, &msgData); err != nil {
|
if err := proto.Unmarshal(data.Data, &msgData); err != nil {
|
||||||
return nil, errs.WrapMsg(err, "SendMessage: error unmarshaling message data", "action", "unmarshal", "dataType", "MsgData")
|
return nil, errs.WrapMsg(err, "SendMessage: error unmarshaling message data", "action", "unmarshal", "dataType", "MsgData")
|
||||||
@ -150,7 +159,7 @@ func (g GrpcHandler) SendMessage(ctx context.Context, data *Req) ([]byte, error)
|
|||||||
}
|
}
|
||||||
|
|
||||||
req := msg.SendMsgReq{MsgData: &msgData}
|
req := msg.SendMsgReq{MsgData: &msgData}
|
||||||
resp, err := g.msgRpcClient.SendMsg(ctx, &req)
|
resp, err := g.msgClient.MsgClient.SendMsg(ctx, &req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -163,8 +172,8 @@ func (g GrpcHandler) SendMessage(ctx context.Context, data *Req) ([]byte, error)
|
|||||||
return c, nil
|
return c, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g GrpcHandler) SendSignalMessage(context context.Context, data *Req) ([]byte, error) {
|
func (g *GrpcHandler) SendSignalMessage(ctx context.Context, data *Req) ([]byte, error) {
|
||||||
resp, err := g.msgRpcClient.SendMsg(context, nil)
|
resp, err := g.msgClient.MsgClient.SendMsg(ctx, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -175,7 +184,7 @@ func (g GrpcHandler) SendSignalMessage(context context.Context, data *Req) ([]by
|
|||||||
return c, nil
|
return c, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g GrpcHandler) PullMessageBySeqList(context context.Context, data *Req) ([]byte, error) {
|
func (g *GrpcHandler) PullMessageBySeqList(ctx context.Context, data *Req) ([]byte, error) {
|
||||||
req := sdkws.PullMessageBySeqsReq{}
|
req := sdkws.PullMessageBySeqsReq{}
|
||||||
if err := proto.Unmarshal(data.Data, &req); err != nil {
|
if err := proto.Unmarshal(data.Data, &req); err != nil {
|
||||||
return nil, errs.WrapMsg(err, "err proto unmarshal", "action", "unmarshal", "dataType", "PullMessageBySeqsReq")
|
return nil, errs.WrapMsg(err, "err proto unmarshal", "action", "unmarshal", "dataType", "PullMessageBySeqsReq")
|
||||||
@ -183,7 +192,7 @@ func (g GrpcHandler) PullMessageBySeqList(context context.Context, data *Req) ([
|
|||||||
if err := g.validate.Struct(data); err != nil {
|
if err := g.validate.Struct(data); err != nil {
|
||||||
return nil, errs.WrapMsg(err, "validation failed", "action", "validate", "dataType", "PullMessageBySeqsReq")
|
return nil, errs.WrapMsg(err, "validation failed", "action", "validate", "dataType", "PullMessageBySeqsReq")
|
||||||
}
|
}
|
||||||
resp, err := g.msgRpcClient.PullMessageBySeqList(context, &req)
|
resp, err := g.msgClient.MsgClient.PullMessageBySeqs(ctx, &req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -194,7 +203,7 @@ func (g GrpcHandler) PullMessageBySeqList(context context.Context, data *Req) ([
|
|||||||
return c, nil
|
return c, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g GrpcHandler) GetConversationsHasReadAndMaxSeq(context context.Context, data *Req) ([]byte, error) {
|
func (g *GrpcHandler) GetConversationsHasReadAndMaxSeq(ctx context.Context, data *Req) ([]byte, error) {
|
||||||
req := msg.GetConversationsHasReadAndMaxSeqReq{}
|
req := msg.GetConversationsHasReadAndMaxSeqReq{}
|
||||||
if err := proto.Unmarshal(data.Data, &req); err != nil {
|
if err := proto.Unmarshal(data.Data, &req); err != nil {
|
||||||
return nil, errs.WrapMsg(err, "err proto unmarshal", "action", "unmarshal", "dataType", "GetConversationsHasReadAndMaxSeq")
|
return nil, errs.WrapMsg(err, "err proto unmarshal", "action", "unmarshal", "dataType", "GetConversationsHasReadAndMaxSeq")
|
||||||
@ -202,7 +211,7 @@ func (g GrpcHandler) GetConversationsHasReadAndMaxSeq(context context.Context, d
|
|||||||
if err := g.validate.Struct(data); err != nil {
|
if err := g.validate.Struct(data); err != nil {
|
||||||
return nil, errs.WrapMsg(err, "validation failed", "action", "validate", "dataType", "GetConversationsHasReadAndMaxSeq")
|
return nil, errs.WrapMsg(err, "validation failed", "action", "validate", "dataType", "GetConversationsHasReadAndMaxSeq")
|
||||||
}
|
}
|
||||||
resp, err := g.msgRpcClient.GetConversationsHasReadAndMaxSeq(context, &req)
|
resp, err := g.msgClient.MsgClient.GetConversationsHasReadAndMaxSeq(ctx, &req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -213,7 +222,7 @@ func (g GrpcHandler) GetConversationsHasReadAndMaxSeq(context context.Context, d
|
|||||||
return c, nil
|
return c, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g GrpcHandler) GetSeqMessage(context context.Context, data *Req) ([]byte, error) {
|
func (g *GrpcHandler) GetSeqMessage(ctx context.Context, data *Req) ([]byte, error) {
|
||||||
req := msg.GetSeqMessageReq{}
|
req := msg.GetSeqMessageReq{}
|
||||||
if err := proto.Unmarshal(data.Data, &req); err != nil {
|
if err := proto.Unmarshal(data.Data, &req); err != nil {
|
||||||
return nil, errs.WrapMsg(err, "error unmarshaling request", "action", "unmarshal", "dataType", "GetSeqMessage")
|
return nil, errs.WrapMsg(err, "error unmarshaling request", "action", "unmarshal", "dataType", "GetSeqMessage")
|
||||||
@ -221,7 +230,7 @@ func (g GrpcHandler) GetSeqMessage(context context.Context, data *Req) ([]byte,
|
|||||||
if err := g.validate.Struct(data); err != nil {
|
if err := g.validate.Struct(data); err != nil {
|
||||||
return nil, errs.WrapMsg(err, "validation failed", "action", "validate", "dataType", "GetSeqMessage")
|
return nil, errs.WrapMsg(err, "validation failed", "action", "validate", "dataType", "GetSeqMessage")
|
||||||
}
|
}
|
||||||
resp, err := g.msgRpcClient.GetSeqMessage(context, &req)
|
resp, err := g.msgClient.MsgClient.GetSeqMessage(ctx, &req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -232,12 +241,12 @@ func (g GrpcHandler) GetSeqMessage(context context.Context, data *Req) ([]byte,
|
|||||||
return c, nil
|
return c, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g GrpcHandler) UserLogout(context context.Context, data *Req) ([]byte, error) {
|
func (g *GrpcHandler) UserLogout(ctx context.Context, data *Req) ([]byte, error) {
|
||||||
req := push.DelUserPushTokenReq{}
|
req := push.DelUserPushTokenReq{}
|
||||||
if err := proto.Unmarshal(data.Data, &req); err != nil {
|
if err := proto.Unmarshal(data.Data, &req); err != nil {
|
||||||
return nil, errs.WrapMsg(err, "error unmarshaling request", "action", "unmarshal", "dataType", "DelUserPushTokenReq")
|
return nil, errs.WrapMsg(err, "error unmarshaling request", "action", "unmarshal", "dataType", "DelUserPushTokenReq")
|
||||||
}
|
}
|
||||||
resp, err := g.pushClient.DelUserPushToken(context, &req)
|
resp, err := g.pushClient.PushMsgServiceClient.DelUserPushToken(ctx, &req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -248,7 +257,7 @@ func (g GrpcHandler) UserLogout(context context.Context, data *Req) ([]byte, err
|
|||||||
return c, nil
|
return c, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g GrpcHandler) SetUserDeviceBackground(_ context.Context, data *Req) ([]byte, bool, error) {
|
func (g *GrpcHandler) SetUserDeviceBackground(ctx context.Context, data *Req) ([]byte, bool, error) {
|
||||||
req := sdkws.SetAppBackgroundStatusReq{}
|
req := sdkws.SetAppBackgroundStatusReq{}
|
||||||
if err := proto.Unmarshal(data.Data, &req); err != nil {
|
if err := proto.Unmarshal(data.Data, &req); err != nil {
|
||||||
return nil, false, errs.WrapMsg(err, "error unmarshaling request", "action", "unmarshal", "dataType", "SetAppBackgroundStatusReq")
|
return nil, false, errs.WrapMsg(err, "error unmarshaling request", "action", "unmarshal", "dataType", "SetAppBackgroundStatusReq")
|
||||||
@ -258,3 +267,15 @@ func (g GrpcHandler) SetUserDeviceBackground(_ context.Context, data *Req) ([]by
|
|||||||
}
|
}
|
||||||
return nil, req.IsBackground, nil
|
return nil, req.IsBackground, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (g *GrpcHandler) GetLastMessage(ctx context.Context, data *Req) ([]byte, error) {
|
||||||
|
var req msg.GetLastMessageReq
|
||||||
|
if err := proto.Unmarshal(data.Data, &req); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
resp, err := g.msgClient.GetLastMessage(ctx, &req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return proto.Marshal(resp)
|
||||||
|
}
|
||||||
|
@ -87,9 +87,22 @@ func (ws *WsServer) ChangeOnlineStatus(concurrent int) {
|
|||||||
opIdCtx := mcontext.SetOperationID(context.Background(), operationIDPrefix+strconv.FormatInt(count.Add(1), 10))
|
opIdCtx := mcontext.SetOperationID(context.Background(), operationIDPrefix+strconv.FormatInt(count.Add(1), 10))
|
||||||
ctx, cancel := context.WithTimeout(opIdCtx, time.Second*5)
|
ctx, cancel := context.WithTimeout(opIdCtx, time.Second*5)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
if _, err := ws.userClient.Client.SetUserOnlineStatus(ctx, req); err != nil {
|
if err := ws.userClient.SetUserOnlineStatus(ctx, req); err != nil {
|
||||||
log.ZError(ctx, "update user online status", err)
|
log.ZError(ctx, "update user online status", err)
|
||||||
}
|
}
|
||||||
|
for _, ss := range req.Status {
|
||||||
|
for _, online := range ss.Online {
|
||||||
|
client, _, _ := ws.clients.Get(ss.UserID, int(online))
|
||||||
|
back := false
|
||||||
|
if len(client) > 0 {
|
||||||
|
back = client[0].IsBackground
|
||||||
|
}
|
||||||
|
ws.webhookAfterUserOnline(ctx, &ws.msgGatewayConfig.WebhooksConfig.AfterUserOnline, ss.UserID, int(online), back, ss.ConnID)
|
||||||
|
}
|
||||||
|
for _, offline := range ss.Offline {
|
||||||
|
ws.webhookAfterUserOffline(ctx, &ws.msgGatewayConfig.WebhooksConfig.AfterUserOffline, ss.UserID, int(offline), ss.ConnID)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := 0; i < concurrent; i++ {
|
for i := 0; i < concurrent; i++ {
|
||||||
|
@ -1,35 +1,25 @@
|
|||||||
// Copyright © 2023 OpenIM. All rights reserved.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package msggateway
|
package msggateway
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/common/webhook"
|
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/rpccache"
|
|
||||||
pbAuth "github.com/openimsdk/protocol/auth"
|
|
||||||
"github.com/openimsdk/tools/mcontext"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/openimsdk/open-im-server/v3/pkg/rpcli"
|
||||||
|
|
||||||
|
"github.com/openimsdk/open-im-server/v3/pkg/common/discovery/etcd"
|
||||||
|
"github.com/openimsdk/open-im-server/v3/pkg/common/webhook"
|
||||||
|
"github.com/openimsdk/open-im-server/v3/pkg/rpccache"
|
||||||
|
pbAuth "github.com/openimsdk/protocol/auth"
|
||||||
|
"github.com/openimsdk/tools/mcontext"
|
||||||
|
|
||||||
"github.com/go-playground/validator/v10"
|
"github.com/go-playground/validator/v10"
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics"
|
"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/servererrs"
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
|
|
||||||
"github.com/openimsdk/protocol/constant"
|
"github.com/openimsdk/protocol/constant"
|
||||||
"github.com/openimsdk/protocol/msggateway"
|
"github.com/openimsdk/protocol/msggateway"
|
||||||
"github.com/openimsdk/tools/discovery"
|
"github.com/openimsdk/tools/discovery"
|
||||||
@ -45,13 +35,12 @@ type LongConnServer interface {
|
|||||||
GetUserAllCons(userID string) ([]*Client, bool)
|
GetUserAllCons(userID string) ([]*Client, bool)
|
||||||
GetUserPlatformCons(userID string, platform int) ([]*Client, bool, bool)
|
GetUserPlatformCons(userID string, platform int) ([]*Client, bool, bool)
|
||||||
Validate(s any) error
|
Validate(s any) error
|
||||||
SetDiscoveryRegistry(client discovery.SvcDiscoveryRegistry, config *Config)
|
SetDiscoveryRegistry(ctx context.Context, client discovery.SvcDiscoveryRegistry, config *Config) error
|
||||||
KickUserConn(client *Client) error
|
KickUserConn(client *Client) error
|
||||||
UnRegister(c *Client)
|
UnRegister(c *Client)
|
||||||
SetKickHandlerInfo(i *kickHandler)
|
SetKickHandlerInfo(i *kickHandler)
|
||||||
SubUserOnlineStatus(ctx context.Context, client *Client, data *Req) ([]byte, error)
|
SubUserOnlineStatus(ctx context.Context, client *Client, data *Req) ([]byte, error)
|
||||||
Compressor
|
Compressor
|
||||||
Encoder
|
|
||||||
MessageHandler
|
MessageHandler
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,13 +60,13 @@ type WsServer struct {
|
|||||||
handshakeTimeout time.Duration
|
handshakeTimeout time.Duration
|
||||||
writeBufferSize int
|
writeBufferSize int
|
||||||
validate *validator.Validate
|
validate *validator.Validate
|
||||||
userClient *rpcclient.UserRpcClient
|
|
||||||
authClient *rpcclient.Auth
|
|
||||||
disCov discovery.SvcDiscoveryRegistry
|
disCov discovery.SvcDiscoveryRegistry
|
||||||
Compressor
|
Compressor
|
||||||
Encoder
|
//Encoder
|
||||||
MessageHandler
|
MessageHandler
|
||||||
webhookClient *webhook.Client
|
webhookClient *webhook.Client
|
||||||
|
userClient *rpcli.UserClient
|
||||||
|
authClient *rpcli.AuthClient
|
||||||
}
|
}
|
||||||
|
|
||||||
type kickHandler struct {
|
type kickHandler struct {
|
||||||
@ -86,12 +75,28 @@ type kickHandler struct {
|
|||||||
newClient *Client
|
newClient *Client
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ws *WsServer) SetDiscoveryRegistry(disCov discovery.SvcDiscoveryRegistry, config *Config) {
|
func (ws *WsServer) SetDiscoveryRegistry(ctx context.Context, disCov discovery.SvcDiscoveryRegistry, config *Config) error {
|
||||||
ws.MessageHandler = NewGrpcHandler(ws.validate, disCov, &config.Share.RpcRegisterName)
|
userConn, err := disCov.GetConn(ctx, config.Discovery.RpcService.User)
|
||||||
u := rpcclient.NewUserRpcClient(disCov, config.Share.RpcRegisterName.User, config.Share.IMAdminUserID)
|
if err != nil {
|
||||||
ws.authClient = rpcclient.NewAuth(disCov, config.Share.RpcRegisterName.Auth)
|
return err
|
||||||
ws.userClient = &u
|
}
|
||||||
|
pushConn, err := disCov.GetConn(ctx, config.Discovery.RpcService.Push)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
authConn, err := disCov.GetConn(ctx, config.Discovery.RpcService.Auth)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
msgConn, err := disCov.GetConn(ctx, config.Discovery.RpcService.Msg)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
ws.userClient = rpcli.NewUserClient(userConn)
|
||||||
|
ws.authClient = rpcli.NewAuthClient(authConn)
|
||||||
|
ws.MessageHandler = NewGrpcHandler(ws.validate, rpcli.NewMsgClient(msgConn), rpcli.NewPushMsgServiceClient(pushConn))
|
||||||
ws.disCov = disCov
|
ws.disCov = disCov
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
//func (ws *WsServer) SetUserOnlineStatus(ctx context.Context, client *Client, status int32) {
|
//func (ws *WsServer) SetUserOnlineStatus(ctx context.Context, client *Client, status int32) {
|
||||||
@ -128,7 +133,7 @@ func NewWsServer(msgGatewayConfig *Config, opts ...Option) *WsServer {
|
|||||||
for _, o := range opts {
|
for _, o := range opts {
|
||||||
o(&config)
|
o(&config)
|
||||||
}
|
}
|
||||||
//userRpcClient := rpcclient.NewUserRpcClient(client, config.Share.RpcRegisterName.User, config.Share.IMAdminUserID)
|
//userRpcClient := rpcclient.NewUserRpcClient(client, config.Discovery.RpcService.User, config.Share.IMAdminUserID)
|
||||||
|
|
||||||
v := validator.New()
|
v := validator.New()
|
||||||
return &WsServer{
|
return &WsServer{
|
||||||
@ -149,7 +154,6 @@ func NewWsServer(msgGatewayConfig *Config, opts ...Option) *WsServer {
|
|||||||
clients: newUserMap(),
|
clients: newUserMap(),
|
||||||
subscription: newSubscription(),
|
subscription: newSubscription(),
|
||||||
Compressor: NewGzipCompressor(),
|
Compressor: NewGzipCompressor(),
|
||||||
Encoder: NewGobEncoder(),
|
|
||||||
webhookClient: webhook.NewWebhookClient(msgGatewayConfig.WebhooksConfig.URL),
|
webhookClient: webhook.NewWebhookClient(msgGatewayConfig.WebhooksConfig.URL),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -181,21 +185,28 @@ func (ws *WsServer) Run(done chan error) error {
|
|||||||
go func() {
|
go func() {
|
||||||
http.HandleFunc("/", ws.wsHandler)
|
http.HandleFunc("/", ws.wsHandler)
|
||||||
err := server.ListenAndServe()
|
err := server.ListenAndServe()
|
||||||
defer close(netDone)
|
if err != nil && !errors.Is(err, http.ErrServerClosed) {
|
||||||
if err != nil && err != http.ErrServerClosed {
|
|
||||||
netErr = errs.WrapMsg(err, "ws start err", server.Addr)
|
netErr = errs.WrapMsg(err, "ws start err", server.Addr)
|
||||||
|
netDone <- struct{}{}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
|
||||||
defer cancel()
|
shutDown := func() error {
|
||||||
var err error
|
|
||||||
select {
|
|
||||||
case err = <-done:
|
|
||||||
sErr := server.Shutdown(ctx)
|
sErr := server.Shutdown(ctx)
|
||||||
if sErr != nil {
|
if sErr != nil {
|
||||||
return errs.WrapMsg(sErr, "shutdown err")
|
return errs.WrapMsg(sErr, "shutdown err")
|
||||||
}
|
}
|
||||||
close(shutdownDone)
|
close(shutdownDone)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
etcd.RegisterShutDown(shutDown)
|
||||||
|
defer cancel()
|
||||||
|
var err error
|
||||||
|
select {
|
||||||
|
case err = <-done:
|
||||||
|
if err := shutDown(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -208,11 +219,10 @@ func (ws *WsServer) Run(done chan error) error {
|
|||||||
var concurrentRequest = 3
|
var concurrentRequest = 3
|
||||||
|
|
||||||
func (ws *WsServer) sendUserOnlineInfoToOtherNode(ctx context.Context, client *Client) error {
|
func (ws *WsServer) sendUserOnlineInfoToOtherNode(ctx context.Context, client *Client) error {
|
||||||
conns, err := ws.disCov.GetConns(ctx, ws.msgGatewayConfig.Share.RpcRegisterName.MessageGateway)
|
conns, err := ws.disCov.GetConns(ctx, ws.msgGatewayConfig.Discovery.RpcService.MessageGateway)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
wg := errgroup.Group{}
|
wg := errgroup.Group{}
|
||||||
wg.SetLimit(concurrentRequest)
|
wg.SetLimit(concurrentRequest)
|
||||||
|
|
||||||
@ -293,14 +303,7 @@ func (ws *WsServer) registerClient(client *Client) {
|
|||||||
|
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
|
|
||||||
log.ZDebug(
|
log.ZDebug(client.ctx, "user online", "online user Num", ws.onlineUserNum.Load(), "online user conn Num", ws.onlineUserConnNum.Load())
|
||||||
client.ctx,
|
|
||||||
"user online",
|
|
||||||
"online user Num",
|
|
||||||
ws.onlineUserNum.Load(),
|
|
||||||
"online user conn Num",
|
|
||||||
ws.onlineUserConnNum.Load(),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func getRemoteAdders(client []*Client) string {
|
func getRemoteAdders(client []*Client) string {
|
||||||
@ -321,7 +324,26 @@ func (ws *WsServer) KickUserConn(client *Client) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (ws *WsServer) multiTerminalLoginChecker(clientOK bool, oldClients []*Client, newClient *Client) {
|
func (ws *WsServer) multiTerminalLoginChecker(clientOK bool, oldClients []*Client, newClient *Client) {
|
||||||
switch ws.msgGatewayConfig.Share.MultiLoginPolicy {
|
kickTokenFunc := func(kickClients []*Client) {
|
||||||
|
var kickTokens []string
|
||||||
|
ws.clients.DeleteClients(newClient.UserID, kickClients)
|
||||||
|
for _, c := range kickClients {
|
||||||
|
kickTokens = append(kickTokens, c.token)
|
||||||
|
err := c.KickOnlineMessage()
|
||||||
|
if err != nil {
|
||||||
|
log.ZWarn(c.ctx, "KickOnlineMessage", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ctx := mcontext.WithMustInfoCtx(
|
||||||
|
[]string{newClient.ctx.GetOperationID(), newClient.ctx.GetUserID(),
|
||||||
|
constant.PlatformIDToName(newClient.PlatformID), newClient.ctx.GetConnID()},
|
||||||
|
)
|
||||||
|
if err := ws.authClient.KickTokens(ctx, kickTokens); err != nil {
|
||||||
|
log.ZWarn(newClient.ctx, "kickTokens err", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ws.msgGatewayConfig.Share.MultiLogin.Policy {
|
||||||
case constant.DefalutNotKick:
|
case constant.DefalutNotKick:
|
||||||
case constant.PCAndOther:
|
case constant.PCAndOther:
|
||||||
if constant.PlatformIDToClass(newClient.PlatformID) == constant.TerminalPC {
|
if constant.PlatformIDToClass(newClient.PlatformID) == constant.TerminalPC {
|
||||||
@ -343,10 +365,29 @@ func (ws *WsServer) multiTerminalLoginChecker(clientOK bool, oldClients []*Clien
|
|||||||
[]string{newClient.ctx.GetOperationID(), newClient.ctx.GetUserID(),
|
[]string{newClient.ctx.GetOperationID(), newClient.ctx.GetUserID(),
|
||||||
constant.PlatformIDToName(newClient.PlatformID), newClient.ctx.GetConnID()},
|
constant.PlatformIDToName(newClient.PlatformID), newClient.ctx.GetConnID()},
|
||||||
)
|
)
|
||||||
if _, err := ws.authClient.InvalidateToken(ctx, newClient.token, newClient.UserID, newClient.PlatformID); err != nil {
|
req := &pbAuth.InvalidateTokenReq{
|
||||||
|
PreservedToken: newClient.token,
|
||||||
|
UserID: newClient.UserID,
|
||||||
|
PlatformID: int32(newClient.PlatformID),
|
||||||
|
}
|
||||||
|
if err := ws.authClient.InvalidateToken(ctx, req); err != nil {
|
||||||
log.ZWarn(newClient.ctx, "InvalidateToken err", err, "userID", newClient.UserID,
|
log.ZWarn(newClient.ctx, "InvalidateToken err", err, "userID", newClient.UserID,
|
||||||
"platformID", newClient.PlatformID)
|
"platformID", newClient.PlatformID)
|
||||||
}
|
}
|
||||||
|
case constant.AllLoginButSameClassKick:
|
||||||
|
clients, ok := ws.clients.GetAll(newClient.UserID)
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var (
|
||||||
|
kickClients []*Client
|
||||||
|
)
|
||||||
|
for _, client := range clients {
|
||||||
|
if constant.PlatformIDToClass(client.PlatformID) == constant.PlatformIDToClass(newClient.PlatformID) {
|
||||||
|
kickClients = append(kickClients, client)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
kickTokenFunc(kickClients)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,22 +18,30 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
|
"strconv"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
|
disetcd "github.com/openimsdk/open-im-server/v3/pkg/common/discovery/etcd"
|
||||||
|
"github.com/openimsdk/tools/discovery"
|
||||||
|
"github.com/openimsdk/tools/discovery/etcd"
|
||||||
|
"github.com/openimsdk/tools/utils/jsonutil"
|
||||||
|
"github.com/openimsdk/tools/utils/network"
|
||||||
|
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics"
|
"github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics"
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/common/storage/cache/redis"
|
"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/database/mgo"
|
||||||
"github.com/openimsdk/tools/db/mongoutil"
|
"github.com/openimsdk/tools/db/mongoutil"
|
||||||
"github.com/openimsdk/tools/db/redisutil"
|
"github.com/openimsdk/tools/db/redisutil"
|
||||||
"github.com/openimsdk/tools/utils/datautil"
|
"github.com/openimsdk/tools/utils/datautil"
|
||||||
|
"github.com/openimsdk/tools/utils/runtimeenv"
|
||||||
|
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
conf "github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
||||||
discRegister "github.com/openimsdk/open-im-server/v3/pkg/common/discoveryregister"
|
discRegister "github.com/openimsdk/open-im-server/v3/pkg/common/discovery"
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/common/storage/controller"
|
"github.com/openimsdk/open-im-server/v3/pkg/common/storage/controller"
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
|
|
||||||
"github.com/openimsdk/tools/errs"
|
"github.com/openimsdk/tools/errs"
|
||||||
"github.com/openimsdk/tools/log"
|
"github.com/openimsdk/tools/log"
|
||||||
"github.com/openimsdk/tools/mw"
|
"github.com/openimsdk/tools/mw"
|
||||||
@ -51,20 +59,24 @@ type MsgTransfer struct {
|
|||||||
historyMongoCH *OnlineHistoryMongoConsumerHandler
|
historyMongoCH *OnlineHistoryMongoConsumerHandler
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
cancel context.CancelFunc
|
cancel context.CancelFunc
|
||||||
|
|
||||||
|
runTimeEnv string
|
||||||
}
|
}
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
MsgTransfer config.MsgTransfer
|
MsgTransfer conf.MsgTransfer
|
||||||
RedisConfig config.Redis
|
RedisConfig conf.Redis
|
||||||
MongodbConfig config.Mongo
|
MongodbConfig conf.Mongo
|
||||||
KafkaConfig config.Kafka
|
KafkaConfig conf.Kafka
|
||||||
Share config.Share
|
Share conf.Share
|
||||||
WebhooksConfig config.Webhooks
|
WebhooksConfig conf.Webhooks
|
||||||
Discovery config.Discovery
|
Discovery conf.Discovery
|
||||||
}
|
}
|
||||||
|
|
||||||
func Start(ctx context.Context, index int, config *Config) error {
|
func Start(ctx context.Context, index int, config *Config) error {
|
||||||
log.CInfo(ctx, "MSG-TRANSFER server is initializing", "prometheusPorts",
|
runTimeEnv := runtimeenv.PrintRuntimeEnvironment()
|
||||||
|
|
||||||
|
log.CInfo(ctx, "MSG-TRANSFER server is initializing", "runTimeEnv", runTimeEnv, "prometheusPorts",
|
||||||
config.MsgTransfer.Prometheus.Ports, "index", index)
|
config.MsgTransfer.Prometheus.Ports, "index", index)
|
||||||
|
|
||||||
mgocli, err := mongoutil.NewMongoDB(ctx, config.MongodbConfig.Build())
|
mgocli, err := mongoutil.NewMongoDB(ctx, config.MongodbConfig.Build())
|
||||||
@ -75,18 +87,32 @@ func Start(ctx context.Context, index int, config *Config) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
client, err := discRegister.NewDiscoveryRegister(&config.Discovery, &config.Share)
|
client, err := discRegister.NewDiscoveryRegister(&config.Discovery, runTimeEnv, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
client.AddOption(mw.GrpcClient(), grpc.WithTransportCredentials(insecure.NewCredentials()),
|
client.AddOption(mw.GrpcClient(), grpc.WithTransportCredentials(insecure.NewCredentials()),
|
||||||
grpc.WithDefaultServiceConfig(fmt.Sprintf(`{"LoadBalancingPolicy": "%s"}`, "round_robin")))
|
grpc.WithDefaultServiceConfig(fmt.Sprintf(`{"LoadBalancingPolicy": "%s"}`, "round_robin")))
|
||||||
|
|
||||||
msgModel := redis.NewMsgCache(rdb)
|
if config.Discovery.Enable == conf.ETCD {
|
||||||
|
cm := disetcd.NewConfigManager(client.(*etcd.SvcDiscoveryRegistryImpl).GetClient(), []string{
|
||||||
|
config.MsgTransfer.GetConfigFileName(),
|
||||||
|
config.RedisConfig.GetConfigFileName(),
|
||||||
|
config.MongodbConfig.GetConfigFileName(),
|
||||||
|
config.KafkaConfig.GetConfigFileName(),
|
||||||
|
config.Share.GetConfigFileName(),
|
||||||
|
config.WebhooksConfig.GetConfigFileName(),
|
||||||
|
config.Discovery.GetConfigFileName(),
|
||||||
|
conf.LogConfigFileName,
|
||||||
|
})
|
||||||
|
cm.Watch(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
msgDocModel, err := mgo.NewMsgMongo(mgocli.GetDB())
|
msgDocModel, err := mgo.NewMsgMongo(mgocli.GetDB())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
msgModel := redis.NewMsgCache(rdb, msgDocModel)
|
||||||
seqConversation, err := mgo.NewSeqConversationMongo(mgocli.GetDB())
|
seqConversation, err := mgo.NewSeqConversationMongo(mgocli.GetDB())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -101,9 +127,7 @@ func Start(ctx context.Context, index int, config *Config) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
conversationRpcClient := rpcclient.NewConversationRpcClient(client, config.Share.RpcRegisterName.Conversation)
|
historyCH, err := NewOnlineHistoryRedisConsumerHandler(ctx, client, config, msgTransferDatabase)
|
||||||
groupRpcClient := rpcclient.NewGroupRpcClient(client, config.Share.RpcRegisterName.Group)
|
|
||||||
historyCH, err := NewOnlineHistoryRedisConsumerHandler(&config.KafkaConfig, msgTransferDatabase, &conversationRpcClient, &groupRpcClient)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -115,11 +139,13 @@ func Start(ctx context.Context, index int, config *Config) error {
|
|||||||
msgTransfer := &MsgTransfer{
|
msgTransfer := &MsgTransfer{
|
||||||
historyCH: historyCH,
|
historyCH: historyCH,
|
||||||
historyMongoCH: historyMongoCH,
|
historyMongoCH: historyMongoCH,
|
||||||
|
runTimeEnv: runTimeEnv,
|
||||||
}
|
}
|
||||||
return msgTransfer.Start(index, config)
|
|
||||||
|
return msgTransfer.Start(index, config, client)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MsgTransfer) Start(index int, config *Config) error {
|
func (m *MsgTransfer) Start(index int, config *Config, client discovery.SvcDiscoveryRegistry) error {
|
||||||
m.ctx, m.cancel = context.WithCancel(context.Background())
|
m.ctx, m.cancel = context.WithCancel(context.Background())
|
||||||
var (
|
var (
|
||||||
netDone = make(chan struct{}, 1)
|
netDone = make(chan struct{}, 1)
|
||||||
@ -128,21 +154,68 @@ func (m *MsgTransfer) Start(index int, config *Config) error {
|
|||||||
|
|
||||||
go m.historyCH.historyConsumerGroup.RegisterHandleAndConsumer(m.ctx, m.historyCH)
|
go m.historyCH.historyConsumerGroup.RegisterHandleAndConsumer(m.ctx, m.historyCH)
|
||||||
go m.historyMongoCH.historyConsumerGroup.RegisterHandleAndConsumer(m.ctx, m.historyMongoCH)
|
go m.historyMongoCH.historyConsumerGroup.RegisterHandleAndConsumer(m.ctx, m.historyMongoCH)
|
||||||
|
go m.historyCH.HandleUserHasReadSeqMessages(m.ctx)
|
||||||
err := m.historyCH.redisMessageBatches.Start()
|
err := m.historyCH.redisMessageBatches.Start()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
registerIP, err := network.GetRpcRegisterIP("")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
getAutoPort := func() (net.Listener, int, error) {
|
||||||
|
registerAddr := net.JoinHostPort(registerIP, "0")
|
||||||
|
listener, err := net.Listen("tcp", registerAddr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, errs.WrapMsg(err, "listen err", "registerAddr", registerAddr)
|
||||||
|
}
|
||||||
|
_, portStr, _ := net.SplitHostPort(listener.Addr().String())
|
||||||
|
port, _ := strconv.Atoi(portStr)
|
||||||
|
return listener, port, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if config.MsgTransfer.Prometheus.AutoSetPorts && config.Discovery.Enable != conf.ETCD {
|
||||||
|
return errs.New("only etcd support autoSetPorts", "RegisterName", "api").Wrap()
|
||||||
|
}
|
||||||
|
|
||||||
if config.MsgTransfer.Prometheus.Enable {
|
if config.MsgTransfer.Prometheus.Enable {
|
||||||
go func() {
|
var (
|
||||||
prometheusPort, err := datautil.GetElemByIndex(config.MsgTransfer.Prometheus.Ports, index)
|
listener net.Listener
|
||||||
|
prometheusPort int
|
||||||
|
)
|
||||||
|
|
||||||
|
if config.MsgTransfer.Prometheus.AutoSetPorts {
|
||||||
|
listener, prometheusPort, err = getAutoPort()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
netErr = err
|
return err
|
||||||
netDone <- struct{}{}
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := prommetrics.TransferInit(prometheusPort); err != nil && !errors.Is(err, http.ErrServerClosed) {
|
etcdClient := client.(*etcd.SvcDiscoveryRegistryImpl).GetClient()
|
||||||
|
|
||||||
|
_, err = etcdClient.Put(context.TODO(), prommetrics.BuildDiscoveryKey(prommetrics.MessageTransferKeyName), jsonutil.StructToJsonString(prommetrics.BuildDefaultTarget(registerIP, prometheusPort)))
|
||||||
|
if err != nil {
|
||||||
|
return errs.WrapMsg(err, "etcd put err")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
prometheusPort, err = datautil.GetElemByIndex(config.MsgTransfer.Prometheus.Ports, index)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
listener, err = net.Listen("tcp", fmt.Sprintf(":%d", prometheusPort))
|
||||||
|
if err != nil {
|
||||||
|
return errs.WrapMsg(err, "listen err", "addr", fmt.Sprintf(":%d", prometheusPort))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
log.ZPanic(m.ctx, "MsgTransfer Start Panic", errs.ErrPanic(r))
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
if err := prommetrics.TransferInit(listener); err != nil && !errors.Is(err, http.ErrServerClosed) {
|
||||||
netErr = errs.WrapMsg(err, "prometheus start error", "prometheusPort", prometheusPort)
|
netErr = errs.WrapMsg(err, "prometheus start error", "prometheusPort", prometheusPort)
|
||||||
netDone <- struct{}{}
|
netDone <- struct{}{}
|
||||||
}
|
}
|
||||||
@ -157,12 +230,14 @@ func (m *MsgTransfer) Start(index int, config *Config) error {
|
|||||||
// graceful close kafka client.
|
// graceful close kafka client.
|
||||||
m.cancel()
|
m.cancel()
|
||||||
m.historyCH.redisMessageBatches.Close()
|
m.historyCH.redisMessageBatches.Close()
|
||||||
|
m.historyCH.Close()
|
||||||
m.historyCH.historyConsumerGroup.Close()
|
m.historyCH.historyConsumerGroup.Close()
|
||||||
m.historyMongoCH.historyConsumerGroup.Close()
|
m.historyMongoCH.historyConsumerGroup.Close()
|
||||||
return nil
|
return nil
|
||||||
case <-netDone:
|
case <-netDone:
|
||||||
m.cancel()
|
m.cancel()
|
||||||
m.historyCH.redisMessageBatches.Close()
|
m.historyCH.redisMessageBatches.Close()
|
||||||
|
m.historyCH.Close()
|
||||||
m.historyCH.historyConsumerGroup.Close()
|
m.historyCH.historyConsumerGroup.Close()
|
||||||
m.historyMongoCH.historyConsumerGroup.Close()
|
m.historyMongoCH.historyConsumerGroup.Close()
|
||||||
close(netDone)
|
close(netDone)
|
||||||
|
@ -18,18 +18,21 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
|
"github.com/openimsdk/open-im-server/v3/pkg/rpcli"
|
||||||
|
"github.com/openimsdk/tools/discovery"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/IBM/sarama"
|
"github.com/IBM/sarama"
|
||||||
"github.com/go-redis/redis"
|
"github.com/go-redis/redis"
|
||||||
"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/storage/controller"
|
"github.com/openimsdk/open-im-server/v3/pkg/common/storage/controller"
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/msgprocessor"
|
"github.com/openimsdk/open-im-server/v3/pkg/msgprocessor"
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
|
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/tools/batcher"
|
"github.com/openimsdk/open-im-server/v3/pkg/tools/batcher"
|
||||||
"github.com/openimsdk/protocol/constant"
|
"github.com/openimsdk/protocol/constant"
|
||||||
|
pbconv "github.com/openimsdk/protocol/conversation"
|
||||||
"github.com/openimsdk/protocol/sdkws"
|
"github.com/openimsdk/protocol/sdkws"
|
||||||
"github.com/openimsdk/tools/errs"
|
"github.com/openimsdk/tools/errs"
|
||||||
"github.com/openimsdk/tools/log"
|
"github.com/openimsdk/tools/log"
|
||||||
@ -40,11 +43,12 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
size = 500
|
size = 500
|
||||||
mainDataBuffer = 500
|
mainDataBuffer = 500
|
||||||
subChanBuffer = 50
|
subChanBuffer = 50
|
||||||
worker = 50
|
worker = 50
|
||||||
interval = 100 * time.Millisecond
|
interval = 100 * time.Millisecond
|
||||||
|
hasReadChanBuffer = 1000
|
||||||
)
|
)
|
||||||
|
|
||||||
type ContextMsg struct {
|
type ContextMsg struct {
|
||||||
@ -52,24 +56,46 @@ type ContextMsg struct {
|
|||||||
ctx context.Context
|
ctx context.Context
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This structure is used for asynchronously writing the sender’s read sequence (seq) regarding a message into MongoDB.
|
||||||
|
// For example, if the sender sends a message with a seq of 10, then their own read seq for this conversation should be set to 10.
|
||||||
|
type userHasReadSeq struct {
|
||||||
|
conversationID string
|
||||||
|
userHasReadMap map[string]int64
|
||||||
|
}
|
||||||
|
|
||||||
type OnlineHistoryRedisConsumerHandler struct {
|
type OnlineHistoryRedisConsumerHandler struct {
|
||||||
historyConsumerGroup *kafka.MConsumerGroup
|
historyConsumerGroup *kafka.MConsumerGroup
|
||||||
|
|
||||||
redisMessageBatches *batcher.Batcher[sarama.ConsumerMessage]
|
redisMessageBatches *batcher.Batcher[sarama.ConsumerMessage]
|
||||||
|
|
||||||
msgTransferDatabase controller.MsgTransferDatabase
|
msgTransferDatabase controller.MsgTransferDatabase
|
||||||
conversationRpcClient *rpcclient.ConversationRpcClient
|
conversationUserHasReadChan chan *userHasReadSeq
|
||||||
groupRpcClient *rpcclient.GroupRpcClient
|
wg sync.WaitGroup
|
||||||
|
|
||||||
|
groupClient *rpcli.GroupClient
|
||||||
|
conversationClient *rpcli.ConversationClient
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewOnlineHistoryRedisConsumerHandler(kafkaConf *config.Kafka, database controller.MsgTransferDatabase,
|
func NewOnlineHistoryRedisConsumerHandler(ctx context.Context, client discovery.SvcDiscoveryRegistry, config *Config, database controller.MsgTransferDatabase) (*OnlineHistoryRedisConsumerHandler, error) {
|
||||||
conversationRpcClient *rpcclient.ConversationRpcClient, groupRpcClient *rpcclient.GroupRpcClient) (*OnlineHistoryRedisConsumerHandler, error) {
|
kafkaConf := config.KafkaConfig
|
||||||
historyConsumerGroup, err := kafka.NewMConsumerGroup(kafkaConf.Build(), kafkaConf.ToRedisGroupID, []string{kafkaConf.ToRedisTopic}, false)
|
historyConsumerGroup, err := kafka.NewMConsumerGroup(kafkaConf.Build(), kafkaConf.ToRedisGroupID, []string{kafkaConf.ToRedisTopic}, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
groupConn, err := client.GetConn(ctx, config.Discovery.RpcService.Group)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
conversationConn, err := client.GetConn(ctx, config.Discovery.RpcService.Conversation)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
var och OnlineHistoryRedisConsumerHandler
|
var och OnlineHistoryRedisConsumerHandler
|
||||||
och.msgTransferDatabase = database
|
och.msgTransferDatabase = database
|
||||||
|
och.conversationUserHasReadChan = make(chan *userHasReadSeq, hasReadChanBuffer)
|
||||||
|
och.groupClient = rpcli.NewGroupClient(groupConn)
|
||||||
|
och.conversationClient = rpcli.NewConversationClient(conversationConn)
|
||||||
|
och.wg.Add(1)
|
||||||
|
|
||||||
b := batcher.New[sarama.ConsumerMessage](
|
b := batcher.New[sarama.ConsumerMessage](
|
||||||
batcher.WithSize(size),
|
batcher.WithSize(size),
|
||||||
@ -88,25 +114,21 @@ func NewOnlineHistoryRedisConsumerHandler(kafkaConf *config.Kafka, database cont
|
|||||||
}
|
}
|
||||||
b.Do = och.do
|
b.Do = och.do
|
||||||
och.redisMessageBatches = b
|
och.redisMessageBatches = b
|
||||||
och.conversationRpcClient = conversationRpcClient
|
|
||||||
och.groupRpcClient = groupRpcClient
|
|
||||||
och.historyConsumerGroup = historyConsumerGroup
|
och.historyConsumerGroup = historyConsumerGroup
|
||||||
|
|
||||||
return &och, err
|
return &och, nil
|
||||||
}
|
}
|
||||||
func (och *OnlineHistoryRedisConsumerHandler) do(ctx context.Context, channelID int, val *batcher.Msg[sarama.ConsumerMessage]) {
|
func (och *OnlineHistoryRedisConsumerHandler) do(ctx context.Context, channelID int, val *batcher.Msg[sarama.ConsumerMessage]) {
|
||||||
ctx = mcontext.WithTriggerIDContext(ctx, val.TriggerID())
|
ctx = mcontext.WithTriggerIDContext(ctx, val.TriggerID())
|
||||||
ctxMessages := och.parseConsumerMessages(ctx, val.Val())
|
ctxMessages := och.parseConsumerMessages(ctx, val.Val())
|
||||||
ctx = withAggregationCtx(ctx, ctxMessages)
|
ctx = withAggregationCtx(ctx, ctxMessages)
|
||||||
log.ZInfo(ctx, "msg arrived channel", "channel id", channelID, "msgList length", len(ctxMessages),
|
log.ZInfo(ctx, "msg arrived channel", "channel id", channelID, "msgList length", len(ctxMessages), "key", val.Key())
|
||||||
"key", val.Key())
|
|
||||||
och.doSetReadSeq(ctx, ctxMessages)
|
och.doSetReadSeq(ctx, ctxMessages)
|
||||||
|
|
||||||
storageMsgList, notStorageMsgList, storageNotificationList, notStorageNotificationList :=
|
storageMsgList, notStorageMsgList, storageNotificationList, notStorageNotificationList :=
|
||||||
och.categorizeMessageLists(ctxMessages)
|
och.categorizeMessageLists(ctxMessages)
|
||||||
log.ZDebug(ctx, "number of categorized messages", "storageMsgList", len(storageMsgList), "notStorageMsgList",
|
log.ZDebug(ctx, "number of categorized messages", "storageMsgList", len(storageMsgList), "notStorageMsgList",
|
||||||
len(notStorageMsgList), "storageNotificationList", len(storageNotificationList), "notStorageNotificationList",
|
len(notStorageMsgList), "storageNotificationList", len(storageNotificationList), "notStorageNotificationList", len(notStorageNotificationList))
|
||||||
len(notStorageNotificationList))
|
|
||||||
|
|
||||||
conversationIDMsg := msgprocessor.GetChatConversationIDByMsg(ctxMessages[0].message)
|
conversationIDMsg := msgprocessor.GetChatConversationIDByMsg(ctxMessages[0].message)
|
||||||
conversationIDNotification := msgprocessor.GetNotificationConversationIDByMsg(ctxMessages[0].message)
|
conversationIDNotification := msgprocessor.GetNotificationConversationIDByMsg(ctxMessages[0].message)
|
||||||
@ -115,25 +137,25 @@ func (och *OnlineHistoryRedisConsumerHandler) do(ctx context.Context, channelID
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (och *OnlineHistoryRedisConsumerHandler) doSetReadSeq(ctx context.Context, msgs []*ContextMsg) {
|
func (och *OnlineHistoryRedisConsumerHandler) doSetReadSeq(ctx context.Context, msgs []*ContextMsg) {
|
||||||
type seqKey struct {
|
|
||||||
conversationID string
|
var conversationID string
|
||||||
userID string
|
var userSeqMap map[string]int64
|
||||||
}
|
|
||||||
var readSeq map[seqKey]int64
|
|
||||||
for _, msg := range msgs {
|
for _, msg := range msgs {
|
||||||
if msg.message.ContentType != constant.HasReadReceipt {
|
if msg.message.ContentType != constant.HasReadReceipt {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
var elem sdkws.NotificationElem
|
var elem sdkws.NotificationElem
|
||||||
if err := json.Unmarshal(msg.message.Content, &elem); err != nil {
|
if err := json.Unmarshal(msg.message.Content, &elem); err != nil {
|
||||||
log.ZError(ctx, "handlerConversationRead Unmarshal NotificationElem msg err", err, "msg", msg)
|
log.ZWarn(ctx, "handlerConversationRead Unmarshal NotificationElem msg err", err, "msg", msg)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
var tips sdkws.MarkAsReadTips
|
var tips sdkws.MarkAsReadTips
|
||||||
if err := json.Unmarshal([]byte(elem.Detail), &tips); err != nil {
|
if err := json.Unmarshal([]byte(elem.Detail), &tips); err != nil {
|
||||||
log.ZError(ctx, "handlerConversationRead Unmarshal MarkAsReadTips msg err", err, "msg", msg)
|
log.ZWarn(ctx, "handlerConversationRead Unmarshal MarkAsReadTips msg err", err, "msg", msg)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
//The conversation ID for each batch of messages processed by the batcher is the same.
|
||||||
|
conversationID = tips.ConversationID
|
||||||
if len(tips.Seqs) > 0 {
|
if len(tips.Seqs) > 0 {
|
||||||
for _, seq := range tips.Seqs {
|
for _, seq := range tips.Seqs {
|
||||||
if tips.HasReadSeq < seq {
|
if tips.HasReadSeq < seq {
|
||||||
@ -146,26 +168,25 @@ func (och *OnlineHistoryRedisConsumerHandler) doSetReadSeq(ctx context.Context,
|
|||||||
if tips.HasReadSeq < 0 {
|
if tips.HasReadSeq < 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if readSeq == nil {
|
if userSeqMap == nil {
|
||||||
readSeq = make(map[seqKey]int64)
|
userSeqMap = make(map[string]int64)
|
||||||
}
|
}
|
||||||
key := seqKey{
|
|
||||||
conversationID: tips.ConversationID,
|
if userSeqMap[tips.MarkAsReadUserID] > tips.HasReadSeq {
|
||||||
userID: tips.MarkAsReadUserID,
|
|
||||||
}
|
|
||||||
if readSeq[key] > tips.HasReadSeq {
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
readSeq[key] = tips.HasReadSeq
|
userSeqMap[tips.MarkAsReadUserID] = tips.HasReadSeq
|
||||||
}
|
}
|
||||||
if readSeq == nil {
|
if userSeqMap == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
for key, seq := range readSeq {
|
if len(conversationID) == 0 {
|
||||||
if err := och.msgTransferDatabase.SetHasReadSeqToDB(ctx, key.userID, key.conversationID, seq); err != nil {
|
log.ZWarn(ctx, "conversation err", nil, "conversationID", conversationID)
|
||||||
log.ZError(ctx, "set read seq to db error", err, "userID", key.userID, "conversationID", key.conversationID, "seq", seq)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
if err := och.msgTransferDatabase.SetHasReadSeqToDB(ctx, conversationID, userSeqMap); err != nil {
|
||||||
|
log.ZWarn(ctx, "set read seq to db error", err, "conversationID", conversationID, "userSeqMap", userSeqMap)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (och *OnlineHistoryRedisConsumerHandler) parseConsumerMessages(ctx context.Context, consumerMessages []*sarama.ConsumerMessage) []*ContextMsg {
|
func (och *OnlineHistoryRedisConsumerHandler) parseConsumerMessages(ctx context.Context, consumerMessages []*sarama.ConsumerMessage) []*ContextMsg {
|
||||||
@ -250,34 +271,48 @@ func (och *OnlineHistoryRedisConsumerHandler) handleMsg(ctx context.Context, key
|
|||||||
}
|
}
|
||||||
if len(storageMessageList) > 0 {
|
if len(storageMessageList) > 0 {
|
||||||
msg := storageMessageList[0]
|
msg := storageMessageList[0]
|
||||||
lastSeq, isNewConversation, err := och.msgTransferDatabase.BatchInsertChat2Cache(ctx, conversationID, storageMessageList)
|
lastSeq, isNewConversation, userSeqMap, err := och.msgTransferDatabase.BatchInsertChat2Cache(ctx, conversationID, storageMessageList)
|
||||||
if err != nil && !errors.Is(errs.Unwrap(err), redis.Nil) {
|
if err != nil && !errors.Is(errs.Unwrap(err), redis.Nil) {
|
||||||
log.ZError(ctx, "batch data insert to redis err", err, "storageMsgList", storageMessageList)
|
log.ZWarn(ctx, "batch data insert to redis err", err, "storageMsgList", storageMessageList)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
log.ZInfo(ctx, "BatchInsertChat2Cache end")
|
log.ZInfo(ctx, "BatchInsertChat2Cache end")
|
||||||
|
err = och.msgTransferDatabase.SetHasReadSeqs(ctx, conversationID, userSeqMap)
|
||||||
|
if err != nil {
|
||||||
|
log.ZWarn(ctx, "SetHasReadSeqs error", err, "userSeqMap", userSeqMap, "conversationID", conversationID)
|
||||||
|
prommetrics.SeqSetFailedCounter.Inc()
|
||||||
|
}
|
||||||
|
och.conversationUserHasReadChan <- &userHasReadSeq{
|
||||||
|
conversationID: conversationID,
|
||||||
|
userHasReadMap: userSeqMap,
|
||||||
|
}
|
||||||
|
|
||||||
if isNewConversation {
|
if isNewConversation {
|
||||||
switch msg.SessionType {
|
switch msg.SessionType {
|
||||||
case constant.ReadGroupChatType:
|
case constant.ReadGroupChatType:
|
||||||
log.ZDebug(ctx, "group chat first create conversation", "conversationID",
|
log.ZDebug(ctx, "group chat first create conversation", "conversationID",
|
||||||
conversationID)
|
conversationID)
|
||||||
userIDs, err := och.groupRpcClient.GetGroupMemberIDs(ctx, msg.GroupID)
|
|
||||||
|
userIDs, err := och.groupClient.GetGroupMemberUserIDs(ctx, msg.GroupID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.ZWarn(ctx, "get group member ids error", err, "conversationID",
|
log.ZWarn(ctx, "get group member ids error", err, "conversationID",
|
||||||
conversationID)
|
conversationID)
|
||||||
} else {
|
} else {
|
||||||
log.ZInfo(ctx, "GetGroupMemberIDs end")
|
log.ZInfo(ctx, "GetGroupMemberIDs end")
|
||||||
|
|
||||||
if err := och.conversationRpcClient.GroupChatFirstCreateConversation(ctx,
|
if err := och.conversationClient.CreateGroupChatConversations(ctx, msg.GroupID, userIDs); err != nil {
|
||||||
msg.GroupID, userIDs); err != nil {
|
|
||||||
log.ZWarn(ctx, "single chat first create conversation error", err,
|
log.ZWarn(ctx, "single chat first create conversation error", err,
|
||||||
"conversationID", conversationID)
|
"conversationID", conversationID)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case constant.SingleChatType, constant.NotificationChatType:
|
case constant.SingleChatType, constant.NotificationChatType:
|
||||||
if err := och.conversationRpcClient.SingleChatFirstCreateConversation(ctx, msg.RecvID,
|
req := &pbconv.CreateSingleChatConversationsReq{
|
||||||
msg.SendID, conversationID, msg.SessionType); err != nil {
|
RecvID: msg.RecvID,
|
||||||
|
SendID: msg.SendID,
|
||||||
|
ConversationID: conversationID,
|
||||||
|
ConversationType: msg.SessionType,
|
||||||
|
}
|
||||||
|
if err := och.conversationClient.CreateSingleChatConversations(ctx, req); err != nil {
|
||||||
log.ZWarn(ctx, "single chat or notification first create conversation error", err,
|
log.ZWarn(ctx, "single chat or notification first create conversation error", err,
|
||||||
"conversationID", conversationID, "sessionType", msg.SessionType)
|
"conversationID", conversationID, "sessionType", msg.SessionType)
|
||||||
}
|
}
|
||||||
@ -308,7 +343,7 @@ func (och *OnlineHistoryRedisConsumerHandler) handleNotification(ctx context.Con
|
|||||||
storageMessageList = append(storageMessageList, msg.message)
|
storageMessageList = append(storageMessageList, msg.message)
|
||||||
}
|
}
|
||||||
if len(storageMessageList) > 0 {
|
if len(storageMessageList) > 0 {
|
||||||
lastSeq, _, err := och.msgTransferDatabase.BatchInsertChat2Cache(ctx, conversationID, storageMessageList)
|
lastSeq, _, _, err := och.msgTransferDatabase.BatchInsertChat2Cache(ctx, conversationID, storageMessageList)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.ZError(ctx, "notification batch insert to redis error", err, "conversationID", conversationID,
|
log.ZError(ctx, "notification batch insert to redis error", err, "conversationID", conversationID,
|
||||||
"storageList", storageMessageList)
|
"storageList", storageMessageList)
|
||||||
@ -323,6 +358,27 @@ func (och *OnlineHistoryRedisConsumerHandler) handleNotification(ctx context.Con
|
|||||||
och.toPushTopic(ctx, key, conversationID, storageList)
|
och.toPushTopic(ctx, key, conversationID, storageList)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
func (och *OnlineHistoryRedisConsumerHandler) HandleUserHasReadSeqMessages(ctx context.Context) {
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
log.ZPanic(ctx, "HandleUserHasReadSeqMessages Panic", errs.ErrPanic(r))
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
defer och.wg.Done()
|
||||||
|
|
||||||
|
for msg := range och.conversationUserHasReadChan {
|
||||||
|
if err := och.msgTransferDatabase.SetHasReadSeqToDB(ctx, msg.conversationID, msg.userHasReadMap); err != nil {
|
||||||
|
log.ZWarn(ctx, "set read seq to db error", err, "conversationID", msg.conversationID, "userSeqMap", msg.userHasReadMap)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log.ZInfo(ctx, "Channel closed, exiting handleUserHasReadSeqMessages")
|
||||||
|
}
|
||||||
|
func (och *OnlineHistoryRedisConsumerHandler) Close() {
|
||||||
|
close(och.conversationUserHasReadChan)
|
||||||
|
och.wg.Wait()
|
||||||
|
}
|
||||||
|
|
||||||
func (och *OnlineHistoryRedisConsumerHandler) toPushTopic(ctx context.Context, key, conversationID string, msgs []*ContextMsg) {
|
func (och *OnlineHistoryRedisConsumerHandler) toPushTopic(ctx context.Context, key, conversationID string, msgs []*ContextMsg) {
|
||||||
for _, v := range msgs {
|
for _, v := range msgs {
|
||||||
|
@ -77,27 +77,13 @@ func (mc *OnlineHistoryMongoConsumerHandler) handleChatWs2Mongo(ctx context.Cont
|
|||||||
for _, msg := range msgFromMQ.MsgData {
|
for _, msg := range msgFromMQ.MsgData {
|
||||||
seqs = append(seqs, msg.Seq)
|
seqs = append(seqs, msg.Seq)
|
||||||
}
|
}
|
||||||
err = mc.msgTransferDatabase.DeleteMessagesFromCache(ctx, msgFromMQ.ConversationID, seqs)
|
|
||||||
if err != nil {
|
|
||||||
log.ZError(
|
|
||||||
ctx,
|
|
||||||
"remove cache msg from redis err",
|
|
||||||
err,
|
|
||||||
"msg",
|
|
||||||
msgFromMQ.MsgData,
|
|
||||||
"conversationID",
|
|
||||||
msgFromMQ.ConversationID,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (*OnlineHistoryMongoConsumerHandler) Setup(_ sarama.ConsumerGroupSession) error { return nil }
|
func (*OnlineHistoryMongoConsumerHandler) Setup(_ sarama.ConsumerGroupSession) error { return nil }
|
||||||
|
|
||||||
func (*OnlineHistoryMongoConsumerHandler) Cleanup(_ sarama.ConsumerGroupSession) error { return nil }
|
func (*OnlineHistoryMongoConsumerHandler) Cleanup(_ sarama.ConsumerGroupSession) error { return nil }
|
||||||
|
|
||||||
func (mc *OnlineHistoryMongoConsumerHandler) ConsumeClaim(
|
func (mc *OnlineHistoryMongoConsumerHandler) ConsumeClaim(sess sarama.ConsumerGroupSession, claim sarama.ConsumerGroupClaim) error { // an instance in the consumer group
|
||||||
sess sarama.ConsumerGroupSession,
|
|
||||||
claim sarama.ConsumerGroupClaim,
|
|
||||||
) error { // an instance in the consumer group
|
|
||||||
log.ZDebug(context.Background(), "online new session msg come", "highWaterMarkOffset",
|
log.ZDebug(context.Background(), "online new session msg come", "highWaterMarkOffset",
|
||||||
claim.HighWaterMarkOffset(), "topic", claim.Topic(), "partition", claim.Partition())
|
claim.HighWaterMarkOffset(), "topic", claim.Topic(), "partition", claim.Partition())
|
||||||
for msg := range claim.Messages() {
|
for msg := range claim.Messages() {
|
||||||
|
@ -1,29 +0,0 @@
|
|||||||
package push
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/openimsdk/protocol/sdkws"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestName(t *testing.T) {
|
|
||||||
var c ConsumerHandler
|
|
||||||
c.readCh = make(chan *sdkws.MarkAsReadTips)
|
|
||||||
|
|
||||||
go c.loopRead()
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
for i := 0; ; i++ {
|
|
||||||
seq := int64(i + 1)
|
|
||||||
if seq%3 == 0 {
|
|
||||||
seq = 1
|
|
||||||
}
|
|
||||||
c.readCh <- &sdkws.MarkAsReadTips{
|
|
||||||
ConversationID: "c100",
|
|
||||||
MarkAsReadUserID: "u100",
|
|
||||||
HasReadSeq: seq,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
select {}
|
|
||||||
}
|
|
@ -24,7 +24,6 @@ import (
|
|||||||
"github.com/openimsdk/protocol/constant"
|
"github.com/openimsdk/protocol/constant"
|
||||||
"github.com/openimsdk/protocol/sdkws"
|
"github.com/openimsdk/protocol/sdkws"
|
||||||
"github.com/openimsdk/tools/mcontext"
|
"github.com/openimsdk/tools/mcontext"
|
||||||
"github.com/openimsdk/tools/utils/datautil"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func (c *ConsumerHandler) webhookBeforeOfflinePush(ctx context.Context, before *config.BeforeConfig, userIDs []string, msg *sdkws.MsgData, offlinePushUserIDs *[]string) error {
|
func (c *ConsumerHandler) webhookBeforeOfflinePush(ctx context.Context, before *config.BeforeConfig, userIDs []string, msg *sdkws.MsgData, offlinePushUserIDs *[]string) error {
|
||||||
@ -70,7 +69,7 @@ func (c *ConsumerHandler) webhookBeforeOfflinePush(ctx context.Context, before *
|
|||||||
|
|
||||||
func (c *ConsumerHandler) webhookBeforeOnlinePush(ctx context.Context, before *config.BeforeConfig, userIDs []string, msg *sdkws.MsgData) error {
|
func (c *ConsumerHandler) webhookBeforeOnlinePush(ctx context.Context, before *config.BeforeConfig, userIDs []string, msg *sdkws.MsgData) error {
|
||||||
return webhook.WithCondition(ctx, before, func(ctx context.Context) error {
|
return webhook.WithCondition(ctx, before, func(ctx context.Context) error {
|
||||||
if datautil.Contain(msg.SendID, userIDs...) || msg.ContentType == constant.Typing {
|
if msg.ContentType == constant.Typing {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
req := callbackstruct.CallbackBeforePushReq{
|
req := callbackstruct.CallbackBeforePushReq{
|
||||||
|
@ -18,6 +18,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"github.com/openimsdk/open-im-server/v3/internal/push/offlinepush/options"
|
"github.com/openimsdk/open-im-server/v3/internal/push/offlinepush/options"
|
||||||
"github.com/openimsdk/tools/log"
|
"github.com/openimsdk/tools/log"
|
||||||
|
"sync/atomic"
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewClient() *Dummy {
|
func NewClient() *Dummy {
|
||||||
@ -25,9 +26,12 @@ func NewClient() *Dummy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Dummy struct {
|
type Dummy struct {
|
||||||
|
v atomic.Bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Dummy) Push(ctx context.Context, userIDs []string, title, content string, opts *options.Opts) error {
|
func (d *Dummy) Push(ctx context.Context, userIDs []string, title, content string, opts *options.Opts) error {
|
||||||
log.ZDebug(ctx, "dummy push")
|
if d.v.CompareAndSwap(false, true) {
|
||||||
|
log.ZWarn(ctx, "dummy push", nil, "ps", "the offline push is not configured. to configure it, please go to config/openim-push.yml")
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
package body
|
package body
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/openimsdk/open-im-server/v3/internal/push/offlinepush/options"
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -26,38 +27,44 @@ type Notification struct {
|
|||||||
|
|
||||||
type Android struct {
|
type Android struct {
|
||||||
Alert string `json:"alert,omitempty"`
|
Alert string `json:"alert,omitempty"`
|
||||||
|
Title string `json:"title,omitempty"`
|
||||||
Intent struct {
|
Intent struct {
|
||||||
URL string `json:"url,omitempty"`
|
URL string `json:"url,omitempty"`
|
||||||
} `json:"intent,omitempty"`
|
} `json:"intent,omitempty"`
|
||||||
Extras Extras `json:"extras"`
|
Extras map[string]string `json:"extras,omitempty"`
|
||||||
}
|
}
|
||||||
type Ios struct {
|
type Ios struct {
|
||||||
Alert string `json:"alert,omitempty"`
|
Alert IosAlert `json:"alert,omitempty"`
|
||||||
Sound string `json:"sound,omitempty"`
|
Sound string `json:"sound,omitempty"`
|
||||||
Badge string `json:"badge,omitempty"`
|
Badge string `json:"badge,omitempty"`
|
||||||
Extras Extras `json:"extras"`
|
Extras map[string]string `json:"extras,omitempty"`
|
||||||
MutableContent bool `json:"mutable-content"`
|
MutableContent bool `json:"mutable-content"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Extras struct {
|
type IosAlert struct {
|
||||||
ClientMsgID string `json:"clientMsgID"`
|
Title string `json:"title,omitempty"`
|
||||||
|
Body string `json:"body,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *Notification) SetAlert(alert string) {
|
func (n *Notification) SetAlert(alert string, title string, opts *options.Opts) {
|
||||||
n.Alert = alert
|
n.Alert = alert
|
||||||
n.Android.Alert = alert
|
n.Android.Alert = alert
|
||||||
n.IOS.Alert = alert
|
n.Android.Title = title
|
||||||
n.IOS.Sound = "default"
|
n.IOS.Alert.Body = alert
|
||||||
n.IOS.Badge = "+1"
|
n.IOS.Alert.Title = title
|
||||||
|
n.IOS.Sound = opts.IOSPushSound
|
||||||
|
if opts.IOSBadgeCount {
|
||||||
|
n.IOS.Badge = "+1"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *Notification) SetExtras(extras Extras) {
|
func (n *Notification) SetExtras(extras map[string]string) {
|
||||||
n.IOS.Extras = extras
|
n.IOS.Extras = extras
|
||||||
n.Android.Extras = extras
|
n.Android.Extras = extras
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *Notification) SetAndroidIntent(pushConf *config.Push) {
|
func (n *Notification) SetAndroidIntent(pushConf *config.Push) {
|
||||||
n.Android.Intent.URL = pushConf.JPNS.PushIntent
|
n.Android.Intent.URL = pushConf.JPush.PushIntent
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *Notification) IOSEnableMutableContent() {
|
func (n *Notification) IOSEnableMutableContent() {
|
||||||
|
@ -18,9 +18,9 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/openimsdk/open-im-server/v3/internal/push/offlinepush/options"
|
|
||||||
|
|
||||||
"github.com/openimsdk/open-im-server/v3/internal/push/offlinepush/jpush/body"
|
"github.com/openimsdk/open-im-server/v3/internal/push/offlinepush/jpush/body"
|
||||||
|
"github.com/openimsdk/open-im-server/v3/internal/push/offlinepush/options"
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
||||||
"github.com/openimsdk/tools/utils/httputil"
|
"github.com/openimsdk/tools/utils/httputil"
|
||||||
)
|
)
|
||||||
@ -57,17 +57,23 @@ func (j *JPush) Push(ctx context.Context, userIDs []string, title, content strin
|
|||||||
var au body.Audience
|
var au body.Audience
|
||||||
au.SetAlias(userIDs)
|
au.SetAlias(userIDs)
|
||||||
var no body.Notification
|
var no body.Notification
|
||||||
var extras body.Extras
|
extras := make(map[string]string)
|
||||||
|
extras["ex"] = opts.Ex
|
||||||
if opts.Signal.ClientMsgID != "" {
|
if opts.Signal.ClientMsgID != "" {
|
||||||
extras.ClientMsgID = opts.Signal.ClientMsgID
|
extras["ClientMsgID"] = opts.Signal.ClientMsgID
|
||||||
}
|
}
|
||||||
no.IOSEnableMutableContent()
|
no.IOSEnableMutableContent()
|
||||||
no.SetExtras(extras)
|
no.SetExtras(extras)
|
||||||
no.SetAlert(title)
|
no.SetAlert(content, title, opts)
|
||||||
no.SetAndroidIntent(j.pushConf)
|
no.SetAndroidIntent(j.pushConf)
|
||||||
|
|
||||||
var msg body.Message
|
var msg body.Message
|
||||||
msg.SetMsgContent(content)
|
msg.SetMsgContent(content)
|
||||||
|
msg.SetTitle(title)
|
||||||
|
if opts.Signal.ClientMsgID != "" {
|
||||||
|
msg.SetExtras("ClientMsgID", opts.Signal.ClientMsgID)
|
||||||
|
}
|
||||||
|
msg.SetExtras("ex", opts.Ex)
|
||||||
var opt body.Options
|
var opt body.Options
|
||||||
opt.SetApnsProduction(j.pushConf.IOSPush.Production)
|
opt.SetApnsProduction(j.pushConf.IOSPush.Production)
|
||||||
var pushObj body.PushObj
|
var pushObj body.PushObj
|
||||||
@ -76,19 +82,26 @@ func (j *JPush) Push(ctx context.Context, userIDs []string, title, content strin
|
|||||||
pushObj.SetNotification(&no)
|
pushObj.SetNotification(&no)
|
||||||
pushObj.SetMessage(&msg)
|
pushObj.SetMessage(&msg)
|
||||||
pushObj.SetOptions(&opt)
|
pushObj.SetOptions(&opt)
|
||||||
var resp any
|
var resp map[string]any
|
||||||
return j.request(ctx, pushObj, resp, 5)
|
return j.request(ctx, pushObj, &resp, 5)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (j *JPush) request(ctx context.Context, po body.PushObj, resp any, timeout int) error {
|
func (j *JPush) request(ctx context.Context, po body.PushObj, resp *map[string]any, timeout int) error {
|
||||||
return j.httpClient.PostReturn(
|
err := j.httpClient.PostReturn(
|
||||||
ctx,
|
ctx,
|
||||||
j.pushConf.JPNS.PushURL,
|
j.pushConf.JPush.PushURL,
|
||||||
map[string]string{
|
map[string]string{
|
||||||
"Authorization": j.getAuthorization(j.pushConf.JPNS.AppKey, j.pushConf.JPNS.MasterSecret),
|
"Authorization": j.getAuthorization(j.pushConf.JPush.AppKey, j.pushConf.JPush.MasterSecret),
|
||||||
},
|
},
|
||||||
po,
|
po,
|
||||||
resp,
|
resp,
|
||||||
timeout,
|
timeout,
|
||||||
)
|
)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if (*resp)["sendno"] != "0" {
|
||||||
|
return fmt.Errorf("jpush push failed %v", resp)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -23,10 +23,11 @@ import (
|
|||||||
"github.com/openimsdk/open-im-server/v3/internal/push/offlinepush/options"
|
"github.com/openimsdk/open-im-server/v3/internal/push/offlinepush/options"
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/common/storage/cache"
|
"github.com/openimsdk/open-im-server/v3/pkg/common/storage/cache"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
geTUI = "geTui"
|
geTUI = "getui"
|
||||||
firebase = "fcm"
|
firebase = "fcm"
|
||||||
jPush = "jpush"
|
jPush = "jpush"
|
||||||
)
|
)
|
||||||
@ -38,6 +39,7 @@ type OfflinePusher interface {
|
|||||||
|
|
||||||
func NewOfflinePusher(pushConf *config.Push, cache cache.ThirdCache, fcmConfigPath string) (OfflinePusher, error) {
|
func NewOfflinePusher(pushConf *config.Push, cache cache.ThirdCache, fcmConfigPath string) (OfflinePusher, error) {
|
||||||
var offlinePusher OfflinePusher
|
var offlinePusher OfflinePusher
|
||||||
|
pushConf.Enable = strings.ToLower(pushConf.Enable)
|
||||||
switch pushConf.Enable {
|
switch pushConf.Enable {
|
||||||
case geTUI:
|
case geTUI:
|
||||||
offlinePusher = getui.NewClient(pushConf, cache)
|
offlinePusher = getui.NewClient(pushConf, cache)
|
||||||
|
@ -55,6 +55,9 @@ func (o *OfflinePushConsumerHandler) handleMsg2OfflinePush(ctx context.Context,
|
|||||||
log.ZError(ctx, "offline push msg is empty", errs.New("offlinePushMsg is empty"), "userIDs", offlinePushMsg.UserIDs, "msg", offlinePushMsg.MsgData)
|
log.ZError(ctx, "offline push msg is empty", errs.New("offlinePushMsg is empty"), "userIDs", offlinePushMsg.UserIDs, "msg", offlinePushMsg.MsgData)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if offlinePushMsg.MsgData.Status == constant.MsgStatusSending {
|
||||||
|
offlinePushMsg.MsgData.Status = constant.MsgStatusSendSuccess
|
||||||
|
}
|
||||||
log.ZInfo(ctx, "receive to OfflinePush MQ", "userIDs", offlinePushMsg.UserIDs, "msg", offlinePushMsg.MsgData)
|
log.ZInfo(ctx, "receive to OfflinePush MQ", "userIDs", offlinePushMsg.UserIDs, "msg", offlinePushMsg.MsgData)
|
||||||
|
|
||||||
err := o.offlinePushMsg(ctx, offlinePushMsg.MsgData, offlinePushMsg.UserIDs)
|
err := o.offlinePushMsg(ctx, offlinePushMsg.MsgData, offlinePushMsg.UserIDs)
|
||||||
@ -70,7 +73,7 @@ func (o *OfflinePushConsumerHandler) getOfflinePushInfos(msg *sdkws.MsgData) (ti
|
|||||||
IsAtSelf bool `json:"isAtSelf"`
|
IsAtSelf bool `json:"isAtSelf"`
|
||||||
}
|
}
|
||||||
|
|
||||||
opts = &options.Opts{Signal: &options.Signal{}}
|
opts = &options.Opts{Signal: &options.Signal{ClientMsgID: msg.ClientMsgID}}
|
||||||
if msg.OfflinePushInfo != nil {
|
if msg.OfflinePushInfo != nil {
|
||||||
opts.IOSBadgeCount = msg.OfflinePushInfo.IOSBadgeCount
|
opts.IOSBadgeCount = msg.OfflinePushInfo.IOSBadgeCount
|
||||||
opts.IOSPushSound = msg.OfflinePushInfo.IOSPushSound
|
opts.IOSPushSound = msg.OfflinePushInfo.IOSPushSound
|
||||||
|
@ -2,14 +2,19 @@ package push
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
|
"sync"
|
||||||
|
|
||||||
"github.com/openimsdk/protocol/msggateway"
|
"github.com/openimsdk/protocol/msggateway"
|
||||||
"github.com/openimsdk/protocol/sdkws"
|
"github.com/openimsdk/protocol/sdkws"
|
||||||
"github.com/openimsdk/tools/discovery"
|
"github.com/openimsdk/tools/discovery"
|
||||||
|
"github.com/openimsdk/tools/errs"
|
||||||
"github.com/openimsdk/tools/log"
|
"github.com/openimsdk/tools/log"
|
||||||
"github.com/openimsdk/tools/utils/datautil"
|
"github.com/openimsdk/tools/utils/datautil"
|
||||||
"golang.org/x/sync/errgroup"
|
"golang.org/x/sync/errgroup"
|
||||||
"google.golang.org/grpc"
|
"google.golang.org/grpc"
|
||||||
"sync"
|
|
||||||
|
conf "github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
type OnlinePusher interface {
|
type OnlinePusher interface {
|
||||||
@ -37,15 +42,16 @@ func (u emptyOnlinePusher) GetOnlinePushFailedUserIDs(ctx context.Context, msg *
|
|||||||
}
|
}
|
||||||
|
|
||||||
func NewOnlinePusher(disCov discovery.SvcDiscoveryRegistry, config *Config) OnlinePusher {
|
func NewOnlinePusher(disCov discovery.SvcDiscoveryRegistry, config *Config) OnlinePusher {
|
||||||
switch config.Discovery.Enable {
|
|
||||||
case "k8s":
|
if config.runTimeEnv == conf.KUBERNETES {
|
||||||
return NewK8sStaticConsistentHash(disCov, config)
|
|
||||||
case "zookeeper":
|
|
||||||
return NewDefaultAllNode(disCov, config)
|
return NewDefaultAllNode(disCov, config)
|
||||||
case "etcd":
|
}
|
||||||
|
switch config.Discovery.Enable {
|
||||||
|
case conf.ETCD:
|
||||||
return NewDefaultAllNode(disCov, config)
|
return NewDefaultAllNode(disCov, config)
|
||||||
default:
|
default:
|
||||||
return newEmptyOnlinePusher()
|
log.ZError(context.Background(), "NewOnlinePusher is error", errs.Wrap(errors.New("unsupported discovery type")), "type", config.Discovery.Enable)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,7 +66,7 @@ func NewDefaultAllNode(disCov discovery.SvcDiscoveryRegistry, config *Config) *D
|
|||||||
|
|
||||||
func (d *DefaultAllNode) GetConnsAndOnlinePush(ctx context.Context, msg *sdkws.MsgData,
|
func (d *DefaultAllNode) GetConnsAndOnlinePush(ctx context.Context, msg *sdkws.MsgData,
|
||||||
pushToUserIDs []string) (wsResults []*msggateway.SingleMsgToUserResults, err error) {
|
pushToUserIDs []string) (wsResults []*msggateway.SingleMsgToUserResults, err error) {
|
||||||
conns, err := d.disCov.GetConns(ctx, d.config.Share.RpcRegisterName.MessageGateway)
|
conns, err := d.disCov.GetConns(ctx, d.config.Discovery.RpcService.MessageGateway)
|
||||||
if len(conns) == 0 {
|
if len(conns) == 0 {
|
||||||
log.ZWarn(ctx, "get gateway conn 0 ", nil)
|
log.ZWarn(ctx, "get gateway conn 0 ", nil)
|
||||||
} else {
|
} else {
|
||||||
|
@ -14,6 +14,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type pushServer struct {
|
type pushServer struct {
|
||||||
|
pbpush.UnimplementedPushMsgServiceServer
|
||||||
database controller.PushDatabase
|
database controller.PushDatabase
|
||||||
disCov discovery.SvcDiscoveryRegistry
|
disCov discovery.SvcDiscoveryRegistry
|
||||||
offlinePusher offlinepush.OfflinePusher
|
offlinePusher offlinepush.OfflinePusher
|
||||||
@ -31,11 +32,8 @@ type Config struct {
|
|||||||
LocalCacheConfig config.LocalCache
|
LocalCacheConfig config.LocalCache
|
||||||
Discovery config.Discovery
|
Discovery config.Discovery
|
||||||
FcmConfigPath string
|
FcmConfigPath string
|
||||||
}
|
|
||||||
|
|
||||||
func (p pushServer) PushMsg(ctx context.Context, req *pbpush.PushMsgReq) (*pbpush.PushMsgResp, error) {
|
runTimeEnv string
|
||||||
//todo reserved Interface
|
|
||||||
return nil, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p pushServer) DelUserPushToken(ctx context.Context,
|
func (p pushServer) DelUserPushToken(ctx context.Context,
|
||||||
@ -59,7 +57,7 @@ func Start(ctx context.Context, config *Config, client discovery.SvcDiscoveryReg
|
|||||||
|
|
||||||
database := controller.NewPushDatabase(cacheModel, &config.KafkaConfig)
|
database := controller.NewPushDatabase(cacheModel, &config.KafkaConfig)
|
||||||
|
|
||||||
consumer, err := NewConsumerHandler(config, database, offlinePusher, rdb, client)
|
consumer, err := NewConsumerHandler(ctx, config, database, offlinePusher, rdb, client)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,11 @@ package push
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"math/rand"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/openimsdk/open-im-server/v3/pkg/rpcli"
|
||||||
|
|
||||||
"github.com/IBM/sarama"
|
"github.com/IBM/sarama"
|
||||||
"github.com/openimsdk/open-im-server/v3/internal/push/offlinepush"
|
"github.com/openimsdk/open-im-server/v3/internal/push/offlinepush"
|
||||||
@ -12,7 +17,6 @@ import (
|
|||||||
"github.com/openimsdk/open-im-server/v3/pkg/common/webhook"
|
"github.com/openimsdk/open-im-server/v3/pkg/common/webhook"
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/msgprocessor"
|
"github.com/openimsdk/open-im-server/v3/pkg/msgprocessor"
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/rpccache"
|
"github.com/openimsdk/open-im-server/v3/pkg/rpccache"
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
|
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/util/conversationutil"
|
"github.com/openimsdk/open-im-server/v3/pkg/util/conversationutil"
|
||||||
"github.com/openimsdk/protocol/constant"
|
"github.com/openimsdk/protocol/constant"
|
||||||
"github.com/openimsdk/protocol/msggateway"
|
"github.com/openimsdk/protocol/msggateway"
|
||||||
@ -27,9 +31,6 @@ import (
|
|||||||
"github.com/openimsdk/tools/utils/timeutil"
|
"github.com/openimsdk/tools/utils/timeutil"
|
||||||
"github.com/redis/go-redis/v9"
|
"github.com/redis/go-redis/v9"
|
||||||
"google.golang.org/protobuf/proto"
|
"google.golang.org/protobuf/proto"
|
||||||
"math/rand"
|
|
||||||
"strconv"
|
|
||||||
"time"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type ConsumerHandler struct {
|
type ConsumerHandler struct {
|
||||||
@ -40,14 +41,15 @@ type ConsumerHandler struct {
|
|||||||
onlineCache *rpccache.OnlineCache
|
onlineCache *rpccache.OnlineCache
|
||||||
groupLocalCache *rpccache.GroupLocalCache
|
groupLocalCache *rpccache.GroupLocalCache
|
||||||
conversationLocalCache *rpccache.ConversationLocalCache
|
conversationLocalCache *rpccache.ConversationLocalCache
|
||||||
msgRpcClient rpcclient.MessageRpcClient
|
|
||||||
conversationRpcClient rpcclient.ConversationRpcClient
|
|
||||||
groupRpcClient rpcclient.GroupRpcClient
|
|
||||||
webhookClient *webhook.Client
|
webhookClient *webhook.Client
|
||||||
config *Config
|
config *Config
|
||||||
|
userClient *rpcli.UserClient
|
||||||
|
groupClient *rpcli.GroupClient
|
||||||
|
msgClient *rpcli.MsgClient
|
||||||
|
conversationClient *rpcli.ConversationClient
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewConsumerHandler(config *Config, database controller.PushDatabase, offlinePusher offlinepush.OfflinePusher, rdb redis.UniversalClient,
|
func NewConsumerHandler(ctx context.Context, config *Config, database controller.PushDatabase, offlinePusher offlinepush.OfflinePusher, rdb redis.UniversalClient,
|
||||||
client discovery.SvcDiscoveryRegistry) (*ConsumerHandler, error) {
|
client discovery.SvcDiscoveryRegistry) (*ConsumerHandler, error) {
|
||||||
var consumerHandler ConsumerHandler
|
var consumerHandler ConsumerHandler
|
||||||
var err error
|
var err error
|
||||||
@ -56,20 +58,35 @@ func NewConsumerHandler(config *Config, database controller.PushDatabase, offlin
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
userConn, err := client.GetConn(ctx, config.Discovery.RpcService.User)
|
||||||
userRpcClient := rpcclient.NewUserRpcClient(client, config.Share.RpcRegisterName.User, config.Share.IMAdminUserID)
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
groupConn, err := client.GetConn(ctx, config.Discovery.RpcService.Group)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
msgConn, err := client.GetConn(ctx, config.Discovery.RpcService.Msg)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
conversationConn, err := client.GetConn(ctx, config.Discovery.RpcService.Conversation)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
consumerHandler.userClient = rpcli.NewUserClient(userConn)
|
||||||
|
consumerHandler.groupClient = rpcli.NewGroupClient(groupConn)
|
||||||
|
consumerHandler.msgClient = rpcli.NewMsgClient(msgConn)
|
||||||
|
consumerHandler.conversationClient = rpcli.NewConversationClient(conversationConn)
|
||||||
|
|
||||||
consumerHandler.offlinePusher = offlinePusher
|
consumerHandler.offlinePusher = offlinePusher
|
||||||
consumerHandler.onlinePusher = NewOnlinePusher(client, config)
|
consumerHandler.onlinePusher = NewOnlinePusher(client, config)
|
||||||
consumerHandler.groupRpcClient = rpcclient.NewGroupRpcClient(client, config.Share.RpcRegisterName.Group)
|
consumerHandler.groupLocalCache = rpccache.NewGroupLocalCache(consumerHandler.groupClient, &config.LocalCacheConfig, rdb)
|
||||||
consumerHandler.groupLocalCache = rpccache.NewGroupLocalCache(consumerHandler.groupRpcClient, &config.LocalCacheConfig, rdb)
|
consumerHandler.conversationLocalCache = rpccache.NewConversationLocalCache(consumerHandler.conversationClient, &config.LocalCacheConfig, rdb)
|
||||||
consumerHandler.msgRpcClient = rpcclient.NewMessageRpcClient(client, config.Share.RpcRegisterName.Msg)
|
|
||||||
consumerHandler.conversationRpcClient = rpcclient.NewConversationRpcClient(client, config.Share.RpcRegisterName.Conversation)
|
|
||||||
consumerHandler.conversationLocalCache = rpccache.NewConversationLocalCache(consumerHandler.conversationRpcClient, &config.LocalCacheConfig, rdb)
|
|
||||||
consumerHandler.webhookClient = webhook.NewWebhookClient(config.WebhooksConfig.URL)
|
consumerHandler.webhookClient = webhook.NewWebhookClient(config.WebhooksConfig.URL)
|
||||||
consumerHandler.config = config
|
consumerHandler.config = config
|
||||||
consumerHandler.pushDatabase = database
|
consumerHandler.pushDatabase = database
|
||||||
consumerHandler.onlineCache, err = rpccache.NewOnlineCache(userRpcClient, consumerHandler.groupLocalCache, rdb, config.RpcConfig.FullUserCache, nil)
|
consumerHandler.onlineCache, err = rpccache.NewOnlineCache(consumerHandler.userClient, consumerHandler.groupLocalCache, rdb, config.RpcConfig.FullUserCache, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -136,24 +153,24 @@ func (c *ConsumerHandler) Push2User(ctx context.Context, userIDs []string, msg *
|
|||||||
log.ZInfo(ctx, "Get msg from msg_transfer And push msg", "userIDs", userIDs, "msg", msg.String())
|
log.ZInfo(ctx, "Get msg from msg_transfer And push msg", "userIDs", userIDs, "msg", msg.String())
|
||||||
defer func(duration time.Time) {
|
defer func(duration time.Time) {
|
||||||
t := time.Since(duration)
|
t := time.Since(duration)
|
||||||
log.ZInfo(ctx, "Get msg from msg_transfer And push msg", "msg", msg.String(), "time cost", t)
|
log.ZInfo(ctx, "Get msg from msg_transfer And push msg end", "msg", msg.String(), "time cost", t)
|
||||||
}(time.Now())
|
}(time.Now())
|
||||||
if err := c.webhookBeforeOnlinePush(ctx, &c.config.WebhooksConfig.BeforeOnlinePush, userIDs, msg); err != nil {
|
if err := c.webhookBeforeOnlinePush(ctx, &c.config.WebhooksConfig.BeforeOnlinePush, userIDs, msg); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
log.ZInfo(ctx, "webhookBeforeOnlinePush end")
|
|
||||||
|
|
||||||
wsResults, err := c.GetConnsAndOnlinePush(ctx, msg, userIDs)
|
wsResults, err := c.GetConnsAndOnlinePush(ctx, msg, userIDs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
log.ZInfo(ctx, "single and notification push result", "result", wsResults, "msg", msg, "push_to_userID", userIDs)
|
log.ZDebug(ctx, "single and notification push result", "result", wsResults, "msg", msg, "push_to_userID", userIDs)
|
||||||
|
log.ZInfo(ctx, "single and notification push end")
|
||||||
|
|
||||||
if !c.shouldPushOffline(ctx, msg) {
|
if !c.shouldPushOffline(ctx, msg) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
log.ZInfo(ctx, "shouldPushOffline end")
|
log.ZInfo(ctx, "pushOffline start")
|
||||||
|
|
||||||
for _, v := range wsResults {
|
for _, v := range wsResults {
|
||||||
//message sender do not need offline push
|
//message sender do not need offline push
|
||||||
@ -165,17 +182,21 @@ func (c *ConsumerHandler) Push2User(ctx context.Context, userIDs []string, msg *
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
offlinePushUserID := []string{msg.RecvID}
|
needOfflinePushUserID := []string{msg.RecvID}
|
||||||
|
var offlinePushUserID []string
|
||||||
|
|
||||||
//receiver offline push
|
//receiver offline push
|
||||||
if err = c.webhookBeforeOfflinePush(ctx, &c.config.WebhooksConfig.BeforeOfflinePush,
|
if err = c.webhookBeforeOfflinePush(ctx, &c.config.WebhooksConfig.BeforeOfflinePush, needOfflinePushUserID, msg, &offlinePushUserID); err != nil {
|
||||||
offlinePushUserID, msg, nil); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
log.ZInfo(ctx, "webhookBeforeOfflinePush end")
|
|
||||||
err = c.offlinePushMsg(ctx, msg, offlinePushUserID)
|
if len(offlinePushUserID) > 0 {
|
||||||
|
needOfflinePushUserID = offlinePushUserID
|
||||||
|
}
|
||||||
|
err = c.offlinePushMsg(ctx, msg, needOfflinePushUserID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.ZWarn(ctx, "offlinePushMsg failed", err, "offlinePushUserID", offlinePushUserID, "msg", msg)
|
log.ZDebug(ctx, "offlinePushMsg failed", err, "needOfflinePushUserID", needOfflinePushUserID, "msg", msg)
|
||||||
|
log.ZWarn(ctx, "offlinePushMsg failed", err, "needOfflinePushUserID length", len(needOfflinePushUserID), "msg", msg)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -194,6 +215,9 @@ func (c *ConsumerHandler) shouldPushOffline(_ context.Context, msg *sdkws.MsgDat
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *ConsumerHandler) GetConnsAndOnlinePush(ctx context.Context, msg *sdkws.MsgData, pushToUserIDs []string) ([]*msggateway.SingleMsgToUserResults, error) {
|
func (c *ConsumerHandler) GetConnsAndOnlinePush(ctx context.Context, msg *sdkws.MsgData, pushToUserIDs []string) ([]*msggateway.SingleMsgToUserResults, error) {
|
||||||
|
if msg != nil && msg.Status == constant.MsgStatusSending {
|
||||||
|
msg.Status = constant.MsgStatusSendSuccess
|
||||||
|
}
|
||||||
onlineUserIDs, offlineUserIDs, err := c.onlineCache.GetUsersOnline(ctx, pushToUserIDs)
|
onlineUserIDs, offlineUserIDs, err := c.onlineCache.GetUsersOnline(ctx, pushToUserIDs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -227,26 +251,24 @@ func (c *ConsumerHandler) Push2Group(ctx context.Context, groupID string, msg *s
|
|||||||
&pushToUserIDs); err != nil {
|
&pushToUserIDs); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
log.ZInfo(ctx, "webhookBeforeGroupOnlinePush end")
|
|
||||||
|
|
||||||
err = c.groupMessagesHandler(ctx, groupID, &pushToUserIDs, msg)
|
err = c.groupMessagesHandler(ctx, groupID, &pushToUserIDs, msg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
log.ZInfo(ctx, "groupMessagesHandler end")
|
|
||||||
|
|
||||||
wsResults, err := c.GetConnsAndOnlinePush(ctx, msg, pushToUserIDs)
|
wsResults, err := c.GetConnsAndOnlinePush(ctx, msg, pushToUserIDs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
log.ZInfo(ctx, "group push result", "result", wsResults, "msg", msg)
|
log.ZDebug(ctx, "group push result", "result", wsResults, "msg", msg)
|
||||||
|
log.ZInfo(ctx, "online group push end")
|
||||||
|
|
||||||
if !c.shouldPushOffline(ctx, msg) {
|
if !c.shouldPushOffline(ctx, msg) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
needOfflinePushUserIDs := c.onlinePusher.GetOnlinePushFailedUserIDs(ctx, msg, wsResults, &pushToUserIDs)
|
needOfflinePushUserIDs := c.onlinePusher.GetOnlinePushFailedUserIDs(ctx, msg, wsResults, &pushToUserIDs)
|
||||||
log.ZInfo(ctx, "GetOnlinePushFailedUserIDs end")
|
|
||||||
//filter some user, like don not disturb or don't need offline push etc.
|
//filter some user, like don not disturb or don't need offline push etc.
|
||||||
needOfflinePushUserIDs, err = c.filterGroupMessageOfflinePush(ctx, groupID, msg, needOfflinePushUserIDs)
|
needOfflinePushUserIDs, err = c.filterGroupMessageOfflinePush(ctx, groupID, msg, needOfflinePushUserIDs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -274,9 +296,11 @@ func (c *ConsumerHandler) asyncOfflinePush(ctx context.Context, needOfflinePushU
|
|||||||
needOfflinePushUserIDs = offlinePushUserIDs
|
needOfflinePushUserIDs = offlinePushUserIDs
|
||||||
}
|
}
|
||||||
if err := c.pushDatabase.MsgToOfflinePushMQ(ctx, conversationutil.GenConversationUniqueKeyForSingle(msg.SendID, msg.RecvID), needOfflinePushUserIDs, msg); err != nil {
|
if err := c.pushDatabase.MsgToOfflinePushMQ(ctx, conversationutil.GenConversationUniqueKeyForSingle(msg.SendID, msg.RecvID), needOfflinePushUserIDs, msg); err != nil {
|
||||||
log.ZError(ctx, "Msg To OfflinePush MQ error", err, "needOfflinePushUserIDs",
|
log.ZDebug(ctx, "Msg To OfflinePush MQ error", err, "needOfflinePushUserIDs",
|
||||||
needOfflinePushUserIDs, "msg", msg)
|
needOfflinePushUserIDs, "msg", msg)
|
||||||
prommetrics.SingleChatMsgProcessFailedCounter.Inc()
|
log.ZWarn(ctx, "Msg To OfflinePush MQ error", err, "needOfflinePushUserIDs length",
|
||||||
|
len(needOfflinePushUserIDs), "msg", msg)
|
||||||
|
prommetrics.GroupChatMsgProcessFailedCounter.Inc()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -319,7 +343,7 @@ func (c *ConsumerHandler) groupMessagesHandler(ctx context.Context, groupID stri
|
|||||||
ctx = mcontext.WithOpUserIDContext(ctx, c.config.Share.IMAdminUserID[0])
|
ctx = mcontext.WithOpUserIDContext(ctx, c.config.Share.IMAdminUserID[0])
|
||||||
}
|
}
|
||||||
defer func(groupID string) {
|
defer func(groupID string) {
|
||||||
if err = c.groupRpcClient.DismissGroup(ctx, groupID); err != nil {
|
if err := c.groupClient.DismissGroup(ctx, groupID, true); err != nil {
|
||||||
log.ZError(ctx, "DismissGroup Notification clear members", err, "groupID", groupID)
|
log.ZError(ctx, "DismissGroup Notification clear members", err, "groupID", groupID)
|
||||||
}
|
}
|
||||||
}(groupID)
|
}(groupID)
|
||||||
@ -332,6 +356,7 @@ func (c *ConsumerHandler) groupMessagesHandler(ctx context.Context, groupID stri
|
|||||||
func (c *ConsumerHandler) offlinePushMsg(ctx context.Context, msg *sdkws.MsgData, offlinePushUserIDs []string) error {
|
func (c *ConsumerHandler) offlinePushMsg(ctx context.Context, msg *sdkws.MsgData, offlinePushUserIDs []string) error {
|
||||||
title, content, opts, err := c.getOfflinePushInfos(msg)
|
title, content, opts, err := c.getOfflinePushInfos(msg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
log.ZError(ctx, "getOfflinePushInfos failed", err, "msg", msg)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = c.offlinePusher.Push(ctx, offlinePushUserIDs, title, content, opts)
|
err = c.offlinePusher.Push(ctx, offlinePushUserIDs, title, content, opts)
|
||||||
@ -344,10 +369,7 @@ func (c *ConsumerHandler) offlinePushMsg(ctx context.Context, msg *sdkws.MsgData
|
|||||||
|
|
||||||
func (c *ConsumerHandler) filterGroupMessageOfflinePush(ctx context.Context, groupID string, msg *sdkws.MsgData,
|
func (c *ConsumerHandler) filterGroupMessageOfflinePush(ctx context.Context, groupID string, msg *sdkws.MsgData,
|
||||||
offlinePushUserIDs []string) (userIDs []string, err error) {
|
offlinePushUserIDs []string) (userIDs []string, err error) {
|
||||||
|
needOfflinePushUserIDs, err := c.conversationClient.GetConversationOfflinePushUserIDs(ctx, conversationutil.GenGroupConversationID(groupID), offlinePushUserIDs)
|
||||||
//todo local cache Obtain the difference set through local comparison.
|
|
||||||
needOfflinePushUserIDs, err := c.conversationRpcClient.GetConversationOfflinePushUserIDs(
|
|
||||||
ctx, conversationutil.GenGroupConversationID(groupID), offlinePushUserIDs)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -361,7 +383,7 @@ func (c *ConsumerHandler) getOfflinePushInfos(msg *sdkws.MsgData) (title, conten
|
|||||||
IsAtSelf bool `json:"isAtSelf"`
|
IsAtSelf bool `json:"isAtSelf"`
|
||||||
}
|
}
|
||||||
|
|
||||||
opts = &options.Opts{Signal: &options.Signal{}}
|
opts = &options.Opts{Signal: &options.Signal{ClientMsgID: msg.ClientMsgID}}
|
||||||
if msg.OfflinePushInfo != nil {
|
if msg.OfflinePushInfo != nil {
|
||||||
opts.IOSBadgeCount = msg.OfflinePushInfo.IOSBadgeCount
|
opts.IOSBadgeCount = msg.OfflinePushInfo.IOSBadgeCount
|
||||||
opts.IOSPushSound = msg.OfflinePushInfo.IOSPushSound
|
opts.IOSPushSound = msg.OfflinePushInfo.IOSPushSound
|
||||||
@ -401,11 +423,11 @@ func (c *ConsumerHandler) getOfflinePushInfos(msg *sdkws.MsgData) (title, conten
|
|||||||
|
|
||||||
func (c *ConsumerHandler) DeleteMemberAndSetConversationSeq(ctx context.Context, groupID string, userIDs []string) error {
|
func (c *ConsumerHandler) DeleteMemberAndSetConversationSeq(ctx context.Context, groupID string, userIDs []string) error {
|
||||||
conversationID := msgprocessor.GetConversationIDBySessionType(constant.ReadGroupChatType, groupID)
|
conversationID := msgprocessor.GetConversationIDBySessionType(constant.ReadGroupChatType, groupID)
|
||||||
maxSeq, err := c.msgRpcClient.GetConversationMaxSeq(ctx, conversationID)
|
maxSeq, err := c.msgClient.GetConversationMaxSeq(ctx, conversationID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return c.conversationRpcClient.SetConversationMaxSeq(ctx, userIDs, conversationID, maxSeq)
|
return c.conversationClient.SetConversationMaxSeq(ctx, conversationID, userIDs, maxSeq)
|
||||||
}
|
}
|
||||||
|
|
||||||
func unmarshalNotificationElem(bytes []byte, t any) error {
|
func unmarshalNotificationElem(bytes []byte, t any) error {
|
||||||
@ -413,6 +435,5 @@ func unmarshalNotificationElem(bytes []byte, t any) error {
|
|||||||
if err := json.Unmarshal(bytes, ¬ification); err != nil {
|
if err := json.Unmarshal(bytes, ¬ification); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return json.Unmarshal([]byte(notification.Detail), t)
|
return json.Unmarshal([]byte(notification.Detail), t)
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,9 @@ package auth
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"github.com/openimsdk/open-im-server/v3/pkg/rpcli"
|
||||||
|
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
||||||
redis2 "github.com/openimsdk/open-im-server/v3/pkg/common/storage/cache/redis"
|
redis2 "github.com/openimsdk/open-im-server/v3/pkg/common/storage/cache/redis"
|
||||||
@ -27,7 +30,6 @@ import (
|
|||||||
"github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics"
|
"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/servererrs"
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/common/storage/controller"
|
"github.com/openimsdk/open-im-server/v3/pkg/common/storage/controller"
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
|
|
||||||
pbauth "github.com/openimsdk/protocol/auth"
|
pbauth "github.com/openimsdk/protocol/auth"
|
||||||
"github.com/openimsdk/protocol/constant"
|
"github.com/openimsdk/protocol/constant"
|
||||||
"github.com/openimsdk/protocol/msggateway"
|
"github.com/openimsdk/protocol/msggateway"
|
||||||
@ -39,10 +41,11 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type authServer struct {
|
type authServer struct {
|
||||||
|
pbauth.UnimplementedAuthServer
|
||||||
authDatabase controller.AuthDatabase
|
authDatabase controller.AuthDatabase
|
||||||
userRpcClient *rpcclient.UserRpcClient
|
|
||||||
RegisterCenter discovery.SvcDiscoveryRegistry
|
RegisterCenter discovery.SvcDiscoveryRegistry
|
||||||
config *Config
|
config *Config
|
||||||
|
userClient *rpcli.UserClient
|
||||||
}
|
}
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
@ -57,17 +60,21 @@ func Start(ctx context.Context, config *Config, client discovery.SvcDiscoveryReg
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
userRpcClient := rpcclient.NewUserRpcClient(client, config.Share.RpcRegisterName.User, config.Share.IMAdminUserID)
|
userConn, err := client.GetConn(ctx, config.Discovery.RpcService.User)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
pbauth.RegisterAuthServer(server, &authServer{
|
pbauth.RegisterAuthServer(server, &authServer{
|
||||||
userRpcClient: &userRpcClient,
|
|
||||||
RegisterCenter: client,
|
RegisterCenter: client,
|
||||||
authDatabase: controller.NewAuthDatabase(
|
authDatabase: controller.NewAuthDatabase(
|
||||||
redis2.NewTokenCacheModel(rdb, config.RpcConfig.TokenPolicy.Expire),
|
redis2.NewTokenCacheModel(rdb, config.RpcConfig.TokenPolicy.Expire),
|
||||||
config.Share.Secret,
|
config.Share.Secret,
|
||||||
config.RpcConfig.TokenPolicy.Expire,
|
config.RpcConfig.TokenPolicy.Expire,
|
||||||
config.Share.MultiLoginPolicy,
|
config.Share.MultiLogin,
|
||||||
|
config.Share.IMAdminUserID,
|
||||||
),
|
),
|
||||||
config: config,
|
config: config,
|
||||||
|
userClient: rpcli.NewUserClient(userConn),
|
||||||
})
|
})
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -83,7 +90,7 @@ func (s *authServer) GetAdminToken(ctx context.Context, req *pbauth.GetAdminToke
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := s.userRpcClient.GetUserInfo(ctx, req.UserID); err != nil {
|
if err := s.userClient.CheckUser(ctx, []string{req.UserID}); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -112,9 +119,13 @@ func (s *authServer) GetUserToken(ctx context.Context, req *pbauth.GetUserTokenR
|
|||||||
if authverify.IsManagerUserID(req.UserID, s.config.Share.IMAdminUserID) {
|
if authverify.IsManagerUserID(req.UserID, s.config.Share.IMAdminUserID) {
|
||||||
return nil, errs.ErrNoPermission.WrapMsg("don't get Admin token")
|
return nil, errs.ErrNoPermission.WrapMsg("don't get Admin token")
|
||||||
}
|
}
|
||||||
if _, err := s.userRpcClient.GetUserInfo(ctx, req.UserID); err != nil {
|
user, err := s.userClient.GetUserInfo(ctx, req.UserID)
|
||||||
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
if user.AppMangerLevel >= constant.AppNotificationAdmin {
|
||||||
|
return nil, errs.ErrArgs.WrapMsg("app account can`t get token")
|
||||||
|
}
|
||||||
token, err := s.authDatabase.CreateToken(ctx, req.UserID, int(req.PlatformID))
|
token, err := s.authDatabase.CreateToken(ctx, req.UserID, int(req.PlatformID))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -127,7 +138,11 @@ func (s *authServer) GetUserToken(ctx context.Context, req *pbauth.GetUserTokenR
|
|||||||
func (s *authServer) parseToken(ctx context.Context, tokensString string) (claims *tokenverify.Claims, err error) {
|
func (s *authServer) parseToken(ctx context.Context, tokensString string) (claims *tokenverify.Claims, err error) {
|
||||||
claims, err = tokenverify.GetClaimFromToken(tokensString, authverify.Secret(s.config.Share.Secret))
|
claims, err = tokenverify.GetClaimFromToken(tokensString, authverify.Secret(s.config.Share.Secret))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errs.Wrap(err)
|
return nil, err
|
||||||
|
}
|
||||||
|
isAdmin := authverify.IsManagerUserID(claims.UserID, s.config.Share.IMAdminUserID)
|
||||||
|
if isAdmin {
|
||||||
|
return claims, nil
|
||||||
}
|
}
|
||||||
m, err := s.authDatabase.GetTokensWithoutError(ctx, claims.UserID, claims.PlatformID)
|
m, err := s.authDatabase.GetTokensWithoutError(ctx, claims.UserID, claims.PlatformID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -149,10 +164,7 @@ func (s *authServer) parseToken(ctx context.Context, tokensString string) (claim
|
|||||||
return nil, servererrs.ErrTokenNotExist.Wrap()
|
return nil, servererrs.ErrTokenNotExist.Wrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *authServer) ParseToken(
|
func (s *authServer) ParseToken(ctx context.Context, req *pbauth.ParseTokenReq) (resp *pbauth.ParseTokenResp, err error) {
|
||||||
ctx context.Context,
|
|
||||||
req *pbauth.ParseTokenReq,
|
|
||||||
) (resp *pbauth.ParseTokenResp, err error) {
|
|
||||||
resp = &pbauth.ParseTokenResp{}
|
resp = &pbauth.ParseTokenResp{}
|
||||||
claims, err := s.parseToken(ctx, req.Token)
|
claims, err := s.parseToken(ctx, req.Token)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -175,7 +187,7 @@ func (s *authServer) ForceLogout(ctx context.Context, req *pbauth.ForceLogoutReq
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *authServer) forceKickOff(ctx context.Context, userID string, platformID int32) error {
|
func (s *authServer) forceKickOff(ctx context.Context, userID string, platformID int32) error {
|
||||||
conns, err := s.RegisterCenter.GetConns(ctx, s.config.Share.RpcRegisterName.MessageGateway)
|
conns, err := s.RegisterCenter.GetConns(ctx, s.config.Discovery.RpcService.MessageGateway)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -190,7 +202,7 @@ func (s *authServer) forceKickOff(ctx context.Context, userID string, platformID
|
|||||||
}
|
}
|
||||||
|
|
||||||
m, err := s.authDatabase.GetTokensWithoutError(ctx, userID, int(platformID))
|
m, err := s.authDatabase.GetTokensWithoutError(ctx, userID, int(platformID))
|
||||||
if err != nil && err != redis.Nil {
|
if err != nil && !errors.Is(err, redis.Nil) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
for k := range m {
|
for k := range m {
|
||||||
@ -208,7 +220,7 @@ func (s *authServer) forceKickOff(ctx context.Context, userID string, platformID
|
|||||||
|
|
||||||
func (s *authServer) InvalidateToken(ctx context.Context, req *pbauth.InvalidateTokenReq) (*pbauth.InvalidateTokenResp, error) {
|
func (s *authServer) InvalidateToken(ctx context.Context, req *pbauth.InvalidateTokenReq) (*pbauth.InvalidateTokenResp, error) {
|
||||||
m, err := s.authDatabase.GetTokensWithoutError(ctx, req.UserID, int(req.PlatformID))
|
m, err := s.authDatabase.GetTokensWithoutError(ctx, req.UserID, int(req.PlatformID))
|
||||||
if err != nil && err != redis.Nil {
|
if err != nil && !errors.Is(err, redis.Nil) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if m == nil {
|
if m == nil {
|
||||||
@ -230,3 +242,10 @@ func (s *authServer) InvalidateToken(ctx context.Context, req *pbauth.Invalidate
|
|||||||
}
|
}
|
||||||
return &pbauth.InvalidateTokenResp{}, nil
|
return &pbauth.InvalidateTokenResp{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *authServer) KickTokens(ctx context.Context, req *pbauth.KickTokensReq) (*pbauth.KickTokensResp, error) {
|
||||||
|
if err := s.authDatabase.BatchSetTokenMapByUidPid(ctx, req.Tokens); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &pbauth.KickTokensResp{}, nil
|
||||||
|
}
|
||||||
|
@ -19,18 +19,20 @@ import (
|
|||||||
"sort"
|
"sort"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/openimsdk/open-im-server/v3/pkg/rpcli"
|
||||||
|
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
"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/cache/redis"
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/common/storage/database/mgo"
|
"github.com/openimsdk/open-im-server/v3/pkg/common/storage/database/mgo"
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/common/storage/model"
|
"github.com/openimsdk/open-im-server/v3/pkg/common/storage/model"
|
||||||
dbModel "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/localcache"
|
||||||
|
"github.com/openimsdk/open-im-server/v3/pkg/msgprocessor"
|
||||||
"github.com/openimsdk/tools/db/redisutil"
|
"github.com/openimsdk/tools/db/redisutil"
|
||||||
|
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/common/convert"
|
"github.com/openimsdk/open-im-server/v3/pkg/common/convert"
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/common/servererrs"
|
"github.com/openimsdk/open-im-server/v3/pkg/common/servererrs"
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/common/storage/controller"
|
"github.com/openimsdk/open-im-server/v3/pkg/common/storage/controller"
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
|
|
||||||
"github.com/openimsdk/protocol/constant"
|
"github.com/openimsdk/protocol/constant"
|
||||||
pbconversation "github.com/openimsdk/protocol/conversation"
|
pbconversation "github.com/openimsdk/protocol/conversation"
|
||||||
"github.com/openimsdk/protocol/sdkws"
|
"github.com/openimsdk/protocol/sdkws"
|
||||||
@ -43,13 +45,15 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type conversationServer struct {
|
type conversationServer struct {
|
||||||
msgRpcClient *rpcclient.MessageRpcClient
|
pbconversation.UnimplementedConversationServer
|
||||||
user *rpcclient.UserRpcClient
|
|
||||||
groupRpcClient *rpcclient.GroupRpcClient
|
|
||||||
conversationDatabase controller.ConversationDatabase
|
conversationDatabase controller.ConversationDatabase
|
||||||
|
|
||||||
conversationNotificationSender *ConversationNotificationSender
|
conversationNotificationSender *ConversationNotificationSender
|
||||||
config *Config
|
config *Config
|
||||||
|
|
||||||
|
userClient *rpcli.UserClient
|
||||||
|
msgClient *rpcli.MsgClient
|
||||||
|
groupClient *rpcli.GroupClient
|
||||||
}
|
}
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
@ -75,17 +79,27 @@ func Start(ctx context.Context, config *Config, client discovery.SvcDiscoveryReg
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
groupRpcClient := rpcclient.NewGroupRpcClient(client, config.Share.RpcRegisterName.Group)
|
userConn, err := client.GetConn(ctx, config.Discovery.RpcService.User)
|
||||||
msgRpcClient := rpcclient.NewMessageRpcClient(client, config.Share.RpcRegisterName.Msg)
|
if err != nil {
|
||||||
userRpcClient := rpcclient.NewUserRpcClient(client, config.Share.RpcRegisterName.User, config.Share.IMAdminUserID)
|
return err
|
||||||
|
}
|
||||||
|
groupConn, err := client.GetConn(ctx, config.Discovery.RpcService.Group)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
msgConn, err := client.GetConn(ctx, config.Discovery.RpcService.Msg)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
msgClient := rpcli.NewMsgClient(msgConn)
|
||||||
localcache.InitLocalCache(&config.LocalCacheConfig)
|
localcache.InitLocalCache(&config.LocalCacheConfig)
|
||||||
pbconversation.RegisterConversationServer(server, &conversationServer{
|
pbconversation.RegisterConversationServer(server, &conversationServer{
|
||||||
msgRpcClient: &msgRpcClient,
|
conversationNotificationSender: NewConversationNotificationSender(&config.NotificationConfig, msgClient),
|
||||||
user: &userRpcClient,
|
|
||||||
conversationNotificationSender: NewConversationNotificationSender(&config.NotificationConfig, &msgRpcClient),
|
|
||||||
groupRpcClient: &groupRpcClient,
|
|
||||||
conversationDatabase: controller.NewConversationDatabase(conversationDB,
|
conversationDatabase: controller.NewConversationDatabase(conversationDB,
|
||||||
redis.NewConversationRedis(rdb, &config.LocalCacheConfig, redis.GetRocksCacheOptions(), conversationDB), mgocli.GetTx()),
|
redis.NewConversationRedis(rdb, &config.LocalCacheConfig, redis.GetRocksCacheOptions(), conversationDB), mgocli.GetTx()),
|
||||||
|
userClient: rpcli.NewUserClient(userConn),
|
||||||
|
groupClient: rpcli.NewGroupClient(groupConn),
|
||||||
|
msgClient: msgClient,
|
||||||
})
|
})
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -122,13 +136,12 @@ func (c *conversationServer) GetSortedConversationList(ctx context.Context, req
|
|||||||
if len(conversations) == 0 {
|
if len(conversations) == 0 {
|
||||||
return nil, errs.ErrRecordNotFound.Wrap()
|
return nil, errs.ErrRecordNotFound.Wrap()
|
||||||
}
|
}
|
||||||
|
maxSeqs, err := c.msgClient.GetMaxSeqs(ctx, conversationIDs)
|
||||||
maxSeqs, err := c.msgRpcClient.GetMaxSeqs(ctx, conversationIDs)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
chatLogs, err := c.msgRpcClient.GetMsgByConversationIDs(ctx, conversationIDs, maxSeqs)
|
chatLogs, err := c.msgClient.GetMsgByConversationIDs(ctx, conversationIDs, maxSeqs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -138,7 +151,7 @@ func (c *conversationServer) GetSortedConversationList(ctx context.Context, req
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
hasReadSeqs, err := c.msgRpcClient.GetHasReadSeqs(ctx, req.UserID, conversationIDs)
|
hasReadSeqs, err := c.msgClient.GetHasReadSeqs(ctx, conversationIDs, req.UserID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -225,12 +238,14 @@ func (c *conversationServer) SetConversations(ctx context.Context, req *pbconver
|
|||||||
if req.Conversation == nil {
|
if req.Conversation == nil {
|
||||||
return nil, errs.ErrArgs.WrapMsg("conversation must not be nil")
|
return nil, errs.ErrArgs.WrapMsg("conversation must not be nil")
|
||||||
}
|
}
|
||||||
|
|
||||||
if req.Conversation.ConversationType == constant.WriteGroupChatType {
|
if req.Conversation.ConversationType == constant.WriteGroupChatType {
|
||||||
groupInfo, err := c.groupRpcClient.GetGroupInfo(ctx, req.Conversation.GroupID)
|
groupInfo, err := c.groupClient.GetGroupInfo(ctx, req.Conversation.GroupID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
if groupInfo == nil {
|
||||||
|
return nil, servererrs.ErrGroupIDNotFound.WrapMsg(req.Conversation.GroupID)
|
||||||
|
}
|
||||||
if groupInfo.Status == constant.GroupStatusDismissed {
|
if groupInfo.Status == constant.GroupStatusDismissed {
|
||||||
return nil, servererrs.ErrDismissedAlready.WrapMsg("group dismissed")
|
return nil, servererrs.ErrDismissedAlready.WrapMsg("group dismissed")
|
||||||
}
|
}
|
||||||
@ -261,27 +276,35 @@ func (c *conversationServer) SetConversations(ctx context.Context, req *pbconver
|
|||||||
|
|
||||||
setConversationFieldsFunc := func() {
|
setConversationFieldsFunc := func() {
|
||||||
if req.Conversation.RecvMsgOpt != nil {
|
if req.Conversation.RecvMsgOpt != nil {
|
||||||
|
conversation.RecvMsgOpt = req.Conversation.RecvMsgOpt.Value
|
||||||
m["recv_msg_opt"] = req.Conversation.RecvMsgOpt.Value
|
m["recv_msg_opt"] = req.Conversation.RecvMsgOpt.Value
|
||||||
}
|
}
|
||||||
if req.Conversation.AttachedInfo != nil {
|
if req.Conversation.AttachedInfo != nil {
|
||||||
|
conversation.AttachedInfo = req.Conversation.AttachedInfo.Value
|
||||||
m["attached_info"] = req.Conversation.AttachedInfo.Value
|
m["attached_info"] = req.Conversation.AttachedInfo.Value
|
||||||
}
|
}
|
||||||
if req.Conversation.Ex != nil {
|
if req.Conversation.Ex != nil {
|
||||||
|
conversation.Ex = req.Conversation.Ex.Value
|
||||||
m["ex"] = req.Conversation.Ex.Value
|
m["ex"] = req.Conversation.Ex.Value
|
||||||
}
|
}
|
||||||
if req.Conversation.IsPinned != nil {
|
if req.Conversation.IsPinned != nil {
|
||||||
|
conversation.IsPinned = req.Conversation.IsPinned.Value
|
||||||
m["is_pinned"] = req.Conversation.IsPinned.Value
|
m["is_pinned"] = req.Conversation.IsPinned.Value
|
||||||
}
|
}
|
||||||
if req.Conversation.GroupAtType != nil {
|
if req.Conversation.GroupAtType != nil {
|
||||||
|
conversation.GroupAtType = req.Conversation.GroupAtType.Value
|
||||||
m["group_at_type"] = req.Conversation.GroupAtType.Value
|
m["group_at_type"] = req.Conversation.GroupAtType.Value
|
||||||
}
|
}
|
||||||
if req.Conversation.MsgDestructTime != nil {
|
if req.Conversation.MsgDestructTime != nil {
|
||||||
|
conversation.MsgDestructTime = req.Conversation.MsgDestructTime.Value
|
||||||
m["msg_destruct_time"] = req.Conversation.MsgDestructTime.Value
|
m["msg_destruct_time"] = req.Conversation.MsgDestructTime.Value
|
||||||
}
|
}
|
||||||
if req.Conversation.IsMsgDestruct != nil {
|
if req.Conversation.IsMsgDestruct != nil {
|
||||||
|
conversation.IsMsgDestruct = req.Conversation.IsMsgDestruct.Value
|
||||||
m["is_msg_destruct"] = req.Conversation.IsMsgDestruct.Value
|
m["is_msg_destruct"] = req.Conversation.IsMsgDestruct.Value
|
||||||
}
|
}
|
||||||
if req.Conversation.BurnDuration != nil {
|
if req.Conversation.BurnDuration != nil {
|
||||||
|
conversation.BurnDuration = req.Conversation.BurnDuration.Value
|
||||||
m["burn_duration"] = req.Conversation.BurnDuration.Value
|
m["burn_duration"] = req.Conversation.BurnDuration.Value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -343,7 +366,15 @@ func (c *conversationServer) SetConversations(ctx context.Context, req *pbconver
|
|||||||
needUpdateUsersList = append(needUpdateUsersList, userID)
|
needUpdateUsersList = append(needUpdateUsersList, userID)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if len(m) != 0 && len(needUpdateUsersList) != 0 {
|
||||||
|
if err := c.conversationDatabase.SetUsersConversationFieldTx(ctx, needUpdateUsersList, &conversation, m); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, v := range needUpdateUsersList {
|
||||||
|
c.conversationNotificationSender.ConversationChangeNotification(ctx, v, []string{req.Conversation.ConversationID})
|
||||||
|
}
|
||||||
|
}
|
||||||
if req.Conversation.IsPrivateChat != nil && req.Conversation.ConversationType != constant.ReadGroupChatType {
|
if req.Conversation.IsPrivateChat != nil && req.Conversation.ConversationType != constant.ReadGroupChatType {
|
||||||
var conversations []*dbModel.Conversation
|
var conversations []*dbModel.Conversation
|
||||||
for _, ownerUserID := range req.UserIDs {
|
for _, ownerUserID := range req.UserIDs {
|
||||||
@ -361,16 +392,6 @@ func (c *conversationServer) SetConversations(ctx context.Context, req *pbconver
|
|||||||
c.conversationNotificationSender.ConversationSetPrivateNotification(ctx, userID, req.Conversation.UserID,
|
c.conversationNotificationSender.ConversationSetPrivateNotification(ctx, userID, req.Conversation.UserID,
|
||||||
req.Conversation.IsPrivateChat.Value, req.Conversation.ConversationID)
|
req.Conversation.IsPrivateChat.Value, req.Conversation.ConversationID)
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
if len(m) != 0 && len(needUpdateUsersList) != 0 {
|
|
||||||
if err := c.conversationDatabase.SetUsersConversationFieldTx(ctx, needUpdateUsersList, &conversation, m); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, v := range needUpdateUsersList {
|
|
||||||
c.conversationNotificationSender.ConversationChangeNotification(ctx, v, []string{req.Conversation.ConversationID})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return &pbconversation.SetConversationsResp{}, nil
|
return &pbconversation.SetConversationsResp{}, nil
|
||||||
@ -424,22 +445,38 @@ func (c *conversationServer) CreateGroupChatConversations(ctx context.Context, r
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
conversationID := msgprocessor.GetConversationIDBySessionType(constant.ReadGroupChatType, req.GroupID)
|
||||||
|
if err := c.msgClient.SetUserConversationMaxSeq(ctx, conversationID, req.UserIDs, 0); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
return &pbconversation.CreateGroupChatConversationsResp{}, nil
|
return &pbconversation.CreateGroupChatConversationsResp{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *conversationServer) SetConversationMaxSeq(ctx context.Context, req *pbconversation.SetConversationMaxSeqReq) (*pbconversation.SetConversationMaxSeqResp, error) {
|
func (c *conversationServer) SetConversationMaxSeq(ctx context.Context, req *pbconversation.SetConversationMaxSeqReq) (*pbconversation.SetConversationMaxSeqResp, error) {
|
||||||
|
if err := c.msgClient.SetUserConversationMaxSeq(ctx, req.ConversationID, req.OwnerUserID, req.MaxSeq); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
if err := c.conversationDatabase.UpdateUsersConversationField(ctx, req.OwnerUserID, req.ConversationID,
|
if err := c.conversationDatabase.UpdateUsersConversationField(ctx, req.OwnerUserID, req.ConversationID,
|
||||||
map[string]any{"max_seq": req.MaxSeq}); err != nil {
|
map[string]any{"max_seq": req.MaxSeq}); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
for _, userID := range req.OwnerUserID {
|
||||||
|
c.conversationNotificationSender.ConversationChangeNotification(ctx, userID, []string{req.ConversationID})
|
||||||
|
}
|
||||||
return &pbconversation.SetConversationMaxSeqResp{}, nil
|
return &pbconversation.SetConversationMaxSeqResp{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *conversationServer) SetConversationMinSeq(ctx context.Context, req *pbconversation.SetConversationMinSeqReq) (*pbconversation.SetConversationMinSeqResp, error) {
|
func (c *conversationServer) SetConversationMinSeq(ctx context.Context, req *pbconversation.SetConversationMinSeqReq) (*pbconversation.SetConversationMinSeqResp, error) {
|
||||||
|
if err := c.msgClient.SetUserConversationMin(ctx, req.ConversationID, req.OwnerUserID, req.MinSeq); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
if err := c.conversationDatabase.UpdateUsersConversationField(ctx, req.OwnerUserID, req.ConversationID,
|
if err := c.conversationDatabase.UpdateUsersConversationField(ctx, req.OwnerUserID, req.ConversationID,
|
||||||
map[string]any{"min_seq": req.MinSeq}); err != nil {
|
map[string]any{"min_seq": req.MinSeq}); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
for _, userID := range req.OwnerUserID {
|
||||||
|
c.conversationNotificationSender.ConversationChangeNotification(ctx, userID, []string{req.ConversationID})
|
||||||
|
}
|
||||||
return &pbconversation.SetConversationMinSeqResp{}, nil
|
return &pbconversation.SetConversationMinSeqResp{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -540,7 +577,7 @@ func (c *conversationServer) getConversationInfo(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(sendIDs) != 0 {
|
if len(sendIDs) != 0 {
|
||||||
sendInfos, err := c.user.GetUsersInfo(ctx, sendIDs)
|
sendInfos, err := c.userClient.GetUsersInfo(ctx, sendIDs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -549,7 +586,7 @@ func (c *conversationServer) getConversationInfo(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(groupIDs) != 0 {
|
if len(groupIDs) != 0 {
|
||||||
groupInfos, err := c.groupRpcClient.GetGroupInfos(ctx, groupIDs, false)
|
groupInfos, err := c.groupClient.GetGroupsInfo(ctx, groupIDs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -661,7 +698,7 @@ func (c *conversationServer) GetOwnerConversation(ctx context.Context, req *pbco
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *conversationServer) GetConversationsNeedDestructMsgs(ctx context.Context, _ *pbconversation.GetConversationsNeedDestructMsgsReq) (*pbconversation.GetConversationsNeedDestructMsgsResp, error) {
|
func (c *conversationServer) GetConversationsNeedClearMsg(ctx context.Context, _ *pbconversation.GetConversationsNeedClearMsgReq) (*pbconversation.GetConversationsNeedClearMsgResp, error) {
|
||||||
num, err := c.conversationDatabase.GetAllConversationIDsNumber(ctx)
|
num, err := c.conversationDatabase.GetAllConversationIDsNumber(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.ZError(ctx, "GetAllConversationIDsNumber failed", err)
|
log.ZError(ctx, "GetAllConversationIDsNumber failed", err)
|
||||||
@ -685,7 +722,7 @@ func (c *conversationServer) GetConversationsNeedDestructMsgs(ctx context.Contex
|
|||||||
|
|
||||||
conversationIDs, err := c.conversationDatabase.PageConversationIDs(ctx, pagination)
|
conversationIDs, err := c.conversationDatabase.PageConversationIDs(ctx, pagination)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// log.ZError(ctx, "PageConversationIDs failed", err, "pageNumber", pageNumber)
|
log.ZError(ctx, "PageConversationIDs failed", err, "pageNumber", pageNumber)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -708,7 +745,7 @@ func (c *conversationServer) GetConversationsNeedDestructMsgs(ctx context.Contex
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return &pbconversation.GetConversationsNeedDestructMsgsResp{Conversations: convert.ConversationsDB2Pb(temp)}, nil
|
return &pbconversation.GetConversationsNeedClearMsgResp{Conversations: convert.ConversationsDB2Pb(temp)}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *conversationServer) GetNotNotifyConversationIDs(ctx context.Context, req *pbconversation.GetNotNotifyConversationIDsReq) (*pbconversation.GetNotNotifyConversationIDsResp, error) {
|
func (c *conversationServer) GetNotNotifyConversationIDs(ctx context.Context, req *pbconversation.GetNotNotifyConversationIDsReq) (*pbconversation.GetNotNotifyConversationIDsResp, error) {
|
||||||
@ -726,3 +763,51 @@ func (c *conversationServer) GetPinnedConversationIDs(ctx context.Context, req *
|
|||||||
}
|
}
|
||||||
return &pbconversation.GetPinnedConversationIDsResp{ConversationIDs: conversationIDs}, nil
|
return &pbconversation.GetPinnedConversationIDsResp{ConversationIDs: conversationIDs}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *conversationServer) ClearUserConversationMsg(ctx context.Context, req *pbconversation.ClearUserConversationMsgReq) (*pbconversation.ClearUserConversationMsgResp, error) {
|
||||||
|
conversations, err := c.conversationDatabase.FindRandConversation(ctx, req.Timestamp, int(req.Limit))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
latestMsgDestructTime := time.UnixMilli(req.Timestamp)
|
||||||
|
for i, conversation := range conversations {
|
||||||
|
if conversation.IsMsgDestruct == false || conversation.MsgDestructTime == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
seq, err := c.msgClient.GetLastMessageSeqByTime(ctx, conversation.ConversationID, req.Timestamp-(conversation.MsgDestructTime*1000))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if seq <= 0 {
|
||||||
|
log.ZDebug(ctx, "ClearUserConversationMsg GetLastMessageSeqByTime seq <= 0", "index", i, "conversationID", conversation.ConversationID, "ownerUserID", conversation.OwnerUserID, "msgDestructTime", conversation.MsgDestructTime, "seq", seq)
|
||||||
|
if err := c.setConversationMinSeqAndLatestMsgDestructTime(ctx, conversation.ConversationID, conversation.OwnerUserID, -1, latestMsgDestructTime); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
seq++
|
||||||
|
if err := c.setConversationMinSeqAndLatestMsgDestructTime(ctx, conversation.ConversationID, conversation.OwnerUserID, seq, latestMsgDestructTime); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
log.ZDebug(ctx, "ClearUserConversationMsg set min seq", "index", i, "conversationID", conversation.ConversationID, "ownerUserID", conversation.OwnerUserID, "seq", seq, "msgDestructTime", conversation.MsgDestructTime)
|
||||||
|
}
|
||||||
|
return &pbconversation.ClearUserConversationMsgResp{Count: int32(len(conversations))}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *conversationServer) setConversationMinSeqAndLatestMsgDestructTime(ctx context.Context, conversationID string, ownerUserID string, minSeq int64, latestMsgDestructTime time.Time) error {
|
||||||
|
update := map[string]any{
|
||||||
|
"latest_msg_destruct_time": latestMsgDestructTime,
|
||||||
|
}
|
||||||
|
if minSeq >= 0 {
|
||||||
|
if err := c.msgClient.SetUserConversationMin(ctx, conversationID, []string{ownerUserID}, minSeq); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
update["min_seq"] = minSeq
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := c.conversationDatabase.UpdateUsersConversationField(ctx, []string{ownerUserID}, conversationID, update); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
c.conversationNotificationSender.ConversationChangeNotification(ctx, ownerUserID, []string{conversationID})
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
@ -16,9 +16,11 @@ package conversation
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"github.com/openimsdk/open-im-server/v3/pkg/rpcli"
|
||||||
|
"github.com/openimsdk/protocol/msg"
|
||||||
|
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
|
"github.com/openimsdk/open-im-server/v3/pkg/notification"
|
||||||
"github.com/openimsdk/protocol/constant"
|
"github.com/openimsdk/protocol/constant"
|
||||||
"github.com/openimsdk/protocol/sdkws"
|
"github.com/openimsdk/protocol/sdkws"
|
||||||
)
|
)
|
||||||
@ -27,8 +29,10 @@ type ConversationNotificationSender struct {
|
|||||||
*rpcclient.NotificationSender
|
*rpcclient.NotificationSender
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewConversationNotificationSender(conf *config.Notification, msgRpcClient *rpcclient.MessageRpcClient) *ConversationNotificationSender {
|
func NewConversationNotificationSender(conf *config.Notification, msgClient *rpcli.MsgClient) *ConversationNotificationSender {
|
||||||
return &ConversationNotificationSender{rpcclient.NewNotificationSender(conf, rpcclient.WithRpcClient(msgRpcClient))}
|
return &ConversationNotificationSender{rpcclient.NewNotificationSender(conf, rpcclient.WithRpcClient(func(ctx context.Context, req *msg.SendMsgReq) (*msg.SendMsgResp, error) {
|
||||||
|
return msgClient.SendMsg(ctx, req)
|
||||||
|
}))}
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetPrivate invote.
|
// SetPrivate invote.
|
||||||
|
@ -110,7 +110,7 @@ func UpdateGroupMemberMap(req *pbgroup.SetGroupMemberInfo) map[string]any {
|
|||||||
m["nickname"] = req.Nickname.Value
|
m["nickname"] = req.Nickname.Value
|
||||||
}
|
}
|
||||||
if req.FaceURL != nil {
|
if req.FaceURL != nil {
|
||||||
m["user_group_face_url"] = req.FaceURL.Value
|
m["face_url"] = req.FaceURL.Value
|
||||||
}
|
}
|
||||||
if req.RoleLevel != nil {
|
if req.RoleLevel != nil {
|
||||||
m["role_level"] = req.RoleLevel.Value
|
m["role_level"] = req.RoleLevel.Value
|
||||||
|
@ -17,30 +17,28 @@ package group
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/openimsdk/open-im-server/v3/pkg/rpcli"
|
||||||
"math/big"
|
"math/big"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/openimsdk/open-im-server/v3/pkg/authverify"
|
||||||
|
"github.com/openimsdk/open-im-server/v3/pkg/callbackstruct"
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
||||||
|
"github.com/openimsdk/open-im-server/v3/pkg/common/convert"
|
||||||
|
"github.com/openimsdk/open-im-server/v3/pkg/common/servererrs"
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/common/storage/common"
|
"github.com/openimsdk/open-im-server/v3/pkg/common/storage/common"
|
||||||
|
"github.com/openimsdk/open-im-server/v3/pkg/common/storage/controller"
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/common/storage/database/mgo"
|
"github.com/openimsdk/open-im-server/v3/pkg/common/storage/database/mgo"
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/common/storage/model"
|
"github.com/openimsdk/open-im-server/v3/pkg/common/storage/model"
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/common/webhook"
|
"github.com/openimsdk/open-im-server/v3/pkg/common/webhook"
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/localcache"
|
"github.com/openimsdk/open-im-server/v3/pkg/localcache"
|
||||||
|
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/authverify"
|
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/callbackstruct"
|
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/common/convert"
|
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/common/servererrs"
|
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/common/storage/controller"
|
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/msgprocessor"
|
"github.com/openimsdk/open-im-server/v3/pkg/msgprocessor"
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
|
"github.com/openimsdk/open-im-server/v3/pkg/notification/grouphash"
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient/grouphash"
|
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient/notification"
|
|
||||||
"github.com/openimsdk/protocol/constant"
|
"github.com/openimsdk/protocol/constant"
|
||||||
pbconversation "github.com/openimsdk/protocol/conversation"
|
pbconv "github.com/openimsdk/protocol/conversation"
|
||||||
pbgroup "github.com/openimsdk/protocol/group"
|
pbgroup "github.com/openimsdk/protocol/group"
|
||||||
"github.com/openimsdk/protocol/sdkws"
|
"github.com/openimsdk/protocol/sdkws"
|
||||||
"github.com/openimsdk/protocol/wrapperspb"
|
"github.com/openimsdk/protocol/wrapperspb"
|
||||||
@ -57,13 +55,14 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type groupServer struct {
|
type groupServer struct {
|
||||||
db controller.GroupDatabase
|
pbgroup.UnimplementedGroupServer
|
||||||
user rpcclient.UserRpcClient
|
db controller.GroupDatabase
|
||||||
notification *GroupNotificationSender
|
notification *NotificationSender
|
||||||
conversationRpcClient rpcclient.ConversationRpcClient
|
config *Config
|
||||||
msgRpcClient rpcclient.MessageRpcClient
|
webhookClient *webhook.Client
|
||||||
config *Config
|
userClient *rpcli.UserClient
|
||||||
webhookClient *webhook.Client
|
msgClient *rpcli.MsgClient
|
||||||
|
conversationClient *rpcli.ConversationClient
|
||||||
}
|
}
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
@ -98,32 +97,33 @@ func Start(ctx context.Context, config *Config, client discovery.SvcDiscoveryReg
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
userRpcClient := rpcclient.NewUserRpcClient(client, config.Share.RpcRegisterName.User, config.Share.IMAdminUserID)
|
|
||||||
msgRpcClient := rpcclient.NewMessageRpcClient(client, config.Share.RpcRegisterName.Msg)
|
//userRpcClient := rpcclient.NewUserRpcClient(client, config.Share.RpcRegisterName.User, config.Share.IMAdminUserID)
|
||||||
conversationRpcClient := rpcclient.NewConversationRpcClient(client, config.Share.RpcRegisterName.Conversation)
|
//msgRpcClient := rpcclient.NewMessageRpcClient(client, config.Share.RpcRegisterName.Msg)
|
||||||
var gs groupServer
|
//conversationRpcClient := rpcclient.NewConversationRpcClient(client, config.Share.RpcRegisterName.Conversation)
|
||||||
database := controller.NewGroupDatabase(rdb, &config.LocalCacheConfig, groupDB, groupMemberDB, groupRequestDB, mgocli.GetTx(), grouphash.NewGroupHashFromGroupServer(&gs))
|
|
||||||
gs.db = database
|
userConn, err := client.GetConn(ctx, config.Discovery.RpcService.User)
|
||||||
gs.user = userRpcClient
|
if err != nil {
|
||||||
gs.notification = NewGroupNotificationSender(
|
return err
|
||||||
database,
|
}
|
||||||
&msgRpcClient,
|
msgConn, err := client.GetConn(ctx, config.Discovery.RpcService.Msg)
|
||||||
&userRpcClient,
|
if err != nil {
|
||||||
&conversationRpcClient,
|
return err
|
||||||
config,
|
}
|
||||||
func(ctx context.Context, userIDs []string) ([]notification.CommonUser, error) {
|
conversationConn, err := client.GetConn(ctx, config.Discovery.RpcService.Conversation)
|
||||||
users, err := userRpcClient.GetUsersInfo(ctx, userIDs)
|
if err != nil {
|
||||||
if err != nil {
|
return err
|
||||||
return nil, err
|
}
|
||||||
}
|
gs := groupServer{
|
||||||
return datautil.Slice(users, func(e *sdkws.UserInfo) notification.CommonUser { return e }), nil
|
config: config,
|
||||||
},
|
webhookClient: webhook.NewWebhookClient(config.WebhooksConfig.URL),
|
||||||
)
|
userClient: rpcli.NewUserClient(userConn),
|
||||||
|
msgClient: rpcli.NewMsgClient(msgConn),
|
||||||
|
conversationClient: rpcli.NewConversationClient(conversationConn),
|
||||||
|
}
|
||||||
|
gs.db = controller.NewGroupDatabase(rdb, &config.LocalCacheConfig, groupDB, groupMemberDB, groupRequestDB, mgocli.GetTx(), grouphash.NewGroupHashFromGroupServer(&gs))
|
||||||
|
gs.notification = NewNotificationSender(gs.db, config, gs.userClient, gs.msgClient, gs.conversationClient)
|
||||||
localcache.InitLocalCache(&config.LocalCacheConfig)
|
localcache.InitLocalCache(&config.LocalCacheConfig)
|
||||||
gs.conversationRpcClient = conversationRpcClient
|
|
||||||
gs.msgRpcClient = msgRpcClient
|
|
||||||
gs.config = config
|
|
||||||
gs.webhookClient = webhook.NewWebhookClient(config.WebhooksConfig.URL)
|
|
||||||
pbgroup.RegisterGroupServer(server, &gs)
|
pbgroup.RegisterGroupServer(server, &gs)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -167,19 +167,6 @@ func (g *groupServer) CheckGroupAdmin(ctx context.Context, groupID string) error
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *groupServer) GetPublicUserInfoMap(ctx context.Context, userIDs []string) (map[string]*sdkws.PublicUserInfo, error) {
|
|
||||||
if len(userIDs) == 0 {
|
|
||||||
return map[string]*sdkws.PublicUserInfo{}, nil
|
|
||||||
}
|
|
||||||
users, err := g.user.GetPublicUserInfos(ctx, userIDs)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return datautil.SliceToMapAny(users, func(e *sdkws.PublicUserInfo) (string, *sdkws.PublicUserInfo) {
|
|
||||||
return e.UserID, e
|
|
||||||
}), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (g *groupServer) IsNotFound(err error) bool {
|
func (g *groupServer) IsNotFound(err error) bool {
|
||||||
return errs.ErrRecordNotFound.Is(specialerror.ErrCode(errs.Unwrap(err)))
|
return errs.ErrRecordNotFound.Is(specialerror.ErrCode(errs.Unwrap(err)))
|
||||||
}
|
}
|
||||||
@ -221,7 +208,6 @@ func (g *groupServer) CreateGroup(ctx context.Context, req *pbgroup.CreateGroupR
|
|||||||
return nil, errs.ErrArgs.WrapMsg("no group owner")
|
return nil, errs.ErrArgs.WrapMsg("no group owner")
|
||||||
}
|
}
|
||||||
if err := authverify.CheckAccessV3(ctx, req.OwnerUserID, g.config.Share.IMAdminUserID); err != nil {
|
if err := authverify.CheckAccessV3(ctx, req.OwnerUserID, g.config.Share.IMAdminUserID); err != nil {
|
||||||
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
userIDs := append(append(req.MemberUserIDs, req.AdminUserIDs...), req.OwnerUserID)
|
userIDs := append(append(req.MemberUserIDs, req.AdminUserIDs...), req.OwnerUserID)
|
||||||
@ -234,7 +220,7 @@ func (g *groupServer) CreateGroup(ctx context.Context, req *pbgroup.CreateGroupR
|
|||||||
return nil, errs.ErrArgs.WrapMsg("group member repeated")
|
return nil, errs.ErrArgs.WrapMsg("group member repeated")
|
||||||
}
|
}
|
||||||
|
|
||||||
userMap, err := g.user.GetUsersInfoMap(ctx, userIDs)
|
userMap, err := g.userClient.GetUsersInfoMap(ctx, userIDs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -385,7 +371,7 @@ func (g *groupServer) InviteUserToGroup(ctx context.Context, req *pbgroup.Invite
|
|||||||
return nil, servererrs.ErrDismissedAlready.WrapMsg("group dismissed checking group status found it dismissed")
|
return nil, servererrs.ErrDismissedAlready.WrapMsg("group dismissed checking group status found it dismissed")
|
||||||
}
|
}
|
||||||
|
|
||||||
userMap, err := g.user.GetUsersInfoMap(ctx, req.InvitedUserIDs)
|
userMap, err := g.userClient.GetUsersInfoMap(ctx, req.InvitedUserIDs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -465,7 +451,7 @@ func (g *groupServer) InviteUserToGroup(ctx context.Context, req *pbgroup.Invite
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = g.notification.MemberEnterNotification(ctx, req.GroupID, req.InvitedUserIDs...); err != nil {
|
if err = g.notification.GroupApplicationAgreeMemberEnterNotification(ctx, req.GroupID, opUserID, req.InvitedUserIDs...); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &pbgroup.InviteUserToGroupResp{}, nil
|
return &pbgroup.InviteUserToGroupResp{}, nil
|
||||||
@ -696,7 +682,7 @@ func (g *groupServer) GetGroupApplicationList(ctx context.Context, req *pbgroup.
|
|||||||
userIDs = append(userIDs, gr.UserID)
|
userIDs = append(userIDs, gr.UserID)
|
||||||
}
|
}
|
||||||
userIDs = datautil.Distinct(userIDs)
|
userIDs = datautil.Distinct(userIDs)
|
||||||
userMap, err := g.user.GetPublicUserInfoMap(ctx, userIDs)
|
userMap, err := g.userClient.GetUsersInfoMap(ctx, userIDs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -808,7 +794,7 @@ func (g *groupServer) GroupApplicationResponse(ctx context.Context, req *pbgroup
|
|||||||
} else if !g.IsNotFound(err) {
|
} else if !g.IsNotFound(err) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if _, err := g.user.GetPublicUserInfo(ctx, req.FromUserID); err != nil {
|
if err := g.userClient.CheckUser(ctx, []string{req.FromUserID}); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
var member *model.GroupMember
|
var member *model.GroupMember
|
||||||
@ -852,7 +838,7 @@ func (g *groupServer) GroupApplicationResponse(ctx context.Context, req *pbgroup
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (g *groupServer) JoinGroup(ctx context.Context, req *pbgroup.JoinGroupReq) (*pbgroup.JoinGroupResp, error) {
|
func (g *groupServer) JoinGroup(ctx context.Context, req *pbgroup.JoinGroupReq) (*pbgroup.JoinGroupResp, error) {
|
||||||
user, err := g.user.GetUserInfo(ctx, req.InviterUserID)
|
user, err := g.userClient.GetUserInfo(ctx, req.InviterUserID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -958,12 +944,12 @@ func (g *groupServer) QuitGroup(ctx context.Context, req *pbgroup.QuitGroupReq)
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (g *groupServer) deleteMemberAndSetConversationSeq(ctx context.Context, groupID string, userIDs []string) error {
|
func (g *groupServer) deleteMemberAndSetConversationSeq(ctx context.Context, groupID string, userIDs []string) error {
|
||||||
conevrsationID := msgprocessor.GetConversationIDBySessionType(constant.ReadGroupChatType, groupID)
|
conversationID := msgprocessor.GetConversationIDBySessionType(constant.ReadGroupChatType, groupID)
|
||||||
maxSeq, err := g.msgRpcClient.GetConversationMaxSeq(ctx, conevrsationID)
|
maxSeq, err := g.msgClient.GetConversationMaxSeq(ctx, conversationID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return g.conversationRpcClient.SetConversationMaxSeq(ctx, userIDs, conevrsationID, maxSeq)
|
return g.conversationClient.SetConversationMaxSeq(ctx, conversationID, userIDs, maxSeq)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *groupServer) SetGroupInfo(ctx context.Context, req *pbgroup.SetGroupInfoReq) (*pbgroup.SetGroupInfoResp, error) {
|
func (g *groupServer) SetGroupInfo(ctx context.Context, req *pbgroup.SetGroupInfoReq) (*pbgroup.SetGroupInfoResp, error) {
|
||||||
@ -1026,9 +1012,9 @@ func (g *groupServer) SetGroupInfo(ctx context.Context, req *pbgroup.SetGroupInf
|
|||||||
}
|
}
|
||||||
num := len(update)
|
num := len(update)
|
||||||
if req.GroupInfoForSet.Notification != "" {
|
if req.GroupInfoForSet.Notification != "" {
|
||||||
num--
|
num -= 3
|
||||||
func() {
|
func() {
|
||||||
conversation := &pbconversation.ConversationReq{
|
conversation := &pbconv.ConversationReq{
|
||||||
ConversationID: msgprocessor.GetConversationIDBySessionType(constant.ReadGroupChatType, req.GroupInfoForSet.GroupID),
|
ConversationID: msgprocessor.GetConversationIDBySessionType(constant.ReadGroupChatType, req.GroupInfoForSet.GroupID),
|
||||||
ConversationType: constant.ReadGroupChatType,
|
ConversationType: constant.ReadGroupChatType,
|
||||||
GroupID: req.GroupInfoForSet.GroupID,
|
GroupID: req.GroupInfoForSet.GroupID,
|
||||||
@ -1039,7 +1025,7 @@ func (g *groupServer) SetGroupInfo(ctx context.Context, req *pbgroup.SetGroupInf
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
conversation.GroupAtType = &wrapperspb.Int32Value{Value: constant.GroupNotification}
|
conversation.GroupAtType = &wrapperspb.Int32Value{Value: constant.GroupNotification}
|
||||||
if err := g.conversationRpcClient.SetConversations(ctx, resp.UserIDs, conversation); err != nil {
|
if err := g.conversationClient.SetConversations(ctx, resp.UserIDs, conversation); err != nil {
|
||||||
log.ZWarn(ctx, "SetConversations", err, "UserIDs", resp.UserIDs, "conversation", conversation)
|
log.ZWarn(ctx, "SetConversations", err, "UserIDs", resp.UserIDs, "conversation", conversation)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
@ -1133,12 +1119,13 @@ func (g *groupServer) SetGroupInfoEx(ctx context.Context, req *pbgroup.SetGroupI
|
|||||||
}
|
}
|
||||||
|
|
||||||
num := len(updatedData)
|
num := len(updatedData)
|
||||||
|
|
||||||
if req.Notification != nil {
|
if req.Notification != nil {
|
||||||
num--
|
num -= 3
|
||||||
|
|
||||||
if req.Notification.Value != "" {
|
if req.Notification.Value != "" {
|
||||||
func() {
|
func() {
|
||||||
conversation := &pbconversation.ConversationReq{
|
conversation := &pbconv.ConversationReq{
|
||||||
ConversationID: msgprocessor.GetConversationIDBySessionType(constant.ReadGroupChatType, req.GroupID),
|
ConversationID: msgprocessor.GetConversationIDBySessionType(constant.ReadGroupChatType, req.GroupID),
|
||||||
ConversationType: constant.ReadGroupChatType,
|
ConversationType: constant.ReadGroupChatType,
|
||||||
GroupID: req.GroupID,
|
GroupID: req.GroupID,
|
||||||
@ -1151,8 +1138,7 @@ func (g *groupServer) SetGroupInfoEx(ctx context.Context, req *pbgroup.SetGroupI
|
|||||||
}
|
}
|
||||||
|
|
||||||
conversation.GroupAtType = &wrapperspb.Int32Value{Value: constant.GroupNotification}
|
conversation.GroupAtType = &wrapperspb.Int32Value{Value: constant.GroupNotification}
|
||||||
|
if err := g.conversationClient.SetConversations(ctx, resp.UserIDs, conversation); err != nil {
|
||||||
if err := g.conversationRpcClient.SetConversations(ctx, resp.UserIDs, conversation); err != nil {
|
|
||||||
log.ZWarn(ctx, "SetConversations", err, "UserIDs", resp.UserIDs, "conversation", conversation)
|
log.ZWarn(ctx, "SetConversations", err, "UserIDs", resp.UserIDs, "conversation", conversation)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
@ -1180,36 +1166,53 @@ func (g *groupServer) TransferGroupOwner(ctx context.Context, req *pbgroup.Trans
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if group.Status == constant.GroupStatusDismissed {
|
if group.Status == constant.GroupStatusDismissed {
|
||||||
return nil, servererrs.ErrDismissedAlready.Wrap()
|
return nil, servererrs.ErrDismissedAlready.Wrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
if req.OldOwnerUserID == req.NewOwnerUserID {
|
if req.OldOwnerUserID == req.NewOwnerUserID {
|
||||||
return nil, errs.ErrArgs.WrapMsg("OldOwnerUserID == NewOwnerUserID")
|
return nil, errs.ErrArgs.WrapMsg("OldOwnerUserID == NewOwnerUserID")
|
||||||
}
|
}
|
||||||
|
|
||||||
members, err := g.db.FindGroupMembers(ctx, req.GroupID, []string{req.OldOwnerUserID, req.NewOwnerUserID})
|
members, err := g.db.FindGroupMembers(ctx, req.GroupID, []string{req.OldOwnerUserID, req.NewOwnerUserID})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := g.PopulateGroupMember(ctx, members...); err != nil {
|
if err := g.PopulateGroupMember(ctx, members...); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
memberMap := datautil.SliceToMap(members, func(e *model.GroupMember) string { return e.UserID })
|
memberMap := datautil.SliceToMap(members, func(e *model.GroupMember) string { return e.UserID })
|
||||||
if ids := datautil.Single([]string{req.OldOwnerUserID, req.NewOwnerUserID}, datautil.Keys(memberMap)); len(ids) > 0 {
|
if ids := datautil.Single([]string{req.OldOwnerUserID, req.NewOwnerUserID}, datautil.Keys(memberMap)); len(ids) > 0 {
|
||||||
return nil, errs.ErrArgs.WrapMsg("user not in group " + strings.Join(ids, ","))
|
return nil, errs.ErrArgs.WrapMsg("user not in group " + strings.Join(ids, ","))
|
||||||
}
|
}
|
||||||
|
|
||||||
oldOwner := memberMap[req.OldOwnerUserID]
|
oldOwner := memberMap[req.OldOwnerUserID]
|
||||||
if oldOwner == nil {
|
if oldOwner == nil {
|
||||||
return nil, errs.ErrArgs.WrapMsg("OldOwnerUserID not in group " + req.NewOwnerUserID)
|
return nil, errs.ErrArgs.WrapMsg("OldOwnerUserID not in group " + req.NewOwnerUserID)
|
||||||
}
|
}
|
||||||
|
|
||||||
newOwner := memberMap[req.NewOwnerUserID]
|
newOwner := memberMap[req.NewOwnerUserID]
|
||||||
if newOwner == nil {
|
if newOwner == nil {
|
||||||
return nil, errs.ErrArgs.WrapMsg("NewOwnerUser not in group " + req.NewOwnerUserID)
|
return nil, errs.ErrArgs.WrapMsg("NewOwnerUser not in group " + req.NewOwnerUserID)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !authverify.IsAppManagerUid(ctx, g.config.Share.IMAdminUserID) {
|
if !authverify.IsAppManagerUid(ctx, g.config.Share.IMAdminUserID) {
|
||||||
if !(mcontext.GetOpUserID(ctx) == oldOwner.UserID && oldOwner.RoleLevel == constant.GroupOwner) {
|
if !(mcontext.GetOpUserID(ctx) == oldOwner.UserID && oldOwner.RoleLevel == constant.GroupOwner) {
|
||||||
return nil, errs.ErrNoPermission.WrapMsg("no permission transfer group owner")
|
return nil, errs.ErrNoPermission.WrapMsg("no permission transfer group owner")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if newOwner.MuteEndTime.After(time.Now()) {
|
||||||
|
if _, err := g.CancelMuteGroupMember(ctx, &pbgroup.CancelMuteGroupMemberReq{
|
||||||
|
GroupID: group.GroupID,
|
||||||
|
UserID: req.NewOwnerUserID}); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if err := g.db.TransferGroupOwner(ctx, req.GroupID, req.OldOwnerUserID, req.NewOwnerUserID, newOwner.RoleLevel); err != nil {
|
if err := g.db.TransferGroupOwner(ctx, req.GroupID, req.OldOwnerUserID, req.NewOwnerUserID, newOwner.RoleLevel); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -1217,6 +1220,7 @@ func (g *groupServer) TransferGroupOwner(ctx context.Context, req *pbgroup.Trans
|
|||||||
g.webhookAfterTransferGroupOwner(ctx, &g.config.WebhooksConfig.AfterTransferGroupOwner, req)
|
g.webhookAfterTransferGroupOwner(ctx, &g.config.WebhooksConfig.AfterTransferGroupOwner, req)
|
||||||
|
|
||||||
g.notification.GroupOwnerTransferredNotification(ctx, req)
|
g.notification.GroupOwnerTransferredNotification(ctx, req)
|
||||||
|
|
||||||
return &pbgroup.TransferGroupOwnerResp{}, nil
|
return &pbgroup.TransferGroupOwnerResp{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1286,7 +1290,7 @@ func (g *groupServer) GetGroupMembersCMS(ctx context.Context, req *pbgroup.GetGr
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (g *groupServer) GetUserReqApplicationList(ctx context.Context, req *pbgroup.GetUserReqApplicationListReq) (*pbgroup.GetUserReqApplicationListResp, error) {
|
func (g *groupServer) GetUserReqApplicationList(ctx context.Context, req *pbgroup.GetUserReqApplicationListReq) (*pbgroup.GetUserReqApplicationListResp, error) {
|
||||||
user, err := g.user.GetPublicUserInfo(ctx, req.UserID)
|
user, err := g.userClient.GetUserInfo(ctx, req.UserID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -1425,32 +1429,38 @@ func (g *groupServer) CancelMuteGroupMember(ctx context.Context, req *pbgroup.Ca
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := g.PopulateGroupMember(ctx, member); err != nil {
|
if err := g.PopulateGroupMember(ctx, member); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if !authverify.IsAppManagerUid(ctx, g.config.Share.IMAdminUserID) {
|
if !authverify.IsAppManagerUid(ctx, g.config.Share.IMAdminUserID) {
|
||||||
opMember, err := g.db.TakeGroupMember(ctx, req.GroupID, mcontext.GetOpUserID(ctx))
|
opMember, err := g.db.TakeGroupMember(ctx, req.GroupID, mcontext.GetOpUserID(ctx))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
switch member.RoleLevel {
|
switch member.RoleLevel {
|
||||||
case constant.GroupOwner:
|
case constant.GroupOwner:
|
||||||
return nil, errs.ErrNoPermission.WrapMsg("set group owner mute")
|
return nil, errs.ErrNoPermission.WrapMsg("Can not set group owner unmute")
|
||||||
case constant.GroupAdmin:
|
case constant.GroupAdmin:
|
||||||
if opMember.RoleLevel != constant.GroupOwner {
|
if opMember.RoleLevel != constant.GroupOwner {
|
||||||
return nil, errs.ErrNoPermission.WrapMsg("set group admin mute")
|
return nil, errs.ErrNoPermission.WrapMsg("Can not set group admin unmute")
|
||||||
}
|
}
|
||||||
case constant.GroupOrdinaryUsers:
|
case constant.GroupOrdinaryUsers:
|
||||||
if !(opMember.RoleLevel == constant.GroupAdmin || opMember.RoleLevel == constant.GroupOwner) {
|
if !(opMember.RoleLevel == constant.GroupAdmin || opMember.RoleLevel == constant.GroupOwner) {
|
||||||
return nil, errs.ErrNoPermission.WrapMsg("set group ordinary users mute")
|
return nil, errs.ErrNoPermission.WrapMsg("Can not set group ordinary users unmute")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
data := UpdateGroupMemberMutedTimeMap(time.Unix(0, 0))
|
data := UpdateGroupMemberMutedTimeMap(time.Unix(0, 0))
|
||||||
if err := g.db.UpdateGroupMember(ctx, member.GroupID, member.UserID, data); err != nil {
|
if err := g.db.UpdateGroupMember(ctx, member.GroupID, member.UserID, data); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
g.notification.GroupMemberCancelMutedNotification(ctx, req.GroupID, req.UserID)
|
g.notification.GroupMemberCancelMutedNotification(ctx, req.GroupID, req.UserID)
|
||||||
|
|
||||||
return &pbgroup.CancelMuteGroupMemberResp{}, nil
|
return &pbgroup.CancelMuteGroupMemberResp{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1485,9 +1495,6 @@ func (g *groupServer) SetGroupMemberInfo(ctx context.Context, req *pbgroup.SetGr
|
|||||||
return nil, errs.ErrNoPermission.WrapMsg("no op user id")
|
return nil, errs.ErrNoPermission.WrapMsg("no op user id")
|
||||||
}
|
}
|
||||||
isAppManagerUid := authverify.IsAppManagerUid(ctx, g.config.Share.IMAdminUserID)
|
isAppManagerUid := authverify.IsAppManagerUid(ctx, g.config.Share.IMAdminUserID)
|
||||||
for i := range req.Members {
|
|
||||||
req.Members[i].FaceURL = nil
|
|
||||||
}
|
|
||||||
groupMembers := make(map[string][]*pbgroup.SetGroupMemberInfo)
|
groupMembers := make(map[string][]*pbgroup.SetGroupMemberInfo)
|
||||||
for i, member := range req.Members {
|
for i, member := range req.Members {
|
||||||
if member.RoleLevel != nil {
|
if member.RoleLevel != nil {
|
||||||
@ -1529,29 +1536,61 @@ func (g *groupServer) SetGroupMemberInfo(ctx context.Context, req *pbgroup.SetGr
|
|||||||
case 0:
|
case 0:
|
||||||
if !isAppManagerUid {
|
if !isAppManagerUid {
|
||||||
roleLevel := dbMembers[opUserIndex].RoleLevel
|
roleLevel := dbMembers[opUserIndex].RoleLevel
|
||||||
if roleLevel != constant.GroupOwner {
|
var (
|
||||||
switch roleLevel {
|
dbSelf = &model.GroupMember{}
|
||||||
case constant.GroupAdmin:
|
reqSelf *pbgroup.SetGroupMemberInfo
|
||||||
for _, member := range dbMembers {
|
)
|
||||||
if member.RoleLevel == constant.GroupOwner {
|
switch roleLevel {
|
||||||
return nil, errs.ErrNoPermission.WrapMsg("admin can not change group owner")
|
case constant.GroupOwner:
|
||||||
}
|
for _, member := range dbMembers {
|
||||||
if member.RoleLevel == constant.GroupAdmin && member.UserID != opUserID {
|
if member.UserID == opUserID {
|
||||||
return nil, errs.ErrNoPermission.WrapMsg("admin can not change other group admin")
|
dbSelf = member
|
||||||
}
|
break
|
||||||
}
|
}
|
||||||
case constant.GroupOrdinaryUsers:
|
}
|
||||||
for _, member := range dbMembers {
|
case constant.GroupAdmin:
|
||||||
if !(member.RoleLevel == constant.GroupOrdinaryUsers && member.UserID == opUserID) {
|
for _, member := range dbMembers {
|
||||||
return nil, errs.ErrNoPermission.WrapMsg("ordinary users can not change other role level")
|
if member.UserID == opUserID {
|
||||||
}
|
dbSelf = member
|
||||||
}
|
}
|
||||||
default:
|
if member.RoleLevel == constant.GroupOwner {
|
||||||
for _, member := range dbMembers {
|
return nil, errs.ErrNoPermission.WrapMsg("admin can not change group owner")
|
||||||
if member.RoleLevel >= roleLevel {
|
|
||||||
return nil, errs.ErrNoPermission.WrapMsg("can not change higher role level")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
if member.RoleLevel == constant.GroupAdmin && member.UserID != opUserID {
|
||||||
|
return nil, errs.ErrNoPermission.WrapMsg("admin can not change other group admin")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case constant.GroupOrdinaryUsers:
|
||||||
|
for _, member := range dbMembers {
|
||||||
|
if member.UserID == opUserID {
|
||||||
|
dbSelf = member
|
||||||
|
}
|
||||||
|
if !(member.RoleLevel == constant.GroupOrdinaryUsers && member.UserID == opUserID) {
|
||||||
|
return nil, errs.ErrNoPermission.WrapMsg("ordinary users can not change other role level")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
for _, member := range dbMembers {
|
||||||
|
if member.UserID == opUserID {
|
||||||
|
dbSelf = member
|
||||||
|
}
|
||||||
|
if member.RoleLevel >= roleLevel {
|
||||||
|
return nil, errs.ErrNoPermission.WrapMsg("can not change higher role level")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, member := range req.Members {
|
||||||
|
if member.UserID == opUserID {
|
||||||
|
reqSelf = member
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if reqSelf != nil && reqSelf.RoleLevel != nil {
|
||||||
|
if reqSelf.RoleLevel.GetValue() > dbSelf.RoleLevel {
|
||||||
|
return nil, errs.ErrNoPermission.WrapMsg("can not improve role level by self")
|
||||||
|
}
|
||||||
|
if roleLevel == constant.GroupOwner {
|
||||||
|
return nil, errs.ErrArgs.WrapMsg("group owner can not change own role level") // Prevent the absence of a group owner
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1707,7 +1746,7 @@ func (g *groupServer) GetGroupUsersReqApplicationList(ctx context.Context, req *
|
|||||||
return nil, servererrs.ErrGroupIDNotFound.WrapMsg(strings.Join(ids, ","))
|
return nil, servererrs.ErrGroupIDNotFound.WrapMsg(strings.Join(ids, ","))
|
||||||
}
|
}
|
||||||
|
|
||||||
userMap, err := g.user.GetPublicUserInfoMap(ctx, req.UserIDs)
|
userMap, err := g.userClient.GetUsersInfoMap(ctx, req.UserIDs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -1738,7 +1777,7 @@ func (g *groupServer) GetGroupUsersReqApplicationList(ctx context.Context, req *
|
|||||||
ownerUserID = owner.UserID
|
ownerUserID = owner.UserID
|
||||||
}
|
}
|
||||||
|
|
||||||
var userInfo *sdkws.PublicUserInfo
|
var userInfo *sdkws.UserInfo
|
||||||
if user, ok := userMap[e.UserID]; !ok {
|
if user, ok := userMap[e.UserID]; !ok {
|
||||||
userInfo = user
|
userInfo = user
|
||||||
}
|
}
|
||||||
@ -1757,7 +1796,6 @@ func (g *groupServer) GetSpecifiedUserGroupRequestInfo(ctx context.Context, req
|
|||||||
}
|
}
|
||||||
|
|
||||||
if req.UserID != opUserID {
|
if req.UserID != opUserID {
|
||||||
req.UserID = mcontext.GetOpUserID(ctx)
|
|
||||||
adminIDs, err := g.db.GetGroupRoleLevelMemberIDs(ctx, req.GroupID, constant.GroupAdmin)
|
adminIDs, err := g.db.GetGroupRoleLevelMemberIDs(ctx, req.GroupID, constant.GroupAdmin)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -1766,10 +1804,11 @@ func (g *groupServer) GetSpecifiedUserGroupRequestInfo(ctx context.Context, req
|
|||||||
adminIDs = append(adminIDs, owners[0].UserID)
|
adminIDs = append(adminIDs, owners[0].UserID)
|
||||||
adminIDs = append(adminIDs, g.config.Share.IMAdminUserID...)
|
adminIDs = append(adminIDs, g.config.Share.IMAdminUserID...)
|
||||||
|
|
||||||
if !datautil.Contain(req.UserID, adminIDs...) {
|
if !datautil.Contain(opUserID, adminIDs...) {
|
||||||
return nil, errs.ErrNoPermission.WrapMsg("opUser no permission")
|
return nil, errs.ErrNoPermission.WrapMsg("opUser no permission")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
requests, err := g.db.FindGroupRequests(ctx, req.GroupID, []string{req.UserID})
|
requests, err := g.db.FindGroupRequests(ctx, req.GroupID, []string{req.UserID})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -1784,7 +1823,7 @@ func (g *groupServer) GetSpecifiedUserGroupRequestInfo(ctx context.Context, req
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
userInfos, err := g.user.GetPublicUserInfos(ctx, []string{req.UserID})
|
userInfos, err := g.userClient.GetUsersInfo(ctx, []string{req.UserID})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,10 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/openimsdk/open-im-server/v3/pkg/rpcli"
|
||||||
|
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/authverify"
|
"github.com/openimsdk/open-im-server/v3/pkg/authverify"
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/common/convert"
|
"github.com/openimsdk/open-im-server/v3/pkg/common/convert"
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/common/servererrs"
|
"github.com/openimsdk/open-im-server/v3/pkg/common/servererrs"
|
||||||
@ -26,8 +30,8 @@ import (
|
|||||||
"github.com/openimsdk/open-im-server/v3/pkg/common/storage/model"
|
"github.com/openimsdk/open-im-server/v3/pkg/common/storage/model"
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/common/storage/versionctx"
|
"github.com/openimsdk/open-im-server/v3/pkg/common/storage/versionctx"
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/msgprocessor"
|
"github.com/openimsdk/open-im-server/v3/pkg/msgprocessor"
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
|
"github.com/openimsdk/open-im-server/v3/pkg/notification"
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient/notification"
|
"github.com/openimsdk/open-im-server/v3/pkg/notification/common_user"
|
||||||
"github.com/openimsdk/protocol/constant"
|
"github.com/openimsdk/protocol/constant"
|
||||||
pbgroup "github.com/openimsdk/protocol/group"
|
pbgroup "github.com/openimsdk/protocol/group"
|
||||||
"github.com/openimsdk/protocol/msg"
|
"github.com/openimsdk/protocol/msg"
|
||||||
@ -46,36 +50,38 @@ const (
|
|||||||
adminReceiver
|
adminReceiver
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewGroupNotificationSender(
|
func NewNotificationSender(db controller.GroupDatabase, config *Config, userClient *rpcli.UserClient, msgClient *rpcli.MsgClient, conversationClient *rpcli.ConversationClient) *NotificationSender {
|
||||||
db controller.GroupDatabase,
|
return &NotificationSender{
|
||||||
msgRpcClient *rpcclient.MessageRpcClient,
|
NotificationSender: rpcclient.NewNotificationSender(&config.NotificationConfig,
|
||||||
userRpcClient *rpcclient.UserRpcClient,
|
rpcclient.WithRpcClient(func(ctx context.Context, req *msg.SendMsgReq) (*msg.SendMsgResp, error) {
|
||||||
conversationRpcClient *rpcclient.ConversationRpcClient,
|
return msgClient.SendMsg(ctx, req)
|
||||||
config *Config,
|
}),
|
||||||
fn func(ctx context.Context, userIDs []string) ([]notification.CommonUser, error),
|
rpcclient.WithUserRpcClient(userClient.GetUserInfo),
|
||||||
) *GroupNotificationSender {
|
),
|
||||||
return &GroupNotificationSender{
|
getUsersInfo: func(ctx context.Context, userIDs []string) ([]common_user.CommonUser, error) {
|
||||||
NotificationSender: rpcclient.NewNotificationSender(&config.NotificationConfig, rpcclient.WithRpcClient(msgRpcClient), rpcclient.WithUserRpcClient(userRpcClient)),
|
users, err := userClient.GetUsersInfo(ctx, userIDs)
|
||||||
getUsersInfo: fn,
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return datautil.Slice(users, func(e *sdkws.UserInfo) common_user.CommonUser { return e }), nil
|
||||||
|
},
|
||||||
db: db,
|
db: db,
|
||||||
config: config,
|
config: config,
|
||||||
|
msgClient: msgClient,
|
||||||
conversationRpcClient: conversationRpcClient,
|
conversationClient: conversationClient,
|
||||||
msgRpcClient: msgRpcClient,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type GroupNotificationSender struct {
|
type NotificationSender struct {
|
||||||
*rpcclient.NotificationSender
|
*rpcclient.NotificationSender
|
||||||
getUsersInfo func(ctx context.Context, userIDs []string) ([]notification.CommonUser, error)
|
getUsersInfo func(ctx context.Context, userIDs []string) ([]common_user.CommonUser, error)
|
||||||
db controller.GroupDatabase
|
db controller.GroupDatabase
|
||||||
config *Config
|
config *Config
|
||||||
|
msgClient *rpcli.MsgClient
|
||||||
conversationRpcClient *rpcclient.ConversationRpcClient
|
conversationClient *rpcli.ConversationClient
|
||||||
msgRpcClient *rpcclient.MessageRpcClient
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GroupNotificationSender) PopulateGroupMember(ctx context.Context, members ...*model.GroupMember) error {
|
func (g *NotificationSender) PopulateGroupMember(ctx context.Context, members ...*model.GroupMember) error {
|
||||||
if len(members) == 0 {
|
if len(members) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -90,7 +96,7 @@ func (g *GroupNotificationSender) PopulateGroupMember(ctx context.Context, membe
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
userMap := make(map[string]notification.CommonUser)
|
userMap := make(map[string]common_user.CommonUser)
|
||||||
for i, user := range users {
|
for i, user := range users {
|
||||||
userMap[user.GetUserID()] = users[i]
|
userMap[user.GetUserID()] = users[i]
|
||||||
}
|
}
|
||||||
@ -110,7 +116,7 @@ func (g *GroupNotificationSender) PopulateGroupMember(ctx context.Context, membe
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GroupNotificationSender) getUser(ctx context.Context, userID string) (*sdkws.PublicUserInfo, error) {
|
func (g *NotificationSender) getUser(ctx context.Context, userID string) (*sdkws.PublicUserInfo, error) {
|
||||||
users, err := g.getUsersInfo(ctx, []string{userID})
|
users, err := g.getUsersInfo(ctx, []string{userID})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -126,7 +132,7 @@ func (g *GroupNotificationSender) getUser(ctx context.Context, userID string) (*
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GroupNotificationSender) getGroupInfo(ctx context.Context, groupID string) (*sdkws.GroupInfo, error) {
|
func (g *NotificationSender) getGroupInfo(ctx context.Context, groupID string) (*sdkws.GroupInfo, error) {
|
||||||
gm, err := g.db.TakeGroup(ctx, groupID)
|
gm, err := g.db.TakeGroup(ctx, groupID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -147,7 +153,7 @@ func (g *GroupNotificationSender) getGroupInfo(ctx context.Context, groupID stri
|
|||||||
return convert.Db2PbGroupInfo(gm, ownerUserID, num), nil
|
return convert.Db2PbGroupInfo(gm, ownerUserID, num), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GroupNotificationSender) getGroupMembers(ctx context.Context, groupID string, userIDs []string) ([]*sdkws.GroupMemberFullInfo, error) {
|
func (g *NotificationSender) getGroupMembers(ctx context.Context, groupID string, userIDs []string) ([]*sdkws.GroupMemberFullInfo, error) {
|
||||||
members, err := g.db.FindGroupMembers(ctx, groupID, userIDs)
|
members, err := g.db.FindGroupMembers(ctx, groupID, userIDs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -163,7 +169,7 @@ func (g *GroupNotificationSender) getGroupMembers(ctx context.Context, groupID s
|
|||||||
return res, nil
|
return res, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GroupNotificationSender) getGroupMemberMap(ctx context.Context, groupID string, userIDs []string) (map[string]*sdkws.GroupMemberFullInfo, error) {
|
func (g *NotificationSender) getGroupMemberMap(ctx context.Context, groupID string, userIDs []string) (map[string]*sdkws.GroupMemberFullInfo, error) {
|
||||||
members, err := g.getGroupMembers(ctx, groupID, userIDs)
|
members, err := g.getGroupMembers(ctx, groupID, userIDs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -175,7 +181,7 @@ func (g *GroupNotificationSender) getGroupMemberMap(ctx context.Context, groupID
|
|||||||
return m, nil
|
return m, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GroupNotificationSender) getGroupMember(ctx context.Context, groupID string, userID string) (*sdkws.GroupMemberFullInfo, error) {
|
func (g *NotificationSender) getGroupMember(ctx context.Context, groupID string, userID string) (*sdkws.GroupMemberFullInfo, error) {
|
||||||
members, err := g.getGroupMembers(ctx, groupID, []string{userID})
|
members, err := g.getGroupMembers(ctx, groupID, []string{userID})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -186,7 +192,7 @@ func (g *GroupNotificationSender) getGroupMember(ctx context.Context, groupID st
|
|||||||
return members[0], nil
|
return members[0], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GroupNotificationSender) getGroupOwnerAndAdminUserID(ctx context.Context, groupID string) ([]string, error) {
|
func (g *NotificationSender) getGroupOwnerAndAdminUserID(ctx context.Context, groupID string) ([]string, error) {
|
||||||
members, err := g.db.FindGroupMemberRoleLevels(ctx, groupID, []int32{constant.GroupOwner, constant.GroupAdmin})
|
members, err := g.db.FindGroupMemberRoleLevels(ctx, groupID, []int32{constant.GroupOwner, constant.GroupAdmin})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -198,7 +204,7 @@ func (g *GroupNotificationSender) getGroupOwnerAndAdminUserID(ctx context.Contex
|
|||||||
return datautil.Slice(members, fn), nil
|
return datautil.Slice(members, fn), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GroupNotificationSender) groupMemberDB2PB(member *model.GroupMember, appMangerLevel int32) *sdkws.GroupMemberFullInfo {
|
func (g *NotificationSender) groupMemberDB2PB(member *model.GroupMember, appMangerLevel int32) *sdkws.GroupMemberFullInfo {
|
||||||
return &sdkws.GroupMemberFullInfo{
|
return &sdkws.GroupMemberFullInfo{
|
||||||
GroupID: member.GroupID,
|
GroupID: member.GroupID,
|
||||||
UserID: member.UserID,
|
UserID: member.UserID,
|
||||||
@ -215,7 +221,7 @@ func (g *GroupNotificationSender) groupMemberDB2PB(member *model.GroupMember, ap
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* func (g *GroupNotificationSender) getUsersInfoMap(ctx context.Context, userIDs []string) (map[string]*sdkws.UserInfo, error) {
|
/* func (g *NotificationSender) getUsersInfoMap(ctx context.Context, userIDs []string) (map[string]*sdkws.UserInfo, error) {
|
||||||
users, err := g.getUsersInfo(ctx, userIDs)
|
users, err := g.getUsersInfo(ctx, userIDs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -227,11 +233,11 @@ func (g *GroupNotificationSender) groupMemberDB2PB(member *model.GroupMember, ap
|
|||||||
return result, nil
|
return result, nil
|
||||||
} */
|
} */
|
||||||
|
|
||||||
func (g *GroupNotificationSender) fillOpUser(ctx context.Context, opUser **sdkws.GroupMemberFullInfo, groupID string) (err error) {
|
func (g *NotificationSender) fillOpUser(ctx context.Context, opUser **sdkws.GroupMemberFullInfo, groupID string) (err error) {
|
||||||
return g.fillOpUserByUserID(ctx, mcontext.GetOpUserID(ctx), opUser, groupID)
|
return g.fillOpUserByUserID(ctx, mcontext.GetOpUserID(ctx), opUser, groupID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GroupNotificationSender) fillOpUserByUserID(ctx context.Context, userID string, opUser **sdkws.GroupMemberFullInfo, groupID string) error {
|
func (g *NotificationSender) fillOpUserByUserID(ctx context.Context, userID string, opUser **sdkws.GroupMemberFullInfo, groupID string) error {
|
||||||
if opUser == nil {
|
if opUser == nil {
|
||||||
return errs.ErrInternalServer.WrapMsg("**sdkws.GroupMemberFullInfo is nil")
|
return errs.ErrInternalServer.WrapMsg("**sdkws.GroupMemberFullInfo is nil")
|
||||||
}
|
}
|
||||||
@ -275,7 +281,7 @@ func (g *GroupNotificationSender) fillOpUserByUserID(ctx context.Context, userID
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GroupNotificationSender) setVersion(ctx context.Context, version *uint64, versionID *string, collName string, id string) {
|
func (g *NotificationSender) setVersion(ctx context.Context, version *uint64, versionID *string, collName string, id string) {
|
||||||
versions := versionctx.GetVersionLog(ctx).Get()
|
versions := versionctx.GetVersionLog(ctx).Get()
|
||||||
for _, coll := range versions {
|
for _, coll := range versions {
|
||||||
if coll.Name == collName && coll.Doc.DID == id {
|
if coll.Name == collName && coll.Doc.DID == id {
|
||||||
@ -286,7 +292,7 @@ func (g *GroupNotificationSender) setVersion(ctx context.Context, version *uint6
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GroupNotificationSender) setSortVersion(ctx context.Context, version *uint64, versionID *string, collName string, id string, sortVersion *uint64) {
|
func (g *NotificationSender) setSortVersion(ctx context.Context, version *uint64, versionID *string, collName string, id string, sortVersion *uint64) {
|
||||||
versions := versionctx.GetVersionLog(ctx).Get()
|
versions := versionctx.GetVersionLog(ctx).Get()
|
||||||
for _, coll := range versions {
|
for _, coll := range versions {
|
||||||
if coll.Name == collName && coll.Doc.DID == id {
|
if coll.Name == collName && coll.Doc.DID == id {
|
||||||
@ -301,7 +307,7 @@ func (g *GroupNotificationSender) setSortVersion(ctx context.Context, version *u
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GroupNotificationSender) GroupCreatedNotification(ctx context.Context, tips *sdkws.GroupCreatedTips) {
|
func (g *NotificationSender) GroupCreatedNotification(ctx context.Context, tips *sdkws.GroupCreatedTips) {
|
||||||
var err error
|
var err error
|
||||||
defer func() {
|
defer func() {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -315,7 +321,7 @@ func (g *GroupNotificationSender) GroupCreatedNotification(ctx context.Context,
|
|||||||
g.Notification(ctx, mcontext.GetOpUserID(ctx), tips.Group.GroupID, constant.GroupCreatedNotification, tips)
|
g.Notification(ctx, mcontext.GetOpUserID(ctx), tips.Group.GroupID, constant.GroupCreatedNotification, tips)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GroupNotificationSender) GroupInfoSetNotification(ctx context.Context, tips *sdkws.GroupInfoSetTips) {
|
func (g *NotificationSender) GroupInfoSetNotification(ctx context.Context, tips *sdkws.GroupInfoSetTips) {
|
||||||
var err error
|
var err error
|
||||||
defer func() {
|
defer func() {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -329,7 +335,7 @@ func (g *GroupNotificationSender) GroupInfoSetNotification(ctx context.Context,
|
|||||||
g.Notification(ctx, mcontext.GetOpUserID(ctx), tips.Group.GroupID, constant.GroupInfoSetNotification, tips, rpcclient.WithRpcGetUserName())
|
g.Notification(ctx, mcontext.GetOpUserID(ctx), tips.Group.GroupID, constant.GroupInfoSetNotification, tips, rpcclient.WithRpcGetUserName())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GroupNotificationSender) GroupInfoSetNameNotification(ctx context.Context, tips *sdkws.GroupInfoSetNameTips) {
|
func (g *NotificationSender) GroupInfoSetNameNotification(ctx context.Context, tips *sdkws.GroupInfoSetNameTips) {
|
||||||
var err error
|
var err error
|
||||||
defer func() {
|
defer func() {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -343,7 +349,7 @@ func (g *GroupNotificationSender) GroupInfoSetNameNotification(ctx context.Conte
|
|||||||
g.Notification(ctx, mcontext.GetOpUserID(ctx), tips.Group.GroupID, constant.GroupInfoSetNameNotification, tips)
|
g.Notification(ctx, mcontext.GetOpUserID(ctx), tips.Group.GroupID, constant.GroupInfoSetNameNotification, tips)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GroupNotificationSender) GroupInfoSetAnnouncementNotification(ctx context.Context, tips *sdkws.GroupInfoSetAnnouncementTips) {
|
func (g *NotificationSender) GroupInfoSetAnnouncementNotification(ctx context.Context, tips *sdkws.GroupInfoSetAnnouncementTips) {
|
||||||
var err error
|
var err error
|
||||||
defer func() {
|
defer func() {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -357,7 +363,7 @@ func (g *GroupNotificationSender) GroupInfoSetAnnouncementNotification(ctx conte
|
|||||||
g.Notification(ctx, mcontext.GetOpUserID(ctx), tips.Group.GroupID, constant.GroupInfoSetAnnouncementNotification, tips, rpcclient.WithRpcGetUserName())
|
g.Notification(ctx, mcontext.GetOpUserID(ctx), tips.Group.GroupID, constant.GroupInfoSetAnnouncementNotification, tips, rpcclient.WithRpcGetUserName())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GroupNotificationSender) JoinGroupApplicationNotification(ctx context.Context, req *pbgroup.JoinGroupReq) {
|
func (g *NotificationSender) JoinGroupApplicationNotification(ctx context.Context, req *pbgroup.JoinGroupReq) {
|
||||||
var err error
|
var err error
|
||||||
defer func() {
|
defer func() {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -385,7 +391,7 @@ func (g *GroupNotificationSender) JoinGroupApplicationNotification(ctx context.C
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GroupNotificationSender) MemberQuitNotification(ctx context.Context, member *sdkws.GroupMemberFullInfo) {
|
func (g *NotificationSender) MemberQuitNotification(ctx context.Context, member *sdkws.GroupMemberFullInfo) {
|
||||||
var err error
|
var err error
|
||||||
defer func() {
|
defer func() {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -402,7 +408,7 @@ func (g *GroupNotificationSender) MemberQuitNotification(ctx context.Context, me
|
|||||||
g.Notification(ctx, mcontext.GetOpUserID(ctx), member.GroupID, constant.MemberQuitNotification, tips)
|
g.Notification(ctx, mcontext.GetOpUserID(ctx), member.GroupID, constant.MemberQuitNotification, tips)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GroupNotificationSender) GroupApplicationAcceptedNotification(ctx context.Context, req *pbgroup.GroupApplicationResponseReq) {
|
func (g *NotificationSender) GroupApplicationAcceptedNotification(ctx context.Context, req *pbgroup.GroupApplicationResponseReq) {
|
||||||
var err error
|
var err error
|
||||||
defer func() {
|
defer func() {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -435,7 +441,7 @@ func (g *GroupNotificationSender) GroupApplicationAcceptedNotification(ctx conte
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GroupNotificationSender) GroupApplicationRejectedNotification(ctx context.Context, req *pbgroup.GroupApplicationResponseReq) {
|
func (g *NotificationSender) GroupApplicationRejectedNotification(ctx context.Context, req *pbgroup.GroupApplicationResponseReq) {
|
||||||
var err error
|
var err error
|
||||||
defer func() {
|
defer func() {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -468,7 +474,7 @@ func (g *GroupNotificationSender) GroupApplicationRejectedNotification(ctx conte
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GroupNotificationSender) GroupOwnerTransferredNotification(ctx context.Context, req *pbgroup.TransferGroupOwnerReq) {
|
func (g *NotificationSender) GroupOwnerTransferredNotification(ctx context.Context, req *pbgroup.TransferGroupOwnerReq) {
|
||||||
var err error
|
var err error
|
||||||
defer func() {
|
defer func() {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -499,7 +505,7 @@ func (g *GroupNotificationSender) GroupOwnerTransferredNotification(ctx context.
|
|||||||
g.Notification(ctx, mcontext.GetOpUserID(ctx), group.GroupID, constant.GroupOwnerTransferredNotification, tips)
|
g.Notification(ctx, mcontext.GetOpUserID(ctx), group.GroupID, constant.GroupOwnerTransferredNotification, tips)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GroupNotificationSender) MemberKickedNotification(ctx context.Context, tips *sdkws.MemberKickedTips) {
|
func (g *NotificationSender) MemberKickedNotification(ctx context.Context, tips *sdkws.MemberKickedTips) {
|
||||||
var err error
|
var err error
|
||||||
defer func() {
|
defer func() {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -513,7 +519,7 @@ func (g *GroupNotificationSender) MemberKickedNotification(ctx context.Context,
|
|||||||
g.Notification(ctx, mcontext.GetOpUserID(ctx), tips.Group.GroupID, constant.MemberKickedNotification, tips)
|
g.Notification(ctx, mcontext.GetOpUserID(ctx), tips.Group.GroupID, constant.MemberKickedNotification, tips)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GroupNotificationSender) GroupApplicationAgreeMemberEnterNotification(ctx context.Context, groupID string, invitedOpUserID string, entrantUserID ...string) error {
|
func (g *NotificationSender) GroupApplicationAgreeMemberEnterNotification(ctx context.Context, groupID string, invitedOpUserID string, entrantUserID ...string) error {
|
||||||
var err error
|
var err error
|
||||||
defer func() {
|
defer func() {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -523,20 +529,15 @@ func (g *GroupNotificationSender) GroupApplicationAgreeMemberEnterNotification(c
|
|||||||
|
|
||||||
if !g.config.RpcConfig.EnableHistoryForNewMembers {
|
if !g.config.RpcConfig.EnableHistoryForNewMembers {
|
||||||
conversationID := msgprocessor.GetConversationIDBySessionType(constant.ReadGroupChatType, groupID)
|
conversationID := msgprocessor.GetConversationIDBySessionType(constant.ReadGroupChatType, groupID)
|
||||||
maxSeq, err := g.msgRpcClient.GetConversationMaxSeq(ctx, conversationID)
|
maxSeq, err := g.msgClient.GetConversationMaxSeq(ctx, conversationID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if _, err = g.msgRpcClient.SetUserConversationsMinSeq(ctx, &msg.SetUserConversationsMinSeqReq{
|
if err := g.msgClient.SetUserConversationsMinSeq(ctx, conversationID, entrantUserID, maxSeq+1); err != nil {
|
||||||
UserIDs: entrantUserID,
|
|
||||||
ConversationID: conversationID,
|
|
||||||
Seq: maxSeq,
|
|
||||||
}); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if err := g.conversationClient.CreateGroupChatConversations(ctx, groupID, entrantUserID); err != nil {
|
||||||
if err := g.conversationRpcClient.GroupChatFirstCreateConversation(ctx, groupID, entrantUserID); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -572,11 +573,48 @@ func (g *GroupNotificationSender) GroupApplicationAgreeMemberEnterNotification(c
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GroupNotificationSender) MemberEnterNotification(ctx context.Context, groupID string, entrantUserID ...string) error {
|
func (g *NotificationSender) MemberEnterNotification(ctx context.Context, groupID string, entrantUserID string) error {
|
||||||
return g.GroupApplicationAgreeMemberEnterNotification(ctx, groupID, "", entrantUserID...)
|
var err error
|
||||||
|
defer func() {
|
||||||
|
if err != nil {
|
||||||
|
log.ZError(ctx, stringutil.GetFuncName(1)+" failed", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
if !g.config.RpcConfig.EnableHistoryForNewMembers {
|
||||||
|
conversationID := msgprocessor.GetConversationIDBySessionType(constant.ReadGroupChatType, groupID)
|
||||||
|
maxSeq, err := g.msgClient.GetConversationMaxSeq(ctx, conversationID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := g.msgClient.SetUserConversationsMinSeq(ctx, conversationID, []string{entrantUserID}, maxSeq+1); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err := g.conversationClient.CreateGroupChatConversations(ctx, groupID, []string{entrantUserID}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
var group *sdkws.GroupInfo
|
||||||
|
group, err = g.getGroupInfo(ctx, groupID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
user, err := g.getGroupMember(ctx, groupID, entrantUserID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
tips := &sdkws.MemberEnterTips{
|
||||||
|
Group: group,
|
||||||
|
EntrantUser: user,
|
||||||
|
OperationTime: time.Now().UnixMilli(),
|
||||||
|
}
|
||||||
|
g.setVersion(ctx, &tips.GroupMemberVersion, &tips.GroupMemberVersionID, database.GroupMemberVersionName, tips.Group.GroupID)
|
||||||
|
g.Notification(ctx, mcontext.GetOpUserID(ctx), group.GroupID, constant.MemberEnterNotification, tips)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GroupNotificationSender) GroupDismissedNotification(ctx context.Context, tips *sdkws.GroupDismissedTips) {
|
func (g *NotificationSender) GroupDismissedNotification(ctx context.Context, tips *sdkws.GroupDismissedTips) {
|
||||||
var err error
|
var err error
|
||||||
defer func() {
|
defer func() {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -589,7 +627,7 @@ func (g *GroupNotificationSender) GroupDismissedNotification(ctx context.Context
|
|||||||
g.Notification(ctx, mcontext.GetOpUserID(ctx), tips.Group.GroupID, constant.GroupDismissedNotification, tips)
|
g.Notification(ctx, mcontext.GetOpUserID(ctx), tips.Group.GroupID, constant.GroupDismissedNotification, tips)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GroupNotificationSender) GroupMemberMutedNotification(ctx context.Context, groupID, groupMemberUserID string, mutedSeconds uint32) {
|
func (g *NotificationSender) GroupMemberMutedNotification(ctx context.Context, groupID, groupMemberUserID string, mutedSeconds uint32) {
|
||||||
var err error
|
var err error
|
||||||
defer func() {
|
defer func() {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -617,7 +655,7 @@ func (g *GroupNotificationSender) GroupMemberMutedNotification(ctx context.Conte
|
|||||||
g.Notification(ctx, mcontext.GetOpUserID(ctx), group.GroupID, constant.GroupMemberMutedNotification, tips)
|
g.Notification(ctx, mcontext.GetOpUserID(ctx), group.GroupID, constant.GroupMemberMutedNotification, tips)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GroupNotificationSender) GroupMemberCancelMutedNotification(ctx context.Context, groupID, groupMemberUserID string) {
|
func (g *NotificationSender) GroupMemberCancelMutedNotification(ctx context.Context, groupID, groupMemberUserID string) {
|
||||||
var err error
|
var err error
|
||||||
defer func() {
|
defer func() {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -642,7 +680,7 @@ func (g *GroupNotificationSender) GroupMemberCancelMutedNotification(ctx context
|
|||||||
g.Notification(ctx, mcontext.GetOpUserID(ctx), group.GroupID, constant.GroupMemberCancelMutedNotification, tips)
|
g.Notification(ctx, mcontext.GetOpUserID(ctx), group.GroupID, constant.GroupMemberCancelMutedNotification, tips)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GroupNotificationSender) GroupMutedNotification(ctx context.Context, groupID string) {
|
func (g *NotificationSender) GroupMutedNotification(ctx context.Context, groupID string) {
|
||||||
var err error
|
var err error
|
||||||
defer func() {
|
defer func() {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -670,7 +708,7 @@ func (g *GroupNotificationSender) GroupMutedNotification(ctx context.Context, gr
|
|||||||
g.Notification(ctx, mcontext.GetOpUserID(ctx), group.GroupID, constant.GroupMutedNotification, tips)
|
g.Notification(ctx, mcontext.GetOpUserID(ctx), group.GroupID, constant.GroupMutedNotification, tips)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GroupNotificationSender) GroupCancelMutedNotification(ctx context.Context, groupID string) {
|
func (g *NotificationSender) GroupCancelMutedNotification(ctx context.Context, groupID string) {
|
||||||
var err error
|
var err error
|
||||||
defer func() {
|
defer func() {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -698,7 +736,7 @@ func (g *GroupNotificationSender) GroupCancelMutedNotification(ctx context.Conte
|
|||||||
g.Notification(ctx, mcontext.GetOpUserID(ctx), group.GroupID, constant.GroupCancelMutedNotification, tips)
|
g.Notification(ctx, mcontext.GetOpUserID(ctx), group.GroupID, constant.GroupCancelMutedNotification, tips)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GroupNotificationSender) GroupMemberInfoSetNotification(ctx context.Context, groupID, groupMemberUserID string) {
|
func (g *NotificationSender) GroupMemberInfoSetNotification(ctx context.Context, groupID, groupMemberUserID string) {
|
||||||
var err error
|
var err error
|
||||||
defer func() {
|
defer func() {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -723,7 +761,7 @@ func (g *GroupNotificationSender) GroupMemberInfoSetNotification(ctx context.Con
|
|||||||
g.Notification(ctx, mcontext.GetOpUserID(ctx), group.GroupID, constant.GroupMemberInfoSetNotification, tips)
|
g.Notification(ctx, mcontext.GetOpUserID(ctx), group.GroupID, constant.GroupMemberInfoSetNotification, tips)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GroupNotificationSender) GroupMemberSetToAdminNotification(ctx context.Context, groupID, groupMemberUserID string) {
|
func (g *NotificationSender) GroupMemberSetToAdminNotification(ctx context.Context, groupID, groupMemberUserID string) {
|
||||||
var err error
|
var err error
|
||||||
defer func() {
|
defer func() {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -747,7 +785,7 @@ func (g *GroupNotificationSender) GroupMemberSetToAdminNotification(ctx context.
|
|||||||
g.Notification(ctx, mcontext.GetOpUserID(ctx), group.GroupID, constant.GroupMemberSetToAdminNotification, tips)
|
g.Notification(ctx, mcontext.GetOpUserID(ctx), group.GroupID, constant.GroupMemberSetToAdminNotification, tips)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GroupNotificationSender) GroupMemberSetToOrdinaryUserNotification(ctx context.Context, groupID, groupMemberUserID string) {
|
func (g *NotificationSender) GroupMemberSetToOrdinaryUserNotification(ctx context.Context, groupID, groupMemberUserID string) {
|
||||||
var err error
|
var err error
|
||||||
defer func() {
|
defer func() {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -16,6 +16,7 @@ package msg
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
|
|
||||||
cbapi "github.com/openimsdk/open-im-server/v3/pkg/callbackstruct"
|
cbapi "github.com/openimsdk/open-im-server/v3/pkg/callbackstruct"
|
||||||
"github.com/openimsdk/protocol/constant"
|
"github.com/openimsdk/protocol/constant"
|
||||||
@ -108,7 +109,7 @@ func (m *msgServer) MarkMsgsAsRead(ctx context.Context, req *msg.MarkMsgsAsReadR
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
currentHasReadSeq, err := m.MsgDatabase.GetHasReadSeq(ctx, req.UserID, req.ConversationID)
|
currentHasReadSeq, err := m.MsgDatabase.GetHasReadSeq(ctx, req.UserID, req.ConversationID)
|
||||||
if err != nil && errs.Unwrap(err) != redis.Nil {
|
if err != nil && !errors.Is(err, redis.Nil) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if hasReadSeq > currentHasReadSeq {
|
if hasReadSeq > currentHasReadSeq {
|
||||||
@ -136,7 +137,7 @@ func (m *msgServer) MarkConversationAsRead(ctx context.Context, req *msg.MarkCon
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
hasReadSeq, err := m.MsgDatabase.GetHasReadSeq(ctx, req.UserID, req.ConversationID)
|
hasReadSeq, err := m.MsgDatabase.GetHasReadSeq(ctx, req.UserID, req.ConversationID)
|
||||||
if err != nil && errs.Unwrap(err) != redis.Nil {
|
if err != nil && !errors.Is(err, redis.Nil) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
var seqs []int64
|
var seqs []int64
|
||||||
@ -180,14 +181,23 @@ func (m *msgServer) MarkConversationAsRead(ctx context.Context, req *msg.MarkCon
|
|||||||
req.UserID, seqs, hasReadSeq)
|
req.UserID, seqs, hasReadSeq)
|
||||||
}
|
}
|
||||||
|
|
||||||
reqCall := &cbapi.CallbackGroupMsgReadReq{
|
if conversation.ConversationType == constant.SingleChatType {
|
||||||
SendID: conversation.OwnerUserID,
|
reqCall := &cbapi.CallbackSingleMsgReadReq{
|
||||||
ReceiveID: req.UserID,
|
ConversationID: conversation.ConversationID,
|
||||||
UnreadMsgNum: req.HasReadSeq,
|
UserID: conversation.OwnerUserID,
|
||||||
ContentType: int64(conversation.ConversationType),
|
Seqs: req.Seqs,
|
||||||
|
ContentType: conversation.ConversationType,
|
||||||
|
}
|
||||||
|
m.webhookAfterSingleMsgRead(ctx, &m.config.WebhooksConfig.AfterSingleMsgRead, reqCall)
|
||||||
|
} else if conversation.ConversationType == constant.ReadGroupChatType {
|
||||||
|
reqCall := &cbapi.CallbackGroupMsgReadReq{
|
||||||
|
SendID: conversation.OwnerUserID,
|
||||||
|
ReceiveID: req.UserID,
|
||||||
|
UnreadMsgNum: req.HasReadSeq,
|
||||||
|
ContentType: int64(conversation.ConversationType),
|
||||||
|
}
|
||||||
|
m.webhookAfterGroupMsgRead(ctx, &m.config.WebhooksConfig.AfterGroupMsgRead, reqCall)
|
||||||
}
|
}
|
||||||
|
|
||||||
m.webhookAfterGroupMsgRead(ctx, &m.config.WebhooksConfig.AfterGroupMsgRead, reqCall)
|
|
||||||
return &msg.MarkConversationAsReadResp{}, nil
|
return &msg.MarkConversationAsReadResp{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user