mirror of
https://github.com/openimsdk/open-im-server.git
synced 2026-04-29 14:59:19 +08:00
Compare commits
37 Commits
| 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 |
@@ -1,4 +1,4 @@
|
||||
name: Build and release services Images
|
||||
name: Build and release services Docker Images
|
||||
|
||||
on:
|
||||
push:
|
||||
@@ -19,26 +19,26 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
uses: docker/setup-buildx-action@v3.8.0
|
||||
|
||||
- name: Log in to Docker Hub
|
||||
uses: docker/login-action@v2
|
||||
uses: docker/login-action@v3.3.0
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||
|
||||
- name: Log in to GitHub Container Registry
|
||||
uses: docker/login-action@v2
|
||||
uses: docker/login-action@v3.3.0
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.repository_owner }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Log in to Aliyun Container Registry
|
||||
uses: docker/login-action@v2
|
||||
uses: docker/login-action@v3.3.0
|
||||
with:
|
||||
registry: registry.cn-hangzhou.aliyuncs.com
|
||||
username: ${{ secrets.ALIREGISTRY_USERNAME }}
|
||||
@@ -46,7 +46,7 @@ jobs:
|
||||
|
||||
- name: Extract metadata for Docker (tags, labels)
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
uses: docker/metadata-action@v5.6.0
|
||||
with:
|
||||
tags: |
|
||||
type=ref,event=tag
|
||||
@@ -54,15 +54,14 @@ jobs:
|
||||
type=ref,event=branch
|
||||
type=semver,pattern={{version}}
|
||||
type=semver,pattern=v{{version}}
|
||||
# type=semver,pattern={{major}}.{{minor}}
|
||||
type=semver,pattern=release-{{raw}}
|
||||
type=sha
|
||||
type=raw,value=${{ github.event.inputs.tag }}
|
||||
|
||||
- name: Build and push Docker images
|
||||
run: |
|
||||
ROOT_DIR="build/images"
|
||||
for dir in "$ROOT_DIR"/*/; do
|
||||
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)
|
||||
|
||||
@@ -84,8 +83,9 @@ jobs:
|
||||
docker buildx build --platform linux/amd64,linux/arm64 \
|
||||
--file "$dockerfile" \
|
||||
"${tag_args[@]}" \
|
||||
--push "$dir"
|
||||
--push \
|
||||
"."
|
||||
else
|
||||
echo "No valid Dockerfile found in $dir"
|
||||
fi
|
||||
done
|
||||
done
|
||||
@@ -4,7 +4,7 @@ on:
|
||||
push:
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- '**/*.md'
|
||||
- "**/*.md"
|
||||
|
||||
workflow_dispatch:
|
||||
|
||||
@@ -18,7 +18,7 @@ jobs:
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest]
|
||||
go_version: ["1.21.x", "1.22.x"]
|
||||
go_version: ["1.22.x"]
|
||||
|
||||
steps:
|
||||
- name: Checkout Server repository
|
||||
@@ -37,27 +37,20 @@ jobs:
|
||||
|
||||
- name: Set up infra services
|
||||
uses: hoverkraft-tech/compose-action@v2.0.1
|
||||
# Uncomment and set the correct path to your docker-compose file
|
||||
with:
|
||||
compose-file: "./docker-compose.yml"
|
||||
|
||||
# run: |
|
||||
# sudo docker compose up -d
|
||||
# sudo sleep 30 # Increased sleep time for better stability
|
||||
# timeout-minutes: 60 # Increased timeout for Docker setup
|
||||
# - name: Get Internal IP Address
|
||||
# id: get-ip
|
||||
# run: |
|
||||
# IP=$(hostname -I | awk '{print $1}')
|
||||
# echo "The IP Address is: $IP"
|
||||
# echo "::set-output name=ip::$IP"
|
||||
|
||||
|
||||
# - name: Get Internal IP Address
|
||||
# id: get-ip
|
||||
# run: |
|
||||
# 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: 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
|
||||
run: |
|
||||
@@ -85,6 +78,90 @@ jobs:
|
||||
mage start
|
||||
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:
|
||||
name: Benchmark Test with go ${{ matrix.go_version }} on ${{ matrix.os }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
@@ -93,11 +170,11 @@ jobs:
|
||||
env:
|
||||
SDK_DIR: openim-sdk-core
|
||||
CONFIG_PATH: config/notification.yml
|
||||
# pull-requests: write
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ ubuntu-latest ]
|
||||
go_version: [ "1.22.x" ]
|
||||
os: [ubuntu-latest]
|
||||
go_version: ["1.22.x"]
|
||||
|
||||
steps:
|
||||
- name: Checkout Server repository
|
||||
@@ -106,7 +183,8 @@ jobs:
|
||||
- name: Checkout SDK repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: 'openimsdk/openim-sdk-core'
|
||||
repository: "openimsdk/openim-sdk-core"
|
||||
ref: "release-v3.8"
|
||||
path: ${{ env.SDK_DIR }}
|
||||
|
||||
- name: Set up Go ${{ matrix.go_version }}
|
||||
@@ -119,15 +197,10 @@ jobs:
|
||||
go install github.com/magefile/mage@latest
|
||||
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
|
||||
run: |
|
||||
yq e '.groupCreated.unreadCount = true' -i ${{ env.CONFIG_PATH }}
|
||||
yq e '.friendApplicationApproved.unreadCount = true' -i ${{ env.CONFIG_PATH }}
|
||||
yq e '.groupCreated.isSendMsg = true' -i ${{ env.CONFIG_PATH }}
|
||||
yq e '.friendApplicationApproved.isSendMsg = true' -i ${{ env.CONFIG_PATH }}
|
||||
|
||||
- name: Start Server Services
|
||||
run: |
|
||||
@@ -183,11 +256,3 @@ jobs:
|
||||
run: |
|
||||
CONTAINER_NAME="${{ github.event.repository.name }}-container"
|
||||
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
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
name: Create Pre-Release PR from Milestone
|
||||
name: Create Individual PRs from Milestone
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
@@ -9,24 +9,24 @@ on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
milestone_name:
|
||||
description: 'Milestone name to collect closed PRs from'
|
||||
description: "Milestone name to collect closed PRs from"
|
||||
required: true
|
||||
default: 'v3.8.2'
|
||||
default: "v3.8.4"
|
||||
target_branch:
|
||||
description: 'Target branch to merge the consolidated PR'
|
||||
description: "Target branch to merge the consolidated PR"
|
||||
required: true
|
||||
default: 'pre-release-v3.8.2'
|
||||
default: "pre-release-v3.8.4"
|
||||
|
||||
env:
|
||||
MILESTONE_NAME: ${{ github.event.inputs.milestone_name || 'v3.8.2' }}
|
||||
TARGET_BRANCH: ${{ github.event.inputs.target_branch || 'pre-release-v3.8.2' }}
|
||||
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 # Using /tmp as the temporary directory
|
||||
TEMP_DIR: /tmp
|
||||
|
||||
jobs:
|
||||
cherry_pick_milestone_prs:
|
||||
merge_milestone_prs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Setup temp directory
|
||||
@@ -47,7 +47,6 @@ jobs:
|
||||
|
||||
- name: Setup Git User for OpenIM-Robot
|
||||
run: |
|
||||
# Set up Git credentials for the bot
|
||||
git config --global user.email "OpenIM-Robot@users.noreply.github.com"
|
||||
git config --global user.name "OpenIM-Robot"
|
||||
|
||||
@@ -83,136 +82,65 @@ jobs:
|
||||
if ! echo "$labels" | grep -q "${LABEL_NAME}"; then
|
||||
echo "PR #$pr_number does not have the 'cherry-picked' label. Adding to the list."
|
||||
echo "$pr_number" >> ${{ env.TEMP_DIR }}/pr_numbers.txt
|
||||
else
|
||||
echo "PR #$pr_number already has the 'cherry-picked' label. Skipping."
|
||||
fi
|
||||
done
|
||||
|
||||
# Sort the filtered PR numbers
|
||||
sort -n ${{ env.TEMP_DIR }}/pr_numbers.txt -o ${{ env.TEMP_DIR }}/pr_numbers.txt
|
||||
|
||||
echo "Filtered and sorted PR numbers:"
|
||||
cat ${{ env.TEMP_DIR }}/pr_numbers.txt || echo "No closed PR numbers found for milestone."
|
||||
|
||||
- name: Fetch Merge Commits for PRs and Generate Title and Body
|
||||
- name: Create Individual PRs
|
||||
run: |
|
||||
# Ensure the files are initialized
|
||||
> ${{ env.TEMP_DIR }}/commit_hashes.txt
|
||||
> ${{ env.TEMP_DIR }}/pr_title.txt
|
||||
> ${{ env.TEMP_DIR }}/pr_body.txt
|
||||
|
||||
# Write description to the PR body
|
||||
echo "### Description:" >> ${{ env.TEMP_DIR }}/pr_body.txt
|
||||
echo "Merging PRs from milestone \`$MILESTONE_NAME\` into target branch \`$TARGET_BRANCH\`." >> ${{ env.TEMP_DIR }}/pr_body.txt
|
||||
echo "" >> ${{ env.TEMP_DIR }}/pr_body.txt
|
||||
echo "### Need Merge PRs:" >> ${{ env.TEMP_DIR }}/pr_body.txt
|
||||
|
||||
pr_numbers_in_title=""
|
||||
|
||||
# Process sorted PR numbers and generate commit hashes
|
||||
for pr_number in $(cat ${{ env.TEMP_DIR }}/pr_numbers.txt); do
|
||||
echo "Processing PR #$pr_number"
|
||||
pr_details=$(curl -s -H "Authorization: token $BOT_TOKEN" \
|
||||
-H "Accept: application/vnd.github+json" \
|
||||
"https://api.github.com/repos/${{ github.repository }}/pulls/$pr_number")
|
||||
pr_title=$(echo "$pr_details" | jq -r '.title')
|
||||
pr_body=$(echo "$pr_details" | jq -r '.body')
|
||||
pr_creator=$(echo "$pr_details" | jq -r '.user.login')
|
||||
merge_commit=$(echo "$pr_details" | jq -r '.merge_commit_sha')
|
||||
short_commit_hash=$(echo "$merge_commit" | cut -c 1-7)
|
||||
|
||||
# Append PR details to the body
|
||||
echo "- $pr_title: (#$pr_number) ($short_commit_hash)" >> ${{ env.TEMP_DIR }}/pr_body.txt
|
||||
if [ "$merge_commit" != "null" ]; then
|
||||
git fetch origin
|
||||
|
||||
echo "Checking out target branch: $TARGET_BRANCH"
|
||||
git checkout $TARGET_BRANCH
|
||||
|
||||
if [ "$merge_commit" != "null" ];then
|
||||
echo "$merge_commit" >> ${{ env.TEMP_DIR }}/commit_hashes.txt
|
||||
echo "#$pr_number" >> ${{ env.TEMP_DIR }}/pr_title.txt
|
||||
pr_numbers_in_title="$pr_numbers_in_title #$pr_number"
|
||||
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
|
||||
|
||||
commit_hashes=$(cat ${{ env.TEMP_DIR }}/commit_hashes.txt | tr '\n' ' ')
|
||||
first_commit_hash=$(head -n 1 ${{ env.TEMP_DIR }}/commit_hashes.txt)
|
||||
cherry_pick_branch="cherry-pick-${first_commit_hash:0:7}"
|
||||
echo "COMMIT_HASHES=$commit_hashes" >> $GITHUB_ENV
|
||||
echo "CHERRY_PICK_BRANCH=$cherry_pick_branch" >> $GITHUB_ENV
|
||||
echo "pr_numbers_in_title=$pr_numbers_in_title" >> $GITHUB_ENV
|
||||
|
||||
- name: Pull and Cherry-pick Commits, Then Push
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
BOT_TOKEN: ${{ secrets.BOT_TOKEN }}
|
||||
run: |
|
||||
# Fetch and pull the latest changes from the target branch
|
||||
git fetch origin
|
||||
git checkout $TARGET_BRANCH
|
||||
git pull origin $TARGET_BRANCH
|
||||
|
||||
# Create a new branch for cherry-picking
|
||||
git checkout -b $CHERRY_PICK_BRANCH
|
||||
|
||||
# Cherry-pick the commits and handle conflicts
|
||||
for commit_hash in $COMMIT_HASHES; do
|
||||
echo "Attempting to cherry-pick commit $commit_hash"
|
||||
if ! git cherry-pick "$commit_hash" --strategy=recursive -X theirs; then
|
||||
echo "Conflict detected for $commit_hash. Resolving with incoming changes."
|
||||
conflict_files=$(git diff --name-only --diff-filter=U)
|
||||
echo "Conflicting files:"
|
||||
echo "$conflict_files"
|
||||
|
||||
for file in $conflict_files; do
|
||||
if [ -f "$file" ]; then
|
||||
echo "Resolving conflict for $file"
|
||||
git add "$file"
|
||||
else
|
||||
echo "File $file has been deleted. Skipping."
|
||||
git rm "$file"
|
||||
fi
|
||||
done
|
||||
|
||||
echo "Conflicts resolved. Continuing cherry-pick."
|
||||
git cherry-pick --continue
|
||||
else
|
||||
echo "Cherry-pick successful for commit $commit_hash."
|
||||
fi
|
||||
done
|
||||
|
||||
# Push the cherry-pick branch to the repository
|
||||
git remote set-url origin "https://${BOT_TOKEN}@github.com/${{ github.repository }}.git"
|
||||
git push origin $CHERRY_PICK_BRANCH --force
|
||||
|
||||
- name: Create Pull Request
|
||||
run: |
|
||||
# Prepare and create the PR
|
||||
pr_title="deps: Merge ${{ env.pr_numbers_in_title }} PRs into $TARGET_BRANCH"
|
||||
pr_body=$(cat ${{ env.TEMP_DIR }}/pr_body.txt)
|
||||
|
||||
echo "Prepared PR title:"
|
||||
echo "$pr_title"
|
||||
echo "Prepared PR body:"
|
||||
echo "$pr_body"
|
||||
|
||||
# Create the PR using the GitHub API
|
||||
response=$(curl -s -X POST -H "Authorization: token $BOT_TOKEN" \
|
||||
-H "Accept: application/vnd.github+json" \
|
||||
https://api.github.com/repos/${{ github.repository }}/pulls \
|
||||
-d "$(jq -n --arg title "$pr_title" \
|
||||
--arg head "$CHERRY_PICK_BRANCH" \
|
||||
--arg base "$TARGET_BRANCH" \
|
||||
--arg body "$pr_body" \
|
||||
'{title: $title, head: $head, base: $base, body: $body}')")
|
||||
|
||||
pr_number=$(echo "$response" | jq -r '.number')
|
||||
echo "$pr_number" > ${{ env.TEMP_DIR }}/created_pr_number.txt
|
||||
echo "Created PR #$pr_number"
|
||||
|
||||
- name: Add Label to Created Pull Request
|
||||
run: |
|
||||
# Add 'milestone-merge' label to the created PR
|
||||
pr_number=$(cat ${{ env.TEMP_DIR }}/created_pr_number.txt)
|
||||
echo "Adding label to PR #$pr_number"
|
||||
|
||||
curl -s -X POST -H "Authorization: token $GITHUB_TOKEN" \
|
||||
-H "Accept: application/vnd.github+json" \
|
||||
-d '{"labels": ["milestone-merge"]}' \
|
||||
"https://api.github.com/repos/${{ github.repository }}/issues/$pr_number/labels"
|
||||
|
||||
echo "Added 'milestone-merge' label to PR #$pr_number."
|
||||
|
||||
@@ -25,11 +25,11 @@ jobs:
|
||||
with:
|
||||
path: main-repo
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
# - name: Set up QEMU
|
||||
# uses: docker/setup-qemu-action@v3.3.0
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
uses: docker/setup-buildx-action@v3.8.0
|
||||
|
||||
- name: Build Docker image
|
||||
id: build
|
||||
@@ -38,11 +38,8 @@ jobs:
|
||||
context: ./main-repo
|
||||
load: true
|
||||
tags: "openim/openim-server:local"
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
|
||||
- name: Save Docker image to file
|
||||
run: docker save -o image.tar openim/openim-server:local
|
||||
cache-from: type=gha,scope=build
|
||||
cache-to: type=gha,mode=max,scope=build
|
||||
|
||||
- name: Checkout compose repository
|
||||
uses: actions/checkout@v4
|
||||
@@ -66,43 +63,12 @@ jobs:
|
||||
run: |
|
||||
cd ${{ github.workspace }}/compose-repo
|
||||
docker compose up -d
|
||||
sleep 60
|
||||
|
||||
# - name: Check openim-server health
|
||||
# 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
|
||||
docker compose ps
|
||||
|
||||
- name: Extract metadata for Docker (tags, labels)
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5.5.1
|
||||
uses: docker/metadata-action@v5.6.0
|
||||
with:
|
||||
images: |
|
||||
openim/openim-server
|
||||
@@ -112,29 +78,27 @@ jobs:
|
||||
type=ref,event=tag
|
||||
type=schedule
|
||||
type=ref,event=branch
|
||||
type=semver,pattern={{version}}
|
||||
# type=semver,pattern={{version}}
|
||||
type=semver,pattern=v{{version}}
|
||||
type=semver,pattern={{major}}.{{minor}}
|
||||
type=semver,pattern={{major}}
|
||||
type=semver,pattern=release-{{raw}}
|
||||
type=sha
|
||||
type=raw,value=${{ github.event.inputs.tag }}
|
||||
|
||||
- name: Log in to Docker Hub
|
||||
uses: docker/login-action@v2
|
||||
uses: docker/login-action@v3.3.0
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||
|
||||
- name: Log in to GitHub Container Registry
|
||||
uses: docker/login-action@v2
|
||||
uses: docker/login-action@v3.3.0
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.repository_owner }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Log in to Aliyun Container Registry
|
||||
uses: docker/login-action@v2
|
||||
uses: docker/login-action@v3.3.0
|
||||
with:
|
||||
registry: registry.cn-hangzhou.aliyuncs.com
|
||||
username: ${{ secrets.ALIREGISTRY_USERNAME }}
|
||||
@@ -148,3 +112,28 @@ jobs:
|
||||
platforms: linux/amd64,linux/arm64
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
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
|
||||
|
||||
+10
-1
@@ -5,4 +5,13 @@ etcd:
|
||||
username: ''
|
||||
password: ''
|
||||
|
||||
|
||||
rpcService:
|
||||
user: user-rpc-service
|
||||
friend: friend-rpc-service
|
||||
msg: msg-rpc-service
|
||||
push: push-rpc-service
|
||||
messageGateway: messagegateway-rpc-service
|
||||
group: group-rpc-service
|
||||
auth: auth-rpc-service
|
||||
conversation: conversation-rpc-service
|
||||
third: third-rpc-service
|
||||
+17
-19
@@ -1,12 +1,10 @@
|
||||
groupCreated:
|
||||
isSendMsg: true
|
||||
# Reliability level of the message sending.
|
||||
# Set to 1 to send only when online, 2 for guaranteed delivery.
|
||||
# Deprecated. Fixed as 1.
|
||||
reliabilityLevel: 1
|
||||
# This setting is effective only when 'isSendMsg' is true.
|
||||
# It controls whether to count unread messages.
|
||||
# Deprecated. Fixed as false.
|
||||
unreadCount: false
|
||||
# Configuration for offline push notifications.
|
||||
# Configuration for offline push notifications.
|
||||
offlinePush:
|
||||
# Enables or disables offline push notifications.
|
||||
enable: false
|
||||
@@ -33,7 +31,7 @@ joinGroupApplication:
|
||||
reliabilityLevel: 1
|
||||
unreadCount: false
|
||||
offlinePush:
|
||||
enable: true
|
||||
enable: false
|
||||
title: joinGroupApplication title
|
||||
desc: joinGroupApplication desc
|
||||
ext: joinGroupApplication ext
|
||||
@@ -53,7 +51,7 @@ groupApplicationAccepted:
|
||||
reliabilityLevel: 1
|
||||
unreadCount: false
|
||||
offlinePush:
|
||||
enable: true
|
||||
enable: false
|
||||
title: groupApplicationAccepted title
|
||||
desc: groupApplicationAccepted desc
|
||||
ext: groupApplicationAccepted ext
|
||||
@@ -63,7 +61,7 @@ groupApplicationRejected:
|
||||
reliabilityLevel: 1
|
||||
unreadCount: false
|
||||
offlinePush:
|
||||
enable: true
|
||||
enable: false
|
||||
title: groupApplicationRejected title
|
||||
desc: groupApplicationRejected desc
|
||||
ext: groupApplicationRejected ext
|
||||
@@ -200,7 +198,7 @@ friendApplicationAdded:
|
||||
reliabilityLevel: 1
|
||||
unreadCount: false
|
||||
offlinePush:
|
||||
enable: true
|
||||
enable: false
|
||||
title: Somebody applies to add you as a friend
|
||||
desc: Somebody applies to add you as a friend
|
||||
ext: Somebody applies to add you as a friend
|
||||
@@ -230,7 +228,7 @@ friendAdded:
|
||||
reliabilityLevel: 1
|
||||
unreadCount: false
|
||||
offlinePush:
|
||||
enable: false
|
||||
enable: true
|
||||
title: We have become friends
|
||||
desc: We have become friends
|
||||
ext: We have become friends
|
||||
@@ -240,7 +238,7 @@ friendDeleted:
|
||||
reliabilityLevel: 1
|
||||
unreadCount: false
|
||||
offlinePush:
|
||||
enable: false
|
||||
enable: true
|
||||
title: deleted a friend
|
||||
desc: deleted a friend
|
||||
ext: deleted a friend
|
||||
@@ -250,7 +248,7 @@ friendRemarkSet:
|
||||
reliabilityLevel: 1
|
||||
unreadCount: false
|
||||
offlinePush:
|
||||
enable: false
|
||||
enable: true
|
||||
title: Your friend's profile has been changed
|
||||
desc: Your friend's profile has been changed
|
||||
ext: Your friend's profile has been changed
|
||||
@@ -260,7 +258,7 @@ blackAdded:
|
||||
reliabilityLevel: 1
|
||||
unreadCount: false
|
||||
offlinePush:
|
||||
enable: false
|
||||
enable: true
|
||||
title: blocked a user
|
||||
desc: blocked a user
|
||||
ext: blocked a user
|
||||
@@ -270,7 +268,7 @@ blackDeleted:
|
||||
reliabilityLevel: 1
|
||||
unreadCount: false
|
||||
offlinePush:
|
||||
enable: false
|
||||
enable: true
|
||||
title: Remove a blocked user
|
||||
desc: Remove a blocked user
|
||||
ext: Remove a blocked user
|
||||
@@ -280,7 +278,7 @@ friendInfoUpdated:
|
||||
reliabilityLevel: 1
|
||||
unreadCount: false
|
||||
offlinePush:
|
||||
enable: false
|
||||
enable: true
|
||||
title: friend info updated
|
||||
desc: friend info updated
|
||||
ext: friend info updated
|
||||
@@ -291,7 +289,7 @@ userInfoUpdated:
|
||||
reliabilityLevel: 1
|
||||
unreadCount: false
|
||||
offlinePush:
|
||||
enable: false
|
||||
enable: true
|
||||
title: userInfo updated
|
||||
desc: userInfo updated
|
||||
ext: userInfo updated
|
||||
@@ -312,7 +310,7 @@ conversationChanged:
|
||||
reliabilityLevel: 1
|
||||
unreadCount: false
|
||||
offlinePush:
|
||||
enable: false
|
||||
enable: true
|
||||
title: conversation changed
|
||||
desc: conversation changed
|
||||
ext: conversation changed
|
||||
@@ -322,7 +320,7 @@ conversationSetPrivate:
|
||||
reliabilityLevel: 1
|
||||
unreadCount: false
|
||||
offlinePush:
|
||||
enable: false
|
||||
enable: true
|
||||
title: burn after reading
|
||||
desc: burn after reading
|
||||
ext: burn after reading
|
||||
ext: burn after reading
|
||||
+1
-10
@@ -1,18 +1,9 @@
|
||||
secret: openIM123
|
||||
rpcRegisterName:
|
||||
user: user
|
||||
friend: friend
|
||||
msg: msg
|
||||
push: push
|
||||
messageGateway: messageGateway
|
||||
group: group
|
||||
auth: auth
|
||||
conversation: conversation
|
||||
third: third
|
||||
|
||||
imAdminUserID: [ imAdmin ]
|
||||
|
||||
# 1: For Android, iOS, Windows, Mac, and web platforms, only one instance can be online at a time
|
||||
multiLogin:
|
||||
policy: 1
|
||||
# max num of tokens in one end
|
||||
maxNumOneEnd: 30
|
||||
@@ -12,8 +12,8 @@ require (
|
||||
github.com/gorilla/websocket v1.5.1
|
||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0
|
||||
github.com/mitchellh/mapstructure v1.5.0
|
||||
github.com/openimsdk/protocol v0.0.72-alpha.78
|
||||
github.com/openimsdk/tools v0.0.50-alpha.74
|
||||
github.com/openimsdk/protocol v0.0.72-alpha.71
|
||||
github.com/openimsdk/tools v0.0.50-alpha.72
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/prometheus/client_golang v1.18.0
|
||||
github.com/stretchr/testify v1.9.0
|
||||
@@ -43,6 +43,9 @@ require (
|
||||
go.etcd.io/etcd/client/v3 v3.5.13
|
||||
go.uber.org/automaxprocs v1.5.3
|
||||
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 (
|
||||
@@ -198,9 +201,6 @@ require (
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
gorm.io/gorm v1.25.8 // indirect
|
||||
k8s.io/api v0.31.2 // indirect
|
||||
k8s.io/apimachinery v0.31.2 // indirect
|
||||
k8s.io/client-go v0.31.2 // indirect
|
||||
k8s.io/klog/v2 v2.130.1 // indirect
|
||||
k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 // indirect
|
||||
k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 // indirect
|
||||
|
||||
@@ -347,10 +347,10 @@ github.com/onsi/gomega v1.25.0 h1:Vw7br2PCDYijJHSfBOWhov+8cAnUf8MfMaIOV323l6Y=
|
||||
github.com/onsi/gomega v1.25.0/go.mod h1:r+zV744Re+DiYCIPRlYOTxn0YkOLcAnW8k1xXdMPGhM=
|
||||
github.com/openimsdk/gomake v0.0.14-alpha.5 h1:VY9c5x515lTfmdhhPjMvR3BBRrRquAUCFsz7t7vbv7Y=
|
||||
github.com/openimsdk/gomake v0.0.14-alpha.5/go.mod h1:PndCozNc2IsQIciyn9mvEblYWZwJmAI+06z94EY+csI=
|
||||
github.com/openimsdk/protocol v0.0.72-alpha.78 h1:n9HVj5olMPiGLF3Z4apPvvYzn2yOpyrsn2/YiAaIsxw=
|
||||
github.com/openimsdk/protocol v0.0.72-alpha.78/go.mod h1:WF7EuE55vQvpyUAzDXcqg+B+446xQyEba0X35lTINmw=
|
||||
github.com/openimsdk/tools v0.0.50-alpha.74 h1:yh10SiMiivMEjicEQg+QAsH4pvaO+4noMPdlw+ew0Kc=
|
||||
github.com/openimsdk/tools v0.0.50-alpha.74/go.mod h1:n2poR3asX1e1XZce4O+MOWAp+X02QJRFvhcLCXZdzRo=
|
||||
github.com/openimsdk/protocol v0.0.72-alpha.71 h1:R3utzOlqepaJWTAmnfJi4ccUM/XIoFasSyjQMOipM70=
|
||||
github.com/openimsdk/protocol v0.0.72-alpha.71/go.mod h1:WF7EuE55vQvpyUAzDXcqg+B+446xQyEba0X35lTINmw=
|
||||
github.com/openimsdk/tools v0.0.50-alpha.72 h1:d/vaZjIfvrNp3EeRJEIiamBO7HiPx6CP4wiuq8NpfzY=
|
||||
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/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
|
||||
github.com/pierrec/lz4/v4 v4.1.21 h1:yOVMLb6qSIDP67pl/5F7RepeKYu/VmTyEXvuMI5d9mQ=
|
||||
|
||||
+310
-311
@@ -1,313 +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})
|
||||
//}
|
||||
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})
|
||||
}
|
||||
|
||||
+60
-36
@@ -1,3 +1,17 @@
|
||||
// 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 (
|
||||
@@ -12,46 +26,45 @@ import (
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
||||
"github.com/openimsdk/tools/mw"
|
||||
"github.com/openimsdk/tools/utils/datautil"
|
||||
"github.com/openimsdk/tools/utils/network"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/credentials/insecure"
|
||||
|
||||
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/tools/discovery"
|
||||
"github.com/openimsdk/tools/discovery/etcd"
|
||||
"github.com/openimsdk/tools/errs"
|
||||
"github.com/openimsdk/tools/log"
|
||||
"github.com/openimsdk/tools/mw"
|
||||
"github.com/openimsdk/tools/system/program"
|
||||
"github.com/openimsdk/tools/utils/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 {
|
||||
API config.API
|
||||
Share config.Share
|
||||
Discovery config.Discovery
|
||||
*conf.AllConfig
|
||||
|
||||
RuntimeEnv string
|
||||
ConfigPath string
|
||||
}
|
||||
|
||||
func Start(ctx context.Context, index int, cfg *Config) error {
|
||||
apiPort, err := datautil.GetElemByIndex(cfg.API.Api.Ports, index)
|
||||
func Start(ctx context.Context, index int, config *Config) error {
|
||||
apiPort, err := datautil.GetElemByIndex(config.API.Api.Ports, index)
|
||||
if err != nil {
|
||||
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(&cfg.Discovery, &cfg.Share, []string{
|
||||
cfg.Share.RpcRegisterName.MessageGateway,
|
||||
client, err := kdisc.NewDiscoveryRegister(&config.Discovery, config.RuntimeEnv, []string{
|
||||
config.Discovery.RpcService.MessageGateway,
|
||||
})
|
||||
if err != nil {
|
||||
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")))
|
||||
client.AddOption(mw.GrpcClient(), grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithDefaultServiceConfig(fmt.Sprintf(`{"LoadBalancingPolicy": "%s"}`, "round_robin")))
|
||||
|
||||
var (
|
||||
netDone = make(chan struct{}, 1)
|
||||
@@ -59,10 +72,6 @@ func Start(ctx context.Context, index int, cfg *Config) error {
|
||||
prometheusPort int
|
||||
)
|
||||
|
||||
router, err := newGinRouter(ctx, client, cfg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
registerIP, err := network.GetRpcRegisterIP("")
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -79,16 +88,20 @@ func Start(ctx context.Context, index int, cfg *Config) error {
|
||||
return listener, port, nil
|
||||
}
|
||||
|
||||
if cfg.API.Prometheus.AutoSetPorts && cfg.Discovery.Enable != config.ETCD {
|
||||
if config.API.Prometheus.AutoSetPorts && config.Discovery.Enable != conf.ETCD {
|
||||
return errs.New("only etcd support autoSetPorts", "RegisterName", "api").Wrap()
|
||||
}
|
||||
|
||||
if cfg.API.Prometheus.Enable {
|
||||
router, err := newGinRouter(ctx, client, config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if config.API.Prometheus.Enable {
|
||||
var (
|
||||
listener net.Listener
|
||||
)
|
||||
|
||||
if cfg.API.Prometheus.AutoSetPorts {
|
||||
if config.API.Prometheus.AutoSetPorts {
|
||||
listener, prometheusPort, err = getAutoPort()
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -101,7 +114,7 @@ func Start(ctx context.Context, index int, cfg *Config) error {
|
||||
return errs.WrapMsg(err, "etcd put err")
|
||||
}
|
||||
} else {
|
||||
prometheusPort, err = datautil.GetElemByIndex(cfg.API.Prometheus.Ports, index)
|
||||
prometheusPort, err = datautil.GetElemByIndex(config.API.Prometheus.Ports, index)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -119,31 +132,42 @@ func Start(ctx context.Context, index int, cfg *Config) error {
|
||||
}()
|
||||
|
||||
}
|
||||
address := net.JoinHostPort(network.GetListenIP(cfg.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}
|
||||
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() {
|
||||
err = server.ListenAndServe()
|
||||
if err != nil && !errors.Is(err, http.ErrServerClosed) {
|
||||
netErr = errs.WrapMsg(err, fmt.Sprintf("api start err: %s", server.Addr))
|
||||
netDone <- struct{}{}
|
||||
|
||||
}
|
||||
}()
|
||||
|
||||
if config.Discovery.Enable == conf.ETCD {
|
||||
cm := disetcd.NewConfigManager(client.(*etcd.SvcDiscoveryRegistryImpl).GetClient(), config.GetConfigNames())
|
||||
cm.Watch(ctx)
|
||||
}
|
||||
|
||||
sigs := make(chan os.Signal, 1)
|
||||
signal.Notify(sigs, syscall.SIGTERM)
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
|
||||
defer cancel()
|
||||
select {
|
||||
case <-sigs:
|
||||
program.SIGTERMExit()
|
||||
shutdown := func() error {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
|
||||
defer cancel()
|
||||
err := server.Shutdown(ctx)
|
||||
if err != nil {
|
||||
return errs.WrapMsg(err, "shutdown err")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
disetcd.RegisterShutDown(shutdown)
|
||||
select {
|
||||
case <-sigs:
|
||||
program.SIGTERMExit()
|
||||
if err := shutdown(); err != nil {
|
||||
return err
|
||||
}
|
||||
case <-netDone:
|
||||
close(netDone)
|
||||
return netErr
|
||||
|
||||
@@ -2,6 +2,9 @@ package jssdk
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"strings"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/openimsdk/tools/a2r"
|
||||
"github.com/openimsdk/tools/apiresp"
|
||||
@@ -9,8 +12,6 @@ import (
|
||||
"github.com/openimsdk/tools/errs"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/protobuf/proto"
|
||||
"io"
|
||||
"strings"
|
||||
)
|
||||
|
||||
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) {
|
||||
|
||||
+31
-19
@@ -248,24 +248,44 @@ func (m *MessageApi) SendMessage(c *gin.Context) {
|
||||
|
||||
func (m *MessageApi) SendBusinessNotification(c *gin.Context) {
|
||||
req := struct {
|
||||
Key string `json:"key"`
|
||||
Data string `json:"data"`
|
||||
SendUserID string `json:"sendUserID" binding:"required"`
|
||||
RecvUserID string `json:"recvUserID" binding:"required"`
|
||||
Key string `json:"key"`
|
||||
Data string `json:"data"`
|
||||
SendUserID string `json:"sendUserID" 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 {
|
||||
apiresp.GinError(c, errs.ErrArgs.WithDetail(err.Error()).Wrap())
|
||||
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) {
|
||||
apiresp.GinError(c, errs.ErrNoPermission.WrapMsg("only app manager can send message"))
|
||||
return
|
||||
}
|
||||
sendMsgReq := msg.SendMsgReq{
|
||||
MsgData: &sdkws.MsgData{
|
||||
SendID: req.SendUserID,
|
||||
RecvID: req.RecvUserID,
|
||||
SendID: req.SendUserID,
|
||||
RecvID: req.RecvUserID,
|
||||
GroupID: req.RecvGroupID,
|
||||
Content: []byte(jsonutil.StructToJsonString(&sdkws.NotificationElem{
|
||||
Detail: jsonutil.StructToJsonString(&struct {
|
||||
Key string `json:"key"`
|
||||
@@ -274,14 +294,14 @@ func (m *MessageApi) SendBusinessNotification(c *gin.Context) {
|
||||
})),
|
||||
MsgFrom: constant.SysMsgType,
|
||||
ContentType: constant.BusinessNotification,
|
||||
SessionType: constant.SingleChatType,
|
||||
SessionType: sessionType,
|
||||
CreateTime: timeutil.GetCurrentTimestampByMill(),
|
||||
ClientMsgID: idutil.GetMsgIDByMD5(mcontext.GetOpUserID(c)),
|
||||
Options: config.GetOptionsByNotification(config.NotificationConfig{
|
||||
IsSendMsg: false,
|
||||
ReliabilityLevel: 1,
|
||||
IsSendMsg: req.SendMsg,
|
||||
ReliabilityLevel: *req.ReliabilityLevel,
|
||||
UnreadCount: false,
|
||||
}, nil),
|
||||
}),
|
||||
},
|
||||
}
|
||||
respPb, err := m.Client.SendMsg(c, &sendMsgReq)
|
||||
@@ -371,11 +391,3 @@ func (m *MessageApi) SearchMsg(c *gin.Context) {
|
||||
func (m *MessageApi) GetServerTime(c *gin.Context) {
|
||||
a2r.Call(c, msg.MsgClient.GetServerTime, m.Client)
|
||||
}
|
||||
|
||||
func (m *MessageApi) GetStreamMsg(c *gin.Context) {
|
||||
a2r.Call(c, msg.MsgClient.GetServerTime, m.Client)
|
||||
}
|
||||
|
||||
func (m *MessageApi) AppendStreamMsg(c *gin.Context) {
|
||||
a2r.Call(c, msg.MsgClient.GetServerTime, m.Client)
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
"net/http"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
||||
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"
|
||||
@@ -20,18 +20,18 @@ type PrometheusDiscoveryApi struct {
|
||||
client *clientv3.Client
|
||||
}
|
||||
|
||||
func NewPrometheusDiscoveryApi(cfg *Config, client discovery.SvcDiscoveryRegistry) *PrometheusDiscoveryApi {
|
||||
func NewPrometheusDiscoveryApi(config *Config, client discovery.SvcDiscoveryRegistry) *PrometheusDiscoveryApi {
|
||||
api := &PrometheusDiscoveryApi{
|
||||
config: cfg,
|
||||
config: config,
|
||||
}
|
||||
if cfg.Discovery.Enable == config.ETCD {
|
||||
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 != config.ETCD {
|
||||
if p.config.Discovery.Enable != conf.ETCD {
|
||||
c.JSON(http.StatusOK, []struct{}{})
|
||||
c.Abort()
|
||||
}
|
||||
@@ -74,39 +74,39 @@ func (p *PrometheusDiscoveryApi) Api(c *gin.Context) {
|
||||
}
|
||||
|
||||
func (p *PrometheusDiscoveryApi) User(c *gin.Context) {
|
||||
p.discovery(c, p.config.Share.RpcRegisterName.User)
|
||||
p.discovery(c, p.config.Discovery.RpcService.User)
|
||||
}
|
||||
|
||||
func (p *PrometheusDiscoveryApi) Group(c *gin.Context) {
|
||||
p.discovery(c, p.config.Share.RpcRegisterName.Group)
|
||||
p.discovery(c, p.config.Discovery.RpcService.Group)
|
||||
}
|
||||
|
||||
func (p *PrometheusDiscoveryApi) Msg(c *gin.Context) {
|
||||
p.discovery(c, p.config.Share.RpcRegisterName.Msg)
|
||||
p.discovery(c, p.config.Discovery.RpcService.Msg)
|
||||
}
|
||||
|
||||
func (p *PrometheusDiscoveryApi) Friend(c *gin.Context) {
|
||||
p.discovery(c, p.config.Share.RpcRegisterName.Friend)
|
||||
p.discovery(c, p.config.Discovery.RpcService.Friend)
|
||||
}
|
||||
|
||||
func (p *PrometheusDiscoveryApi) Conversation(c *gin.Context) {
|
||||
p.discovery(c, p.config.Share.RpcRegisterName.Conversation)
|
||||
p.discovery(c, p.config.Discovery.RpcService.Conversation)
|
||||
}
|
||||
|
||||
func (p *PrometheusDiscoveryApi) Third(c *gin.Context) {
|
||||
p.discovery(c, p.config.Share.RpcRegisterName.Third)
|
||||
p.discovery(c, p.config.Discovery.RpcService.Third)
|
||||
}
|
||||
|
||||
func (p *PrometheusDiscoveryApi) Auth(c *gin.Context) {
|
||||
p.discovery(c, p.config.Share.RpcRegisterName.Auth)
|
||||
p.discovery(c, p.config.Discovery.RpcService.Auth)
|
||||
}
|
||||
|
||||
func (p *PrometheusDiscoveryApi) Push(c *gin.Context) {
|
||||
p.discovery(c, p.config.Share.RpcRegisterName.Push)
|
||||
p.discovery(c, p.config.Discovery.RpcService.Push)
|
||||
}
|
||||
|
||||
func (p *PrometheusDiscoveryApi) MessageGateway(c *gin.Context) {
|
||||
p.discovery(c, p.config.Share.RpcRegisterName.MessageGateway)
|
||||
p.discovery(c, p.config.Discovery.RpcService.MessageGateway)
|
||||
}
|
||||
|
||||
func (p *PrometheusDiscoveryApi) MessageTransfer(c *gin.Context) {
|
||||
|
||||
+47
-26
@@ -5,29 +5,29 @@ import (
|
||||
"net/http"
|
||||
"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/servererrs"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/rpcli"
|
||||
pbAuth "github.com/openimsdk/protocol/auth"
|
||||
"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/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"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/servererrs"
|
||||
"github.com/openimsdk/protocol/constant"
|
||||
"github.com/openimsdk/tools/apiresp"
|
||||
"github.com/openimsdk/tools/discovery"
|
||||
"github.com/openimsdk/tools/discovery/etcd"
|
||||
"github.com/openimsdk/tools/log"
|
||||
"github.com/openimsdk/tools/mw"
|
||||
clientv3 "go.etcd.io/etcd/client/v3"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -52,32 +52,32 @@ func prommetricsGin() gin.HandlerFunc {
|
||||
}
|
||||
}
|
||||
|
||||
func newGinRouter(ctx context.Context, client discovery.SvcDiscoveryRegistry, config *Config) (*gin.Engine, error) {
|
||||
authConn, err := client.GetConn(ctx, config.Share.RpcRegisterName.Auth)
|
||||
func newGinRouter(ctx context.Context, client discovery.SvcDiscoveryRegistry, cfg *Config) (*gin.Engine, error) {
|
||||
authConn, err := client.GetConn(ctx, cfg.Discovery.RpcService.Auth)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
userConn, err := client.GetConn(ctx, config.Share.RpcRegisterName.User)
|
||||
userConn, err := client.GetConn(ctx, cfg.Discovery.RpcService.User)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
groupConn, err := client.GetConn(ctx, config.Share.RpcRegisterName.Group)
|
||||
groupConn, err := client.GetConn(ctx, cfg.Discovery.RpcService.Group)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
friendConn, err := client.GetConn(ctx, config.Share.RpcRegisterName.Friend)
|
||||
friendConn, err := client.GetConn(ctx, cfg.Discovery.RpcService.Friend)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
conversationConn, err := client.GetConn(ctx, config.Share.RpcRegisterName.Conversation)
|
||||
conversationConn, err := client.GetConn(ctx, cfg.Discovery.RpcService.Conversation)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
thirdConn, err := client.GetConn(ctx, config.Share.RpcRegisterName.Third)
|
||||
thirdConn, err := client.GetConn(ctx, cfg.Discovery.RpcService.Third)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
msgConn, err := client.GetConn(ctx, config.Share.RpcRegisterName.Msg)
|
||||
msgConn, err := client.GetConn(ctx, cfg.Discovery.RpcService.Msg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -86,7 +86,7 @@ func newGinRouter(ctx context.Context, client discovery.SvcDiscoveryRegistry, co
|
||||
if v, ok := binding.Validator.Engine().(*validator.Validate); ok {
|
||||
_ = v.RegisterValidation("required_if", RequiredIf)
|
||||
}
|
||||
switch config.API.Api.CompressionLevel {
|
||||
switch cfg.API.Api.CompressionLevel {
|
||||
case NoCompression:
|
||||
case DefaultCompression:
|
||||
r.Use(gzip.Gzip(gzip.DefaultCompression))
|
||||
@@ -95,11 +95,12 @@ func newGinRouter(ctx context.Context, client discovery.SvcDiscoveryRegistry, co
|
||||
case BestSpeed:
|
||||
r.Use(gzip.Gzip(gzip.BestSpeed))
|
||||
}
|
||||
r.Use(prommetricsGin(), gin.RecoveryWithWriter(gin.DefaultErrorWriter, mw.GinPanicErr), mw.CorsHandler(), mw.GinParseOperationID(), GinParseToken(rpcli.NewAuthClient(authConn)))
|
||||
u := NewUserApi(user.NewUserClient(userConn), client, config.Share.RpcRegisterName)
|
||||
m := NewMessageApi(msg.NewMsgClient(msgConn), rpcli.NewUserClient(userConn), config.Share.IMAdminUserID)
|
||||
userRouterGroup := r.Group("/user")
|
||||
r.Use(prommetricsGin(), gin.RecoveryWithWriter(gin.DefaultErrorWriter, mw.GinPanicErr), mw.CorsHandler(),
|
||||
mw.GinParseOperationID(), GinParseToken(rpcli.NewAuthClient(authConn)))
|
||||
|
||||
u := NewUserApi(user.NewUserClient(userConn), client, cfg.Discovery.RpcService)
|
||||
{
|
||||
userRouterGroup := r.Group("/user")
|
||||
userRouterGroup.POST("/user_register", u.UserRegister)
|
||||
userRouterGroup.POST("/update_user_info", u.UpdateUserInfo)
|
||||
userRouterGroup.POST("/update_user_info_ex", u.UpdateUserInfoEx)
|
||||
@@ -198,7 +199,7 @@ func newGinRouter(ctx context.Context, client discovery.SvcDiscoveryRegistry, co
|
||||
}
|
||||
// Third service
|
||||
{
|
||||
t := NewThirdApi(third.NewThirdClient(thirdConn), config.API.Prometheus.GrafanaURL)
|
||||
t := NewThirdApi(third.NewThirdClient(thirdConn), cfg.API.Prometheus.GrafanaURL)
|
||||
thirdGroup := r.Group("/third")
|
||||
thirdGroup.GET("/prometheus", t.GetPrometheus)
|
||||
thirdGroup.POST("/fcm_update_token", t.FcmUpdateToken)
|
||||
@@ -222,6 +223,7 @@ func newGinRouter(ctx context.Context, client discovery.SvcDiscoveryRegistry, co
|
||||
objectGroup.GET("/*name", t.ObjectRedirect)
|
||||
}
|
||||
// Message
|
||||
m := NewMessageApi(msg.NewMsgClient(msgConn), rpcli.NewUserClient(userConn), cfg.Share.IMAdminUserID)
|
||||
{
|
||||
msgGroup := r.Group("/msg")
|
||||
msgGroup.POST("/newest_seq", m.GetSeq)
|
||||
@@ -278,7 +280,7 @@ func newGinRouter(ctx context.Context, client discovery.SvcDiscoveryRegistry, co
|
||||
jssdk.POST("/get_active_conversations", j.GetActiveConversations)
|
||||
}
|
||||
{
|
||||
pd := NewPrometheusDiscoveryApi(config, client)
|
||||
pd := NewPrometheusDiscoveryApi(cfg, client)
|
||||
proDiscoveryGroup := r.Group("/prometheus_discovery", pd.Enable)
|
||||
proDiscoveryGroup.GET("/api", pd.Api)
|
||||
proDiscoveryGroup.GET("/user", pd.User)
|
||||
@@ -292,6 +294,25 @@ func newGinRouter(ctx context.Context, client discovery.SvcDiscoveryRegistry, co
|
||||
proDiscoveryGroup.GET("/msg_gateway", pd.MessageGateway)
|
||||
proDiscoveryGroup.GET("/msg_transfer", pd.MessageTransfer)
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
|
||||
@@ -30,10 +30,10 @@ import (
|
||||
type UserApi struct {
|
||||
Client user.UserClient
|
||||
discov discovery.SvcDiscoveryRegistry
|
||||
config config.RpcRegisterName
|
||||
config config.RpcService
|
||||
}
|
||||
|
||||
func NewUserApi(client user.UserClient, discov discovery.SvcDiscoveryRegistry, config config.RpcRegisterName) UserApi {
|
||||
func NewUserApi(client user.UserClient, discov discovery.SvcDiscoveryRegistry, config config.RpcService) UserApi {
|
||||
return UserApi{Client: client, discov: discov, config: config}
|
||||
}
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ import (
|
||||
)
|
||||
|
||||
func (s *Server) InitServer(ctx context.Context, config *Config, disCov discovery.SvcDiscoveryRegistry, server *grpc.Server) error {
|
||||
userConn, err := disCov.GetConn(ctx, config.Share.RpcRegisterName.User)
|
||||
userConn, err := disCov.GetConn(ctx, config.Discovery.RpcService.User)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -54,13 +54,19 @@ func (s *Server) InitServer(ctx context.Context, config *Config, disCov discover
|
||||
func (s *Server) Start(ctx context.Context, index int, conf *Config) error {
|
||||
return startrpc.Start(ctx, &conf.Discovery, &conf.MsgGateway.Prometheus, conf.MsgGateway.ListenIP,
|
||||
conf.MsgGateway.RPC.RegisterIP,
|
||||
conf.MsgGateway.RPC.AutoSetPorts,
|
||||
conf.MsgGateway.RPC.Ports, index,
|
||||
conf.Share.RpcRegisterName.MessageGateway,
|
||||
&conf.Share,
|
||||
conf.MsgGateway.RPC.AutoSetPorts, conf.MsgGateway.RPC.Ports, index,
|
||||
conf.Discovery.RpcService.MessageGateway,
|
||||
nil,
|
||||
conf,
|
||||
[]string{
|
||||
conf.Share.RpcRegisterName.MessageGateway,
|
||||
conf.Share.GetConfigFileName(),
|
||||
conf.Discovery.GetConfigFileName(),
|
||||
conf.MsgGateway.GetConfigFileName(),
|
||||
conf.WebhooksConfig.GetConfigFileName(),
|
||||
conf.RedisConfig.GetConfigFileName(),
|
||||
},
|
||||
[]string{
|
||||
conf.Discovery.RpcService.MessageGateway,
|
||||
},
|
||||
s.InitServer,
|
||||
)
|
||||
@@ -68,7 +74,7 @@ func (s *Server) Start(ctx context.Context, index int, conf *Config) error {
|
||||
|
||||
type Server struct {
|
||||
msggateway.UnimplementedMsgGatewayServer
|
||||
rpcPort int
|
||||
|
||||
LongConnServer LongConnServer
|
||||
config *Config
|
||||
pushTerminal map[int]struct{}
|
||||
|
||||
@@ -2,6 +2,7 @@ package msggateway
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"sync"
|
||||
@@ -10,18 +11,20 @@ import (
|
||||
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/rpcli"
|
||||
|
||||
"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/servererrs"
|
||||
"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/openimsdk/open-im-server/v3/pkg/common/prommetrics"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/servererrs"
|
||||
"github.com/openimsdk/protocol/constant"
|
||||
"github.com/openimsdk/protocol/msggateway"
|
||||
"github.com/openimsdk/tools/discovery"
|
||||
"github.com/openimsdk/tools/errs"
|
||||
"github.com/openimsdk/tools/log"
|
||||
"github.com/openimsdk/tools/mcontext"
|
||||
"github.com/openimsdk/tools/utils/stringutil"
|
||||
"golang.org/x/sync/errgroup"
|
||||
)
|
||||
@@ -73,19 +76,19 @@ type kickHandler struct {
|
||||
}
|
||||
|
||||
func (ws *WsServer) SetDiscoveryRegistry(ctx context.Context, disCov discovery.SvcDiscoveryRegistry, config *Config) error {
|
||||
userConn, err := disCov.GetConn(ctx, config.Share.RpcRegisterName.User)
|
||||
userConn, err := disCov.GetConn(ctx, config.Discovery.RpcService.User)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
pushConn, err := disCov.GetConn(ctx, config.Share.RpcRegisterName.Push)
|
||||
pushConn, err := disCov.GetConn(ctx, config.Discovery.RpcService.Push)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
authConn, err := disCov.GetConn(ctx, config.Share.RpcRegisterName.Auth)
|
||||
authConn, err := disCov.GetConn(ctx, config.Discovery.RpcService.Auth)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
msgConn, err := disCov.GetConn(ctx, config.Share.RpcRegisterName.Msg)
|
||||
msgConn, err := disCov.GetConn(ctx, config.Discovery.RpcService.Msg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -130,7 +133,7 @@ func NewWsServer(msgGatewayConfig *Config, opts ...Option) *WsServer {
|
||||
for _, o := range opts {
|
||||
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()
|
||||
return &WsServer{
|
||||
@@ -182,21 +185,28 @@ func (ws *WsServer) Run(done chan error) error {
|
||||
go func() {
|
||||
http.HandleFunc("/", ws.wsHandler)
|
||||
err := server.ListenAndServe()
|
||||
defer close(netDone)
|
||||
if err != nil && err != http.ErrServerClosed {
|
||||
if err != nil && !errors.Is(err, http.ErrServerClosed) {
|
||||
netErr = errs.WrapMsg(err, "ws start err", server.Addr)
|
||||
netDone <- struct{}{}
|
||||
}
|
||||
}()
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
|
||||
defer cancel()
|
||||
var err error
|
||||
select {
|
||||
case err = <-done:
|
||||
shutDown := func() error {
|
||||
sErr := server.Shutdown(ctx)
|
||||
if sErr != nil {
|
||||
return errs.WrapMsg(sErr, "shutdown err")
|
||||
}
|
||||
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 {
|
||||
return err
|
||||
}
|
||||
@@ -209,23 +219,19 @@ func (ws *WsServer) Run(done chan error) error {
|
||||
var concurrentRequest = 3
|
||||
|
||||
func (ws *WsServer) sendUserOnlineInfoToOtherNode(ctx context.Context, client *Client) error {
|
||||
conns, err := ws.disCov.GetConns(ctx, ws.msgGatewayConfig.Share.RpcRegisterName.MessageGateway)
|
||||
conns, err := ws.disCov.GetConns(ctx, ws.msgGatewayConfig.Discovery.RpcService.MessageGateway)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(conns) == 0 || (len(conns) == 1 && ws.disCov.IsSelfNode(conns[0])) {
|
||||
return nil
|
||||
}
|
||||
|
||||
wg := errgroup.Group{}
|
||||
wg.SetLimit(concurrentRequest)
|
||||
|
||||
// Online push user online message to other node
|
||||
for _, v := range conns {
|
||||
v := v
|
||||
log.ZDebug(ctx, "sendUserOnlineInfoToOtherNode conn")
|
||||
if ws.disCov.IsSelfNode(v) {
|
||||
log.ZDebug(ctx, "Filter out this node")
|
||||
log.ZDebug(ctx, " sendUserOnlineInfoToOtherNode conn ", "target", v.Target())
|
||||
if v.Target() == ws.disCov.GetSelfConnTarget() {
|
||||
log.ZDebug(ctx, "Filter out this node", "node", v.Target())
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -236,7 +242,7 @@ func (ws *WsServer) sendUserOnlineInfoToOtherNode(ctx context.Context, client *C
|
||||
PlatformID: int32(client.PlatformID), Token: client.token,
|
||||
})
|
||||
if err != nil {
|
||||
log.ZWarn(ctx, "MultiTerminalLoginCheck err", err)
|
||||
log.ZWarn(ctx, "MultiTerminalLoginCheck err", err, "node", v.Target())
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
@@ -25,6 +25,8 @@ import (
|
||||
"strconv"
|
||||
"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"
|
||||
@@ -35,10 +37,10 @@ import (
|
||||
"github.com/openimsdk/tools/db/mongoutil"
|
||||
"github.com/openimsdk/tools/db/redisutil"
|
||||
"github.com/openimsdk/tools/utils/datautil"
|
||||
"github.com/openimsdk/tools/utils/runtimeenv"
|
||||
|
||||
conf "github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
||||
discRegister "github.com/openimsdk/open-im-server/v3/pkg/common/discoveryregister"
|
||||
kdisc "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/tools/errs"
|
||||
"github.com/openimsdk/tools/log"
|
||||
@@ -57,6 +59,8 @@ type MsgTransfer struct {
|
||||
historyMongoCH *OnlineHistoryMongoConsumerHandler
|
||||
ctx context.Context
|
||||
cancel context.CancelFunc
|
||||
|
||||
runTimeEnv string
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
@@ -70,8 +74,9 @@ type Config struct {
|
||||
}
|
||||
|
||||
func Start(ctx context.Context, index int, config *Config) error {
|
||||
runTimeEnv := runtimeenv.PrintRuntimeEnvironment()
|
||||
|
||||
log.CInfo(ctx, "MSG-TRANSFER server is initializing", "prometheusPorts",
|
||||
log.CInfo(ctx, "MSG-TRANSFER server is initializing", "runTimeEnv", runTimeEnv, "prometheusPorts",
|
||||
config.MsgTransfer.Prometheus.Ports, "index", index)
|
||||
|
||||
mgocli, err := mongoutil.NewMongoDB(ctx, config.MongodbConfig.Build())
|
||||
@@ -82,13 +87,27 @@ func Start(ctx context.Context, index int, config *Config) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
client, err := discRegister.NewDiscoveryRegister(&config.Discovery, &config.Share, nil)
|
||||
client, err := discRegister.NewDiscoveryRegister(&config.Discovery, runTimeEnv, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
client.AddOption(mw.GrpcClient(), grpc.WithTransportCredentials(insecure.NewCredentials()),
|
||||
grpc.WithDefaultServiceConfig(fmt.Sprintf(`{"LoadBalancingPolicy": "%s"}`, "round_robin")))
|
||||
|
||||
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())
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -120,11 +139,13 @@ func Start(ctx context.Context, index int, config *Config) error {
|
||||
msgTransfer := &MsgTransfer{
|
||||
historyCH: historyCH,
|
||||
historyMongoCH: historyMongoCH,
|
||||
runTimeEnv: runTimeEnv,
|
||||
}
|
||||
return msgTransfer.Start(index, config)
|
||||
|
||||
return msgTransfer.Start(index, config, client)
|
||||
}
|
||||
|
||||
func (m *MsgTransfer) Start(index int, cfg *Config) error {
|
||||
func (m *MsgTransfer) Start(index int, config *Config, client discovery.SvcDiscoveryRegistry) error {
|
||||
m.ctx, m.cancel = context.WithCancel(context.Background())
|
||||
var (
|
||||
netDone = make(chan struct{}, 1)
|
||||
@@ -139,11 +160,6 @@ func (m *MsgTransfer) Start(index int, cfg *Config) error {
|
||||
return err
|
||||
}
|
||||
|
||||
client, err := kdisc.NewDiscoveryRegister(&cfg.Discovery, &cfg.Share, nil)
|
||||
if err != nil {
|
||||
return errs.WrapMsg(err, "failed to register discovery service")
|
||||
}
|
||||
|
||||
registerIP, err := network.GetRpcRegisterIP("")
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -160,17 +176,17 @@ func (m *MsgTransfer) Start(index int, cfg *Config) error {
|
||||
return listener, port, nil
|
||||
}
|
||||
|
||||
if cfg.MsgTransfer.Prometheus.AutoSetPorts && cfg.Discovery.Enable != conf.ETCD {
|
||||
if config.MsgTransfer.Prometheus.AutoSetPorts && config.Discovery.Enable != conf.ETCD {
|
||||
return errs.New("only etcd support autoSetPorts", "RegisterName", "api").Wrap()
|
||||
}
|
||||
|
||||
if cfg.MsgTransfer.Prometheus.Enable {
|
||||
if config.MsgTransfer.Prometheus.Enable {
|
||||
var (
|
||||
listener net.Listener
|
||||
prometheusPort int
|
||||
)
|
||||
|
||||
if cfg.MsgTransfer.Prometheus.AutoSetPorts {
|
||||
if config.MsgTransfer.Prometheus.AutoSetPorts {
|
||||
listener, prometheusPort, err = getAutoPort()
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -183,7 +199,7 @@ func (m *MsgTransfer) Start(index int, cfg *Config) error {
|
||||
return errs.WrapMsg(err, "etcd put err")
|
||||
}
|
||||
} else {
|
||||
prometheusPort, err = datautil.GetElemByIndex(cfg.MsgTransfer.Prometheus.Ports, index)
|
||||
prometheusPort, err = datautil.GetElemByIndex(config.MsgTransfer.Prometheus.Ports, index)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -25,12 +25,10 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics"
|
||||
|
||||
"github.com/IBM/sarama"
|
||||
"github.com/go-redis/redis"
|
||||
"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/kafka"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/msgprocessor"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/tools/batcher"
|
||||
"github.com/openimsdk/protocol/constant"
|
||||
@@ -39,6 +37,7 @@ import (
|
||||
"github.com/openimsdk/tools/errs"
|
||||
"github.com/openimsdk/tools/log"
|
||||
"github.com/openimsdk/tools/mcontext"
|
||||
"github.com/openimsdk/tools/mq/kafka"
|
||||
"github.com/openimsdk/tools/utils/stringutil"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
@@ -83,11 +82,11 @@ func NewOnlineHistoryRedisConsumerHandler(ctx context.Context, client discovery.
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
groupConn, err := client.GetConn(ctx, config.Share.RpcRegisterName.Group)
|
||||
groupConn, err := client.GetConn(ctx, config.Discovery.RpcService.Group)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
conversationConn, err := client.GetConn(ctx, config.Share.RpcRegisterName.Conversation)
|
||||
conversationConn, err := client.GetConn(ctx, config.Discovery.RpcService.Conversation)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -21,9 +21,9 @@ import (
|
||||
"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/kafka"
|
||||
pbmsg "github.com/openimsdk/protocol/msg"
|
||||
"github.com/openimsdk/tools/log"
|
||||
"github.com/openimsdk/tools/mq/kafka"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
|
||||
@@ -7,12 +7,12 @@ import (
|
||||
"github.com/openimsdk/open-im-server/v3/internal/push/offlinepush"
|
||||
"github.com/openimsdk/open-im-server/v3/internal/push/offlinepush/options"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/storage/kafka"
|
||||
"github.com/openimsdk/protocol/constant"
|
||||
pbpush "github.com/openimsdk/protocol/push"
|
||||
"github.com/openimsdk/protocol/sdkws"
|
||||
"github.com/openimsdk/tools/errs"
|
||||
"github.com/openimsdk/tools/log"
|
||||
"github.com/openimsdk/tools/mq/kafka"
|
||||
"github.com/openimsdk/tools/utils/jsonutil"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
@@ -2,15 +2,19 @@ package push
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"sync"
|
||||
|
||||
"github.com/openimsdk/protocol/msggateway"
|
||||
"github.com/openimsdk/protocol/sdkws"
|
||||
"github.com/openimsdk/tools/discovery"
|
||||
"github.com/openimsdk/tools/errs"
|
||||
"github.com/openimsdk/tools/log"
|
||||
"github.com/openimsdk/tools/utils/datautil"
|
||||
"golang.org/x/sync/errgroup"
|
||||
"google.golang.org/grpc"
|
||||
|
||||
conf "github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
||||
)
|
||||
|
||||
type OnlinePusher interface {
|
||||
@@ -38,15 +42,16 @@ func (u emptyOnlinePusher) GetOnlinePushFailedUserIDs(ctx context.Context, msg *
|
||||
}
|
||||
|
||||
func NewOnlinePusher(disCov discovery.SvcDiscoveryRegistry, config *Config) OnlinePusher {
|
||||
switch config.Discovery.Enable {
|
||||
case "k8s":
|
||||
return NewK8sStaticConsistentHash(disCov, config)
|
||||
case "zookeeper":
|
||||
|
||||
if config.runTimeEnv == conf.KUBERNETES {
|
||||
return NewDefaultAllNode(disCov, config)
|
||||
case "etcd":
|
||||
}
|
||||
switch config.Discovery.Enable {
|
||||
case conf.ETCD:
|
||||
return NewDefaultAllNode(disCov, config)
|
||||
default:
|
||||
return newEmptyOnlinePusher()
|
||||
log.ZError(context.Background(), "NewOnlinePusher is error", errs.Wrap(errors.New("unsupported discovery type")), "type", config.Discovery.Enable)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,7 +66,7 @@ func NewDefaultAllNode(disCov discovery.SvcDiscoveryRegistry, config *Config) *D
|
||||
|
||||
func (d *DefaultAllNode) GetConnsAndOnlinePush(ctx context.Context, msg *sdkws.MsgData,
|
||||
pushToUserIDs []string) (wsResults []*msggateway.SingleMsgToUserResults, err error) {
|
||||
conns, err := d.disCov.GetConns(ctx, d.config.Share.RpcRegisterName.MessageGateway)
|
||||
conns, err := d.disCov.GetConns(ctx, d.config.Discovery.RpcService.MessageGateway)
|
||||
if len(conns) == 0 {
|
||||
log.ZWarn(ctx, "get gateway conn 0 ", nil)
|
||||
} else {
|
||||
@@ -161,7 +166,7 @@ func (k *K8sStaticConsistentHash) GetConnsAndOnlinePush(ctx context.Context, msg
|
||||
}
|
||||
}
|
||||
log.ZDebug(ctx, "genUsers send hosts struct:", "usersHost", usersHost)
|
||||
var usersConns = make(map[grpc.ClientConnInterface][]string)
|
||||
var usersConns = make(map[*grpc.ClientConn][]string)
|
||||
for host, userIds := range usersHost {
|
||||
tconn, _ := k.disCov.GetConn(ctx, host)
|
||||
usersConns[tconn] = userIds
|
||||
|
||||
@@ -14,7 +14,6 @@ import (
|
||||
"github.com/openimsdk/open-im-server/v3/internal/push/offlinepush/options"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/storage/controller"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/storage/kafka"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/webhook"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/msgprocessor"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/rpccache"
|
||||
@@ -26,6 +25,7 @@ import (
|
||||
"github.com/openimsdk/tools/discovery"
|
||||
"github.com/openimsdk/tools/log"
|
||||
"github.com/openimsdk/tools/mcontext"
|
||||
"github.com/openimsdk/tools/mq/kafka"
|
||||
"github.com/openimsdk/tools/utils/datautil"
|
||||
"github.com/openimsdk/tools/utils/jsonutil"
|
||||
"github.com/openimsdk/tools/utils/timeutil"
|
||||
@@ -58,19 +58,19 @@ func NewConsumerHandler(ctx context.Context, config *Config, database controller
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
userConn, err := client.GetConn(ctx, config.Share.RpcRegisterName.User)
|
||||
userConn, err := client.GetConn(ctx, config.Discovery.RpcService.User)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
groupConn, err := client.GetConn(ctx, config.Share.RpcRegisterName.Group)
|
||||
groupConn, err := client.GetConn(ctx, config.Discovery.RpcService.Group)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
msgConn, err := client.GetConn(ctx, config.Share.RpcRegisterName.Msg)
|
||||
msgConn, err := client.GetConn(ctx, config.Discovery.RpcService.Msg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
conversationConn, err := client.GetConn(ctx, config.Share.RpcRegisterName.Conversation)
|
||||
conversationConn, err := client.GetConn(ctx, config.Discovery.RpcService.Conversation)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -208,10 +208,7 @@ func (c *ConsumerHandler) shouldPushOffline(_ context.Context, msg *sdkws.MsgDat
|
||||
if !isOfflinePush {
|
||||
return false
|
||||
}
|
||||
switch msg.ContentType {
|
||||
case constant.RoomParticipantsConnectedNotification:
|
||||
return false
|
||||
case constant.RoomParticipantsDisconnectedNotification:
|
||||
if msg.ContentType == constant.SignalingNotification {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
|
||||
@@ -60,7 +60,7 @@ func Start(ctx context.Context, config *Config, client discovery.SvcDiscoveryReg
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
userConn, err := client.GetConn(ctx, config.Share.RpcRegisterName.User)
|
||||
userConn, err := client.GetConn(ctx, config.Discovery.RpcService.User)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -187,12 +187,12 @@ func (s *authServer) ForceLogout(ctx context.Context, req *pbauth.ForceLogoutReq
|
||||
}
|
||||
|
||||
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 {
|
||||
return err
|
||||
}
|
||||
for _, v := range conns {
|
||||
log.ZDebug(ctx, "forceKickOff", "userID", userID, "platformID", platformID)
|
||||
log.ZDebug(ctx, "forceKickOff", "conn", v.Target())
|
||||
client := msggateway.NewMsgGatewayClient(v)
|
||||
kickReq := &msggateway.KickUserOfflineReq{KickUserIDList: []string{userID}, PlatformID: platformID}
|
||||
_, err := client.KickUserOffline(ctx, kickReq)
|
||||
|
||||
@@ -79,15 +79,15 @@ func Start(ctx context.Context, config *Config, client discovery.SvcDiscoveryReg
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
userConn, err := client.GetConn(ctx, config.Share.RpcRegisterName.User)
|
||||
userConn, err := client.GetConn(ctx, config.Discovery.RpcService.User)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
groupConn, err := client.GetConn(ctx, config.Share.RpcRegisterName.Group)
|
||||
groupConn, err := client.GetConn(ctx, config.Discovery.RpcService.Group)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
msgConn, err := client.GetConn(ctx, config.Share.RpcRegisterName.Msg)
|
||||
msgConn, err := client.GetConn(ctx, config.Discovery.RpcService.Msg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -238,12 +238,14 @@ func (c *conversationServer) SetConversations(ctx context.Context, req *pbconver
|
||||
if req.Conversation == nil {
|
||||
return nil, errs.ErrArgs.WrapMsg("conversation must not be nil")
|
||||
}
|
||||
|
||||
if req.Conversation.ConversationType == constant.WriteGroupChatType {
|
||||
groupInfo, err := c.groupClient.GetGroupInfo(ctx, req.Conversation.GroupID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if groupInfo == nil {
|
||||
return nil, servererrs.ErrGroupIDNotFound.WrapMsg(req.Conversation.GroupID)
|
||||
}
|
||||
if groupInfo.Status == constant.GroupStatusDismissed {
|
||||
return nil, servererrs.ErrDismissedAlready.WrapMsg("group dismissed")
|
||||
}
|
||||
|
||||
@@ -16,22 +16,21 @@ package conversation
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/notification"
|
||||
"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/notification"
|
||||
"github.com/openimsdk/protocol/constant"
|
||||
"github.com/openimsdk/protocol/sdkws"
|
||||
)
|
||||
|
||||
type ConversationNotificationSender struct {
|
||||
*notification.NotificationSender
|
||||
*rpcclient.NotificationSender
|
||||
}
|
||||
|
||||
func NewConversationNotificationSender(conf *config.Notification, msgClient *rpcli.MsgClient) *ConversationNotificationSender {
|
||||
return &ConversationNotificationSender{notification.NewNotificationSender(conf, notification.WithRpcClient(func(ctx context.Context, req *msg.SendMsgReq) (*msg.SendMsgResp, error) {
|
||||
return &ConversationNotificationSender{rpcclient.NewNotificationSender(conf, rpcclient.WithRpcClient(func(ctx context.Context, req *msg.SendMsgReq) (*msg.SendMsgResp, error) {
|
||||
return msgClient.SendMsg(ctx, req)
|
||||
}))}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@ package group
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
pbgroup "github.com/openimsdk/protocol/group"
|
||||
@@ -56,52 +55,41 @@ func UpdateGroupInfoMap(ctx context.Context, group *sdkws.GroupInfoForSet) map[s
|
||||
return m
|
||||
}
|
||||
|
||||
func UpdateGroupInfoExMap(ctx context.Context, group *pbgroup.SetGroupInfoExReq) (m map[string]any, normalFlag, groupNameFlag, notificationFlag bool, err error) {
|
||||
m = make(map[string]any)
|
||||
func UpdateGroupInfoExMap(ctx context.Context, group *pbgroup.SetGroupInfoExReq) (map[string]any, error) {
|
||||
m := make(map[string]any)
|
||||
|
||||
if group.GroupName != nil {
|
||||
if strings.TrimSpace(group.GroupName.Value) != "" {
|
||||
if group.GroupName.Value != "" {
|
||||
m["group_name"] = group.GroupName.Value
|
||||
groupNameFlag = true
|
||||
} else {
|
||||
return nil, normalFlag, notificationFlag, groupNameFlag, errs.ErrArgs.WrapMsg("group name is empty")
|
||||
return nil, errs.ErrArgs.WrapMsg("group name is empty")
|
||||
}
|
||||
}
|
||||
|
||||
if group.Notification != nil {
|
||||
notificationFlag = true
|
||||
group.Notification.Value = strings.TrimSpace(group.Notification.Value) // if Notification only contains spaces, set it to empty string
|
||||
|
||||
m["notification"] = group.Notification.Value
|
||||
m["notification_user_id"] = mcontext.GetOpUserID(ctx)
|
||||
m["notification_update_time"] = time.Now()
|
||||
m["notification_user_id"] = mcontext.GetOpUserID(ctx)
|
||||
}
|
||||
if group.Introduction != nil {
|
||||
m["introduction"] = group.Introduction.Value
|
||||
normalFlag = true
|
||||
}
|
||||
if group.FaceURL != nil {
|
||||
m["face_url"] = group.FaceURL.Value
|
||||
normalFlag = true
|
||||
}
|
||||
if group.NeedVerification != nil {
|
||||
m["need_verification"] = group.NeedVerification.Value
|
||||
normalFlag = true
|
||||
}
|
||||
if group.LookMemberInfo != nil {
|
||||
m["look_member_info"] = group.LookMemberInfo.Value
|
||||
normalFlag = true
|
||||
}
|
||||
if group.ApplyMemberFriend != nil {
|
||||
m["apply_member_friend"] = group.ApplyMemberFriend.Value
|
||||
normalFlag = true
|
||||
}
|
||||
if group.Ex != nil {
|
||||
m["ex"] = group.Ex.Value
|
||||
normalFlag = true
|
||||
}
|
||||
|
||||
return m, normalFlag, groupNameFlag, notificationFlag, nil
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func UpdateGroupStatusMap(status int) map[string]any {
|
||||
|
||||
+45
-55
@@ -17,30 +17,28 @@ package group
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/rpcli"
|
||||
"math/big"
|
||||
"math/rand"
|
||||
"strconv"
|
||||
"strings"
|
||||
"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/callbackstruct"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/convert"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/servererrs"
|
||||
"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/model"
|
||||
"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/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/notification/grouphash"
|
||||
"github.com/openimsdk/protocol/constant"
|
||||
pbconversation "github.com/openimsdk/protocol/conversation"
|
||||
pbconv "github.com/openimsdk/protocol/conversation"
|
||||
pbgroup "github.com/openimsdk/protocol/group"
|
||||
"github.com/openimsdk/protocol/sdkws"
|
||||
"github.com/openimsdk/protocol/wrapperspb"
|
||||
@@ -104,15 +102,15 @@ func Start(ctx context.Context, config *Config, client discovery.SvcDiscoveryReg
|
||||
//msgRpcClient := rpcclient.NewMessageRpcClient(client, config.Share.RpcRegisterName.Msg)
|
||||
//conversationRpcClient := rpcclient.NewConversationRpcClient(client, config.Share.RpcRegisterName.Conversation)
|
||||
|
||||
userConn, err := client.GetConn(ctx, config.Share.RpcRegisterName.User)
|
||||
userConn, err := client.GetConn(ctx, config.Discovery.RpcService.User)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
msgConn, err := client.GetConn(ctx, config.Share.RpcRegisterName.Msg)
|
||||
msgConn, err := client.GetConn(ctx, config.Discovery.RpcService.Msg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
conversationConn, err := client.GetConn(ctx, config.Share.RpcRegisterName.Conversation)
|
||||
conversationConn, err := client.GetConn(ctx, config.Discovery.RpcService.Conversation)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -290,14 +288,13 @@ func (g *groupServer) CreateGroup(ctx context.Context, req *pbgroup.CreateGroupR
|
||||
break
|
||||
}
|
||||
}
|
||||
g.notification.GroupCreatedNotification(ctx, tips, req.SendMessage)
|
||||
g.notification.GroupCreatedNotification(ctx, tips)
|
||||
|
||||
if req.GroupInfo.Notification != "" {
|
||||
notificationFlag := true
|
||||
g.notification.GroupInfoSetAnnouncementNotification(ctx, &sdkws.GroupInfoSetAnnouncementTips{
|
||||
Group: tips.Group,
|
||||
OpUser: tips.OpUser,
|
||||
}, ¬ificationFlag)
|
||||
})
|
||||
}
|
||||
|
||||
reqCallBackAfter := &pbgroup.CreateGroupReq{
|
||||
@@ -395,8 +392,6 @@ func (g *groupServer) InviteUserToGroup(ctx context.Context, req *pbgroup.Invite
|
||||
if err := g.PopulateGroupMember(ctx, groupMember); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
opUserID = mcontext.GetOpUserID(ctx)
|
||||
}
|
||||
|
||||
if err := g.webhookBeforeInviteUserToGroup(ctx, &g.config.WebhooksConfig.BeforeInviteUserToGroup, req); err != nil && err != servererrs.ErrCallbackContinue {
|
||||
@@ -432,7 +427,6 @@ func (g *groupServer) InviteUserToGroup(ctx context.Context, req *pbgroup.Invite
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var groupMembers []*model.GroupMember
|
||||
for _, userID := range req.InvitedUserIDs {
|
||||
member := &model.GroupMember{
|
||||
@@ -457,7 +451,7 @@ func (g *groupServer) InviteUserToGroup(ctx context.Context, req *pbgroup.Invite
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err = g.notification.GroupApplicationAgreeMemberEnterNotification(ctx, req.GroupID, req.SendMessage, opUserID, req.InvitedUserIDs...); err != nil {
|
||||
if err = g.notification.GroupApplicationAgreeMemberEnterNotification(ctx, req.GroupID, opUserID, req.InvitedUserIDs...); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &pbgroup.InviteUserToGroupResp{}, nil
|
||||
@@ -623,7 +617,7 @@ func (g *groupServer) KickGroupMember(ctx context.Context, req *pbgroup.KickGrou
|
||||
for _, userID := range req.KickedUserIDs {
|
||||
tips.KickedUserList = append(tips.KickedUserList, convert.Db2PbGroupMember(memberMap[userID]))
|
||||
}
|
||||
g.notification.MemberKickedNotification(ctx, tips, req.SendMessage)
|
||||
g.notification.MemberKickedNotification(ctx, tips)
|
||||
if err := g.deleteMemberAndSetConversationSeq(ctx, req.GroupID, req.KickedUserIDs); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -832,14 +826,8 @@ func (g *groupServer) GroupApplicationResponse(ctx context.Context, req *pbgroup
|
||||
if member == nil {
|
||||
log.ZDebug(ctx, "GroupApplicationResponse", "member is nil")
|
||||
} else {
|
||||
if groupRequest.InviterUserID == "" {
|
||||
if err = g.notification.MemberEnterNotification(ctx, req.GroupID, req.FromUserID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
if err = g.notification.GroupApplicationAgreeMemberEnterNotification(ctx, req.GroupID, nil, groupRequest.InviterUserID, req.FromUserID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = g.notification.GroupApplicationAgreeMemberEnterNotification(ctx, req.GroupID, groupRequest.InviterUserID, req.FromUserID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
case constant.GroupResponseRefuse:
|
||||
@@ -1026,7 +1014,7 @@ func (g *groupServer) SetGroupInfo(ctx context.Context, req *pbgroup.SetGroupInf
|
||||
if req.GroupInfoForSet.Notification != "" {
|
||||
num -= 3
|
||||
func() {
|
||||
conversation := &pbconversation.ConversationReq{
|
||||
conversation := &pbconv.ConversationReq{
|
||||
ConversationID: msgprocessor.GetConversationIDBySessionType(constant.ReadGroupChatType, req.GroupInfoForSet.GroupID),
|
||||
ConversationType: constant.ReadGroupChatType,
|
||||
GroupID: req.GroupInfoForSet.GroupID,
|
||||
@@ -1041,8 +1029,7 @@ func (g *groupServer) SetGroupInfo(ctx context.Context, req *pbgroup.SetGroupInf
|
||||
log.ZWarn(ctx, "SetConversations", err, "UserIDs", resp.UserIDs, "conversation", conversation)
|
||||
}
|
||||
}()
|
||||
notficationFlag := true
|
||||
g.notification.GroupInfoSetAnnouncementNotification(ctx, &sdkws.GroupInfoSetAnnouncementTips{Group: tips.Group, OpUser: tips.OpUser}, ¬ficationFlag)
|
||||
g.notification.GroupInfoSetAnnouncementNotification(ctx, &sdkws.GroupInfoSetAnnouncementTips{Group: tips.Group, OpUser: tips.OpUser})
|
||||
}
|
||||
if req.GroupInfoForSet.GroupName != "" {
|
||||
num--
|
||||
@@ -1103,7 +1090,7 @@ func (g *groupServer) SetGroupInfoEx(ctx context.Context, req *pbgroup.SetGroupI
|
||||
return nil, err
|
||||
}
|
||||
|
||||
updatedData, normalFlag, groupNameFlag, notificationFlag, err := UpdateGroupInfoExMap(ctx, req)
|
||||
updatedData, err := UpdateGroupInfoExMap(ctx, req)
|
||||
if len(updatedData) == 0 {
|
||||
return &pbgroup.SetGroupInfoExResp{}, nil
|
||||
}
|
||||
@@ -1131,38 +1118,41 @@ func (g *groupServer) SetGroupInfoEx(ctx context.Context, req *pbgroup.SetGroupI
|
||||
tips.OpUser = g.groupMemberDB2PB(opMember, 0)
|
||||
}
|
||||
|
||||
if notificationFlag {
|
||||
num := len(updatedData)
|
||||
|
||||
if req.Notification != nil {
|
||||
num -= 3
|
||||
|
||||
if req.Notification.Value != "" {
|
||||
conversation := &pbconversation.ConversationReq{
|
||||
ConversationID: msgprocessor.GetConversationIDBySessionType(constant.ReadGroupChatType, req.GroupID),
|
||||
ConversationType: constant.ReadGroupChatType,
|
||||
GroupID: req.GroupID,
|
||||
}
|
||||
func() {
|
||||
conversation := &pbconv.ConversationReq{
|
||||
ConversationID: msgprocessor.GetConversationIDBySessionType(constant.ReadGroupChatType, req.GroupID),
|
||||
ConversationType: constant.ReadGroupChatType,
|
||||
GroupID: req.GroupID,
|
||||
}
|
||||
|
||||
resp, err := g.GetGroupMemberUserIDs(ctx, &pbgroup.GetGroupMemberUserIDsReq{GroupID: req.GroupID})
|
||||
if err != nil {
|
||||
log.ZWarn(ctx, "GetGroupMemberIDs is failed.", err)
|
||||
return nil, err
|
||||
}
|
||||
resp, err := g.GetGroupMemberUserIDs(ctx, &pbgroup.GetGroupMemberUserIDsReq{GroupID: req.GroupID})
|
||||
if err != nil {
|
||||
log.ZWarn(ctx, "GetGroupMemberIDs is failed.", err)
|
||||
return
|
||||
}
|
||||
|
||||
conversation.GroupAtType = &wrapperspb.Int32Value{Value: constant.GroupNotification}
|
||||
if err := g.conversationClient.SetConversations(ctx, resp.UserIDs, conversation); err != nil {
|
||||
log.ZWarn(ctx, "SetConversations", err, "UserIDs", resp.UserIDs, "conversation", conversation)
|
||||
}
|
||||
conversation.GroupAtType = &wrapperspb.Int32Value{Value: constant.GroupNotification}
|
||||
if err := g.conversationClient.SetConversations(ctx, resp.UserIDs, conversation); err != nil {
|
||||
log.ZWarn(ctx, "SetConversations", err, "UserIDs", resp.UserIDs, "conversation", conversation)
|
||||
}
|
||||
}()
|
||||
|
||||
g.notification.GroupInfoSetAnnouncementNotification(ctx, &sdkws.GroupInfoSetAnnouncementTips{Group: tips.Group, OpUser: tips.OpUser}, ¬ificationFlag)
|
||||
} else {
|
||||
notificationFlag = false
|
||||
g.notification.GroupInfoSetAnnouncementNotification(ctx, &sdkws.GroupInfoSetAnnouncementTips{Group: tips.Group, OpUser: tips.OpUser}, ¬ificationFlag)
|
||||
g.notification.GroupInfoSetAnnouncementNotification(ctx, &sdkws.GroupInfoSetAnnouncementTips{Group: tips.Group, OpUser: tips.OpUser})
|
||||
}
|
||||
}
|
||||
|
||||
if groupNameFlag {
|
||||
if req.GroupName != nil {
|
||||
num--
|
||||
g.notification.GroupInfoSetNameNotification(ctx, &sdkws.GroupInfoSetNameTips{Group: tips.Group, OpUser: tips.OpUser})
|
||||
}
|
||||
|
||||
// if updatedData > 0, send the normal notification
|
||||
if normalFlag {
|
||||
if num > 0 {
|
||||
g.notification.GroupInfoSetNotification(ctx, tips)
|
||||
}
|
||||
|
||||
@@ -1382,7 +1372,7 @@ func (g *groupServer) DismissGroup(ctx context.Context, req *pbgroup.DismissGrou
|
||||
if mcontext.GetOpUserID(ctx) == owner.UserID {
|
||||
tips.OpUser = g.groupMemberDB2PB(owner, 0)
|
||||
}
|
||||
g.notification.GroupDismissedNotification(ctx, tips, req.SendMessage)
|
||||
g.notification.GroupDismissedNotification(ctx, tips)
|
||||
}
|
||||
membersID, err := g.db.FindGroupMemberUserID(ctx, group.GroupID)
|
||||
if err != nil {
|
||||
|
||||
@@ -52,11 +52,11 @@ const (
|
||||
|
||||
func NewNotificationSender(db controller.GroupDatabase, config *Config, userClient *rpcli.UserClient, msgClient *rpcli.MsgClient, conversationClient *rpcli.ConversationClient) *NotificationSender {
|
||||
return &NotificationSender{
|
||||
NotificationSender: notification.NewNotificationSender(&config.NotificationConfig,
|
||||
notification.WithRpcClient(func(ctx context.Context, req *msg.SendMsgReq) (*msg.SendMsgResp, error) {
|
||||
NotificationSender: rpcclient.NewNotificationSender(&config.NotificationConfig,
|
||||
rpcclient.WithRpcClient(func(ctx context.Context, req *msg.SendMsgReq) (*msg.SendMsgResp, error) {
|
||||
return msgClient.SendMsg(ctx, req)
|
||||
}),
|
||||
notification.WithUserRpcClient(userClient.GetUserInfo),
|
||||
rpcclient.WithUserRpcClient(userClient.GetUserInfo),
|
||||
),
|
||||
getUsersInfo: func(ctx context.Context, userIDs []string) ([]common_user.CommonUser, error) {
|
||||
users, err := userClient.GetUsersInfo(ctx, userIDs)
|
||||
@@ -73,7 +73,7 @@ func NewNotificationSender(db controller.GroupDatabase, config *Config, userClie
|
||||
}
|
||||
|
||||
type NotificationSender struct {
|
||||
*notification.NotificationSender
|
||||
*rpcclient.NotificationSender
|
||||
getUsersInfo func(ctx context.Context, userIDs []string) ([]common_user.CommonUser, error)
|
||||
db controller.GroupDatabase
|
||||
config *Config
|
||||
@@ -233,17 +233,17 @@ func (g *NotificationSender) groupMemberDB2PB(member *model.GroupMember, appMang
|
||||
return result, nil
|
||||
} */
|
||||
|
||||
func (g *NotificationSender) fillOpUser(ctx context.Context, targetUser **sdkws.GroupMemberFullInfo, groupID string) (err error) {
|
||||
return g.fillUserByUserID(ctx, mcontext.GetOpUserID(ctx), targetUser, groupID)
|
||||
func (g *NotificationSender) fillOpUser(ctx context.Context, opUser **sdkws.GroupMemberFullInfo, groupID string) (err error) {
|
||||
return g.fillOpUserByUserID(ctx, mcontext.GetOpUserID(ctx), opUser, groupID)
|
||||
}
|
||||
|
||||
func (g *NotificationSender) fillUserByUserID(ctx context.Context, userID string, targetUser **sdkws.GroupMemberFullInfo, groupID string) error {
|
||||
if targetUser == nil {
|
||||
func (g *NotificationSender) fillOpUserByUserID(ctx context.Context, userID string, opUser **sdkws.GroupMemberFullInfo, groupID string) error {
|
||||
if opUser == nil {
|
||||
return errs.ErrInternalServer.WrapMsg("**sdkws.GroupMemberFullInfo is nil")
|
||||
}
|
||||
if groupID != "" {
|
||||
if authverify.IsManagerUserID(userID, g.config.Share.IMAdminUserID) {
|
||||
*targetUser = &sdkws.GroupMemberFullInfo{
|
||||
*opUser = &sdkws.GroupMemberFullInfo{
|
||||
GroupID: groupID,
|
||||
UserID: userID,
|
||||
RoleLevel: constant.GroupAdmin,
|
||||
@@ -252,7 +252,7 @@ func (g *NotificationSender) fillUserByUserID(ctx context.Context, userID string
|
||||
} else {
|
||||
member, err := g.db.TakeGroupMember(ctx, groupID, userID)
|
||||
if err == nil {
|
||||
*targetUser = g.groupMemberDB2PB(member, 0)
|
||||
*opUser = g.groupMemberDB2PB(member, 0)
|
||||
} else if !(errors.Is(err, mongo.ErrNoDocuments) || errs.ErrRecordNotFound.Is(err)) {
|
||||
return err
|
||||
}
|
||||
@@ -262,8 +262,8 @@ func (g *NotificationSender) fillUserByUserID(ctx context.Context, userID string
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if *targetUser == nil {
|
||||
*targetUser = &sdkws.GroupMemberFullInfo{
|
||||
if *opUser == nil {
|
||||
*opUser = &sdkws.GroupMemberFullInfo{
|
||||
GroupID: groupID,
|
||||
UserID: userID,
|
||||
Nickname: user.Nickname,
|
||||
@@ -271,11 +271,11 @@ func (g *NotificationSender) fillUserByUserID(ctx context.Context, userID string
|
||||
OperatorUserID: userID,
|
||||
}
|
||||
} else {
|
||||
if (*targetUser).Nickname == "" {
|
||||
(*targetUser).Nickname = user.Nickname
|
||||
if (*opUser).Nickname == "" {
|
||||
(*opUser).Nickname = user.Nickname
|
||||
}
|
||||
if (*targetUser).FaceURL == "" {
|
||||
(*targetUser).FaceURL = user.FaceURL
|
||||
if (*opUser).FaceURL == "" {
|
||||
(*opUser).FaceURL = user.FaceURL
|
||||
}
|
||||
}
|
||||
return nil
|
||||
@@ -307,7 +307,7 @@ func (g *NotificationSender) setSortVersion(ctx context.Context, version *uint64
|
||||
}
|
||||
}
|
||||
|
||||
func (g *NotificationSender) GroupCreatedNotification(ctx context.Context, tips *sdkws.GroupCreatedTips, SendMessage *bool) {
|
||||
func (g *NotificationSender) GroupCreatedNotification(ctx context.Context, tips *sdkws.GroupCreatedTips) {
|
||||
var err error
|
||||
defer func() {
|
||||
if err != nil {
|
||||
@@ -318,7 +318,7 @@ func (g *NotificationSender) GroupCreatedNotification(ctx context.Context, tips
|
||||
return
|
||||
}
|
||||
g.setVersion(ctx, &tips.GroupMemberVersion, &tips.GroupMemberVersionID, database.GroupMemberVersionName, tips.Group.GroupID)
|
||||
g.Notification(ctx, mcontext.GetOpUserID(ctx), tips.Group.GroupID, constant.GroupCreatedNotification, tips, notification.WithSendMessage(SendMessage))
|
||||
g.Notification(ctx, mcontext.GetOpUserID(ctx), tips.Group.GroupID, constant.GroupCreatedNotification, tips)
|
||||
}
|
||||
|
||||
func (g *NotificationSender) GroupInfoSetNotification(ctx context.Context, tips *sdkws.GroupInfoSetTips) {
|
||||
@@ -332,7 +332,7 @@ func (g *NotificationSender) GroupInfoSetNotification(ctx context.Context, tips
|
||||
return
|
||||
}
|
||||
g.setVersion(ctx, &tips.GroupMemberVersion, &tips.GroupMemberVersionID, database.GroupMemberVersionName, tips.Group.GroupID)
|
||||
g.Notification(ctx, mcontext.GetOpUserID(ctx), tips.Group.GroupID, constant.GroupInfoSetNotification, tips, notification.WithRpcGetUserName())
|
||||
g.Notification(ctx, mcontext.GetOpUserID(ctx), tips.Group.GroupID, constant.GroupInfoSetNotification, tips, rpcclient.WithRpcGetUserName())
|
||||
}
|
||||
|
||||
func (g *NotificationSender) GroupInfoSetNameNotification(ctx context.Context, tips *sdkws.GroupInfoSetNameTips) {
|
||||
@@ -349,7 +349,7 @@ func (g *NotificationSender) GroupInfoSetNameNotification(ctx context.Context, t
|
||||
g.Notification(ctx, mcontext.GetOpUserID(ctx), tips.Group.GroupID, constant.GroupInfoSetNameNotification, tips)
|
||||
}
|
||||
|
||||
func (g *NotificationSender) GroupInfoSetAnnouncementNotification(ctx context.Context, tips *sdkws.GroupInfoSetAnnouncementTips, sendMessage *bool) {
|
||||
func (g *NotificationSender) GroupInfoSetAnnouncementNotification(ctx context.Context, tips *sdkws.GroupInfoSetAnnouncementTips) {
|
||||
var err error
|
||||
defer func() {
|
||||
if err != nil {
|
||||
@@ -360,7 +360,7 @@ func (g *NotificationSender) GroupInfoSetAnnouncementNotification(ctx context.Co
|
||||
return
|
||||
}
|
||||
g.setVersion(ctx, &tips.GroupMemberVersion, &tips.GroupMemberVersionID, database.GroupMemberVersionName, tips.Group.GroupID)
|
||||
g.Notification(ctx, mcontext.GetOpUserID(ctx), tips.Group.GroupID, constant.GroupInfoSetAnnouncementNotification, tips, notification.WithRpcGetUserName(), notification.WithSendMessage(sendMessage))
|
||||
g.Notification(ctx, mcontext.GetOpUserID(ctx), tips.Group.GroupID, constant.GroupInfoSetAnnouncementNotification, tips, rpcclient.WithRpcGetUserName())
|
||||
}
|
||||
|
||||
func (g *NotificationSender) JoinGroupApplicationNotification(ctx context.Context, req *pbgroup.JoinGroupReq) {
|
||||
@@ -505,7 +505,7 @@ func (g *NotificationSender) GroupOwnerTransferredNotification(ctx context.Conte
|
||||
g.Notification(ctx, mcontext.GetOpUserID(ctx), group.GroupID, constant.GroupOwnerTransferredNotification, tips)
|
||||
}
|
||||
|
||||
func (g *NotificationSender) MemberKickedNotification(ctx context.Context, tips *sdkws.MemberKickedTips, SendMessage *bool) {
|
||||
func (g *NotificationSender) MemberKickedNotification(ctx context.Context, tips *sdkws.MemberKickedTips) {
|
||||
var err error
|
||||
defer func() {
|
||||
if err != nil {
|
||||
@@ -516,10 +516,10 @@ func (g *NotificationSender) MemberKickedNotification(ctx context.Context, tips
|
||||
return
|
||||
}
|
||||
g.setVersion(ctx, &tips.GroupMemberVersion, &tips.GroupMemberVersionID, database.GroupMemberVersionName, tips.Group.GroupID)
|
||||
g.Notification(ctx, mcontext.GetOpUserID(ctx), tips.Group.GroupID, constant.MemberKickedNotification, tips, notification.WithSendMessage(SendMessage))
|
||||
g.Notification(ctx, mcontext.GetOpUserID(ctx), tips.Group.GroupID, constant.MemberKickedNotification, tips)
|
||||
}
|
||||
|
||||
func (g *NotificationSender) GroupApplicationAgreeMemberEnterNotification(ctx context.Context, groupID string, SendMessage *bool, invitedOpUserID string, entrantUserID ...string) error {
|
||||
func (g *NotificationSender) GroupApplicationAgreeMemberEnterNotification(ctx context.Context, groupID string, invitedOpUserID string, entrantUserID ...string) error {
|
||||
var err error
|
||||
defer func() {
|
||||
if err != nil {
|
||||
@@ -556,18 +556,20 @@ func (g *NotificationSender) GroupApplicationAgreeMemberEnterNotification(ctx co
|
||||
InvitedUserList: users,
|
||||
}
|
||||
opUserID := mcontext.GetOpUserID(ctx)
|
||||
if err = g.fillUserByUserID(ctx, opUserID, &tips.OpUser, tips.Group.GroupID); err != nil {
|
||||
if err = g.fillOpUserByUserID(ctx, opUserID, &tips.OpUser, tips.Group.GroupID); err != nil {
|
||||
return nil
|
||||
}
|
||||
if invitedOpUserID == opUserID {
|
||||
switch {
|
||||
case invitedOpUserID == "":
|
||||
case invitedOpUserID == opUserID:
|
||||
tips.InviterUser = tips.OpUser
|
||||
} else {
|
||||
if err = g.fillUserByUserID(ctx, invitedOpUserID, &tips.InviterUser, tips.Group.GroupID); err != nil {
|
||||
default:
|
||||
if err = g.fillOpUserByUserID(ctx, invitedOpUserID, &tips.InviterUser, tips.Group.GroupID); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
g.setVersion(ctx, &tips.GroupMemberVersion, &tips.GroupMemberVersionID, database.GroupMemberVersionName, tips.Group.GroupID)
|
||||
g.Notification(ctx, mcontext.GetOpUserID(ctx), group.GroupID, constant.MemberInvitedNotification, tips, notification.WithSendMessage(SendMessage))
|
||||
g.Notification(ctx, mcontext.GetOpUserID(ctx), group.GroupID, constant.MemberInvitedNotification, tips)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -612,7 +614,7 @@ func (g *NotificationSender) MemberEnterNotification(ctx context.Context, groupI
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *NotificationSender) GroupDismissedNotification(ctx context.Context, tips *sdkws.GroupDismissedTips, SendMessage *bool) {
|
||||
func (g *NotificationSender) GroupDismissedNotification(ctx context.Context, tips *sdkws.GroupDismissedTips) {
|
||||
var err error
|
||||
defer func() {
|
||||
if err != nil {
|
||||
@@ -622,7 +624,7 @@ func (g *NotificationSender) GroupDismissedNotification(ctx context.Context, tip
|
||||
if err = g.fillOpUser(ctx, &tips.OpUser, tips.Group.GroupID); err != nil {
|
||||
return
|
||||
}
|
||||
g.Notification(ctx, mcontext.GetOpUserID(ctx), tips.Group.GroupID, constant.GroupDismissedNotification, tips, notification.WithSendMessage(SendMessage))
|
||||
g.Notification(ctx, mcontext.GetOpUserID(ctx), tips.Group.GroupID, constant.GroupDismissedNotification, tips)
|
||||
}
|
||||
|
||||
func (g *NotificationSender) GroupMemberMutedNotification(ctx context.Context, groupID, groupMemberUserID string, mutedSeconds uint32) {
|
||||
@@ -779,7 +781,7 @@ func (g *NotificationSender) GroupMemberSetToAdminNotification(ctx context.Conte
|
||||
if err = g.fillOpUser(ctx, &tips.OpUser, tips.Group.GroupID); err != nil {
|
||||
return
|
||||
}
|
||||
g.setSortVersion(ctx, &tips.GroupMemberVersion, &tips.GroupMemberVersionID, database.GroupMemberVersionName, tips.Group.GroupID, &tips.GroupSortVersion)
|
||||
g.setVersion(ctx, &tips.GroupMemberVersion, &tips.GroupMemberVersionID, database.GroupMemberVersionName, tips.Group.GroupID)
|
||||
g.Notification(ctx, mcontext.GetOpUserID(ctx), group.GroupID, constant.GroupMemberSetToAdminNotification, tips)
|
||||
}
|
||||
|
||||
@@ -804,6 +806,6 @@ func (g *NotificationSender) GroupMemberSetToOrdinaryUserNotification(ctx contex
|
||||
if err = g.fillOpUser(ctx, &tips.OpUser, tips.Group.GroupID); err != nil {
|
||||
return
|
||||
}
|
||||
g.setSortVersion(ctx, &tips.GroupMemberVersion, &tips.GroupMemberVersionID, database.GroupMemberVersionName, tips.Group.GroupID, &tips.GroupSortVersion)
|
||||
g.setVersion(ctx, &tips.GroupMemberVersion, &tips.GroupMemberVersionID, database.GroupMemberVersionName, tips.Group.GroupID)
|
||||
g.Notification(ctx, mcontext.GetOpUserID(ctx), group.GroupID, constant.GroupMemberSetToOrdinaryUserNotification, tips)
|
||||
}
|
||||
|
||||
+154
-30
@@ -11,16 +11,16 @@ import (
|
||||
"github.com/openimsdk/protocol/constant"
|
||||
pbgroup "github.com/openimsdk/protocol/group"
|
||||
"github.com/openimsdk/protocol/sdkws"
|
||||
"github.com/openimsdk/tools/errs"
|
||||
"github.com/openimsdk/tools/log"
|
||||
)
|
||||
|
||||
const versionSyncLimit = 500
|
||||
|
||||
func (g *groupServer) GetFullGroupMemberUserIDs(ctx context.Context, req *pbgroup.GetFullGroupMemberUserIDsReq) (*pbgroup.GetFullGroupMemberUserIDsResp, error) {
|
||||
vl, err := g.db.FindMaxGroupMemberVersionCache(ctx, req.GroupID)
|
||||
func (s *groupServer) GetFullGroupMemberUserIDs(ctx context.Context, req *pbgroup.GetFullGroupMemberUserIDsReq) (*pbgroup.GetFullGroupMemberUserIDsResp, error) {
|
||||
vl, err := s.db.FindMaxGroupMemberVersionCache(ctx, req.GroupID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
userIDs, err := g.db.FindGroupMemberUserID(ctx, req.GroupID)
|
||||
userIDs, err := s.db.FindGroupMemberUserID(ctx, req.GroupID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -132,8 +132,152 @@ func (s *groupServer) GetIncrementalGroupMember(ctx context.Context, req *pbgrou
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func (g *groupServer) GetIncrementalJoinGroup(ctx context.Context, req *pbgroup.GetIncrementalJoinGroupReq) (*pbgroup.GetIncrementalJoinGroupResp, error) {
|
||||
if err := authverify.CheckAccessV3(ctx, req.UserID, g.config.Share.IMAdminUserID); err != nil {
|
||||
func (s *groupServer) BatchGetIncrementalGroupMember(ctx context.Context, req *pbgroup.BatchGetIncrementalGroupMemberReq) (resp *pbgroup.BatchGetIncrementalGroupMemberResp, err error) {
|
||||
type VersionInfo struct {
|
||||
GroupID string
|
||||
VersionID string
|
||||
VersionNumber uint64
|
||||
}
|
||||
|
||||
var groupIDs []string
|
||||
|
||||
groupsVersionMap := make(map[string]*VersionInfo)
|
||||
groupsMap := make(map[string]*model.Group)
|
||||
hasGroupUpdateMap := make(map[string]bool)
|
||||
sortVersionMap := make(map[string]uint64)
|
||||
|
||||
var targetKeys, versionIDs []string
|
||||
var versionNumbers []uint64
|
||||
|
||||
var requestBodyLen int
|
||||
|
||||
for _, group := range req.ReqList {
|
||||
groupsVersionMap[group.GroupID] = &VersionInfo{
|
||||
GroupID: group.GroupID,
|
||||
VersionID: group.VersionID,
|
||||
VersionNumber: group.Version,
|
||||
}
|
||||
|
||||
groupIDs = append(groupIDs, group.GroupID)
|
||||
}
|
||||
|
||||
groups, err := s.db.FindGroup(ctx, groupIDs)
|
||||
if err != nil {
|
||||
return nil, errs.Wrap(err)
|
||||
}
|
||||
|
||||
for _, group := range groups {
|
||||
if group.Status == constant.GroupStatusDismissed {
|
||||
err = servererrs.ErrDismissedAlready.Wrap()
|
||||
log.ZError(ctx, "This group is Dismissed Already", err, "group is", group.GroupID)
|
||||
|
||||
delete(groupsVersionMap, group.GroupID)
|
||||
} else {
|
||||
groupsMap[group.GroupID] = group
|
||||
}
|
||||
}
|
||||
|
||||
for groupID, vInfo := range groupsVersionMap {
|
||||
targetKeys = append(targetKeys, groupID)
|
||||
versionIDs = append(versionIDs, vInfo.VersionID)
|
||||
versionNumbers = append(versionNumbers, vInfo.VersionNumber)
|
||||
}
|
||||
|
||||
opt := incrversion.BatchOption[[]*sdkws.GroupMemberFullInfo, pbgroup.BatchGetIncrementalGroupMemberResp]{
|
||||
Ctx: ctx,
|
||||
TargetKeys: targetKeys,
|
||||
VersionIDs: versionIDs,
|
||||
VersionNumbers: versionNumbers,
|
||||
Versions: func(ctx context.Context, groupIDs []string, versions []uint64, limits []int) (map[string]*model.VersionLog, error) {
|
||||
vLogs, err := s.db.BatchFindMemberIncrVersion(ctx, groupIDs, versions, limits)
|
||||
if err != nil {
|
||||
return nil, errs.Wrap(err)
|
||||
}
|
||||
|
||||
for groupID, vlog := range vLogs {
|
||||
vlogElems := make([]model.VersionLogElem, 0, len(vlog.Logs))
|
||||
for i, log := range vlog.Logs {
|
||||
switch log.EID {
|
||||
case model.VersionGroupChangeID:
|
||||
vlog.LogLen--
|
||||
hasGroupUpdateMap[groupID] = true
|
||||
case model.VersionSortChangeID:
|
||||
vlog.LogLen--
|
||||
sortVersionMap[groupID] = uint64(log.Version)
|
||||
default:
|
||||
vlogElems = append(vlogElems, vlog.Logs[i])
|
||||
}
|
||||
}
|
||||
vlog.Logs = vlogElems
|
||||
if vlog.LogLen > 0 {
|
||||
hasGroupUpdateMap[groupID] = true
|
||||
}
|
||||
}
|
||||
|
||||
return vLogs, nil
|
||||
},
|
||||
CacheMaxVersions: s.db.BatchFindMaxGroupMemberVersionCache,
|
||||
Find: func(ctx context.Context, groupID string, ids []string) ([]*sdkws.GroupMemberFullInfo, error) {
|
||||
memberInfo, err := s.getGroupMembersInfo(ctx, groupID, ids)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return memberInfo, err
|
||||
},
|
||||
Resp: func(versions map[string]*model.VersionLog, deleteIdsMap map[string][]string, insertListMap, updateListMap map[string][]*sdkws.GroupMemberFullInfo, fullMap map[string]bool) *pbgroup.BatchGetIncrementalGroupMemberResp {
|
||||
resList := make(map[string]*pbgroup.GetIncrementalGroupMemberResp)
|
||||
|
||||
for groupID, versionLog := range versions {
|
||||
resList[groupID] = &pbgroup.GetIncrementalGroupMemberResp{
|
||||
VersionID: versionLog.ID.Hex(),
|
||||
Version: uint64(versionLog.Version),
|
||||
Full: fullMap[groupID],
|
||||
Delete: deleteIdsMap[groupID],
|
||||
Insert: insertListMap[groupID],
|
||||
Update: updateListMap[groupID],
|
||||
SortVersion: sortVersionMap[groupID],
|
||||
}
|
||||
|
||||
requestBodyLen += len(insertListMap[groupID]) + len(updateListMap[groupID]) + len(deleteIdsMap[groupID])
|
||||
if requestBodyLen > 200 {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return &pbgroup.BatchGetIncrementalGroupMemberResp{
|
||||
RespList: resList,
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
resp, err = opt.Build()
|
||||
if err != nil {
|
||||
return nil, errs.Wrap(err)
|
||||
}
|
||||
|
||||
for groupID, val := range resp.RespList {
|
||||
if val.Full || hasGroupUpdateMap[groupID] {
|
||||
count, err := s.db.FindGroupMemberNum(ctx, groupID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
owner, err := s.db.TakeGroupOwner(ctx, groupID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resp.RespList[groupID].Group = s.groupDB2PB(groupsMap[groupID], owner.UserID, count)
|
||||
}
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
|
||||
}
|
||||
|
||||
func (s *groupServer) GetIncrementalJoinGroup(ctx context.Context, req *pbgroup.GetIncrementalJoinGroupReq) (*pbgroup.GetIncrementalJoinGroupResp, error) {
|
||||
if err := authverify.CheckAccessV3(ctx, req.UserID, s.config.Share.IMAdminUserID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
opt := incrversion.Option[*sdkws.GroupInfo, pbgroup.GetIncrementalJoinGroupResp]{
|
||||
@@ -141,9 +285,9 @@ func (g *groupServer) GetIncrementalJoinGroup(ctx context.Context, req *pbgroup.
|
||||
VersionKey: req.UserID,
|
||||
VersionID: req.VersionID,
|
||||
VersionNumber: req.Version,
|
||||
Version: g.db.FindJoinIncrVersion,
|
||||
CacheMaxVersion: g.db.FindMaxJoinGroupVersionCache,
|
||||
Find: g.getGroupsInfo,
|
||||
Version: s.db.FindJoinIncrVersion,
|
||||
CacheMaxVersion: s.db.FindMaxJoinGroupVersionCache,
|
||||
Find: s.getGroupsInfo,
|
||||
Resp: func(version *model.VersionLog, delIDs []string, insertList, updateList []*sdkws.GroupInfo, full bool) *pbgroup.GetIncrementalJoinGroupResp {
|
||||
return &pbgroup.GetIncrementalJoinGroupResp{
|
||||
VersionID: version.ID.Hex(),
|
||||
@@ -157,23 +301,3 @@ func (g *groupServer) GetIncrementalJoinGroup(ctx context.Context, req *pbgroup.
|
||||
}
|
||||
return opt.Build()
|
||||
}
|
||||
|
||||
func (g *groupServer) BatchGetIncrementalGroupMember(ctx context.Context, req *pbgroup.BatchGetIncrementalGroupMemberReq) (*pbgroup.BatchGetIncrementalGroupMemberResp, error) {
|
||||
var num int
|
||||
resp := make(map[string]*pbgroup.GetIncrementalGroupMemberResp)
|
||||
for _, memberReq := range req.ReqList {
|
||||
if _, ok := resp[memberReq.GroupID]; ok {
|
||||
continue
|
||||
}
|
||||
memberResp, err := g.GetIncrementalGroupMember(ctx, memberReq)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp[memberReq.GroupID] = memberResp
|
||||
num += len(memberResp.Insert) + len(memberResp.Update) + len(memberResp.Delete)
|
||||
if num >= versionSyncLimit {
|
||||
break
|
||||
}
|
||||
}
|
||||
return &pbgroup.BatchGetIncrementalGroupMemberResp{RespList: resp}, nil
|
||||
}
|
||||
|
||||
@@ -23,11 +23,11 @@ import (
|
||||
)
|
||||
|
||||
type MsgNotificationSender struct {
|
||||
*notification.NotificationSender
|
||||
*rpcclient.NotificationSender
|
||||
}
|
||||
|
||||
func NewMsgNotificationSender(config *Config, opts ...notification.NotificationSenderOptions) *MsgNotificationSender {
|
||||
return &MsgNotificationSender{notification.NewNotificationSender(&config.NotificationConfig, opts...)}
|
||||
func NewMsgNotificationSender(config *Config, opts ...rpcclient.NotificationSenderOptions) *MsgNotificationSender {
|
||||
return &MsgNotificationSender{rpcclient.NewNotificationSender(&config.NotificationConfig, opts...)}
|
||||
}
|
||||
|
||||
func (m *MsgNotificationSender) UserDeleteMsgsNotification(ctx context.Context, userID, conversationID string, seqs []int64) {
|
||||
@@ -48,7 +48,3 @@ func (m *MsgNotificationSender) MarkAsReadNotification(ctx context.Context, conv
|
||||
}
|
||||
m.NotificationWithSessionType(ctx, sendID, recvID, constant.HasReadReceipt, sessionType, tips)
|
||||
}
|
||||
|
||||
func (m *MsgNotificationSender) StreamMsgNotification(ctx context.Context, sendID string, recvID string, sessionType int32, tips *sdkws.StreamMsgTips) {
|
||||
m.NotificationWithSessionType(ctx, sendID, recvID, constant.StreamMsgNotification, sessionType, tips)
|
||||
}
|
||||
|
||||
@@ -17,7 +17,6 @@ package msg
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/notification"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/rpcli"
|
||||
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
||||
@@ -29,6 +28,7 @@ import (
|
||||
"github.com/openimsdk/tools/db/redisutil"
|
||||
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/storage/controller"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/notification"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/rpccache"
|
||||
"github.com/openimsdk/protocol/constant"
|
||||
"github.com/openimsdk/protocol/conversation"
|
||||
@@ -64,7 +64,7 @@ type msgServer struct {
|
||||
GroupLocalCache *rpccache.GroupLocalCache // Local cache for group data.
|
||||
ConversationLocalCache *rpccache.ConversationLocalCache // Local cache for conversation data.
|
||||
Handlers MessageInterceptorChain // Chain of handlers for processing messages.
|
||||
notificationSender *notification.NotificationSender // RPC client for sending notifications.
|
||||
notificationSender *rpcclient.NotificationSender // RPC client for sending notifications.
|
||||
msgNotificationSender *MsgNotificationSender // RPC client for sending msg notifications.
|
||||
config *Config // Global configuration settings.
|
||||
webhookClient *webhook.Client
|
||||
@@ -104,19 +104,19 @@ func Start(ctx context.Context, config *Config, client discovery.SvcDiscoveryReg
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
userConn, err := client.GetConn(ctx, config.Share.RpcRegisterName.User)
|
||||
userConn, err := client.GetConn(ctx, config.Discovery.RpcService.User)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
groupConn, err := client.GetConn(ctx, config.Share.RpcRegisterName.Group)
|
||||
groupConn, err := client.GetConn(ctx, config.Discovery.RpcService.Group)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
friendConn, err := client.GetConn(ctx, config.Share.RpcRegisterName.Friend)
|
||||
friendConn, err := client.GetConn(ctx, config.Discovery.RpcService.Friend)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
conversationConn, err := client.GetConn(ctx, config.Share.RpcRegisterName.Conversation)
|
||||
conversationConn, err := client.GetConn(ctx, config.Discovery.RpcService.Conversation)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -133,8 +133,8 @@ func Start(ctx context.Context, config *Config, client discovery.SvcDiscoveryReg
|
||||
conversationClient: conversationClient,
|
||||
}
|
||||
|
||||
s.notificationSender = notification.NewNotificationSender(&config.NotificationConfig, notification.WithLocalSendMsg(s.SendMsg))
|
||||
s.msgNotificationSender = NewMsgNotificationSender(config, notification.WithLocalSendMsg(s.SendMsg))
|
||||
s.notificationSender = rpcclient.NewNotificationSender(&config.NotificationConfig, rpcclient.WithLocalSendMsg(s.SendMsg))
|
||||
s.msgNotificationSender = NewMsgNotificationSender(config, rpcclient.WithLocalSendMsg(s.SendMsg))
|
||||
|
||||
msg.RegisterMsgServer(server, s)
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ package relation
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/rpcli"
|
||||
|
||||
"github.com/openimsdk/tools/mq/memamq"
|
||||
@@ -91,11 +92,11 @@ func Start(ctx context.Context, config *Config, client discovery.SvcDiscoveryReg
|
||||
return err
|
||||
}
|
||||
|
||||
userConn, err := client.GetConn(ctx, config.Share.RpcRegisterName.User)
|
||||
userConn, err := client.GetConn(ctx, config.Discovery.RpcService.User)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
msgConn, err := client.GetConn(ctx, config.Share.RpcRegisterName.Msg)
|
||||
msgConn, err := client.GetConn(ctx, config.Discovery.RpcService.Msg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@ package relation
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/rpcli"
|
||||
"github.com/openimsdk/protocol/msg"
|
||||
|
||||
@@ -37,7 +36,7 @@ import (
|
||||
)
|
||||
|
||||
type FriendNotificationSender struct {
|
||||
*notification.NotificationSender
|
||||
*rpcclient.NotificationSender
|
||||
// Target not found err
|
||||
getUsersInfo func(ctx context.Context, userIDs []string) ([]common_user.CommonUser, error)
|
||||
// db controller
|
||||
@@ -90,7 +89,7 @@ func WithRpcFunc(
|
||||
|
||||
func NewFriendNotificationSender(conf *config.Notification, msgClient *rpcli.MsgClient, opts ...friendNotificationSenderOptions) *FriendNotificationSender {
|
||||
f := &FriendNotificationSender{
|
||||
NotificationSender: notification.NewNotificationSender(conf, notification.WithRpcClient(func(ctx context.Context, req *msg.SendMsgReq) (*msg.SendMsgResp, error) {
|
||||
NotificationSender: rpcclient.NewNotificationSender(conf, rpcclient.WithRpcClient(func(ctx context.Context, req *msg.SendMsgReq) (*msg.SendMsgResp, error) {
|
||||
return msgClient.SendMsg(ctx, req)
|
||||
})),
|
||||
}
|
||||
|
||||
@@ -19,12 +19,11 @@ import (
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/authverify"
|
||||
"path"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/authverify"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/servererrs"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/storage/model"
|
||||
@@ -38,10 +37,7 @@ import (
|
||||
)
|
||||
|
||||
func (t *thirdServer) PartLimit(ctx context.Context, req *third.PartLimitReq) (*third.PartLimitResp, error) {
|
||||
limit, err := t.s3dataBase.PartLimit()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
limit := t.s3dataBase.PartLimit()
|
||||
return &third.PartLimitResp{
|
||||
MinPartSize: limit.MinPartSize,
|
||||
MaxPartSize: limit.MaxPartSize,
|
||||
|
||||
@@ -22,16 +22,18 @@ import (
|
||||
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/storage/cache/redis"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/storage/controller"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/storage/database/mgo"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/localcache"
|
||||
"github.com/openimsdk/tools/s3/aws"
|
||||
"github.com/openimsdk/tools/s3/kodo"
|
||||
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/storage/controller"
|
||||
"github.com/openimsdk/protocol/third"
|
||||
"github.com/openimsdk/tools/db/mongoutil"
|
||||
"github.com/openimsdk/tools/db/redisutil"
|
||||
"github.com/openimsdk/tools/discovery"
|
||||
"github.com/openimsdk/tools/s3"
|
||||
"github.com/openimsdk/tools/s3/cos"
|
||||
"github.com/openimsdk/tools/s3/kodo"
|
||||
"github.com/openimsdk/tools/s3/minio"
|
||||
"github.com/openimsdk/tools/s3/oss"
|
||||
"google.golang.org/grpc"
|
||||
@@ -90,13 +92,15 @@ func Start(ctx context.Context, config *Config, client discovery.SvcDiscoveryReg
|
||||
o, err = oss.NewOSS(*config.RpcConfig.Object.Oss.Build())
|
||||
case "kodo":
|
||||
o, err = kodo.NewKodo(*config.RpcConfig.Object.Kodo.Build())
|
||||
case "aws":
|
||||
o, err = aws.NewAws(*config.RpcConfig.Object.Aws.Build())
|
||||
default:
|
||||
err = fmt.Errorf("invalid object enable: %s", enable)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
userConn, err := client.GetConn(ctx, config.Share.RpcRegisterName.User)
|
||||
userConn, err := client.GetConn(ctx, config.Discovery.RpcService.User)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@ package user
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/rpcli"
|
||||
"github.com/openimsdk/protocol/msg"
|
||||
|
||||
@@ -30,7 +29,7 @@ import (
|
||||
)
|
||||
|
||||
type UserNotificationSender struct {
|
||||
*notification.NotificationSender
|
||||
*rpcclient.NotificationSender
|
||||
getUsersInfo func(ctx context.Context, userIDs []string) ([]common_user.CommonUser, error)
|
||||
// db controller
|
||||
db controller.UserDatabase
|
||||
@@ -64,7 +63,7 @@ func WithUserFunc(
|
||||
|
||||
func NewUserNotificationSender(config *Config, msgClient *rpcli.MsgClient, opts ...userNotificationSenderOptions) *UserNotificationSender {
|
||||
f := &UserNotificationSender{
|
||||
NotificationSender: notification.NewNotificationSender(&config.NotificationConfig, notification.WithRpcClient(func(ctx context.Context, req *msg.SendMsgReq) (*msg.SendMsgResp, error) {
|
||||
NotificationSender: rpcclient.NewNotificationSender(&config.NotificationConfig, rpcclient.WithRpcClient(func(ctx context.Context, req *msg.SendMsgReq) (*msg.SendMsgResp, error) {
|
||||
return msgClient.SendMsg(ctx, req)
|
||||
})),
|
||||
}
|
||||
|
||||
@@ -94,15 +94,15 @@ func Start(ctx context.Context, config *Config, client registry.SvcDiscoveryRegi
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
msgConn, err := client.GetConn(ctx, config.Share.RpcRegisterName.Msg)
|
||||
msgConn, err := client.GetConn(ctx, config.Discovery.RpcService.Msg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
groupConn, err := client.GetConn(ctx, config.Share.RpcRegisterName.Group)
|
||||
groupConn, err := client.GetConn(ctx, config.Discovery.RpcService.Group)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
friendConn, err := client.GetConn(ctx, config.Share.RpcRegisterName.Friend)
|
||||
friendConn, err := client.GetConn(ctx, config.Discovery.RpcService.Friend)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
+27
-25
@@ -1,30 +1,19 @@
|
||||
// Copyright © 2023 OpenIM. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package tools
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
||||
kdisc "github.com/openimsdk/open-im-server/v3/pkg/common/discoveryregister"
|
||||
kdisc "github.com/openimsdk/open-im-server/v3/pkg/common/discovery"
|
||||
disetcd "github.com/openimsdk/open-im-server/v3/pkg/common/discovery/etcd"
|
||||
pbconversation "github.com/openimsdk/protocol/conversation"
|
||||
"github.com/openimsdk/protocol/msg"
|
||||
"github.com/openimsdk/protocol/third"
|
||||
"github.com/openimsdk/tools/discovery/etcd"
|
||||
|
||||
"github.com/openimsdk/tools/mcontext"
|
||||
"github.com/openimsdk/tools/mw"
|
||||
"github.com/openimsdk/tools/utils/runtimeenv"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/credentials/insecure"
|
||||
|
||||
@@ -37,38 +26,51 @@ type CronTaskConfig struct {
|
||||
CronTask config.CronTask
|
||||
Share config.Share
|
||||
Discovery config.Discovery
|
||||
|
||||
runTimeEnv string
|
||||
}
|
||||
|
||||
func Start(ctx context.Context, config *CronTaskConfig) error {
|
||||
log.CInfo(ctx, "CRON-TASK server is initializing", "chatRecordsClearTime", config.CronTask.CronExecuteTime, "msgDestructTime", config.CronTask.RetainChatRecords)
|
||||
if config.CronTask.RetainChatRecords < 1 {
|
||||
func Start(ctx context.Context, conf *CronTaskConfig) error {
|
||||
conf.runTimeEnv = runtimeenv.PrintRuntimeEnvironment()
|
||||
|
||||
log.CInfo(ctx, "CRON-TASK server is initializing", "runTimeEnv", conf.runTimeEnv, "chatRecordsClearTime", conf.CronTask.CronExecuteTime, "msgDestructTime", conf.CronTask.RetainChatRecords)
|
||||
if conf.CronTask.RetainChatRecords < 1 {
|
||||
return errs.New("msg destruct time must be greater than 1").Wrap()
|
||||
}
|
||||
client, err := kdisc.NewDiscoveryRegister(&config.Discovery, &config.Share, nil)
|
||||
client, err := kdisc.NewDiscoveryRegister(&conf.Discovery, conf.runTimeEnv, nil)
|
||||
if err != nil {
|
||||
return errs.WrapMsg(err, "failed to register discovery service")
|
||||
}
|
||||
client.AddOption(mw.GrpcClient(), grpc.WithTransportCredentials(insecure.NewCredentials()))
|
||||
ctx = mcontext.SetOpUserID(ctx, config.Share.IMAdminUserID[0])
|
||||
ctx = mcontext.SetOpUserID(ctx, conf.Share.IMAdminUserID[0])
|
||||
|
||||
msgConn, err := client.GetConn(ctx, config.Share.RpcRegisterName.Msg)
|
||||
msgConn, err := client.GetConn(ctx, conf.Discovery.RpcService.Msg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
thirdConn, err := client.GetConn(ctx, config.Share.RpcRegisterName.Third)
|
||||
thirdConn, err := client.GetConn(ctx, conf.Discovery.RpcService.Third)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
conversationConn, err := client.GetConn(ctx, config.Share.RpcRegisterName.Conversation)
|
||||
conversationConn, err := client.GetConn(ctx, conf.Discovery.RpcService.Conversation)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if conf.Discovery.Enable == config.ETCD {
|
||||
cm := disetcd.NewConfigManager(client.(*etcd.SvcDiscoveryRegistryImpl).GetClient(), []string{
|
||||
conf.CronTask.GetConfigFileName(),
|
||||
conf.Share.GetConfigFileName(),
|
||||
conf.Discovery.GetConfigFileName(),
|
||||
})
|
||||
cm.Watch(ctx)
|
||||
}
|
||||
|
||||
srv := &cronServer{
|
||||
ctx: ctx,
|
||||
config: config,
|
||||
config: conf,
|
||||
cron: cron.New(),
|
||||
msgClient: msg.NewMsgClient(msgConn),
|
||||
conversationClient: pbconversation.NewConversationClient(conversationConn),
|
||||
@@ -84,7 +86,7 @@ func Start(ctx context.Context, config *CronTaskConfig) error {
|
||||
if err := srv.registerClearUserMsg(); err != nil {
|
||||
return err
|
||||
}
|
||||
log.ZDebug(ctx, "start cron task", "CronExecuteTime", config.CronTask.CronExecuteTime)
|
||||
log.ZDebug(ctx, "start cron task", "CronExecuteTime", conf.CronTask.CronExecuteTime)
|
||||
srv.cron.Start()
|
||||
<-ctx.Done()
|
||||
return nil
|
||||
|
||||
@@ -1,63 +0,0 @@
|
||||
package tools
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
||||
kdisc "github.com/openimsdk/open-im-server/v3/pkg/common/discoveryregister"
|
||||
pbconversation "github.com/openimsdk/protocol/conversation"
|
||||
"github.com/openimsdk/protocol/msg"
|
||||
"github.com/openimsdk/protocol/third"
|
||||
"github.com/openimsdk/tools/mcontext"
|
||||
"github.com/openimsdk/tools/mw"
|
||||
"github.com/robfig/cron/v3"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/credentials/insecure"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestName(t *testing.T) {
|
||||
conf := &config.Discovery{
|
||||
Enable: config.ETCD,
|
||||
Etcd: config.Etcd{
|
||||
RootDirectory: "openim",
|
||||
Address: []string{"localhost:12379"},
|
||||
},
|
||||
}
|
||||
client, err := kdisc.NewDiscoveryRegister(conf, "source")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
client.AddOption(mw.GrpcClient(), grpc.WithTransportCredentials(insecure.NewCredentials()))
|
||||
ctx := mcontext.SetOpUserID(context.Background(), "imAdmin")
|
||||
msgConn, err := client.GetConn(ctx, "msg-rpc-service")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
thirdConn, err := client.GetConn(ctx, "third-rpc-service")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
conversationConn, err := client.GetConn(ctx, "conversation-rpc-service")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
srv := &cronServer{
|
||||
ctx: ctx,
|
||||
config: &CronTaskConfig{
|
||||
CronTask: config.CronTask{
|
||||
RetainChatRecords: 1,
|
||||
FileExpireTime: 1,
|
||||
DeleteObjectType: []string{"msg-picture", "msg-file", "msg-voice", "msg-video", "msg-video-snapshot", "sdklog", ""},
|
||||
},
|
||||
},
|
||||
cron: cron.New(),
|
||||
msgClient: msg.NewMsgClient(msgConn),
|
||||
conversationClient: pbconversation.NewConversationClient(conversationConn),
|
||||
thirdClient: third.NewThirdClient(thirdConn),
|
||||
}
|
||||
srv.deleteMsg()
|
||||
//srv.clearS3()
|
||||
//srv.clearUserMsg()
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package apistruct
|
||||
|
||||
type GetConfigReq struct {
|
||||
ConfigName string `json:"configName"`
|
||||
}
|
||||
|
||||
type GetConfigListResp struct {
|
||||
Environment string `json:"environment"`
|
||||
Version string `json:"version"`
|
||||
ConfigNames []string `json:"configNames"`
|
||||
}
|
||||
|
||||
type SetConfigReq struct {
|
||||
ConfigName string `json:"configName"`
|
||||
Data string `json:"data"`
|
||||
}
|
||||
|
||||
type SetEnableConfigManagerReq struct {
|
||||
Enable bool `json:"enable"`
|
||||
}
|
||||
|
||||
type GetEnableConfigManagerResp struct {
|
||||
Enable bool `json:"enable"`
|
||||
}
|
||||
+25
-4
@@ -18,6 +18,7 @@ import (
|
||||
"context"
|
||||
|
||||
"github.com/openimsdk/open-im-server/v3/internal/api"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
||||
"github.com/openimsdk/open-im-server/v3/version"
|
||||
"github.com/openimsdk/tools/system/program"
|
||||
"github.com/spf13/cobra"
|
||||
@@ -31,16 +32,36 @@ type ApiCmd struct {
|
||||
}
|
||||
|
||||
func NewApiCmd() *ApiCmd {
|
||||
var apiConfig api.Config
|
||||
apiConfig := api.Config{AllConfig: &config.AllConfig{}}
|
||||
ret := &ApiCmd{apiConfig: &apiConfig}
|
||||
ret.configMap = map[string]any{
|
||||
OpenIMAPICfgFileName: &apiConfig.API,
|
||||
ShareFileName: &apiConfig.Share,
|
||||
DiscoveryConfigFilename: &apiConfig.Discovery,
|
||||
config.DiscoveryConfigFilename: &apiConfig.Discovery,
|
||||
config.KafkaConfigFileName: &apiConfig.Kafka,
|
||||
config.LocalCacheConfigFileName: &apiConfig.LocalCache,
|
||||
config.LogConfigFileName: &apiConfig.Log,
|
||||
config.MinioConfigFileName: &apiConfig.Minio,
|
||||
config.MongodbConfigFileName: &apiConfig.Mongo,
|
||||
config.NotificationFileName: &apiConfig.Notification,
|
||||
config.OpenIMAPICfgFileName: &apiConfig.API,
|
||||
config.OpenIMCronTaskCfgFileName: &apiConfig.CronTask,
|
||||
config.OpenIMMsgGatewayCfgFileName: &apiConfig.MsgGateway,
|
||||
config.OpenIMMsgTransferCfgFileName: &apiConfig.MsgTransfer,
|
||||
config.OpenIMPushCfgFileName: &apiConfig.Push,
|
||||
config.OpenIMRPCAuthCfgFileName: &apiConfig.Auth,
|
||||
config.OpenIMRPCConversationCfgFileName: &apiConfig.Conversation,
|
||||
config.OpenIMRPCFriendCfgFileName: &apiConfig.Friend,
|
||||
config.OpenIMRPCGroupCfgFileName: &apiConfig.Group,
|
||||
config.OpenIMRPCMsgCfgFileName: &apiConfig.Msg,
|
||||
config.OpenIMRPCThirdCfgFileName: &apiConfig.Third,
|
||||
config.OpenIMRPCUserCfgFileName: &apiConfig.User,
|
||||
config.RedisConfigFileName: &apiConfig.Redis,
|
||||
config.ShareFileName: &apiConfig.Share,
|
||||
config.WebhooksConfigFileName: &apiConfig.Webhooks,
|
||||
}
|
||||
ret.RootCmd = NewRootCmd(program.GetProcessName(), WithConfigMap(ret.configMap))
|
||||
ret.ctx = context.WithValue(context.Background(), "version", version.Version)
|
||||
ret.Command.RunE = func(cmd *cobra.Command, args []string) error {
|
||||
apiConfig.ConfigPath = ret.configPath
|
||||
return ret.runE()
|
||||
}
|
||||
return ret
|
||||
|
||||
+13
-6
@@ -18,6 +18,7 @@ import (
|
||||
"context"
|
||||
|
||||
"github.com/openimsdk/open-im-server/v3/internal/rpc/auth"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/startrpc"
|
||||
"github.com/openimsdk/open-im-server/v3/version"
|
||||
"github.com/openimsdk/tools/system/program"
|
||||
@@ -35,10 +36,10 @@ func NewAuthRpcCmd() *AuthRpcCmd {
|
||||
var authConfig auth.Config
|
||||
ret := &AuthRpcCmd{authConfig: &authConfig}
|
||||
ret.configMap = map[string]any{
|
||||
OpenIMRPCAuthCfgFileName: &authConfig.RpcConfig,
|
||||
RedisConfigFileName: &authConfig.RedisConfig,
|
||||
ShareFileName: &authConfig.Share,
|
||||
DiscoveryConfigFilename: &authConfig.Discovery,
|
||||
config.OpenIMRPCAuthCfgFileName: &authConfig.RpcConfig,
|
||||
config.RedisConfigFileName: &authConfig.RedisConfig,
|
||||
config.ShareFileName: &authConfig.Share,
|
||||
config.DiscoveryConfigFilename: &authConfig.Discovery,
|
||||
}
|
||||
ret.RootCmd = NewRootCmd(program.GetProcessName(), WithConfigMap(ret.configMap))
|
||||
ret.ctx = context.WithValue(context.Background(), "version", version.Version)
|
||||
@@ -56,9 +57,15 @@ func (a *AuthRpcCmd) Exec() error {
|
||||
func (a *AuthRpcCmd) runE() error {
|
||||
return startrpc.Start(a.ctx, &a.authConfig.Discovery, &a.authConfig.RpcConfig.Prometheus, a.authConfig.RpcConfig.RPC.ListenIP,
|
||||
a.authConfig.RpcConfig.RPC.RegisterIP, a.authConfig.RpcConfig.RPC.AutoSetPorts, a.authConfig.RpcConfig.RPC.Ports,
|
||||
a.Index(), a.authConfig.Share.RpcRegisterName.Auth, &a.authConfig.Share, a.authConfig,
|
||||
a.Index(), a.authConfig.Discovery.RpcService.Auth, nil, a.authConfig,
|
||||
[]string{
|
||||
a.authConfig.Share.RpcRegisterName.MessageGateway,
|
||||
a.authConfig.RpcConfig.GetConfigFileName(),
|
||||
a.authConfig.Share.GetConfigFileName(),
|
||||
a.authConfig.RedisConfig.GetConfigFileName(),
|
||||
a.authConfig.Discovery.GetConfigFileName(),
|
||||
},
|
||||
[]string{
|
||||
a.authConfig.Discovery.RpcService.MessageGateway,
|
||||
},
|
||||
auth.Start)
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ import (
|
||||
"context"
|
||||
|
||||
"github.com/openimsdk/open-im-server/v3/internal/rpc/conversation"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/startrpc"
|
||||
"github.com/openimsdk/open-im-server/v3/version"
|
||||
"github.com/openimsdk/tools/system/program"
|
||||
@@ -35,13 +36,13 @@ func NewConversationRpcCmd() *ConversationRpcCmd {
|
||||
var conversationConfig conversation.Config
|
||||
ret := &ConversationRpcCmd{conversationConfig: &conversationConfig}
|
||||
ret.configMap = map[string]any{
|
||||
OpenIMRPCConversationCfgFileName: &conversationConfig.RpcConfig,
|
||||
RedisConfigFileName: &conversationConfig.RedisConfig,
|
||||
MongodbConfigFileName: &conversationConfig.MongodbConfig,
|
||||
ShareFileName: &conversationConfig.Share,
|
||||
NotificationFileName: &conversationConfig.NotificationConfig,
|
||||
LocalCacheConfigFileName: &conversationConfig.LocalCacheConfig,
|
||||
DiscoveryConfigFilename: &conversationConfig.Discovery,
|
||||
config.OpenIMRPCConversationCfgFileName: &conversationConfig.RpcConfig,
|
||||
config.RedisConfigFileName: &conversationConfig.RedisConfig,
|
||||
config.MongodbConfigFileName: &conversationConfig.MongodbConfig,
|
||||
config.ShareFileName: &conversationConfig.Share,
|
||||
config.NotificationFileName: &conversationConfig.NotificationConfig,
|
||||
config.LocalCacheConfigFileName: &conversationConfig.LocalCacheConfig,
|
||||
config.DiscoveryConfigFilename: &conversationConfig.Discovery,
|
||||
}
|
||||
ret.RootCmd = NewRootCmd(program.GetProcessName(), WithConfigMap(ret.configMap))
|
||||
ret.ctx = context.WithValue(context.Background(), "version", version.Version)
|
||||
@@ -58,7 +59,15 @@ func (a *ConversationRpcCmd) Exec() error {
|
||||
func (a *ConversationRpcCmd) runE() error {
|
||||
return startrpc.Start(a.ctx, &a.conversationConfig.Discovery, &a.conversationConfig.RpcConfig.Prometheus, a.conversationConfig.RpcConfig.RPC.ListenIP,
|
||||
a.conversationConfig.RpcConfig.RPC.RegisterIP, a.conversationConfig.RpcConfig.RPC.AutoSetPorts, a.conversationConfig.RpcConfig.RPC.Ports,
|
||||
a.Index(), a.conversationConfig.Share.RpcRegisterName.Conversation, &a.conversationConfig.Share, a.conversationConfig,
|
||||
nil,
|
||||
a.Index(), a.conversationConfig.Discovery.RpcService.Conversation, &a.conversationConfig.NotificationConfig, a.conversationConfig,
|
||||
[]string{
|
||||
a.conversationConfig.RpcConfig.GetConfigFileName(),
|
||||
a.conversationConfig.RedisConfig.GetConfigFileName(),
|
||||
a.conversationConfig.MongodbConfig.GetConfigFileName(),
|
||||
a.conversationConfig.NotificationConfig.GetConfigFileName(),
|
||||
a.conversationConfig.Share.GetConfigFileName(),
|
||||
a.conversationConfig.LocalCacheConfig.GetConfigFileName(),
|
||||
a.conversationConfig.Discovery.GetConfigFileName(),
|
||||
}, nil,
|
||||
conversation.Start)
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ import (
|
||||
"context"
|
||||
|
||||
"github.com/openimsdk/open-im-server/v3/internal/tools"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
||||
"github.com/openimsdk/open-im-server/v3/version"
|
||||
"github.com/openimsdk/tools/system/program"
|
||||
"github.com/spf13/cobra"
|
||||
@@ -34,9 +35,9 @@ func NewCronTaskCmd() *CronTaskCmd {
|
||||
var cronTaskConfig tools.CronTaskConfig
|
||||
ret := &CronTaskCmd{cronTaskConfig: &cronTaskConfig}
|
||||
ret.configMap = map[string]any{
|
||||
OpenIMCronTaskCfgFileName: &cronTaskConfig.CronTask,
|
||||
ShareFileName: &cronTaskConfig.Share,
|
||||
DiscoveryConfigFilename: &cronTaskConfig.Discovery,
|
||||
config.OpenIMCronTaskCfgFileName: &cronTaskConfig.CronTask,
|
||||
config.ShareFileName: &cronTaskConfig.Share,
|
||||
config.DiscoveryConfigFilename: &cronTaskConfig.Discovery,
|
||||
}
|
||||
ret.RootCmd = NewRootCmd(program.GetProcessName(), WithConfigMap(ret.configMap))
|
||||
ret.ctx = context.WithValue(context.Background(), "version", version.Version)
|
||||
|
||||
+20
-10
@@ -18,6 +18,7 @@ import (
|
||||
"context"
|
||||
|
||||
"github.com/openimsdk/open-im-server/v3/internal/rpc/relation"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/startrpc"
|
||||
"github.com/openimsdk/open-im-server/v3/version"
|
||||
"github.com/openimsdk/tools/system/program"
|
||||
@@ -35,14 +36,14 @@ func NewFriendRpcCmd() *FriendRpcCmd {
|
||||
var relationConfig relation.Config
|
||||
ret := &FriendRpcCmd{relationConfig: &relationConfig}
|
||||
ret.configMap = map[string]any{
|
||||
OpenIMRPCFriendCfgFileName: &relationConfig.RpcConfig,
|
||||
RedisConfigFileName: &relationConfig.RedisConfig,
|
||||
MongodbConfigFileName: &relationConfig.MongodbConfig,
|
||||
ShareFileName: &relationConfig.Share,
|
||||
NotificationFileName: &relationConfig.NotificationConfig,
|
||||
WebhooksConfigFileName: &relationConfig.WebhooksConfig,
|
||||
LocalCacheConfigFileName: &relationConfig.LocalCacheConfig,
|
||||
DiscoveryConfigFilename: &relationConfig.Discovery,
|
||||
config.OpenIMRPCFriendCfgFileName: &relationConfig.RpcConfig,
|
||||
config.RedisConfigFileName: &relationConfig.RedisConfig,
|
||||
config.MongodbConfigFileName: &relationConfig.MongodbConfig,
|
||||
config.ShareFileName: &relationConfig.Share,
|
||||
config.NotificationFileName: &relationConfig.NotificationConfig,
|
||||
config.WebhooksConfigFileName: &relationConfig.WebhooksConfig,
|
||||
config.LocalCacheConfigFileName: &relationConfig.LocalCacheConfig,
|
||||
config.DiscoveryConfigFilename: &relationConfig.Discovery,
|
||||
}
|
||||
ret.RootCmd = NewRootCmd(program.GetProcessName(), WithConfigMap(ret.configMap))
|
||||
ret.ctx = context.WithValue(context.Background(), "version", version.Version)
|
||||
@@ -59,7 +60,16 @@ func (a *FriendRpcCmd) Exec() error {
|
||||
func (a *FriendRpcCmd) runE() error {
|
||||
return startrpc.Start(a.ctx, &a.relationConfig.Discovery, &a.relationConfig.RpcConfig.Prometheus, a.relationConfig.RpcConfig.RPC.ListenIP,
|
||||
a.relationConfig.RpcConfig.RPC.RegisterIP, a.relationConfig.RpcConfig.RPC.AutoSetPorts, a.relationConfig.RpcConfig.RPC.Ports,
|
||||
a.Index(), a.relationConfig.Share.RpcRegisterName.Friend, &a.relationConfig.Share, a.relationConfig,
|
||||
nil,
|
||||
a.Index(), a.relationConfig.Discovery.RpcService.Friend, &a.relationConfig.NotificationConfig, a.relationConfig,
|
||||
[]string{
|
||||
a.relationConfig.RpcConfig.GetConfigFileName(),
|
||||
a.relationConfig.RedisConfig.GetConfigFileName(),
|
||||
a.relationConfig.MongodbConfig.GetConfigFileName(),
|
||||
a.relationConfig.NotificationConfig.GetConfigFileName(),
|
||||
a.relationConfig.Share.GetConfigFileName(),
|
||||
a.relationConfig.WebhooksConfig.GetConfigFileName(),
|
||||
a.relationConfig.LocalCacheConfig.GetConfigFileName(),
|
||||
a.relationConfig.Discovery.GetConfigFileName(),
|
||||
}, nil,
|
||||
relation.Start)
|
||||
}
|
||||
|
||||
+20
-10
@@ -18,6 +18,7 @@ import (
|
||||
"context"
|
||||
|
||||
"github.com/openimsdk/open-im-server/v3/internal/rpc/group"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/startrpc"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/storage/versionctx"
|
||||
"github.com/openimsdk/open-im-server/v3/version"
|
||||
@@ -36,14 +37,14 @@ func NewGroupRpcCmd() *GroupRpcCmd {
|
||||
var groupConfig group.Config
|
||||
ret := &GroupRpcCmd{groupConfig: &groupConfig}
|
||||
ret.configMap = map[string]any{
|
||||
OpenIMRPCGroupCfgFileName: &groupConfig.RpcConfig,
|
||||
RedisConfigFileName: &groupConfig.RedisConfig,
|
||||
MongodbConfigFileName: &groupConfig.MongodbConfig,
|
||||
ShareFileName: &groupConfig.Share,
|
||||
NotificationFileName: &groupConfig.NotificationConfig,
|
||||
WebhooksConfigFileName: &groupConfig.WebhooksConfig,
|
||||
LocalCacheConfigFileName: &groupConfig.LocalCacheConfig,
|
||||
DiscoveryConfigFilename: &groupConfig.Discovery,
|
||||
config.OpenIMRPCGroupCfgFileName: &groupConfig.RpcConfig,
|
||||
config.RedisConfigFileName: &groupConfig.RedisConfig,
|
||||
config.MongodbConfigFileName: &groupConfig.MongodbConfig,
|
||||
config.ShareFileName: &groupConfig.Share,
|
||||
config.NotificationFileName: &groupConfig.NotificationConfig,
|
||||
config.WebhooksConfigFileName: &groupConfig.WebhooksConfig,
|
||||
config.LocalCacheConfigFileName: &groupConfig.LocalCacheConfig,
|
||||
config.DiscoveryConfigFilename: &groupConfig.Discovery,
|
||||
}
|
||||
ret.RootCmd = NewRootCmd(program.GetProcessName(), WithConfigMap(ret.configMap))
|
||||
ret.ctx = context.WithValue(context.Background(), "version", version.Version)
|
||||
@@ -60,7 +61,16 @@ func (a *GroupRpcCmd) Exec() error {
|
||||
func (a *GroupRpcCmd) runE() error {
|
||||
return startrpc.Start(a.ctx, &a.groupConfig.Discovery, &a.groupConfig.RpcConfig.Prometheus, a.groupConfig.RpcConfig.RPC.ListenIP,
|
||||
a.groupConfig.RpcConfig.RPC.RegisterIP, a.groupConfig.RpcConfig.RPC.AutoSetPorts, a.groupConfig.RpcConfig.RPC.Ports,
|
||||
a.Index(), a.groupConfig.Share.RpcRegisterName.Group, &a.groupConfig.Share, a.groupConfig,
|
||||
nil,
|
||||
a.Index(), a.groupConfig.Discovery.RpcService.Group, &a.groupConfig.NotificationConfig, a.groupConfig,
|
||||
[]string{
|
||||
a.groupConfig.RpcConfig.GetConfigFileName(),
|
||||
a.groupConfig.RedisConfig.GetConfigFileName(),
|
||||
a.groupConfig.MongodbConfig.GetConfigFileName(),
|
||||
a.groupConfig.NotificationConfig.GetConfigFileName(),
|
||||
a.groupConfig.Share.GetConfigFileName(),
|
||||
a.groupConfig.WebhooksConfig.GetConfigFileName(),
|
||||
a.groupConfig.LocalCacheConfig.GetConfigFileName(),
|
||||
a.groupConfig.Discovery.GetConfigFileName(),
|
||||
}, nil,
|
||||
group.Start, versionctx.EnableVersionCtx())
|
||||
}
|
||||
|
||||
+22
-11
@@ -18,6 +18,7 @@ import (
|
||||
"context"
|
||||
|
||||
"github.com/openimsdk/open-im-server/v3/internal/rpc/msg"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/startrpc"
|
||||
"github.com/openimsdk/open-im-server/v3/version"
|
||||
"github.com/openimsdk/tools/system/program"
|
||||
@@ -35,15 +36,15 @@ func NewMsgRpcCmd() *MsgRpcCmd {
|
||||
var msgConfig msg.Config
|
||||
ret := &MsgRpcCmd{msgConfig: &msgConfig}
|
||||
ret.configMap = map[string]any{
|
||||
OpenIMRPCMsgCfgFileName: &msgConfig.RpcConfig,
|
||||
RedisConfigFileName: &msgConfig.RedisConfig,
|
||||
MongodbConfigFileName: &msgConfig.MongodbConfig,
|
||||
KafkaConfigFileName: &msgConfig.KafkaConfig,
|
||||
ShareFileName: &msgConfig.Share,
|
||||
NotificationFileName: &msgConfig.NotificationConfig,
|
||||
WebhooksConfigFileName: &msgConfig.WebhooksConfig,
|
||||
LocalCacheConfigFileName: &msgConfig.LocalCacheConfig,
|
||||
DiscoveryConfigFilename: &msgConfig.Discovery,
|
||||
config.OpenIMRPCMsgCfgFileName: &msgConfig.RpcConfig,
|
||||
config.RedisConfigFileName: &msgConfig.RedisConfig,
|
||||
config.MongodbConfigFileName: &msgConfig.MongodbConfig,
|
||||
config.KafkaConfigFileName: &msgConfig.KafkaConfig,
|
||||
config.ShareFileName: &msgConfig.Share,
|
||||
config.NotificationFileName: &msgConfig.NotificationConfig,
|
||||
config.WebhooksConfigFileName: &msgConfig.WebhooksConfig,
|
||||
config.LocalCacheConfigFileName: &msgConfig.LocalCacheConfig,
|
||||
config.DiscoveryConfigFilename: &msgConfig.Discovery,
|
||||
}
|
||||
ret.RootCmd = NewRootCmd(program.GetProcessName(), WithConfigMap(ret.configMap))
|
||||
ret.ctx = context.WithValue(context.Background(), "version", version.Version)
|
||||
@@ -60,7 +61,17 @@ func (a *MsgRpcCmd) Exec() error {
|
||||
func (a *MsgRpcCmd) runE() error {
|
||||
return startrpc.Start(a.ctx, &a.msgConfig.Discovery, &a.msgConfig.RpcConfig.Prometheus, a.msgConfig.RpcConfig.RPC.ListenIP,
|
||||
a.msgConfig.RpcConfig.RPC.RegisterIP, a.msgConfig.RpcConfig.RPC.AutoSetPorts, a.msgConfig.RpcConfig.RPC.Ports,
|
||||
a.Index(), a.msgConfig.Share.RpcRegisterName.Msg, &a.msgConfig.Share, a.msgConfig,
|
||||
nil,
|
||||
a.Index(), a.msgConfig.Discovery.RpcService.Msg, &a.msgConfig.NotificationConfig, a.msgConfig,
|
||||
[]string{
|
||||
a.msgConfig.RpcConfig.GetConfigFileName(),
|
||||
a.msgConfig.RedisConfig.GetConfigFileName(),
|
||||
a.msgConfig.MongodbConfig.GetConfigFileName(),
|
||||
a.msgConfig.KafkaConfig.GetConfigFileName(),
|
||||
a.msgConfig.NotificationConfig.GetConfigFileName(),
|
||||
a.msgConfig.Share.GetConfigFileName(),
|
||||
a.msgConfig.WebhooksConfig.GetConfigFileName(),
|
||||
a.msgConfig.LocalCacheConfig.GetConfigFileName(),
|
||||
a.msgConfig.Discovery.GetConfigFileName(),
|
||||
}, nil,
|
||||
msg.Start)
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ import (
|
||||
"context"
|
||||
|
||||
"github.com/openimsdk/open-im-server/v3/internal/msggateway"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
||||
"github.com/openimsdk/open-im-server/v3/version"
|
||||
|
||||
"github.com/openimsdk/tools/system/program"
|
||||
@@ -35,11 +36,11 @@ func NewMsgGatewayCmd() *MsgGatewayCmd {
|
||||
var msgGatewayConfig msggateway.Config
|
||||
ret := &MsgGatewayCmd{msgGatewayConfig: &msgGatewayConfig}
|
||||
ret.configMap = map[string]any{
|
||||
OpenIMMsgGatewayCfgFileName: &msgGatewayConfig.MsgGateway,
|
||||
ShareFileName: &msgGatewayConfig.Share,
|
||||
RedisConfigFileName: &msgGatewayConfig.RedisConfig,
|
||||
WebhooksConfigFileName: &msgGatewayConfig.WebhooksConfig,
|
||||
DiscoveryConfigFilename: &msgGatewayConfig.Discovery,
|
||||
config.OpenIMMsgGatewayCfgFileName: &msgGatewayConfig.MsgGateway,
|
||||
config.ShareFileName: &msgGatewayConfig.Share,
|
||||
config.RedisConfigFileName: &msgGatewayConfig.RedisConfig,
|
||||
config.WebhooksConfigFileName: &msgGatewayConfig.WebhooksConfig,
|
||||
config.DiscoveryConfigFilename: &msgGatewayConfig.Discovery,
|
||||
}
|
||||
ret.RootCmd = NewRootCmd(program.GetProcessName(), WithConfigMap(ret.configMap))
|
||||
ret.ctx = context.WithValue(context.Background(), "version", version.Version)
|
||||
|
||||
@@ -18,6 +18,7 @@ import (
|
||||
"context"
|
||||
|
||||
"github.com/openimsdk/open-im-server/v3/internal/msgtransfer"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
||||
"github.com/openimsdk/open-im-server/v3/version"
|
||||
"github.com/openimsdk/tools/system/program"
|
||||
"github.com/spf13/cobra"
|
||||
@@ -34,13 +35,13 @@ func NewMsgTransferCmd() *MsgTransferCmd {
|
||||
var msgTransferConfig msgtransfer.Config
|
||||
ret := &MsgTransferCmd{msgTransferConfig: &msgTransferConfig}
|
||||
ret.configMap = map[string]any{
|
||||
OpenIMMsgTransferCfgFileName: &msgTransferConfig.MsgTransfer,
|
||||
RedisConfigFileName: &msgTransferConfig.RedisConfig,
|
||||
MongodbConfigFileName: &msgTransferConfig.MongodbConfig,
|
||||
KafkaConfigFileName: &msgTransferConfig.KafkaConfig,
|
||||
ShareFileName: &msgTransferConfig.Share,
|
||||
WebhooksConfigFileName: &msgTransferConfig.WebhooksConfig,
|
||||
DiscoveryConfigFilename: &msgTransferConfig.Discovery,
|
||||
config.OpenIMMsgTransferCfgFileName: &msgTransferConfig.MsgTransfer,
|
||||
config.RedisConfigFileName: &msgTransferConfig.RedisConfig,
|
||||
config.MongodbConfigFileName: &msgTransferConfig.MongodbConfig,
|
||||
config.KafkaConfigFileName: &msgTransferConfig.KafkaConfig,
|
||||
config.ShareFileName: &msgTransferConfig.Share,
|
||||
config.WebhooksConfigFileName: &msgTransferConfig.WebhooksConfig,
|
||||
config.DiscoveryConfigFilename: &msgTransferConfig.Discovery,
|
||||
}
|
||||
ret.RootCmd = NewRootCmd(program.GetProcessName(), WithConfigMap(ret.configMap))
|
||||
ret.ctx = context.WithValue(context.Background(), "version", version.Version)
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
@@ -26,11 +27,11 @@ func (m *MsgUtilsCmd) AddUserIDFlag() {
|
||||
m.Command.PersistentFlags().StringP("userID", "u", "", "openIM userID")
|
||||
}
|
||||
func (m *MsgUtilsCmd) AddIndexFlag() {
|
||||
m.Command.PersistentFlags().IntP(FlagTransferIndex, "i", 0, "process startup sequence number")
|
||||
m.Command.PersistentFlags().IntP(config.FlagTransferIndex, "i", 0, "process startup sequence number")
|
||||
}
|
||||
|
||||
func (m *MsgUtilsCmd) AddConfigDirFlag() {
|
||||
m.Command.PersistentFlags().StringP(FlagConf, "c", "", "path of config directory")
|
||||
m.Command.PersistentFlags().StringP(config.FlagConf, "c", "", "path of config directory")
|
||||
|
||||
}
|
||||
|
||||
|
||||
+21
-10
@@ -18,6 +18,7 @@ import (
|
||||
"context"
|
||||
|
||||
"github.com/openimsdk/open-im-server/v3/internal/push"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/startrpc"
|
||||
"github.com/openimsdk/open-im-server/v3/version"
|
||||
"github.com/openimsdk/tools/system/program"
|
||||
@@ -35,14 +36,14 @@ func NewPushRpcCmd() *PushRpcCmd {
|
||||
var pushConfig push.Config
|
||||
ret := &PushRpcCmd{pushConfig: &pushConfig}
|
||||
ret.configMap = map[string]any{
|
||||
OpenIMPushCfgFileName: &pushConfig.RpcConfig,
|
||||
RedisConfigFileName: &pushConfig.RedisConfig,
|
||||
KafkaConfigFileName: &pushConfig.KafkaConfig,
|
||||
ShareFileName: &pushConfig.Share,
|
||||
NotificationFileName: &pushConfig.NotificationConfig,
|
||||
WebhooksConfigFileName: &pushConfig.WebhooksConfig,
|
||||
LocalCacheConfigFileName: &pushConfig.LocalCacheConfig,
|
||||
DiscoveryConfigFilename: &pushConfig.Discovery,
|
||||
config.OpenIMPushCfgFileName: &pushConfig.RpcConfig,
|
||||
config.RedisConfigFileName: &pushConfig.RedisConfig,
|
||||
config.KafkaConfigFileName: &pushConfig.KafkaConfig,
|
||||
config.ShareFileName: &pushConfig.Share,
|
||||
config.NotificationFileName: &pushConfig.NotificationConfig,
|
||||
config.WebhooksConfigFileName: &pushConfig.WebhooksConfig,
|
||||
config.LocalCacheConfigFileName: &pushConfig.LocalCacheConfig,
|
||||
config.DiscoveryConfigFilename: &pushConfig.Discovery,
|
||||
}
|
||||
ret.RootCmd = NewRootCmd(program.GetProcessName(), WithConfigMap(ret.configMap))
|
||||
ret.ctx = context.WithValue(context.Background(), "version", version.Version)
|
||||
@@ -60,9 +61,19 @@ func (a *PushRpcCmd) Exec() error {
|
||||
func (a *PushRpcCmd) runE() error {
|
||||
return startrpc.Start(a.ctx, &a.pushConfig.Discovery, &a.pushConfig.RpcConfig.Prometheus, a.pushConfig.RpcConfig.RPC.ListenIP,
|
||||
a.pushConfig.RpcConfig.RPC.RegisterIP, a.pushConfig.RpcConfig.RPC.AutoSetPorts, a.pushConfig.RpcConfig.RPC.Ports,
|
||||
a.Index(), a.pushConfig.Share.RpcRegisterName.Push, &a.pushConfig.Share, a.pushConfig,
|
||||
a.Index(), a.pushConfig.Discovery.RpcService.Push, &a.pushConfig.NotificationConfig, a.pushConfig,
|
||||
[]string{
|
||||
a.pushConfig.Share.RpcRegisterName.MessageGateway,
|
||||
a.pushConfig.RpcConfig.GetConfigFileName(),
|
||||
a.pushConfig.RedisConfig.GetConfigFileName(),
|
||||
a.pushConfig.KafkaConfig.GetConfigFileName(),
|
||||
a.pushConfig.NotificationConfig.GetConfigFileName(),
|
||||
a.pushConfig.Share.GetConfigFileName(),
|
||||
a.pushConfig.WebhooksConfig.GetConfigFileName(),
|
||||
a.pushConfig.LocalCacheConfig.GetConfigFileName(),
|
||||
a.pushConfig.Discovery.GetConfigFileName(),
|
||||
},
|
||||
[]string{
|
||||
a.pushConfig.Discovery.RpcService.MessageGateway,
|
||||
},
|
||||
push.Start)
|
||||
}
|
||||
|
||||
+103
-25
@@ -1,28 +1,20 @@
|
||||
// Copyright © 2023 OpenIM. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
|
||||
"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/version"
|
||||
"github.com/openimsdk/tools/discovery/etcd"
|
||||
"github.com/openimsdk/tools/errs"
|
||||
"github.com/openimsdk/tools/log"
|
||||
"github.com/openimsdk/tools/utils/runtimeenv"
|
||||
"github.com/spf13/cobra"
|
||||
clientv3 "go.etcd.io/etcd/client/v3"
|
||||
)
|
||||
|
||||
type RootCmd struct {
|
||||
@@ -33,6 +25,7 @@ type RootCmd struct {
|
||||
log config.Log
|
||||
index int
|
||||
configPath string
|
||||
etcdClient *clientv3.Client
|
||||
}
|
||||
|
||||
func (r *RootCmd) ConfigPath() string {
|
||||
@@ -80,23 +73,49 @@ func NewRootCmd(processName string, opts ...func(*CmdOpts)) *RootCmd {
|
||||
SilenceUsage: true,
|
||||
SilenceErrors: false,
|
||||
}
|
||||
cmd.Flags().StringP(FlagConf, "c", "", "path of config directory")
|
||||
cmd.Flags().IntP(FlagTransferIndex, "i", 0, "process startup sequence number")
|
||||
cmd.Flags().StringP(config.FlagConf, "c", "", "path of config directory")
|
||||
cmd.Flags().IntP(config.FlagTransferIndex, "i", 0, "process startup sequence number")
|
||||
|
||||
rootCmd.Command = cmd
|
||||
return rootCmd
|
||||
}
|
||||
|
||||
func (r *RootCmd) initEtcd() error {
|
||||
configDirectory, _, err := r.getFlag(&r.Command)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
disConfig := config.Discovery{}
|
||||
env := runtimeenv.PrintRuntimeEnvironment()
|
||||
err = config.Load(configDirectory, config.DiscoveryConfigFilename, config.EnvPrefixMap[config.DiscoveryConfigFilename],
|
||||
env, &disConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if disConfig.Enable == config.ETCD {
|
||||
discov, _ := kdisc.NewDiscoveryRegister(&disConfig, env, nil)
|
||||
r.etcdClient = discov.(*etcd.SvcDiscoveryRegistryImpl).GetClient()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *RootCmd) persistentPreRun(cmd *cobra.Command, opts ...func(*CmdOpts)) error {
|
||||
if err := r.initEtcd(); err != nil {
|
||||
return err
|
||||
}
|
||||
cmdOpts := r.applyOptions(opts...)
|
||||
if err := r.initializeConfiguration(cmd, cmdOpts); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := r.updateConfigFromEtcd(cmdOpts); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := r.initializeLogger(cmdOpts); err != nil {
|
||||
return errs.WrapMsg(err, "failed to initialize logger")
|
||||
}
|
||||
|
||||
if err := r.etcdClient.Close(); err != nil {
|
||||
return errs.WrapMsg(err, "failed to close etcd client")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -105,18 +124,77 @@ func (r *RootCmd) initializeConfiguration(cmd *cobra.Command, opts *CmdOpts) err
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
runtimeEnv := runtimeenv.PrintRuntimeEnvironment()
|
||||
|
||||
// Load common configuration file
|
||||
//opts.configMap[ShareFileName] = StructEnvPrefix{EnvPrefix: shareEnvPrefix, ConfigStruct: &r.share}
|
||||
for configFileName, configStruct := range opts.configMap {
|
||||
err := config.LoadConfig(filepath.Join(configDirectory, configFileName),
|
||||
ConfigEnvPrefixMap[configFileName], configStruct)
|
||||
err := config.Load(configDirectory, configFileName, config.EnvPrefixMap[configFileName], runtimeEnv, configStruct)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
// Load common log configuration file
|
||||
return config.LoadConfig(filepath.Join(configDirectory, LogConfigFileName),
|
||||
ConfigEnvPrefixMap[LogConfigFileName], &r.log)
|
||||
return config.Load(configDirectory, config.LogConfigFileName, config.EnvPrefixMap[config.LogConfigFileName], runtimeEnv, &r.log)
|
||||
}
|
||||
|
||||
func (r *RootCmd) updateConfigFromEtcd(opts *CmdOpts) error {
|
||||
if r.etcdClient == nil {
|
||||
return nil
|
||||
}
|
||||
ctx := context.TODO()
|
||||
|
||||
res, err := r.etcdClient.Get(ctx, disetcd.BuildKey(disetcd.EnableConfigCenterKey))
|
||||
if err != nil {
|
||||
log.ZWarn(ctx, "root cmd updateConfigFromEtcd, etcd Get EnableConfigCenterKey err: %v", errs.Wrap(err))
|
||||
return nil
|
||||
}
|
||||
if res.Count == 0 {
|
||||
return nil
|
||||
} else {
|
||||
if string(res.Kvs[0].Value) == disetcd.Disable {
|
||||
return nil
|
||||
} else if string(res.Kvs[0].Value) != disetcd.Enable {
|
||||
return errs.New("unknown EnableConfigCenter value").Wrap()
|
||||
}
|
||||
}
|
||||
|
||||
update := func(configFileName string, configStruct any) error {
|
||||
key := disetcd.BuildKey(configFileName)
|
||||
etcdRes, err := r.etcdClient.Get(ctx, key)
|
||||
if err != nil {
|
||||
log.ZWarn(ctx, "root cmd updateConfigFromEtcd, etcd Get err: %v", errs.Wrap(err))
|
||||
return nil
|
||||
}
|
||||
if etcdRes.Count == 0 {
|
||||
data, err := json.Marshal(configStruct)
|
||||
if err != nil {
|
||||
return errs.ErrArgs.WithDetail(err.Error()).Wrap()
|
||||
}
|
||||
_, err = r.etcdClient.Put(ctx, disetcd.BuildKey(configFileName), string(data))
|
||||
if err != nil {
|
||||
log.ZWarn(ctx, "root cmd updateConfigFromEtcd, etcd Put err: %v", errs.Wrap(err))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
err = json.Unmarshal(etcdRes.Kvs[0].Value, configStruct)
|
||||
if err != nil {
|
||||
return errs.WrapMsg(err, "failed to unmarshal config from etcd")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
for configFileName, configStruct := range opts.configMap {
|
||||
if err := update(configFileName, configStruct); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err := update(config.LogConfigFileName, &r.log); err != nil {
|
||||
return err
|
||||
}
|
||||
// Load common log configuration file
|
||||
return nil
|
||||
|
||||
}
|
||||
|
||||
func (r *RootCmd) applyOptions(opts ...func(*CmdOpts)) *CmdOpts {
|
||||
@@ -157,12 +235,12 @@ func defaultCmdOpts() *CmdOpts {
|
||||
}
|
||||
|
||||
func (r *RootCmd) getFlag(cmd *cobra.Command) (string, int, error) {
|
||||
configDirectory, err := cmd.Flags().GetString(FlagConf)
|
||||
configDirectory, err := cmd.Flags().GetString(config.FlagConf)
|
||||
if err != nil {
|
||||
return "", 0, errs.Wrap(err)
|
||||
}
|
||||
r.configPath = configDirectory
|
||||
index, err := cmd.Flags().GetInt(FlagTransferIndex)
|
||||
index, err := cmd.Flags().GetInt(config.FlagTransferIndex)
|
||||
if err != nil {
|
||||
return "", 0, errs.Wrap(err)
|
||||
}
|
||||
|
||||
+20
-10
@@ -18,6 +18,7 @@ import (
|
||||
"context"
|
||||
|
||||
"github.com/openimsdk/open-im-server/v3/internal/rpc/third"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/startrpc"
|
||||
"github.com/openimsdk/open-im-server/v3/version"
|
||||
"github.com/openimsdk/tools/system/program"
|
||||
@@ -35,14 +36,14 @@ func NewThirdRpcCmd() *ThirdRpcCmd {
|
||||
var thirdConfig third.Config
|
||||
ret := &ThirdRpcCmd{thirdConfig: &thirdConfig}
|
||||
ret.configMap = map[string]any{
|
||||
OpenIMRPCThirdCfgFileName: &thirdConfig.RpcConfig,
|
||||
RedisConfigFileName: &thirdConfig.RedisConfig,
|
||||
MongodbConfigFileName: &thirdConfig.MongodbConfig,
|
||||
ShareFileName: &thirdConfig.Share,
|
||||
NotificationFileName: &thirdConfig.NotificationConfig,
|
||||
MinioConfigFileName: &thirdConfig.MinioConfig,
|
||||
LocalCacheConfigFileName: &thirdConfig.LocalCacheConfig,
|
||||
DiscoveryConfigFilename: &thirdConfig.Discovery,
|
||||
config.OpenIMRPCThirdCfgFileName: &thirdConfig.RpcConfig,
|
||||
config.RedisConfigFileName: &thirdConfig.RedisConfig,
|
||||
config.MongodbConfigFileName: &thirdConfig.MongodbConfig,
|
||||
config.ShareFileName: &thirdConfig.Share,
|
||||
config.NotificationFileName: &thirdConfig.NotificationConfig,
|
||||
config.MinioConfigFileName: &thirdConfig.MinioConfig,
|
||||
config.LocalCacheConfigFileName: &thirdConfig.LocalCacheConfig,
|
||||
config.DiscoveryConfigFilename: &thirdConfig.Discovery,
|
||||
}
|
||||
ret.RootCmd = NewRootCmd(program.GetProcessName(), WithConfigMap(ret.configMap))
|
||||
ret.ctx = context.WithValue(context.Background(), "version", version.Version)
|
||||
@@ -59,7 +60,16 @@ func (a *ThirdRpcCmd) Exec() error {
|
||||
func (a *ThirdRpcCmd) runE() error {
|
||||
return startrpc.Start(a.ctx, &a.thirdConfig.Discovery, &a.thirdConfig.RpcConfig.Prometheus, a.thirdConfig.RpcConfig.RPC.ListenIP,
|
||||
a.thirdConfig.RpcConfig.RPC.RegisterIP, a.thirdConfig.RpcConfig.RPC.AutoSetPorts, a.thirdConfig.RpcConfig.RPC.Ports,
|
||||
a.Index(), a.thirdConfig.Share.RpcRegisterName.Third, &a.thirdConfig.Share, a.thirdConfig,
|
||||
nil,
|
||||
a.Index(), a.thirdConfig.Discovery.RpcService.Third, &a.thirdConfig.NotificationConfig, a.thirdConfig,
|
||||
[]string{
|
||||
a.thirdConfig.RpcConfig.GetConfigFileName(),
|
||||
a.thirdConfig.RedisConfig.GetConfigFileName(),
|
||||
a.thirdConfig.MongodbConfig.GetConfigFileName(),
|
||||
a.thirdConfig.NotificationConfig.GetConfigFileName(),
|
||||
a.thirdConfig.Share.GetConfigFileName(),
|
||||
a.thirdConfig.MinioConfig.GetConfigFileName(),
|
||||
a.thirdConfig.LocalCacheConfig.GetConfigFileName(),
|
||||
a.thirdConfig.Discovery.GetConfigFileName(),
|
||||
}, nil,
|
||||
third.Start)
|
||||
}
|
||||
|
||||
+22
-11
@@ -18,6 +18,7 @@ import (
|
||||
"context"
|
||||
|
||||
"github.com/openimsdk/open-im-server/v3/internal/rpc/user"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/startrpc"
|
||||
"github.com/openimsdk/open-im-server/v3/version"
|
||||
"github.com/openimsdk/tools/system/program"
|
||||
@@ -35,15 +36,15 @@ func NewUserRpcCmd() *UserRpcCmd {
|
||||
var userConfig user.Config
|
||||
ret := &UserRpcCmd{userConfig: &userConfig}
|
||||
ret.configMap = map[string]any{
|
||||
OpenIMRPCUserCfgFileName: &userConfig.RpcConfig,
|
||||
RedisConfigFileName: &userConfig.RedisConfig,
|
||||
MongodbConfigFileName: &userConfig.MongodbConfig,
|
||||
KafkaConfigFileName: &userConfig.KafkaConfig,
|
||||
ShareFileName: &userConfig.Share,
|
||||
NotificationFileName: &userConfig.NotificationConfig,
|
||||
WebhooksConfigFileName: &userConfig.WebhooksConfig,
|
||||
LocalCacheConfigFileName: &userConfig.LocalCacheConfig,
|
||||
DiscoveryConfigFilename: &userConfig.Discovery,
|
||||
config.OpenIMRPCUserCfgFileName: &userConfig.RpcConfig,
|
||||
config.RedisConfigFileName: &userConfig.RedisConfig,
|
||||
config.MongodbConfigFileName: &userConfig.MongodbConfig,
|
||||
config.KafkaConfigFileName: &userConfig.KafkaConfig,
|
||||
config.ShareFileName: &userConfig.Share,
|
||||
config.NotificationFileName: &userConfig.NotificationConfig,
|
||||
config.WebhooksConfigFileName: &userConfig.WebhooksConfig,
|
||||
config.LocalCacheConfigFileName: &userConfig.LocalCacheConfig,
|
||||
config.DiscoveryConfigFilename: &userConfig.Discovery,
|
||||
}
|
||||
ret.RootCmd = NewRootCmd(program.GetProcessName(), WithConfigMap(ret.configMap))
|
||||
ret.ctx = context.WithValue(context.Background(), "version", version.Version)
|
||||
@@ -60,7 +61,17 @@ func (a *UserRpcCmd) Exec() error {
|
||||
func (a *UserRpcCmd) runE() error {
|
||||
return startrpc.Start(a.ctx, &a.userConfig.Discovery, &a.userConfig.RpcConfig.Prometheus, a.userConfig.RpcConfig.RPC.ListenIP,
|
||||
a.userConfig.RpcConfig.RPC.RegisterIP, a.userConfig.RpcConfig.RPC.AutoSetPorts, a.userConfig.RpcConfig.RPC.Ports,
|
||||
a.Index(), a.userConfig.Share.RpcRegisterName.User, &a.userConfig.Share, a.userConfig,
|
||||
nil,
|
||||
a.Index(), a.userConfig.Discovery.RpcService.User, &a.userConfig.NotificationConfig, a.userConfig,
|
||||
[]string{
|
||||
a.userConfig.RpcConfig.GetConfigFileName(),
|
||||
a.userConfig.RedisConfig.GetConfigFileName(),
|
||||
a.userConfig.MongodbConfig.GetConfigFileName(),
|
||||
a.userConfig.KafkaConfig.GetConfigFileName(),
|
||||
a.userConfig.NotificationConfig.GetConfigFileName(),
|
||||
a.userConfig.Share.GetConfigFileName(),
|
||||
a.userConfig.WebhooksConfig.GetConfigFileName(),
|
||||
a.userConfig.LocalCacheConfig.GetConfigFileName(),
|
||||
a.userConfig.Discovery.GetConfigFileName(),
|
||||
}, nil,
|
||||
user.Start)
|
||||
}
|
||||
|
||||
+211
-9
@@ -18,9 +18,9 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/storage/kafka"
|
||||
"github.com/openimsdk/tools/db/mongoutil"
|
||||
"github.com/openimsdk/tools/db/redisutil"
|
||||
"github.com/openimsdk/tools/mq/kafka"
|
||||
"github.com/openimsdk/tools/s3/aws"
|
||||
"github.com/openimsdk/tools/s3/cos"
|
||||
"github.com/openimsdk/tools/s3/kodo"
|
||||
@@ -380,10 +380,9 @@ type AfterConfig struct {
|
||||
}
|
||||
|
||||
type Share struct {
|
||||
Secret string `mapstructure:"secret"`
|
||||
RpcRegisterName RpcRegisterName `mapstructure:"rpcRegisterName"`
|
||||
IMAdminUserID []string `mapstructure:"imAdminUserID"`
|
||||
MultiLogin MultiLogin `mapstructure:"multiLogin"`
|
||||
Secret string `mapstructure:"secret"`
|
||||
IMAdminUserID []string `mapstructure:"imAdminUserID"`
|
||||
MultiLogin MultiLogin `mapstructure:"multiLogin"`
|
||||
}
|
||||
|
||||
type MultiLogin struct {
|
||||
@@ -478,11 +477,41 @@ type ZooKeeper struct {
|
||||
}
|
||||
|
||||
type Discovery struct {
|
||||
Enable string `mapstructure:"enable"`
|
||||
Etcd Etcd `mapstructure:"etcd"`
|
||||
ZooKeeper ZooKeeper `mapstructure:"zooKeeper"`
|
||||
Enable string `mapstructure:"enable"`
|
||||
Etcd Etcd `mapstructure:"etcd"`
|
||||
Kubernetes Kubernetes `mapstructure:"kubernetes"`
|
||||
RpcService RpcService `mapstructure:"rpcService"`
|
||||
}
|
||||
|
||||
type RpcService struct {
|
||||
User string `mapstructure:"user"`
|
||||
Friend string `mapstructure:"friend"`
|
||||
Msg string `mapstructure:"msg"`
|
||||
Push string `mapstructure:"push"`
|
||||
MessageGateway string `mapstructure:"messageGateway"`
|
||||
Group string `mapstructure:"group"`
|
||||
Auth string `mapstructure:"auth"`
|
||||
Conversation string `mapstructure:"conversation"`
|
||||
Third string `mapstructure:"third"`
|
||||
}
|
||||
|
||||
func (r *RpcService) GetServiceNames() []string {
|
||||
return []string{
|
||||
r.User,
|
||||
r.Friend,
|
||||
r.Msg,
|
||||
r.Push,
|
||||
r.MessageGateway,
|
||||
r.Group,
|
||||
r.Auth,
|
||||
r.Conversation,
|
||||
r.Third,
|
||||
}
|
||||
}
|
||||
|
||||
type Kubernetes struct {
|
||||
Namespace string `yaml:"namespace"`
|
||||
}
|
||||
type Etcd struct {
|
||||
RootDirectory string `mapstructure:"rootDirectory"`
|
||||
Address []string `mapstructure:"address"`
|
||||
@@ -606,7 +635,7 @@ func (l *CacheConfig) Enable() bool {
|
||||
return l.Topic != "" && l.SlotNum > 0 && l.SlotSize > 0
|
||||
}
|
||||
|
||||
var (
|
||||
const (
|
||||
DiscoveryConfigFilename = "discovery.yml"
|
||||
KafkaConfigFileName = "kafka.yml"
|
||||
LocalCacheConfigFileName = "local-cache.yml"
|
||||
@@ -628,6 +657,7 @@ var (
|
||||
RedisConfigFileName = "redis.yml"
|
||||
ShareFileName = "share.yml"
|
||||
WebhooksConfigFileName = "webhooks.yml"
|
||||
NotificationFileName = "notification.yml"
|
||||
)
|
||||
|
||||
func (d *Discovery) GetConfigFileName() string {
|
||||
@@ -717,3 +747,175 @@ func (s *Share) GetConfigFileName() string {
|
||||
func (w *Webhooks) GetConfigFileName() string {
|
||||
return WebhooksConfigFileName
|
||||
}
|
||||
|
||||
func InitNotification(notification *Notification) {
|
||||
notification.GroupCreated.UnreadCount = false
|
||||
notification.GroupCreated.ReliabilityLevel = 1
|
||||
notification.GroupInfoSet.UnreadCount = false
|
||||
notification.GroupInfoSet.ReliabilityLevel = 1
|
||||
notification.JoinGroupApplication.UnreadCount = false
|
||||
notification.JoinGroupApplication.ReliabilityLevel = 1
|
||||
notification.MemberQuit.UnreadCount = false
|
||||
notification.MemberQuit.ReliabilityLevel = 1
|
||||
notification.GroupApplicationAccepted.UnreadCount = false
|
||||
notification.GroupApplicationAccepted.ReliabilityLevel = 1
|
||||
notification.GroupApplicationRejected.UnreadCount = false
|
||||
notification.GroupApplicationRejected.ReliabilityLevel = 1
|
||||
notification.GroupOwnerTransferred.UnreadCount = false
|
||||
notification.GroupOwnerTransferred.ReliabilityLevel = 1
|
||||
notification.MemberKicked.UnreadCount = false
|
||||
notification.MemberKicked.ReliabilityLevel = 1
|
||||
notification.MemberInvited.UnreadCount = false
|
||||
notification.MemberInvited.ReliabilityLevel = 1
|
||||
notification.MemberEnter.UnreadCount = false
|
||||
notification.MemberEnter.ReliabilityLevel = 1
|
||||
notification.GroupDismissed.UnreadCount = false
|
||||
notification.GroupDismissed.ReliabilityLevel = 1
|
||||
notification.GroupMuted.UnreadCount = false
|
||||
notification.GroupMuted.ReliabilityLevel = 1
|
||||
notification.GroupCancelMuted.UnreadCount = false
|
||||
notification.GroupCancelMuted.ReliabilityLevel = 1
|
||||
notification.GroupMemberMuted.UnreadCount = false
|
||||
notification.GroupMemberMuted.ReliabilityLevel = 1
|
||||
notification.GroupMemberCancelMuted.UnreadCount = false
|
||||
notification.GroupMemberCancelMuted.ReliabilityLevel = 1
|
||||
notification.GroupMemberInfoSet.UnreadCount = false
|
||||
notification.GroupMemberInfoSet.ReliabilityLevel = 1
|
||||
notification.GroupMemberSetToAdmin.UnreadCount = false
|
||||
notification.GroupMemberSetToAdmin.ReliabilityLevel = 1
|
||||
notification.GroupMemberSetToOrdinary.UnreadCount = false
|
||||
notification.GroupMemberSetToOrdinary.ReliabilityLevel = 1
|
||||
notification.GroupInfoSetAnnouncement.UnreadCount = false
|
||||
notification.GroupInfoSetAnnouncement.ReliabilityLevel = 1
|
||||
notification.GroupInfoSetName.UnreadCount = false
|
||||
notification.GroupInfoSetName.ReliabilityLevel = 1
|
||||
notification.FriendApplicationAdded.UnreadCount = false
|
||||
notification.FriendApplicationAdded.ReliabilityLevel = 1
|
||||
notification.FriendApplicationApproved.UnreadCount = false
|
||||
notification.FriendApplicationApproved.ReliabilityLevel = 1
|
||||
notification.FriendApplicationRejected.UnreadCount = false
|
||||
notification.FriendApplicationRejected.ReliabilityLevel = 1
|
||||
notification.FriendAdded.UnreadCount = false
|
||||
notification.FriendAdded.ReliabilityLevel = 1
|
||||
notification.FriendDeleted.UnreadCount = false
|
||||
notification.FriendDeleted.ReliabilityLevel = 1
|
||||
notification.FriendRemarkSet.UnreadCount = false
|
||||
notification.FriendRemarkSet.ReliabilityLevel = 1
|
||||
notification.BlackAdded.UnreadCount = false
|
||||
notification.BlackAdded.ReliabilityLevel = 1
|
||||
notification.BlackDeleted.UnreadCount = false
|
||||
notification.BlackDeleted.ReliabilityLevel = 1
|
||||
notification.FriendInfoUpdated.UnreadCount = false
|
||||
notification.FriendInfoUpdated.ReliabilityLevel = 1
|
||||
notification.UserInfoUpdated.UnreadCount = false
|
||||
notification.UserInfoUpdated.ReliabilityLevel = 1
|
||||
notification.UserStatusChanged.UnreadCount = false
|
||||
notification.UserStatusChanged.ReliabilityLevel = 1
|
||||
notification.ConversationChanged.UnreadCount = false
|
||||
notification.ConversationChanged.ReliabilityLevel = 1
|
||||
notification.ConversationSetPrivate.UnreadCount = false
|
||||
notification.ConversationSetPrivate.ReliabilityLevel = 1
|
||||
}
|
||||
|
||||
type AllConfig struct {
|
||||
Discovery Discovery
|
||||
Kafka Kafka
|
||||
LocalCache LocalCache
|
||||
Log Log
|
||||
Minio Minio
|
||||
Mongo Mongo
|
||||
Notification Notification
|
||||
API API
|
||||
CronTask CronTask
|
||||
MsgGateway MsgGateway
|
||||
MsgTransfer MsgTransfer
|
||||
Push Push
|
||||
Auth Auth
|
||||
Conversation Conversation
|
||||
Friend Friend
|
||||
Group Group
|
||||
Msg Msg
|
||||
Third Third
|
||||
User User
|
||||
Redis Redis
|
||||
Share Share
|
||||
Webhooks Webhooks
|
||||
}
|
||||
|
||||
func (a *AllConfig) Name2Config(name string) any {
|
||||
switch name {
|
||||
case a.Discovery.GetConfigFileName():
|
||||
return a.Discovery
|
||||
case a.Kafka.GetConfigFileName():
|
||||
return a.Kafka
|
||||
case a.LocalCache.GetConfigFileName():
|
||||
return a.LocalCache
|
||||
case a.Log.GetConfigFileName():
|
||||
return a.Log
|
||||
case a.Minio.GetConfigFileName():
|
||||
return a.Minio
|
||||
case a.Mongo.GetConfigFileName():
|
||||
return a.Mongo
|
||||
case a.Notification.GetConfigFileName():
|
||||
return a.Notification
|
||||
case a.API.GetConfigFileName():
|
||||
return a.API
|
||||
case a.CronTask.GetConfigFileName():
|
||||
return a.CronTask
|
||||
case a.MsgGateway.GetConfigFileName():
|
||||
return a.MsgGateway
|
||||
case a.MsgTransfer.GetConfigFileName():
|
||||
return a.MsgTransfer
|
||||
case a.Push.GetConfigFileName():
|
||||
return a.Push
|
||||
case a.Auth.GetConfigFileName():
|
||||
return a.Auth
|
||||
case a.Conversation.GetConfigFileName():
|
||||
return a.Conversation
|
||||
case a.Friend.GetConfigFileName():
|
||||
return a.Friend
|
||||
case a.Group.GetConfigFileName():
|
||||
return a.Group
|
||||
case a.Msg.GetConfigFileName():
|
||||
return a.Msg
|
||||
case a.Third.GetConfigFileName():
|
||||
return a.Third
|
||||
case a.User.GetConfigFileName():
|
||||
return a.User
|
||||
case a.Redis.GetConfigFileName():
|
||||
return a.Redis
|
||||
case a.Share.GetConfigFileName():
|
||||
return a.Share
|
||||
case a.Webhooks.GetConfigFileName():
|
||||
return a.Webhooks
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func (a *AllConfig) GetConfigNames() []string {
|
||||
return []string{
|
||||
a.Discovery.GetConfigFileName(),
|
||||
a.Kafka.GetConfigFileName(),
|
||||
a.LocalCache.GetConfigFileName(),
|
||||
a.Log.GetConfigFileName(),
|
||||
a.Minio.GetConfigFileName(),
|
||||
a.Mongo.GetConfigFileName(),
|
||||
a.Notification.GetConfigFileName(),
|
||||
a.API.GetConfigFileName(),
|
||||
a.CronTask.GetConfigFileName(),
|
||||
a.MsgGateway.GetConfigFileName(),
|
||||
a.MsgTransfer.GetConfigFileName(),
|
||||
a.Push.GetConfigFileName(),
|
||||
a.Auth.GetConfigFileName(),
|
||||
a.Conversation.GetConfigFileName(),
|
||||
a.Friend.GetConfigFileName(),
|
||||
a.Group.GetConfigFileName(),
|
||||
a.Msg.GetConfigFileName(),
|
||||
a.Third.GetConfigFileName(),
|
||||
a.User.GetConfigFileName(),
|
||||
a.Redis.GetConfigFileName(),
|
||||
a.Share.GetConfigFileName(),
|
||||
a.Webhooks.GetConfigFileName(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
|
||||
package config
|
||||
|
||||
const ConfKey = "conf"
|
||||
|
||||
const (
|
||||
MountConfigFilePath = "CONFIG_PATH"
|
||||
DeploymentType = "DEPLOYMENT_TYPE"
|
||||
|
||||
@@ -1,13 +1,29 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/mitchellh/mapstructure"
|
||||
"github.com/openimsdk/tools/errs"
|
||||
"github.com/spf13/viper"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func LoadConfig(path string, envPrefix string, config any) error {
|
||||
func Load(configDirectory string, configFileName string, envPrefix string, runtimeEnv string, config any) error {
|
||||
if runtimeEnv == KUBERNETES {
|
||||
mountPath := os.Getenv(MountConfigFilePath)
|
||||
if mountPath == "" {
|
||||
return errs.ErrArgs.WrapMsg(MountConfigFilePath + " env is empty")
|
||||
}
|
||||
|
||||
return loadConfig(filepath.Join(mountPath, configFileName), envPrefix, config)
|
||||
}
|
||||
|
||||
return loadConfig(filepath.Join(configDirectory, configFileName), envPrefix, config)
|
||||
}
|
||||
|
||||
func loadConfig(path string, envPrefix string, config any) error {
|
||||
v := viper.New()
|
||||
v.SetConfigFile(path)
|
||||
v.SetEnvPrefix(envPrefix)
|
||||
|
||||
@@ -26,9 +26,7 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
FileName = "config.yaml"
|
||||
NotificationFileName = "notification.yaml"
|
||||
DefaultFolderPath = "../config/"
|
||||
FileName = "config.yaml"
|
||||
)
|
||||
|
||||
// return absolude path join ../config/, this is k8s container config path.
|
||||
@@ -58,13 +56,10 @@ func GetProjectRoot() (string, error) {
|
||||
return projectRoot, nil
|
||||
}
|
||||
|
||||
func GetOptionsByNotification(cfg NotificationConfig, sendMessage *bool) msgprocessor.Options {
|
||||
func GetOptionsByNotification(cfg NotificationConfig) msgprocessor.Options {
|
||||
opts := msgprocessor.NewOptions()
|
||||
|
||||
if sendMessage != nil {
|
||||
cfg.IsSendMsg = *sendMessage
|
||||
}
|
||||
if cfg.IsSendMsg {
|
||||
if cfg.UnreadCount {
|
||||
opts = msgprocessor.WithOptions(opts, msgprocessor.WithUnreadCount(true))
|
||||
}
|
||||
if cfg.OfflinePush.Enable {
|
||||
|
||||
@@ -12,4 +12,4 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package direct // import "github.com/openimsdk/open-im-server/v3/pkg/common/discoveryregister/direct"
|
||||
package direct // import "github.com/openimsdk/open-im-server/v3/pkg/common/discovery/direct"
|
||||
+13
-9
@@ -12,29 +12,33 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package discoveryregister
|
||||
package discovery
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
||||
"github.com/openimsdk/tools/discovery"
|
||||
"github.com/openimsdk/tools/discovery/etcd"
|
||||
"github.com/openimsdk/tools/discovery/kubernetes"
|
||||
"github.com/openimsdk/tools/errs"
|
||||
"google.golang.org/grpc"
|
||||
|
||||
"github.com/openimsdk/tools/discovery/kubernetes"
|
||||
|
||||
"github.com/openimsdk/tools/discovery/etcd"
|
||||
"github.com/openimsdk/tools/errs"
|
||||
)
|
||||
|
||||
// NewDiscoveryRegister creates a new service discovery and registry client based on the provided environment type.
|
||||
func NewDiscoveryRegister(discovery *config.Discovery, share *config.Share, watchNames []string) (discovery.SvcDiscoveryRegistry, error) {
|
||||
switch discovery.Enable {
|
||||
case "k8s":
|
||||
return kubernetes.NewKubernetesConnManager("default",
|
||||
func NewDiscoveryRegister(discovery *config.Discovery, runtimeEnv string, watchNames []string) (discovery.SvcDiscoveryRegistry, error) {
|
||||
if runtimeEnv == config.KUBERNETES {
|
||||
return kubernetes.NewKubernetesConnManager(discovery.Kubernetes.Namespace,
|
||||
grpc.WithDefaultCallOptions(
|
||||
grpc.MaxCallSendMsgSize(1024*1024*20),
|
||||
),
|
||||
)
|
||||
case "etcd":
|
||||
}
|
||||
|
||||
switch discovery.Enable {
|
||||
case config.ETCD:
|
||||
return etcd.NewSvcDiscoveryRegistry(
|
||||
discovery.Etcd.RootDirectory,
|
||||
discovery.Etcd.Address,
|
||||
+1
-1
@@ -12,7 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package discoveryregister
|
||||
package discovery
|
||||
|
||||
import (
|
||||
"os"
|
||||
@@ -12,4 +12,4 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package discoveryregister // import "github.com/openimsdk/open-im-server/v3/pkg/common/discoveryregister"
|
||||
package discovery // import "github.com/openimsdk/open-im-server/v3/pkg/common/discovery"
|
||||
@@ -0,0 +1,106 @@
|
||||
package etcd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"os/exec"
|
||||
"runtime"
|
||||
"sync"
|
||||
"syscall"
|
||||
|
||||
"github.com/openimsdk/tools/errs"
|
||||
"github.com/openimsdk/tools/log"
|
||||
"github.com/openimsdk/tools/utils/datautil"
|
||||
clientv3 "go.etcd.io/etcd/client/v3"
|
||||
)
|
||||
|
||||
var (
|
||||
ShutDowns []func() error
|
||||
)
|
||||
|
||||
func RegisterShutDown(shutDown ...func() error) {
|
||||
ShutDowns = append(ShutDowns, shutDown...)
|
||||
}
|
||||
|
||||
type ConfigManager struct {
|
||||
client *clientv3.Client
|
||||
watchConfigNames []string
|
||||
lock sync.Mutex
|
||||
}
|
||||
|
||||
func BuildKey(s string) string {
|
||||
return ConfigKeyPrefix + s
|
||||
}
|
||||
|
||||
func NewConfigManager(client *clientv3.Client, configNames []string) *ConfigManager {
|
||||
return &ConfigManager{
|
||||
client: client,
|
||||
watchConfigNames: datautil.Batch(func(s string) string { return BuildKey(s) }, append(configNames, RestartKey))}
|
||||
}
|
||||
|
||||
func (c *ConfigManager) Watch(ctx context.Context) {
|
||||
chans := make([]clientv3.WatchChan, 0, len(c.watchConfigNames))
|
||||
for _, name := range c.watchConfigNames {
|
||||
chans = append(chans, c.client.Watch(ctx, name, clientv3.WithPrefix()))
|
||||
}
|
||||
|
||||
doWatch := func(watchChan clientv3.WatchChan) {
|
||||
for watchResp := range watchChan {
|
||||
if watchResp.Err() != nil {
|
||||
log.ZError(ctx, "watch err", errs.Wrap(watchResp.Err()))
|
||||
continue
|
||||
}
|
||||
for _, event := range watchResp.Events {
|
||||
if event.IsModify() {
|
||||
if datautil.Contain(string(event.Kv.Key), c.watchConfigNames...) {
|
||||
c.lock.Lock()
|
||||
err := restartServer(ctx)
|
||||
if err != nil {
|
||||
log.ZError(ctx, "restart server err", err)
|
||||
}
|
||||
c.lock.Unlock()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, ch := range chans {
|
||||
go doWatch(ch)
|
||||
}
|
||||
}
|
||||
|
||||
func restartServer(ctx context.Context) error {
|
||||
exePath, err := os.Executable()
|
||||
if err != nil {
|
||||
return errs.New("get executable path fail").Wrap()
|
||||
}
|
||||
|
||||
args := os.Args
|
||||
env := os.Environ()
|
||||
|
||||
cmd := exec.Command(exePath, args[1:]...)
|
||||
cmd.Env = env
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
cmd.Stdin = os.Stdin
|
||||
|
||||
if runtime.GOOS != "windows" {
|
||||
cmd.SysProcAttr = &syscall.SysProcAttr{}
|
||||
}
|
||||
log.ZInfo(ctx, "shutdown server")
|
||||
for _, f := range ShutDowns {
|
||||
if err = f(); err != nil {
|
||||
log.ZError(ctx, "shutdown fail", err)
|
||||
}
|
||||
}
|
||||
|
||||
log.ZInfo(ctx, "restart server")
|
||||
err = cmd.Start()
|
||||
if err != nil {
|
||||
return errs.New("restart server fail").Wrap()
|
||||
}
|
||||
log.ZInfo(ctx, "cmd start over")
|
||||
|
||||
os.Exit(0)
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package etcd
|
||||
|
||||
const (
|
||||
ConfigKeyPrefix = "/open-im/config/"
|
||||
RestartKey = "restart"
|
||||
EnableConfigCenterKey = "enable-config-center"
|
||||
Enable = "enable"
|
||||
Disable = "disable"
|
||||
)
|
||||
@@ -12,4 +12,4 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package kubernetes // import "github.com/openimsdk/open-im-server/v3/pkg/common/discoveryregister/etcd"
|
||||
package kubernetes // import "github.com/openimsdk/open-im-server/v3/pkg/common/discovery/kubernetes"
|
||||
@@ -0,0 +1,270 @@
|
||||
package kubernetes
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/credentials/insecure"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/client-go/informers"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
)
|
||||
|
||||
type KubernetesConnManager struct {
|
||||
clientset *kubernetes.Clientset
|
||||
namespace string
|
||||
dialOptions []grpc.DialOption
|
||||
|
||||
rpcTargets map[string]string
|
||||
selfTarget string
|
||||
|
||||
mu sync.RWMutex
|
||||
connMap map[string][]*grpc.ClientConn
|
||||
}
|
||||
|
||||
// NewKubernetesConnManager creates a new connection manager that uses Kubernetes services for service discovery.
|
||||
func NewKubernetesConnManager(namespace string, options ...grpc.DialOption) (*KubernetesConnManager, error) {
|
||||
config, err := rest.InClusterConfig()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create in-cluster config: %v", err)
|
||||
}
|
||||
|
||||
clientset, err := kubernetes.NewForConfig(config)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create clientset: %v", err)
|
||||
}
|
||||
|
||||
k := &KubernetesConnManager{
|
||||
clientset: clientset,
|
||||
namespace: namespace,
|
||||
dialOptions: options,
|
||||
connMap: make(map[string][]*grpc.ClientConn),
|
||||
}
|
||||
|
||||
go k.watchEndpoints()
|
||||
|
||||
return k, nil
|
||||
}
|
||||
|
||||
func (k *KubernetesConnManager) initializeConns(serviceName string) error {
|
||||
port, err := k.getServicePort(serviceName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
endpoints, err := k.clientset.CoreV1().Endpoints(k.namespace).Get(context.Background(), serviceName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get endpoints for service %s: %v", serviceName, err)
|
||||
}
|
||||
|
||||
// fmt.Println("Endpoints:", endpoints, "endpoints.Subsets:", endpoints.Subsets)
|
||||
|
||||
var conns []*grpc.ClientConn
|
||||
for _, subset := range endpoints.Subsets {
|
||||
for _, address := range subset.Addresses {
|
||||
target := fmt.Sprintf("%s:%d", address.IP, port)
|
||||
// fmt.Println("IP target:", target)
|
||||
conn, err := grpc.Dial(target, append(k.dialOptions, grpc.WithTransportCredentials(insecure.NewCredentials()))...)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to dial endpoint %s: %v", target, err)
|
||||
}
|
||||
conns = append(conns, conn)
|
||||
}
|
||||
}
|
||||
|
||||
k.mu.Lock()
|
||||
k.connMap[serviceName] = conns
|
||||
k.mu.Unlock()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetConns returns gRPC client connections for a given Kubernetes service name.
|
||||
func (k *KubernetesConnManager) GetConns(ctx context.Context, serviceName string, opts ...grpc.DialOption) ([]*grpc.ClientConn, error) {
|
||||
k.mu.RLock()
|
||||
|
||||
conns, exists := k.connMap[serviceName]
|
||||
k.mu.RUnlock()
|
||||
if exists {
|
||||
return conns, nil
|
||||
}
|
||||
|
||||
k.mu.Lock()
|
||||
// Check if another goroutine has already initialized the connections when we released the read lock
|
||||
conns, exists = k.connMap[serviceName]
|
||||
if exists {
|
||||
return conns, nil
|
||||
}
|
||||
k.mu.Unlock()
|
||||
|
||||
if err := k.initializeConns(serviceName); err != nil {
|
||||
fmt.Println("Failed to initialize connections:", err)
|
||||
return nil, fmt.Errorf("failed to initialize connections for service %s: %v", serviceName, err)
|
||||
}
|
||||
|
||||
return k.connMap[serviceName], nil
|
||||
}
|
||||
|
||||
// GetConn returns a single gRPC client connection for a given Kubernetes service name.
|
||||
func (k *KubernetesConnManager) GetConn(ctx context.Context, serviceName string, opts ...grpc.DialOption) (*grpc.ClientConn, error) {
|
||||
var target string
|
||||
|
||||
if k.rpcTargets[serviceName] == "" {
|
||||
var err error
|
||||
|
||||
svcPort, err := k.getServicePort(serviceName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
target = fmt.Sprintf("%s.%s.svc.cluster.local:%d", serviceName, k.namespace, svcPort)
|
||||
|
||||
// fmt.Println("SVC target:", target)
|
||||
} else {
|
||||
target = k.rpcTargets[serviceName]
|
||||
}
|
||||
|
||||
return grpc.DialContext(
|
||||
ctx,
|
||||
target,
|
||||
append([]grpc.DialOption{
|
||||
grpc.WithTransportCredentials(insecure.NewCredentials()),
|
||||
grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(1024*1024*10), grpc.MaxCallSendMsgSize(1024*1024*20)),
|
||||
}, k.dialOptions...)...,
|
||||
)
|
||||
}
|
||||
|
||||
// GetSelfConnTarget returns the connection target for the current service.
|
||||
func (k *KubernetesConnManager) GetSelfConnTarget() string {
|
||||
if k.selfTarget == "" {
|
||||
hostName := os.Getenv("HOSTNAME")
|
||||
|
||||
pod, err := k.clientset.CoreV1().Pods(k.namespace).Get(context.Background(), hostName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
log.Printf("failed to get pod %s: %v \n", hostName, err)
|
||||
}
|
||||
|
||||
for pod.Status.PodIP == "" {
|
||||
pod, err = k.clientset.CoreV1().Pods(k.namespace).Get(context.TODO(), hostName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
log.Printf("Error getting pod: %v \n", err)
|
||||
}
|
||||
|
||||
time.Sleep(3 * time.Second)
|
||||
}
|
||||
|
||||
var selfPort int32
|
||||
|
||||
for _, port := range pod.Spec.Containers[0].Ports {
|
||||
if port.ContainerPort != 10001 {
|
||||
selfPort = port.ContainerPort
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
k.selfTarget = fmt.Sprintf("%s:%d", pod.Status.PodIP, selfPort)
|
||||
}
|
||||
|
||||
return k.selfTarget
|
||||
}
|
||||
|
||||
// AddOption appends gRPC dial options to the existing options.
|
||||
func (k *KubernetesConnManager) AddOption(opts ...grpc.DialOption) {
|
||||
k.mu.Lock()
|
||||
defer k.mu.Unlock()
|
||||
k.dialOptions = append(k.dialOptions, opts...)
|
||||
}
|
||||
|
||||
// CloseConn closes a given gRPC client connection.
|
||||
func (k *KubernetesConnManager) CloseConn(conn *grpc.ClientConn) {
|
||||
conn.Close()
|
||||
}
|
||||
|
||||
// Close closes all gRPC connections managed by KubernetesConnManager.
|
||||
func (k *KubernetesConnManager) Close() {
|
||||
k.mu.Lock()
|
||||
defer k.mu.Unlock()
|
||||
for _, conns := range k.connMap {
|
||||
for _, conn := range conns {
|
||||
_ = conn.Close()
|
||||
}
|
||||
}
|
||||
k.connMap = make(map[string][]*grpc.ClientConn)
|
||||
}
|
||||
|
||||
func (k *KubernetesConnManager) Register(serviceName, host string, port int, opts ...grpc.DialOption) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (k *KubernetesConnManager) UnRegister() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (k *KubernetesConnManager) GetUserIdHashGatewayHost(ctx context.Context, userId string) (string, error) {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func (k *KubernetesConnManager) getServicePort(serviceName string) (int32, error) {
|
||||
var svcPort int32
|
||||
|
||||
svc, err := k.clientset.CoreV1().Services(k.namespace).Get(context.Background(), serviceName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
fmt.Print("namespace:", k.namespace)
|
||||
return 0, fmt.Errorf("failed to get service %s: %v", serviceName, err)
|
||||
}
|
||||
|
||||
if len(svc.Spec.Ports) == 0 {
|
||||
return 0, fmt.Errorf("service %s has no ports defined", serviceName)
|
||||
}
|
||||
|
||||
for _, port := range svc.Spec.Ports {
|
||||
// fmt.Println(serviceName, " Now Get Port:", port.Port)
|
||||
if port.Port != 10001 {
|
||||
svcPort = port.Port
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return svcPort, nil
|
||||
}
|
||||
|
||||
// watchEndpoints listens for changes in Pod resources.
|
||||
func (k *KubernetesConnManager) watchEndpoints() {
|
||||
informerFactory := informers.NewSharedInformerFactory(k.clientset, time.Minute*10)
|
||||
informer := informerFactory.Core().V1().Pods().Informer()
|
||||
|
||||
// Watch for Pod changes (add, update, delete)
|
||||
informer.AddEventHandler(cache.ResourceEventHandlerFuncs{
|
||||
AddFunc: func(obj interface{}) {
|
||||
k.handleEndpointChange(obj)
|
||||
},
|
||||
UpdateFunc: func(oldObj, newObj interface{}) {
|
||||
k.handleEndpointChange(newObj)
|
||||
},
|
||||
DeleteFunc: func(obj interface{}) {
|
||||
k.handleEndpointChange(obj)
|
||||
},
|
||||
})
|
||||
|
||||
informerFactory.Start(context.Background().Done())
|
||||
<-context.Background().Done() // Block forever
|
||||
}
|
||||
|
||||
func (k *KubernetesConnManager) handleEndpointChange(obj interface{}) {
|
||||
endpoint, ok := obj.(*v1.Endpoints)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
serviceName := endpoint.Name
|
||||
if err := k.initializeConns(serviceName); err != nil {
|
||||
fmt.Printf("Error initializing connections for %s: %v\n", serviceName, err)
|
||||
}
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
// Copyright © 2024 OpenIM. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package zookeeper // import "github.com/openimsdk/open-im-server/v3/pkg/common/discoveryregister/zookeeper"
|
||||
@@ -43,25 +43,25 @@ func GetGrpcServerMetrics() *gp.ServerMetrics {
|
||||
return grpcMetrics
|
||||
}
|
||||
|
||||
func GetGrpcCusMetrics(registerName string, share *config.Share) []prometheus.Collector {
|
||||
func GetGrpcCusMetrics(registerName string, discovery *config.Discovery) []prometheus.Collector {
|
||||
switch registerName {
|
||||
case share.RpcRegisterName.MessageGateway:
|
||||
case discovery.RpcService.MessageGateway:
|
||||
return []prometheus.Collector{OnlineUserGauge}
|
||||
case share.RpcRegisterName.Msg:
|
||||
case discovery.RpcService.Msg:
|
||||
return []prometheus.Collector{
|
||||
SingleChatMsgProcessSuccessCounter,
|
||||
SingleChatMsgProcessFailedCounter,
|
||||
GroupChatMsgProcessSuccessCounter,
|
||||
GroupChatMsgProcessFailedCounter,
|
||||
}
|
||||
case share.RpcRegisterName.Push:
|
||||
case discovery.RpcService.Push:
|
||||
return []prometheus.Collector{
|
||||
MsgOfflinePushFailedCounter,
|
||||
MsgLoneTimePushCounter,
|
||||
}
|
||||
case share.RpcRegisterName.Auth:
|
||||
case discovery.RpcService.Auth:
|
||||
return []prometheus.Collector{UserLoginCounter}
|
||||
case share.RpcRegisterName.User:
|
||||
case discovery.RpcService.User:
|
||||
return []prometheus.Collector{UserRegisterCounter}
|
||||
default:
|
||||
return nil
|
||||
|
||||
@@ -27,12 +27,15 @@ import (
|
||||
"time"
|
||||
|
||||
conf "github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
||||
disetcd "github.com/openimsdk/open-im-server/v3/pkg/common/discovery/etcd"
|
||||
"github.com/openimsdk/tools/discovery/etcd"
|
||||
"github.com/openimsdk/tools/utils/datautil"
|
||||
"github.com/openimsdk/tools/utils/jsonutil"
|
||||
"google.golang.org/grpc/status"
|
||||
|
||||
kdisc "github.com/openimsdk/open-im-server/v3/pkg/common/discoveryregister"
|
||||
"github.com/openimsdk/tools/utils/runtimeenv"
|
||||
|
||||
kdisc "github.com/openimsdk/open-im-server/v3/pkg/common/discovery"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics"
|
||||
"github.com/openimsdk/tools/discovery"
|
||||
"github.com/openimsdk/tools/errs"
|
||||
@@ -45,11 +48,12 @@ import (
|
||||
|
||||
// Start rpc server.
|
||||
func Start[T any](ctx context.Context, discovery *conf.Discovery, prometheusConfig *conf.Prometheus, listenIP,
|
||||
registerIP string, autoSetPorts bool, rpcPorts []int, index int, rpcRegisterName string, share *conf.Share, config T,
|
||||
watchServiceNames []string,
|
||||
registerIP string, autoSetPorts bool, rpcPorts []int, index int, rpcRegisterName string, notification *conf.Notification, config T,
|
||||
watchConfigNames []string, watchServiceNames []string,
|
||||
rpcFn func(ctx context.Context, config T, client discovery.SvcDiscoveryRegistry, server *grpc.Server) error,
|
||||
options ...grpc.ServerOption) error {
|
||||
|
||||
watchConfigNames = append(watchConfigNames, conf.LogConfigFileName)
|
||||
var (
|
||||
rpcTcpAddr string
|
||||
netDone = make(chan struct{}, 2)
|
||||
@@ -57,11 +61,17 @@ func Start[T any](ctx context.Context, discovery *conf.Discovery, prometheusConf
|
||||
prometheusPort int
|
||||
)
|
||||
|
||||
if notification != nil {
|
||||
conf.InitNotification(notification)
|
||||
}
|
||||
|
||||
registerIP, err := network.GetRpcRegisterIP(registerIP)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
runTimeEnv := runtimeenv.PrintRuntimeEnvironment()
|
||||
|
||||
if !autoSetPorts {
|
||||
rpcPort, err := datautil.GetElemByIndex(rpcPorts, index)
|
||||
if err != nil {
|
||||
@@ -85,7 +95,7 @@ func Start[T any](ctx context.Context, discovery *conf.Discovery, prometheusConf
|
||||
if autoSetPorts && discovery.Enable != conf.ETCD {
|
||||
return errs.New("only etcd support autoSetPorts", "rpcRegisterName", rpcRegisterName).Wrap()
|
||||
}
|
||||
client, err := kdisc.NewDiscoveryRegister(discovery, share, watchServiceNames)
|
||||
client, err := kdisc.NewDiscoveryRegister(discovery, runTimeEnv, watchServiceNames)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -132,7 +142,7 @@ func Start[T any](ctx context.Context, discovery *conf.Discovery, prometheusConf
|
||||
return errs.WrapMsg(err, "listen err", "rpcTcpAddr", rpcTcpAddr)
|
||||
}
|
||||
}
|
||||
cs := prommetrics.GetGrpcCusMetrics(rpcRegisterName, share)
|
||||
cs := prommetrics.GetGrpcCusMetrics(rpcRegisterName, discovery)
|
||||
go func() {
|
||||
if err := prommetrics.RpcInit(cs, listener); err != nil && !errors.Is(err, http.ErrServerClosed) {
|
||||
netErr = errs.WrapMsg(err, fmt.Sprintf("rpc %s prometheus start err: %d", rpcRegisterName, prometheusPort))
|
||||
@@ -167,7 +177,6 @@ func Start[T any](ctx context.Context, discovery *conf.Discovery, prometheusConf
|
||||
}
|
||||
|
||||
err = client.Register(
|
||||
ctx,
|
||||
rpcRegisterName,
|
||||
registerIP,
|
||||
port,
|
||||
@@ -185,6 +194,11 @@ func Start[T any](ctx context.Context, discovery *conf.Discovery, prometheusConf
|
||||
}
|
||||
}()
|
||||
|
||||
if discovery.Enable == conf.ETCD {
|
||||
cm := disetcd.NewConfigManager(client.(*etcd.SvcDiscoveryRegistryImpl).GetClient(), watchConfigNames)
|
||||
cm.Watch(ctx)
|
||||
}
|
||||
|
||||
sigs := make(chan os.Signal, 1)
|
||||
signal.Notify(sigs, syscall.SIGTERM)
|
||||
select {
|
||||
|
||||
@@ -22,7 +22,6 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/storage/kafka"
|
||||
"github.com/openimsdk/tools/utils/jsonutil"
|
||||
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/storage/database"
|
||||
@@ -39,6 +38,7 @@ import (
|
||||
"github.com/openimsdk/protocol/sdkws"
|
||||
"github.com/openimsdk/tools/errs"
|
||||
"github.com/openimsdk/tools/log"
|
||||
"github.com/openimsdk/tools/mq/kafka"
|
||||
"github.com/openimsdk/tools/utils/datautil"
|
||||
)
|
||||
|
||||
|
||||
@@ -2,9 +2,7 @@ package controller
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/convert"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/storage/kafka"
|
||||
"github.com/openimsdk/protocol/constant"
|
||||
"github.com/openimsdk/tools/utils/datautil"
|
||||
|
||||
@@ -16,6 +14,7 @@ import (
|
||||
"github.com/openimsdk/protocol/sdkws"
|
||||
"github.com/openimsdk/tools/errs"
|
||||
"github.com/openimsdk/tools/log"
|
||||
"github.com/openimsdk/tools/mq/kafka"
|
||||
"go.mongodb.org/mongo-driver/mongo"
|
||||
)
|
||||
|
||||
|
||||
@@ -19,10 +19,10 @@ import (
|
||||
|
||||
"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/kafka"
|
||||
"github.com/openimsdk/protocol/push"
|
||||
"github.com/openimsdk/protocol/sdkws"
|
||||
"github.com/openimsdk/tools/log"
|
||||
"github.com/openimsdk/tools/mq/kafka"
|
||||
)
|
||||
|
||||
type PushDatabase interface {
|
||||
|
||||
@@ -30,7 +30,7 @@ import (
|
||||
)
|
||||
|
||||
type S3Database interface {
|
||||
PartLimit() (*s3.PartLimit, error)
|
||||
PartLimit() *s3.PartLimit
|
||||
PartSize(ctx context.Context, size int64) (int64, error)
|
||||
AuthSign(ctx context.Context, uploadID string, partNumbers []int) (*s3.AuthSignResult, error)
|
||||
InitiateMultipartUpload(ctx context.Context, hash string, size int64, expire time.Duration, maxParts int) (*cont.InitiateUploadResult, error)
|
||||
@@ -65,7 +65,7 @@ func (s *s3Database) PartSize(ctx context.Context, size int64) (int64, error) {
|
||||
return s.s3.PartSize(ctx, size)
|
||||
}
|
||||
|
||||
func (s *s3Database) PartLimit() (*s3.PartLimit, error) {
|
||||
func (s *s3Database) PartLimit() *s3.PartLimit {
|
||||
return s.s3.PartLimit()
|
||||
}
|
||||
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
// Copyright © 2024 OpenIM open source community. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package kafka
|
||||
|
||||
type TLSConfig struct {
|
||||
EnableTLS bool `yaml:"enableTLS"`
|
||||
CACrt string `yaml:"caCrt"`
|
||||
ClientCrt string `yaml:"clientCrt"`
|
||||
ClientKey string `yaml:"clientKey"`
|
||||
ClientKeyPwd string `yaml:"clientKeyPwd"`
|
||||
InsecureSkipVerify bool `yaml:"insecureSkipVerify"`
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
Username string `yaml:"username"`
|
||||
Password string `yaml:"password"`
|
||||
ProducerAck string `yaml:"producerAck"`
|
||||
CompressType string `yaml:"compressType"`
|
||||
Addr []string `yaml:"addr"`
|
||||
TLS TLSConfig `yaml:"tls"`
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
// Copyright © 2023 OpenIM. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package kafka
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
"github.com/IBM/sarama"
|
||||
"github.com/openimsdk/tools/log"
|
||||
)
|
||||
|
||||
type MConsumerGroup struct {
|
||||
sarama.ConsumerGroup
|
||||
groupID string
|
||||
topics []string
|
||||
}
|
||||
|
||||
func NewMConsumerGroup(conf *Config, groupID string, topics []string, autoCommitEnable bool) (*MConsumerGroup, error) {
|
||||
config, err := BuildConsumerGroupConfig(conf, sarama.OffsetNewest, autoCommitEnable)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
group, err := NewConsumerGroup(config, conf.Addr, groupID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &MConsumerGroup{
|
||||
ConsumerGroup: group,
|
||||
groupID: groupID,
|
||||
topics: topics,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (mc *MConsumerGroup) GetContextFromMsg(cMsg *sarama.ConsumerMessage) context.Context {
|
||||
return GetContextWithMQHeader(cMsg.Headers)
|
||||
}
|
||||
|
||||
func (mc *MConsumerGroup) RegisterHandleAndConsumer(ctx context.Context, handler sarama.ConsumerGroupHandler) {
|
||||
for {
|
||||
err := mc.ConsumerGroup.Consume(ctx, mc.topics, handler)
|
||||
if errors.Is(err, sarama.ErrClosedConsumerGroup) {
|
||||
return
|
||||
}
|
||||
if errors.Is(err, context.Canceled) {
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
log.ZWarn(ctx, "consume err", err, "topic", mc.topics, "groupID", mc.groupID)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (mc *MConsumerGroup) Close() error {
|
||||
return mc.ConsumerGroup.Close()
|
||||
}
|
||||
@@ -1,82 +0,0 @@
|
||||
// Copyright © 2023 OpenIM. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package kafka
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/IBM/sarama"
|
||||
"github.com/openimsdk/tools/errs"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
// Producer represents a Kafka producer.
|
||||
type Producer struct {
|
||||
addr []string
|
||||
topic string
|
||||
config *sarama.Config
|
||||
producer sarama.SyncProducer
|
||||
}
|
||||
|
||||
func NewKafkaProducer(config *sarama.Config, addr []string, topic string) (*Producer, error) {
|
||||
producer, err := NewProducer(config, addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Producer{
|
||||
addr: addr,
|
||||
topic: topic,
|
||||
config: config,
|
||||
producer: producer,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// SendMessage sends a message to the Kafka topic configured in the Producer.
|
||||
func (p *Producer) SendMessage(ctx context.Context, key string, msg proto.Message) (int32, int64, error) {
|
||||
// Marshal the protobuf message
|
||||
bMsg, err := proto.Marshal(msg)
|
||||
if err != nil {
|
||||
return 0, 0, errs.WrapMsg(err, "kafka proto Marshal err")
|
||||
}
|
||||
if len(bMsg) == 0 {
|
||||
return 0, 0, errs.WrapMsg(errEmptyMsg, "kafka proto Marshal err")
|
||||
}
|
||||
|
||||
// Prepare Kafka message
|
||||
kMsg := &sarama.ProducerMessage{
|
||||
Topic: p.topic,
|
||||
Key: sarama.StringEncoder(key),
|
||||
Value: sarama.ByteEncoder(bMsg),
|
||||
}
|
||||
|
||||
// Validate message key and value
|
||||
if kMsg.Key.Length() == 0 || kMsg.Value.Length() == 0 {
|
||||
return 0, 0, errs.Wrap(errEmptyMsg)
|
||||
}
|
||||
|
||||
// Attach context metadata as headers
|
||||
header, err := GetMQHeaderWithContext(ctx)
|
||||
if err != nil {
|
||||
return 0, 0, err
|
||||
}
|
||||
kMsg.Headers = header
|
||||
|
||||
// Send the message
|
||||
partition, offset, err := p.producer.SendMessage(kMsg)
|
||||
if err != nil {
|
||||
return 0, 0, errs.WrapMsg(err, "p.producer.SendMessage error")
|
||||
}
|
||||
|
||||
return partition, offset, nil
|
||||
}
|
||||
@@ -1,85 +0,0 @@
|
||||
package kafka
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"strings"
|
||||
|
||||
"github.com/IBM/sarama"
|
||||
"github.com/openimsdk/tools/errs"
|
||||
)
|
||||
|
||||
func BuildConsumerGroupConfig(conf *Config, initial int64, autoCommitEnable bool) (*sarama.Config, error) {
|
||||
kfk := sarama.NewConfig()
|
||||
kfk.Version = sarama.V2_0_0_0
|
||||
kfk.Consumer.Offsets.Initial = initial
|
||||
kfk.Consumer.Offsets.AutoCommit.Enable = autoCommitEnable
|
||||
kfk.Consumer.Return.Errors = false
|
||||
if conf.Username != "" || conf.Password != "" {
|
||||
kfk.Net.SASL.Enable = true
|
||||
kfk.Net.SASL.User = conf.Username
|
||||
kfk.Net.SASL.Password = conf.Password
|
||||
}
|
||||
if conf.TLS.EnableTLS {
|
||||
tls, err := newTLSConfig(conf.TLS.ClientCrt, conf.TLS.ClientKey, conf.TLS.CACrt, []byte(conf.TLS.ClientKeyPwd), conf.TLS.InsecureSkipVerify)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
kfk.Net.TLS.Config = tls
|
||||
kfk.Net.TLS.Enable = true
|
||||
}
|
||||
return kfk, nil
|
||||
}
|
||||
|
||||
func NewConsumerGroup(conf *sarama.Config, addr []string, groupID string) (sarama.ConsumerGroup, error) {
|
||||
cg, err := sarama.NewConsumerGroup(addr, groupID, conf)
|
||||
if err != nil {
|
||||
return nil, errs.WrapMsg(err, "NewConsumerGroup failed", "addr", addr, "groupID", groupID, "conf", *conf)
|
||||
}
|
||||
return cg, nil
|
||||
}
|
||||
|
||||
func BuildProducerConfig(conf Config) (*sarama.Config, error) {
|
||||
kfk := sarama.NewConfig()
|
||||
kfk.Producer.Return.Successes = true
|
||||
kfk.Producer.Return.Errors = true
|
||||
kfk.Producer.Partitioner = sarama.NewHashPartitioner
|
||||
if conf.Username != "" || conf.Password != "" {
|
||||
kfk.Net.SASL.Enable = true
|
||||
kfk.Net.SASL.User = conf.Username
|
||||
kfk.Net.SASL.Password = conf.Password
|
||||
}
|
||||
switch strings.ToLower(conf.ProducerAck) {
|
||||
case "no_response":
|
||||
kfk.Producer.RequiredAcks = sarama.NoResponse
|
||||
case "wait_for_local":
|
||||
kfk.Producer.RequiredAcks = sarama.WaitForLocal
|
||||
case "wait_for_all":
|
||||
kfk.Producer.RequiredAcks = sarama.WaitForAll
|
||||
default:
|
||||
kfk.Producer.RequiredAcks = sarama.WaitForAll
|
||||
}
|
||||
if conf.CompressType == "" {
|
||||
kfk.Producer.Compression = sarama.CompressionNone
|
||||
} else {
|
||||
if err := kfk.Producer.Compression.UnmarshalText(bytes.ToLower([]byte(conf.CompressType))); err != nil {
|
||||
return nil, errs.WrapMsg(err, "UnmarshalText failed", "compressType", conf.CompressType)
|
||||
}
|
||||
}
|
||||
if conf.TLS.EnableTLS {
|
||||
tls, err := newTLSConfig(conf.TLS.ClientCrt, conf.TLS.ClientKey, conf.TLS.CACrt, []byte(conf.TLS.ClientKeyPwd), conf.TLS.InsecureSkipVerify)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
kfk.Net.TLS.Config = tls
|
||||
kfk.Net.TLS.Enable = true
|
||||
}
|
||||
return kfk, nil
|
||||
}
|
||||
|
||||
func NewProducer(conf *sarama.Config, addr []string) (sarama.SyncProducer, error) {
|
||||
producer, err := sarama.NewSyncProducer(addr, conf)
|
||||
if err != nil {
|
||||
return nil, errs.WrapMsg(err, "NewSyncProducer failed", "addr", addr, "conf", *conf)
|
||||
}
|
||||
return producer, nil
|
||||
}
|
||||
@@ -1,83 +0,0 @@
|
||||
// Copyright © 2024 OpenIM open source community. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package kafka
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
"os"
|
||||
|
||||
"github.com/openimsdk/tools/errs"
|
||||
)
|
||||
|
||||
// decryptPEM decrypts a PEM block using a password.
|
||||
func decryptPEM(data []byte, passphrase []byte) ([]byte, error) {
|
||||
if len(passphrase) == 0 {
|
||||
return data, nil
|
||||
}
|
||||
b, _ := pem.Decode(data)
|
||||
d, err := x509.DecryptPEMBlock(b, passphrase)
|
||||
if err != nil {
|
||||
return nil, errs.WrapMsg(err, "DecryptPEMBlock failed")
|
||||
}
|
||||
return pem.EncodeToMemory(&pem.Block{
|
||||
Type: b.Type,
|
||||
Bytes: d,
|
||||
}), nil
|
||||
}
|
||||
|
||||
func readEncryptablePEMBlock(path string, pwd []byte) ([]byte, error) {
|
||||
data, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return nil, errs.WrapMsg(err, "ReadFile failed", "path", path)
|
||||
}
|
||||
return decryptPEM(data, pwd)
|
||||
}
|
||||
|
||||
// newTLSConfig setup the TLS config from general config file.
|
||||
func newTLSConfig(clientCertFile, clientKeyFile, caCertFile string, keyPwd []byte, insecureSkipVerify bool) (*tls.Config, error) {
|
||||
var tlsConfig tls.Config
|
||||
if clientCertFile != "" && clientKeyFile != "" {
|
||||
certPEMBlock, err := os.ReadFile(clientCertFile)
|
||||
if err != nil {
|
||||
return nil, errs.WrapMsg(err, "ReadFile failed", "clientCertFile", clientCertFile)
|
||||
}
|
||||
keyPEMBlock, err := readEncryptablePEMBlock(clientKeyFile, keyPwd)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cert, err := tls.X509KeyPair(certPEMBlock, keyPEMBlock)
|
||||
if err != nil {
|
||||
return nil, errs.WrapMsg(err, "X509KeyPair failed")
|
||||
}
|
||||
tlsConfig.Certificates = []tls.Certificate{cert}
|
||||
}
|
||||
|
||||
if caCertFile != "" {
|
||||
caCert, err := os.ReadFile(caCertFile)
|
||||
if err != nil {
|
||||
return nil, errs.WrapMsg(err, "ReadFile failed", "caCertFile", caCertFile)
|
||||
}
|
||||
caCertPool := x509.NewCertPool()
|
||||
if ok := caCertPool.AppendCertsFromPEM(caCert); !ok {
|
||||
return nil, errs.New("AppendCertsFromPEM failed")
|
||||
}
|
||||
tlsConfig.RootCAs = caCertPool
|
||||
}
|
||||
tlsConfig.InsecureSkipVerify = insecureSkipVerify
|
||||
return &tlsConfig, nil
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
package kafka
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"github.com/IBM/sarama"
|
||||
"github.com/openimsdk/protocol/constant"
|
||||
"github.com/openimsdk/tools/mcontext"
|
||||
)
|
||||
|
||||
var errEmptyMsg = errors.New("kafka binary msg is empty")
|
||||
|
||||
// GetMQHeaderWithContext extracts message queue headers from the context.
|
||||
func GetMQHeaderWithContext(ctx context.Context) ([]sarama.RecordHeader, error) {
|
||||
operationID, opUserID, platform, connID, err := mcontext.GetCtxInfos(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return []sarama.RecordHeader{
|
||||
{Key: []byte(constant.OperationID), Value: []byte(operationID)},
|
||||
{Key: []byte(constant.OpUserID), Value: []byte(opUserID)},
|
||||
{Key: []byte(constant.OpUserPlatform), Value: []byte(platform)},
|
||||
{Key: []byte(constant.ConnID), Value: []byte(connID)},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// GetContextWithMQHeader creates a context from message queue headers.
|
||||
func GetContextWithMQHeader(header []*sarama.RecordHeader) context.Context {
|
||||
var values []string
|
||||
for _, recordHeader := range header {
|
||||
values = append(values, string(recordHeader.Value))
|
||||
}
|
||||
return mcontext.WithMustInfoCtx(values) // Attach extracted values to context
|
||||
}
|
||||
@@ -1,79 +0,0 @@
|
||||
// Copyright © 2024 OpenIM open source community. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package kafka
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/IBM/sarama"
|
||||
"github.com/openimsdk/tools/errs"
|
||||
)
|
||||
|
||||
func CheckTopics(ctx context.Context, conf *Config, topics []string) error {
|
||||
kfk, err := BuildConsumerGroupConfig(conf, sarama.OffsetNewest, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cli, err := sarama.NewClient(conf.Addr, kfk)
|
||||
if err != nil {
|
||||
return errs.WrapMsg(err, "NewClient failed", "config: ", fmt.Sprintf("%+v", conf))
|
||||
}
|
||||
defer cli.Close()
|
||||
|
||||
existingTopics, err := cli.Topics()
|
||||
if err != nil {
|
||||
return errs.WrapMsg(err, "Failed to list topics")
|
||||
}
|
||||
|
||||
existingTopicsMap := make(map[string]bool)
|
||||
for _, t := range existingTopics {
|
||||
existingTopicsMap[t] = true
|
||||
}
|
||||
|
||||
for _, topic := range topics {
|
||||
if !existingTopicsMap[topic] {
|
||||
return errs.New("topic not exist", "topic", topic).Wrap()
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func CheckHealth(ctx context.Context, conf *Config) error {
|
||||
kfk, err := BuildConsumerGroupConfig(conf, sarama.OffsetNewest, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cli, err := sarama.NewClient(conf.Addr, kfk)
|
||||
if err != nil {
|
||||
return errs.WrapMsg(err, "NewClient failed", "config: ", fmt.Sprintf("%+v", conf))
|
||||
}
|
||||
defer cli.Close()
|
||||
|
||||
// Get broker list
|
||||
brokers := cli.Brokers()
|
||||
if len(brokers) == 0 {
|
||||
return errs.New("no brokers found").Wrap()
|
||||
}
|
||||
|
||||
// Check if all brokers are reachable
|
||||
for _, broker := range brokers {
|
||||
if err := broker.Open(kfk); err != nil {
|
||||
return errs.WrapMsg(err, "failed to open broker", "broker", broker.Addr())
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
+6
-11
@@ -12,7 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package notification
|
||||
package rpcclient
|
||||
|
||||
import (
|
||||
"context"
|
||||
@@ -179,24 +179,19 @@ func NewNotificationSender(conf *config.Notification, opts ...NotificationSender
|
||||
}
|
||||
|
||||
type notificationOpt struct {
|
||||
RpcGetUsername bool
|
||||
SendMessage *bool
|
||||
WithRpcGetUsername bool
|
||||
}
|
||||
|
||||
type NotificationOptions func(*notificationOpt)
|
||||
|
||||
func WithRpcGetUserName() NotificationOptions {
|
||||
return func(opt *notificationOpt) {
|
||||
opt.RpcGetUsername = true
|
||||
}
|
||||
}
|
||||
func WithSendMessage(sendMessage *bool) NotificationOptions {
|
||||
return func(opt *notificationOpt) {
|
||||
opt.SendMessage = sendMessage
|
||||
opt.WithRpcGetUsername = true
|
||||
}
|
||||
}
|
||||
|
||||
func (s *NotificationSender) send(ctx context.Context, sendID, recvID string, contentType, sessionType int32, m proto.Message, opts ...NotificationOptions) {
|
||||
//ctx = mcontext.WithMustInfoCtx([]string{mcontext.GetOperationID(ctx), mcontext.GetOpUserID(ctx), mcontext.GetOpUserPlatform(ctx), mcontext.GetConnID(ctx)})
|
||||
ctx = context.WithoutCancel(ctx)
|
||||
ctx, cancel := context.WithTimeout(ctx, time.Second*time.Duration(5))
|
||||
defer cancel()
|
||||
@@ -213,7 +208,7 @@ func (s *NotificationSender) send(ctx context.Context, sendID, recvID string, co
|
||||
var req msg.SendMsgReq
|
||||
var msg sdkws.MsgData
|
||||
var userInfo *sdkws.UserInfo
|
||||
if notificationOpt.RpcGetUsername && s.getUserInfo != nil {
|
||||
if notificationOpt.WithRpcGetUsername && s.getUserInfo != nil {
|
||||
userInfo, err = s.getUserInfo(ctx, sendID)
|
||||
if err != nil {
|
||||
log.ZWarn(ctx, "getUserInfo failed", err, "sendID", sendID)
|
||||
@@ -238,7 +233,7 @@ func (s *NotificationSender) send(ctx context.Context, sendID, recvID string, co
|
||||
if sendID == recvID && contentType == constant.HasReadReceipt {
|
||||
optionsConfig.ReliabilityLevel = constant.UnreliableNotification
|
||||
}
|
||||
options := config.GetOptionsByNotification(optionsConfig, notificationOpt.SendMessage)
|
||||
options := config.GetOptionsByNotification(optionsConfig)
|
||||
s.SetOptionsByContentType(ctx, options, contentType)
|
||||
msg.Options = options
|
||||
// fill Notification OfflinePush by config
|
||||
|
||||
@@ -2,6 +2,7 @@ package rpcli
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/openimsdk/tools/errs"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
@@ -2,6 +2,7 @@ package rpcli
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/openimsdk/protocol/sdkws"
|
||||
"github.com/openimsdk/protocol/user"
|
||||
"github.com/openimsdk/tools/errs"
|
||||
|
||||
@@ -18,29 +18,35 @@ import (
|
||||
"context"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/cmd"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/storage/kafka"
|
||||
"github.com/openimsdk/tools/db/mongoutil"
|
||||
"github.com/openimsdk/tools/db/redisutil"
|
||||
"github.com/openimsdk/tools/discovery/etcd"
|
||||
"github.com/openimsdk/tools/discovery/zookeeper"
|
||||
"github.com/openimsdk/tools/mq/kafka"
|
||||
"github.com/openimsdk/tools/s3/minio"
|
||||
"github.com/openimsdk/tools/system/program"
|
||||
"github.com/openimsdk/tools/utils/runtimeenv"
|
||||
)
|
||||
|
||||
const maxRetry = 180
|
||||
|
||||
const (
|
||||
MountConfigFilePath = "CONFIG_PATH"
|
||||
DeploymentType = "DEPLOYMENT_TYPE"
|
||||
KUBERNETES = "kubernetes"
|
||||
)
|
||||
|
||||
func CheckZookeeper(ctx context.Context, config *config.ZooKeeper) error {
|
||||
// Temporary disable logging
|
||||
originalLogger := log.Default().Writer()
|
||||
log.SetOutput(ioutil.Discard)
|
||||
log.SetOutput(io.Discard)
|
||||
defer log.SetOutput(originalLogger) // Ensure logging is restored
|
||||
return zookeeper.Check(ctx, config.Address, config.Schema, zookeeper.WithUserNameAndPassword(config.Username, config.Password))
|
||||
}
|
||||
@@ -78,35 +84,37 @@ func initConfig(configDir string) (*config.Mongo, *config.Redis, *config.Kafka,
|
||||
discovery = &config.Discovery{}
|
||||
thirdConfig = &config.Third{}
|
||||
)
|
||||
err := config.LoadConfig(filepath.Join(configDir, cmd.MongodbConfigFileName), cmd.ConfigEnvPrefixMap[cmd.MongodbConfigFileName], mongoConfig)
|
||||
runtimeEnv := runtimeenv.PrintRuntimeEnvironment()
|
||||
|
||||
err := config.Load(configDir, config.MongodbConfigFileName, config.EnvPrefixMap[config.MongodbConfigFileName], runtimeEnv, mongoConfig)
|
||||
if err != nil {
|
||||
return nil, nil, nil, nil, nil, err
|
||||
}
|
||||
|
||||
err = config.LoadConfig(filepath.Join(configDir, cmd.RedisConfigFileName), cmd.ConfigEnvPrefixMap[cmd.RedisConfigFileName], redisConfig)
|
||||
err = config.Load(configDir, config.RedisConfigFileName, config.EnvPrefixMap[config.RedisConfigFileName], runtimeEnv, redisConfig)
|
||||
if err != nil {
|
||||
return nil, nil, nil, nil, nil, err
|
||||
}
|
||||
|
||||
err = config.LoadConfig(filepath.Join(configDir, cmd.KafkaConfigFileName), cmd.ConfigEnvPrefixMap[cmd.KafkaConfigFileName], kafkaConfig)
|
||||
err = config.Load(configDir, config.KafkaConfigFileName, config.EnvPrefixMap[config.KafkaConfigFileName], runtimeEnv, kafkaConfig)
|
||||
if err != nil {
|
||||
return nil, nil, nil, nil, nil, err
|
||||
}
|
||||
|
||||
err = config.LoadConfig(filepath.Join(configDir, cmd.OpenIMRPCThirdCfgFileName), cmd.ConfigEnvPrefixMap[cmd.OpenIMRPCThirdCfgFileName], thirdConfig)
|
||||
err = config.Load(configDir, config.OpenIMRPCThirdCfgFileName, config.EnvPrefixMap[config.OpenIMRPCThirdCfgFileName], runtimeEnv, thirdConfig)
|
||||
if err != nil {
|
||||
return nil, nil, nil, nil, nil, err
|
||||
}
|
||||
|
||||
if thirdConfig.Object.Enable == "minio" {
|
||||
err = config.LoadConfig(filepath.Join(configDir, cmd.MinioConfigFileName), cmd.ConfigEnvPrefixMap[cmd.MinioConfigFileName], minioConfig)
|
||||
err = config.Load(configDir, config.MinioConfigFileName, config.EnvPrefixMap[config.MinioConfigFileName], runtimeEnv, minioConfig)
|
||||
if err != nil {
|
||||
return nil, nil, nil, nil, nil, err
|
||||
}
|
||||
} else {
|
||||
minioConfig = nil
|
||||
}
|
||||
err = config.LoadConfig(filepath.Join(configDir, cmd.DiscoveryConfigFilename), cmd.ConfigEnvPrefixMap[cmd.DiscoveryConfigFilename], discovery)
|
||||
err = config.Load(configDir, config.DiscoveryConfigFilename, config.EnvPrefixMap[config.DiscoveryConfigFilename], runtimeEnv, discovery)
|
||||
if err != nil {
|
||||
return nil, nil, nil, nil, nil, err
|
||||
}
|
||||
@@ -160,10 +168,6 @@ func performChecks(ctx context.Context, mongoConfig *config.Mongo, redisConfig *
|
||||
checks["Etcd"] = func(ctx context.Context) error {
|
||||
return CheckEtcd(ctx, &discovery.Etcd)
|
||||
}
|
||||
} else if discovery.Enable == "zookeeper" {
|
||||
checks["Zookeeper"] = func(ctx context.Context) error {
|
||||
return CheckZookeeper(ctx, &discovery.ZooKeeper)
|
||||
}
|
||||
}
|
||||
|
||||
for i := 0; i < maxRetry; i++ {
|
||||
|
||||
@@ -16,7 +16,6 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/mitchellh/mapstructure"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/cmd"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/storage/database/mgo"
|
||||
"github.com/openimsdk/tools/db/mongoutil"
|
||||
@@ -44,7 +43,7 @@ const (
|
||||
)
|
||||
|
||||
func readConfig[T any](dir string, name string) (*T, error) {
|
||||
if runtimeenv.RuntimeEnvironment() == config.KUBERNETES {
|
||||
if runtimeenv.PrintRuntimeEnvironment() == config.KUBERNETES {
|
||||
dir = os.Getenv(config.MountConfigFilePath)
|
||||
}
|
||||
v := viper.New()
|
||||
@@ -66,11 +65,11 @@ func readConfig[T any](dir string, name string) (*T, error) {
|
||||
}
|
||||
|
||||
func Main(conf string, del time.Duration) error {
|
||||
redisConfig, err := readConfig[config.Redis](conf, cmd.RedisConfigFileName)
|
||||
redisConfig, err := readConfig[config.Redis](conf, config.RedisConfigFileName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
mongodbConfig, err := readConfig[config.Mongo](conf, cmd.MongodbConfigFileName)
|
||||
mongodbConfig, err := readConfig[config.Mongo](conf, config.MongodbConfigFileName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
v3.8.3-patch.4
|
||||
v3.8.4-alpha.1
|
||||
|
||||
Reference in New Issue
Block a user