Compare commits

..

2 Commits

Author SHA1 Message Date
Xinwei Xiong(cubxxw) 5c7e5f37be fix: add chat thmp 2023-11-10 21:16:07 +08:00
cubxxw 229c656eda cicd: robot automated Change 2023-11-10 11:55:43 +00:00
259 changed files with 15443 additions and 12348 deletions
+79
View File
@@ -0,0 +1,79 @@
# 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.
#---------------Infrastructure configuration---------------------#
etcd:
etcdSchema: openim #默认即可
etcdAddr: [ 127.0.0.1:2379 ] #单机部署时,默认即可
userName:
password:
secret: openIM123
mysql:
dbMysqlDatabaseName: admin_chat # 数据库名字 默认即可
# 默认管理员账号
admin:
defaultAccount:
account: [ "admin1", "admin2" ]
defaultPassword: [ "password1", "password2" ]
openIMUserID: [ "openIM123456", "openIMAdmin" ]
faceURL: [ "", "" ]
nickname: [ "admin1", "admin2" ]
level: [ 1, 100 ]
adminapi:
openImAdminApiPort: [ 10009 ] #管理后台api服务端口,默认即可,需要开放此端口或做nginx转发
listenIP: 0.0.0.0
chatapi:
openImChatApiPort: [ 10008 ] #登录注册,默认即可,需要开放此端口或做nginx转发
listenIP: 0.0.0.0
rpcport: # rpc服务端口 默认即可
openImAdminPort: [ 30200 ]
openImChatPort: [ 30300 ]
rpcregistername: #rpc注册服务名,默认即可
openImChatName: Chat
openImAdminCMSName: Admin
chat:
codeTTL: 300 #短信验证码有效时间(秒)
superVerificationCode: 666666 # 超级验证码
alismsverify: #阿里云短信配置,在阿里云申请成功后修改以下四项
accessKeyId:
accessKeySecret:
signName:
verificationCodeTemplateCode:
oss:
tempDir: enterprise-temp # 临时密钥上传的目录
dataDir: enterprise-data # 最终存放目录
aliyun:
endpoint: https://oss-cn-chengdu.aliyuncs.com
accessKeyID: ""
accessKeySecret: ""
bucket: ""
tencent:
BucketURL: ""
serviceURL: https://cos.COS_REGION.myqcloud.com
secretID: ""
secretKey: ""
sessionToken: ""
bucket: ""
use: "minio"
@@ -0,0 +1,27 @@
# Copyright © 2023 OpenIM. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#more datasource-compose.yaml
apiVersion: 1
datasources:
- name: Prometheus
type: prometheus
access: proxy
orgId: 1
url: http://127.0.0.1:9091
basicAuth: false
isDefault: true
version: 1
editable: true
Binary file not shown.
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,85 @@
# 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.
#more prometheus-compose.yml
global:
scrape_interval: 15s
evaluation_interval: 15s
external_labels:
monitor: 'openIM-monitor'
scrape_configs:
- job_name: 'prometheus'
static_configs:
- targets: ['localhost:9091']
- job_name: 'openIM-server'
metrics_path: /metrics
static_configs:
- targets: ['localhost:10002']
labels:
group: 'api'
- targets: ['localhost:20110']
labels:
group: 'user'
- targets: ['localhost:20120']
labels:
group: 'friend'
- targets: ['localhost:20130']
labels:
group: 'message'
- targets: ['localhost:20140']
labels:
group: 'msg-gateway'
- targets: ['localhost:20150']
labels:
group: 'group'
- targets: ['localhost:20160']
labels:
group: 'auth'
- targets: ['localhost:20170']
labels:
group: 'push'
- targets: ['localhost:20120']
labels:
group: 'friend'
- targets: ['localhost:20230']
labels:
group: 'conversation'
- targets: ['localhost:21400', 'localhost:21401', 'localhost:21402', 'localhost:21403']
labels:
group: 'msg-transfer'
- job_name: 'node'
scrape_interval: 8s
static_configs:
- targets: ['localhost:9100']
+1
View File
@@ -20,6 +20,7 @@ CHANGELOG/
# Ignore deployment-related files # Ignore deployment-related files
docker-compose.yaml docker-compose.yaml
deployments/
# Ignore assets # Ignore assets
assets/ assets/
+90 -54
View File
@@ -1,9 +1,23 @@
# 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.
# ====================================== # ======================================
# ========= Basic Configuration ======== # ========= Basic Configuration ========
# ====================================== # ======================================
# The user for authentication or system operations. # The user for authentication or system operations.
# Default: OPENIM_USER=root # Default: USER=root
USER=root USER=root
# Password associated with the specified user for authentication. # Password associated with the specified user for authentication.
@@ -15,8 +29,8 @@ PASSWORD=openIM123
MINIO_ENDPOINT=http://172.28.0.1:10005 MINIO_ENDPOINT=http://172.28.0.1:10005
# Base URL for the application programming interface (API). # Base URL for the application programming interface (API).
# Default: API_URL=http://172.28.0.1:10002 # Default: API_URL=http://172.0.0.1:10002
API_URL=http://172.28.0.1:10002 API_URL=http://172.0.0.1:10002
# Directory path for storing data files or related information. # Directory path for storing data files or related information.
# Default: DATA_DIR=./ # Default: DATA_DIR=./
@@ -41,19 +55,50 @@ DOCKER_BRIDGE_SUBNET=172.28.0.0/16
# Default: DOCKER_BRIDGE_GATEWAY=172.28.0.1 # Default: DOCKER_BRIDGE_GATEWAY=172.28.0.1
DOCKER_BRIDGE_GATEWAY=172.28.0.1 DOCKER_BRIDGE_GATEWAY=172.28.0.1
MONGO_NETWORK_ADDRESS=172.28.0.2 # Address or hostname for the MySQL network.
REDIS_NETWORK_ADDRESS=172.28.0.3 # Default: MYSQL_NETWORK_ADDRESS=172.28.0.2
KAFKA_NETWORK_ADDRESS=172.28.0.4 MYSQL_NETWORK_ADDRESS=172.28.0.2
ZOOKEEPER_NETWORK_ADDRESS=172.28.0.5
MINIO_NETWORK_ADDRESS=172.28.0.6 # Address or hostname for the MongoDB network.
OPENIM_WEB_NETWORK_ADDRESS=172.28.0.7 # Default: MONGO_NETWORK_ADDRESS=172.28.0.3
OPENIM_SERVER_NETWORK_ADDRESS=172.28.0.8 MONGO_NETWORK_ADDRESS=172.28.0.3
OPENIM_CHAT_NETWORK_ADDRESS=172.28.0.9
PROMETHEUS_NETWORK_ADDRESS=172.28.0.10 # Address or hostname for the Redis network.
GRAFANA_NETWORK_ADDRESS=172.28.0.11 # Default: REDIS_NETWORK_ADDRESS=172.28.0.4
NODE_EXPORTER_NETWORK_ADDRESS=172.28.0.12 REDIS_NETWORK_ADDRESS=172.28.0.4
OPENIM_ADMIN_FRONT_NETWORK_ADDRESS=172.28.0.13
ALERT_MANAGER_NETWORK_ADDRESS=172.28.0.14 # Address or hostname for the Kafka network.
# Default: KAFKA_NETWORK_ADDRESS=172.28.0.5
KAFKA_NETWORK_ADDRESS=172.28.0.5
# Address or hostname for the ZooKeeper network.
# Default: ZOOKEEPER_NETWORK_ADDRESS=172.28.0.6
ZOOKEEPER_NETWORK_ADDRESS=172.28.0.6
# Address or hostname for the MinIO network.
# Default: MINIO_NETWORK_ADDRESS=172.28.0.7
MINIO_NETWORK_ADDRESS=172.28.0.7
# Address or hostname for the OpenIM web network.
# Default: OPENIM_WEB_NETWORK_ADDRESS=172.28.0.8
OPENIM_WEB_NETWORK_ADDRESS=172.28.0.8
# Address or hostname for the OpenIM server network.
# Default: OPENIM_SERVER_NETWORK_ADDRESS=172.28.0.9
OPENIM_SERVER_NETWORK_ADDRESS=172.28.0.9
# Address or hostname for the OpenIM chat network.
# Default: OPENIM_CHAT_NETWORK_ADDRESS=172.28.0.10
OPENIM_CHAT_NETWORK_ADDRESS=172.28.0.10
# Address or hostname for the Prometheus network.
# Default: PROMETHEUS_NETWORK_ADDRESS=172.28.0.11
PROMETHEUS_NETWORK_ADDRESS=172.28.0.11
# Address or hostname for the Grafana network.
# Default: GRAFANA_NETWORK_ADDRESS=172.28.0.12
GRAFANA_NETWORK_ADDRESS=172.28.0.12
# =============================================== # ===============================================
# = Component Extension Configuration = # = Component Extension Configuration =
@@ -63,24 +108,38 @@ ALERT_MANAGER_NETWORK_ADDRESS=172.28.0.14
# ----- ZooKeeper Configuration ----- # ----- ZooKeeper Configuration -----
# Address or hostname for the ZooKeeper service. # Address or hostname for the ZooKeeper service.
# Default: ZOOKEEPER_ADDRESS=172.28.0.1 # Default: ZOOKEEPER_ADDRESS=172.28.0.1
ZOOKEEPER_ADDRESS=172.28.0.5 ZOOKEEPER_ADDRESS=172.28.0.6
# Port for ZooKeeper service. # Port for ZooKeeper service.
# Default: ZOOKEEPER_PORT=12181 # Default: ZOOKEEPER_PORT=12181
ZOOKEEPER_PORT=12181 ZOOKEEPER_PORT=12181
# ----- MySQL Configuration -----
# Address or hostname for the MySQL service.
# Default: MYSQL_ADDRESS=172.28.0.1
MYSQL_ADDRESS=172.28.0.2
# Port on which MySQL database service is running.
# Default: MYSQL_PORT=13306
MYSQL_PORT=13306
# Password to authenticate with the MySQL database service.
# Default: MYSQL_PASSWORD=openIM123
MYSQL_PASSWORD=openIM123
# ----- MongoDB Configuration ----- # ----- MongoDB Configuration -----
# Address or hostname for the MongoDB service. # Address or hostname for the MongoDB service.
# Default: MONGO_ADDRESS=172.28.0.1 # Default: MONGO_ADDRESS=172.28.0.1
MONGO_ADDRESS=172.28.0.2 MONGO_ADDRESS=172.28.0.3
# Port on which MongoDB service is running. # Port on which MongoDB service is running.
# Default: MONGO_PORT=37017 # Default: MONGO_PORT=37017
# MONGO_PORT=37017 MONGO_PORT=37017
# Username to authenticate with the MongoDB service. # Username to authenticate with the MongoDB service.
# Default: MONGO_USERNAME=root # Default: MONGO_USERNAME=root
# MONGO_USERNAME=root MONGO_USERNAME=root
# Password to authenticate with the MongoDB service. # Password to authenticate with the MongoDB service.
# Default: MONGO_PASSWORD=openIM123 # Default: MONGO_PASSWORD=openIM123
@@ -93,7 +152,7 @@ MONGO_DATABASE=openIM_v3
# ----- Redis Configuration ----- # ----- Redis Configuration -----
# Address or hostname for the Redis service. # Address or hostname for the Redis service.
# Default: REDIS_ADDRESS=172.28.0.1 # Default: REDIS_ADDRESS=172.28.0.1
REDIS_ADDRESS=172.28.0.3 REDIS_ADDRESS=172.28.0.4
# Port on which Redis in-memory data structure store is running. # Port on which Redis in-memory data structure store is running.
# Default: REDIS_PORT=16379 # Default: REDIS_PORT=16379
@@ -106,10 +165,7 @@ REDIS_PASSWORD=openIM123
# ----- Kafka Configuration ----- # ----- Kafka Configuration -----
# Address or hostname for the Kafka service. # Address or hostname for the Kafka service.
# Default: KAFKA_ADDRESS=172.28.0.1 # Default: KAFKA_ADDRESS=172.28.0.1
KAFKA_ADDRESS=172.28.0.4 KAFKA_ADDRESS=172.28.0.5
# Kakfa username to authenticate with the Kafka service.
# KAFKA_USERNAME=''
# Port on which Kafka distributed streaming platform is running. # Port on which Kafka distributed streaming platform is running.
# Default: KAFKA_PORT=19092 # Default: KAFKA_PORT=19092
@@ -130,7 +186,7 @@ KAFKA_OFFLINEMSG_MONGO_TOPIC=offlineMsgToMongoMysql
# ----- MinIO Configuration ---- # ----- MinIO Configuration ----
# Address or hostname for the MinIO object storage service. # Address or hostname for the MinIO object storage service.
# Default: MINIO_ADDRESS=172.28.0.1 # Default: MINIO_ADDRESS=172.28.0.1
MINIO_ADDRESS=172.28.0.6 MINIO_ADDRESS=172.28.0.7
# Port on which MinIO object storage service is running. # Port on which MinIO object storage service is running.
# Default: MINIO_PORT=10005 # Default: MINIO_PORT=10005
@@ -138,7 +194,7 @@ MINIO_PORT=10005
# Access key to authenticate with the MinIO service. # Access key to authenticate with the MinIO service.
# Default: MINIO_ACCESS_KEY=root # Default: MINIO_ACCESS_KEY=root
# MINIO_ACCESS_KEY=root MINIO_ACCESS_KEY=root
# Secret key corresponding to the access key for MinIO authentication. # Secret key corresponding to the access key for MinIO authentication.
# Default: MINIO_SECRET_KEY=openIM123 # Default: MINIO_SECRET_KEY=openIM123
@@ -147,7 +203,7 @@ MINIO_SECRET_KEY=openIM123
# ----- Prometheus Configuration ----- # ----- Prometheus Configuration -----
# Address or hostname for the Prometheus service. # Address or hostname for the Prometheus service.
# Default: PROMETHEUS_ADDRESS=172.28.0.1 # Default: PROMETHEUS_ADDRESS=172.28.0.1
PROMETHEUS_ADDRESS=172.28.0.10 PROMETHEUS_ADDRESS=172.28.0.11
# Port on which Prometheus service is running. # Port on which Prometheus service is running.
# Default: PROMETHEUS_PORT=19090 # Default: PROMETHEUS_PORT=19090
@@ -156,11 +212,11 @@ PROMETHEUS_PORT=19090
# ----- Grafana Configuration ----- # ----- Grafana Configuration -----
# Address or hostname for the Grafana service. # Address or hostname for the Grafana service.
# Default: GRAFANA_ADDRESS=172.28.0.1 # Default: GRAFANA_ADDRESS=172.28.0.1
GRAFANA_ADDRESS=172.28.0.11 GRAFANA_ADDRESS=172.28.0.12
# Port on which Grafana service is running. # Port on which Grafana service is running.
# Default: GRAFANA_PORT=13000 # Default: GRAFANA_PORT=3000
GRAFANA_PORT=13000 GRAFANA_PORT=3000
# ====================================== # ======================================
# ============ OpenIM Web =============== # ============ OpenIM Web ===============
@@ -176,7 +232,7 @@ OPENIM_WEB_PORT=11001
# Address or hostname for the OpenIM web service. # Address or hostname for the OpenIM web service.
# Default: OPENIM_WEB_ADDRESS=172.28.0.1 # Default: OPENIM_WEB_ADDRESS=172.28.0.1
OPENIM_WEB_ADDRESS=172.28.0.7 OPENIM_WEB_ADDRESS=172.28.0.8
# ====================================== # ======================================
# ========= OpenIM Server ============== # ========= OpenIM Server ==============
@@ -184,7 +240,7 @@ OPENIM_WEB_ADDRESS=172.28.0.7
# Address or hostname for the OpenIM server. # Address or hostname for the OpenIM server.
# Default: OPENIM_SERVER_ADDRESS=172.28.0.1 # Default: OPENIM_SERVER_ADDRESS=172.28.0.1
OPENIM_SERVER_ADDRESS=172.28.0.8 OPENIM_SERVER_ADDRESS=172.28.0.9
# Port for the OpenIM WebSockets. # Port for the OpenIM WebSockets.
# Default: OPENIM_WS_PORT=10001 # Default: OPENIM_WS_PORT=10001
@@ -205,7 +261,7 @@ CHAT_BRANCH=main
# Address or hostname for the OpenIM chat service. # Address or hostname for the OpenIM chat service.
# Default: OPENIM_CHAT_ADDRESS=172.28.0.1 # Default: OPENIM_CHAT_ADDRESS=172.28.0.1
OPENIM_CHAT_ADDRESS=172.28.0.9 OPENIM_CHAT_ADDRESS=172.28.0.10
# Port for the OpenIM chat API. # Port for the OpenIM chat API.
# Default: OPENIM_CHAT_API_PORT=10008 # Default: OPENIM_CHAT_API_PORT=10008
@@ -227,23 +283,3 @@ SERVER_BRANCH=main
# Port for the OpenIM admin API. # Port for the OpenIM admin API.
# Default: OPENIM_ADMIN_API_PORT=10009 # Default: OPENIM_ADMIN_API_PORT=10009
OPENIM_ADMIN_API_PORT=10009 OPENIM_ADMIN_API_PORT=10009
# Port for the node exporter.
# Default: NODE_EXPORTER_PORT=19100
NODE_EXPORTER_PORT=19100
# Port for the prometheus.
# Default: PROMETHEUS_PORT=19090
PROMETHEUS_PORT=19090
# Port for the grafana.
# Default: GRAFANA_PORT=13000
GRAFANA_PORT=13000
# Port for the admin front.
# Default: OPENIM_ADMIN_FRONT_PORT=11002
OPENIM_ADMIN_FRONT_PORT=11002
# Port for the alertmanager.
# Default: ALERT_MANAGER_PORT=19093
ALERT_MANAGER_PORT=19093
+90
View File
@@ -0,0 +1,90 @@
# 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.
name: OpenIM API TEST
on:
push:
branches:
- main
paths-ignore:
- "docs/**"
- "README.md"
- "README_zh-CN.md"
- "CONTRIBUTING.md"
pull_request:
branches:
- main
paths-ignore:
- "README.md"
- "README_zh-CN.md"
- "CONTRIBUTING.md"
- "docs/**"
env:
GO_VERSION: "1.19"
GOLANGCI_VERSION: "v1.50.1"
jobs:
execute-linux-systemd-scripts:
name: Execute OpenIM script on ${{ matrix.os }}
runs-on: ${{ matrix.os }}
environment:
name: openim
strategy:
matrix:
go_version: ["1.20"]
os: ["ubuntu-latest"]
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Go ${{ matrix.go_version }}
uses: actions/setup-go@v4
with:
go-version: ${{ matrix.go_version }}
id: go
- name: Install Task
uses: arduino/setup-task@v1
with:
version: '3.x' # If available, use the latest major version that's compatible
repo-token: ${{ secrets.GITHUB_TOKEN }}
- name: Docker Operations
run: |
curl -o docker-compose.yml https://raw.githubusercontent.com/OpenIMSDK/openim-docker/main/example/basic-openim-server-dependency.yml
sudo docker compose up -d
sudo sleep 60
- name: Module Operations
run: |
sudo make tidy
sudo make tools.verify.go-gitlint
- name: Build, Start, Check Services and Print Logs
run: |
sudo ./scripts/install/install.sh -i && \
sudo ./scripts/install/install.sh -s && \
(echo "An error occurred, printing logs:" && sudo cat ./_output/logs/* 2>/dev/null)
- name: Run Test
run: |
sudo make test-api && \
(echo "An error occurred, printing logs:" && sudo cat ./_output/logs/* 2>/dev/null)
- name: Stop Services
run: |
sudo ./scripts/install/install.sh -u && \
(echo "An error occurred, printing logs:" && sudo cat ./_output/logs/* 2>/dev/null)
-12
View File
@@ -52,7 +52,6 @@ jobs:
type=ref,event=branch type=ref,event=branch
type=ref,event=pr type=ref,event=pr
type=semver,pattern={{version}} type=semver,pattern={{version}}
type=semver,pattern=v{{version}}
type=semver,pattern={{major}}.{{minor}} type=semver,pattern={{major}}.{{minor}}
type=semver,pattern={{major}} type=semver,pattern={{major}}
type=sha type=sha
@@ -88,16 +87,6 @@ jobs:
uses: docker/metadata-action@v5.0.0 uses: docker/metadata-action@v5.0.0
with: with:
images: registry.cn-hangzhou.aliyuncs.com/openimsdk/openim-server images: registry.cn-hangzhou.aliyuncs.com/openimsdk/openim-server
# generate Docker tags based on the following events/attributes
tags: |
type=schedule
type=ref,event=branch
type=ref,event=pr
type=semver,pattern={{version}}
type=semver,pattern=v{{version}}
type=semver,pattern={{major}}.{{minor}}
type=semver,pattern={{major}}
type=sha
- name: Log in to AliYun Docker Hub - name: Log in to AliYun Docker Hub
uses: docker/login-action@v3 uses: docker/login-action@v3
@@ -137,7 +126,6 @@ jobs:
type=ref,event=branch type=ref,event=branch
type=ref,event=pr type=ref,event=pr
type=semver,pattern={{version}} type=semver,pattern={{version}}
type=semver,pattern=v{{version}}
type=semver,pattern={{major}}.{{minor}} type=semver,pattern={{major}}.{{minor}}
type=semver,pattern={{major}} type=semver,pattern={{major}}
type=sha type=sha
@@ -0,0 +1,139 @@
# Copyright © 2023 OpenIM open source community. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
name: Build OpenIM Web Docker image
on:
schedule:
- cron: '30 3 * * *'
push:
branches:
- main
- release-*
tags:
- v*
workflow_dispatch:
env:
# Common versions
GO_VERSION: "1.20"
jobs:
build-openim-web-dockerhub:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
# docker.io/openim/openim-web:latest
- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@v5.0.0
with:
images: openim/openim-web
# generate Docker tags based on the following events/attributes
tags: |
type=schedule
type=ref,event=branch
type=ref,event=pr
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=semver,pattern={{major}}
type=sha
- name: Log in to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: .
file: ./build/images/openim-tools/openim-web/Dockerfile
platforms: linux/amd64,linux/arm64
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-openim-web-aliyun:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
# registry.cn-hangzhou.aliyuncs.com/openimsdk/openim-web:latest
- name: Extract metadata (tags, labels) for Docker
id: meta2
uses: docker/metadata-action@v5.0.0
with:
images: registry.cn-hangzhou.aliyuncs.com/openimsdk/openim-web
- name: Log in to AliYun Docker Hub
uses: docker/login-action@v3
with:
registry: registry.cn-hangzhou.aliyuncs.com
username: ${{ secrets.ALIREGISTRY_USERNAME }}
password: ${{ secrets.ALIREGISTRY_TOKEN }}
- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: .
file: ./build/images/openim-tools/openim-web/Dockerfile
platforms: linux/amd64,linux/arm64
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta2.outputs.tags }}
labels: ${{ steps.meta2.outputs.labels }}
build-openim-web-ghcr:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
# ghcr.io/openimsdk/openim-web:latest
- name: Extract metadata (tags, labels) for Docker
id: meta2
uses: docker/metadata-action@v5.0.0
with:
images: ghcr.io/openimsdk/openim-web
- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: .
file: ./build/images/openim-tools/openim-web/Dockerfile
platforms: linux/amd64,linux/arm64
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta2.outputs.tags }}
labels: ${{ steps.meta2.outputs.labels }}
+3 -17
View File
@@ -22,9 +22,6 @@ on:
# run e2e test every 4 hours # run e2e test every 4 hours
- cron: 0 */4 * * * - cron: 0 */4 * * *
env:
CALLBACK_ENABLE: true
jobs: jobs:
build: build:
name: Test name: Test
@@ -73,9 +70,9 @@ jobs:
- name: Docker Operations - name: Docker Operations
run: | run: |
sudo make init curl -o docker-compose.yml https://raw.githubusercontent.com/OpenIMSDK/openim-docker/main/example/basic-openim-server-dependency.yml
sudo docker compose up -d sudo docker compose up -d
sudo sleep 20 sudo sleep 60
- name: Module Operations - name: Module Operations
run: | run: |
@@ -100,15 +97,4 @@ jobs:
- name: Exec OpenIM System uninstall - name: Exec OpenIM System uninstall
run: | run: |
sudo ./scripts/install/install.sh -u sudo ./scripts/install/install.sh -u
- name: gobenchdata publish
uses: bobheadxi/gobenchdata@v1
with:
PRUNE_COUNT: 30
GO_TEST_FLAGS: -cpu 1,2
PUBLISH: true
PUBLISH_BRANCH: gh-pages
env:
GITHUB_TOKEN: ${{ secrets.BOT_GITHUB_TOKEN }}
continue-on-error: true
+1 -1
View File
@@ -41,7 +41,7 @@ jobs:
# ./*.md all markdown files in the root directory # ./*.md all markdown files in the root directory
args: --verbose -E -i --no-progress --exclude-path './CHANGELOG' './**/*.md' args: --verbose -E -i --no-progress --exclude-path './CHANGELOG' './**/*.md'
env: env:
GITHUB_TOKEN: ${{secrets.BOT_GITHUB_TOKEN}} GITHUB_TOKEN: ${{secrets.GH_PAT}}
- name: Create Issue From File - name: Create Issue From File
if: env.lychee_exit_code != 0 if: env.lychee_exit_code != 0
+1 -2
View File
@@ -51,5 +51,4 @@ jobs:
OCO_EMOJI: false OCO_EMOJI: false
OCO_MODEL: gpt-3.5-turbo-16k OCO_MODEL: gpt-3.5-turbo-16k
OCO_LANGUAGE: en OCO_LANGUAGE: en
OCO_PROMPT_MODULE: conventional-commit OCO_PROMPT_MODULE: conventional-commit
continue-on-error: true
+2 -3
View File
@@ -156,9 +156,9 @@ jobs:
- name: Docker Operations - name: Docker Operations
run: | run: |
sudo make init curl -o docker-compose.yml https://raw.githubusercontent.com/OpenIMSDK/openim-docker/main/example/basic-openim-server-dependency.yml
sudo docker compose up -d sudo docker compose up -d
sudo sleep 20 sudo sleep 60
- name: Module Operations - name: Module Operations
run: | run: |
@@ -195,5 +195,4 @@ jobs:
- name: Test Docker Build - name: Test Docker Build
run: | run: |
sudo make init
sudo make image sudo make image
-2
View File
@@ -391,5 +391,3 @@ Sessionx.vim
dist/ dist/
.env .env
config/config.yaml config/config.yaml
config/alertmanager.yml
config/prometheus.yml
+2 -3
View File
@@ -25,8 +25,7 @@ WORKDIR ${SERVER_WORKDIR}
# Copy scripts and binary files to the production image # Copy scripts and binary files to the production image
COPY --from=builder ${OPENIM_SERVER_BINDIR} /openim/openim-server/_output/bin COPY --from=builder ${OPENIM_SERVER_BINDIR} /openim/openim-server/_output/bin
COPY --from=builder ${OPENIM_SERVER_CMDDIR} /openim/openim-server/scripts # COPY --from=builder ${OPENIM_SERVER_CMDDIR} /openim/openim-server/scripts
COPY --from=builder ${SERVER_WORKDIR}/config /openim/openim-server/config # COPY --from=builder ${SERVER_WORKDIR}/config /openim/openim-server/config
COPY --from=builder ${SERVER_WORKDIR}/deployments /openim/openim-server/deployments
CMD ["/openim/openim-server/scripts/docker-start-all.sh"] CMD ["/openim/openim-server/scripts/docker-start-all.sh"]
+1 -1
View File
@@ -30,7 +30,7 @@
</p> </p>
## 🟢 扫描微信进群交流 ## 🟢 扫描微信进群交流
<img src="./docs/images/Wechat.jpg" width="300"> <img src="https://openim-1253691595.cos.ap-nanjing.myqcloud.com/WechatIMG20.jpeg" width="300">
## Ⓜ️ 关于 OpenIM ## Ⓜ️ 关于 OpenIM
+1 -1
View File
@@ -231,7 +231,7 @@ Before you start, please make sure your changes are in demand. The best for that
- [OpenIM Makefile Utilities](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/util-makefile.md) - [OpenIM Makefile Utilities](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/util-makefile.md)
- [OpenIM Script Utilities](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/util-scripts.md) - [OpenIM Script Utilities](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/util-scripts.md)
- [OpenIM Versioning](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/version.md) - [OpenIM Versioning](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/version.md)
- [Manage backend and monitor deployment](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/prometheus-grafana.md)
## :busts_in_silhouette: Community ## :busts_in_silhouette: Community
Executable
BIN
View File
Binary file not shown.
+13 -30
View File
@@ -18,13 +18,11 @@ import (
"context" "context"
"fmt" "fmt"
"net" "net"
"net/http"
_ "net/http/pprof" _ "net/http/pprof"
"os"
"os/signal"
"strconv" "strconv"
"syscall"
"time" ginProm "github.com/openimsdk/open-im-server/v3/pkg/common/ginprometheus"
"github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics"
"github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/protocol/constant"
"github.com/OpenIMSDK/tools/discoveryregistry" "github.com/OpenIMSDK/tools/discoveryregistry"
@@ -35,8 +33,6 @@ import (
"github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/config"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache"
kdisc "github.com/openimsdk/open-im-server/v3/pkg/common/discoveryregister" kdisc "github.com/openimsdk/open-im-server/v3/pkg/common/discoveryregister"
ginProm "github.com/openimsdk/open-im-server/v3/pkg/common/ginprometheus"
"github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics"
) )
func main() { func main() {
@@ -55,12 +51,13 @@ func run(port int, proPort int) error {
if port == 0 || proPort == 0 { if port == 0 || proPort == 0 {
err := "port or proPort is empty:" + strconv.Itoa(port) + "," + strconv.Itoa(proPort) err := "port or proPort is empty:" + strconv.Itoa(port) + "," + strconv.Itoa(proPort)
log.ZError(context.Background(), err, nil) log.ZError(context.Background(), err, nil)
return fmt.Errorf(err) return fmt.Errorf(err)
} }
rdb, err := cache.NewRedis() rdb, err := cache.NewRedis()
if err != nil { if err != nil {
log.ZError(context.Background(), "Failed to initialize Redis", err) log.ZError(context.Background(), "Failed to initialize Redis", err)
return err return err
} }
log.ZInfo(context.Background(), "api start init discov client") log.ZInfo(context.Background(), "api start init discov client")
@@ -71,29 +68,30 @@ func run(port int, proPort int) error {
client, err = kdisc.NewDiscoveryRegister(config.Config.Envs.Discovery) client, err = kdisc.NewDiscoveryRegister(config.Config.Envs.Discovery)
if err != nil { if err != nil {
log.ZError(context.Background(), "Failed to initialize discovery register", err) log.ZError(context.Background(), "Failed to initialize discovery register", err)
return err return err
} }
if err = client.CreateRpcRootNodes(config.Config.GetServiceNames()); err != nil { if err = client.CreateRpcRootNodes(config.Config.GetServiceNames()); err != nil {
log.ZError(context.Background(), "Failed to create RPC root nodes", err) log.ZError(context.Background(), "Failed to create RPC root nodes", err)
return err return err
} }
log.ZInfo(context.Background(), "api register public config to discov") log.ZInfo(context.Background(), "api register public config to discov")
if err = client.RegisterConf2Registry(constant.OpenIMCommonConfigKey, config.Config.EncodeConfig()); err != nil { if err = client.RegisterConf2Registry(constant.OpenIMCommonConfigKey, config.Config.EncodeConfig()); err != nil {
log.ZError(context.Background(), "Failed to register public config to discov", err) log.ZError(context.Background(), "Failed to register public config to discov", err)
return err return err
} }
log.ZInfo(context.Background(), "api register public config to discov success") log.ZInfo(context.Background(), "api register public config to discov success")
router := api.NewGinRouter(client, rdb) router := api.NewGinRouter(client, rdb)
//////////////////////////////
if config.Config.Prometheus.Enable { if config.Config.Prometheus.Enable {
p := ginProm.NewPrometheus("app", prommetrics.GetGinCusMetrics("Api")) p := ginProm.NewPrometheus("app", prommetrics.GetGinCusMetrics("Api"))
p.SetListenAddress(fmt.Sprintf(":%d", proPort)) p.SetListenAddress(fmt.Sprintf(":%d", proPort))
p.Use(router) p.Use(router)
} }
/////////////////////////////////
log.ZInfo(context.Background(), "api init router success") log.ZInfo(context.Background(), "api init router success")
var address string var address string
if config.Config.Api.ListenIP != "" { if config.Config.Api.ListenIP != "" {
address = net.JoinHostPort(config.Config.Api.ListenIP, strconv.Itoa(port)) address = net.JoinHostPort(config.Config.Api.ListenIP, strconv.Itoa(port))
@@ -102,25 +100,10 @@ func run(port int, proPort int) error {
} }
log.ZInfo(context.Background(), "start api server", "address", address, "OpenIM version", config.Version) log.ZInfo(context.Background(), "start api server", "address", address, "OpenIM version", config.Version)
server := http.Server{Addr: address, Handler: router} err = router.Run(address)
go func() { if err != nil {
err = server.ListenAndServe() log.ZError(context.Background(), "api run failed", err, "address", address)
if err != nil && err != http.ErrServerClosed {
log.ZError(context.Background(), "api run failed", err, "address", address)
os.Exit(1)
}
}()
sigs := make(chan os.Signal, 1)
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)
<-sigs
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
defer cancel()
// graceful shutdown operation.
if err := server.Shutdown(ctx); err != nil {
log.ZError(context.Background(), "failed to api-server shutdown", err)
return err return err
} }
-1
View File
@@ -23,7 +23,6 @@ func main() {
msgGatewayCmd.AddWsPortFlag() msgGatewayCmd.AddWsPortFlag()
msgGatewayCmd.AddPortFlag() msgGatewayCmd.AddPortFlag()
msgGatewayCmd.AddPrometheusPortFlag() msgGatewayCmd.AddPrometheusPortFlag()
if err := msgGatewayCmd.Exec(); err != nil { if err := msgGatewayCmd.Exec(); err != nil {
panic(err.Error()) panic(err.Error())
} }
@@ -35,6 +35,26 @@ zookeeper:
username: '' username: ''
password: '' password: ''
###################### Mysql ######################
# MySQL configuration
# Currently, only single machine setup is supported
#
# Maximum number of open connections
# Maximum number of idle connections
# Maximum lifetime in seconds a connection can be reused
# Log level: 1=slient, 2=error, 3=warn, 4=info
# Slow query threshold in milliseconds
mysql:
address: [ 172.28.0.1:13306 ]
username: root
password: openIM123
database: openIM_v3
maxOpenConn: 1000
maxIdleConn: 100
maxLifeTime: 60
logLevel: 4
slowThreshold: 500
###################### Mongo ###################### ###################### Mongo ######################
# MongoDB configuration # MongoDB configuration
# If uri is not empty, it will be used directly # If uri is not empty, it will be used directly
@@ -115,14 +135,14 @@ api:
# minio.signEndpoint is minio public network address # minio.signEndpoint is minio public network address
object: object:
enable: "minio" enable: "minio"
apiURL: "http://172.28.0.1:10002" apiURL: "http://127.0.0.1:10002"
minio: minio:
bucket: "openim" bucket: "openim"
endpoint: "http://172.28.0.1:10005" endpoint: "http://172.28.0.1:10005"
accessKeyID: "root" accessKeyID: "root"
secretAccessKey: "openIM123" secretAccessKey: "openIM123"
sessionToken: '' sessionToken: ''
signEndpoint: "http://172.28.0.1:10005" signEndpoint: "http://127.0.0.1:10005"
publicRead: false publicRead: false
cos: cos:
bucketURL: https://temp-1252357374.cos.ap-chengdu.myqcloud.com bucketURL: https://temp-1252357374.cos.ap-chengdu.myqcloud.com
@@ -138,21 +158,13 @@ object:
accessKeySecret: '' accessKeySecret: ''
sessionToken: '' sessionToken: ''
publicRead: false publicRead: false
kodo:
endpoint: "http://s3.cn-east-1.qiniucs.com"
bucket: "demo-9999999"
bucketURL: "http://your.domain.com"
accessKeyID: ''
accessKeySecret: ''
sessionToken: ''
publicRead: false
###################### RPC Port Configuration ###################### ###################### RPC Port Configuration ######################
# RPC service ports # RPC service ports
# These ports are passed into the program by the script and are not recommended to modify # These ports are passed into the program by the script and are not recommended to modify
# For launching multiple programs, just fill in multiple ports separated by commas # For launching multiple programs, just fill in multiple ports separated by commas
# For example, [10110, 10111] # For example, [10110, 10111]
rpcPort: rpcPort:
openImUserPort: [ 10110 ] openImUserPort: [ 10110 ]
openImFriendPort: [ 10120 ] openImFriendPort: [ 10120 ]
openImMessagePort: [ 10130 ] openImMessagePort: [ 10130 ]
@@ -186,7 +198,7 @@ rpcRegisterName:
# Whether to output in json format # Whether to output in json format
# Whether to include stack trace in logs # Whether to include stack trace in logs
log: log:
storageLocation: ../logs/ storageLocation: ./logs/
rotationTime: 24 rotationTime: 24
remainRotationCount: 2 remainRotationCount: 2
remainLogLevel: 6 remainLogLevel: 6
@@ -300,7 +312,7 @@ iosPush:
# Timeout in seconds # Timeout in seconds
# Whether to continue execution if callback fails # Whether to continue execution if callback fails
callback: callback:
url: "" url:
beforeSendSingleMsg: beforeSendSingleMsg:
enable: false enable: false
timeout: 5 timeout: 5
@@ -308,7 +320,6 @@ callback:
afterSendSingleMsg: afterSendSingleMsg:
enable: false enable: false
timeout: 5 timeout: 5
failedContinue: true
beforeSendGroupMsg: beforeSendGroupMsg:
enable: false enable: false
timeout: 5 timeout: 5
@@ -316,7 +327,6 @@ callback:
afterSendGroupMsg: afterSendGroupMsg:
enable: false enable: false
timeout: 5 timeout: 5
failedContinue: true
msgModify: msgModify:
enable: false enable: false
timeout: 5 timeout: 5
@@ -324,15 +334,12 @@ callback:
userOnline: userOnline:
enable: false enable: false
timeout: 5 timeout: 5
failedContinue: true
userOffline: userOffline:
enable: false enable: false
timeout: 5 timeout: 5
failedContinue: true
userKickOff: userKickOff:
enable: false enable: false
timeout: 5 timeout: 5
failedContinue: true
offlinePush: offlinePush:
enable: false enable: false
timeout: 5 timeout: 5
@@ -357,10 +364,6 @@ callback:
enable: false enable: false
timeout: 5 timeout: 5
failedContinue: true failedContinue: true
afterCreateGroup:
enable: false
timeout: 5
failedContinue: true
beforeMemberJoinGroup: beforeMemberJoinGroup:
enable: false enable: false
timeout: 5 timeout: 5
@@ -369,129 +372,18 @@ callback:
enable: false enable: false
timeout: 5 timeout: 5
failedContinue: true failedContinue: true
afterSetGroupMemberInfo:
enable: false
timeout: 5
failedContinue: true
setMessageReactionExtensions: setMessageReactionExtensions:
enable: false enable: false
timeout: 5 timeout: 5
failedContinue: true failedContinue: true
quitGroup:
enable: false
timeout: 5
failedContinue: true
killGroupMember:
enable: false
timeout: 5
failedContinue: true
dismissGroup:
enable: false
timeout: 5
failedContinue: true
joinGroup:
enable: false
timeout: 5
failedContinue: true
groupMsgRead:
enable: false
timeout: 5
failedContinue: true
singleMsgRead:
enable: false
timeout: 5
failedContinue: true
updateUserInfo:
enable: false
timeout: 5
failedContinue: true
beforeUserRegister:
enable: false
timeout: 5
failedContinue: true
afterUserRegister:
enable: false
timeout: 5
failedContinue: true
transferGroupOwner:
enable: false
timeout: 5
failedContinue: true
beforeSetFriendRemark:
enable: false
timeout: 5
failedContinue: true
afterSetFriendRemark:
enable: false
timeout: 5
failedContinue: true
afterGroupMsgRead:
enable: false
timeout: 5
failedContinue: true
afterGroupMsgRevoke:
enable: false
timeout: 5
failedContinue: true
afterJoinGroup:
enable: false
timeout: 5
failedContinue: true
beforeInviteUserToGroup:
enable: false
timeout: 5
failedContinue: true
joinGroupAfter:
enable: false
timeout: 5
failedContinue: true
setGroupInfoAfter:
enable: false
timeout: 5
failedContinue: true
setGroupInfoBefore:
enable: false
timeout: 5
failedContinue: true
revokeMsgAfter:
enable: false
timeout: 5
failedContinue: true
addBlackBefore:
enable: false
timeout: 5
failedContinue: true
addFriendAfter:
enable: false
timeout: 5
failedContinue: true
addFriendAgreeBefore:
enable: false
timeout: 5
failedContinue: true
deleteFriendAfter:
enable: false
timeout: 5
failedContinue: true
importFriendsBefore:
enable: false
timeout: 5
failedContinue: true
importFriendsAfter:
enable: false
timeout: 5
failedContinue: true
removeBlackAfter:
enable: false
timeout: 5
failedContinue: true
###################### Prometheus ###################### ###################### Prometheus ######################
# Prometheus configuration for various services # Prometheus configuration for various services
# The number of Prometheus ports per service needs to correspond to rpcPort # The number of Prometheus ports per service needs to correspond to rpcPort
# The number of ports needs to be consistent with msg_transfer_service_num in script/path_info.sh # The number of ports needs to be consistent with msg_transfer_service_num in script/path_info.sh
prometheus: prometheus:
enable: false enable: true
prometheusUrl: 172.28.0.1:13000 prometheusUrl: "https://openim.prometheus"
apiPrometheusPort: [20100] apiPrometheusPort: [20100]
userPrometheusPort: [ 20110 ] userPrometheusPort: [ 20110 ]
friendPrometheusPort: [ 20120 ] friendPrometheusPort: [ 20120 ]
-16
View File
@@ -1,16 +0,0 @@
{{ define "email.to.html" }}
{{ range .Alerts }}
<!-- Begin of OpenIM Alert -->
<div style="border:1px solid #ccc; padding:10px; margin-bottom:10px;">
<h3>OpenIM Alert</h3>
<p><strong>Alert Program:</strong> Prometheus Alert</p>
<p><strong>Severity Level:</strong> {{ .Labels.severity }}</p>
<p><strong>Alert Type:</strong> {{ .Labels.alertname }}</p>
<p><strong>Affected Host:</strong> {{ .Labels.instance }}</p>
<p><strong>Affected Service:</strong> {{ .Labels.job }}</p>
<p><strong>Alert Subject:</strong> {{ .Annotations.summary }}</p>
<p><strong>Trigger Time:</strong> {{ .StartsAt.Format "2006-01-02 15:04:05" }}</p>
</div>
<!-- End of OpenIM Alert -->
{{ end }}
{{ end }}
-22
View File
@@ -1,22 +0,0 @@
groups:
- name: instance_down
rules:
- alert: InstanceDown
expr: up == 0
for: 1m
labels:
severity: critical
annotations:
summary: "Instance {{ $labels.instance }} down"
description: "{{ $labels.instance }} of job {{ $labels.job }} has been down for more than 1 minutes."
- name: database_insert_failure_alerts
rules:
- alert: DatabaseInsertFailed
expr: (increase(msg_insert_redis_failed_total[5m]) > 0) or (increase(msg_insert_mongo_failed_total[5m]) > 0)
for: 1m
labels:
severity: critical
annotations:
summary: "Increase in MsgInsertRedisFailedCounter or MsgInsertMongoFailedCounter detected"
description: "Either MsgInsertRedisFailedCounter or MsgInsertMongoFailedCounter has increased in the last 5 minutes, indicating failures in message insert operations to Redis or MongoDB,maybe the redis or mongodb is crash."
File diff suppressed because it is too large Load Diff
-36
View File
@@ -1,36 +0,0 @@
# Examples Directory
Welcome to the `examples` directory of our project! This directory contains a collection of example files that demonstrate various configurations and setups for our software. These examples are designed to provide you with templates that can be used as a starting point for your own configurations.
## Overview
In this directory, you'll find examples for a variety of use cases. Each file is a template with default values and configurations that illustrate best practices and typical scenarios. Whether you're just getting started or looking to implement a complex setup, these examples should help you get on the right track.
## Structure
Here's a quick overview of what you'll find in this directory:
+ `env-example.yaml`: Demonstrates how to set up environment variables.
+ `openim-example.yaml`: A sample configuration file for the OpenIM application.
+ `prometheus-example.yml`: An example Prometheus configuration for monitoring.
+ `alertmanager-example.yml`: A template for setting up Alertmanager configurations.
## How to Use These Examples
To use these examples, simply copy the relevant file to your working directory and rename it as needed (e.g., removing the `-example` suffix). Then, modify the file according to your requirements.
### Tips for Using Example Files:
1. **Read the Comments**: Each file contains comments that explain various sections and settings. Make sure to read these comments for a better understanding of how to customize the file.
2. **Check for Required Changes**: Some examples might require mandatory changes (like setting specific environment variables) before they can be used effectively.
3. **Version Compatibility**: Ensure that the example files are compatible with the version of the software you are using.
## Contributing
If you have a configuration that you believe would be beneficial to others, please feel free to contribute by opening a pull request with your proposed changes. We appreciate contributions that expand our examples with new scenarios and use cases.
## Support
If you encounter any issues or have questions regarding the example files, please open an issue on our repository. Our community is here to help you navigate through any challenges you might face.
Thank you for exploring our examples, and we hope they will be helpful in setting up and configuring your environment!
@@ -1,33 +0,0 @@
###################### AlertManager Configuration ######################
# AlertManager configuration using environment variables
#
# Resolve timeout
# SMTP configuration for sending alerts
# Templates for email notifications
# Routing configurations for alerts
# Receiver configurations
global:
resolve_timeout: 5m
smtp_from: alert@openim.io
smtp_smarthost: smtp.163.com:465
smtp_auth_username: alert@openim.io
smtp_auth_password: YOURAUTHPASSWORD
smtp_require_tls: false
smtp_hello: xxx监控告警
templates:
- /etc/alertmanager/email.tmpl
route:
group_by: ['alertname']
group_wait: 5s
group_interval: 5s
repeat_interval: 5m
receiver: email
receivers:
- name: email
email_configs:
- to: 'alert@example.com'
html: '{{ template "email.to.html" . }}'
headers: { Subject: "[OPENIM-SERVER]Alarm" }
send_resolved: true
-85
View File
@@ -1,85 +0,0 @@
# my global config
global:
scrape_interval: 15s # Set the scrape interval to every 15 seconds. Default is every 1 minute.
evaluation_interval: 15s # Evaluate rules every 15 seconds. The default is every 1 minute.
# scrape_timeout is set to the global default (10s).
# Alertmanager configuration
alerting:
alertmanagers:
- static_configs:
- targets: ['172.28.0.1:19093']
# Load rules once and periodically evaluate them according to the global 'evaluation_interval'.
rule_files:
- "instance-down-rules.yml"
# - "first_rules.yml"
# - "second_rules.yml"
# A scrape configuration containing exactly one endpoint to scrape:
# Here it's Prometheus itself.
scrape_configs:
# The job name is added as a label "job='job_name'"" to any timeseries scraped from this config.
# Monitored information captured by prometheus
- job_name: 'node-exporter'
static_configs:
- targets: [ '172.28.0.1:19100' ]
labels:
namespace: 'default'
# prometheus fetches application services
- job_name: 'openimserver-openim-api'
static_configs:
- targets: [ '172.28.0.1:20100' ]
labels:
namespace: 'default'
- job_name: 'openimserver-openim-msggateway'
static_configs:
- targets: [ '172.28.0.1:20140' ]
labels:
namespace: 'default'
- job_name: 'openimserver-openim-msgtransfer'
static_configs:
- targets: [ 172.28.0.1:21400, 172.28.0.1:21401, 172.28.0.1:21402, 172.28.0.1:21403 ]
labels:
namespace: 'default'
- job_name: 'openimserver-openim-push'
static_configs:
- targets: [ '172.28.0.1:20170' ]
labels:
namespace: 'default'
- job_name: 'openimserver-openim-rpc-auth'
static_configs:
- targets: [ '172.28.0.1:20160' ]
labels:
namespace: 'default'
- job_name: 'openimserver-openim-rpc-conversation'
static_configs:
- targets: [ '172.28.0.1:20230' ]
labels:
namespace: 'default'
- job_name: 'openimserver-openim-rpc-friend'
static_configs:
- targets: [ '172.28.0.1:20120' ]
labels:
namespace: 'default'
- job_name: 'openimserver-openim-rpc-group'
static_configs:
- targets: [ '172.28.0.1:20150' ]
labels:
namespace: 'default'
- job_name: 'openimserver-openim-rpc-msg'
static_configs:
- targets: [ '172.28.0.1:20130' ]
labels:
namespace: 'default'
- job_name: 'openimserver-openim-rpc-third'
static_configs:
- targets: [ '172.28.0.1:21301' ]
labels:
namespace: 'default'
- job_name: 'openimserver-openim-rpc-user'
static_configs:
- targets: [ '172.28.0.1:20110' ]
labels:
namespace: 'default'
+5 -27
View File
@@ -84,8 +84,8 @@ $ sudo sealos run labring/kubernetes:v1.25.0 labring/helm:v3.8.2 labring/calico:
If you are local, you can also use Kind and Minikube to test, for example, using Kind: If you are local, you can also use Kind and Minikube to test, for example, using Kind:
```bash ```bash
$ GO111MODULE="on" go get sigs.k8s.io/kind@v0.11.1 $ sGO111MODULE="on" go get sigs.k8s.io/kind@v0.11.1
$ kind create cluster $ skind create cluster
``` ```
### Installing helm ### Installing helm
@@ -123,30 +123,6 @@ Explore our Helm-Charts repository and read through: [Helm-Charts Repository](ht
Using the helm charts repository, you can ignore the following configuration, but if you want to just use the server and scale on top of it, you can go ahead: Using the helm charts repository, you can ignore the following configuration, but if you want to just use the server and scale on top of it, you can go ahead:
**Use the Helm template to generate the deployment yaml file: `openim-charts.yaml`**
**Gen Image:**
```bash
../scripts/genconfig.sh ../scripts/install/environment.sh ./templates/helm-image.yaml > ./charts/generated-configs/helm-image.yaml
```
**Gen Charts:**
```bash
for chart in ./charts/*/; do
if [[ "$chart" == *"generated-configs"* || "$chart" == *"helmfile.yaml"* ]]; then
continue
fi
if [ -f "${chart}values.yaml" ]; then
helm template "$chart" -f "./charts/generated-configs/helm-image.yaml" -f "./charts/generated-configs/config.yaml" -f "./charts/generated-configs/notification.yaml" >> openim-charts.yaml
else
helm template "$chart" >> openim-charts.yaml
fi
done
```
**Use Helmfile:** **Use Helmfile:**
```bash ```bash
@@ -154,6 +130,8 @@ GO111MODULE=on go get github.com/roboll/helmfile@latest
``` ```
```bash ```bash
export MYSQL_ADDRESS=im-mysql
export MYSQL_PORT=3306
export MONGO_ADDRESS=im-mongo export MONGO_ADDRESS=im-mongo
export MONGO_PORT=27017 export MONGO_PORT=27017
export REDIS_ADDRESS=im-redis-master export REDIS_ADDRESS=im-redis-master
@@ -172,4 +150,4 @@ cp ../config/notification.yaml ./charts/generated-configs/notification.yaml
```bash ```bash
helmfile apply helmfile apply
``` ```
File diff suppressed because it is too large Load Diff
-33
View File
@@ -1,33 +0,0 @@
###################### AlertManager Configuration ######################
# AlertManager configuration using environment variables
#
# Resolve timeout
# SMTP configuration for sending alerts
# Templates for email notifications
# Routing configurations for alerts
# Receiver configurations
global:
resolve_timeout: ${ALERTMANAGER_RESOLVE_TIMEOUT}
smtp_from: ${ALERTMANAGER_SMTP_FROM}
smtp_smarthost: ${ALERTMANAGER_SMTP_SMARTHOST}
smtp_auth_username: ${ALERTMANAGER_SMTP_AUTH_USERNAME}
smtp_auth_password: ${ALERTMANAGER_SMTP_AUTH_PASSWORD}
smtp_require_tls: ${ALERTMANAGER_SMTP_REQUIRE_TLS}
smtp_hello: ${ALERTMANAGER_SMTP_HELLO}
templates:
- /etc/alertmanager/email.tmpl
route:
group_by: ['alertname']
group_wait: 5s
group_interval: 5s
repeat_interval: 5m
receiver: email
receivers:
- name: email
email_configs:
- to: '${ALERTMANAGER_EMAIL_TO}'
html: '{{ template "email.to.html" . }}'
headers: { Subject: "[OPENIM-SERVER]Alarm" }
send_resolved: true
+13
View File
@@ -53,6 +53,19 @@ rpcRegisterName:
openImAdminName: ${OPENIM_ADMIN_NAME} openImAdminName: ${OPENIM_ADMIN_NAME}
openImChatName: ${OPENIM_CHAT_NAME} openImChatName: ${OPENIM_CHAT_NAME}
###################### MySQL ######################
mysql:
# address: [ 127.0.0.1:13306 ] #目前仅支持单机
# username: root #用户名
# password: openIM123 #密码
# database: openIM_v2 #不建议修改
# maxOpenConn: 1000 #最大连接数
# maxIdleConn: 100 #最大空闲连接数
# maxLifeTime: 60 #连接可以重复使用的最长时间(秒)
# logLevel: 4 #日志级别 1=slient 2=error 3=warn 4=info
# slowThreshold: 500 #慢语句阈值 (毫秒)
database: openim_enterprise
###################### Log ###################### ###################### Log ######################
log: log:
storageLocation: ../logs/ #存放目录 storageLocation: ../logs/ #存放目录
@@ -1,10 +1,24 @@
# 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.
# ====================================== # ======================================
# ========= Basic Configuration ======== # ========= Basic Configuration ========
# ====================================== # ======================================
# The user for authentication or system operations. # The user for authentication or system operations.
# Default: OPENIM_USER=root # Default: USER=root
USER=${OPENIM_USER} USER=${USER}
# Password associated with the specified user for authentication. # Password associated with the specified user for authentication.
# Default: PASSWORD=openIM123 # Default: PASSWORD=openIM123
@@ -41,19 +55,50 @@ DOCKER_BRIDGE_SUBNET=${DOCKER_BRIDGE_SUBNET}
# Default: DOCKER_BRIDGE_GATEWAY=172.28.0.1 # Default: DOCKER_BRIDGE_GATEWAY=172.28.0.1
DOCKER_BRIDGE_GATEWAY=${DOCKER_BRIDGE_GATEWAY} DOCKER_BRIDGE_GATEWAY=${DOCKER_BRIDGE_GATEWAY}
# Address or hostname for the MySQL network.
# Default: MYSQL_NETWORK_ADDRESS=172.28.0.2
MYSQL_NETWORK_ADDRESS=${MYSQL_NETWORK_ADDRESS}
# Address or hostname for the MongoDB network.
# Default: MONGO_NETWORK_ADDRESS=172.28.0.3
MONGO_NETWORK_ADDRESS=${MONGO_NETWORK_ADDRESS} MONGO_NETWORK_ADDRESS=${MONGO_NETWORK_ADDRESS}
# Address or hostname for the Redis network.
# Default: REDIS_NETWORK_ADDRESS=172.28.0.4
REDIS_NETWORK_ADDRESS=${REDIS_NETWORK_ADDRESS} REDIS_NETWORK_ADDRESS=${REDIS_NETWORK_ADDRESS}
# Address or hostname for the Kafka network.
# Default: KAFKA_NETWORK_ADDRESS=172.28.0.5
KAFKA_NETWORK_ADDRESS=${KAFKA_NETWORK_ADDRESS} KAFKA_NETWORK_ADDRESS=${KAFKA_NETWORK_ADDRESS}
# Address or hostname for the ZooKeeper network.
# Default: ZOOKEEPER_NETWORK_ADDRESS=172.28.0.6
ZOOKEEPER_NETWORK_ADDRESS=${ZOOKEEPER_NETWORK_ADDRESS} ZOOKEEPER_NETWORK_ADDRESS=${ZOOKEEPER_NETWORK_ADDRESS}
# Address or hostname for the MinIO network.
# Default: MINIO_NETWORK_ADDRESS=172.28.0.7
MINIO_NETWORK_ADDRESS=${MINIO_NETWORK_ADDRESS} MINIO_NETWORK_ADDRESS=${MINIO_NETWORK_ADDRESS}
# Address or hostname for the OpenIM web network.
# Default: OPENIM_WEB_NETWORK_ADDRESS=172.28.0.8
OPENIM_WEB_NETWORK_ADDRESS=${OPENIM_WEB_NETWORK_ADDRESS} OPENIM_WEB_NETWORK_ADDRESS=${OPENIM_WEB_NETWORK_ADDRESS}
# Address or hostname for the OpenIM server network.
# Default: OPENIM_SERVER_NETWORK_ADDRESS=172.28.0.9
OPENIM_SERVER_NETWORK_ADDRESS=${OPENIM_SERVER_NETWORK_ADDRESS} OPENIM_SERVER_NETWORK_ADDRESS=${OPENIM_SERVER_NETWORK_ADDRESS}
# Address or hostname for the OpenIM chat network.
# Default: OPENIM_CHAT_NETWORK_ADDRESS=172.28.0.10
OPENIM_CHAT_NETWORK_ADDRESS=${OPENIM_CHAT_NETWORK_ADDRESS} OPENIM_CHAT_NETWORK_ADDRESS=${OPENIM_CHAT_NETWORK_ADDRESS}
# Address or hostname for the Prometheus network.
# Default: PROMETHEUS_NETWORK_ADDRESS=172.28.0.11
PROMETHEUS_NETWORK_ADDRESS=${PROMETHEUS_NETWORK_ADDRESS} PROMETHEUS_NETWORK_ADDRESS=${PROMETHEUS_NETWORK_ADDRESS}
# Address or hostname for the Grafana network.
# Default: GRAFANA_NETWORK_ADDRESS=172.28.0.12
GRAFANA_NETWORK_ADDRESS=${GRAFANA_NETWORK_ADDRESS} GRAFANA_NETWORK_ADDRESS=${GRAFANA_NETWORK_ADDRESS}
NODE_EXPORTER_NETWORK_ADDRESS=${NODE_EXPORTER_NETWORK_ADDRESS}
OPENIM_ADMIN_FRONT_NETWORK_ADDRESS=${OPENIM_ADMIN_FRONT_NETWORK_ADDRESS}
ALERT_MANAGER_NETWORK_ADDRESS=${ALERT_MANAGER_NETWORK_ADDRESS}
# =============================================== # ===============================================
# = Component Extension Configuration = # = Component Extension Configuration =
@@ -69,6 +114,20 @@ ZOOKEEPER_ADDRESS=${ZOOKEEPER_NETWORK_ADDRESS}
# Default: ZOOKEEPER_PORT=12181 # Default: ZOOKEEPER_PORT=12181
ZOOKEEPER_PORT=${ZOOKEEPER_PORT} ZOOKEEPER_PORT=${ZOOKEEPER_PORT}
# ----- MySQL Configuration -----
# Address or hostname for the MySQL service.
# Default: MYSQL_ADDRESS=172.28.0.1
MYSQL_ADDRESS=${MYSQL_NETWORK_ADDRESS}
# Port on which MySQL database service is running.
# Default: MYSQL_PORT=13306
MYSQL_PORT=${MYSQL_PORT}
# Password to authenticate with the MySQL database service.
# Default: MYSQL_PASSWORD=openIM123
MYSQL_PASSWORD=${MYSQL_PASSWORD}
# ----- MongoDB Configuration ----- # ----- MongoDB Configuration -----
# Address or hostname for the MongoDB service. # Address or hostname for the MongoDB service.
# Default: MONGO_ADDRESS=172.28.0.1 # Default: MONGO_ADDRESS=172.28.0.1
@@ -76,11 +135,11 @@ MONGO_ADDRESS=${MONGO_NETWORK_ADDRESS}
# Port on which MongoDB service is running. # Port on which MongoDB service is running.
# Default: MONGO_PORT=37017 # Default: MONGO_PORT=37017
# MONGO_PORT=${MONGO_PORT} MONGO_PORT=${MONGO_PORT}
# Username to authenticate with the MongoDB service. # Username to authenticate with the MongoDB service.
# Default: MONGO_USERNAME=root # Default: MONGO_USERNAME=root
# MONGO_USERNAME=${MONGO_USERNAME} MONGO_USERNAME=${MONGO_USERNAME}
# Password to authenticate with the MongoDB service. # Password to authenticate with the MongoDB service.
# Default: MONGO_PASSWORD=openIM123 # Default: MONGO_PASSWORD=openIM123
@@ -108,9 +167,6 @@ REDIS_PASSWORD=${REDIS_PASSWORD}
# Default: KAFKA_ADDRESS=172.28.0.1 # Default: KAFKA_ADDRESS=172.28.0.1
KAFKA_ADDRESS=${KAFKA_NETWORK_ADDRESS} KAFKA_ADDRESS=${KAFKA_NETWORK_ADDRESS}
# Kakfa username to authenticate with the Kafka service.
# KAFKA_USERNAME=${KAFKA_USERNAME}
# Port on which Kafka distributed streaming platform is running. # Port on which Kafka distributed streaming platform is running.
# Default: KAFKA_PORT=19092 # Default: KAFKA_PORT=19092
KAFKA_PORT=${KAFKA_PORT} KAFKA_PORT=${KAFKA_PORT}
@@ -138,7 +194,7 @@ MINIO_PORT=${MINIO_PORT}
# Access key to authenticate with the MinIO service. # Access key to authenticate with the MinIO service.
# Default: MINIO_ACCESS_KEY=root # Default: MINIO_ACCESS_KEY=root
# MINIO_ACCESS_KEY=${MINIO_ACCESS_KEY} MINIO_ACCESS_KEY=${MINIO_ACCESS_KEY}
# Secret key corresponding to the access key for MinIO authentication. # Secret key corresponding to the access key for MinIO authentication.
# Default: MINIO_SECRET_KEY=openIM123 # Default: MINIO_SECRET_KEY=openIM123
@@ -159,7 +215,7 @@ PROMETHEUS_PORT=${PROMETHEUS_PORT}
GRAFANA_ADDRESS=${GRAFANA_NETWORK_ADDRESS} GRAFANA_ADDRESS=${GRAFANA_NETWORK_ADDRESS}
# Port on which Grafana service is running. # Port on which Grafana service is running.
# Default: GRAFANA_PORT=13000 # Default: GRAFANA_PORT=3000
GRAFANA_PORT=${GRAFANA_PORT} GRAFANA_PORT=${GRAFANA_PORT}
# ====================================== # ======================================
@@ -227,23 +283,3 @@ SERVER_BRANCH=${SERVER_BRANCH}
# Port for the OpenIM admin API. # Port for the OpenIM admin API.
# Default: OPENIM_ADMIN_API_PORT=10009 # Default: OPENIM_ADMIN_API_PORT=10009
OPENIM_ADMIN_API_PORT=${OPENIM_ADMIN_API_PORT} OPENIM_ADMIN_API_PORT=${OPENIM_ADMIN_API_PORT}
# Port for the node exporter.
# Default: NODE_EXPORTER_PORT=19100
NODE_EXPORTER_PORT=${NODE_EXPORTER_PORT}
# Port for the prometheus.
# Default: PROMETHEUS_PORT=19090
PROMETHEUS_PORT=${PROMETHEUS_PORT}
# Port for the grafana.
# Default: GRAFANA_PORT=13000
GRAFANA_PORT=${GRAFANA_PORT}
# Port for the admin front.
# Default: OPENIM_ADMIN_FRONT_PORT=11002
OPENIM_ADMIN_FRONT_PORT=${OPENIM_ADMIN_FRONT_PORT}
# Port for the alertmanager.
# Default: ALERT_MANAGER_PORT=19093
ALERT_MANAGER_PORT=${ALERT_MANAGER_PORT}
+75 -190
View File
@@ -35,22 +35,35 @@ zookeeper:
username: ${ZOOKEEPER_USERNAME} username: ${ZOOKEEPER_USERNAME}
password: ${ZOOKEEPER_PASSWORD} password: ${ZOOKEEPER_PASSWORD}
###################### Mysql ######################
# MySQL configuration
# Currently, only single machine setup is supported
#
# Maximum number of open connections
# Maximum number of idle connections
# Maximum lifetime in seconds a connection can be reused
# Log level: 1=slient, 2=error, 3=warn, 4=info
# Slow query threshold in milliseconds
mysql:
address: [ ${MYSQL_ADDRESS}:${MYSQL_PORT} ]
username: ${MYSQL_USERNAME}
password: ${MYSQL_PASSWORD}
database: ${MYSQL_DATABASE}
maxOpenConn: ${MYSQL_MAX_OPEN_CONN}
maxIdleConn: ${MYSQL_MAX_IDLE_CONN}
maxLifeTime: ${MYSQL_MAX_LIFETIME}
logLevel: ${MYSQL_LOG_LEVEL}
slowThreshold: ${MYSQL_SLOW_THRESHOLD}
###################### Mongo ###################### ###################### Mongo ######################
# MongoDB configuration # MongoDB configuration
# If uri is not empty, it will be used directly
# If uri is not empty, it will be used directly for the MongoDB connection. #
# This is a complete MongoDB URI string. # MongoDB address for standalone setup, Mongos address for sharded cluster setup
# Example: mongodb://user:password@host1:port1,host2:port2/dbname?options
mongo:
uri: ${MONGO_URI}
# List of MongoDB server addresses.
# Used for constructing the MongoDB URI if 'uri' above is empty.
# For a standalone setup, specify the address of the single server.
# For a sharded cluster, specify the addresses of the Mongos servers.
# Example: [ '172.28.0.1:37017', '172.28.0.2:37017' ]
# Default MongoDB database name # Default MongoDB database name
# Maximum connection pool size # Maximum connection pool size
mongo:
uri: ${MONGO_URI}
address: [ ${MONGO_ADDRESS}:${MONGO_PORT} ] address: [ ${MONGO_ADDRESS}:${MONGO_PORT} ]
database: ${MONGO_DATABASE} database: ${MONGO_DATABASE}
username: ${MONGO_USERNAME} username: ${MONGO_USERNAME}
@@ -145,21 +158,13 @@ object:
accessKeySecret: ${OSS_ACCESS_KEY_SECRET} accessKeySecret: ${OSS_ACCESS_KEY_SECRET}
sessionToken: ${OSS_SESSION_TOKEN} sessionToken: ${OSS_SESSION_TOKEN}
publicRead: ${OSS_PUBLIC_READ} publicRead: ${OSS_PUBLIC_READ}
kodo:
endpoint: "${KODO_ENDPOINT}"
bucket: "${KODO_BUCKET}"
bucketURL: "${KODO_BUCKET_URL}"
accessKeyID: ${KODO_ACCESS_KEY_ID}
accessKeySecret: ${KODO_ACCESS_KEY_SECRET}
sessionToken: ${KODO_SESSION_TOKEN}
publicRead: ${KODO_PUBLIC_READ}
###################### RPC Port Configuration ###################### ###################### RPC Port Configuration ######################
# RPC service ports # RPC service ports
# These ports are passed into the program by the script and are not recommended to modify # These ports are passed into the program by the script and are not recommended to modify
# For launching multiple programs, just fill in multiple ports separated by commas # For launching multiple programs, just fill in multiple ports separated by commas
# For example, [10110, 10111] # For example, [10110, 10111]
rpcPort: rpcPort:
openImUserPort: [ ${OPENIM_USER_PORT} ] openImUserPort: [ ${OPENIM_USER_PORT} ]
openImFriendPort: [ ${OPENIM_FRIEND_PORT} ] openImFriendPort: [ ${OPENIM_FRIEND_PORT} ]
openImMessagePort: [ ${OPENIM_MESSAGE_PORT} ] openImMessagePort: [ ${OPENIM_MESSAGE_PORT} ]
@@ -307,191 +312,71 @@ iosPush:
# Timeout in seconds # Timeout in seconds
# Whether to continue execution if callback fails # Whether to continue execution if callback fails
callback: callback:
url: "" url:
beforeSendSingleMsg: beforeSendSingleMsg:
enable: ${CALLBACK_ENABLE} enable: false
timeout: ${CALLBACK_TIMEOUT} timeout: 5
failedContinue: ${CALLBACK_FAILED_CONTINUE} failedContinue: true
afterSendSingleMsg: afterSendSingleMsg:
enable: ${CALLBACK_ENABLE} enable: false
timeout: ${CALLBACK_TIMEOUT} timeout: 5
failedContinue: ${CALLBACK_FAILED_CONTINUE}
beforeSendGroupMsg: beforeSendGroupMsg:
enable: ${CALLBACK_ENABLE} enable: false
timeout: ${CALLBACK_TIMEOUT} timeout: 5
failedContinue: ${CALLBACK_FAILED_CONTINUE} failedContinue: true
afterSendGroupMsg: afterSendGroupMsg:
enable: ${CALLBACK_ENABLE} enable: false
timeout: ${CALLBACK_TIMEOUT} timeout: 5
failedContinue: ${CALLBACK_FAILED_CONTINUE}
msgModify: msgModify:
enable: ${CALLBACK_ENABLE} enable: false
timeout: ${CALLBACK_TIMEOUT} timeout: 5
failedContinue: ${CALLBACK_FAILED_CONTINUE} failedContinue: true
userOnline: userOnline:
enable: ${CALLBACK_ENABLE} enable: false
timeout: ${CALLBACK_TIMEOUT} timeout: 5
failedContinue: ${CALLBACK_FAILED_CONTINUE}
userOffline: userOffline:
enable: ${CALLBACK_ENABLE} enable: false
timeout: ${CALLBACK_TIMEOUT} timeout: 5
failedContinue: ${CALLBACK_FAILED_CONTINUE}
userKickOff: userKickOff:
enable: ${CALLBACK_ENABLE} enable: false
timeout: ${CALLBACK_TIMEOUT} timeout: 5
failedContinue: ${CALLBACK_FAILED_CONTINUE}
offlinePush: offlinePush:
enable: ${CALLBACK_ENABLE} enable: false
timeout: ${CALLBACK_TIMEOUT} timeout: 5
failedContinue: ${CALLBACK_FAILED_CONTINUE} failedContinue: true
onlinePush: onlinePush:
enable: ${CALLBACK_ENABLE} enable: false
timeout: ${CALLBACK_TIMEOUT} timeout: 5
failedContinue: ${CALLBACK_FAILED_CONTINUE} failedContinue: true
superGroupOnlinePush: superGroupOnlinePush:
enable: ${CALLBACK_ENABLE} enable: false
timeout: ${CALLBACK_TIMEOUT} timeout: 5
failedContinue: ${CALLBACK_FAILED_CONTINUE} failedContinue: true
beforeAddFriend: beforeAddFriend:
enable: ${CALLBACK_ENABLE} enable: false
timeout: ${CALLBACK_TIMEOUT} timeout: 5
failedContinue: ${CALLBACK_FAILED_CONTINUE} failedContinue: true
beforeUpdateUserInfo: beforeUpdateUserInfo:
enable: ${CALLBACK_ENABLE} enable: false
timeout: ${CALLBACK_TIMEOUT} timeout: 5
failedContinue: ${CALLBACK_FAILED_CONTINUE} failedContinue: true
beforeCreateGroup: beforeCreateGroup:
enable: ${CALLBACK_ENABLE} enable: false
timeout: ${CALLBACK_TIMEOUT} timeout: 5
failedContinue: ${CALLBACK_FAILED_CONTINUE} failedContinue: true
afterCreateGroup:
enable: ${CALLBACK_ENABLE}
timeout: ${CALLBACK_TIMEOUT}
failedContinue: ${CALLBACK_FAILED_CONTINUE}
beforeMemberJoinGroup: beforeMemberJoinGroup:
enable: ${CALLBACK_ENABLE} enable: false
timeout: ${CALLBACK_TIMEOUT} timeout: 5
failedContinue: ${CALLBACK_FAILED_CONTINUE} failedContinue: true
beforeSetGroupMemberInfo: beforeSetGroupMemberInfo:
enable: ${CALLBACK_ENABLE} enable: false
timeout: ${CALLBACK_TIMEOUT} timeout: 5
failedContinue: ${CALLBACK_FAILED_CONTINUE} failedContinue: true
afterSetGroupMemberInfo:
enable: ${CALLBACK_ENABLE}
timeout: ${CALLBACK_TIMEOUT}
failedContinue: ${CALLBACK_FAILED_CONTINUE}
setMessageReactionExtensions: setMessageReactionExtensions:
enable: ${CALLBACK_ENABLE} enable: false
timeout: ${CALLBACK_TIMEOUT} timeout: 5
failedContinue: ${CALLBACK_FAILED_CONTINUE} failedContinue: true
quitGroup:
enable: ${CALLBACK_ENABLE}
timeout: ${CALLBACK_TIMEOUT}
failedContinue: ${CALLBACK_FAILED_CONTINUE}
killGroupMember:
enable: ${CALLBACK_ENABLE}
timeout: ${CALLBACK_TIMEOUT}
failedContinue: ${CALLBACK_FAILED_CONTINUE}
dismissGroup:
enable: ${CALLBACK_ENABLE}
timeout: ${CALLBACK_TIMEOUT}
failedContinue: ${CALLBACK_FAILED_CONTINUE}
joinGroup:
enable: ${CALLBACK_ENABLE}
timeout: ${CALLBACK_TIMEOUT}
failedContinue: ${CALLBACK_FAILED_CONTINUE}
groupMsgRead:
enable: ${CALLBACK_ENABLE}
timeout: ${CALLBACK_TIMEOUT}
failedContinue: ${CALLBACK_FAILED_CONTINUE}
singleMsgRead:
enable: ${CALLBACK_ENABLE}
timeout: ${CALLBACK_TIMEOUT}
failedContinue: ${CALLBACK_FAILED_CONTINUE}
updateUserInfo:
enable: ${CALLBACK_ENABLE}
timeout: ${CALLBACK_TIMEOUT}
failedContinue: ${CALLBACK_FAILED_CONTINUE}
beforeUserRegister:
enable: ${CALLBACK_ENABLE}
timeout: ${CALLBACK_TIMEOUT}
failedContinue: ${CALLBACK_FAILED_CONTINUE}
afterUserRegister:
enable: ${CALLBACK_ENABLE}
timeout: ${CALLBACK_TIMEOUT}
failedContinue: ${CALLBACK_FAILED_CONTINUE}
transferGroupOwner:
enable: ${CALLBACK_ENABLE}
timeout: ${CALLBACK_TIMEOUT}
failedContinue: ${CALLBACK_FAILED_CONTINUE}
beforeSetFriendRemark:
enable: ${CALLBACK_ENABLE}
timeout: ${CALLBACK_TIMEOUT}
failedContinue: ${CALLBACK_FAILED_CONTINUE}
afterSetFriendRemark:
enable: ${CALLBACK_ENABLE}
timeout: ${CALLBACK_TIMEOUT}
failedContinue: ${CALLBACK_FAILED_CONTINUE}
afterGroupMsgRead:
enable: ${CALLBACK_ENABLE}
timeout: ${CALLBACK_TIMEOUT}
failedContinue: ${CALLBACK_FAILED_CONTINUE}
afterGroupMsgRevoke:
enable: ${CALLBACK_ENABLE}
timeout: ${CALLBACK_TIMEOUT}
failedContinue: ${CALLBACK_FAILED_CONTINUE}
afterJoinGroup:
enable: ${CALLBACK_ENABLE}
timeout: ${CALLBACK_TIMEOUT}
failedContinue: ${CALLBACK_FAILED_CONTINUE}
beforeInviteUserToGroup:
enable: ${CALLBACK_ENABLE}
timeout: ${CALLBACK_TIMEOUT}
failedContinue: ${CALLBACK_FAILED_CONTINUE}
joinGroupAfter:
enable: ${CALLBACK_ENABLE}
timeout: ${CALLBACK_TIMEOUT}
failedContinue: ${CALLBACK_FAILED_CONTINUE}
setGroupInfoAfter:
enable: ${CALLBACK_ENABLE}
timeout: ${CALLBACK_TIMEOUT}
failedContinue: ${CALLBACK_FAILED_CONTINUE}
setGroupInfoBefore:
enable: ${CALLBACK_ENABLE}
timeout: ${CALLBACK_TIMEOUT}
failedContinue: ${CALLBACK_FAILED_CONTINUE}
revokeMsgAfter:
enable: ${CALLBACK_ENABLE}
timeout: ${CALLBACK_TIMEOUT}
failedContinue: ${CALLBACK_FAILED_CONTINUE}
addBlackBefore:
enable: ${CALLBACK_ENABLE}
timeout: ${CALLBACK_TIMEOUT}
failedContinue: ${CALLBACK_FAILED_CONTINUE}
addFriendAfter:
enable: ${CALLBACK_ENABLE}
timeout: ${CALLBACK_TIMEOUT}
failedContinue: ${CALLBACK_FAILED_CONTINUE}
addFriendAgreeBefore:
enable: ${CALLBACK_ENABLE}
timeout: ${CALLBACK_TIMEOUT}
failedContinue: ${CALLBACK_FAILED_CONTINUE}
deleteFriendAfter:
enable: ${CALLBACK_ENABLE}
timeout: ${CALLBACK_TIMEOUT}
failedContinue: ${CALLBACK_FAILED_CONTINUE}
importFriendsBefore:
enable: ${CALLBACK_ENABLE}
timeout: ${CALLBACK_TIMEOUT}
failedContinue: ${CALLBACK_FAILED_CONTINUE}
importFriendsAfter:
enable: ${CALLBACK_ENABLE}
timeout: ${CALLBACK_TIMEOUT}
failedContinue: ${CALLBACK_FAILED_CONTINUE}
removeBlackAfter:
enable: ${CALLBACK_ENABLE}
timeout: ${CALLBACK_TIMEOUT}
failedContinue: ${CALLBACK_FAILED_CONTINUE}
###################### Prometheus ###################### ###################### Prometheus ######################
# Prometheus configuration for various services # Prometheus configuration for various services
# The number of Prometheus ports per service needs to correspond to rpcPort # The number of Prometheus ports per service needs to correspond to rpcPort
@@ -510,4 +395,4 @@ prometheus:
conversationPrometheusPort: [ ${CONVERSATION_PROM_PORT} ] conversationPrometheusPort: [ ${CONVERSATION_PROM_PORT} ]
rtcPrometheusPort: [ ${RTC_PROM_PORT} ] rtcPrometheusPort: [ ${RTC_PROM_PORT} ]
thirdPrometheusPort: [ ${THIRD_PROM_PORT} ] thirdPrometheusPort: [ ${THIRD_PROM_PORT} ]
messageTransferPrometheusPort: [ ${MSG_TRANSFER_PROM_PORT} ] # List of ports messageTransferPrometheusPort: [ ${MSG_TRANSFER_PROM_PORT} ] # List of ports
-85
View File
@@ -1,85 +0,0 @@
# my global config
global:
scrape_interval: 15s # Set the scrape interval to every 15 seconds. Default is every 1 minute.
evaluation_interval: 15s # Evaluate rules every 15 seconds. The default is every 1 minute.
# scrape_timeout is set to the global default (10s).
# Alertmanager configuration
alerting:
alertmanagers:
- static_configs:
- targets: ['${ALERT_MANAGER_ADDRESS}:${ALERT_MANAGER_PORT}']
# Load rules once and periodically evaluate them according to the global 'evaluation_interval'.
rule_files:
- "instance-down-rules.yml"
# - "first_rules.yml"
# - "second_rules.yml"
# A scrape configuration containing exactly one endpoint to scrape:
# Here it's Prometheus itself.
scrape_configs:
# The job name is added as a label "job='job_name'"" to any timeseries scraped from this config.
# Monitored information captured by prometheus
- job_name: 'node-exporter'
static_configs:
- targets: [ '${NODE_EXPORTER_ADDRESS}:${NODE_EXPORTER_PORT}' ]
labels:
namespace: 'default'
# prometheus fetches application services
- job_name: 'openimserver-openim-api'
static_configs:
- targets: [ '${OPENIM_SERVER_ADDRESS}:${API_PROM_PORT}' ]
labels:
namespace: 'default'
- job_name: 'openimserver-openim-msggateway'
static_configs:
- targets: [ '${OPENIM_SERVER_ADDRESS}:${MSG_GATEWAY_PROM_PORT}' ]
labels:
namespace: 'default'
- job_name: 'openimserver-openim-msgtransfer'
static_configs:
- targets: [ ${MSG_TRANSFER_PROM_ADDRESS_PORT} ]
labels:
namespace: 'default'
- job_name: 'openimserver-openim-push'
static_configs:
- targets: [ '${OPENIM_SERVER_ADDRESS}:${PUSH_PROM_PORT}' ]
labels:
namespace: 'default'
- job_name: 'openimserver-openim-rpc-auth'
static_configs:
- targets: [ '${OPENIM_SERVER_ADDRESS}:${AUTH_PROM_PORT}' ]
labels:
namespace: 'default'
- job_name: 'openimserver-openim-rpc-conversation'
static_configs:
- targets: [ '${OPENIM_SERVER_ADDRESS}:${CONVERSATION_PROM_PORT}' ]
labels:
namespace: 'default'
- job_name: 'openimserver-openim-rpc-friend'
static_configs:
- targets: [ '${OPENIM_SERVER_ADDRESS}:${FRIEND_PROM_PORT}' ]
labels:
namespace: 'default'
- job_name: 'openimserver-openim-rpc-group'
static_configs:
- targets: [ '${OPENIM_SERVER_ADDRESS}:${GROUP_PROM_PORT}' ]
labels:
namespace: 'default'
- job_name: 'openimserver-openim-rpc-msg'
static_configs:
- targets: [ '${OPENIM_SERVER_ADDRESS}:${MESSAGE_PROM_PORT}' ]
labels:
namespace: 'default'
- job_name: 'openimserver-openim-rpc-third'
static_configs:
- targets: [ '${OPENIM_SERVER_ADDRESS}:${THIRD_PROM_PORT}' ]
labels:
namespace: 'default'
- job_name: 'openimserver-openim-rpc-user'
static_configs:
- targets: [ '${OPENIM_SERVER_ADDRESS}:${USER_PROM_PORT}' ]
labels:
namespace: 'default'
+74 -117
View File
@@ -7,181 +7,138 @@ networks:
ipam: ipam:
driver: default driver: default
config: config:
- subnet: '${DOCKER_BRIDGE_SUBNET:-172.28.0.0/16}' - subnet: '${DOCKER_BRIDGE_SUBNET}'
gateway: '${DOCKER_BRIDGE_GATEWAY:-172.28.0.1}' gateway: '${DOCKER_BRIDGE_GATEWAY}'
services: services:
mongodb: mysql:
image: mongo:${MONGODB_IMAGE_VERSION-6.0.2} image: mysql:5.7
ports: ports:
- "${MONGO_PORT:-37017}:27017" - "${MYSQL_PORT}:3306"
container_name: mongo container_name: mysql
command: --wiredTigerCacheSizeGB 1 --auth
volumes: volumes:
- "${DATA_DIR:-./}/components/mongodb/data/db:/data/db" - "${DATA_DIR}/components/mysql/data:/var/lib/mysql"
- "${DATA_DIR:-./}/components/mongodb/data/logs:/data/logs" - "/etc/localtime:/etc/localtime"
- "${DATA_DIR:-./}/components/mongodb/data/conf:/etc/mongo"
- ./scripts/mongo-init.sh:/docker-entrypoint-initdb.d/mongo-init.sh:ro
environment: environment:
- TZ=Asia/Shanghai MYSQL_ROOT_PASSWORD: "${MYSQL_PASSWORD}"
- wiredTigerCacheSizeGB=1
- MONGO_INITDB_ROOT_USERNAME=${MONGO_USERNAME:-root}
- MONGO_INITDB_ROOT_PASSWORD=${MONGO_PASSWORD:-openIM123}
- MONGO_INITDB_DATABASE=${MONGO_DATABASE:-openIM_v3}
restart: always restart: always
networks: networks:
server: server:
ipv4_address: ${MONGO_NETWORK_ADDRESS:-172.28.0.2} ipv4_address: ${MYSQL_NETWORK_ADDRESS}
mongodb:
image: mongo:6.0.2
ports:
- "${MONGO_PORT}:27017"
container_name: mongo
command: --wiredTigerCacheSizeGB 1 --auth
volumes:
- "${DATA_DIR}/components/mongodb/data/db:/data/db"
- "${DATA_DIR}/components/mongodb/data/logs:/data/logs"
- "${DATA_DIR}/components/mongodb/data/conf:/etc/mongo"
- ./scripts/mongo-init.sh:/docker-entrypoint-initdb.d/mongo-init.sh:ro"
environment:
- TZ=Asia/Shanghai
- wiredTigerCacheSizeGB=1
- MONGO_INITDB_ROOT_USERNAME=${MONGO_USERNAME}
- MONGO_INITDB_ROOT_PASSWORD=${MONGO_PASSWORD}
- MONGO_INITDB_DATABASE=${MONGO_DATABASE}
restart: always
networks:
server:
ipv4_address: ${MONGO_NETWORK_ADDRESS}
redis: redis:
image: redis:${REDIS_IMAGE_VERSION:-7.0.0} image: redis:7.0.0
container_name: redis container_name: redis
ports: ports:
- "${REDIS_PORT:-16379}:6379" - "${REDIS_PORT}:6379"
volumes: volumes:
- "${DATA_DIR:-./}/components/redis/data:/data" - "${DATA_DIR}/components/redis/data:/data"
- "${DATA_DIR:-./}/components/redis/config/redis.conf:/usr/local/redis/config/redis.conf" - "${DATA_DIR}/components/redis/config/redis.conf:/usr/local/redis/config/redis.conf"
environment: environment:
TZ: Asia/Shanghai TZ: Asia/Shanghai
restart: always restart: always
sysctls: sysctls:
net.core.somaxconn: 1024 net.core.somaxconn: 1024
command: redis-server --requirepass ${REDIS_PASSWORD:-openIM123} --appendonly yes command: redis-server --requirepass ${REDIS_PASSWORD} --appendonly yes
networks: networks:
server: server:
ipv4_address: ${REDIS_NETWORK_ADDRESS:-172.28.0.3} ipv4_address: ${REDIS_NETWORK_ADDRESS}
zookeeper: zookeeper:
image: bitnami/zookeeper:${ZOOKEEPER_IMAGE_VERSION:-3.8} image: bitnami/zookeeper:3.8
container_name: zookeeper container_name: zookeeper
ports: ports:
- "${ZOOKEEPER_PORT:-12181}:2181" - "${ZOOKEEPER_PORT}:2181"
volumes: volumes:
- "/etc/localtime:/etc/localtime" - "/etc/localtime:/etc/localtime"
environment: environment:
- ALLOW_ANONYMOUS_LOGIN=yes - ALLOW_ANONYMOUS_LOGIN=yes
- TZ="Asia/Shanghai" - TZ="Asia/Shanghai"
restart: always restart: always
networks: networks:
server: server:
ipv4_address: ${ZOOKEEPER_NETWORK_ADDRESS:-172.28.0.5} ipv4_address: ${ZOOKEEPER_NETWORK_ADDRESS}
kafka: kafka:
image: 'bitnami/kafka:${KAFKA_IMAGE_VERSION:-3.5.1}' image: 'bitnami/kafka:3.5.1'
container_name: kafka container_name: kafka
user: root
restart: always restart: always
user: ${KAFKA_USER:-root}
ports: ports:
- "${KAFKA_PORT:-19094}:9094" - "${KAFKA_PORT}:9094"
volumes: volumes:
- ./scripts/create-topic.sh:/opt/bitnami/kafka/create-topic.sh - ./scripts/create-topic.sh:/opt/bitnami/kafka/create-topic.sh
- "${DATA_DIR:-./}/components/kafka:/bitnami/kafka" - ${DATA_DIR}/components/kafka:/bitnami/kafka
command: > command: >
bash -c "/opt/bitnami/scripts/kafka/run.sh & sleep 5; /opt/bitnami/kafka/create-topic.sh; wait" bash -c "
/opt/bitnami/scripts/kafka/run.sh & sleep 5; /opt/bitnami/kafka/create-topic.sh; wait
"
environment: environment:
- TZ=Asia/Shanghai - TZ=Asia/Shanghai
- KAFKA_CFG_NODE_ID=0 - KAFKA_CFG_NODE_ID=0
- KAFKA_CFG_PROCESS_ROLES=controller,broker - KAFKA_CFG_PROCESS_ROLES=controller,broker
- KAFKA_CFG_CONTROLLER_QUORUM_VOTERS=0@<your_host>:9093 - KAFKA_CFG_CONTROLLER_QUORUM_VOTERS=0@<your_host>:9093
- KAFKA_CFG_LISTENERS=PLAINTEXT://:9092,CONTROLLER://:9093,EXTERNAL://:9094 - KAFKA_CFG_LISTENERS=PLAINTEXT://:9092,CONTROLLER://:9093,EXTERNAL://:9094
- KAFKA_CFG_ADVERTISED_LISTENERS=PLAINTEXT://kafka:9092,EXTERNAL://${DOCKER_BRIDGE_GATEWAY:-172.28.0.1}:${KAFKA_PORT:-19094} - KAFKA_CFG_ADVERTISED_LISTENERS=PLAINTEXT://kafka:9092,EXTERNAL://${DOCKER_BRIDGE_GATEWAY}:${KAFKA_PORT}
- KAFKA_CFG_LISTENER_SECURITY_PROTOCOL_MAP=CONTROLLER:PLAINTEXT,EXTERNAL:PLAINTEXT,PLAINTEXT:PLAINTEXT - KAFKA_CFG_LISTENER_SECURITY_PROTOCOL_MAP=CONTROLLER:PLAINTEXT,EXTERNAL:PLAINTEXT,PLAINTEXT:PLAINTEXT
- KAFKA_CFG_CONTROLLER_LISTENER_NAMES=CONTROLLER - KAFKA_CFG_CONTROLLER_LISTENER_NAMES=CONTROLLER
networks: networks:
server: server:
ipv4_address: ${KAFKA_NETWORK_ADDRESS:-172.28.0.4} ipv4_address: ${KAFKA_NETWORK_ADDRESS}
minio: minio:
image: minio/minio:${MINIO_IMAGE_VERSION:-latest} image: minio/minio
ports: ports:
- "${MINIO_PORT:-10005}:9000" - "${MINIO_PORT}:9000"
- "9090:9090" - "9090:9090"
container_name: minio container_name: minio
volumes: volumes:
- "${DATA_DIR:-./}/components/mnt/data:/data" - "${DATA_DIR}/components/mnt/data:/data"
- "${DATA_DIR:-./}/components/mnt/config:/root/.minio" - "${DATA_DIR}/components/mnt/config:/root/.minio"
environment: environment:
MINIO_ROOT_USER: "${MINIO_ACCESS_KEY:-root}" MINIO_ROOT_USER: "${MINIO_ACCESS_KEY}"
MINIO_ROOT_PASSWORD: "${MINIO_SECRET_KEY:-openIM123}" MINIO_ROOT_PASSWORD: "${MINIO_SECRET_KEY}"
restart: always restart: always
command: minio server /data --console-address ':9090' command: minio server /data --console-address ':9090'
networks: networks:
server: server:
ipv4_address: ${MINIO_NETWORK_ADDRESS:-172.28.0.6} ipv4_address: ${MINIO_NETWORK_ADDRESS}
openim-web: openim-web:
image: ${IMAGE_REGISTRY:-ghcr.io/openimsdk}/openim-web:${OPENIM_WEB_IMAGE_VERSION:-latest} # image: ghcr.io/openimsdk/openim-web:latest
# image: registry.cn-hangzhou.aliyuncs.com/openimsdk/openim-web:latest
# image: openim/openim-web:latest
image: ${IMAGE_REGISTRY}/openim-web:latest
container_name: openim-web container_name: openim-web
environment: environment:
- OPENIM_WEB_DIST_PATH=${OPENIM_WEB_DIST_PATH:-/app/dist} - OPENIM_WEB_DIST_PATH=${OPENIM_WEB_DIST_PATH}
- OPENIM_WEB_PORT=${OPENIM_WEB_PORT:-11001} - OPENIM_WEB_PORT=${OPENIM_WEB_PORT}
restart: always restart: always
ports: ports:
- "${OPENIM_WEB_PORT:-11001}:11001" - "${OPENIM_WEB_PORT}:11001"
networks: networks:
server: server:
ipv4_address: ${OPENIM_WEB_NETWORK_ADDRESS:-172.28.0.7} ipv4_address: ${OPENIM_WEB_NETWORK_ADDRESS}
# Uncomment and configure the following services as needed
# openim-admin:
# image: ${IMAGE_REGISTRY:-ghcr.io/openimsdk}/openim-admin-front:v3.4.0
# container_name: openim-admin
# restart: always
# ports:
# - "${OPENIM_ADMIN_FRONT_PORT:-11002}:80"
# networks:
# server:
# ipv4_address: ${OPENIM_ADMIN_FRONT_NETWORK_ADDRESS:-172.28.0.13}
# prometheus:
# image: prom/prometheus
# container_name: prometheus
# hostname: prometheus
# restart: always
# volumes:
# - ./config/prometheus.yml:/etc/prometheus/prometheus.yml
# - ./config/instance-down-rules.yml:/etc/prometheus/instance-down-rules.yml
# ports:
# - "${PROMETHEUS_PORT:-19090}:9090"
# networks:
# server:
# ipv4_address: ${PROMETHEUS_NETWORK_ADDRESS:-172.28.0.10}
# alertmanager:
# image: prom/alertmanager
# container_name: alertmanager
# hostname: alertmanager
# restart: always
# volumes:
# - ./config/alertmanager.yml:/etc/alertmanager/alertmanager.yml
# - ./config/email.tmpl:/etc/alertmanager/email.tmpl
# ports:
# - "${ALERT_MANAGER_PORT:-19093}:9093"
# networks:
# server:
# ipv4_address: ${ALERT_MANAGER_NETWORK_ADDRESS:-172.28.0.14}
# grafana:
# image: grafana/grafana
# container_name: grafana
# hostname: grafana
# user: root
# restart: always
# ports:
# - "${GRAFANA_PORT:-13000}:3000"
# volumes:
# - ${DATA_DIR:-./}/components/grafana:/var/lib/grafana
# networks:
# server:
# ipv4_address: ${GRAFANA_NETWORK_ADDRESS:-172.28.0.11}
# node-exporter:
# image: quay.io/prometheus/node-exporter
# container_name: node-exporter
# hostname: node-exporter
# restart: always
# ports:
# - "${NODE_EXPORTER_PORT:-19100}:9100"
# networks:
# server:
# ipv4_address: ${NODE_EXPORTER_NETWORK_ADDRESS:-172.28.0.12}
+7 -7
View File
@@ -2,28 +2,28 @@
# Each line is a file pattern followed by one or more owners. # Each line is a file pattern followed by one or more owners.
# README files # README files
README.md @openimsdk/openim @cubxxw @openimsdk/bot @Bloomingg @FGadvancer @skiffer-git @rfyiamcool @withchao README.md @openimsdk/openim @cubxxw @openimsdk/bot @Bloomingg @FGadvancer @skiffer-git @wangchuxiao-dev @withchao
# Contributing guidelines # Contributing guidelines
CONTRIBUTING.md @cubxxw @openimsdk/bot @Bloomingg @FGadvancer @skiffer-git @rfyiamcool @withchao CONTRIBUTING.md @cubxxw @openimsdk/bot @Bloomingg @FGadvancer @skiffer-git @wangchuxiao-dev @withchao
# License files # License files
LICENSE @cubxxw @openimsdk/bot @Bloomingg @FGadvancer @skiffer-git @rfyiamcool @withchao LICENSE @cubxxw @openimsdk/bot @Bloomingg @FGadvancer @skiffer-git @wangchuxiao-dev @withchao
# Makefile # Makefile
Makefile @cubxxw @openimsdk/bot @Bloomingg @FGadvancer @skiffer-git @rfyiamcool @withchao Makefile @cubxxw @openimsdk/bot @Bloomingg @FGadvancer @skiffer-git @wangchuxiao-dev @withchao
# These owners will be the default owners for everything in # These owners will be the default owners for everything in
# the repo. Unless a later match takes precedence, # the repo. Unless a later match takes precedence,
# @cubxxw and @openimsdk/bot will be requested for # @cubxxw and @openimsdk/bot will be requested for
# review when someone opens a pull request. # review when someone opens a pull request.
* @openimsdk/openim @cubxxw @openimsdk/bot @Bloomingg @FGadvancer @skiffer-git @rfyiamcool @withchao * @openimsdk/openim @cubxxw @openimsdk/bot @Bloomingg @FGadvancer @skiffer-git @wangchuxiao-dev @withchao
# Order is important; the last matching pattern takes the most # Order is important; the last matching pattern takes the most
# precedence. When someone opens a pull request that only # precedence. When someone opens a pull request that only
# modifies JS files, only @js-owner and not the global # modifies JS files, only @js-owner and not the global
# owner(s) will be requested for a review. # owner(s) will be requested for a review.
*.js @cubxxw @openimsdk/bot @Bloomingg @FGadvancer @skiffer-git @rfyiamcool @withchao *.js @cubxxw @openimsdk/bot @Bloomingg @FGadvancer @skiffer-git @wangchuxiao-dev @withchao
# You can also use email addresses if you prefer. They'll be # You can also use email addresses if you prefer. They'll be
# used to look up users just like we do for commit author # used to look up users just like we do for commit author
@@ -35,7 +35,7 @@ Makefile @cubxxw @openimsdk/bot @Bloomingg @FGadvancer @skiffer-git @rfyiam
# be identified in the format @org/team-name. Teams must have # be identified in the format @org/team-name. Teams must have
# explicit write access to the repository. In this example, # explicit write access to the repository. In this example,
# the OpenIMSDK team in the github organization owns all .txt files. # the OpenIMSDK team in the github organization owns all .txt files.
*.txt @cubxxw @openimsdk/bot @Bloomingg @FGadvancer @skiffer-git @rfyiamcool @withchao *.txt @cubxxw @openimsdk/bot @Bloomingg @FGadvancer @skiffer-git @wangchuxiao-dev @withchao
# The `docs/*` pattern will match files like # The `docs/*` pattern will match files like
# `docs/getting-started.md` but not further nested files like # `docs/getting-started.md` but not further nested files like
+1 -1
View File
@@ -11,7 +11,7 @@ OpenIM, an intricate project, requires a robust logging mechanism to diagnose is
1. **Initialization**: The system begins by determining the verbosity level through the `OPENIM_VERBOSE` variable. If it's not set, a default value of 5 is assigned. This verbosity level dictates the depth of the log details. 1. **Initialization**: The system begins by determining the verbosity level through the `OPENIM_VERBOSE` variable. If it's not set, a default value of 5 is assigned. This verbosity level dictates the depth of the log details.
2. **Log File Setup**: Logs are stored in the directory specified by `OPENIM_OUTPUT`. If this variable isn't explicitly set, it defaults to the `_output` directory relative to the script location. Each log file is named based on the date to facilitate easy identification. 2. **Log File Setup**: Logs are stored in the directory specified by `OPENIM_OUTPUT`. If this variable isn't explicitly set, it defaults to the `_output` directory relative to the script location. Each log file is named based on the date to facilitate easy identification.
3. **Logging Function**: The `echo_log()` function plays a pivotal role by writing messages to both the console (stdout) and the log file. 3. **Logging Function**: The `echo_log()` function plays a pivotal role by writing messages to both the console (stdout) and the log file.
4. **Logging to a file**: The `echo_log()` function writes to the log file by appending the message to the file. It also adds a timestamp to the message. path: `_output/logs/*`, Enable logging by default. Set to false to disable. If you wish to turn off output to log files set `export ENABLE_LOGGING=flase`. 4. **Logging to a file**: The `echo_log()` function writes to the log file by appending the message to the file. It also adds a timestamp to the message. path: `_output/logs/*`, Enable logging by default. Set to false to disable. If you wish to turn off output to log files set `ENABLE_LOGGING=flase`.
### Key Functions & Their Usages ### Key Functions & Their Usages
+19 -22
View File
@@ -37,7 +37,6 @@
* 2.20. [Prometheus Configuration](#PrometheusConfiguration-1) * 2.20. [Prometheus Configuration](#PrometheusConfiguration-1)
* 2.20.1. [General Configuration](#GeneralConfiguration) * 2.20.1. [General Configuration](#GeneralConfiguration)
* 2.20.2. [Service-Specific Prometheus Ports](#Service-SpecificPrometheusPorts) * 2.20.2. [Service-Specific Prometheus Ports](#Service-SpecificPrometheusPorts)
* 2.21. [Qiniu Cloud Kodo Configuration](#QiniuCloudKODOConfiguration)
## 0. <a name='TableofContents'></a>OpenIM Config File ## 0. <a name='TableofContents'></a>OpenIM Config File
@@ -151,7 +150,7 @@ For convenience, configuration through modifying environment variables is recomm
+ **Description**: API address. + **Description**: API address.
+ **Note**: If the server has an external IP, it will be automatically obtained. For internal networks, set this variable to the IP serving internally. + **Note**: If the server has an external IP, it will be automatically obtained. For internal networks, set this variable to the IP serving internally.
```bash ```
export API_URL="http://ip:10002" export API_URL="http://ip:10002"
``` ```
@@ -296,6 +295,19 @@ Feel free to explore the MinIO documentation for more advanced configurations an
| `ZOOKEEPER_USERNAME` | `""` | Username for Zookeeper. | | `ZOOKEEPER_USERNAME` | `""` | Username for Zookeeper. |
| `ZOOKEEPER_PASSWORD` | `""` | Password for Zookeeper. | | `ZOOKEEPER_PASSWORD` | `""` | Password for Zookeeper. |
### 2.6. <a name='MySQLConfiguration'></a>MySQL Configuration
**Description**: Configuration for MySQL, including port, address, and credentials.
| Parameter | Example Value | Description |
| ---------------- | ------------------------ | ------------------- |
| `MYSQL_PORT` | `"13306"` | Port for MySQL. |
| `MYSQL_ADDRESS` | Docker Bridge Gateway IP | Address for MySQL. |
| `MYSQL_USERNAME` | User-defined | Username for MySQL. |
| `MYSQL_PASSWORD` | User-defined | Password for MySQL. |
Note: The configurations for other services (e.g., MONGO, REDIS, KAFKA, etc.) follow a similar pattern to MySQL and can be documented in a similar manner.
### 2.7. <a name='MongoDBConfiguration'></a>MongoDB Configuration ### 2.7. <a name='MongoDBConfiguration'></a>MongoDB Configuration
This section involves setting up MongoDB, including its port, address, and credentials. This section involves setting up MongoDB, including its port, address, and credentials.
@@ -400,7 +412,7 @@ Configuration for Grafana, including its port and address.
| Parameter | Example Value | Description | | Parameter | Example Value | Description |
| --------------- | -------------------------- | --------------------- | | --------------- | -------------------------- | --------------------- |
| GRAFANA_PORT | "13000" | Port used by Grafana. | | GRAFANA_PORT | "3000" | Port used by Grafana. |
| GRAFANA_ADDRESS | "${DOCKER_BRIDGE_GATEWAY}" | Address for Grafana. | | GRAFANA_ADDRESS | "${DOCKER_BRIDGE_GATEWAY}" | Address for Grafana. |
### 2.16. <a name='RPCPortConfigurationVariables'></a>RPC Port Configuration Variables ### 2.16. <a name='RPCPortConfigurationVariables'></a>RPC Port Configuration Variables
@@ -454,7 +466,7 @@ This section involves configuring the log settings, including storage location,
This section involves setting up additional configuration variables for Websocket, Push Notifications, and Chat. This section involves setting up additional configuration variables for Websocket, Push Notifications, and Chat.
| Parameter | Example Value | Description | | Parameter | Example Value | Description |
|-------------------------|-------------------|------------------------------------| | ----------------------- | ----------------- | ---------------------------------- |
| WEBSOCKET_MAX_CONN_NUM | "100000" | Maximum Websocket connections | | WEBSOCKET_MAX_CONN_NUM | "100000" | Maximum Websocket connections |
| WEBSOCKET_MAX_MSG_LEN | "4096" | Maximum Websocket message length | | WEBSOCKET_MAX_MSG_LEN | "4096" | Maximum Websocket message length |
| WEBSOCKET_TIMEOUT | "10" | Websocket timeout | | WEBSOCKET_TIMEOUT | "10" | Websocket timeout |
@@ -488,9 +500,9 @@ This section involves setting up additional configuration variables for Websocke
| TOKEN_EXPIRE | "90" | Token Expiry Time | | TOKEN_EXPIRE | "90" | Token Expiry Time |
| FRIEND_VERIFY | "false" | Friend Verification Enable | | FRIEND_VERIFY | "false" | Friend Verification Enable |
| IOS_PUSH_SOUND | "xxx" | iOS | | IOS_PUSH_SOUND | "xxx" | iOS |
| CALLBACK_ENABLE | "false" | Enable callback |
| CALLBACK_TIMEOUT | "5" | Maximum timeout for callback call |
| CALLBACK_FAILED_CONTINUE| "true" | fails to continue to the next step |
### 2.20. <a name='PrometheusConfiguration-1'></a>Prometheus Configuration ### 2.20. <a name='PrometheusConfiguration-1'></a>Prometheus Configuration
This section involves configuring Prometheus, including enabling/disabling it and setting up ports for various services. This section involves configuring Prometheus, including enabling/disabling it and setting up ports for various services.
@@ -516,18 +528,3 @@ This section involves configuring Prometheus, including enabling/disabling it an
| RTC Service | `RTC_PROM_PORT` | '21300' | Prometheus port for the RTC service. | | RTC Service | `RTC_PROM_PORT` | '21300' | Prometheus port for the RTC service. |
| Third Service | `THIRD_PROM_PORT` | '21301' | Prometheus port for the Third service. | | Third Service | `THIRD_PROM_PORT` | '21301' | Prometheus port for the Third service. |
| Message Transfer Service | `MSG_TRANSFER_PROM_PORT` | '21400, 21401, 21402, 21403' | Prometheus ports for the Message Transfer service. | | Message Transfer Service | `MSG_TRANSFER_PROM_PORT` | '21400, 21401, 21402, 21403' | Prometheus ports for the Message Transfer service. |
### 2.21. <a name='QiniuCloudKODOConfiguration'></a>Qiniu Cloud Kodo Configuration
This section involves setting up Qiniu Cloud Kodo, including its endpoint, bucket name, and credentials.
| Parameter | Example Value | Description |
| --------------------- | ------------------------------------------------------------ | ---------------------------------------- |
| KODO_ENDPOINT | "[http://s3.cn-east-1.qiniucs.com](http://s3.cn-east-1.qiniucs.com)" | Endpoint URL for Qiniu Cloud Kodo. |
| KODO_BUCKET | "demo-9999999" | Bucket name for Qiniu Cloud Kodo. |
| KODO_BUCKET_URL | "[http://your.domain.com](http://your.domain.com)" | Bucket URL for Qiniu Cloud Kodo. |
| KODO_ACCESS_KEY_ID | [User Defined] | Access key ID for Qiniu Cloud Kodo. |
| KODO_ACCESS_KEY_SECRET | [User Defined] | Access key secret for Qiniu Cloud Kodo. |
| KODO_SESSION_TOKEN | [User Defined] | Session token for Qiniu Cloud Kodo. |
| KODO_PUBLIC_READ | "false" | Public read access. |
-323
View File
@@ -1,323 +0,0 @@
# Deployment and Design of OpenIM's Management Backend and Monitoring
<!-- vscode-markdown-toc -->
* 1. [Source Code & Docker](#SourceCodeDocker)
* 1.1. [Deployment](#Deployment)
* 1.2. [Configuration](#Configuration)
* 1.3. [Monitoring Running in Docker Guide](#MonitoringRunninginDockerGuide)
* 1.3.1. [Introduction](#Introduction)
* 1.3.2. [Prerequisites](#Prerequisites)
* 1.3.3. [Step 1: Clone the Repository](#Step1:ClonetheRepository)
* 1.3.4. [Step 2: Start Docker Compose](#Step2:StartDockerCompose)
* 1.3.5. [Step 3: Use the OpenIM Web Interface](#Step3:UsetheOpenIMWebInterface)
* 1.3.6. [Running Effect](#RunningEffect)
* 1.3.7. [Step 4: Access the Admin Panel](#Step4:AccesstheAdminPanel)
* 1.3.8. [Step 5: Access the Monitoring Interface](#Step5:AccesstheMonitoringInterface)
* 1.3.9. [Next Steps](#NextSteps)
* 1.3.10. [Troubleshooting](#Troubleshooting)
* 2. [Kubernetes](#Kubernetes)
* 2.1. [Middleware Monitoring](#MiddlewareMonitoring)
* 2.2. [Custom OpenIM Metrics](#CustomOpenIMMetrics)
* 2.3. [Node Exporter](#NodeExporter)
* 3. [Setting Up and Configuring AlertManager Using Environment Variables and `make init`](#SettingUpandConfiguringAlertManagerUsingEnvironmentVariablesandmakeinit)
* 3.1. [Introduction](#Introduction-1)
* 3.2. [Prerequisites](#Prerequisites-1)
* 3.3. [Configuration Steps](#ConfigurationSteps)
* 3.3.1. [Exporting Environment Variables](#ExportingEnvironmentVariables)
* 3.3.2. [Initializing AlertManager](#InitializingAlertManager)
* 3.3.3. [Key Configuration Fields](#KeyConfigurationFields)
* 3.3.4. [Configuring SMTP Authentication Password](#ConfiguringSMTPAuthenticationPassword)
* 3.3.5. [Useful Links for Common Email Servers](#UsefulLinksforCommonEmailServers)
* 3.4. [Conclusion](#Conclusion)
<!-- vscode-markdown-toc-config
numbering=true
autoSave=true
/vscode-markdown-toc-config -->
<!-- /vscode-markdown-toc -->
OpenIM offers various flexible deployment options to suit different environments and requirements. Here is a simplified and optimized description of these deployment options:
1. Source Code Deployment:
+ **Regular Source Code Deployment**: Deployment using the `nohup` method. This is a basic deployment method suitable for development and testing environments. For details, refer to the [Regular Source Code Deployment Guide](https://docs.openim.io/).
+ **Production-Level Deployment**: Deployment using the `system` method, more suitable for production environments. This method provides higher stability and reliability. For details, refer to the [Production-Level Deployment Guide](https://docs.openim.io/guides/gettingStarted/install-openim-linux-system).
2. Cluster Deployment:
+ **Kubernetes Deployment**: Provides two deployment methods, including deployment through Helm and sealos. This is suitable for environments that require high availability and scalability. Specific methods can be found in the [Kubernetes Deployment Guide](https://docs.openim.io/guides/gettingStarted/k8s-deployment).
3. Docker Deployment:
+ **Regular Docker Deployment**: Suitable for quick deployments and small projects. For detailed information, refer to the [Docker Deployment Guide](https://docs.openim.io/guides/gettingStarted/dockerCompose).
+ **Docker Compose Deployment**: Provides more convenient service management and configuration, suitable for complex multi-container applications.
Next, we will introduce the specific steps, monitoring, and management backend configuration for each of these deployment methods, as well as usage tips to help you choose the most suitable deployment option according to your needs.
## 1. <a name='SourceCodeDocker'></a>Source Code & Docker
### 1.1. <a name='Deployment'></a>Deployment
OpenIM deploys openim-server and openim-chat from source code, while other components are deployed via Docker.
For Docker deployment, you can deploy all components with a single command using the [openimsdk/openim-docker](https://github.com/openimsdk/openim-docker) repository. The deployment configuration can be found in the [environment.sh](https://github.com/openimsdk/open-im-server/blob/main/scripts/install/environment.sh) document, which provides information on how to learn and familiarize yourself with various environment variables.
For Prometheus, it is not enabled by default. To enable it, set the environment variable before executing `make init`:
```bash
export PROMETHEUS_ENABLE=true # Default is false
```
Then, execute:
```bash
make init
docker compose up -d
```
### 1.2. <a name='Configuration'></a>Configuration
To configure Prometheus data sources in Grafana, follow these steps:
1. **Log in to Grafana**: First, open your web browser and access the Grafana URL. If you haven't changed the port, the address is typically [http://localhost:13000](http://localhost:13000/).
2. **Log in with default credentials**: Grafana's default username and password are both `admin`. You will be prompted to change the password on your first login.
3. **Access Data Sources Settings**:
+ In the left menu of Grafana, look for and click the "gear" icon representing "Configuration."
+ In the configuration menu, select "Data Sources."
4. **Add a New Data Source**:
+ On the Data Sources page, click the "Add data source" button.
+ In the list, find and select "Prometheus."
![image-20231114175117374](http://sm.nsddd.top/sm202311141751692.png)
Click `Add New connection` to add more data sources, such as Loki (responsible for log storage and query processing).
5. **Configure the Prometheus Data Source**:
+ On the configuration page, fill in the details of the Prometheus server. This typically includes the URL of the Prometheus service (e.g., if Prometheus is running on the same machine as OpenIM, the URL might be `http://172.28.0.1:19090`, with the address matching the `DOCKER_BRIDGE_GATEWAY` variable address). OpenIM and the components are linked via a gateway. The default port used by OpenIM is `19090`.
+ Adjust other settings as needed, such as authentication and TLS settings.
![image-20231114180351923](http://sm.nsddd.top/sm202311141803076.png)
6. **Save and Test**:
+ After completing the configuration, click the "Save & Test" button to ensure that Grafana can successfully connect to Prometheus.
**Importing Dashboards in Grafana**
Importing Grafana Dashboards is a straightforward process and is applicable to OpenIM Server application services and Node Exporter. Here are detailed steps and necessary considerations:
**Key Metrics Overview and Deployment Steps**
To monitor OpenIM in Grafana, you need to focus on three categories of key metrics, each with its specific deployment and configuration steps:
1. **OpenIM Metrics (`prometheus-dashboard.yaml`)**:
+ **Configuration File Path**: Located at `config/prometheus-dashboard.yaml`.
+ **Enabling Monitoring**: Set the environment variable `export PROMETHEUS_ENABLE=true` to enable Prometheus monitoring.
+ **More Information**: Refer to the [OpenIM Configuration Guide](https://docs.openim.io/configurations/prometheus-integration).
2. **Node Exporter**:
+ **Container Deployment**: Deploy the `quay.io/prometheus/node-exporter` container for node monitoring.
+ **Get Dashboard**: Access the [Node Exporter Full Feature Dashboard](https://grafana.com/grafana/dashboards/1860-node-exporter-full/) and import it using YAML file download or ID import.
+ **Deployment Guide**: Refer to the [Node Exporter Deployment Documentation](https://prometheus.io/docs/guides/node-exporter/).
3. **Middleware Metrics**: Each middleware requires specific steps and configurations to enable monitoring. Here is a list of common middleware and links to their respective setup guides:
+ MySQL:
+ **Configuration**: Ensure MySQL has performance monitoring enabled.
+ **Link**: Refer to the [MySQL Monitoring Configuration Guide](https://grafana.com/docs/grafana/latest/datasources/mysql/).
+ Redis:
+ **Configuration**: Configure Redis to allow monitoring data export.
+ **Link**: Refer to the [Redis Monitoring Guide](https://grafana.com/docs/grafana/latest/datasources/redis/).
+ MongoDB:
+ **Configuration**: Set up monitoring metrics for MongoDB.
+ **Link**: Refer to the [MongoDB Monitoring Guide](https://grafana.com/grafana/plugins/grafana-mongodb-datasource/).
+ Kafka:
+ **Configuration**: Integrate Kafka with Prometheus monitoring.
+ **Link**: Refer to the [Kafka Monitoring Guide](https://grafana.com/grafana/plugins/grafana-kafka-datasource/).
+ Zookeeper:
+ **Configuration**: Ensure Zookeeper can be monitored by Prometheus.
+ **Link**: Refer to the [Zookeeper Monitoring Configuration](https://grafana.com/docs/grafana/latest/datasources/zookeeper/).
**Importing Steps**:
1. Access the Dashboard Import Interface:
+ Click the `+` icon on the left menu or in the top right corner of Grafana, then select "Create."
+ Choose "Import" to access the dashboard import interface.
2. **Perform Dashboard Import**:
+ **Upload via File**: Directly upload your YAML file.
+ **Paste Content**: Open the YAML file, copy its content, and paste it into the import interface.
+ **Import via Grafana.com Dashboard**: Visit [Grafana Dashboards](https://grafana.com/grafana/dashboards/), search for the desired dashboard, and import it using its ID.
3. **Configure the Dashboard**:
+ Select the appropriate data source, such as the previously configured Prometheus.
+ Adjust other settings, such as the dashboard name or folder.
4. **Save and View the Dashboard**:
+ After configuring, click "Import" to complete the process.
+ Immediately view the new dashboard after successful import.
**Graph Examples:**
![image-20231114194451673](http://sm.nsddd.top/sm202311141944953.png)
### 1.3. <a name='MonitoringRunninginDockerGuide'></a>Monitoring Running in Docker Guide
#### 1.3.1. <a name='Introduction'></a>Introduction
This guide provides the steps to run OpenIM using Docker. OpenIM is an open-source instant messaging solution that can be quickly deployed using Docker. For more information, please refer to the [OpenIM Docker GitHub](https://github.com/openimsdk/openim-docker).
#### 1.3.2. <a name='Prerequisites'></a>Prerequisites
+ Ensure that Docker and Docker Compose are installed.
+ Basic understanding of Docker and containerization technology.
#### 1.3.3. <a name='Step1:ClonetheRepository'></a>Step 1: Clone the Repository
First, clone the OpenIM Docker repository:
```bash
git clone https://github.com/openimsdk/openim-docker.git
```
Navigate to the repository directory and check the `README` file for more information and configuration options.
#### 1.3.4. <a name='Step2:StartDockerCompose'></a>Step 2: Start Docker Compose
In the repository directory, run the following command to start the service:
```bash
docker-compose up -d
```
This will download the required Docker images and start the OpenIM service.
#### 1.3.5. <a name='Step3:UsetheOpenIMWebInterface'></a>Step 3: Use the OpenIM Web Interface
+ Open a browser in private mode and access [OpenIM Web](http://localhost:11001/).
+ Register two users and try adding friends.
+ Test sending messages and pictures.
#### 1.3.6. <a name='RunningEffect'></a>Running Effect
![image-20231115100811208](http://sm.nsddd.top/sm202311151008639.png)
#### 1.3.7. <a name='Step4:AccesstheAdminPanel'></a>Step 4: Access the Admin Panel
+ Access the [OpenIM Admin Panel](http://localhost:11002/).
+ Log in using the default username and password (`admin1:admin1`).
Running Effect Image:
![image-20231115101039837](http://sm.nsddd.top/sm202311151010116.png)
#### 1.3.8. <a name='Step5:AccesstheMonitoringInterface'></a>Step 5: Access the Monitoring Interface
+ Log in to the [Monitoring Interface](http://localhost:3000/login) using the credentials (`admin:admin`).
#### 1.3.9. <a name='NextSteps'></a>Next Steps
+ Configure and manage the services following the steps provided in the OpenIM source code.
+ Refer to the `README` file for advanced configuration and management.
#### 1.3.10. <a name='Troubleshooting'></a>Troubleshooting
+ If you encounter any issues, please check the documentation on [OpenIM Docker GitHub](https://github.com/openimsdk/openim-docker) or search for related issues in the Issues section.
+ If the problem persists, you can create an issue on the [openim-docker](https://github.com/openimsdk/openim-docker/issues/new/choose) repository or the [openim-server](https://github.com/openimsdk/open-im-server/issues/new/choose) repository.
## 2. <a name='Kubernetes'></a>Kubernetes
Refer to [openimsdk/helm-charts](https://github.com/openimsdk/helm-charts).
When deploying and monitoring OpenIM in a Kubernetes environment, you will focus on three main metrics: middleware, custom OpenIM metrics, and Node Exporter. Here are detailed steps and guidelines:
### 2.1. <a name='MiddlewareMonitoring'></a>Middleware Monitoring
Middleware monitoring is crucial to ensure the overall system's stability. Typically, this includes monitoring the following components:
+ **MySQL**: Monitor database performance, query latency, and more.
+ **Redis**: Track operation latency, memory usage, and more.
+ **MongoDB**: Observe database operations, resource usage, and more.
+ **Kafka**: Monitor message throughput, latency, and more.
+ **Zookeeper**: Keep an eye on cluster status, performance metrics, and more.
For Kubernetes environments, you can use the corresponding Prometheus Exporters to collect monitoring data for these middleware components.
### 2.2. <a name='CustomOpenIMMetrics'></a>Custom OpenIM Metrics
Custom OpenIM metrics provide essential information about the OpenIM application itself, such as user activity, message traffic, system performance, and more. To monitor these metrics in Kubernetes:
+ Ensure OpenIM application configurations expose Prometheus metrics.
+ When deploying using Helm charts (refer to [OpenIM Helm Charts](https://github.com/openimsdk/helm-charts)), pay attention to configuring relevant monitoring settings.
### 2.3. <a name='NodeExporter'></a>Node Exporter
Node Exporter is used to collect hardware and operating system-level metrics for Kubernetes nodes, such as CPU, memory, disk usage, and more. To integrate Node Exporter in Kubernetes:
+ Deploy Node Exporter using the appropriate Helm chart. You can find information and guides on [Prometheus Community](https://prometheus.io/docs/guides/node-exporter/).
+ Ensure Node Exporter's data is collected by Prometheus instances within your cluster.
## 3. <a name='SettingUpandConfiguringAlertManagerUsingEnvironmentVariablesandmakeinit'></a>Setting Up and Configuring AlertManager Using Environment Variables and `make init`
### 3.1. <a name='Introduction-1'></a>Introduction
AlertManager, a component of the Prometheus monitoring system, handles alerts sent by client applications such as the Prometheus server. It takes care of deduplicating, grouping, and routing them to the correct receiver. This document outlines how to set up and configure AlertManager using environment variables and the `make init` command. We will focus on configuring key fields like the sender's email, SMTP settings, and SMTP authentication password.
### 3.2. <a name='Prerequisites-1'></a>Prerequisites
+ Basic knowledge of terminal and command-line operations.
+ AlertManager installed on your system.
+ Access to an SMTP server for sending emails.
### 3.3. <a name='ConfigurationSteps'></a>Configuration Steps
#### 3.3.1. <a name='ExportingEnvironmentVariables'></a>Exporting Environment Variables
Before initializing AlertManager, you need to set environment variables. These variables are used to configure the AlertManager settings without altering the code. Use the `export` command in your terminal. Here are some key variables you might set:
+ `export ALERTMANAGER_RESOLVE_TIMEOUT='5m'`
+ `export ALERTMANAGER_SMTP_FROM='alert@example.com'`
+ `export ALERTMANAGER_SMTP_SMARTHOST='smtp.example.com:465'`
+ `export ALERTMANAGER_SMTP_AUTH_USERNAME='alert@example.com'`
+ `export ALERTMANAGER_SMTP_AUTH_PASSWORD='your_password'`
+ `export ALERTMANAGER_SMTP_REQUIRE_TLS='false'`
#### 3.3.2. <a name='InitializingAlertManager'></a>Initializing AlertManager
After setting the necessary environment variables, you can initialize AlertManager by running the `make init` command. This command typically runs a script that prepares AlertManager with the provided configuration.
#### 3.3.3. <a name='KeyConfigurationFields'></a>Key Configuration Fields
##### a. Sender's Email (`ALERTMANAGER_SMTP_FROM`)
This variable sets the email address that will appear as the sender in the notifications sent by AlertManager.
##### b. SMTP Configuration
+ **SMTP Server (`ALERTMANAGER_SMTP_SMARTHOST`):** Specifies the address and port of the SMTP server used for sending emails.
+ **SMTP Authentication Username (`ALERTMANAGER_SMTP_AUTH_USERNAME`):** The username for authenticating with the SMTP server.
+ **SMTP Authentication Password (`ALERTMANAGER_SMTP_AUTH_PASSWORD`):** The password for SMTP server authentication. It's crucial to keep this value secure.
#### 3.3.4. <a name='ConfiguringSMTPAuthenticationPassword'></a>Configuring SMTP Authentication Password
The SMTP authentication password can be set using the `ALERTMANAGER_SMTP_AUTH_PASSWORD` environment variable. It's recommended to use a secure method to set this variable to avoid exposing sensitive information. For instance, you might read the password from a secure file or a secret management tool.
#### 3.3.5. <a name='UsefulLinksforCommonEmailServers'></a>Useful Links for Common Email Servers
For specific configurations related to common email servers, you may refer to their respective documentation:
+ Gmail SMTP Settings:
+ [Gmail SMTP Configuration](https://support.google.com/mail/answer/7126229?hl=en)
+ Microsoft Outlook SMTP Settings:
+ [Outlook Email Settings](https://support.microsoft.com/en-us/office/pop-imap-and-smtp-settings-8361e398-8af4-4e97-b147-6c6c4ac95353)
+ Yahoo Mail SMTP Settings:
+ [Yahoo SMTP Configuration](https://help.yahoo.com/kb/SLN4724.html)
### 3.4. <a name='Conclusion'></a>Conclusion
Setting up and configuring AlertManager with environment variables provides a flexible and secure way to manage alert settings. By following the above steps, you can easily configure AlertManager for your monitoring needs. Always ensure to secure sensitive information, especially when dealing with SMTP authentication credentials.
+1 -1
View File
@@ -30,7 +30,7 @@ Executing `make tools` ensures verification and installation of the default tool
- go-junit-report - go-junit-report
- go-gitlint - go-gitlint
The installation path is situated at `./_output/tools/`. The installation path is situated at `/root/workspaces/openim/Open-IM-Server/_output/tools/`.
## Toolset Categories ## Toolset Categories
Binary file not shown.

Before

Width:  |  Height:  |  Size: 118 KiB

After

Width:  |  Height:  |  Size: 144 KiB

+9 -7
View File
@@ -4,16 +4,16 @@ go 1.19
require ( require (
firebase.google.com/go v3.13.0+incompatible firebase.google.com/go v3.13.0+incompatible
github.com/OpenIMSDK/protocol v0.0.31
github.com/OpenIMSDK/tools v0.0.20
github.com/bwmarrin/snowflake v0.3.0 // indirect github.com/bwmarrin/snowflake v0.3.0 // indirect
github.com/dtm-labs/rockscache v0.1.1 github.com/dtm-labs/rockscache v0.1.1
github.com/gin-gonic/gin v1.9.1 github.com/gin-gonic/gin v1.9.1
github.com/go-playground/validator/v10 v10.15.5 github.com/go-playground/validator/v10 v10.15.5
github.com/gogo/protobuf v1.3.2 github.com/gogo/protobuf v1.3.2
github.com/golang-jwt/jwt/v4 v4.5.0 github.com/golang-jwt/jwt/v4 v4.5.0
github.com/golang/protobuf v1.5.3
github.com/gorilla/websocket v1.5.0 github.com/gorilla/websocket v1.5.0
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0
github.com/jinzhu/copier v0.4.0
github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible // indirect github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible // indirect
github.com/minio/minio-go/v7 v7.0.63 github.com/minio/minio-go/v7 v7.0.63
github.com/mitchellh/mapstructure v1.5.0 github.com/mitchellh/mapstructure v1.5.0
@@ -29,18 +29,22 @@ require (
google.golang.org/grpc v1.59.0 google.golang.org/grpc v1.59.0
google.golang.org/protobuf v1.31.0 google.golang.org/protobuf v1.31.0
gopkg.in/yaml.v3 v3.0.1 gopkg.in/yaml.v3 v3.0.1
gorm.io/driver/mysql v1.5.2
gorm.io/gorm v1.25.5
) )
require github.com/google/uuid v1.3.1 require github.com/google/uuid v1.3.1
require ( require (
github.com/IBM/sarama v1.41.3 github.com/IBM/sarama v1.41.3
github.com/OpenIMSDK/protocol v0.0.31
github.com/OpenIMSDK/tools v0.0.16
github.com/aliyun/aliyun-oss-go-sdk v2.2.9+incompatible github.com/aliyun/aliyun-oss-go-sdk v2.2.9+incompatible
github.com/go-redis/redis v6.15.9+incompatible github.com/go-redis/redis v6.15.9+incompatible
github.com/go-sql-driver/mysql v1.7.1
github.com/redis/go-redis/v9 v9.2.1 github.com/redis/go-redis/v9 v9.2.1
github.com/tencentyun/cos-go-sdk-v5 v0.7.45 github.com/tencentyun/cos-go-sdk-v5 v0.7.45
go.uber.org/automaxprocs v1.5.3 go.uber.org/automaxprocs v1.5.3
golang.org/x/sync v0.4.0
gopkg.in/src-d/go-git.v4 v4.13.1 gopkg.in/src-d/go-git.v4 v4.13.1
gotest.tools v2.2.0+incompatible gotest.tools v2.2.0+incompatible
) )
@@ -70,7 +74,6 @@ require (
github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/go-zookeeper/zk v1.0.3 // indirect github.com/go-zookeeper/zk v1.0.3 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/golang/snappy v0.0.4 // indirect github.com/golang/snappy v0.0.4 // indirect
github.com/google/go-cmp v0.6.0 // indirect github.com/google/go-cmp v0.6.0 // indirect
github.com/google/go-querystring v1.1.0 // indirect github.com/google/go-querystring v1.1.0 // indirect
@@ -87,7 +90,6 @@ require (
github.com/jcmturner/gofork v1.7.6 // indirect github.com/jcmturner/gofork v1.7.6 // indirect
github.com/jcmturner/gokrb5/v8 v8.4.4 // indirect github.com/jcmturner/gokrb5/v8 v8.4.4 // indirect
github.com/jcmturner/rpc/v2 v2.0.3 // indirect github.com/jcmturner/rpc/v2 v2.0.3 // indirect
github.com/jinzhu/copier v0.3.5 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect github.com/jinzhu/now v1.1.5 // indirect
github.com/json-iterator/go v1.1.12 // indirect github.com/json-iterator/go v1.1.12 // indirect
@@ -130,7 +132,8 @@ require (
golang.org/x/arch v0.3.0 // indirect golang.org/x/arch v0.3.0 // indirect
golang.org/x/net v0.17.0 // indirect golang.org/x/net v0.17.0 // indirect
golang.org/x/oauth2 v0.13.0 // indirect golang.org/x/oauth2 v0.13.0 // indirect
golang.org/x/sys v0.14.0 // indirect golang.org/x/sync v0.4.0 // indirect
golang.org/x/sys v0.13.0 // indirect
golang.org/x/text v0.13.0 // indirect golang.org/x/text v0.13.0 // indirect
golang.org/x/time v0.3.0 // indirect golang.org/x/time v0.3.0 // indirect
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
@@ -140,7 +143,6 @@ require (
google.golang.org/genproto/googleapis/rpc v0.0.0-20231012201019-e917dd12ba7a // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20231012201019-e917dd12ba7a // indirect
gopkg.in/src-d/go-billy.v4 v4.3.2 // indirect gopkg.in/src-d/go-billy.v4 v4.3.2 // indirect
gopkg.in/warnings.v0 v0.1.2 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect
gorm.io/gorm v1.23.8 // indirect
) )
require ( require (
+14 -9
View File
@@ -20,8 +20,8 @@ github.com/IBM/sarama v1.41.3 h1:MWBEJ12vHC8coMjdEXFq/6ftO6DUZnQlFYcxtOJFa7c=
github.com/IBM/sarama v1.41.3/go.mod h1:Xxho9HkHd4K/MDUo/T/sOqwtX/17D33++E9Wib6hUdQ= github.com/IBM/sarama v1.41.3/go.mod h1:Xxho9HkHd4K/MDUo/T/sOqwtX/17D33++E9Wib6hUdQ=
github.com/OpenIMSDK/protocol v0.0.31 h1:ax43x9aqA6EKNXNukS5MT5BSTqkUmwO4uTvbJLtzCgE= github.com/OpenIMSDK/protocol v0.0.31 h1:ax43x9aqA6EKNXNukS5MT5BSTqkUmwO4uTvbJLtzCgE=
github.com/OpenIMSDK/protocol v0.0.31/go.mod h1:F25dFrwrIx3lkNoiuf6FkCfxuwf8L4Z8UIsdTHP/r0Y= github.com/OpenIMSDK/protocol v0.0.31/go.mod h1:F25dFrwrIx3lkNoiuf6FkCfxuwf8L4Z8UIsdTHP/r0Y=
github.com/OpenIMSDK/tools v0.0.20 h1:zBTjQZRJ5lR1FIzP9mtWyAvh5dKsmJXQugi4p8X/97k= github.com/OpenIMSDK/tools v0.0.16 h1:te/GIq2imCMsrRPgU9OObYKbzZ3rT08Lih/o+3QFIz0=
github.com/OpenIMSDK/tools v0.0.20/go.mod h1:eg+q4A34Qmu73xkY0mt37FHGMCMfC6CtmOnm0kFEGFI= github.com/OpenIMSDK/tools v0.0.16/go.mod h1:eg+q4A34Qmu73xkY0mt37FHGMCMfC6CtmOnm0kFEGFI=
github.com/QcloudApi/qcloud_sign_golang v0.0.0-20141224014652-e4130a326409/go.mod h1:1pk82RBxDY/JZnPQrtqHlUFfCctgdorsd9M06fMynOM= github.com/QcloudApi/qcloud_sign_golang v0.0.0-20141224014652-e4130a326409/go.mod h1:1pk82RBxDY/JZnPQrtqHlUFfCctgdorsd9M06fMynOM=
github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7 h1:uSoVVbwJiQipAclBbw+8quDsfcvFjOpI5iCf4p/cqCs= github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7 h1:uSoVVbwJiQipAclBbw+8quDsfcvFjOpI5iCf4p/cqCs=
github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs= github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs=
@@ -100,6 +100,9 @@ github.com/go-playground/validator/v10 v10.15.5 h1:LEBecTWb/1j5TNY1YYG2RcOUN3R7N
github.com/go-playground/validator/v10 v10.15.5/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= github.com/go-playground/validator/v10 v10.15.5/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
github.com/go-redis/redis v6.15.9+incompatible h1:K0pv1D7EQUjfyoMql+r/jZqCLizCGKFlFgcHWWmHQjg= github.com/go-redis/redis v6.15.9+incompatible h1:K0pv1D7EQUjfyoMql+r/jZqCLizCGKFlFgcHWWmHQjg=
github.com/go-redis/redis v6.15.9+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= github.com/go-redis/redis v6.15.9+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI=
github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
github.com/go-zookeeper/zk v1.0.3 h1:7M2kwOsc//9VeeFiPtf+uSJlVpU66x9Ba5+8XK7/TDg= github.com/go-zookeeper/zk v1.0.3 h1:7M2kwOsc//9VeeFiPtf+uSJlVpU66x9Ba5+8XK7/TDg=
github.com/go-zookeeper/zk v1.0.3/go.mod h1:nOB03cncLtlp4t+UAkGSV+9beXP/akpekBwL+UX1Qcw= github.com/go-zookeeper/zk v1.0.3/go.mod h1:nOB03cncLtlp4t+UAkGSV+9beXP/akpekBwL+UX1Qcw=
@@ -190,11 +193,10 @@ github.com/jcmturner/gokrb5/v8 v8.4.4/go.mod h1:1btQEpgT6k+unzCwX1KdWMEwPPkkgBtP
github.com/jcmturner/rpc/v2 v2.0.3 h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZY= github.com/jcmturner/rpc/v2 v2.0.3 h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZY=
github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc= github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jinzhu/copier v0.3.5 h1:GlvfUwHk62RokgqVNvYsku0TATCF7bAHVwEXoBh3iJg= github.com/jinzhu/copier v0.4.0 h1:w3ciUoD19shMCRargcpm0cm91ytaBhDvuRpz1ODO/U8=
github.com/jinzhu/copier v0.3.5/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg= github.com/jinzhu/copier v0.4.0/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg=
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
github.com/jinzhu/now v1.1.4/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/jonboulle/clockwork v0.4.0 h1:p4Cf1aMWXnXAUh8lVfewRBx1zaTSYKrKMF2g3ST4RZ4= github.com/jonboulle/clockwork v0.4.0 h1:p4Cf1aMWXnXAUh8lVfewRBx1zaTSYKrKMF2g3ST4RZ4=
@@ -436,8 +438,8 @@ golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
@@ -529,8 +531,11 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gorm.io/gorm v1.23.8 h1:h8sGJ+biDgBA1AD1Ha9gFCx7h8npU7AsLdlkX0n2TpE= gorm.io/driver/mysql v1.5.2 h1:QC2HRskSE75wBuOxe0+iCkyJZ+RqpudsQtqkp+IMuXs=
gorm.io/gorm v1.23.8/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk= gorm.io/driver/mysql v1.5.2/go.mod h1:pQLhh1Ut/WUAySdTHwBpBv6+JKcj+ua4ZFx1QQTBzb8=
gorm.io/gorm v1.25.2-0.20230530020048-26663ab9bf55/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k=
gorm.io/gorm v1.25.5 h1:zR9lOiiYf09VNh5Q1gphfyia1JpiClIWG9hQaxB/mls=
gorm.io/gorm v1.25.5/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
-1
View File
@@ -13,5 +13,4 @@ use (
./tools/component ./tools/component
./tools/url2im ./tools/url2im
./tools/data-conversion ./tools/data-conversion
./tools/up35
) )
+7 -7
View File
@@ -63,7 +63,7 @@ PROXY=
GITHUB_TOKEN= GITHUB_TOKEN=
# Default user is "root". If you need to modify it, uncomment and replace accordingly. # Default user is "root". If you need to modify it, uncomment and replace accordingly.
# OPENIM_USER=root # USER=root
# Default password for redis, mysql, mongo, as well as accessSecret in config/config.yaml. # Default password for redis, mysql, mongo, as well as accessSecret in config/config.yaml.
# Remember, it should be a combination of 8 or more numbers and letters. If you want to set a different password, uncomment and replace "openIM123". # Remember, it should be a combination of 8 or more numbers and letters. If you want to set a different password, uncomment and replace "openIM123".
@@ -244,10 +244,10 @@ function download_source_code() {
function set_openim_env() { function set_openim_env() {
warn "This command can only be executed once. It will modify the component passwords in docker-compose based on the PASSWORD variable in .env, and modify the component passwords in config/config.yaml. If the password in .env changes, you need to first execute docker-compose down; rm components -rf and then execute this command." warn "This command can only be executed once. It will modify the component passwords in docker-compose based on the PASSWORD variable in .env, and modify the component passwords in config/config.yaml. If the password in .env changes, you need to first execute docker-compose down; rm components -rf and then execute this command."
# Set default values for user input # Set default values for user input
# If the OPENIM_USER environment variable is not set, it defaults to 'root' # If the USER environment variable is not set, it defaults to 'root'
if [ -z "$OPENIM_USER" ]; then if [ -z "$USER" ]; then
OPENIM_USER="root" USER="root"
debug "OPENIM_USER is not set. Defaulting to 'root'." debug "USER is not set. Defaulting to 'root'."
fi fi
# If the PASSWORD environment variable is not set, it defaults to 'openIM123' # If the PASSWORD environment variable is not set, it defaults to 'openIM123'
@@ -321,7 +321,7 @@ function cmd_help() {
function parseinput() { function parseinput() {
# set default values # set default values
# OPENIM_USER=root # USER=root
# PASSWORD=openIM123 # PASSWORD=openIM123
# ENDPOINT=http://127.0.0.1:10005 # ENDPOINT=http://127.0.0.1:10005
# API=http://127.0.0.1:10002/object/ # API=http://127.0.0.1:10002/object/
@@ -347,7 +347,7 @@ function parseinput() {
;; ;;
-u|--user) -u|--user)
shift shift
OPENIM_USER=$1 USER=$1
;; ;;
-p|--password) -p|--password)
shift shift
+176
View File
@@ -0,0 +1,176 @@
#!/usr/bin/env bash
echo "Welcome to the Open-IM-Server installation scripts."
echo "Please select an deploy option:"
echo "1. docker-compose install"
echo "2. exit"
clear_openimlog() {
rm -rf ./logs/*
}
is_path() {
if [ -e "$1" ]; then
return 1
else
return 0
fi
}
is_empty() {
if [ -z "$1" ]; then
return 1
else
return 0
fi
}
is_directory_exists() {
if [ -d "$1" ]; then
return 1
else
return 0
fi
}
edit_config() {
echo "Is edit config.yaml?"
echo "1. vi edit config"
echo "2. do not edit config"
read choice
case $choice in
1)
vi config/config.yaml
;;
2)
echo "do not edit config"
;;
esac
}
edit_enterprise_config() {
echo "Is edit enterprise config.yaml?"
echo "1. vi edit enterprise config"
echo "2. do not edit enterprise config"
read choice
case $choice in
1)
vi ./.docker-compose_cfg/config.yaml
;;
2)
echo "Do not edit enterprise config"
;;
esac
}
install_docker_compose() {
echo "Please input the installation path, default is $(pwd)/Open-IM-Server, press enter to use default"
read install_path
is_empty $install_path
if [ $? -eq 1 ]; then
install_path="."
fi
echo "Installing Open-IM-Server to ${install_path}/Open-IM-Server..."
is_path $install_path
mkdir -p $install_path
cd $install_path
is_directory_exists "${install_path}/Open-IM-Server"
if [ $? -eq 1 ]; then
echo "WARNING: Directory $install_path/Open-IM-Server exist, please ensure your path"
echo "1. delete the directory and install"
echo "2. exit"
read choice
case $choice in
1)
rm -rf "${install_path}/Open-IM-Server"
;;
2)
exit 1
;;
esac
fi
rm -rf ./Open-IM-Server
set -e
git clone https://github.com/openimsdk/open-im-server.git --recursive;
set +e
cd ./Open-IM-Server
git checkout errcode
echo "======== git clone success ========"
source .env
if [ $DATA_DIR = "./" ]; then
DATA_DIR=$(pwd)/components
fi
echo "Please input the components data directory, deault is ${DATA_DIR}, press enter to use default"
read NEW_DATA_DIR
is_empty $NEW_DATA_DIR
if [ $? -eq 0 ]; then
DATA_DIR=$NEW_DATA_DIR
fi
echo "Please input the user, deault is root, press enter to use default"
read NEW_USER
is_empty $NEW_USER
if [ $? -eq 0 ]; then
USER=$NEW_USER
fi
echo "Please input the password, default is openIM123, press enter to use default"
read NEW_PASSWORD
is_empty $NEW_PASSWORD
if [ $? -eq 0 ]; then
PASSWORD=$NEW_PASSWORD
fi
echo "Please input the minio_endpoint, default will detect auto, press enter to use default"
read NEW_MINIO_ENDPOINT
is_empty $NEW_MINIO_ENDPOINT
if [ $? -eq 1 ]; then
internet_ip=`curl ifconfig.me -s`
MINIO_ENDPOINT="http://${internet_ip}:10005"
else
MINIO_ENDPOINT=$NEW_MINIO_ENDPOINT
fi
set -e
export MINIO_ENDPOINT
export USER
export PASSWORD
export DATA_DIR
cat <<EOF > .env
USER=${USER}
PASSWORD=${PASSWORD}
MINIO_ENDPOINT=${MINIO_ENDPOINT}
DATA_DIR=${DATA_DIR}
EOF
edit_config
edit_enterprise_config
cd scripts;
chmod +x *.sh;
./init-pwd.sh;
./env_check.sh;
cd ..;
docker-compose up -d;
cd scripts;
./docker-check-service.sh;
}
read choice
case $choice in
1)
install_docker_compose
;;
2)
;;
3)
;;
4)
echo "Exiting installation scripts..."
exit 0
;;
*)
echo "Invalid option, please try again."
;;
esac
+9 -7
View File
@@ -15,6 +15,14 @@
package api package api
import ( import (
"github.com/OpenIMSDK/tools/mcontext"
"github.com/gin-gonic/gin"
"github.com/go-playground/validator/v10"
"github.com/mitchellh/mapstructure"
"github.com/openimsdk/open-im-server/v3/pkg/authverify"
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
"github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/protocol/constant"
"github.com/OpenIMSDK/protocol/msg" "github.com/OpenIMSDK/protocol/msg"
"github.com/OpenIMSDK/protocol/sdkws" "github.com/OpenIMSDK/protocol/sdkws"
@@ -22,13 +30,7 @@ import (
"github.com/OpenIMSDK/tools/apiresp" "github.com/OpenIMSDK/tools/apiresp"
"github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/errs"
"github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/log"
"github.com/OpenIMSDK/tools/mcontext"
"github.com/OpenIMSDK/tools/utils" "github.com/OpenIMSDK/tools/utils"
"github.com/gin-gonic/gin"
"github.com/go-playground/validator/v10"
"github.com/mitchellh/mapstructure"
"github.com/openimsdk/open-im-server/v3/pkg/authverify"
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
"github.com/openimsdk/open-im-server/v3/pkg/apistruct" "github.com/openimsdk/open-im-server/v3/pkg/apistruct"
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
@@ -150,7 +152,7 @@ func (m *MessageApi) DeleteMsgPhysical(c *gin.Context) {
} }
func (m *MessageApi) getSendMsgReq(c *gin.Context, req apistruct.SendMsg) (sendMsgReq *msg.SendMsgReq, err error) { func (m *MessageApi) getSendMsgReq(c *gin.Context, req apistruct.SendMsg) (sendMsgReq *msg.SendMsgReq, err error) {
var data any var data interface{}
log.ZDebug(c, "getSendMsgReq", "req", req.Content) log.ZDebug(c, "getSendMsgReq", "req", req.Content)
switch req.ContentType { switch req.ContentType {
case constant.Text: case constant.Text:
+6 -15
View File
@@ -37,7 +37,7 @@ func CallbackUserOnline(ctx context.Context, userID string, platformID int, isAp
req := cbapi.CallbackUserOnlineReq{ req := cbapi.CallbackUserOnlineReq{
UserStatusCallbackReq: cbapi.UserStatusCallbackReq{ UserStatusCallbackReq: cbapi.UserStatusCallbackReq{
UserStatusBaseCallback: cbapi.UserStatusBaseCallback{ UserStatusBaseCallback: cbapi.UserStatusBaseCallback{
CallbackCommand: cbapi.CallbackUserOnlineCommand, CallbackCommand: constant.CallbackUserOnlineCommand,
OperationID: mcontext.GetOperationID(ctx), OperationID: mcontext.GetOperationID(ctx),
PlatformID: platformID, PlatformID: platformID,
Platform: constant.PlatformIDToName(platformID), Platform: constant.PlatformIDToName(platformID),
@@ -49,10 +49,7 @@ func CallbackUserOnline(ctx context.Context, userID string, platformID int, isAp
ConnID: connID, ConnID: connID,
} }
resp := cbapi.CommonCallbackResp{} resp := cbapi.CommonCallbackResp{}
if err := http.CallBackPostReturn(ctx, callBackURL(), &req, &resp, config.Config.Callback.CallbackUserOnline); err != nil { return http.CallBackPostReturn(ctx, callBackURL(), &req, &resp, config.Config.Callback.CallbackUserOnline)
return err
}
return nil
} }
func CallbackUserOffline(ctx context.Context, userID string, platformID int, connID string) error { func CallbackUserOffline(ctx context.Context, userID string, platformID int, connID string) error {
@@ -62,7 +59,7 @@ func CallbackUserOffline(ctx context.Context, userID string, platformID int, con
req := &cbapi.CallbackUserOfflineReq{ req := &cbapi.CallbackUserOfflineReq{
UserStatusCallbackReq: cbapi.UserStatusCallbackReq{ UserStatusCallbackReq: cbapi.UserStatusCallbackReq{
UserStatusBaseCallback: cbapi.UserStatusBaseCallback{ UserStatusBaseCallback: cbapi.UserStatusBaseCallback{
CallbackCommand: cbapi.CallbackUserOfflineCommand, CallbackCommand: constant.CallbackUserOfflineCommand,
OperationID: mcontext.GetOperationID(ctx), OperationID: mcontext.GetOperationID(ctx),
PlatformID: platformID, PlatformID: platformID,
Platform: constant.PlatformIDToName(platformID), Platform: constant.PlatformIDToName(platformID),
@@ -73,10 +70,7 @@ func CallbackUserOffline(ctx context.Context, userID string, platformID int, con
ConnID: connID, ConnID: connID,
} }
resp := &cbapi.CallbackUserOfflineResp{} resp := &cbapi.CallbackUserOfflineResp{}
if err := http.CallBackPostReturn(ctx, callBackURL(), req, resp, config.Config.Callback.CallbackUserOffline); err != nil { return http.CallBackPostReturn(ctx, callBackURL(), req, resp, config.Config.Callback.CallbackUserOffline)
return err
}
return nil
} }
func CallbackUserKickOff(ctx context.Context, userID string, platformID int) error { func CallbackUserKickOff(ctx context.Context, userID string, platformID int) error {
@@ -86,7 +80,7 @@ func CallbackUserKickOff(ctx context.Context, userID string, platformID int) err
req := &cbapi.CallbackUserKickOffReq{ req := &cbapi.CallbackUserKickOffReq{
UserStatusCallbackReq: cbapi.UserStatusCallbackReq{ UserStatusCallbackReq: cbapi.UserStatusCallbackReq{
UserStatusBaseCallback: cbapi.UserStatusBaseCallback{ UserStatusBaseCallback: cbapi.UserStatusBaseCallback{
CallbackCommand: cbapi.CallbackUserKickOffCommand, CallbackCommand: constant.CallbackUserKickOffCommand,
OperationID: mcontext.GetOperationID(ctx), OperationID: mcontext.GetOperationID(ctx),
PlatformID: platformID, PlatformID: platformID,
Platform: constant.PlatformIDToName(platformID), Platform: constant.PlatformIDToName(platformID),
@@ -96,10 +90,7 @@ func CallbackUserKickOff(ctx context.Context, userID string, platformID int) err
Seq: time.Now().UnixMilli(), Seq: time.Now().UnixMilli(),
} }
resp := &cbapi.CommonCallbackResp{} resp := &cbapi.CommonCallbackResp{}
if err := http.CallBackPostReturn(ctx, callBackURL(), req, resp, config.Config.Callback.CallbackUserOffline); err != nil { return http.CallBackPostReturn(ctx, callBackURL(), req, resp, config.Config.Callback.CallbackUserOffline)
return err
}
return nil
} }
// func callbackUserOnline(operationID, userID string, platformID int, token string, isAppBackground bool, connID // func callbackUserOnline(operationID, userID string, platformID int, token string, isAppBackground bool, connID
+2 -2
View File
@@ -167,7 +167,7 @@ func (c *Client) readMessage() {
func (c *Client) handleMessage(message []byte) error { func (c *Client) handleMessage(message []byte) error {
if c.IsCompress { if c.IsCompress {
var err error var err error
message, err = c.longConnServer.DecompressWithPool(message) message, err = c.longConnServer.DeCompress(message)
if err != nil { if err != nil {
return utils.Wrap(err, "") return utils.Wrap(err, "")
} }
@@ -317,7 +317,7 @@ func (c *Client) writeBinaryMsg(resp Resp) error {
_ = c.conn.SetWriteDeadline(writeWait) _ = c.conn.SetWriteDeadline(writeWait)
if c.IsCompress { if c.IsCompress {
resultBuf, compressErr := c.longConnServer.CompressWithPool(encodedBuf) resultBuf, compressErr := c.longConnServer.Compress(encodedBuf)
if compressErr != nil { if compressErr != nil {
return utils.Wrap(compressErr, "") return utils.Wrap(compressErr, "")
} }
-45
View File
@@ -17,23 +17,14 @@ package msggateway
import ( import (
"bytes" "bytes"
"compress/gzip" "compress/gzip"
"errors"
"io" "io"
"sync"
"github.com/OpenIMSDK/tools/utils" "github.com/OpenIMSDK/tools/utils"
) )
var (
gzipWriterPool = sync.Pool{New: func() any { return gzip.NewWriter(nil) }}
gzipReaderPool = sync.Pool{New: func() any { return new(gzip.Reader) }}
)
type Compressor interface { type Compressor interface {
Compress(rawData []byte) ([]byte, error) Compress(rawData []byte) ([]byte, error)
CompressWithPool(rawData []byte) ([]byte, error)
DeCompress(compressedData []byte) ([]byte, error) DeCompress(compressedData []byte) ([]byte, error)
DecompressWithPool(compressedData []byte) ([]byte, error)
} }
type GzipCompressor struct { type GzipCompressor struct {
compressProtocol string compressProtocol string
@@ -55,22 +46,6 @@ func (g *GzipCompressor) Compress(rawData []byte) ([]byte, error) {
return gzipBuffer.Bytes(), nil return gzipBuffer.Bytes(), nil
} }
func (g *GzipCompressor) CompressWithPool(rawData []byte) ([]byte, error) {
gz := gzipWriterPool.Get().(*gzip.Writer)
defer gzipWriterPool.Put(gz)
gzipBuffer := bytes.Buffer{}
gz.Reset(&gzipBuffer)
if _, err := gz.Write(rawData); err != nil {
return nil, utils.Wrap(err, "")
}
if err := gz.Close(); err != nil {
return nil, utils.Wrap(err, "")
}
return gzipBuffer.Bytes(), nil
}
func (g *GzipCompressor) DeCompress(compressedData []byte) ([]byte, error) { func (g *GzipCompressor) DeCompress(compressedData []byte) ([]byte, error) {
buff := bytes.NewBuffer(compressedData) buff := bytes.NewBuffer(compressedData)
reader, err := gzip.NewReader(buff) reader, err := gzip.NewReader(buff)
@@ -84,23 +59,3 @@ func (g *GzipCompressor) DeCompress(compressedData []byte) ([]byte, error) {
_ = reader.Close() _ = reader.Close()
return compressedData, nil return compressedData, nil
} }
func (g *GzipCompressor) DecompressWithPool(compressedData []byte) ([]byte, error) {
reader := gzipReaderPool.Get().(*gzip.Reader)
if reader == nil {
return nil, errors.New("NewReader failed")
}
defer gzipReaderPool.Put(reader)
err := reader.Reset(bytes.NewReader(compressedData))
if err != nil {
return nil, utils.Wrap(err, "NewReader failed")
}
compressedData, err = io.ReadAll(reader)
if err != nil {
return nil, utils.Wrap(err, "ReadAll failed")
}
_ = reader.Close()
return compressedData, nil
}
-107
View File
@@ -1,107 +0,0 @@
package msggateway
import (
"crypto/rand"
"sync"
"testing"
"github.com/stretchr/testify/assert"
)
func mockRandom() []byte {
bs := make([]byte, 50)
rand.Read(bs)
return bs
}
func TestCompressDecompress(t *testing.T) {
compressor := NewGzipCompressor()
for i := 0; i < 2000; i++ {
src := mockRandom()
// compress
dest, err := compressor.CompressWithPool(src)
assert.Equal(t, nil, err)
// decompress
res, err := compressor.DecompressWithPool(dest)
assert.Equal(t, nil, err)
// check
assert.EqualValues(t, src, res)
}
}
func TestCompressDecompressWithConcurrency(t *testing.T) {
wg := sync.WaitGroup{}
compressor := NewGzipCompressor()
for i := 0; i < 200; i++ {
wg.Add(1)
go func() {
defer wg.Done()
src := mockRandom()
// compress
dest, err := compressor.CompressWithPool(src)
assert.Equal(t, nil, err)
// decompress
res, err := compressor.DecompressWithPool(dest)
assert.Equal(t, nil, err)
// check
assert.EqualValues(t, src, res)
}()
}
wg.Wait()
}
func BenchmarkCompress(b *testing.B) {
src := mockRandom()
compressor := NewGzipCompressor()
for i := 0; i < b.N; i++ {
_, err := compressor.Compress(src)
assert.Equal(b, nil, err)
}
}
func BenchmarkCompressWithSyncPool(b *testing.B) {
src := mockRandom()
compressor := NewGzipCompressor()
for i := 0; i < b.N; i++ {
_, err := compressor.CompressWithPool(src)
assert.Equal(b, nil, err)
}
}
func BenchmarkDecompress(b *testing.B) {
src := mockRandom()
compressor := NewGzipCompressor()
comdata, err := compressor.Compress(src)
assert.Equal(b, nil, err)
for i := 0; i < b.N; i++ {
_, err := compressor.DeCompress(comdata)
assert.Equal(b, nil, err)
}
}
func BenchmarkDecompressWithSyncPool(b *testing.B) {
src := mockRandom()
compressor := NewGzipCompressor()
comdata, err := compressor.Compress(src)
assert.Equal(b, nil, err)
for i := 0; i < b.N; i++ {
_, err := compressor.DecompressWithPool(comdata)
assert.Equal(b, nil, err)
}
}
+4 -4
View File
@@ -22,8 +22,8 @@ import (
) )
type Encoder interface { type Encoder interface {
Encode(data any) ([]byte, error) Encode(data interface{}) ([]byte, error)
Decode(encodeData []byte, decodeData any) error Decode(encodeData []byte, decodeData interface{}) error
} }
type GobEncoder struct{} type GobEncoder struct{}
@@ -32,7 +32,7 @@ func NewGobEncoder() *GobEncoder {
return &GobEncoder{} return &GobEncoder{}
} }
func (g *GobEncoder) Encode(data any) ([]byte, error) { func (g *GobEncoder) Encode(data interface{}) ([]byte, error) {
buff := bytes.Buffer{} buff := bytes.Buffer{}
enc := gob.NewEncoder(&buff) enc := gob.NewEncoder(&buff)
err := enc.Encode(data) err := enc.Encode(data)
@@ -42,7 +42,7 @@ func (g *GobEncoder) Encode(data any) ([]byte, error) {
return buff.Bytes(), nil return buff.Bytes(), nil
} }
func (g *GobEncoder) Decode(encodeData []byte, decodeData any) error { func (g *GobEncoder) Decode(encodeData []byte, decodeData interface{}) error {
buff := bytes.NewBuffer(encodeData) buff := bytes.NewBuffer(encodeData)
dec := gob.NewDecoder(buff) dec := gob.NewDecoder(buff)
err := dec.Decode(decodeData) err := dec.Decode(decodeData)
+55 -65
View File
@@ -17,19 +17,22 @@ package msggateway
import ( import (
"context" "context"
"github.com/OpenIMSDK/tools/mcontext"
"github.com/openimsdk/open-im-server/v3/pkg/authverify"
"github.com/OpenIMSDK/tools/errs"
"google.golang.org/grpc" "google.golang.org/grpc"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/cache"
"github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/protocol/constant"
"github.com/OpenIMSDK/protocol/msggateway" "github.com/OpenIMSDK/protocol/msggateway"
"github.com/OpenIMSDK/tools/discoveryregistry" "github.com/OpenIMSDK/tools/discoveryregistry"
"github.com/OpenIMSDK/tools/errs"
"github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/log"
"github.com/OpenIMSDK/tools/mcontext"
"github.com/OpenIMSDK/tools/utils" "github.com/OpenIMSDK/tools/utils"
"github.com/openimsdk/open-im-server/v3/pkg/authverify"
"github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/config"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/cache"
"github.com/openimsdk/open-im-server/v3/pkg/common/startrpc" "github.com/openimsdk/open-im-server/v3/pkg/common/startrpc"
) )
@@ -38,7 +41,6 @@ func (s *Server) InitServer(disCov discoveryregistry.SvcDiscoveryRegistry, serve
if err != nil { if err != nil {
return err return err
} }
msgModel := cache.NewMsgCacheModel(rdb) msgModel := cache.NewMsgCacheModel(rdb)
s.LongConnServer.SetDiscoveryRegistry(disCov) s.LongConnServer.SetDiscoveryRegistry(disCov)
s.LongConnServer.SetCacheHandler(msgModel) s.LongConnServer.SetCacheHandler(msgModel)
@@ -95,25 +97,22 @@ func (s *Server) GetUsersOnlineStatus(
if !ok { if !ok {
continue continue
} }
temp := new(msggateway.GetUsersOnlineStatusResp_SuccessResult)
uresp := new(msggateway.GetUsersOnlineStatusResp_SuccessResult) temp.UserID = userID
uresp.UserID = userID
for _, client := range clients { for _, client := range clients {
if client == nil { if client != nil {
continue ps := new(msggateway.GetUsersOnlineStatusResp_SuccessDetail)
ps.Platform = constant.PlatformIDToName(client.PlatformID)
ps.Status = constant.OnlineStatus
ps.ConnID = client.ctx.GetConnID()
ps.Token = client.token
ps.IsBackground = client.IsBackground
temp.Status = constant.OnlineStatus
temp.DetailPlatformStatus = append(temp.DetailPlatformStatus, ps)
} }
ps := new(msggateway.GetUsersOnlineStatusResp_SuccessDetail)
ps.Platform = constant.PlatformIDToName(client.PlatformID)
ps.Status = constant.OnlineStatus
ps.ConnID = client.ctx.GetConnID()
ps.Token = client.token
ps.IsBackground = client.IsBackground
uresp.Status = constant.OnlineStatus
uresp.DetailPlatformStatus = append(uresp.DetailPlatformStatus, ps)
} }
if uresp.Status == constant.OnlineStatus { if temp.Status == constant.OnlineStatus {
resp.SuccessResult = append(resp.SuccessResult, uresp) resp.SuccessResult = append(resp.SuccessResult, temp)
} }
} }
return &resp, nil return &resp, nil
@@ -130,55 +129,50 @@ func (s *Server) SuperGroupOnlineBatchPushOneMsg(
ctx context.Context, ctx context.Context,
req *msggateway.OnlineBatchPushOneMsgReq, req *msggateway.OnlineBatchPushOneMsgReq,
) (*msggateway.OnlineBatchPushOneMsgResp, error) { ) (*msggateway.OnlineBatchPushOneMsgResp, error) {
var singleUserResult []*msggateway.SingleMsgToUserResults
var singleUserResults []*msggateway.SingleMsgToUserResults
for _, v := range req.PushToUserIDs { for _, v := range req.PushToUserIDs {
var resp []*msggateway.SingleMsgToUserPlatform var resp []*msggateway.SingleMsgToUserPlatform
results := &msggateway.SingleMsgToUserResults{ tempT := &msggateway.SingleMsgToUserResults{
UserID: v, UserID: v,
} }
clients, ok := s.LongConnServer.GetUserAllCons(v) clients, ok := s.LongConnServer.GetUserAllCons(v)
if !ok { if !ok {
log.ZDebug(ctx, "push user not online", "userID", v) log.ZDebug(ctx, "push user not online", "userID", v)
results.Resp = resp tempT.Resp = resp
singleUserResults = append(singleUserResults, results) singleUserResult = append(singleUserResult, tempT)
continue continue
} }
log.ZDebug(ctx, "push user online", "clients", clients, "userID", v) log.ZDebug(ctx, "push user online", "clients", clients, "userID", v)
for _, client := range clients { for _, client := range clients {
if client == nil { if client != nil {
continue temp := &msggateway.SingleMsgToUserPlatform{
} RecvID: v,
RecvPlatFormID: int32(client.PlatformID),
userPlatform := &msggateway.SingleMsgToUserPlatform{ }
RecvID: v, if !client.IsBackground ||
RecvPlatFormID: int32(client.PlatformID), (client.IsBackground == true && client.PlatformID != constant.IOSPlatformID) {
} err := client.PushMessage(ctx, req.MsgData)
if !client.IsBackground || if err != nil {
(client.IsBackground && client.PlatformID != constant.IOSPlatformID) { temp.ResultCode = -2
err := client.PushMessage(ctx, req.MsgData) resp = append(resp, temp)
if err != nil { } else {
userPlatform.ResultCode = -2 if utils.IsContainInt(client.PlatformID, s.pushTerminal) {
resp = append(resp, userPlatform) tempT.OnlinePush = true
} else { resp = append(resp, temp)
if utils.IsContainInt(client.PlatformID, s.pushTerminal) { }
results.OnlinePush = true }
resp = append(resp, userPlatform) } else {
} temp.ResultCode = -3
resp = append(resp, temp)
} }
} else {
userPlatform.ResultCode = -3
resp = append(resp, userPlatform)
} }
} }
results.Resp = resp tempT.Resp = resp
singleUserResults = append(singleUserResults, results) singleUserResult = append(singleUserResult, tempT)
} }
return &msggateway.OnlineBatchPushOneMsgResp{ return &msggateway.OnlineBatchPushOneMsgResp{
SinglePushResult: singleUserResults, SinglePushResult: singleUserResult,
}, nil }, nil
} }
@@ -187,21 +181,17 @@ func (s *Server) KickUserOffline(
req *msggateway.KickUserOfflineReq, req *msggateway.KickUserOfflineReq,
) (*msggateway.KickUserOfflineResp, error) { ) (*msggateway.KickUserOfflineResp, error) {
for _, v := range req.KickUserIDList { for _, v := range req.KickUserIDList {
clients, _, ok := s.LongConnServer.GetUserPlatformCons(v, int(req.PlatformID)) if clients, _, ok := s.LongConnServer.GetUserPlatformCons(v, int(req.PlatformID)); ok {
if !ok { for _, client := range clients {
log.ZInfo(ctx, "conn not exist", "userID", v, "platformID", req.PlatformID) log.ZDebug(ctx, "kick user offline", "userID", v, "platformID", req.PlatformID, "client", client)
continue if err := client.longConnServer.KickUserConn(client); err != nil {
} log.ZWarn(ctx, "kick user offline failed", err, "userID", v, "platformID", req.PlatformID)
}
for _, client := range clients {
log.ZDebug(ctx, "kick user offline", "userID", v, "platformID", req.PlatformID, "client", client)
if err := client.longConnServer.KickUserConn(client); err != nil {
log.ZWarn(ctx, "kick user offline failed", err, "userID", v, "platformID", req.PlatformID)
} }
} else {
log.ZInfo(ctx, "conn not exist", "userID", v, "platformID", req.PlatformID)
} }
continue
} }
return &msggateway.KickUserOfflineResp{}, nil return &msggateway.KickUserOfflineResp{}, nil
} }
+7 -20
View File
@@ -19,12 +19,11 @@ import (
"time" "time"
"github.com/OpenIMSDK/tools/utils" "github.com/OpenIMSDK/tools/utils"
"golang.org/x/sync/errgroup"
"github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/config"
) )
// RunWsAndServer run ws server. // RunWsAndServer run ws server
func RunWsAndServer(rpcPort, wsPort, prometheusPort int) error { func RunWsAndServer(rpcPort, wsPort, prometheusPort int) error {
fmt.Println( fmt.Println(
"start rpc/msg_gateway server, port: ", "start rpc/msg_gateway server, port: ",
@@ -38,28 +37,16 @@ func RunWsAndServer(rpcPort, wsPort, prometheusPort int) error {
WithPort(wsPort), WithPort(wsPort),
WithMaxConnNum(int64(config.Config.LongConnSvr.WebsocketMaxConnNum)), WithMaxConnNum(int64(config.Config.LongConnSvr.WebsocketMaxConnNum)),
WithHandshakeTimeout(time.Duration(config.Config.LongConnSvr.WebsocketTimeout)*time.Second), WithHandshakeTimeout(time.Duration(config.Config.LongConnSvr.WebsocketTimeout)*time.Second),
WithMessageMaxMsgLength(config.Config.LongConnSvr.WebsocketMaxMsgLen), WithMessageMaxMsgLength(config.Config.LongConnSvr.WebsocketMaxMsgLen))
WithWriteBufferSize(config.Config.LongConnSvr.WebsocketWriteBufferSize),
)
if err != nil { if err != nil {
return err return err
} }
hubServer := NewServer(rpcPort, prometheusPort, longServer) hubServer := NewServer(rpcPort, prometheusPort, longServer)
go func() {
wg := errgroup.Group{} err := hubServer.Start()
wg.Go(func() error {
err = hubServer.Start()
if err != nil { if err != nil {
return utils.Wrap1(err) panic(utils.Wrap1(err))
} }
return err }()
}) return hubServer.LongConnServer.Run()
wg.Go(func() error {
return hubServer.LongConnServer.Run()
})
err = wg.Wait()
return err
} }
+2 -7
View File
@@ -50,11 +50,10 @@ type GWebSocket struct {
protocolType int protocolType int
conn *websocket.Conn conn *websocket.Conn
handshakeTimeout time.Duration handshakeTimeout time.Duration
writeBufferSize int
} }
func newGWebSocket(protocolType int, handshakeTimeout time.Duration, wbs int) *GWebSocket { func newGWebSocket(protocolType int, handshakeTimeout time.Duration) *GWebSocket {
return &GWebSocket{protocolType: protocolType, handshakeTimeout: handshakeTimeout, writeBufferSize: wbs} return &GWebSocket{protocolType: protocolType, handshakeTimeout: handshakeTimeout}
} }
func (d *GWebSocket) Close() error { func (d *GWebSocket) Close() error {
@@ -66,10 +65,6 @@ func (d *GWebSocket) GenerateLongConn(w http.ResponseWriter, r *http.Request) er
HandshakeTimeout: d.handshakeTimeout, HandshakeTimeout: d.handshakeTimeout,
CheckOrigin: func(r *http.Request) bool { return true }, CheckOrigin: func(r *http.Request) bool { return true },
} }
if d.writeBufferSize > 0 { // default is 4kb.
upgrader.WriteBufferSize = d.writeBufferSize
}
conn, err := upgrader.Upgrade(w, r, nil) conn, err := upgrader.Upgrade(w, r, nil)
if err != nil { if err != nil {
return err return err
+95 -147
View File
@@ -18,30 +18,31 @@ import (
"context" "context"
"errors" "errors"
"net/http" "net/http"
"os"
"os/signal"
"strconv" "strconv"
"sync" "sync"
"sync/atomic" "sync/atomic"
"syscall"
"time" "time"
"github.com/go-playground/validator/v10"
"github.com/redis/go-redis/v9"
"golang.org/x/sync/errgroup"
"github.com/OpenIMSDK/protocol/constant"
"github.com/OpenIMSDK/protocol/msggateway" "github.com/OpenIMSDK/protocol/msggateway"
"github.com/OpenIMSDK/tools/discoveryregistry"
"github.com/OpenIMSDK/tools/errs"
"github.com/OpenIMSDK/tools/log"
"github.com/OpenIMSDK/tools/utils"
"github.com/openimsdk/open-im-server/v3/pkg/authverify" "github.com/openimsdk/open-im-server/v3/pkg/authverify"
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
"github.com/OpenIMSDK/protocol/constant"
"github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/config"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache"
"github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics" "github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics"
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
"github.com/redis/go-redis/v9"
"github.com/OpenIMSDK/tools/discoveryregistry"
"github.com/go-playground/validator/v10"
"github.com/OpenIMSDK/tools/errs"
"github.com/OpenIMSDK/tools/log"
"github.com/OpenIMSDK/tools/utils"
) )
type LongConnServer interface { type LongConnServer interface {
@@ -49,7 +50,7 @@ type LongConnServer interface {
wsHandler(w http.ResponseWriter, r *http.Request) wsHandler(w http.ResponseWriter, r *http.Request)
GetUserAllCons(userID string) ([]*Client, bool) GetUserAllCons(userID string) ([]*Client, bool)
GetUserPlatformCons(userID string, platform int) ([]*Client, bool, bool) GetUserPlatformCons(userID string, platform int) ([]*Client, bool, bool)
Validate(s any) error Validate(s interface{}) error
SetCacheHandler(cache cache.MsgModel) SetCacheHandler(cache cache.MsgModel)
SetDiscoveryRegistry(client discoveryregistry.SvcDiscoveryRegistry) SetDiscoveryRegistry(client discoveryregistry.SvcDiscoveryRegistry)
KickUserConn(client *Client) error KickUserConn(client *Client) error
@@ -61,7 +62,7 @@ type LongConnServer interface {
} }
var bufferPool = sync.Pool{ var bufferPool = sync.Pool{
New: func() any { New: func() interface{} {
return make([]byte, 1024) return make([]byte, 1024)
}, },
} }
@@ -77,7 +78,7 @@ type WsServer struct {
onlineUserNum atomic.Int64 onlineUserNum atomic.Int64
onlineUserConnNum atomic.Int64 onlineUserConnNum atomic.Int64
handshakeTimeout time.Duration handshakeTimeout time.Duration
writeBufferSize int hubServer *Server
validate *validator.Validate validate *validator.Validate
cache cache.MsgModel cache cache.MsgModel
userClient *rpcclient.UserRpcClient userClient *rpcclient.UserRpcClient
@@ -126,8 +127,7 @@ func (ws *WsServer) UnRegister(c *Client) {
ws.unregisterChan <- c ws.unregisterChan <- c
} }
func (ws *WsServer) Validate(s any) error { func (ws *WsServer) Validate(s interface{}) error {
//?question?
return nil return nil
} }
@@ -148,10 +148,9 @@ func NewWsServer(opts ...Option) (*WsServer, error) {
return &WsServer{ return &WsServer{
port: config.port, port: config.port,
wsMaxConnNum: config.maxConnNum, wsMaxConnNum: config.maxConnNum,
writeBufferSize: config.writeBufferSize,
handshakeTimeout: config.handshakeTimeout, handshakeTimeout: config.handshakeTimeout,
clientPool: sync.Pool{ clientPool: sync.Pool{
New: func() any { New: func() interface{} {
return new(Client) return new(Client)
}, },
}, },
@@ -166,22 +165,10 @@ func NewWsServer(opts ...Option) (*WsServer, error) {
} }
func (ws *WsServer) Run() error { func (ws *WsServer) Run() error {
var ( var client *Client
client *Client go func() {
wg errgroup.Group
sigs = make(chan os.Signal, 1)
done = make(chan struct{}, 1)
)
server := http.Server{Addr: ":" + utils.IntToString(ws.port), Handler: nil}
wg.Go(func() error {
for { for {
select { select {
case <-done:
return nil
case client = <-ws.registerChan: case client = <-ws.registerChan:
ws.registerClient(client) ws.registerClient(client)
case client = <-ws.unregisterChan: case client = <-ws.unregisterChan:
@@ -190,69 +177,33 @@ func (ws *WsServer) Run() error {
ws.multiTerminalLoginChecker(onlineInfo.clientOK, onlineInfo.oldClients, onlineInfo.newClient) ws.multiTerminalLoginChecker(onlineInfo.clientOK, onlineInfo.oldClients, onlineInfo.newClient)
} }
} }
})
wg.Go(func() error {
http.HandleFunc("/", ws.wsHandler)
return server.ListenAndServe()
})
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)
<-sigs
go func() {
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
defer cancel()
// graceful exit operation for server
_ = server.Shutdown(ctx)
_ = wg.Wait()
close(done)
}() }()
http.HandleFunc("/", ws.wsHandler)
select { // http.HandleFunc("/metrics", func(w http.ResponseWriter, r *http.Request) {})
case <-done: return http.ListenAndServe(":"+utils.IntToString(ws.port), nil) // Start listening
return nil
case <-time.After(15 * time.Second):
return utils.Wrap1(errors.New("timeout exit"))
}
} }
var concurrentRequest = 3
func (ws *WsServer) sendUserOnlineInfoToOtherNode(ctx context.Context, client *Client) error { func (ws *WsServer) sendUserOnlineInfoToOtherNode(ctx context.Context, client *Client) error {
conns, err := ws.disCov.GetConns(ctx, config.Config.RpcRegisterName.OpenImMessageGatewayName) conns, err := ws.disCov.GetConns(ctx, config.Config.RpcRegisterName.OpenImMessageGatewayName)
if err != nil { if err != nil {
return err return err
} }
wg := errgroup.Group{}
wg.SetLimit(concurrentRequest)
// Online push user online message to other node // Online push user online message to other node
for _, v := range conns { for _, v := range conns {
v := v // safe closure var
if v.Target() == ws.disCov.GetSelfConnTarget() { if v.Target() == ws.disCov.GetSelfConnTarget() {
log.ZDebug(ctx, "Filter out this node", "node", v.Target()) log.ZDebug(ctx, "Filter out this node", "node", v.Target())
continue continue
} }
msgClient := msggateway.NewMsgGatewayClient(v)
wg.Go(func() error { _, err := msgClient.MultiTerminalLoginCheck(ctx, &msggateway.MultiTerminalLoginCheckReq{
msgClient := msggateway.NewMsgGatewayClient(v) UserID: client.UserID,
_, err := msgClient.MultiTerminalLoginCheck(ctx, &msggateway.MultiTerminalLoginCheckReq{ PlatformID: int32(client.PlatformID), Token: client.token,
UserID: client.UserID,
PlatformID: int32(client.PlatformID), Token: client.token,
})
if err != nil {
log.ZWarn(ctx, "MultiTerminalLoginCheck err", err, "node", v.Target())
}
return nil
}) })
if err != nil {
log.ZWarn(ctx, "MultiTerminalLoginCheck err", err, "node", v.Target())
continue
}
} }
_ = wg.Wait()
return nil return nil
} }
@@ -338,72 +289,70 @@ func (ws *WsServer) multiTerminalLoginChecker(clientOK bool, oldClients []*Clien
} }
fallthrough fallthrough
case constant.AllLoginButSameTermKick: case constant.AllLoginButSameTermKick:
if !clientOK { if clientOK {
return isDeleteUser := ws.clients.deleteClients(newClient.UserID, oldClients)
} if isDeleteUser {
ws.onlineUserNum.Add(-1)
}
for _, c := range oldClients {
err := c.KickOnlineMessage()
if err != nil {
log.ZWarn(c.ctx, "KickOnlineMessage", err)
}
}
m, err := ws.cache.GetTokensWithoutError(
newClient.ctx,
newClient.UserID,
newClient.PlatformID,
)
if err != nil && err != redis.Nil {
log.ZWarn(
newClient.ctx,
"get token from redis err",
err,
"userID",
newClient.UserID,
"platformID",
newClient.PlatformID,
)
return
}
if m == nil {
log.ZWarn(
newClient.ctx,
"m is nil",
errors.New("m is nil"),
"userID",
newClient.UserID,
"platformID",
newClient.PlatformID,
)
return
}
log.ZDebug(
newClient.ctx,
"get token from redis",
"userID",
newClient.UserID,
"platformID",
newClient.PlatformID,
"tokenMap",
m,
)
isDeleteUser := ws.clients.deleteClients(newClient.UserID, oldClients) for k := range m {
if isDeleteUser { if k != newClient.ctx.GetToken() {
ws.onlineUserNum.Add(-1) m[k] = constant.KickedToken
} }
for _, c := range oldClients { }
err := c.KickOnlineMessage() log.ZDebug(newClient.ctx, "set token map is ", "token map", m, "userID",
newClient.UserID, "token", newClient.ctx.GetToken())
err = ws.cache.SetTokenMapByUidPid(newClient.ctx, newClient.UserID, newClient.PlatformID, m)
if err != nil { if err != nil {
log.ZWarn(c.ctx, "KickOnlineMessage", err) log.ZWarn(newClient.ctx, "SetTokenMapByUidPid err", err, "userID", newClient.UserID, "platformID", newClient.PlatformID)
return
} }
} }
m, err := ws.cache.GetTokensWithoutError(
newClient.ctx,
newClient.UserID,
newClient.PlatformID,
)
if err != nil && err != redis.Nil {
log.ZWarn(
newClient.ctx,
"get token from redis err",
err,
"userID",
newClient.UserID,
"platformID",
newClient.PlatformID,
)
return
}
if m == nil {
log.ZWarn(
newClient.ctx,
"m is nil",
errors.New("m is nil"),
"userID",
newClient.UserID,
"platformID",
newClient.PlatformID,
)
return
}
log.ZDebug(
newClient.ctx,
"get token from redis",
"userID",
newClient.UserID,
"platformID",
newClient.PlatformID,
"tokenMap",
m,
)
for k := range m {
if k != newClient.ctx.GetToken() {
m[k] = constant.KickedToken
}
}
log.ZDebug(newClient.ctx, "set token map is ", "token map", m, "userID",
newClient.UserID, "token", newClient.ctx.GetToken())
err = ws.cache.SetTokenMapByUidPid(newClient.ctx, newClient.UserID, newClient.PlatformID, m)
if err != nil {
log.ZWarn(newClient.ctx, "SetTokenMapByUidPid err", err, "userID", newClient.UserID, "platformID", newClient.PlatformID)
return
}
} }
} }
@@ -416,7 +365,7 @@ func (ws *WsServer) unregisterClient(client *Client) {
} }
ws.onlineUserConnNum.Add(-1) ws.onlineUserConnNum.Add(-1)
ws.SetUserOnlineStatus(client.ctx, client, constant.Offline) ws.SetUserOnlineStatus(client.ctx, client, constant.Offline)
log.ZInfo(client.ctx, "user offline", "close reason", client.closedErr, "online user Num", ws.onlineUserNum.Load(), "online user conn Num", log.ZInfo(client.ctx, "user offline", "close reason", client.closedErr, "online user Num", ws.onlineUserNum, "online user conn Num",
ws.onlineUserConnNum.Load(), ws.onlineUserConnNum.Load(),
) )
} }
@@ -455,7 +404,7 @@ func (ws *WsServer) wsHandler(w http.ResponseWriter, r *http.Request) {
httpError(connContext, errs.ErrConnArgsErr) httpError(connContext, errs.ErrConnArgsErr)
return return
} }
if err = authverify.WsVerifyToken(token, userID, platformID); err != nil { if err := authverify.WsVerifyToken(token, userID, platformID); err != nil {
httpError(connContext, err) httpError(connContext, err)
return return
} }
@@ -478,8 +427,7 @@ func (ws *WsServer) wsHandler(w http.ResponseWriter, r *http.Request) {
httpError(connContext, errs.ErrTokenNotExist.Wrap()) httpError(connContext, errs.ErrTokenNotExist.Wrap())
return return
} }
wsLongConn := newGWebSocket(WebSocket, ws.handshakeTimeout)
wsLongConn := newGWebSocket(WebSocket, ws.handshakeTimeout, ws.writeBufferSize)
err = wsLongConn.GenerateLongConn(w, r) err = wsLongConn.GenerateLongConn(w, r)
if err != nil { if err != nil {
httpError(connContext, err) httpError(connContext, err)
-8
View File
@@ -27,8 +27,6 @@ type (
handshakeTimeout time.Duration handshakeTimeout time.Duration
// 允许消息最大长度 // 允许消息最大长度
messageMaxMsgLength int messageMaxMsgLength int
// websocket write buffer, default: 4096, 4kb.
writeBufferSize int
} }
) )
@@ -55,9 +53,3 @@ func WithMessageMaxMsgLength(length int) Option {
opt.messageMaxMsgLength = length opt.messageMaxMsgLength = length
} }
} }
func WithWriteBufferSize(size int) Option {
return func(opt *configs) {
opt.writeBufferSize = size
}
}
+20 -4
View File
@@ -21,16 +21,19 @@ import (
"net/http" "net/http"
"sync" "sync"
"github.com/OpenIMSDK/tools/mw"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/collectors" "github.com/prometheus/client_golang/prometheus/collectors"
"github.com/prometheus/client_golang/prometheus/promhttp" "github.com/prometheus/client_golang/prometheus/promhttp"
"google.golang.org/grpc" "google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure" "google.golang.org/grpc/credentials/insecure"
"github.com/OpenIMSDK/tools/mw"
"github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/config"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/relation"
relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/unrelation" "github.com/openimsdk/open-im-server/v3/pkg/common/db/unrelation"
kdisc "github.com/openimsdk/open-im-server/v3/pkg/common/discoveryregister" kdisc "github.com/openimsdk/open-im-server/v3/pkg/common/discoveryregister"
"github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics" "github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics"
@@ -38,12 +41,20 @@ import (
) )
type MsgTransfer struct { type MsgTransfer struct {
persistentCH *PersistentConsumerHandler // 聊天记录持久化到mysql的消费者 订阅的topic: ws2ms_chat
historyCH *OnlineHistoryRedisConsumerHandler // 这个消费者聚合消息, 订阅的topic:ws2ms_chat, 修改通知发往msg_to_modify topic, 消息存入redis后Incr Redis, 再发消息到ms2pschat topic推送, 发消息到msg_to_mongo topic持久化 historyCH *OnlineHistoryRedisConsumerHandler // 这个消费者聚合消息, 订阅的topic:ws2ms_chat, 修改通知发往msg_to_modify topic, 消息存入redis后Incr Redis, 再发消息到ms2pschat topic推送, 发消息到msg_to_mongo topic持久化
historyMongoCH *OnlineHistoryMongoConsumerHandler // mongoDB批量插入, 成功后删除redis中消息,以及处理删除通知消息删除的 订阅的topic: msg_to_mongo historyMongoCH *OnlineHistoryMongoConsumerHandler // mongoDB批量插入, 成功后删除redis中消息,以及处理删除通知消息删除的 订阅的topic: msg_to_mongo
// modifyCH *ModifyMsgConsumerHandler // 负责消费修改消息通知的consumer, 订阅的topic: msg_to_modify // modifyCH *ModifyMsgConsumerHandler // 负责消费修改消息通知的consumer, 订阅的topic: msg_to_modify
} }
func StartTransfer(prometheusPort int) error { func StartTransfer(prometheusPort int) error {
db, err := relation.NewGormDB()
if err != nil {
return err
}
if err := db.AutoMigrate(&relationtb.ChatLogModel{}); err != nil {
fmt.Printf("gorm: AutoMigrate ChatLogModel err: %v\n", err)
}
rdb, err := cache.NewRedis() rdb, err := cache.NewRedis()
if err != nil { if err != nil {
return err return err
@@ -69,16 +80,21 @@ func StartTransfer(prometheusPort int) error {
client.AddOption(mw.GrpcClient(), grpc.WithTransportCredentials(insecure.NewCredentials())) client.AddOption(mw.GrpcClient(), grpc.WithTransportCredentials(insecure.NewCredentials()))
msgModel := cache.NewMsgCacheModel(rdb) msgModel := cache.NewMsgCacheModel(rdb)
msgDocModel := unrelation.NewMsgMongoDriver(mongo.GetDatabase()) msgDocModel := unrelation.NewMsgMongoDriver(mongo.GetDatabase())
msgMysModel := relation.NewChatLogGorm(db)
chatLogDatabase := controller.NewChatLogDatabase(msgMysModel)
msgDatabase := controller.NewCommonMsgDatabase(msgDocModel, msgModel) msgDatabase := controller.NewCommonMsgDatabase(msgDocModel, msgModel)
conversationRpcClient := rpcclient.NewConversationRpcClient(client) conversationRpcClient := rpcclient.NewConversationRpcClient(client)
groupRpcClient := rpcclient.NewGroupRpcClient(client) groupRpcClient := rpcclient.NewGroupRpcClient(client)
msgTransfer := NewMsgTransfer(msgDatabase, &conversationRpcClient, &groupRpcClient) msgTransfer := NewMsgTransfer(chatLogDatabase, msgDatabase, &conversationRpcClient, &groupRpcClient)
return msgTransfer.Start(prometheusPort) return msgTransfer.Start(prometheusPort)
} }
func NewMsgTransfer(msgDatabase controller.CommonMsgDatabase, conversationRpcClient *rpcclient.ConversationRpcClient, groupRpcClient *rpcclient.GroupRpcClient) *MsgTransfer { func NewMsgTransfer(chatLogDatabase controller.ChatLogDatabase,
msgDatabase controller.CommonMsgDatabase,
conversationRpcClient *rpcclient.ConversationRpcClient, groupRpcClient *rpcclient.GroupRpcClient,
) *MsgTransfer {
return &MsgTransfer{ return &MsgTransfer{
historyCH: NewOnlineHistoryRedisConsumerHandler(msgDatabase, conversationRpcClient, groupRpcClient), persistentCH: NewPersistentConsumerHandler(chatLogDatabase), historyCH: NewOnlineHistoryRedisConsumerHandler(msgDatabase, conversationRpcClient, groupRpcClient),
historyMongoCH: NewOnlineHistoryMongoConsumerHandler(msgDatabase), historyMongoCH: NewOnlineHistoryMongoConsumerHandler(msgDatabase),
} }
} }
@@ -61,7 +61,7 @@ type TriggerChannelValue struct {
type Cmd2Value struct { type Cmd2Value struct {
Cmd int Cmd int
Value any Value interface{}
} }
type ContextMsg struct { type ContextMsg struct {
message *sdkws.MsgData message *sdkws.MsgData
@@ -252,10 +252,7 @@ func (och *OnlineHistoryRedisConsumerHandler) handleNotification(
return return
} }
log.ZDebug(ctx, "success to next topic", "conversationID", conversationID) log.ZDebug(ctx, "success to next topic", "conversationID", conversationID)
err = och.msgDatabase.MsgToMongoMQ(ctx, key, conversationID, storageList, lastSeq) och.msgDatabase.MsgToMongoMQ(ctx, key, conversationID, storageList, lastSeq)
if err != nil {
log.ZError(ctx, "MsgToMongoMQ error", err)
}
och.toPushTopic(ctx, key, conversationID, storageList) och.toPushTopic(ctx, key, conversationID, storageList)
} }
} }
@@ -280,6 +277,9 @@ func (och *OnlineHistoryRedisConsumerHandler) handleMsg(
lastSeq, isNewConversation, err := och.msgDatabase.BatchInsertChat2Cache(ctx, conversationID, storageList) lastSeq, isNewConversation, err := och.msgDatabase.BatchInsertChat2Cache(ctx, conversationID, storageList)
if err != nil && errs.Unwrap(err) != redis.Nil { if err != nil && errs.Unwrap(err) != redis.Nil {
log.ZError(ctx, "batch data insert to redis err", err, "storageMsgList", storageList) log.ZError(ctx, "batch data insert to redis err", err, "storageMsgList", storageList)
och.singleMsgFailedCountMutex.Lock()
och.singleMsgFailedCount += uint64(len(storageList))
och.singleMsgFailedCountMutex.Unlock()
return return
} }
if isNewConversation { if isNewConversation {
@@ -311,10 +311,10 @@ func (och *OnlineHistoryRedisConsumerHandler) handleMsg(
} }
log.ZDebug(ctx, "success incr to next topic") log.ZDebug(ctx, "success incr to next topic")
err = och.msgDatabase.MsgToMongoMQ(ctx, key, conversationID, storageList, lastSeq) och.singleMsgSuccessCountMutex.Lock()
if err != nil { och.singleMsgSuccessCount += uint64(len(storageList))
log.ZError(ctx, "MsgToMongoMQ error", err) och.singleMsgSuccessCountMutex.Unlock()
} och.msgDatabase.MsgToMongoMQ(ctx, key, conversationID, storageList, lastSeq)
och.toPushTopic(ctx, key, conversationID, storageList) och.toPushTopic(ctx, key, conversationID, storageList)
} }
} }
@@ -427,62 +427,49 @@ func (och *OnlineHistoryRedisConsumerHandler) ConsumeClaim(
break break
} }
} }
rwLock := new(sync.RWMutex)
log.ZDebug(context.Background(), "online new session msg come", "highWaterMarkOffset", log.ZDebug(context.Background(), "online new session msg come", "highWaterMarkOffset",
claim.HighWaterMarkOffset(), "topic", claim.Topic(), "partition", claim.Partition()) claim.HighWaterMarkOffset(), "topic", claim.Topic(), "partition", claim.Partition())
cMsg := make([]*sarama.ConsumerMessage, 0, 1000)
split := 1000 t := time.NewTicker(time.Millisecond * 100)
rwLock := new(sync.RWMutex)
messages := make([]*sarama.ConsumerMessage, 0, 1000)
ticker := time.NewTicker(time.Millisecond * 100)
go func() { go func() {
for { for {
select { select {
case <-ticker.C: case <-t.C:
if len(messages) == 0 { if len(cMsg) > 0 {
continue rwLock.Lock()
ccMsg := make([]*sarama.ConsumerMessage, 0, 1000)
for _, v := range cMsg {
ccMsg = append(ccMsg, v)
}
cMsg = make([]*sarama.ConsumerMessage, 0, 1000)
rwLock.Unlock()
split := 1000
ctx := mcontext.WithTriggerIDContext(context.Background(), utils.OperationIDGenerator())
log.ZDebug(ctx, "timer trigger msg consumer start", "length", len(ccMsg))
for i := 0; i < len(ccMsg)/split; i++ {
// log.Debug()
och.msgDistributionCh <- Cmd2Value{Cmd: ConsumerMsgs, Value: TriggerChannelValue{
ctx: ctx, cMsgList: ccMsg[i*split : (i+1)*split],
}}
}
if (len(ccMsg) % split) > 0 {
och.msgDistributionCh <- Cmd2Value{Cmd: ConsumerMsgs, Value: TriggerChannelValue{
ctx: ctx, cMsgList: ccMsg[split*(len(ccMsg)/split):],
}}
}
log.ZDebug(ctx, "timer trigger msg consumer end", "length", len(ccMsg))
} }
rwLock.Lock()
buffer := make([]*sarama.ConsumerMessage, 0, len(messages))
buffer = append(buffer, messages...)
// reuse slice, set cap to 0
messages = messages[:0]
rwLock.Unlock()
start := time.Now()
ctx := mcontext.WithTriggerIDContext(context.Background(), utils.OperationIDGenerator())
log.ZDebug(ctx, "timer trigger msg consumer start", "length", len(buffer))
for i := 0; i < len(buffer)/split; i++ {
och.msgDistributionCh <- Cmd2Value{Cmd: ConsumerMsgs, Value: TriggerChannelValue{
ctx: ctx, cMsgList: buffer[i*split : (i+1)*split],
}}
}
if (len(buffer) % split) > 0 {
och.msgDistributionCh <- Cmd2Value{Cmd: ConsumerMsgs, Value: TriggerChannelValue{
ctx: ctx, cMsgList: buffer[split*(len(buffer)/split):],
}}
}
log.ZDebug(ctx, "timer trigger msg consumer end",
"length", len(buffer), "time_cost", time.Since(start),
)
} }
} }
}() }()
for msg := range claim.Messages() { for msg := range claim.Messages() {
if len(msg.Value) == 0 {
continue
}
rwLock.Lock() rwLock.Lock()
messages = append(messages, msg) if len(msg.Value) != 0 {
cMsg = append(cMsg, msg)
}
rwLock.Unlock() rwLock.Unlock()
sess.MarkMessage(msg, "") sess.MarkMessage(msg, "")
} }
return nil return nil
} }
@@ -0,0 +1,119 @@
// 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 msgtransfer
import (
"context"
"github.com/OpenIMSDK/protocol/constant"
pbmsg "github.com/OpenIMSDK/protocol/msg"
"github.com/OpenIMSDK/tools/log"
"github.com/OpenIMSDK/tools/utils"
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/controller"
kfk "github.com/openimsdk/open-im-server/v3/pkg/common/kafka"
"github.com/IBM/sarama"
"google.golang.org/protobuf/proto"
)
type PersistentConsumerHandler struct {
persistentConsumerGroup *kfk.MConsumerGroup
chatLogDatabase controller.ChatLogDatabase
}
func NewPersistentConsumerHandler(database controller.ChatLogDatabase) *PersistentConsumerHandler {
return &PersistentConsumerHandler{
persistentConsumerGroup: kfk.NewMConsumerGroup(&kfk.MConsumerGroupConfig{
KafkaVersion: sarama.V2_0_0_0,
OffsetsInitial: sarama.OffsetNewest, IsReturnErr: false,
}, []string{config.Config.Kafka.LatestMsgToRedis.Topic},
config.Config.Kafka.Addr, config.Config.Kafka.ConsumerGroupID.MsgToMySql),
chatLogDatabase: database,
}
}
func (pc *PersistentConsumerHandler) handleChatWs2Mysql(
ctx context.Context,
cMsg *sarama.ConsumerMessage,
msgKey string,
_ sarama.ConsumerGroupSession,
) {
msg := cMsg.Value
var tag bool
msgFromMQ := pbmsg.MsgDataToMQ{}
err := proto.Unmarshal(msg, &msgFromMQ)
if err != nil {
log.ZError(ctx, "msg_transfer Unmarshal msg err", err)
return
}
log.ZDebug(ctx, "handleChatWs2Mysql", "msg", msgFromMQ.MsgData)
// Control whether to store history messages (mysql)
isPersist := utils.GetSwitchFromOptions(msgFromMQ.MsgData.Options, constant.IsPersistent)
// Only process receiver data
if isPersist {
switch msgFromMQ.MsgData.SessionType {
case constant.SingleChatType, constant.NotificationChatType:
if msgKey == msgFromMQ.MsgData.RecvID {
tag = true
}
case constant.GroupChatType:
if msgKey == msgFromMQ.MsgData.SendID {
tag = true
}
case constant.SuperGroupChatType:
tag = true
}
if tag {
log.ZInfo(ctx, "msg_transfer msg persisting", "msg", string(msg))
if err = pc.chatLogDatabase.CreateChatLog(&msgFromMQ); err != nil {
log.ZError(ctx, "Message insert failed", err, "msg", msgFromMQ.String())
return
}
}
}
}
func (PersistentConsumerHandler) Setup(_ sarama.ConsumerGroupSession) error { return nil }
func (PersistentConsumerHandler) Cleanup(_ sarama.ConsumerGroupSession) error { return nil }
func (pc *PersistentConsumerHandler) ConsumeClaim(
sess sarama.ConsumerGroupSession,
claim sarama.ConsumerGroupClaim,
) error {
for msg := range claim.Messages() {
ctx := pc.persistentConsumerGroup.GetContextFromMsg(msg)
log.ZDebug(
ctx,
"kafka get info to mysql",
"msgTopic",
msg.Topic,
"msgPartition",
msg.Partition,
"msg",
string(msg.Value),
"key",
string(msg.Key),
)
if len(msg.Value) != 0 {
pc.handleChatWs2Mysql(ctx, msg, string(msg.Key), sess)
} else {
log.ZError(ctx, "msg get from kafka but is nil", nil, "key", msg.Key)
}
sess.MarkMessage(msg, "")
}
return nil
}
+11 -8
View File
@@ -19,6 +19,7 @@ import (
"github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/protocol/constant"
"github.com/OpenIMSDK/protocol/sdkws" "github.com/OpenIMSDK/protocol/sdkws"
"github.com/OpenIMSDK/tools/errs"
"github.com/OpenIMSDK/tools/mcontext" "github.com/OpenIMSDK/tools/mcontext"
"github.com/OpenIMSDK/tools/utils" "github.com/OpenIMSDK/tools/utils"
@@ -43,7 +44,7 @@ func callbackOfflinePush(
req := &callbackstruct.CallbackBeforePushReq{ req := &callbackstruct.CallbackBeforePushReq{
UserStatusBatchCallbackReq: callbackstruct.UserStatusBatchCallbackReq{ UserStatusBatchCallbackReq: callbackstruct.UserStatusBatchCallbackReq{
UserStatusBaseCallback: callbackstruct.UserStatusBaseCallback{ UserStatusBaseCallback: callbackstruct.UserStatusBaseCallback{
CallbackCommand: callbackstruct.CallbackOfflinePushCommand, CallbackCommand: constant.CallbackOfflinePushCommand,
OperationID: mcontext.GetOperationID(ctx), OperationID: mcontext.GetOperationID(ctx),
PlatformID: int(msg.SenderPlatformID), PlatformID: int(msg.SenderPlatformID),
Platform: constant.PlatformIDToName(int(msg.SenderPlatformID)), Platform: constant.PlatformIDToName(int(msg.SenderPlatformID)),
@@ -61,6 +62,9 @@ func callbackOfflinePush(
} }
resp := &callbackstruct.CallbackBeforePushResp{} resp := &callbackstruct.CallbackBeforePushResp{}
if err := http.CallBackPostReturn(ctx, url(), req, resp, config.Config.Callback.CallbackOfflinePush); err != nil { if err := http.CallBackPostReturn(ctx, url(), req, resp, config.Config.Callback.CallbackOfflinePush); err != nil {
if err == errs.ErrCallbackContinue {
return nil
}
return err return err
} }
if len(resp.UserIDs) != 0 { if len(resp.UserIDs) != 0 {
@@ -79,7 +83,7 @@ func callbackOnlinePush(ctx context.Context, userIDs []string, msg *sdkws.MsgDat
req := callbackstruct.CallbackBeforePushReq{ req := callbackstruct.CallbackBeforePushReq{
UserStatusBatchCallbackReq: callbackstruct.UserStatusBatchCallbackReq{ UserStatusBatchCallbackReq: callbackstruct.UserStatusBatchCallbackReq{
UserStatusBaseCallback: callbackstruct.UserStatusBaseCallback{ UserStatusBaseCallback: callbackstruct.UserStatusBaseCallback{
CallbackCommand: callbackstruct.CallbackOnlinePushCommand, CallbackCommand: constant.CallbackOnlinePushCommand,
OperationID: mcontext.GetOperationID(ctx), OperationID: mcontext.GetOperationID(ctx),
PlatformID: int(msg.SenderPlatformID), PlatformID: int(msg.SenderPlatformID),
Platform: constant.PlatformIDToName(int(msg.SenderPlatformID)), Platform: constant.PlatformIDToName(int(msg.SenderPlatformID)),
@@ -95,10 +99,7 @@ func callbackOnlinePush(ctx context.Context, userIDs []string, msg *sdkws.MsgDat
Content: GetContent(msg), Content: GetContent(msg),
} }
resp := &callbackstruct.CallbackBeforePushResp{} resp := &callbackstruct.CallbackBeforePushResp{}
if err := http.CallBackPostReturn(ctx, url(), req, resp, config.Config.Callback.CallbackOnlinePush); err != nil { return http.CallBackPostReturn(ctx, url(), req, resp, config.Config.Callback.CallbackOnlinePush)
return err
}
return nil
} }
func callbackBeforeSuperGroupOnlinePush( func callbackBeforeSuperGroupOnlinePush(
@@ -112,7 +113,7 @@ func callbackBeforeSuperGroupOnlinePush(
} }
req := callbackstruct.CallbackBeforeSuperGroupOnlinePushReq{ req := callbackstruct.CallbackBeforeSuperGroupOnlinePushReq{
UserStatusBaseCallback: callbackstruct.UserStatusBaseCallback{ UserStatusBaseCallback: callbackstruct.UserStatusBaseCallback{
CallbackCommand: callbackstruct.CallbackSuperGroupOnlinePushCommand, CallbackCommand: constant.CallbackSuperGroupOnlinePushCommand,
OperationID: mcontext.GetOperationID(ctx), OperationID: mcontext.GetOperationID(ctx),
PlatformID: int(msg.SenderPlatformID), PlatformID: int(msg.SenderPlatformID),
Platform: constant.PlatformIDToName(int(msg.SenderPlatformID)), Platform: constant.PlatformIDToName(int(msg.SenderPlatformID)),
@@ -128,9 +129,11 @@ func callbackBeforeSuperGroupOnlinePush(
} }
resp := &callbackstruct.CallbackBeforeSuperGroupOnlinePushResp{} resp := &callbackstruct.CallbackBeforeSuperGroupOnlinePushResp{}
if err := http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, req, resp, config.Config.Callback.CallbackBeforeSuperGroupOnlinePush); err != nil { if err := http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, req, resp, config.Config.Callback.CallbackBeforeSuperGroupOnlinePush); err != nil {
if err == errs.ErrCallbackContinue {
return nil
}
return err return err
} }
return nil
if len(resp.UserIDs) != 0 { if len(resp.UserIDs) != 0 {
*pushToUserIDs = resp.UserIDs *pushToUserIDs = resp.UserIDs
} }
+3 -3
View File
@@ -21,9 +21,9 @@ import (
) )
type Resp struct { type Resp struct {
Code int `json:"code"` Code int `json:"code"`
Msg string `json:"msg"` Msg string `json:"msg"`
Data any `json:"data"` Data interface{} `json:"data"`
} }
func (r *Resp) parseError() (err error) { func (r *Resp) parseError() (err error) {
+2 -2
View File
@@ -159,7 +159,7 @@ func (g *Client) singlePush(ctx context.Context, token, userID string, pushReq P
return g.request(ctx, pushURL, pushReq, token, nil) return g.request(ctx, pushURL, pushReq, token, nil)
} }
func (g *Client) request(ctx context.Context, url string, input any, token string, output any) error { func (g *Client) request(ctx context.Context, url string, input interface{}, token string, output interface{}) error {
header := map[string]string{"token": token} header := map[string]string{"token": token}
resp := &Resp{} resp := &Resp{}
resp.Data = output resp.Data = output
@@ -170,7 +170,7 @@ func (g *Client) postReturn(
ctx context.Context, ctx context.Context,
url string, url string,
header map[string]string, header map[string]string,
input any, input interface{},
output RespI, output RespI,
timeout int, timeout int,
) error { ) error {
@@ -23,7 +23,7 @@ const (
) )
type Audience struct { type Audience struct {
Object any Object interface{}
audience map[string][]string audience map[string][]string
} }
@@ -15,10 +15,10 @@
package body package body
type Message struct { type Message struct {
MsgContent string `json:"msg_content"` MsgContent string `json:"msg_content"`
Title string `json:"title,omitempty"` Title string `json:"title,omitempty"`
ContentType string `json:"content_type,omitempty"` ContentType string `json:"content_type,omitempty"`
Extras map[string]any `json:"extras,omitempty"` Extras map[string]interface{} `json:"extras,omitempty"`
} }
func (m *Message) SetMsgContent(c string) { func (m *Message) SetMsgContent(c string) {
@@ -33,9 +33,9 @@ func (m *Message) SetContentType(c string) {
m.ContentType = c m.ContentType = c
} }
func (m *Message) SetExtras(key string, value any) { func (m *Message) SetExtras(key string, value interface{}) {
if m.Extras == nil { if m.Extras == nil {
m.Extras = make(map[string]any) m.Extras = make(map[string]interface{})
} }
m.Extras[key] = value m.Extras[key] = value
} }
@@ -29,7 +29,7 @@ const (
) )
type Platform struct { type Platform struct {
Os any Os interface{}
osArry []string osArry []string
} }
@@ -15,11 +15,11 @@
package body package body
type PushObj struct { type PushObj struct {
Platform any `json:"platform"` Platform interface{} `json:"platform"`
Audience any `json:"audience"` Audience interface{} `json:"audience"`
Notification any `json:"notification,omitempty"` Notification interface{} `json:"notification,omitempty"`
Message any `json:"message,omitempty"` Message interface{} `json:"message,omitempty"`
Options any `json:"options,omitempty"` Options interface{} `json:"options,omitempty"`
} }
func (p *PushObj) SetPlatform(pf *Platform) { func (p *PushObj) SetPlatform(pf *Platform) {
+2 -2
View File
@@ -69,11 +69,11 @@ func (j *JPush) Push(ctx context.Context, userIDs []string, title, content strin
pushObj.SetNotification(&no) pushObj.SetNotification(&no)
pushObj.SetMessage(&msg) pushObj.SetMessage(&msg)
pushObj.SetOptions(&opt) pushObj.SetOptions(&opt)
var resp any var resp interface{}
return j.request(ctx, pushObj, resp, 5) return j.request(ctx, pushObj, resp, 5)
} }
func (j *JPush) request(ctx context.Context, po body.PushObj, resp any, timeout int) error { func (j *JPush) request(ctx context.Context, po body.PushObj, resp interface{}, timeout int) error {
return http2.PostReturn( return http2.PostReturn(
ctx, ctx,
config.Config.Push.Jpns.PushUrl, config.Config.Push.Jpns.PushUrl,
+1 -9
View File
@@ -16,7 +16,6 @@ package push
import ( import (
"context" "context"
"github.com/OpenIMSDK/tools/utils"
"sync" "sync"
"google.golang.org/grpc" "google.golang.org/grpc"
@@ -79,14 +78,7 @@ func (r *pushServer) PushMsg(ctx context.Context, pbData *pbpush.PushMsgReq) (re
case constant.SuperGroupChatType: case constant.SuperGroupChatType:
err = r.pusher.Push2SuperGroup(ctx, pbData.MsgData.GroupID, pbData.MsgData) err = r.pusher.Push2SuperGroup(ctx, pbData.MsgData.GroupID, pbData.MsgData)
default: default:
var pushUserIDList []string err = r.pusher.Push2User(ctx, []string{pbData.MsgData.RecvID, pbData.MsgData.SendID}, pbData.MsgData)
isSenderSync := utils.GetSwitchFromOptions(pbData.MsgData.Options, constant.IsSenderSync)
if !isSenderSync {
pushUserIDList = append(pushUserIDList, pbData.MsgData.RecvID)
} else {
pushUserIDList = append(pushUserIDList, pbData.MsgData.RecvID, pbData.MsgData.SendID)
}
err = r.pusher.Push2User(ctx, pushUserIDList, pbData.MsgData)
} }
if err != nil { if err != nil {
if err != errNoOfflinePusher { if err != errNoOfflinePusher {
+12 -40
View File
@@ -18,9 +18,8 @@ import (
"context" "context"
"encoding/json" "encoding/json"
"errors" "errors"
"sync"
"golang.org/x/sync/errgroup" "github.com/openimsdk/open-im-server/v3/pkg/msgprocessor"
"github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/protocol/constant"
"github.com/OpenIMSDK/protocol/conversation" "github.com/OpenIMSDK/protocol/conversation"
@@ -41,7 +40,6 @@ import (
"github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/localcache" "github.com/openimsdk/open-im-server/v3/pkg/common/db/localcache"
"github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics" "github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics"
"github.com/openimsdk/open-im-server/v3/pkg/msgprocessor"
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
) )
@@ -133,7 +131,7 @@ func (p *Pusher) Push2User(ctx context.Context, userIDs []string, msg *sdkws.Msg
return nil return nil
} }
func (p *Pusher) UnmarshalNotificationElem(bytes []byte, t any) error { func (p *Pusher) UnmarshalNotificationElem(bytes []byte, t interface{}) error {
var notification sdkws.NotificationElem var notification sdkws.NotificationElem
if err := json.Unmarshal(bytes, &notification); err != nil { if err := json.Unmarshal(bytes, &notification); err != nil {
return err return err
@@ -287,44 +285,18 @@ func (p *Pusher) GetConnsAndOnlinePush(ctx context.Context, msg *sdkws.MsgData,
if err != nil { if err != nil {
return nil, err return nil, err
} }
var (
mu sync.Mutex
wg = errgroup.Group{}
input = &msggateway.OnlineBatchPushOneMsgReq{MsgData: msg, PushToUserIDs: pushToUserIDs}
maxWorkers = config.Config.Push.MaxConcurrentWorkers
)
if maxWorkers < 3 {
maxWorkers = 3
}
wg.SetLimit(maxWorkers)
// Online push message // Online push message
for _, conn := range conns { for _, v := range conns {
conn := conn // loop var safe msgClient := msggateway.NewMsgGatewayClient(v)
wg.Go(func() error { reply, err := msgClient.SuperGroupOnlineBatchPushOneMsg(ctx, &msggateway.OnlineBatchPushOneMsgReq{MsgData: msg, PushToUserIDs: pushToUserIDs})
msgClient := msggateway.NewMsgGatewayClient(conn) if err != nil {
reply, err := msgClient.SuperGroupOnlineBatchPushOneMsg(ctx, input) continue
if err != nil { }
return nil log.ZDebug(ctx, "push result", "reply", reply)
} if reply != nil && reply.SinglePushResult != nil {
wsResults = append(wsResults, reply.SinglePushResult...)
log.ZDebug(ctx, "push result", "reply", reply) }
if reply != nil && reply.SinglePushResult != nil {
mu.Lock()
wsResults = append(wsResults, reply.SinglePushResult...)
mu.Unlock()
}
return nil
})
} }
_ = wg.Wait()
// always return nil
return wsResults, nil return wsResults, nil
} }
+18 -23
View File
@@ -16,12 +16,6 @@ package conversation
import ( import (
"context" "context"
"errors"
"github.com/OpenIMSDK/tools/tx"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/mgo"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/unrelation"
"google.golang.org/grpc" "google.golang.org/grpc"
@@ -30,11 +24,13 @@ import (
"github.com/OpenIMSDK/tools/discoveryregistry" "github.com/OpenIMSDK/tools/discoveryregistry"
"github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/errs"
"github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/log"
"github.com/OpenIMSDK/tools/tx"
"github.com/OpenIMSDK/tools/utils" "github.com/OpenIMSDK/tools/utils"
"github.com/openimsdk/open-im-server/v3/pkg/common/convert" "github.com/openimsdk/open-im-server/v3/pkg/common/convert"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/relation"
tablerelation "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" tablerelation "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient/notification" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient/notification"
@@ -47,24 +43,24 @@ type conversationServer struct {
} }
func Start(client discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) error { func Start(client discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) error {
db, err := relation.NewGormDB()
if err != nil {
return err
}
if err := db.AutoMigrate(&tablerelation.ConversationModel{}); err != nil {
return err
}
rdb, err := cache.NewRedis() rdb, err := cache.NewRedis()
if err != nil { if err != nil {
return err return err
} }
mongo, err := unrelation.NewMongo() conversationDB := relation.NewConversationGorm(db)
if err != nil {
return err
}
conversationDB, err := mgo.NewConversationMongo(mongo.GetDatabase())
if err != nil {
return err
}
groupRpcClient := rpcclient.NewGroupRpcClient(client) groupRpcClient := rpcclient.NewGroupRpcClient(client)
msgRpcClient := rpcclient.NewMessageRpcClient(client) msgRpcClient := rpcclient.NewMessageRpcClient(client)
pbconversation.RegisterConversationServer(server, &conversationServer{ pbconversation.RegisterConversationServer(server, &conversationServer{
conversationNotificationSender: notification.NewConversationNotificationSender(&msgRpcClient), conversationNotificationSender: notification.NewConversationNotificationSender(&msgRpcClient),
groupRpcClient: &groupRpcClient, groupRpcClient: &groupRpcClient,
conversationDatabase: controller.NewConversationDatabase(conversationDB, cache.NewConversationRedis(rdb, cache.GetDefaultOpt(), conversationDB), tx.NewMongo(mongo.GetClient())), conversationDatabase: controller.NewConversationDatabase(conversationDB, cache.NewConversationRedis(rdb, cache.GetDefaultOpt(), conversationDB), tx.NewGorm(db)),
}) })
return nil return nil
} }
@@ -149,7 +145,7 @@ func (c *conversationServer) SetConversations(ctx context.Context,
conversation.ConversationType = req.Conversation.ConversationType conversation.ConversationType = req.Conversation.ConversationType
conversation.UserID = req.Conversation.UserID conversation.UserID = req.Conversation.UserID
conversation.GroupID = req.Conversation.GroupID conversation.GroupID = req.Conversation.GroupID
m := make(map[string]any) m := make(map[string]interface{})
if req.Conversation.RecvMsgOpt != nil { if req.Conversation.RecvMsgOpt != nil {
m["recv_msg_opt"] = req.Conversation.RecvMsgOpt.Value m["recv_msg_opt"] = req.Conversation.RecvMsgOpt.Value
if req.Conversation.RecvMsgOpt.Value != conv.RecvMsgOpt { if req.Conversation.RecvMsgOpt.Value != conv.RecvMsgOpt {
@@ -233,12 +229,11 @@ func (c *conversationServer) SetConversations(ctx context.Context,
// 获取超级大群开启免打扰的用户ID. // 获取超级大群开启免打扰的用户ID.
func (c *conversationServer) GetRecvMsgNotNotifyUserIDs(ctx context.Context, req *pbconversation.GetRecvMsgNotNotifyUserIDsReq) (*pbconversation.GetRecvMsgNotNotifyUserIDsResp, error) { func (c *conversationServer) GetRecvMsgNotNotifyUserIDs(ctx context.Context, req *pbconversation.GetRecvMsgNotNotifyUserIDsReq) (*pbconversation.GetRecvMsgNotNotifyUserIDsResp, error) {
//userIDs, err := c.conversationDatabase.FindRecvMsgNotNotifyUserIDs(ctx, req.GroupID) userIDs, err := c.conversationDatabase.FindRecvMsgNotNotifyUserIDs(ctx, req.GroupID)
//if err != nil { if err != nil {
// return nil, err return nil, err
//} }
//return &pbconversation.GetRecvMsgNotNotifyUserIDsResp{UserIDs: userIDs}, nil return &pbconversation.GetRecvMsgNotNotifyUserIDsResp{UserIDs: userIDs}, nil
return nil, errors.New("deprecated")
} }
// create conversation without notification for msg redis transfer. // create conversation without notification for msg redis transfer.
@@ -289,7 +284,7 @@ func (c *conversationServer) CreateGroupChatConversations(ctx context.Context, r
func (c *conversationServer) SetConversationMaxSeq(ctx context.Context, req *pbconversation.SetConversationMaxSeqReq) (*pbconversation.SetConversationMaxSeqResp, error) { func (c *conversationServer) SetConversationMaxSeq(ctx context.Context, req *pbconversation.SetConversationMaxSeqReq) (*pbconversation.SetConversationMaxSeqResp, error) {
if err := c.conversationDatabase.UpdateUsersConversationFiled(ctx, req.OwnerUserID, req.ConversationID, if err := c.conversationDatabase.UpdateUsersConversationFiled(ctx, req.OwnerUserID, req.ConversationID,
map[string]any{"max_seq": req.MaxSeq}); err != nil { map[string]interface{}{"max_seq": req.MaxSeq}); err != nil {
return nil, err return nil, err
} }
return &pbconversation.SetConversationMaxSeqResp{}, nil return &pbconversation.SetConversationMaxSeqResp{}, nil
+14 -3
View File
@@ -27,11 +27,19 @@ import (
"github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
) )
func (s *friendServer) GetPaginationBlacks(ctx context.Context, req *pbfriend.GetPaginationBlacksReq) (resp *pbfriend.GetPaginationBlacksResp, err error) { func (s *friendServer) GetPaginationBlacks(
ctx context.Context,
req *pbfriend.GetPaginationBlacksReq,
) (resp *pbfriend.GetPaginationBlacksResp, err error) {
if err := s.userRpcClient.Access(ctx, req.UserID); err != nil { if err := s.userRpcClient.Access(ctx, req.UserID); err != nil {
return nil, err return nil, err
} }
total, blacks, err := s.blackDatabase.FindOwnerBlacks(ctx, req.UserID, req.Pagination) var pageNumber, showNumber int32
if req.Pagination != nil {
pageNumber = req.Pagination.PageNumber
showNumber = req.Pagination.ShowNumber
}
blacks, total, err := s.blackDatabase.FindOwnerBlacks(ctx, req.UserID, pageNumber, showNumber)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -55,7 +63,10 @@ func (s *friendServer) IsBlack(ctx context.Context, req *pbfriend.IsBlackReq) (*
return resp, nil return resp, nil
} }
func (s *friendServer) RemoveBlack(ctx context.Context, req *pbfriend.RemoveBlackReq) (*pbfriend.RemoveBlackResp, error) { func (s *friendServer) RemoveBlack(
ctx context.Context,
req *pbfriend.RemoveBlackReq,
) (*pbfriend.RemoveBlackResp, error) {
if err := s.userRpcClient.Access(ctx, req.OwnerUserID); err != nil { if err := s.userRpcClient.Access(ctx, req.OwnerUserID); err != nil {
return nil, err return nil, err
} }
+10 -151
View File
@@ -16,8 +16,12 @@ package friend
import ( import (
"context" "context"
"github.com/OpenIMSDK/protocol/constant"
pbfriend "github.com/OpenIMSDK/protocol/friend" pbfriend "github.com/OpenIMSDK/protocol/friend"
"github.com/OpenIMSDK/tools/utils" "github.com/OpenIMSDK/tools/errs"
"github.com/OpenIMSDK/tools/mcontext"
cbapi "github.com/openimsdk/open-im-server/v3/pkg/callbackstruct" cbapi "github.com/openimsdk/open-im-server/v3/pkg/callbackstruct"
"github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/config"
"github.com/openimsdk/open-im-server/v3/pkg/common/http" "github.com/openimsdk/open-im-server/v3/pkg/common/http"
@@ -28,162 +32,17 @@ func CallbackBeforeAddFriend(ctx context.Context, req *pbfriend.ApplyToAddFriend
return nil return nil
} }
cbReq := &cbapi.CallbackBeforeAddFriendReq{ cbReq := &cbapi.CallbackBeforeAddFriendReq{
CallbackCommand: cbapi.CallbackBeforeAddFriendCommand, CallbackCommand: constant.CallbackBeforeAddFriendCommand,
FromUserID: req.FromUserID, FromUserID: req.FromUserID,
ToUserID: req.ToUserID, ToUserID: req.ToUserID,
ReqMsg: req.ReqMsg, ReqMsg: req.ReqMsg,
Ex: req.Ex, OperationID: mcontext.GetOperationID(ctx),
} }
resp := &cbapi.CallbackBeforeAddFriendResp{} resp := &cbapi.CallbackBeforeAddFriendResp{}
if err := http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, cbReq, resp, config.Config.Callback.CallbackBeforeAddFriend); err != nil { if err := http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, cbReq, resp, config.Config.Callback.CallbackBeforeAddFriend); err != nil {
return err if err == errs.ErrCallbackContinue {
} return nil
return nil }
}
func CallbackBeforeSetFriendRemark(ctx context.Context, req *pbfriend.SetFriendRemarkReq) error {
if !config.Config.Callback.CallbackBeforeSetFriendRemark.Enable {
return nil
}
cbReq := &cbapi.CallbackBeforeSetFriendRemarkReq{
CallbackCommand: cbapi.CallbackBeforeSetFriendRemark,
OwnerUserID: req.OwnerUserID,
FriendUserID: req.FriendUserID,
Remark: req.Remark,
}
resp := &cbapi.CallbackBeforeSetFriendRemarkResp{}
if err := http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, cbReq, resp, config.Config.Callback.CallbackBeforeAddFriend); err != nil {
return err
}
utils.NotNilReplace(&req.Remark, &resp.Remark)
return nil
}
func CallbackAfterSetFriendRemark(ctx context.Context, req *pbfriend.SetFriendRemarkReq) error {
if !config.Config.Callback.CallbackAfterSetFriendRemark.Enable {
return nil
}
cbReq := &cbapi.CallbackAfterSetFriendRemarkReq{
CallbackCommand: cbapi.CallbackAfterSetFriendRemark,
OwnerUserID: req.OwnerUserID,
FriendUserID: req.FriendUserID,
Remark: req.Remark,
}
resp := &cbapi.CallbackAfterSetFriendRemarkResp{}
if err := http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, cbReq, resp, config.Config.Callback.CallbackBeforeAddFriend); err != nil {
return err
}
return nil
}
func CallbackBeforeAddBlack(ctx context.Context, req *pbfriend.AddBlackReq) error {
if !config.Config.Callback.CallbackBeforeAddBlack.Enable {
return nil
}
cbReq := &cbapi.CallbackBeforeAddBlackReq{
CallbackCommand: cbapi.CallbackBeforeAddBlackCommand,
OwnerUserID: req.OwnerUserID,
BlackUserID: req.BlackUserID,
}
resp := &cbapi.CallbackBeforeAddBlackResp{}
if err := http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, cbReq, resp, config.Config.Callback.CallbackBeforeAddBlack); err != nil {
return err
}
return nil
}
func CallbackAfterAddFriend(ctx context.Context, req *pbfriend.ApplyToAddFriendReq) error {
if !config.Config.Callback.CallbackAfterAddFriend.Enable {
return nil
}
cbReq := &cbapi.CallbackAfterAddFriendReq{
CallbackCommand: cbapi.CallbackAfterAddFriendCommand,
FromUserID: req.FromUserID,
ToUserID: req.ToUserID,
ReqMsg: req.ReqMsg,
}
resp := &cbapi.CallbackAfterAddFriendResp{}
if err := http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, cbReq, resp, config.Config.Callback.CallbackAfterAddFriend); err != nil {
return err
}
return nil
}
func CallbackBeforeAddFriendAgree(ctx context.Context, req *pbfriend.RespondFriendApplyReq) error {
if !config.Config.Callback.CallbackBeforeAddFriendAgree.Enable {
return nil
}
cbReq := &cbapi.CallbackBeforeAddFriendAgreeReq{
CallbackCommand: cbapi.CallbackBeforeAddFriendAgreeCommand,
FromUserID: req.FromUserID,
ToUserID: req.ToUserID,
HandleMsg: req.HandleMsg,
HandleResult: req.HandleResult,
}
resp := &cbapi.CallbackBeforeAddFriendAgreeResp{}
if err := http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, cbReq, resp, config.Config.Callback.CallbackBeforeAddFriendAgree); err != nil {
return err
}
return nil
}
func CallbackAfterDeleteFriend(ctx context.Context, req *pbfriend.DeleteFriendReq) error {
if !config.Config.Callback.CallbackAfterDeleteFriend.Enable {
return nil
}
cbReq := &cbapi.CallbackAfterDeleteFriendReq{
CallbackCommand: cbapi.CallbackAfterDeleteFriendCommand,
OwnerUserID: req.OwnerUserID,
FriendUserID: req.FriendUserID,
}
resp := &cbapi.CallbackAfterDeleteFriendResp{}
if err := http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, cbReq, resp, config.Config.Callback.CallbackAfterDeleteFriend); err != nil {
return err
}
return nil
}
func CallbackBeforeImportFriends(ctx context.Context, req *pbfriend.ImportFriendReq) error {
if !config.Config.Callback.CallbackBeforeImportFriends.Enable {
return nil
}
cbReq := &cbapi.CallbackBeforeImportFriendsReq{
CallbackCommand: cbapi.CallbackBeforeImportFriendsCommand,
OwnerUserID: req.OwnerUserID,
FriendUserIDs: req.FriendUserIDs,
}
resp := &cbapi.CallbackBeforeImportFriendsResp{}
if err := http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, cbReq, resp, config.Config.Callback.CallbackBeforeImportFriends); err != nil {
return err
}
if len(resp.FriendUserIDs) != 0 {
req.FriendUserIDs = resp.FriendUserIDs
}
return nil
}
func CallbackAfterImportFriends(ctx context.Context, req *pbfriend.ImportFriendReq) error {
if !config.Config.Callback.CallbackAfterImportFriends.Enable {
return nil
}
cbReq := &cbapi.CallbackAfterImportFriendsReq{
CallbackCommand: cbapi.CallbackAfterImportFriendsCommand,
OwnerUserID: req.OwnerUserID,
FriendUserIDs: req.FriendUserIDs,
}
resp := &cbapi.CallbackAfterImportFriendsResp{}
if err := http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, cbReq, resp, config.Config.Callback.CallbackAfterImportFriends); err != nil {
return err
}
return nil
}
func CallbackAfterRemoveBlack(ctx context.Context, req *pbfriend.RemoveBlackReq) error {
if !config.Config.Callback.CallbackAfterRemoveBlack.Enable {
return nil
}
cbReq := &cbapi.CallbackAfterRemoveBlackReq{
CallbackCommand: cbapi.CallbackAfterRemoveBlackCommand,
OwnerUserID: req.OwnerUserID,
BlackUserID: req.BlackUserID,
}
resp := &cbapi.CallbackAfterRemoveBlackResp{}
if err := http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, cbReq, resp, config.Config.Callback.CallbackAfterRemoveBlack); err != nil {
return err return err
} }
return nil return nil
+62 -76
View File
@@ -16,7 +16,6 @@ package friend
import ( import (
"context" "context"
"github.com/OpenIMSDK/tools/tx"
"github.com/OpenIMSDK/protocol/sdkws" "github.com/OpenIMSDK/protocol/sdkws"
@@ -33,13 +32,13 @@ import (
pbfriend "github.com/OpenIMSDK/protocol/friend" pbfriend "github.com/OpenIMSDK/protocol/friend"
registry "github.com/OpenIMSDK/tools/discoveryregistry" registry "github.com/OpenIMSDK/tools/discoveryregistry"
"github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/errs"
"github.com/OpenIMSDK/tools/tx"
"github.com/OpenIMSDK/tools/utils" "github.com/OpenIMSDK/tools/utils"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/mgo" "github.com/openimsdk/open-im-server/v3/pkg/common/db/relation"
tablerelation "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" tablerelation "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/unrelation"
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient/notification" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient/notification"
) )
@@ -52,70 +51,50 @@ type friendServer struct {
RegisterCenter registry.SvcDiscoveryRegistry RegisterCenter registry.SvcDiscoveryRegistry
} }
func (s *friendServer) PinFriends(ctx context.Context, req *pbfriend.PinFriendsReq) (*pbfriend.PinFriendsResp, error) {
return nil, errs.ErrInternalServer.Wrap("not implemented")
}
func Start(client registry.SvcDiscoveryRegistry, server *grpc.Server) error { func Start(client registry.SvcDiscoveryRegistry, server *grpc.Server) error {
// Initialize MongoDB db, err := relation.NewGormDB()
mongo, err := unrelation.NewMongo()
if err != nil { if err != nil {
return err return err
} }
if err := db.AutoMigrate(&tablerelation.FriendModel{}, &tablerelation.FriendRequestModel{}, &tablerelation.BlackModel{}); err != nil {
// Initialize Redis return err
}
rdb, err := cache.NewRedis() rdb, err := cache.NewRedis()
if err != nil { if err != nil {
return err return err
} }
blackDB := relation.NewBlackGorm(db)
friendMongoDB, err := mgo.NewFriendMongo(mongo.GetDatabase()) friendDB := relation.NewFriendGorm(db)
if err != nil {
return err
}
friendRequestMongoDB, err := mgo.NewFriendRequestMongo(mongo.GetDatabase())
if err != nil {
return err
}
blackMongoDB, err := mgo.NewBlackMongo(mongo.GetDatabase())
if err != nil {
return err
}
// Initialize RPC clients
userRpcClient := rpcclient.NewUserRpcClient(client) userRpcClient := rpcclient.NewUserRpcClient(client)
msgRpcClient := rpcclient.NewMessageRpcClient(client) msgRpcClient := rpcclient.NewMessageRpcClient(client)
// Initialize notification sender
notificationSender := notification.NewFriendNotificationSender( notificationSender := notification.NewFriendNotificationSender(
&msgRpcClient, &msgRpcClient,
notification.WithRpcFunc(userRpcClient.GetUsersInfo), notification.WithRpcFunc(userRpcClient.GetUsersInfo),
) )
// Register Friend server with refactored MongoDB and Redis integrations
pbfriend.RegisterFriendServer(server, &friendServer{ pbfriend.RegisterFriendServer(server, &friendServer{
friendDatabase: controller.NewFriendDatabase( friendDatabase: controller.NewFriendDatabase(
friendMongoDB, friendDB,
friendRequestMongoDB, relation.NewFriendRequestGorm(db),
cache.NewFriendCacheRedis(rdb, friendMongoDB, cache.GetDefaultOpt()), cache.NewFriendCacheRedis(rdb, friendDB, cache.GetDefaultOpt()),
tx.NewMongo(mongo.GetClient()), tx.NewGorm(db),
), ),
blackDatabase: controller.NewBlackDatabase( blackDatabase: controller.NewBlackDatabase(
blackMongoDB, blackDB,
cache.NewBlackCacheRedis(rdb, blackMongoDB, cache.GetDefaultOpt()), cache.NewBlackCacheRedis(rdb, blackDB, cache.GetDefaultOpt()),
), ),
userRpcClient: &userRpcClient, userRpcClient: &userRpcClient,
notificationSender: notificationSender, notificationSender: notificationSender,
RegisterCenter: client, RegisterCenter: client,
conversationRpcClient: rpcclient.NewConversationRpcClient(client), conversationRpcClient: rpcclient.NewConversationRpcClient(client),
}) })
return nil return nil
} }
// ok. // ok.
func (s *friendServer) ApplyToAddFriend(ctx context.Context, req *pbfriend.ApplyToAddFriendReq) (resp *pbfriend.ApplyToAddFriendResp, err error) { func (s *friendServer) ApplyToAddFriend(
ctx context.Context,
req *pbfriend.ApplyToAddFriendReq,
) (resp *pbfriend.ApplyToAddFriendResp, err error) {
defer log.ZInfo(ctx, utils.GetFuncName()+" Return") defer log.ZInfo(ctx, utils.GetFuncName()+" Return")
resp = &pbfriend.ApplyToAddFriendResp{} resp = &pbfriend.ApplyToAddFriendResp{}
if err := authverify.CheckAccessV3(ctx, req.FromUserID); err != nil { if err := authverify.CheckAccessV3(ctx, req.FromUserID); err != nil {
@@ -124,7 +103,7 @@ func (s *friendServer) ApplyToAddFriend(ctx context.Context, req *pbfriend.Apply
if req.ToUserID == req.FromUserID { if req.ToUserID == req.FromUserID {
return nil, errs.ErrCanNotAddYourself.Wrap() return nil, errs.ErrCanNotAddYourself.Wrap()
} }
if err = CallbackBeforeAddFriend(ctx, req); err != nil && err != errs.ErrCallbackContinue { if err := CallbackBeforeAddFriend(ctx, req); err != nil && err != errs.ErrCallbackContinue {
return nil, err return nil, err
} }
if _, err := s.userRpcClient.GetUsersInfoMap(ctx, []string{req.ToUserID, req.FromUserID}); err != nil { if _, err := s.userRpcClient.GetUsersInfoMap(ctx, []string{req.ToUserID, req.FromUserID}); err != nil {
@@ -141,14 +120,14 @@ func (s *friendServer) ApplyToAddFriend(ctx context.Context, req *pbfriend.Apply
return nil, err return nil, err
} }
s.notificationSender.FriendApplicationAddNotification(ctx, req) s.notificationSender.FriendApplicationAddNotification(ctx, req)
if err = CallbackAfterAddFriend(ctx, req); err != nil && err != errs.ErrCallbackContinue {
return nil, err
}
return resp, nil return resp, nil
} }
// ok. // ok.
func (s *friendServer) ImportFriends(ctx context.Context, req *pbfriend.ImportFriendReq) (resp *pbfriend.ImportFriendResp, err error) { func (s *friendServer) ImportFriends(
ctx context.Context,
req *pbfriend.ImportFriendReq,
) (resp *pbfriend.ImportFriendResp, err error) {
defer log.ZInfo(ctx, utils.GetFuncName()+" Return") defer log.ZInfo(ctx, utils.GetFuncName()+" Return")
if err := authverify.CheckAdmin(ctx); err != nil { if err := authverify.CheckAdmin(ctx); err != nil {
return nil, err return nil, err
@@ -162,10 +141,6 @@ func (s *friendServer) ImportFriends(ctx context.Context, req *pbfriend.ImportFr
if utils.Duplicate(req.FriendUserIDs) { if utils.Duplicate(req.FriendUserIDs) {
return nil, errs.ErrArgs.Wrap("friend userID repeated") return nil, errs.ErrArgs.Wrap("friend userID repeated")
} }
if err := CallbackBeforeImportFriends(ctx, req); err != nil {
return nil, err
}
if err := s.friendDatabase.BecomeFriends(ctx, req.OwnerUserID, req.FriendUserIDs, constant.BecomeFriendByImport); err != nil { if err := s.friendDatabase.BecomeFriends(ctx, req.OwnerUserID, req.FriendUserIDs, constant.BecomeFriendByImport); err != nil {
return nil, err return nil, err
} }
@@ -176,14 +151,14 @@ func (s *friendServer) ImportFriends(ctx context.Context, req *pbfriend.ImportFr
HandleResult: constant.FriendResponseAgree, HandleResult: constant.FriendResponseAgree,
}) })
} }
if err := CallbackAfterImportFriends(ctx, req); err != nil {
return nil, err
}
return &pbfriend.ImportFriendResp{}, nil return &pbfriend.ImportFriendResp{}, nil
} }
// ok. // ok.
func (s *friendServer) RespondFriendApply(ctx context.Context, req *pbfriend.RespondFriendApplyReq) (resp *pbfriend.RespondFriendApplyResp, err error) { func (s *friendServer) RespondFriendApply(
ctx context.Context,
req *pbfriend.RespondFriendApplyReq,
) (resp *pbfriend.RespondFriendApplyResp, err error) {
defer log.ZInfo(ctx, utils.GetFuncName()+" Return") defer log.ZInfo(ctx, utils.GetFuncName()+" Return")
resp = &pbfriend.RespondFriendApplyResp{} resp = &pbfriend.RespondFriendApplyResp{}
if err := authverify.CheckAccessV3(ctx, req.ToUserID); err != nil { if err := authverify.CheckAccessV3(ctx, req.ToUserID); err != nil {
@@ -197,9 +172,6 @@ func (s *friendServer) RespondFriendApply(ctx context.Context, req *pbfriend.Res
HandleResult: req.HandleResult, HandleResult: req.HandleResult,
} }
if req.HandleResult == constant.FriendResponseAgree { if req.HandleResult == constant.FriendResponseAgree {
if err := CallbackBeforeAddFriendAgree(ctx, req); err != nil && err != errs.ErrCallbackContinue {
return nil, err
}
err := s.friendDatabase.AgreeFriendRequest(ctx, &friendRequest) err := s.friendDatabase.AgreeFriendRequest(ctx, &friendRequest)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -219,7 +191,10 @@ func (s *friendServer) RespondFriendApply(ctx context.Context, req *pbfriend.Res
} }
// ok. // ok.
func (s *friendServer) DeleteFriend(ctx context.Context, req *pbfriend.DeleteFriendReq) (resp *pbfriend.DeleteFriendResp, err error) { func (s *friendServer) DeleteFriend(
ctx context.Context,
req *pbfriend.DeleteFriendReq,
) (resp *pbfriend.DeleteFriendResp, err error) {
defer log.ZInfo(ctx, utils.GetFuncName()+" Return") defer log.ZInfo(ctx, utils.GetFuncName()+" Return")
resp = &pbfriend.DeleteFriendResp{} resp = &pbfriend.DeleteFriendResp{}
if err := s.userRpcClient.Access(ctx, req.OwnerUserID); err != nil { if err := s.userRpcClient.Access(ctx, req.OwnerUserID); err != nil {
@@ -233,19 +208,15 @@ func (s *friendServer) DeleteFriend(ctx context.Context, req *pbfriend.DeleteFri
return nil, err return nil, err
} }
s.notificationSender.FriendDeletedNotification(ctx, req) s.notificationSender.FriendDeletedNotification(ctx, req)
if err := CallbackAfterDeleteFriend(ctx, req); err != nil {
return nil, err
}
return resp, nil return resp, nil
} }
// ok. // ok.
func (s *friendServer) SetFriendRemark(ctx context.Context, req *pbfriend.SetFriendRemarkReq) (resp *pbfriend.SetFriendRemarkResp, err error) { func (s *friendServer) SetFriendRemark(
ctx context.Context,
req *pbfriend.SetFriendRemarkReq,
) (resp *pbfriend.SetFriendRemarkResp, err error) {
defer log.ZInfo(ctx, utils.GetFuncName()+" Return") defer log.ZInfo(ctx, utils.GetFuncName()+" Return")
if err = CallbackBeforeSetFriendRemark(ctx, req); err != nil && err != errs.ErrCallbackContinue {
return nil, err
}
resp = &pbfriend.SetFriendRemarkResp{} resp = &pbfriend.SetFriendRemarkResp{}
if err := s.userRpcClient.Access(ctx, req.OwnerUserID); err != nil { if err := s.userRpcClient.Access(ctx, req.OwnerUserID); err != nil {
return nil, err return nil, err
@@ -257,15 +228,15 @@ func (s *friendServer) SetFriendRemark(ctx context.Context, req *pbfriend.SetFri
if err := s.friendDatabase.UpdateRemark(ctx, req.OwnerUserID, req.FriendUserID, req.Remark); err != nil { if err := s.friendDatabase.UpdateRemark(ctx, req.OwnerUserID, req.FriendUserID, req.Remark); err != nil {
return nil, err return nil, err
} }
if err := CallbackAfterSetFriendRemark(ctx, req); err != nil && err != errs.ErrCallbackContinue {
return nil, err
}
s.notificationSender.FriendRemarkSetNotification(ctx, req.OwnerUserID, req.FriendUserID) s.notificationSender.FriendRemarkSetNotification(ctx, req.OwnerUserID, req.FriendUserID)
return resp, nil return resp, nil
} }
// ok. // ok.
func (s *friendServer) GetDesignatedFriends(ctx context.Context, req *pbfriend.GetDesignatedFriendsReq) (resp *pbfriend.GetDesignatedFriendsResp, err error) { func (s *friendServer) GetDesignatedFriends(
ctx context.Context,
req *pbfriend.GetDesignatedFriendsReq,
) (resp *pbfriend.GetDesignatedFriendsResp, err error) {
defer log.ZInfo(ctx, utils.GetFuncName()+" Return") defer log.ZInfo(ctx, utils.GetFuncName()+" Return")
resp = &pbfriend.GetDesignatedFriendsResp{} resp = &pbfriend.GetDesignatedFriendsResp{}
if utils.Duplicate(req.FriendUserIDs) { if utils.Duplicate(req.FriendUserIDs) {
@@ -296,12 +267,15 @@ func (s *friendServer) GetDesignatedFriendsApply(ctx context.Context,
} }
// ok 获取接收到的好友申请(即别人主动申请的). // ok 获取接收到的好友申请(即别人主动申请的).
func (s *friendServer) GetPaginationFriendsApplyTo(ctx context.Context, req *pbfriend.GetPaginationFriendsApplyToReq) (resp *pbfriend.GetPaginationFriendsApplyToResp, err error) { func (s *friendServer) GetPaginationFriendsApplyTo(
ctx context.Context,
req *pbfriend.GetPaginationFriendsApplyToReq,
) (resp *pbfriend.GetPaginationFriendsApplyToResp, err error) {
defer log.ZInfo(ctx, utils.GetFuncName()+" Return") defer log.ZInfo(ctx, utils.GetFuncName()+" Return")
if err := s.userRpcClient.Access(ctx, req.UserID); err != nil { if err := s.userRpcClient.Access(ctx, req.UserID); err != nil {
return nil, err return nil, err
} }
total, friendRequests, err := s.friendDatabase.PageFriendRequestToMe(ctx, req.UserID, req.Pagination) friendRequests, total, err := s.friendDatabase.PageFriendRequestToMe(ctx, req.UserID, req.Pagination.PageNumber, req.Pagination.ShowNumber)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -315,13 +289,16 @@ func (s *friendServer) GetPaginationFriendsApplyTo(ctx context.Context, req *pbf
} }
// ok 获取主动发出去的好友申请列表. // ok 获取主动发出去的好友申请列表.
func (s *friendServer) GetPaginationFriendsApplyFrom(ctx context.Context, req *pbfriend.GetPaginationFriendsApplyFromReq) (resp *pbfriend.GetPaginationFriendsApplyFromResp, err error) { func (s *friendServer) GetPaginationFriendsApplyFrom(
ctx context.Context,
req *pbfriend.GetPaginationFriendsApplyFromReq,
) (resp *pbfriend.GetPaginationFriendsApplyFromResp, err error) {
defer log.ZInfo(ctx, utils.GetFuncName()+" Return") defer log.ZInfo(ctx, utils.GetFuncName()+" Return")
resp = &pbfriend.GetPaginationFriendsApplyFromResp{} resp = &pbfriend.GetPaginationFriendsApplyFromResp{}
if err := s.userRpcClient.Access(ctx, req.UserID); err != nil { if err := s.userRpcClient.Access(ctx, req.UserID); err != nil {
return nil, err return nil, err
} }
total, friendRequests, err := s.friendDatabase.PageFriendRequestFromMe(ctx, req.UserID, req.Pagination) friendRequests, total, err := s.friendDatabase.PageFriendRequestFromMe(ctx, req.UserID, req.Pagination.PageNumber, req.Pagination.ShowNumber)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -334,7 +311,10 @@ func (s *friendServer) GetPaginationFriendsApplyFrom(ctx context.Context, req *p
} }
// ok. // ok.
func (s *friendServer) IsFriend(ctx context.Context, req *pbfriend.IsFriendReq) (resp *pbfriend.IsFriendResp, err error) { func (s *friendServer) IsFriend(
ctx context.Context,
req *pbfriend.IsFriendReq,
) (resp *pbfriend.IsFriendResp, err error) {
defer log.ZInfo(ctx, utils.GetFuncName()+" Return") defer log.ZInfo(ctx, utils.GetFuncName()+" Return")
resp = &pbfriend.IsFriendResp{} resp = &pbfriend.IsFriendResp{}
resp.InUser1Friends, resp.InUser2Friends, err = s.friendDatabase.CheckIn(ctx, req.UserID1, req.UserID2) resp.InUser1Friends, resp.InUser2Friends, err = s.friendDatabase.CheckIn(ctx, req.UserID1, req.UserID2)
@@ -344,12 +324,15 @@ func (s *friendServer) IsFriend(ctx context.Context, req *pbfriend.IsFriendReq)
return resp, nil return resp, nil
} }
func (s *friendServer) GetPaginationFriends(ctx context.Context, req *pbfriend.GetPaginationFriendsReq) (resp *pbfriend.GetPaginationFriendsResp, err error) { func (s *friendServer) GetPaginationFriends(
ctx context.Context,
req *pbfriend.GetPaginationFriendsReq,
) (resp *pbfriend.GetPaginationFriendsResp, err error) {
defer log.ZInfo(ctx, utils.GetFuncName()+" Return") defer log.ZInfo(ctx, utils.GetFuncName()+" Return")
if err := s.userRpcClient.Access(ctx, req.UserID); err != nil { if err := s.userRpcClient.Access(ctx, req.UserID); err != nil {
return nil, err return nil, err
} }
total, friends, err := s.friendDatabase.PageOwnerFriends(ctx, req.UserID, req.Pagination) friends, total, err := s.friendDatabase.PageOwnerFriends(ctx, req.UserID, req.Pagination.PageNumber, req.Pagination.ShowNumber)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -362,7 +345,10 @@ func (s *friendServer) GetPaginationFriends(ctx context.Context, req *pbfriend.G
return resp, nil return resp, nil
} }
func (s *friendServer) GetFriendIDs(ctx context.Context, req *pbfriend.GetFriendIDsReq) (resp *pbfriend.GetFriendIDsResp, err error) { func (s *friendServer) GetFriendIDs(
ctx context.Context,
req *pbfriend.GetFriendIDsReq,
) (resp *pbfriend.GetFriendIDsResp, err error) {
defer log.ZInfo(ctx, utils.GetFuncName()+" Return") defer log.ZInfo(ctx, utils.GetFuncName()+" Return")
if err := s.userRpcClient.Access(ctx, req.UserID); err != nil { if err := s.userRpcClient.Access(ctx, req.UserID); err != nil {
return nil, err return nil, err
+2 -2
View File
@@ -26,7 +26,7 @@ func (s *groupServer) GetGroupInfoCache(
ctx context.Context, ctx context.Context,
req *pbgroup.GetGroupInfoCacheReq, req *pbgroup.GetGroupInfoCacheReq,
) (resp *pbgroup.GetGroupInfoCacheResp, err error) { ) (resp *pbgroup.GetGroupInfoCacheResp, err error) {
group, err := s.db.TakeGroup(ctx, req.GroupID) group, err := s.GroupDatabase.TakeGroup(ctx, req.GroupID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -38,7 +38,7 @@ func (s *groupServer) GetGroupMemberCache(
ctx context.Context, ctx context.Context,
req *pbgroup.GetGroupMemberCacheReq, req *pbgroup.GetGroupMemberCacheReq,
) (resp *pbgroup.GetGroupMemberCacheResp, err error) { ) (resp *pbgroup.GetGroupMemberCacheResp, err error) {
members, err := s.db.TakeGroupMember(ctx, req.GroupID, req.GroupMemberID) members, err := s.GroupDatabase.TakeGroupMember(ctx, req.GroupID, req.GroupMemberID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
+23 -275
View File
@@ -16,17 +16,15 @@ package group
import ( import (
"context" "context"
"github.com/OpenIMSDK/tools/log"
"time" "time"
"github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/protocol/constant"
"github.com/OpenIMSDK/protocol/group" "github.com/OpenIMSDK/protocol/group"
"github.com/OpenIMSDK/protocol/wrapperspb" "github.com/OpenIMSDK/protocol/wrapperspb"
"github.com/OpenIMSDK/tools/errs"
"github.com/OpenIMSDK/tools/mcontext" "github.com/OpenIMSDK/tools/mcontext"
"github.com/OpenIMSDK/tools/utils" "github.com/OpenIMSDK/tools/utils"
pbgroup "github.com/OpenIMSDK/protocol/group"
"github.com/openimsdk/open-im-server/v3/pkg/apistruct" "github.com/openimsdk/open-im-server/v3/pkg/apistruct"
"github.com/openimsdk/open-im-server/v3/pkg/callbackstruct" "github.com/openimsdk/open-im-server/v3/pkg/callbackstruct"
"github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/config"
@@ -39,7 +37,7 @@ func CallbackBeforeCreateGroup(ctx context.Context, req *group.CreateGroupReq) (
return nil return nil
} }
cbReq := &callbackstruct.CallbackBeforeCreateGroupReq{ cbReq := &callbackstruct.CallbackBeforeCreateGroupReq{
CallbackCommand: callbackstruct.CallbackBeforeCreateGroupCommand, CallbackCommand: constant.CallbackBeforeCreateGroupCommand,
OperationID: mcontext.GetOperationID(ctx), OperationID: mcontext.GetOperationID(ctx),
GroupInfo: req.GroupInfo, GroupInfo: req.GroupInfo,
} }
@@ -60,7 +58,17 @@ func CallbackBeforeCreateGroup(ctx context.Context, req *group.CreateGroupReq) (
}) })
} }
resp := &callbackstruct.CallbackBeforeCreateGroupResp{} resp := &callbackstruct.CallbackBeforeCreateGroupResp{}
if err = http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, cbReq, resp, config.Config.Callback.CallbackBeforeCreateGroup); err != nil { err = http.CallBackPostReturn(
ctx,
config.Config.Callback.CallbackUrl,
cbReq,
resp,
config.Config.Callback.CallbackBeforeCreateGroup,
)
if err != nil {
if err == errs.ErrCallbackContinue {
return nil
}
return err return err
} }
utils.NotNilReplace(&req.GroupInfo.GroupID, resp.GroupID) utils.NotNilReplace(&req.GroupInfo.GroupID, resp.GroupID)
@@ -78,37 +86,6 @@ func CallbackBeforeCreateGroup(ctx context.Context, req *group.CreateGroupReq) (
return nil return nil
} }
func CallbackAfterCreateGroup(ctx context.Context, req *group.CreateGroupReq) (err error) {
if !config.Config.Callback.CallbackAfterCreateGroup.Enable {
return nil
}
cbReq := &callbackstruct.CallbackAfterCreateGroupReq{
CallbackCommand: callbackstruct.CallbackAfterCreateGroupCommand,
GroupInfo: req.GroupInfo,
}
cbReq.InitMemberList = append(cbReq.InitMemberList, &apistruct.GroupAddMemberInfo{
UserID: req.OwnerUserID,
RoleLevel: constant.GroupOwner,
})
for _, userID := range req.AdminUserIDs {
cbReq.InitMemberList = append(cbReq.InitMemberList, &apistruct.GroupAddMemberInfo{
UserID: userID,
RoleLevel: constant.GroupAdmin,
})
}
for _, userID := range req.MemberUserIDs {
cbReq.InitMemberList = append(cbReq.InitMemberList, &apistruct.GroupAddMemberInfo{
UserID: userID,
RoleLevel: constant.GroupOrdinaryUsers,
})
}
resp := &callbackstruct.CallbackAfterCreateGroupResp{}
if err = http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, cbReq, resp, config.Config.Callback.CallbackAfterCreateGroup); err != nil {
return err
}
return nil
}
func CallbackBeforeMemberJoinGroup( func CallbackBeforeMemberJoinGroup(
ctx context.Context, ctx context.Context,
groupMember *relation.GroupMemberModel, groupMember *relation.GroupMemberModel,
@@ -118,7 +95,8 @@ func CallbackBeforeMemberJoinGroup(
return nil return nil
} }
callbackReq := &callbackstruct.CallbackBeforeMemberJoinGroupReq{ callbackReq := &callbackstruct.CallbackBeforeMemberJoinGroupReq{
CallbackCommand: callbackstruct.CallbackBeforeMemberJoinGroupCommand, CallbackCommand: constant.CallbackBeforeMemberJoinGroupCommand,
OperationID: mcontext.GetOperationID(ctx),
GroupID: groupMember.GroupID, GroupID: groupMember.GroupID,
UserID: groupMember.UserID, UserID: groupMember.UserID,
Ex: groupMember.Ex, Ex: groupMember.Ex,
@@ -133,6 +111,9 @@ func CallbackBeforeMemberJoinGroup(
config.Config.Callback.CallbackBeforeMemberJoinGroup, config.Config.Callback.CallbackBeforeMemberJoinGroup,
) )
if err != nil { if err != nil {
if err == errs.ErrCallbackContinue {
return nil
}
return err return err
} }
if resp.MuteEndTime != nil { if resp.MuteEndTime != nil {
@@ -150,7 +131,8 @@ func CallbackBeforeSetGroupMemberInfo(ctx context.Context, req *group.SetGroupMe
return nil return nil
} }
callbackReq := callbackstruct.CallbackBeforeSetGroupMemberInfoReq{ callbackReq := callbackstruct.CallbackBeforeSetGroupMemberInfoReq{
CallbackCommand: callbackstruct.CallbackBeforeSetGroupMemberInfoCommand, CallbackCommand: constant.CallbackBeforeSetGroupMemberInfoCommand,
OperationID: mcontext.GetOperationID(ctx),
GroupID: req.GroupID, GroupID: req.GroupID,
UserID: req.UserID, UserID: req.UserID,
} }
@@ -175,6 +157,9 @@ func CallbackBeforeSetGroupMemberInfo(ctx context.Context, req *group.SetGroupMe
config.Config.Callback.CallbackBeforeSetGroupMemberInfo, config.Config.Callback.CallbackBeforeSetGroupMemberInfo,
) )
if err != nil { if err != nil {
if err == errs.ErrCallbackContinue {
return nil
}
return err return err
} }
if resp.FaceURL != nil { if resp.FaceURL != nil {
@@ -191,240 +176,3 @@ func CallbackBeforeSetGroupMemberInfo(ctx context.Context, req *group.SetGroupMe
} }
return nil return nil
} }
func CallbackAfterSetGroupMemberInfo(ctx context.Context, req *group.SetGroupMemberInfo) (err error) {
if !config.Config.Callback.CallbackBeforeSetGroupMemberInfo.Enable {
return nil
}
callbackReq := callbackstruct.CallbackAfterSetGroupMemberInfoReq{
CallbackCommand: callbackstruct.CallbackAfterSetGroupMemberInfoCommand,
GroupID: req.GroupID,
UserID: req.UserID,
}
if req.Nickname != nil {
callbackReq.Nickname = &req.Nickname.Value
}
if req.FaceURL != nil {
callbackReq.FaceURL = &req.FaceURL.Value
}
if req.RoleLevel != nil {
callbackReq.RoleLevel = &req.RoleLevel.Value
}
if req.Ex != nil {
callbackReq.Ex = &req.Ex.Value
}
resp := &callbackstruct.CallbackAfterSetGroupMemberInfoResp{}
if err = http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, callbackReq, resp, config.Config.Callback.CallbackAfterSetGroupMemberInfo); err != nil {
return err
}
return nil
}
func CallbackQuitGroup(ctx context.Context, req *group.QuitGroupReq) (err error) {
if !config.Config.Callback.CallbackQuitGroup.Enable {
return nil
}
cbReq := &callbackstruct.CallbackQuitGroupReq{
CallbackCommand: callbackstruct.CallbackQuitGroupCommand,
GroupID: req.GroupID,
UserID: req.UserID,
}
resp := &callbackstruct.CallbackQuitGroupResp{}
if err = http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, cbReq, resp, config.Config.Callback.CallbackQuitGroup); err != nil {
return err
}
return nil
}
func CallbackKillGroupMember(ctx context.Context, req *pbgroup.KickGroupMemberReq) (err error) {
if !config.Config.Callback.CallbackKillGroupMember.Enable {
return nil
}
cbReq := &callbackstruct.CallbackKillGroupMemberReq{
CallbackCommand: callbackstruct.CallbackKillGroupCommand,
GroupID: req.GroupID,
KickedUserIDs: req.KickedUserIDs,
}
resp := &callbackstruct.CallbackKillGroupMemberResp{}
if err = http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, cbReq, resp, config.Config.Callback.CallbackQuitGroup); err != nil {
return err
}
return nil
}
func CallbackDismissGroup(ctx context.Context, req *callbackstruct.CallbackDisMissGroupReq) (err error) {
if !config.Config.Callback.CallbackDismissGroup.Enable {
return nil
}
req.CallbackCommand = callbackstruct.CallbackDisMissGroupCommand
resp := &callbackstruct.CallbackDisMissGroupResp{}
if err = http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, req, resp, config.Config.Callback.CallbackQuitGroup); err != nil {
return err
}
return nil
}
func CallbackApplyJoinGroupBefore(ctx context.Context, req *callbackstruct.CallbackJoinGroupReq) (err error) {
if !config.Config.Callback.CallbackBeforeJoinGroup.Enable {
return nil
}
req.CallbackCommand = callbackstruct.CallbackBeforeJoinGroupCommand
resp := &callbackstruct.CallbackJoinGroupResp{}
if err = http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, req, resp, config.Config.Callback.CallbackBeforeJoinGroup); err != nil {
return err
}
return nil
}
func CallbackTransferGroupOwnerAfter(ctx context.Context, req *pbgroup.TransferGroupOwnerReq) (err error) {
if !config.Config.Callback.CallbackTransferGroupOwnerAfter.Enable {
return nil
}
cbReq := &callbackstruct.CallbackTransferGroupOwnerReq{
CallbackCommand: callbackstruct.CallbackTransferGroupOwnerAfter,
GroupID: req.GroupID,
OldOwnerUserID: req.OldOwnerUserID,
NewOwnerUserID: req.NewOwnerUserID,
}
resp := &callbackstruct.CallbackTransferGroupOwnerResp{}
if err = http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, cbReq, resp, config.Config.Callback.CallbackBeforeJoinGroup); err != nil {
return err
}
return nil
}
func CallbackBeforeInviteUserToGroup(ctx context.Context, req *group.InviteUserToGroupReq) (err error) {
if !config.Config.Callback.CallbackBeforeInviteUserToGroup.Enable {
return nil
}
callbackReq := &callbackstruct.CallbackBeforeInviteUserToGroupReq{
CallbackCommand: callbackstruct.CallbackBeforeInviteJoinGroupCommand,
OperationID: mcontext.GetOperationID(ctx),
GroupID: req.GroupID,
Reason: req.Reason,
InvitedUserIDs: req.InvitedUserIDs,
}
resp := &callbackstruct.CallbackBeforeInviteUserToGroupResp{}
err = http.CallBackPostReturn(
ctx,
config.Config.Callback.CallbackUrl,
callbackReq,
resp,
config.Config.Callback.CallbackBeforeInviteUserToGroup,
)
if err != nil {
return err
}
if len(resp.RefusedMembersAccount) > 0 {
// Handle the scenario where certain members are refused
// You might want to update the req.Members list or handle it as per your business logic
}
utils.StructFieldNotNilReplace(req, resp)
return nil
}
func CallbackAfterJoinGroup(ctx context.Context, req *group.JoinGroupReq) error {
if !config.Config.Callback.CallbackAfterJoinGroup.Enable {
return nil
}
callbackReq := &callbackstruct.CallbackAfterJoinGroupReq{
CallbackCommand: callbackstruct.CallbackAfterJoinGroupCommand,
OperationID: mcontext.GetOperationID(ctx),
GroupID: req.GroupID,
ReqMessage: req.ReqMessage,
JoinSource: req.JoinSource,
InviterUserID: req.InviterUserID,
}
resp := &callbackstruct.CallbackAfterJoinGroupResp{}
if err := http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, callbackReq, resp, config.Config.Callback.CallbackAfterJoinGroup); err != nil {
return err
}
return nil
}
func CallbackBeforeSetGroupInfo(ctx context.Context, req *group.SetGroupInfoReq) error {
if !config.Config.Callback.CallbackBeforeSetGroupInfo.Enable {
return nil
}
callbackReq := &callbackstruct.CallbackBeforeSetGroupInfoReq{
CallbackCommand: callbackstruct.CallbackBeforeSetGroupInfoCommand,
GroupID: req.GroupInfoForSet.GroupID,
Notification: req.GroupInfoForSet.Notification,
Introduction: req.GroupInfoForSet.Introduction,
FaceURL: req.GroupInfoForSet.FaceURL,
GroupName: req.GroupInfoForSet.GroupName,
}
if req.GroupInfoForSet.Ex != nil {
callbackReq.Ex = req.GroupInfoForSet.Ex.Value
}
log.ZDebug(ctx, "debug CallbackBeforeSetGroupInfo", callbackReq.Ex)
if req.GroupInfoForSet.NeedVerification != nil {
callbackReq.NeedVerification = req.GroupInfoForSet.NeedVerification.Value
}
if req.GroupInfoForSet.LookMemberInfo != nil {
callbackReq.LookMemberInfo = req.GroupInfoForSet.LookMemberInfo.Value
}
if req.GroupInfoForSet.ApplyMemberFriend != nil {
callbackReq.ApplyMemberFriend = req.GroupInfoForSet.ApplyMemberFriend.Value
}
resp := &callbackstruct.CallbackBeforeSetGroupInfoResp{}
if err := http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, callbackReq, resp, config.Config.Callback.CallbackBeforeSetGroupInfo); err != nil {
return err
}
if resp.Ex != nil {
req.GroupInfoForSet.Ex = wrapperspb.String(*resp.Ex)
}
if resp.NeedVerification != nil {
req.GroupInfoForSet.NeedVerification = wrapperspb.Int32(*resp.NeedVerification)
}
if resp.LookMemberInfo != nil {
req.GroupInfoForSet.LookMemberInfo = wrapperspb.Int32(*resp.LookMemberInfo)
}
if resp.ApplyMemberFriend != nil {
req.GroupInfoForSet.ApplyMemberFriend = wrapperspb.Int32(*resp.ApplyMemberFriend)
}
utils.StructFieldNotNilReplace(req, resp)
return nil
}
func CallbackAfterSetGroupInfo(ctx context.Context, req *group.SetGroupInfoReq) error {
if !config.Config.Callback.CallbackAfterSetGroupInfo.Enable {
return nil
}
callbackReq := &callbackstruct.CallbackAfterSetGroupInfoReq{
CallbackCommand: callbackstruct.CallbackAfterSetGroupInfoCommand,
GroupID: req.GroupInfoForSet.GroupID,
Notification: req.GroupInfoForSet.Notification,
Introduction: req.GroupInfoForSet.Introduction,
FaceURL: req.GroupInfoForSet.FaceURL,
GroupName: req.GroupInfoForSet.GroupName,
}
if req.GroupInfoForSet.Ex != nil {
callbackReq.Ex = &req.GroupInfoForSet.Ex.Value
}
if req.GroupInfoForSet.NeedVerification != nil {
callbackReq.NeedVerification = &req.GroupInfoForSet.NeedVerification.Value
}
if req.GroupInfoForSet.LookMemberInfo != nil {
callbackReq.LookMemberInfo = &req.GroupInfoForSet.LookMemberInfo.Value
}
if req.GroupInfoForSet.ApplyMemberFriend != nil {
callbackReq.ApplyMemberFriend = &req.GroupInfoForSet.ApplyMemberFriend.Value
}
resp := &callbackstruct.CallbackAfterSetGroupInfoResp{}
if err := http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, callbackReq, resp, config.Config.Callback.CallbackAfterSetGroupInfo); err != nil {
return err
}
utils.StructFieldNotNilReplace(req, resp)
return nil
}
+1 -1
View File
@@ -27,7 +27,7 @@ import (
func UpdateGroupInfoMap(ctx context.Context, group *sdkws.GroupInfoForSet) map[string]any { func UpdateGroupInfoMap(ctx context.Context, group *sdkws.GroupInfoForSet) map[string]any {
m := make(map[string]any) m := make(map[string]any)
if group.GroupName != "" { if group.GroupName != "" {
m["group_name"] = group.GroupName m["name"] = group.GroupName
} }
if group.Notification != "" { if group.Notification != "" {
m["notification"] = group.Notification m["notification"] = group.Notification
+112 -2
View File
@@ -17,9 +17,119 @@ package group
import ( import (
"context" "context"
"github.com/OpenIMSDK/tools/utils"
relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
) )
func (s *groupServer) PopulateGroupMember(ctx context.Context, members ...*relationtb.GroupMemberModel) error { func (s *groupServer) FindGroupMember(ctx context.Context, groupIDs []string, userIDs []string, roleLevels []int32) ([]*relationtb.GroupMemberModel, error) {
return s.Notification.PopulateGroupMember(ctx, members...) members, err := s.GroupDatabase.FindGroupMember(ctx, groupIDs, userIDs, roleLevels)
if err != nil {
return nil, err
}
emptyUserIDs := make(map[string]struct{})
for _, member := range members {
if member.Nickname == "" || member.FaceURL == "" {
emptyUserIDs[member.UserID] = struct{}{}
}
}
if len(emptyUserIDs) > 0 {
users, err := s.User.GetPublicUserInfoMap(ctx, utils.Keys(emptyUserIDs), true)
if err != nil {
return nil, err
}
for i, member := range members {
user, ok := users[member.UserID]
if !ok {
continue
}
if member.Nickname == "" {
members[i].Nickname = user.Nickname
}
if member.FaceURL == "" {
members[i].FaceURL = user.FaceURL
}
}
}
return members, nil
}
func (s *groupServer) TakeGroupMember(
ctx context.Context,
groupID string,
userID string,
) (*relationtb.GroupMemberModel, error) {
member, err := s.GroupDatabase.TakeGroupMember(ctx, groupID, userID)
if err != nil {
return nil, err
}
if member.Nickname == "" || member.FaceURL == "" {
user, err := s.User.GetPublicUserInfo(ctx, userID)
if err != nil {
return nil, err
}
if member.Nickname == "" {
member.Nickname = user.Nickname
}
if member.FaceURL == "" {
member.FaceURL = user.FaceURL
}
}
return member, nil
}
func (s *groupServer) TakeGroupOwner(ctx context.Context, groupID string) (*relationtb.GroupMemberModel, error) {
owner, err := s.GroupDatabase.TakeGroupOwner(ctx, groupID)
if err != nil {
return nil, err
}
if owner.Nickname == "" || owner.FaceURL == "" {
user, err := s.User.GetUserInfo(ctx, owner.UserID)
if err != nil {
return nil, err
}
if owner.Nickname == "" {
owner.Nickname = user.Nickname
}
if owner.FaceURL == "" {
owner.FaceURL = user.FaceURL
}
}
return owner, nil
}
func (s *groupServer) PageGetGroupMember(
ctx context.Context,
groupID string,
pageNumber, showNumber int32,
) (uint32, []*relationtb.GroupMemberModel, error) {
total, members, err := s.GroupDatabase.PageGetGroupMember(ctx, groupID, pageNumber, showNumber)
if err != nil {
return 0, nil, err
}
emptyUserIDs := make(map[string]struct{})
for _, member := range members {
if member.Nickname == "" || member.FaceURL == "" {
emptyUserIDs[member.UserID] = struct{}{}
}
}
if len(emptyUserIDs) > 0 {
users, err := s.User.GetPublicUserInfoMap(ctx, utils.Keys(emptyUserIDs), true)
if err != nil {
return 0, nil, err
}
for i, member := range members {
user, ok := users[member.UserID]
if !ok {
continue
}
if member.Nickname == "" {
members[i].Nickname = user.Nickname
}
if member.FaceURL == "" {
members[i].FaceURL = user.FaceURL
}
}
}
return total, members, nil
} }
File diff suppressed because it is too large Load Diff
+3 -3
View File
@@ -26,16 +26,16 @@ func (s *groupServer) GroupCreateCount(ctx context.Context, req *group.GroupCrea
if req.Start > req.End { if req.Start > req.End {
return nil, errs.ErrArgs.Wrap("start > end") return nil, errs.ErrArgs.Wrap("start > end")
} }
total, err := s.db.CountTotal(ctx, nil) total, err := s.GroupDatabase.CountTotal(ctx, nil)
if err != nil { if err != nil {
return nil, err return nil, err
} }
start := time.UnixMilli(req.Start) start := time.UnixMilli(req.Start)
before, err := s.db.CountTotal(ctx, &start) before, err := s.GroupDatabase.CountTotal(ctx, &start)
if err != nil { if err != nil {
return nil, err return nil, err
} }
count, err := s.db.CountRangeEverydayTotal(ctx, start, time.UnixMilli(req.End)) count, err := s.GroupDatabase.CountRangeEverydayTotal(ctx, start, time.UnixMilli(req.End))
if err != nil { if err != nil {
return nil, err return nil, err
} }
+89 -5
View File
@@ -16,15 +16,99 @@ package group
import ( import (
"context" "context"
"errors" "fmt"
"strings"
"github.com/OpenIMSDK/protocol/constant"
pbgroup "github.com/OpenIMSDK/protocol/group" pbgroup "github.com/OpenIMSDK/protocol/group"
sdkws "github.com/OpenIMSDK/protocol/sdkws"
"github.com/OpenIMSDK/tools/errs"
"github.com/OpenIMSDK/tools/utils"
"github.com/openimsdk/open-im-server/v3/pkg/common/convert"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/table/unrelation"
) )
func (s *groupServer) GetJoinedSuperGroupList(context.Context, *pbgroup.GetJoinedSuperGroupListReq) (*pbgroup.GetJoinedSuperGroupListResp, error) { func (s *groupServer) GetJoinedSuperGroupList(
return nil, errors.New("deprecated") ctx context.Context,
req *pbgroup.GetJoinedSuperGroupListReq,
) (*pbgroup.GetJoinedSuperGroupListResp, error) {
resp := &pbgroup.GetJoinedSuperGroupListResp{}
groupIDs, err := s.GroupDatabase.FindJoinSuperGroup(ctx, req.UserID)
if err != nil {
return nil, err
}
if len(groupIDs) == 0 {
return resp, nil
}
owners, err := s.FindGroupMember(ctx, groupIDs, nil, []int32{constant.GroupOwner})
if err != nil {
return nil, err
}
ownerMap := utils.SliceToMap(owners, func(e *relation.GroupMemberModel) string {
return e.GroupID
})
if ids := utils.Single(groupIDs, utils.Keys(ownerMap)); len(ids) > 0 {
return nil, errs.ErrData.Wrap(fmt.Sprintf("super group %s not owner", strings.Join(ids, ",")))
}
groups, err := s.GroupDatabase.FindGroup(ctx, groupIDs)
if err != nil {
return nil, err
}
groupMap := utils.SliceToMap(groups, func(e *relation.GroupModel) string {
return e.GroupID
})
if ids := utils.Single(groupIDs, utils.Keys(groupMap)); len(ids) > 0 {
return nil, errs.ErrData.Wrap(fmt.Sprintf("super group info %s not found", strings.Join(ids, ",")))
}
superGroupMembers, err := s.GroupDatabase.FindSuperGroup(ctx, groupIDs)
if err != nil {
return nil, err
}
superGroupMemberMap := utils.SliceToMapAny(
superGroupMembers,
func(e *unrelation.SuperGroupModel) (string, []string) {
return e.GroupID, e.MemberIDs
},
)
resp.Groups = utils.Slice(groupIDs, func(groupID string) *sdkws.GroupInfo {
return convert.Db2PbGroupInfo(groupMap[groupID], ownerMap[groupID].UserID, uint32(len(superGroupMemberMap)))
})
return resp, nil
} }
func (s *groupServer) GetSuperGroupsInfo(context.Context, *pbgroup.GetSuperGroupsInfoReq) (resp *pbgroup.GetSuperGroupsInfoResp, err error) { func (s *groupServer) GetSuperGroupsInfo(
return nil, errors.New("deprecated") ctx context.Context,
req *pbgroup.GetSuperGroupsInfoReq,
) (resp *pbgroup.GetSuperGroupsInfoResp, err error) {
resp = &pbgroup.GetSuperGroupsInfoResp{}
if len(req.GroupIDs) == 0 {
return nil, errs.ErrArgs.Wrap("groupIDs empty")
}
groups, err := s.GroupDatabase.FindGroup(ctx, req.GroupIDs)
if err != nil {
return nil, err
}
superGroupMembers, err := s.GroupDatabase.FindSuperGroup(ctx, req.GroupIDs)
if err != nil {
return nil, err
}
superGroupMemberMap := utils.SliceToMapAny(
superGroupMembers,
func(e *unrelation.SuperGroupModel) (string, []string) {
return e.GroupID, e.MemberIDs
},
)
owners, err := s.FindGroupMember(ctx, req.GroupIDs, nil, []int32{constant.GroupOwner})
if err != nil {
return nil, err
}
ownerMap := utils.SliceToMap(owners, func(e *relation.GroupMemberModel) string {
return e.GroupID
})
resp.GroupInfos = utils.Slice(groups, func(e *relation.GroupModel) *sdkws.GroupInfo {
return convert.Db2PbGroupInfo(e, ownerMap[e.GroupID].UserID, uint32(len(superGroupMemberMap[e.GroupID])))
})
return resp, nil
} }
+2 -21
View File
@@ -16,11 +16,9 @@ package msg
import ( import (
"context" "context"
utils2 "github.com/OpenIMSDK/tools/utils"
"github.com/redis/go-redis/v9" "github.com/redis/go-redis/v9"
cbapi "github.com/openimsdk/open-im-server/v3/pkg/callbackstruct"
"github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/protocol/constant"
"github.com/OpenIMSDK/protocol/msg" "github.com/OpenIMSDK/protocol/msg"
"github.com/OpenIMSDK/protocol/sdkws" "github.com/OpenIMSDK/protocol/sdkws"
@@ -112,7 +110,6 @@ func (m *msgServer) MarkMsgsAsRead(
if err = m.MsgDatabase.MarkSingleChatMsgsAsRead(ctx, req.UserID, req.ConversationID, req.Seqs); err != nil { if err = m.MsgDatabase.MarkSingleChatMsgsAsRead(ctx, req.UserID, req.ConversationID, req.Seqs); err != nil {
return return
} }
currentHasReadSeq, err := m.MsgDatabase.GetHasReadSeq(ctx, req.UserID, req.ConversationID) currentHasReadSeq, err := m.MsgDatabase.GetHasReadSeq(ctx, req.UserID, req.ConversationID)
if err != nil && errs.Unwrap(err) != redis.Nil { if err != nil && errs.Unwrap(err) != redis.Nil {
return return
@@ -150,12 +147,7 @@ func (m *msgServer) MarkConversationAsRead(
for i := hasReadSeq + 1; i <= req.HasReadSeq; i++ { for i := hasReadSeq + 1; i <= req.HasReadSeq; i++ {
seqs = append(seqs, i) seqs = append(seqs, i)
} }
//avoid client missed call MarkConversationMessageAsRead by order
for _, val := range req.Seqs {
if !utils2.Contain(val, seqs...) {
seqs = append(seqs, val)
}
}
if len(seqs) > 0 { if len(seqs) > 0 {
log.ZDebug(ctx, "MarkConversationAsRead", "seqs", seqs, "conversationID", req.ConversationID) log.ZDebug(ctx, "MarkConversationAsRead", "seqs", seqs, "conversationID", req.ConversationID)
if err = m.MsgDatabase.MarkSingleChatMsgsAsRead(ctx, req.UserID, req.ConversationID, seqs); err != nil { if err = m.MsgDatabase.MarkSingleChatMsgsAsRead(ctx, req.UserID, req.ConversationID, seqs); err != nil {
@@ -173,7 +165,6 @@ func (m *msgServer) MarkConversationAsRead(
m.conversationAndGetRecvID(conversation, req.UserID), seqs, hasReadSeq); err != nil { m.conversationAndGetRecvID(conversation, req.UserID), seqs, hasReadSeq); err != nil {
return nil, err return nil, err
} }
} else if conversation.ConversationType == constant.SuperGroupChatType || } else if conversation.ConversationType == constant.SuperGroupChatType ||
conversation.ConversationType == constant.NotificationChatType { conversation.ConversationType == constant.NotificationChatType {
if req.HasReadSeq > hasReadSeq { if req.HasReadSeq > hasReadSeq {
@@ -190,16 +181,6 @@ func (m *msgServer) MarkConversationAsRead(
} }
reqCall := &cbapi.CallbackGroupMsgReadReq{
SendID: conversation.OwnerUserID,
ReceiveID: req.UserID,
UnreadMsgNum: req.HasReadSeq,
ContentType: int64(conversation.ConversationType),
}
if err := CallbackGroupMsgRead(ctx, reqCall); err != nil {
return nil, err
}
return &msg.MarkConversationAsReadResp{}, nil return &msg.MarkConversationAsReadResp{}, nil
} }
@@ -222,4 +203,4 @@ func (m *msgServer) sendMarkAsReadNotification(
log.ZWarn(ctx, "send has read Receipt err", err) log.ZWarn(ctx, "send has read Receipt err", err)
} }
return nil return nil
} }
+25 -51
View File
@@ -16,16 +16,18 @@ package msg
import ( import (
"context" "context"
"github.com/OpenIMSDK/protocol/sdkws" "github.com/OpenIMSDK/protocol/sdkws"
"google.golang.org/protobuf/proto" "google.golang.org/protobuf/proto"
"github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/protocol/constant"
pbchat "github.com/OpenIMSDK/protocol/msg" pbchat "github.com/OpenIMSDK/protocol/msg"
"github.com/OpenIMSDK/tools/errs"
"github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/log"
"github.com/OpenIMSDK/tools/mcontext" "github.com/OpenIMSDK/tools/mcontext"
"github.com/OpenIMSDK/tools/utils" "github.com/OpenIMSDK/tools/utils"
cbapi "github.com/openimsdk/open-im-server/v3/pkg/callbackstruct"
cbapi "github.com/openimsdk/open-im-server/v3/pkg/callbackstruct"
"github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/config"
"github.com/openimsdk/open-im-server/v3/pkg/common/http" "github.com/openimsdk/open-im-server/v3/pkg/common/http"
) )
@@ -72,11 +74,14 @@ func callbackBeforeSendSingleMsg(ctx context.Context, msg *pbchat.SendMsgReq) er
return nil return nil
} }
req := &cbapi.CallbackBeforeSendSingleMsgReq{ req := &cbapi.CallbackBeforeSendSingleMsgReq{
CommonCallbackReq: toCommonCallback(ctx, msg, cbapi.CallbackBeforeSendSingleMsgCommand), CommonCallbackReq: toCommonCallback(ctx, msg, constant.CallbackBeforeSendSingleMsgCommand),
RecvID: msg.MsgData.RecvID, RecvID: msg.MsgData.RecvID,
} }
resp := &cbapi.CallbackBeforeSendSingleMsgResp{} resp := &cbapi.CallbackBeforeSendSingleMsgResp{}
if err := http.CallBackPostReturn(ctx, cbURL(), req, resp, config.Config.Callback.CallbackBeforeSendSingleMsg); err != nil { if err := http.CallBackPostReturn(ctx, cbURL(), req, resp, config.Config.Callback.CallbackBeforeSendSingleMsg); err != nil {
if err == errs.ErrCallbackContinue {
return nil
}
return err return err
} }
return nil return nil
@@ -87,26 +92,32 @@ func callbackAfterSendSingleMsg(ctx context.Context, msg *pbchat.SendMsgReq) err
return nil return nil
} }
req := &cbapi.CallbackAfterSendSingleMsgReq{ req := &cbapi.CallbackAfterSendSingleMsgReq{
CommonCallbackReq: toCommonCallback(ctx, msg, cbapi.CallbackAfterSendSingleMsgCommand), CommonCallbackReq: toCommonCallback(ctx, msg, constant.CallbackAfterSendSingleMsgCommand),
RecvID: msg.MsgData.RecvID, RecvID: msg.MsgData.RecvID,
} }
resp := &cbapi.CallbackAfterSendSingleMsgResp{} resp := &cbapi.CallbackAfterSendSingleMsgResp{}
if err := http.CallBackPostReturn(ctx, cbURL(), req, resp, config.Config.Callback.CallbackAfterSendSingleMsg); err != nil { if err := http.CallBackPostReturn(ctx, cbURL(), req, resp, config.Config.Callback.CallbackAfterSendSingleMsg); err != nil {
if err == errs.ErrCallbackContinue {
return nil
}
return err return err
} }
return nil return nil
} }
func callbackBeforeSendGroupMsg(ctx context.Context, msg *pbchat.SendMsgReq) error { func callbackBeforeSendGroupMsg(ctx context.Context, msg *pbchat.SendMsgReq) error {
if !config.Config.Callback.CallbackBeforeSendSingleMsg.Enable { if !config.Config.Callback.CallbackAfterSendSingleMsg.Enable {
return nil return nil
} }
req := &cbapi.CallbackBeforeSendGroupMsgReq{ req := &cbapi.CallbackAfterSendGroupMsgReq{
CommonCallbackReq: toCommonCallback(ctx, msg, cbapi.CallbackBeforeSendGroupMsgCommand), CommonCallbackReq: toCommonCallback(ctx, msg, constant.CallbackBeforeSendGroupMsgCommand),
GroupID: msg.MsgData.GroupID, GroupID: msg.MsgData.GroupID,
} }
resp := &cbapi.CallbackBeforeSendGroupMsgResp{} resp := &cbapi.CallbackBeforeSendGroupMsgResp{}
if err := http.CallBackPostReturn(ctx, cbURL(), req, resp, config.Config.Callback.CallbackBeforeSendGroupMsg); err != nil { if err := http.CallBackPostReturn(ctx, cbURL(), req, resp, config.Config.Callback.CallbackBeforeSendGroupMsg); err != nil {
if err == errs.ErrCallbackContinue {
return nil
}
return err return err
} }
return nil return nil
@@ -117,11 +128,14 @@ func callbackAfterSendGroupMsg(ctx context.Context, msg *pbchat.SendMsgReq) erro
return nil return nil
} }
req := &cbapi.CallbackAfterSendGroupMsgReq{ req := &cbapi.CallbackAfterSendGroupMsgReq{
CommonCallbackReq: toCommonCallback(ctx, msg, cbapi.CallbackAfterSendGroupMsgCommand), CommonCallbackReq: toCommonCallback(ctx, msg, constant.CallbackAfterSendGroupMsgCommand),
GroupID: msg.MsgData.GroupID, GroupID: msg.MsgData.GroupID,
} }
resp := &cbapi.CallbackAfterSendGroupMsgResp{} resp := &cbapi.CallbackAfterSendGroupMsgResp{}
if err := http.CallBackPostReturn(ctx, cbURL(), req, resp, config.Config.Callback.CallbackAfterSendGroupMsg); err != nil { if err := http.CallBackPostReturn(ctx, cbURL(), req, resp, config.Config.Callback.CallbackAfterSendGroupMsg); err != nil {
if err == errs.ErrCallbackContinue {
return nil
}
return err return err
} }
return nil return nil
@@ -132,10 +146,13 @@ func callbackMsgModify(ctx context.Context, msg *pbchat.SendMsgReq) error {
return nil return nil
} }
req := &cbapi.CallbackMsgModifyCommandReq{ req := &cbapi.CallbackMsgModifyCommandReq{
CommonCallbackReq: toCommonCallback(ctx, msg, cbapi.CallbackMsgModifyCommand), CommonCallbackReq: toCommonCallback(ctx, msg, constant.CallbackMsgModifyCommand),
} }
resp := &cbapi.CallbackMsgModifyCommandResp{} resp := &cbapi.CallbackMsgModifyCommandResp{}
if err := http.CallBackPostReturn(ctx, cbURL(), req, resp, config.Config.Callback.CallbackMsgModify); err != nil { if err := http.CallBackPostReturn(ctx, cbURL(), req, resp, config.Config.Callback.CallbackMsgModify); err != nil {
if err == errs.ErrCallbackContinue {
return nil
}
return err return err
} }
if resp.Content != nil { if resp.Content != nil {
@@ -160,46 +177,3 @@ func callbackMsgModify(ctx context.Context, msg *pbchat.SendMsgReq) error {
log.ZDebug(ctx, "callbackMsgModify", "msg", msg.MsgData) log.ZDebug(ctx, "callbackMsgModify", "msg", msg.MsgData)
return nil return nil
} }
func CallbackGroupMsgRead(ctx context.Context, req *cbapi.CallbackGroupMsgReadReq) error {
if !config.Config.Callback.CallbackGroupMsgRead.Enable || req.ContentType != constant.Text {
return nil
}
req.CallbackCommand = cbapi.CallbackGroupMsgReadCommand
resp := &cbapi.CallbackGroupMsgReadResp{}
if err := http.CallBackPostReturn(ctx, cbURL(), req, resp, config.Config.Callback.CallbackMsgModify); err != nil {
return err
}
return nil
}
func CallbackSingleMsgRead(ctx context.Context, req *cbapi.CallbackSingleMsgReadReq) error {
if !config.Config.Callback.CallbackSingleMsgRead.Enable || req.ContentType != constant.Text {
return nil
}
req.CallbackCommand = cbapi.CallbackSingleMsgRead
resp := &cbapi.CallbackSingleMsgReadResp{}
if err := http.CallBackPostReturn(ctx, cbURL(), req, resp, config.Config.Callback.CallbackMsgModify); err != nil {
return err
}
return nil
}
func CallbackAfterRevokeMsg(ctx context.Context, req *pbchat.RevokeMsgReq) error {
if !config.Config.Callback.CallbackAfterRevokeMsg.Enable {
return nil
}
callbackReq := &cbapi.CallbackAfterRevokeMsgReq{
CallbackCommand: cbapi.CallbackAfterRevokeMsgCommand,
ConversationID: req.ConversationID,
Seq: req.Seq,
UserID: req.UserID,
}
resp := &cbapi.CallbackAfterRevokeMsgResp{}
if err := http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, callbackReq, resp, config.Config.Callback.CallbackAfterRevokeMsg); err != nil {
return err
}
utils.StructFieldNotNilReplace(req, resp)
return nil
}
-4
View File
@@ -61,7 +61,6 @@ func (m *msgServer) RevokeMsg(ctx context.Context, req *msg.RevokeMsgReq) (*msg.
if msgs[0].ContentType == constant.MsgRevokeNotification { if msgs[0].ContentType == constant.MsgRevokeNotification {
return nil, errs.ErrMsgAlreadyRevoke.Wrap("msg already revoke") return nil, errs.ErrMsgAlreadyRevoke.Wrap("msg already revoke")
} }
data, _ := json.Marshal(msgs[0]) data, _ := json.Marshal(msgs[0])
log.ZInfo(ctx, "GetMsgBySeqs", "conversationID", req.ConversationID, "seq", req.Seq, "msg", string(data)) log.ZInfo(ctx, "GetMsgBySeqs", "conversationID", req.ConversationID, "seq", req.Seq, "msg", string(data))
var role int32 var role int32
@@ -129,8 +128,5 @@ func (m *msgServer) RevokeMsg(ctx context.Context, req *msg.RevokeMsgReq) (*msg.
if err := m.notificationSender.NotificationWithSesstionType(ctx, req.UserID, recvID, constant.MsgRevokeNotification, msgs[0].SessionType, &tips); err != nil { if err := m.notificationSender.NotificationWithSesstionType(ctx, req.UserID, recvID, constant.MsgRevokeNotification, msgs[0].SessionType, &tips); err != nil {
return nil, err return nil, err
} }
if err = CallbackAfterRevokeMsg(ctx, req); err != nil {
return nil, err
}
return &msg.RevokeMsgResp{}, nil return &msg.RevokeMsgResp{}, nil
} }
+10 -2
View File
@@ -42,8 +42,15 @@ func (m *msgServer) PullMessageBySeqs(
log.ZError(ctx, "GetConversation error", err, "conversationID", seq.ConversationID) log.ZError(ctx, "GetConversation error", err, "conversationID", seq.ConversationID)
continue continue
} }
minSeq, maxSeq, msgs, err := m.MsgDatabase.GetMsgBySeqsRange(ctx, req.UserID, seq.ConversationID, minSeq, maxSeq, msgs, err := m.MsgDatabase.GetMsgBySeqsRange(
seq.Begin, seq.End, seq.Num, conversation.MaxSeq) ctx,
req.UserID,
seq.ConversationID,
seq.Begin,
seq.End,
seq.Num,
conversation.MaxSeq,
)
if err != nil { if err != nil {
log.ZWarn(ctx, "GetMsgBySeqsRange error", err, "conversationID", seq.ConversationID, "seq", seq) log.ZWarn(ctx, "GetMsgBySeqsRange error", err, "conversationID", seq.ConversationID, "seq", seq)
continue continue
@@ -57,6 +64,7 @@ func (m *msgServer) PullMessageBySeqs(
} }
if len(msgs) == 0 { if len(msgs) == 0 {
log.ZWarn(ctx, "not have msgs", nil, "conversationID", seq.ConversationID, "seq", seq) log.ZWarn(ctx, "not have msgs", nil, "conversationID", seq.ConversationID, "seq", seq)
continue continue
} }
resp.Msgs[seq.ConversationID] = &sdkws.PullMsgs{Msgs: msgs, IsEnd: isEnd} resp.Msgs[seq.ConversationID] = &sdkws.PullMsgs{Msgs: msgs, IsEnd: isEnd}
+4 -3
View File
@@ -15,11 +15,12 @@
package msg package msg
import ( import (
"github.com/redis/go-redis/v9"
"gorm.io/gorm"
"github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/protocol/constant"
"github.com/OpenIMSDK/protocol/sdkws" "github.com/OpenIMSDK/protocol/sdkws"
"github.com/OpenIMSDK/tools/utils" "github.com/OpenIMSDK/tools/utils"
"github.com/redis/go-redis/v9"
"go.mongodb.org/mongo-driver/mongo"
"github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/config"
) )
@@ -44,7 +45,7 @@ func isMessageHasReadEnabled(msgData *sdkws.MsgData) bool {
func IsNotFound(err error) bool { func IsNotFound(err error) bool {
switch utils.Unwrap(err) { switch utils.Unwrap(err) {
case redis.Nil, mongo.ErrNoDocuments: case redis.Nil, gorm.ErrRecordNotFound:
return true return true
default: default:
return false return false
+13 -11
View File
@@ -32,11 +32,11 @@ func genLogID() string {
} }
func (t *thirdServer) UploadLogs(ctx context.Context, req *third.UploadLogsReq) (*third.UploadLogsResp, error) { func (t *thirdServer) UploadLogs(ctx context.Context, req *third.UploadLogsReq) (*third.UploadLogsResp, error) {
var DBlogs []*relationtb.LogModel var DBlogs []*relationtb.Log
userID := ctx.Value(constant.OpUserID).(string) userID := ctx.Value(constant.OpUserID).(string)
platform := constant.PlatformID2Name[int(req.Platform)] platform := constant.PlatformID2Name[int(req.Platform)]
for _, fileURL := range req.FileURLs { for _, fileURL := range req.FileURLs {
log := relationtb.LogModel{ log := relationtb.Log{
Version: req.Version, Version: req.Version,
SystemType: req.SystemType, SystemType: req.SystemType,
Platform: platform, Platform: platform,
@@ -57,7 +57,7 @@ func (t *thirdServer) UploadLogs(ctx context.Context, req *third.UploadLogsReq)
} }
} }
if log.LogID == "" { if log.LogID == "" {
return nil, errs.ErrData.Wrap("LogModel id gen error") return nil, errs.ErrData.Wrap("Log id gen error")
} }
DBlogs = append(DBlogs, &log) DBlogs = append(DBlogs, &log)
} }
@@ -92,8 +92,8 @@ func (t *thirdServer) DeleteLogs(ctx context.Context, req *third.DeleteLogsReq)
return &third.DeleteLogsResp{}, nil return &third.DeleteLogsResp{}, nil
} }
func dbToPbLogInfos(logs []*relationtb.LogModel) []*third.LogInfo { func dbToPbLogInfos(logs []*relationtb.Log) []*third.LogInfo {
db2pbForLogInfo := func(log *relationtb.LogModel) *third.LogInfo { db2pbForLogInfo := func(log *relationtb.Log) *third.LogInfo {
return &third.LogInfo{ return &third.LogInfo{
Filename: log.FileName, Filename: log.FileName,
UserID: log.UserID, UserID: log.UserID,
@@ -120,7 +120,7 @@ func (t *thirdServer) SearchLogs(ctx context.Context, req *third.SearchLogsReq)
if req.StartTime > req.EndTime { if req.StartTime > req.EndTime {
return nil, errs.ErrArgs.Wrap("startTime>endTime") return nil, errs.ErrArgs.Wrap("startTime>endTime")
} }
total, logs, err := t.thirdDatabase.SearchLogs(ctx, req.Keyword, time.UnixMilli(req.StartTime), time.UnixMilli(req.EndTime), req.Pagination) total, logs, err := t.thirdDatabase.SearchLogs(ctx, req.Keyword, time.UnixMilli(req.StartTime), time.UnixMilli(req.EndTime), req.Pagination.PageNumber, req.Pagination.ShowNumber)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -128,16 +128,18 @@ func (t *thirdServer) SearchLogs(ctx context.Context, req *third.SearchLogsReq)
for _, log := range logs { for _, log := range logs {
userIDs = append(userIDs, log.UserID) userIDs = append(userIDs, log.UserID)
} }
userMap, err := t.userRpcClient.GetUsersInfoMap(ctx, userIDs) users, err := t.thirdDatabase.FindUsers(ctx, userIDs)
if err != nil { if err != nil {
return nil, err return nil, err
} }
IDtoName := make(map[string]string)
for _, user := range users {
IDtoName[user.UserID] = user.Nickname
}
for _, pbLog := range pbLogs { for _, pbLog := range pbLogs {
if user, ok := userMap[pbLog.UserID]; ok { pbLog.Nickname = IDtoName[pbLog.UserID]
pbLog.Nickname = user.Nickname
}
} }
resp.LogsInfos = pbLogs resp.LogsInfos = pbLogs
resp.Total = uint32(total) resp.Total = total
return &resp, nil return &resp, nil
} }
+2 -2
View File
@@ -64,7 +64,7 @@ func (t *thirdServer) InitiateMultipartUpload(ctx context.Context, req *third.In
Key: haErr.Object.Key, Key: haErr.Object.Key,
Size: haErr.Object.Size, Size: haErr.Object.Size,
ContentType: req.ContentType, ContentType: req.ContentType,
Group: req.Cause, Cause: req.Cause,
CreateTime: time.Now(), CreateTime: time.Now(),
} }
if err := t.s3dataBase.SetObject(ctx, obj); err != nil { if err := t.s3dataBase.SetObject(ctx, obj); err != nil {
@@ -143,7 +143,7 @@ func (t *thirdServer) CompleteMultipartUpload(ctx context.Context, req *third.Co
Key: result.Key, Key: result.Key,
Size: result.Size, Size: result.Size,
ContentType: req.ContentType, ContentType: req.ContentType,
Group: req.Cause, Cause: req.Cause,
CreateTime: time.Now(), CreateTime: time.Now(),
} }
if err := t.s3dataBase.SetObject(ctx, obj); err != nil { if err := t.s3dataBase.SetObject(ctx, obj); err != nil {
+18 -17
View File
@@ -20,9 +20,6 @@ import (
"net/url" "net/url"
"time" "time"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/mgo"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/unrelation"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/s3" "github.com/openimsdk/open-im-server/v3/pkg/common/db/s3"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/s3/cos" "github.com/openimsdk/open-im-server/v3/pkg/common/db/s3/cos"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/s3/minio" "github.com/openimsdk/open-im-server/v3/pkg/common/db/s3/minio"
@@ -36,22 +33,13 @@ import (
"github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/config"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/relation"
relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
) )
func Start(client discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) error { func Start(client discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) error {
mongo, err := unrelation.NewMongo()
if err != nil {
return err
}
logdb, err := mgo.NewLogMongo(mongo.GetDatabase())
if err != nil {
return err
}
s3db, err := mgo.NewS3Mongo(mongo.GetDatabase())
if err != nil {
return err
}
apiURL := config.Config.Object.ApiURL apiURL := config.Config.Object.ApiURL
if apiURL == "" { if apiURL == "" {
return fmt.Errorf("api url is empty") return fmt.Errorf("api url is empty")
@@ -67,6 +55,13 @@ func Start(client discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) e
if err != nil { if err != nil {
return err return err
} }
db, err := relation.NewGormDB()
if err != nil {
return err
}
if err := db.AutoMigrate(&relationtb.ObjectModel{}); err != nil {
return err
}
// 根据配置文件策略选择 oss 方式 // 根据配置文件策略选择 oss 方式
enable := config.Config.Object.Enable enable := config.Config.Object.Enable
var o s3.Interface var o s3.Interface
@@ -83,11 +78,17 @@ func Start(client discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) e
if err != nil { if err != nil {
return err return err
} }
//specialerror.AddErrHandler(func(err error) errs.CodeError {
// if o.IsNotFound(err) {
// return errs.ErrRecordNotFound
// }
// return nil
//})
third.RegisterThirdServer(server, &thirdServer{ third.RegisterThirdServer(server, &thirdServer{
apiURL: apiURL, apiURL: apiURL,
thirdDatabase: controller.NewThirdDatabase(cache.NewMsgCacheModel(rdb), logdb), thirdDatabase: controller.NewThirdDatabase(cache.NewMsgCacheModel(rdb), db),
userRpcClient: rpcclient.NewUserRpcClient(client), userRpcClient: rpcclient.NewUserRpcClient(client),
s3dataBase: controller.NewS3Database(rdb, o, s3db), s3dataBase: controller.NewS3Database(rdb, o, relation.NewObjectInfo(db)),
defaultExpire: time.Hour * 24 * 7, defaultExpire: time.Hour * 24 * 7,
}) })
return nil return nil
+9 -55
View File
@@ -16,7 +16,11 @@ package user
import ( import (
"context" "context"
"github.com/OpenIMSDK/protocol/constant"
pbuser "github.com/OpenIMSDK/protocol/user" pbuser "github.com/OpenIMSDK/protocol/user"
"github.com/OpenIMSDK/tools/errs"
"github.com/OpenIMSDK/tools/mcontext"
"github.com/OpenIMSDK/tools/utils" "github.com/OpenIMSDK/tools/utils"
cbapi "github.com/openimsdk/open-im-server/v3/pkg/callbackstruct" cbapi "github.com/openimsdk/open-im-server/v3/pkg/callbackstruct"
@@ -29,13 +33,17 @@ func CallbackBeforeUpdateUserInfo(ctx context.Context, req *pbuser.UpdateUserInf
return nil return nil
} }
cbReq := &cbapi.CallbackBeforeUpdateUserInfoReq{ cbReq := &cbapi.CallbackBeforeUpdateUserInfoReq{
CallbackCommand: cbapi.CallbackBeforeUpdateUserInfoCommand, CallbackCommand: constant.CallbackBeforeUpdateUserInfoCommand,
OperationID: mcontext.GetOperationID(ctx),
UserID: req.UserInfo.UserID, UserID: req.UserInfo.UserID,
FaceURL: &req.UserInfo.FaceURL, FaceURL: &req.UserInfo.FaceURL,
Nickname: &req.UserInfo.Nickname, Nickname: &req.UserInfo.Nickname,
} }
resp := &cbapi.CallbackBeforeUpdateUserInfoResp{} resp := &cbapi.CallbackBeforeUpdateUserInfoResp{}
if err := http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, cbReq, resp, config.Config.Callback.CallbackBeforeUpdateUserInfo); err != nil { if err := http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, cbReq, resp, config.Config.Callback.CallbackBeforeUpdateUserInfo); err != nil {
if err == errs.ErrCallbackContinue {
return nil
}
return err return err
} }
utils.NotNilReplace(&req.UserInfo.FaceURL, resp.FaceURL) utils.NotNilReplace(&req.UserInfo.FaceURL, resp.FaceURL)
@@ -43,57 +51,3 @@ func CallbackBeforeUpdateUserInfo(ctx context.Context, req *pbuser.UpdateUserInf
utils.NotNilReplace(&req.UserInfo.Nickname, resp.Nickname) utils.NotNilReplace(&req.UserInfo.Nickname, resp.Nickname)
return nil return nil
} }
func CallbackAfterUpdateUserInfo(ctx context.Context, req *pbuser.UpdateUserInfoReq) error {
if !config.Config.Callback.CallbackAfterUpdateUserInfo.Enable {
return nil
}
cbReq := &cbapi.CallbackAfterUpdateUserInfoReq{
CallbackCommand: cbapi.CallbackAfterUpdateUserInfoCommand,
UserID: req.UserInfo.UserID,
FaceURL: req.UserInfo.FaceURL,
Nickname: req.UserInfo.Nickname,
}
resp := &cbapi.CallbackAfterUpdateUserInfoResp{}
if err := http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, cbReq, resp, config.Config.Callback.CallbackBeforeUpdateUserInfo); err != nil {
return err
}
return nil
}
func CallbackBeforeUserRegister(ctx context.Context, req *pbuser.UserRegisterReq) error {
if !config.Config.Callback.CallbackBeforeUserRegister.Enable {
return nil
}
cbReq := &cbapi.CallbackBeforeUserRegisterReq{
CallbackCommand: cbapi.CallbackBeforeUserRegisterCommand,
Secret: req.Secret,
Users: req.Users,
}
resp := &cbapi.CallbackBeforeUserRegisterResp{}
if err := http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, cbReq, resp, config.Config.Callback.CallbackBeforeUpdateUserInfo); err != nil {
return err
}
if len(resp.Users) != 0 {
req.Users = resp.Users
}
return nil
}
func CallbackAfterUserRegister(ctx context.Context, req *pbuser.UserRegisterReq) error {
if !config.Config.Callback.CallbackAfterUserRegister.Enable {
return nil
}
cbReq := &cbapi.CallbackAfterUserRegisterReq{
CallbackCommand: cbapi.CallbackAfterUserRegisterCommand,
Secret: req.Secret,
Users: req.Users,
}
resp := &cbapi.CallbackAfterUserRegisterResp{}
if err := http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, cbReq, resp, config.Config.Callback.CallbackAfterUpdateUserInfo); err != nil {
return err
}
return nil
}
+27 -42
View File
@@ -20,14 +20,11 @@ import (
"strings" "strings"
"time" "time"
"github.com/OpenIMSDK/tools/tx"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/mgo"
"github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/protocol/constant"
"github.com/OpenIMSDK/protocol/sdkws" "github.com/OpenIMSDK/protocol/sdkws"
"github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/errs"
"github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/log"
"github.com/OpenIMSDK/tools/tx"
"github.com/openimsdk/open-im-server/v3/pkg/authverify" "github.com/openimsdk/open-im-server/v3/pkg/authverify"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/unrelation" "github.com/openimsdk/open-im-server/v3/pkg/common/db/unrelation"
@@ -38,6 +35,7 @@ import (
"github.com/openimsdk/open-im-server/v3/pkg/common/convert" "github.com/openimsdk/open-im-server/v3/pkg/common/convert"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/relation"
tablerelation "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" tablerelation "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient/notification" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient/notification"
@@ -56,23 +54,11 @@ type userServer struct {
RegisterCenter registry.SvcDiscoveryRegistry RegisterCenter registry.SvcDiscoveryRegistry
} }
func (s *userServer) ProcessUserCommandAdd(ctx context.Context, req *pbuser.ProcessUserCommandAddReq) (*pbuser.ProcessUserCommandAddResp, error) {
return nil, errs.ErrInternalServer.Wrap("not implemented")
}
func (s *userServer) ProcessUserCommandUpdate(ctx context.Context, req *pbuser.ProcessUserCommandUpdateReq) (*pbuser.ProcessUserCommandUpdateResp, error) {
return nil, errs.ErrInternalServer.Wrap("not implemented")
}
func (s *userServer) ProcessUserCommandDelete(ctx context.Context, req *pbuser.ProcessUserCommandDeleteReq) (*pbuser.ProcessUserCommandDeleteResp, error) {
return nil, errs.ErrInternalServer.Wrap("not implemented")
}
func (s *userServer) ProcessUserCommandGet(ctx context.Context, req *pbuser.ProcessUserCommandGetReq) (*pbuser.ProcessUserCommandGetResp, error) {
return nil, errs.ErrInternalServer.Wrap("not implemented")
}
func Start(client registry.SvcDiscoveryRegistry, server *grpc.Server) error { func Start(client registry.SvcDiscoveryRegistry, server *grpc.Server) error {
db, err := relation.NewGormDB()
if err != nil {
return err
}
rdb, err := cache.NewRedis() rdb, err := cache.NewRedis()
if err != nil { if err != nil {
return err return err
@@ -81,6 +67,9 @@ func Start(client registry.SvcDiscoveryRegistry, server *grpc.Server) error {
if err != nil { if err != nil {
return err return err
} }
if err := db.AutoMigrate(&tablerelation.UserModel{}); err != nil {
return err
}
users := make([]*tablerelation.UserModel, 0) users := make([]*tablerelation.UserModel, 0)
if len(config.Config.Manager.UserID) != len(config.Config.Manager.Nickname) { if len(config.Config.Manager.UserID) != len(config.Config.Manager.Nickname) {
return errors.New("len(config.Config.Manager.AppManagerUid) != len(config.Config.Manager.Nickname)") return errors.New("len(config.Config.Manager.AppManagerUid) != len(config.Config.Manager.Nickname)")
@@ -88,13 +77,10 @@ func Start(client registry.SvcDiscoveryRegistry, server *grpc.Server) error {
for k, v := range config.Config.Manager.UserID { for k, v := range config.Config.Manager.UserID {
users = append(users, &tablerelation.UserModel{UserID: v, Nickname: config.Config.Manager.Nickname[k], AppMangerLevel: constant.AppAdmin}) users = append(users, &tablerelation.UserModel{UserID: v, Nickname: config.Config.Manager.Nickname[k], AppMangerLevel: constant.AppAdmin})
} }
userDB, err := mgo.NewUserMongo(mongo.GetDatabase()) userDB := relation.NewUserGorm(db)
if err != nil {
return err
}
cache := cache.NewUserCacheRedis(rdb, userDB, cache.GetDefaultOpt()) cache := cache.NewUserCacheRedis(rdb, userDB, cache.GetDefaultOpt())
userMongoDB := unrelation.NewUserMongoDriver(mongo.GetDatabase()) userMongoDB := unrelation.NewUserMongoDriver(mongo.GetDatabase())
database := controller.NewUserDatabase(userDB, cache, tx.NewMongo(mongo.GetClient()), userMongoDB) database := controller.NewUserDatabase(userDB, cache, tx.NewGorm(db), userMongoDB)
friendRpcClient := rpcclient.NewFriendRpcClient(client) friendRpcClient := rpcclient.NewFriendRpcClient(client)
groupRpcClient := rpcclient.NewGroupRpcClient(client) groupRpcClient := rpcclient.NewGroupRpcClient(client)
msgRpcClient := rpcclient.NewMessageRpcClient(client) msgRpcClient := rpcclient.NewMessageRpcClient(client)
@@ -132,8 +118,12 @@ func (s *userServer) UpdateUserInfo(ctx context.Context, req *pbuser.UpdateUserI
if err := CallbackBeforeUpdateUserInfo(ctx, req); err != nil { if err := CallbackBeforeUpdateUserInfo(ctx, req); err != nil {
return nil, err return nil, err
} }
data := convert.UserPb2DBMap(req.UserInfo) user := convert.UserPb2DB(req.UserInfo)
if err := s.UpdateByMap(ctx, req.UserInfo.UserID, data); err != nil { if err != nil {
return nil, err
}
err = s.Update(ctx, user)
if err != nil {
return nil, err return nil, err
} }
_ = s.friendNotificationSender.UserInfoUpdatedNotification(ctx, req.UserInfo.UserID) _ = s.friendNotificationSender.UserInfoUpdatedNotification(ctx, req.UserInfo.UserID)
@@ -149,9 +139,6 @@ func (s *userServer) UpdateUserInfo(ctx context.Context, req *pbuser.UpdateUserI
for _, friendID := range friends { for _, friendID := range friends {
s.friendNotificationSender.FriendInfoUpdatedNotification(ctx, req.UserInfo.UserID, friendID) s.friendNotificationSender.FriendInfoUpdatedNotification(ctx, req.UserInfo.UserID, friendID)
} }
if err := CallbackAfterUpdateUserInfo(ctx, req); err != nil {
return nil, err
}
if err := s.groupRpcClient.NotificationUserInfoUpdate(ctx, req.UserInfo.UserID); err != nil { if err := s.groupRpcClient.NotificationUserInfoUpdate(ctx, req.UserInfo.UserID); err != nil {
log.ZError(ctx, "NotificationUserInfoUpdate", err, "userID", req.UserInfo.UserID) log.ZError(ctx, "NotificationUserInfoUpdate", err, "userID", req.UserInfo.UserID)
} }
@@ -163,7 +150,7 @@ func (s *userServer) SetGlobalRecvMessageOpt(ctx context.Context, req *pbuser.Se
if _, err := s.FindWithError(ctx, []string{req.UserID}); err != nil { if _, err := s.FindWithError(ctx, []string{req.UserID}); err != nil {
return nil, err return nil, err
} }
m := make(map[string]any, 1) m := make(map[string]interface{}, 1)
m["global_recv_msg_opt"] = req.GlobalRecvMsgOpt m["global_recv_msg_opt"] = req.GlobalRecvMsgOpt
if err := s.UpdateByMap(ctx, req.UserID, m); err != nil { if err := s.UpdateByMap(ctx, req.UserID, m); err != nil {
return nil, err return nil, err
@@ -185,7 +172,7 @@ func (s *userServer) AccountCheck(ctx context.Context, req *pbuser.AccountCheckR
if err != nil { if err != nil {
return nil, err return nil, err
} }
userIDs := make(map[string]any, 0) userIDs := make(map[string]interface{}, 0)
for _, v := range users { for _, v := range users {
userIDs[v.UserID] = nil userIDs[v.UserID] = nil
} }
@@ -202,7 +189,12 @@ func (s *userServer) AccountCheck(ctx context.Context, req *pbuser.AccountCheckR
} }
func (s *userServer) GetPaginationUsers(ctx context.Context, req *pbuser.GetPaginationUsersReq) (resp *pbuser.GetPaginationUsersResp, err error) { func (s *userServer) GetPaginationUsers(ctx context.Context, req *pbuser.GetPaginationUsersReq) (resp *pbuser.GetPaginationUsersResp, err error) {
total, users, err := s.Page(ctx, req.Pagination) var pageNumber, showNumber int32
if req.Pagination != nil {
pageNumber = req.Pagination.PageNumber
showNumber = req.Pagination.ShowNumber
}
users, total, err := s.Page(ctx, pageNumber, showNumber)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -238,9 +230,6 @@ func (s *userServer) UserRegister(ctx context.Context, req *pbuser.UserRegisterR
if exist { if exist {
return nil, errs.ErrRegisteredAlready.Wrap("userID registered already") return nil, errs.ErrRegisteredAlready.Wrap("userID registered already")
} }
if err := CallbackBeforeUserRegister(ctx, req); err != nil {
return nil, err
}
now := time.Now() now := time.Now()
users := make([]*tablerelation.UserModel, 0, len(req.Users)) users := make([]*tablerelation.UserModel, 0, len(req.Users))
for _, user := range req.Users { for _, user := range req.Users {
@@ -257,10 +246,6 @@ func (s *userServer) UserRegister(ctx context.Context, req *pbuser.UserRegisterR
if err := s.Create(ctx, users); err != nil { if err := s.Create(ctx, users); err != nil {
return nil, err return nil, err
} }
if err := CallbackAfterUserRegister(ctx, req); err != nil {
return nil, err
}
return resp, nil return resp, nil
} }
@@ -274,11 +259,11 @@ func (s *userServer) GetGlobalRecvMessageOpt(ctx context.Context, req *pbuser.Ge
// GetAllUserID Get user account by page. // GetAllUserID Get user account by page.
func (s *userServer) GetAllUserID(ctx context.Context, req *pbuser.GetAllUserIDReq) (resp *pbuser.GetAllUserIDResp, err error) { func (s *userServer) GetAllUserID(ctx context.Context, req *pbuser.GetAllUserIDReq) (resp *pbuser.GetAllUserIDResp, err error) {
total, userIDs, err := s.UserDatabase.GetAllUserID(ctx, req.Pagination) userIDs, err := s.UserDatabase.GetAllUserID(ctx, req.Pagination.PageNumber, req.Pagination.ShowNumber)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &pbuser.GetAllUserIDResp{Total: int32(total), UserIDs: userIDs}, nil return &pbuser.GetAllUserIDResp{UserIDs: userIDs}, nil
} }
// SubscribeOrCancelUsersStatus Subscribe online or cancel online users. // SubscribeOrCancelUsersStatus Subscribe online or cancel online users.
+2 -8
View File
@@ -19,8 +19,6 @@ import (
"math/rand" "math/rand"
"time" "time"
"github.com/OpenIMSDK/protocol/sdkws"
"github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/log"
"github.com/OpenIMSDK/tools/mcontext" "github.com/OpenIMSDK/tools/mcontext"
"github.com/OpenIMSDK/tools/utils" "github.com/OpenIMSDK/tools/utils"
@@ -93,11 +91,7 @@ func (c *MsgTool) ConversationsDestructMsgs() {
} }
for i := 0; i < count; i++ { for i := 0; i < count; i++ {
pageNumber := rand.Int63() % maxPage pageNumber := rand.Int63() % maxPage
pagination := &sdkws.RequestPagination{ conversationIDs, err := c.conversationDatabase.PageConversationIDs(ctx, int32(pageNumber), batchNum)
PageNumber: int32(pageNumber),
ShowNumber: batchNum,
}
conversationIDs, err := c.conversationDatabase.PageConversationIDs(ctx, pagination)
if err != nil { if err != nil {
log.ZError(ctx, "PageConversationIDs failed", err, "pageNumber", pageNumber) log.ZError(ctx, "PageConversationIDs failed", err, "pageNumber", pageNumber)
continue continue
@@ -139,7 +133,7 @@ func (c *MsgTool) ConversationsDestructMsgs() {
continue continue
} }
if len(seqs) > 0 { if len(seqs) > 0 {
if err := c.conversationDatabase.UpdateUsersConversationFiled(ctx, []string{conversation.OwnerUserID}, conversation.ConversationID, map[string]any{"latest_msg_destruct_time": now}); err != nil { if err := c.conversationDatabase.UpdateUsersConversationFiled(ctx, []string{conversation.OwnerUserID}, conversation.ConversationID, map[string]interface{}{"latest_msg_destruct_time": now}); err != nil {
log.ZError(ctx, "updateUsersConversationFiled failed", err, "conversationID", conversation.ConversationID, "ownerUserID", conversation.OwnerUserID) log.ZError(ctx, "updateUsersConversationFiled failed", err, "conversationID", conversation.ConversationID, "ownerUserID", conversation.OwnerUserID)
continue continue
} }
+9 -66
View File
@@ -17,18 +17,13 @@ package tools
import ( import (
"context" "context"
"fmt" "fmt"
"os" "sync"
"os/signal"
"syscall"
"time"
"github.com/redis/go-redis/v9"
"github.com/robfig/cron/v3" "github.com/robfig/cron/v3"
"github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/log"
"github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/config"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/cache"
) )
func StartTask() error { func StartTask() error {
@@ -37,75 +32,23 @@ func StartTask() error {
if err != nil { if err != nil {
return err return err
} }
msgTool.ConvertTools()
msgTool.convertTools() c := cron.New()
var wg sync.WaitGroup
rdb, err := cache.NewRedis() wg.Add(1)
if err != nil {
return err
}
// register cron tasks
var crontab = cron.New()
log.ZInfo(context.Background(), "start chatRecordsClearTime cron task", "cron config", config.Config.ChatRecordsClearTime) log.ZInfo(context.Background(), "start chatRecordsClearTime cron task", "cron config", config.Config.ChatRecordsClearTime)
_, err = crontab.AddFunc(config.Config.ChatRecordsClearTime, cronWrapFunc(rdb, "cron_clear_msg_and_fix_seq", msgTool.AllConversationClearMsgAndFixSeq)) _, err = c.AddFunc(config.Config.ChatRecordsClearTime, msgTool.AllConversationClearMsgAndFixSeq)
if err != nil { if err != nil {
log.ZError(context.Background(), "start allConversationClearMsgAndFixSeq cron failed", err) log.ZError(context.Background(), "start allConversationClearMsgAndFixSeq cron failed", err)
panic(err) panic(err)
} }
log.ZInfo(context.Background(), "start msgDestruct cron task", "cron config", config.Config.MsgDestructTime) log.ZInfo(context.Background(), "start msgDestruct cron task", "cron config", config.Config.MsgDestructTime)
_, err = crontab.AddFunc(config.Config.MsgDestructTime, cronWrapFunc(rdb, "cron_conversations_destruct_msgs", msgTool.ConversationsDestructMsgs)) _, err = c.AddFunc(config.Config.MsgDestructTime, msgTool.ConversationsDestructMsgs)
if err != nil { if err != nil {
log.ZError(context.Background(), "start conversationsDestructMsgs cron failed", err) log.ZError(context.Background(), "start conversationsDestructMsgs cron failed", err)
panic(err) panic(err)
} }
c.Start()
// start crontab wg.Wait()
crontab.Start()
sigs := make(chan os.Signal, 1)
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)
<-sigs
// stop crontab, Wait for the running task to exit.
ctx := crontab.Stop()
select {
case <-ctx.Done():
// graceful exit
case <-time.After(15 * time.Second):
// forced exit on timeout
}
return nil return nil
} }
// netlock redis lock.
func netlock(rdb redis.UniversalClient, key string, ttl time.Duration) bool {
value := "used"
ok, err := rdb.SetNX(context.Background(), key, value, ttl).Result() // nolint
if err != nil {
// when err is about redis server, return true.
return false
}
return ok
}
func cronWrapFunc(rdb redis.UniversalClient, key string, fn func()) func() {
enableCronLocker := config.Config.EnableCronLocker
return func() {
// if don't enable cron-locker, call fn directly.
if !enableCronLocker {
fn()
return
}
// when acquire redis lock, call fn().
if netlock(rdb, key, 5*time.Second) {
fn()
}
}
}
-82
View File
@@ -1,82 +0,0 @@
package tools
import (
"fmt"
"math/rand"
"sync"
"testing"
"time"
"github.com/redis/go-redis/v9"
"github.com/robfig/cron/v3"
"github.com/stretchr/testify/assert"
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
)
func TestDisLock(t *testing.T) {
rdb := redis.NewClient(&redis.Options{})
defer rdb.Close()
assert.Equal(t, true, netlock(rdb, "cron-1", 1*time.Second))
// if exists, get false
assert.Equal(t, false, netlock(rdb, "cron-1", 1*time.Second))
time.Sleep(2 * time.Second)
// wait for key on timeout, get true
assert.Equal(t, true, netlock(rdb, "cron-1", 2*time.Second))
// set different key
assert.Equal(t, true, netlock(rdb, "cron-2", 2*time.Second))
}
func TestCronWrapFunc(t *testing.T) {
rdb := redis.NewClient(&redis.Options{})
defer rdb.Close()
once := sync.Once{}
done := make(chan struct{}, 1)
cb := func() {
once.Do(func() {
close(done)
})
}
start := time.Now()
key := fmt.Sprintf("cron-%v", rand.Int31())
crontab := cron.New(cron.WithSeconds())
crontab.AddFunc("*/1 * * * * *", cronWrapFunc(rdb, key, cb))
crontab.Start()
<-done
dur := time.Since(start)
assert.LessOrEqual(t, dur.Seconds(), float64(2*time.Second))
crontab.Stop()
}
func TestCronWrapFuncWithNetlock(t *testing.T) {
config.Config.EnableCronLocker = true
rdb := redis.NewClient(&redis.Options{})
defer rdb.Close()
done := make(chan string, 10)
crontab := cron.New(cron.WithSeconds())
key := fmt.Sprintf("cron-%v", rand.Int31())
crontab.AddFunc("*/1 * * * * *", cronWrapFunc(rdb, key, func() {
done <- "host1"
}))
crontab.AddFunc("*/1 * * * * *", cronWrapFunc(rdb, key, func() {
done <- "host2"
}))
crontab.Start()
time.Sleep(12 * time.Second)
// the ttl of netlock is 5s, so expected value is 2.
assert.Equal(t, len(done), 2)
crontab.Stop()
}
+18 -37
View File
@@ -19,11 +19,6 @@ import (
"fmt" "fmt"
"math" "math"
"github.com/OpenIMSDK/protocol/sdkws"
"github.com/OpenIMSDK/tools/tx"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/mgo"
"github.com/redis/go-redis/v9" "github.com/redis/go-redis/v9"
"google.golang.org/grpc" "google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure" "google.golang.org/grpc/credentials/insecure"
@@ -36,11 +31,13 @@ import (
"github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/log"
"github.com/OpenIMSDK/tools/mcontext" "github.com/OpenIMSDK/tools/mcontext"
"github.com/OpenIMSDK/tools/mw" "github.com/OpenIMSDK/tools/mw"
"github.com/OpenIMSDK/tools/tx"
"github.com/OpenIMSDK/tools/utils" "github.com/OpenIMSDK/tools/utils"
"github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/config"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/relation"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/unrelation" "github.com/openimsdk/open-im-server/v3/pkg/common/db/unrelation"
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient/notification" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient/notification"
@@ -75,45 +72,33 @@ func InitMsgTool() (*MsgTool, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
db, err := relation.NewGormDB()
if err != nil {
return nil, err
}
discov, err := kdisc.NewDiscoveryRegister(config.Config.Envs.Discovery) discov, err := kdisc.NewDiscoveryRegister(config.Config.Envs.Discovery)
/*
discov, err := zookeeper.NewClient(config.Config.Zookeeper.ZkAddr, config.Config.Zookeeper.Schema,
zookeeper.WithFreq(time.Hour), zookeeper.WithRoundRobin(), zookeeper.WithUserNameAndPassword(config.Config.Zookeeper.Username,
config.Config.Zookeeper.Password), zookeeper.WithTimeout(10), zookeeper.WithLogger(log.NewZkLogger()))*/
if err != nil { if err != nil {
return nil, err return nil, err
} }
discov.AddOption(mw.GrpcClient(), grpc.WithTransportCredentials(insecure.NewCredentials())) discov.AddOption(mw.GrpcClient(), grpc.WithTransportCredentials(insecure.NewCredentials()))
userDB, err := mgo.NewUserMongo(mongo.GetDatabase()) userDB := relation.NewUserGorm(db)
if err != nil {
return nil, err
}
msgDatabase := controller.InitCommonMsgDatabase(rdb, mongo.GetDatabase()) msgDatabase := controller.InitCommonMsgDatabase(rdb, mongo.GetDatabase())
userMongoDB := unrelation.NewUserMongoDriver(mongo.GetDatabase()) userMongoDB := unrelation.NewUserMongoDriver(mongo.GetDatabase())
ctxTx := tx.NewMongo(mongo.GetClient())
userDatabase := controller.NewUserDatabase( userDatabase := controller.NewUserDatabase(
userDB, userDB,
cache.NewUserCacheRedis(rdb, userDB, cache.GetDefaultOpt()), cache.NewUserCacheRedis(rdb, relation.NewUserGorm(db), cache.GetDefaultOpt()),
ctxTx, tx.NewGorm(db),
userMongoDB, userMongoDB,
) )
groupDB, err := mgo.NewGroupMongo(mongo.GetDatabase()) groupDatabase := controller.InitGroupDatabase(db, rdb, mongo.GetDatabase(), nil)
if err != nil {
return nil, err
}
groupMemberDB, err := mgo.NewGroupMember(mongo.GetDatabase())
if err != nil {
return nil, err
}
groupRequestDB, err := mgo.NewGroupRequestMgo(mongo.GetDatabase())
if err != nil {
return nil, err
}
conversationDB, err := mgo.NewConversationMongo(mongo.GetDatabase())
if err != nil {
return nil, err
}
groupDatabase := controller.NewGroupDatabase(rdb, groupDB, groupMemberDB, groupRequestDB, ctxTx, nil)
conversationDatabase := controller.NewConversationDatabase( conversationDatabase := controller.NewConversationDatabase(
conversationDB, relation.NewConversationGorm(db),
cache.NewConversationRedis(rdb, cache.GetDefaultOpt(), conversationDB), cache.NewConversationRedis(rdb, cache.GetDefaultOpt(), relation.NewConversationGorm(db)),
ctxTx, tx.NewGorm(db),
) )
msgRpcClient := rpcclient.NewMessageRpcClient(discov) msgRpcClient := rpcclient.NewMessageRpcClient(discov)
msgNotificationSender := notification.NewMsgNotificationSender(rpcclient.WithRpcClient(&msgRpcClient)) msgNotificationSender := notification.NewMsgNotificationSender(rpcclient.WithRpcClient(&msgRpcClient))
@@ -159,11 +144,7 @@ func (c *MsgTool) AllConversationClearMsgAndFixSeq() {
} }
for i := 0; i < count; i++ { for i := 0; i < count; i++ {
pageNumber := rand.Int63() % maxPage pageNumber := rand.Int63() % maxPage
pagination := &sdkws.RequestPagination{ conversationIDs, err := c.conversationDatabase.PageConversationIDs(ctx, int32(pageNumber), batchNum)
PageNumber: int32(pageNumber),
ShowNumber: batchNum,
}
conversationIDs, err := c.conversationDatabase.PageConversationIDs(ctx, pagination)
if err != nil { if err != nil {
log.ZError(ctx, "PageConversationIDs failed", err, "pageNumber", pageNumber) log.ZError(ctx, "PageConversationIDs failed", err, "pageNumber", pageNumber)
continue continue
+2 -2
View File
@@ -22,7 +22,7 @@ import (
"github.com/openimsdk/open-im-server/v3/pkg/msgprocessor" "github.com/openimsdk/open-im-server/v3/pkg/msgprocessor"
) )
func (c *MsgTool) convertTools() { func (c *MsgTool) ConvertTools() {
ctx := mcontext.NewCtx("convert") ctx := mcontext.NewCtx("convert")
conversationIDs, err := c.conversationDatabase.GetAllConversationIDs(ctx) conversationIDs, err := c.conversationDatabase.GetAllConversationIDs(ctx)
if err != nil { if err != nil {
@@ -32,7 +32,7 @@ func (c *MsgTool) convertTools() {
for _, conversationID := range conversationIDs { for _, conversationID := range conversationIDs {
conversationIDs = append(conversationIDs, msgprocessor.GetNotificationConversationIDByConversationID(conversationID)) conversationIDs = append(conversationIDs, msgprocessor.GetNotificationConversationIDByConversationID(conversationID))
} }
_, userIDs, err := c.userDatabase.GetAllUserID(ctx, nil) userIDs, err := c.userDatabase.GetAllUserID(ctx, 0, 0)
if err != nil { if err != nil {
log.ZError(ctx, "get all user ids failed", err) log.ZError(ctx, "get all user ids failed", err)
return return
+1 -1
View File
@@ -36,7 +36,7 @@ type SendMsg struct {
SenderPlatformID int32 `json:"senderPlatformID"` SenderPlatformID int32 `json:"senderPlatformID"`
// Content is the actual content of the message, required and excluded from Swagger documentation. // Content is the actual content of the message, required and excluded from Swagger documentation.
Content map[string]any `json:"content" binding:"required" swaggerignore:"true"` Content map[string]interface{} `json:"content" binding:"required" swaggerignore:"true"`
// ContentType is an integer that represents the type of the content. // ContentType is an integer that represents the type of the content.
ContentType int32 `json:"contentType" binding:"required"` ContentType int32 `json:"contentType" binding:"required"`

Some files were not shown because too many files have changed in this diff Show More