Compare commits

..

26 Commits

Author SHA1 Message Date
Xinwei Xiong
0a8198573b Update start.go 2024-02-04 11:06:34 +08:00
OpenIM Bot
8729f90d02 cicd: bump League Patch (#1874) 2024-02-04 02:40:26 +00:00
Xinwei Xiong
854f8dbd2f feat: Optimize openim scripts and standard output logs (#1866)
* feat: add component check func

* fix: fix the outpu error

* fix: fix the stderr outpu

* fix: fix the component check func

* fix: fix the error

* fix: fix the output error

* fix: del the disruptions code

* fix the log output format

* fix: fix the tools version

* fix: fix the cycle detection

* fix: fix the error

* fix: fix the flag

* fix: add mongo ping detection

* fix: fix the tools pkg version

* fix: del the err

* feat: support openim readme docs

Signed-off-by: Xinwei Xiong (cubxxw) <3293172751nss@gmail.com>

* feat: support openim readme docs

Signed-off-by: Xinwei Xiong (cubxxw) <3293172751nss@gmail.com>

* feat: support openim readme docs

Signed-off-by: Xinwei Xiong (cubxxw) <3293172751nss@gmail.com>

* fix: fix the minio nil error

* fix: del the repeated wrap and add err print

* fix: fix this bug scripts

* Revert "Check"

---------

Signed-off-by: Xinwei Xiong (cubxxw) <3293172751nss@gmail.com>
Co-authored-by: luhaoling <2198702716@qq.com>
2024-02-02 13:59:12 +00:00
Xinwei Xiong
af878a96cf feat: add architecture layers (#1860)
* feat: add architecture layers

* feat: add architecture layers

* feat: add architecture layers

* feat: add .gitignore file

* feat: add .gitignore file

* feat: fix openim logs and ci

* feat: fix openim logs and ci

* feat: support openim readme docs

Signed-off-by: Xinwei Xiong (cubxxw) <3293172751nss@gmail.com>

* Update main.go

---------

Signed-off-by: Xinwei Xiong (cubxxw) <3293172751nss@gmail.com>
2024-02-02 11:47:16 +00:00
Brabem
f551b50e79 fix: Refactoring the code for component detection (#1868)
* feat: add component check func

* fix: fix the outpu error

* fix: fix the stderr outpu

* fix: fix the component check func

* fix: fix the error

* fix: fix the output error

* fix: del the disruptions code

* fix the log output format

* fix: fix the tools version
2024-02-02 16:21:14 +08:00
OpenIM Bot
bb862bd207 cicd: bump League Patch (#1863) 2024-02-02 03:41:01 +00:00
OpenIM-Gordon
c55e03dc70 fix: process add errors wrap. (#1862)
* fix: process add errors wrap.

* fix: process add errors wrap.
2024-02-02 02:11:13 +00:00
Brabem
55ca661d13 Bug: replace the component check func by tools pkg (#1846)
* fix: del the manager config and manger init statement

* fix: fix the Manger judge condition

* fix: fix revokeMsg error

* fix: find erors

* fix: find error

* fix: fix the AdminAccount error

* fix: del the debug statement

* fix: fix the component check func

* fix: fix the get zkAddress error

* fix: fix the kafka client close error

* fix: add env in minio connected

* fix: del the minio env

* fix: fix the go.mod tools version

* fix: del get env in minio  conneted
2024-02-01 02:11:22 +00:00
丛蛋白
551781a0ee fix document parameter errors (#1848)
Co-authored-by: Xinwei Xiong <3293172751NSS@gmail.com>
2024-02-01 02:10:38 +00:00
Seal Bell
4c0121849d docs:Add multi-language README.md in ./docs/ file (#1852)
* Add Simplified Chinese README.md

* Add Ukrainian README.md

* Add Traditional Chinese README.md

* Add Czech README.md

* Add Hungarian README.md

* Add spanish README.md

* Add Persian README.md

* Add French README.md

* Add German README.md

* Add Japanese README.md

* Add Polish README.md

* Add Indonesian README.md

* Add Finnish README.md

* Add Malayalam README.md

* Add Dutch README.md

* Add Italian README.md

* Add Russian README.md

* Added Brazilian Portuguese README.md

* Add Esperanto README.md

* Add Korean README.md

* Add Vietnamese README.md

* Add Arabic README.md

* Add Danish README.md

* Add Greek README.md

* Add Turkish README.md
2024-02-01 09:38:21 +08:00
Xinwei Xiong
42a3084a6f Update environment.md fix environment mongo username (#1847) 2024-01-31 09:58:24 +00:00
Xinwei Xiong
c205013436 Update offline-deployment.md openim offine deployment docs (#1843) 2024-01-31 06:16:32 +00:00
Xinwei Xiong
18047859b8 Delete build/images/openim-rpc-encryption directory (#1842) 2024-01-31 06:16:19 +00:00
Xinwei Xiong
4ded2cffed Delete build/images/openim-rpc-extend-msg directory (#1841) 2024-01-31 06:16:09 +00:00
OpenIM Bot
0a245df2f8 cicd: bump League Patch (#1837) 2024-01-31 06:14:03 +00:00
Xinwei Xiong
bd9e50d9e0 fix(docker-compose): Update the env template to uncomment the mongo port (#1833) 2024-01-29 11:58:19 +00:00
Brabem
32cd79044b feat: del the manager configure and it's initializestatement (#1830)
* fix: del the manager config and manger init statement

* fix: fix the Manger judge condition

* fix: fix revokeMsg error

* fix: find erors

* fix: find error

* fix: fix the AdminAccount error

* fix: del the debug statement
2024-01-29 11:57:37 +00:00
dependabot[bot]
f94d8af737 chore(deps): bump google.golang.org/grpc in /tools/url2im (#1283)
Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.56.2 to 1.56.3.
- [Release notes](https://github.com/grpc/grpc-go/releases)
- [Commits](https://github.com/grpc/grpc-go/compare/v1.56.2...v1.56.3)

---
updated-dependencies:
- dependency-name: google.golang.org/grpc
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-28 10:32:34 +00:00
dependabot[bot]
34551a82a2 chore(deps): bump golang.org/x/crypto in /tools/data-conversion (#1580)
Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.16.0 to 0.17.0.
- [Commits](https://github.com/golang/crypto/compare/v0.16.0...v0.17.0)

---
updated-dependencies:
- dependency-name: golang.org/x/crypto
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-28 10:30:51 +00:00
a3d21
b14c0475d2 fix duplicated offline push (#1816) 2024-01-27 02:52:13 +00:00
OpenIM Bot
1d5732c97e cicd: bump League Patch (#1828) 2024-01-27 02:50:25 +00:00
Xinwei Xiong
7ef32bf8a0 [Auto PR] Bump League Patch in '"base branch' (#1827) 2024-01-26 16:50:11 +00:00
OpenIM Bot
19ffde3196 cicd: bump League Patch (#1825) 2024-01-26 16:49:37 +00:00
Xinwei Xiong
e79532aa93 feat: add pull request set workflows (#1824)
* feat: add pull request set workflows

* Update pull-request.yml
2024-01-26 16:10:42 +00:00
chao
c86df88b59 fix: conversation aggregate find error (#1822)
* fix: GroupApplicationAcceptedNotification

* fix: GroupApplicationAcceptedNotification

* fix: NotificationUserInfoUpdate

* cicd: robot automated Change

* fix: conversation aggregate find error

---------

Co-authored-by: withchao <withchao@users.noreply.github.com>
2024-01-26 12:55:37 +00:00
Xinwei Xiong
e2650add40 feat: Enhanced Automation for OpenIM Advanced CICD and GitOps Support (#1819)
* feat: add advanced version cicd

* fix: fix openim server deployment
2024-01-26 12:53:25 +00:00
145 changed files with 2038 additions and 2994 deletions

View File

@@ -14,12 +14,6 @@
name: Github Pull Request name: Github Pull Request
on: on:
push:
branches: [main]
paths-ignore:
- 'README.md'
- 'CONTRIBUTING.md'
- 'docs/**'
workflow_dispatch: workflow_dispatch:
schedule: schedule:
- cron: '0 2 * * *' - cron: '0 2 * * *'
@@ -37,24 +31,18 @@ jobs:
with: with:
fetch-depth: 0 fetch-depth: 0
- name: Get League branch Patch
run: |
git config user.name 'openimbot'
git config user.email 'openimsdk@qq.com'
BRANCH_NAME="auto-pr-$(date +'%Y%m%d%H%M%S')"
git checkout -b $BRANCH_NAME
- uses: actions/setup-node@v4 - uses: actions/setup-node@v4
- name: Setup Go - name: Setup Go
uses: actions/setup-go@v4 uses: actions/setup-go@v4
- name: Run go modules tidy - name: Run go modules tidy
run: | run: |
sudo apt-get install jq
sudo make tidy sudo make tidy
sudo make tools.verify.go-gitlint sudo make tools.verify.go-gitlint
echo "Run go modules tidy successfully" echo "Run go modules tidy successfully"
continue-on-error: true continue-on-error: true
- name: Run go format - name: Run go format and lint
run: | run: |
sudo make format sudo make format
echo "Run go format successfully" echo "Run go format successfully"
@@ -69,7 +57,21 @@ jobs:
- name: Generate all necessary files, such as error code files - name: Generate all necessary files, such as error code files
run: | run: |
make generate make generate
echo "Generate all necessary files successfully" echo "Generate all necessary files successfully"
continue-on-error: true
- name: make init
run: |
export OPENIM_IP=127.0.0.1
export LOG_STORAGE_LOCATION="../logs/"
./scripts/init-config.sh --examples --force
echo "Generate all necessary files successfully"
continue-on-error: true
- name: Generate Vertions
run: |
latest_tag=$(git describe --tags `git rev-list --tags --max-count=1` | grep -oE '[0-9]+\.[0-9]+\.[0-9]+')
echo $latest_tag > pkg/common/config/version
continue-on-error: true continue-on-error: true
- name: Run unit test and get test coverage - name: Run unit test and get test coverage
@@ -80,7 +82,6 @@ jobs:
- name: OpenIM verify copyright - name: OpenIM verify copyright
run: | run: |
sudo make verify-copyright
sudo make add-copyright sudo make add-copyright
echo "OpenIM verify successfully" echo "OpenIM verify successfully"
continue-on-error: true continue-on-error: true
@@ -90,23 +91,28 @@ jobs:
with: with:
token: ${{ secrets.BOT_GITHUB_TOKEN }} token: ${{ secrets.BOT_GITHUB_TOKEN }}
commit-message: "cicd: bump League Patch" commit-message: "cicd: bump League Patch"
author: kubbot <kubbot@3293172751ysy@gmail.com> author: kubbot <3293172751ysy@gmail.com>
signoff: false committer: kubbot <3293172751ysy@gmail.com>
draft: false # signoff: false
branch: '' # draft: false
branch: "asf-auto-updates"
assignees: cubxxw assignees: cubxxw
reviewers: cubxxw reviewers: cubxxw
delete-branch: true title: "[Auto PR 🤖] Bump League Patch auto PR"
title: "Bump League Patch auto PR: $(date +'%Y%m%d')"
body: | body: |
I am a PR generated by robot automation.
Review criteria: Review criteria:
- [ ] Disenchanter can connect and issue actions - [ ] Disenchanter can connect and issue actions
Github Actions Status:
[![Github Pull Request](https://github.com/openimsdk/open-im-server/actions/workflows/pull-request.yml/badge.svg)](https://github.com/openimsdk/open-im-server/actions/workflows/pull-request.yml)
This is an automated PR. @ $(date +'%Y%m%d') This is an automated PR.
<sub>[workflow](https://github.com/openimsdk/open-im-server/blob/main/.github/workflows/pull-request.yml).</sub> <sub>[workflow](https://github.com/openimsdk/open-im-server/blob/main/.github/workflows/pull-request.yml).</sub>
base: main
labels: | labels: |
kind/documentation kind/documentation
enhancement enhancement
report report

33
CONTRIBUTING-zh_CN.md Normal file
View File

@@ -0,0 +1,33 @@
# How do I contribute code to OpenIM
<p align="center">
<a href="./CONTRIBUTING.md">Englist</a> ·
<a href="./CONTRIBUTING-zh_CN.md">中文</a> ·
<a href="docs/contributing/CONTRIBUTING-UA.md">Українська</a> ·
<a href="docs/contributing/CONTRIBUTING-CS.md">Česky</a> ·
<a href="docs/contributing/CONTRIBUTING-HU.md">Magyar</a> ·
<a href="docs/contributing/CONTRIBUTING-ES.md">Español</a> ·
<a href="docs/contributing/CONTRIBUTING-FA.md">فارسی</a> ·
<a href="docs/contributing/CONTRIBUTING-FR.md">Français</a> ·
<a href="docs/contributing/CONTRIBUTING-DE.md">Deutsch</a> ·
<a href="docs/contributing/CONTRIBUTING-PL.md">Polski</a> ·
<a href="docs/contributing/CONTRIBUTING-ID.md">Indonesian</a> ·
<a href="docs/contributing/CONTRIBUTING-FI.md">Suomi</a> ·
<a href="docs/contributing/CONTRIBUTING-ML.md">മലയാളം</a> ·
<a href="docs/contributing/CONTRIBUTING-JP.md">日本語</a> ·
<a href="docs/contributing/CONTRIBUTING-NL.md">Nederlands</a> ·
<a href="docs/contributing/CONTRIBUTING-IT.md">Italiano</a> ·
<a href="docs/contributing/CONTRIBUTING-RU.md">Русский</a> ·
<a href="docs/contributing/CONTRIBUTING-PTBR.md">Português (Brasil)</a> ·
<a href="docs/contributing/CONTRIBUTING-EO.md">Esperanto</a> ·
<a href="docs/contributing/CONTRIBUTING-KR.md">한국어</a> ·
<a href="docs/contributing/CONTRIBUTING-AR.md">العربي</a> ·
<a href="docs/contributing/CONTRIBUTING-VN.md">Tiếng Việt</a> ·
<a href="docs/contributing/CONTRIBUTING-DA.md">Dansk</a> ·
<a href="docs/contributing/CONTRIBUTING-GR.md">Ελληνικά</a> ·
<a href="docs/contributing/CONTRIBUTING-TR.md">Türkçe</a>
</p>
</div>
</p>

View File

@@ -1,6 +1,38 @@
# Contributing to Open-IM-Server # How do I contribute code to OpenIM
So, you want to hack on Open-IM-Server? Yay! <p align="center">
<a href="./CONTRIBUTING.md">Englist</a> ·
<a href="./CONTRIBUTING-zh_CN.md">中文</a> ·
<a href="docs/contributing/CONTRIBUTING-UA.md">Українська</a> ·
<a href="docs/contributing/CONTRIBUTING-CS.md">Česky</a> ·
<a href="docs/contributing/CONTRIBUTING-HU.md">Magyar</a> ·
<a href="docs/contributing/CONTRIBUTING-ES.md">Español</a> ·
<a href="docs/contributing/CONTRIBUTING-FA.md">فارسی</a> ·
<a href="docs/contributing/CONTRIBUTING-FR.md">Français</a> ·
<a href="docs/contributing/CONTRIBUTING-DE.md">Deutsch</a> ·
<a href="docs/contributing/CONTRIBUTING-PL.md">Polski</a> ·
<a href="docs/contributing/CONTRIBUTING-ID.md">Indonesian</a> ·
<a href="docs/contributing/CONTRIBUTING-FI.md">Suomi</a> ·
<a href="docs/contributing/CONTRIBUTING-ML.md">മലയാളം</a> ·
<a href="docs/contributing/CONTRIBUTING-JP.md">日本語</a> ·
<a href="docs/contributing/CONTRIBUTING-NL.md">Nederlands</a> ·
<a href="docs/contributing/CONTRIBUTING-IT.md">Italiano</a> ·
<a href="docs/contributing/CONTRIBUTING-RU.md">Русский</a> ·
<a href="docs/contributing/CONTRIBUTING-PTBR.md">Português (Brasil)</a> ·
<a href="docs/contributing/CONTRIBUTING-EO.md">Esperanto</a> ·
<a href="docs/contributing/CONTRIBUTING-KR.md">한국어</a> ·
<a href="docs/contributing/CONTRIBUTING-AR.md">العربي</a> ·
<a href="docs/contributing/CONTRIBUTING-VN.md">Tiếng Việt</a> ·
<a href="docs/contributing/CONTRIBUTING-DA.md">Dansk</a> ·
<a href="docs/contributing/CONTRIBUTING-GR.md">Ελληνικά</a> ·
<a href="docs/contributing/CONTRIBUTING-TR.md">Türkçe</a>
</p>
</div>
</p>
So, you want to hack on open-im-server? Yay!
First of all, thank you for considering contributing to our project! We appreciate your time and effort, and we value any contribution, whether it's reporting a bug, suggesting a new feature, or submitting a pull request. First of all, thank you for considering contributing to our project! We appreciate your time and effort, and we value any contribution, whether it's reporting a bug, suggesting a new feature, or submitting a pull request.
@@ -12,7 +44,7 @@ This document provides guidelines and best practices to help you contribute effe
## 📇Topics ## 📇Topics
- [Contributing to Open-IM-Server](#contributing-to-open-im-server) - [How do I contribute code to OpenIM](#how-do-i-contribute-code-to-openim)
- [📇Topics](#topics) - [📇Topics](#topics)
- [What we expect of you](#what-we-expect-of-you) - [What we expect of you](#what-we-expect-of-you)
- [Code of ConductCode of Conduct](#code-of-conductcode-of-conduct) - [Code of ConductCode of Conduct](#code-of-conductcode-of-conduct)
@@ -32,13 +64,13 @@ This document provides guidelines and best practices to help you contribute effe
## What we expect of you ## What we expect of you
We hope that anyone can join Open-IM-Server , even if you are a student, writer, translator We hope that anyone can join open-im-server , even if you are a student, writer, translator
Please meet the minimum version of the Go language published in [go.mod](./go.mod). If you want to manage the Go language version, we provide tools to install [gvm](https://github.com/moovweb/gvm) in our [Makefile](./Makefile) Please meet the minimum version of the Go language published in [go.mod](./go.mod). If you want to manage the Go language version, we provide tools tHow do I contribute code to OpenIMo install [gvm](https://github.com/moovweb/gvm) in our [Makefile](./Makefile)
You'd better use Linux OR WSL as the development environment, Linux with [Makefile](./Makefile) can help you quickly build and test Open-IM-Server project. You'd better use Linux OR WSL as the development environment, Linux with [Makefile](./Makefile) can help you quickly build and test open-im-server project.
If you are familiar with [Makefile](./Makefile) , you can easily see the clever design of the Open-IM-Server Makefile. Storing the necessary tools such as golangci in the `/tools` directory can avoid some tool version issues. If you are familiar with [Makefile](./Makefile) , you can easily see the clever design of the open-im-server Makefile. Storing the necessary tools such as golangci in the `/tools` directory can avoid some tool version issues.
The [Makefile](./Makefile) is for every developer, even if you don't know how to use the Makefile tool, don't worry, we provide two great commands to get you up to speed with the Makefile architecture, `make help` and `make help-all`, it can reduce problems of the developing environment. The [Makefile](./Makefile) is for every developer, even if you don't know how to use the Makefile tool, don't worry, we provide two great commands to get you up to speed with the Makefile architecture, `make help` and `make help-all`, it can reduce problems of the developing environment.
@@ -52,7 +84,7 @@ In accordance with the naming conventions adopted by OpenIM and drawing referenc
#### Code and doc contribution #### Code and doc contribution
Every action to make project Open-IM-Server better is encouraged. On GitHub, every improvement for Open-IM-Server could be via a [PR](https://github.com/openimsdk/open-im-server/pulls) (short for pull request). Every action to make project open-im-server better is encouraged. On GitHub, every improvement for open-im-server could be via a [PR](https://github.com/openimsdk/open-im-server/pulls) (short for pull request).
+ If you find a typo, try to fix it! + If you find a typo, try to fix it!
+ If you find a bug, try to fix it! + If you find a bug, try to fix it!
@@ -67,8 +99,8 @@ Every action to make project Open-IM-Server better is encouraged. On GitHub, eve
#### Where should I start? #### Where should I start?
+ If you are new to the project, don't know how to contribute Open-IM-Server, please check out the [good first issue](https://github.com/openimsdk/open-im-server/issues?q=is%3Aopen+label%3A"good+first+issue"+sort%3Aupdated-desc) label. + If you are new to the project, don't know how to contribute open-im-server, please check out the [good first issue](https://github.com/openimsdk/open-im-server/issues?q=is%3Aopen+label%3A"good+first+issue"+sort%3Aupdated-desc) label.
+ You should be good at filtering the Open-IM-Server issue tags and finding the ones you like, such as [RFC](https://github.com/openimsdk/open-im-server/issues?q=is%3Aissue+is%3Aopen+RFC+label%3ARFC) for big initiatives, features for [feature](https://github.com/openimsdk/open-im-server/issues?q=is%3Aissue+label%3Afeature) proposals, and [bug](https://github.com/openimsdk/open-im-server/issues?q=is%3Aissue+label%3Abug+) fixes. + You should be good at filtering the open-im-server issue tags and finding the ones you like, such as [RFC](https://github.com/openimsdk/open-im-server/issues?q=is%3Aissue+is%3Aopen+RFC+label%3ARFC) for big initiatives, features for [feature](https://github.com/openimsdk/open-im-server/issues?q=is%3Aissue+label%3Afeature) proposals, and [bug](https://github.com/openimsdk/open-im-server/issues?q=is%3Aissue+label%3Abug+) fixes.
+ If you are looking for something to work on, check out our [open issues](https://github.com/openimsdk/open-im-server/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc). + If you are looking for something to work on, check out our [open issues](https://github.com/openimsdk/open-im-server/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc).
+ If you have an idea for a new feature, please [open an issue](https://github.com/openimsdk/open-im-server/issues/new/choose), and we can discuss it. + If you have an idea for a new feature, please [open an issue](https://github.com/openimsdk/open-im-server/issues/new/choose), and we can discuss it.
@@ -85,7 +117,7 @@ When documenting a new design, we recommend a 2-step approach:
1. Use the short-form RFC template to outline your ideas and get early feedback. 1. Use the short-form RFC template to outline your ideas and get early feedback.
2. Once you have received sufficient feedback and consensus, you may use the longer-form design doc template to specify and discuss your design in more details. 2. Once you have received sufficient feedback and consensus, you may use the longer-form design doc template to specify and discuss your design in more details.
In order to contribute a feature to Open-IM-Server you'll need to go through the following steps: In order to contribute a feature to open-im-server you'll need to go through the following steps:
+ Discuss your idea with the appropriate [working groups](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q) on the working group's Slack channel. + Discuss your idea with the appropriate [working groups](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q) on the working group's Slack channel.
+ Once there is general agreement that the feature is useful, create a GitHub issue to track the discussion. The issue should include information about the requirements and use cases that it is trying to address. + Once there is general agreement that the feature is useful, create a GitHub issue to track the discussion. The issue should include information about the requirements and use cases that it is trying to address.
@@ -95,13 +127,27 @@ But keep in mind that there is no guarantee of it being accepted and so it is us
## Getting Started ## Getting Started
To propose PR for the Open-IM-Server item, we assume you have registered a GitHub ID. Then you could finish the preparation in the following steps: To propose PR for the open-im-server item, we assume you have registered a GitHub ID. Then you could finish the preparation in the following steps:
1. Fork the repository(Open-IM-Server) 1. Fork the repository(open-im-server)
2. **CLONE** your own repository to main locally. Use `git clone https://github.com/<your-username>/Open-IM-Server.git` to clone repository to your local machine. Then you can create new branches to finish the change you wish to make. 2. **CLONE** your own repository to main locally. Use `git clone https://github.com/<your-username>/open-im-server.git` to clone repository to your local machine. Then you can create new branches to finish the change you wish to make.
3. **Set Remote** upstream to be `https://github.com/openimsdk/open-im-server.git` using the following two commands: 3. **Initialize Git Hooks with `make init-githooks`**
After cloning the repository, it's recommended to set up Git hooks to streamline your workflow and ensure your contributions adhere to OpenIM's community standards. Git hooks are scripts that run automatically every time a particular event occurs in a Git repository, such as before a commit or push. To initialize Git hooks for the OpenIM server repository, use the `make init-githooks` command.
- **Enabling Git Hooks Mode**: By running `make init-githooks` and entering `1` when prompted, you enable Git hooks mode. This action will generate a series of hooks within the `.git/hooks/` directory. These hooks impose certain checks on your commits and pushes, ensuring they meet the quality and standards expected by the OpenIM community. For instance, commit hooks might enforce a specific commit message format, while push hooks could check for code style or linting issues.
- **Benefits for First-Time Contributors**: This setup is especially beneficial for new contributors. It guides you to make professional, community-standard-compliant Pull Requests (PRs) and PR descriptions right from your first contribution. By automating checks and balances, it reduces the chances of common mistakes and speeds up the review process.
- **Disabling Git Hooks**: If for any reason you wish to remove the Git hooks, simply run `make init-githooks` again and enter `2` when prompted. This will delete the existing Git hooks, removing the automatic checks and constraints from your Git operations. However, keep in mind that manually ensuring your contributions adhere to community standards without the aid of Git hooks requires diligence.
> [!NOTE] Utilizing Git hooks through the `make init-githooks` command is a straightforward yet powerful way to ensure your contributions are consistent and high-quality. It's a step towards fostering a professional and efficient development environment in the OpenIM project.
4. **Set Remote** upstream to be `https://github.com/openimsdk/open-im-server.git` using the following two commands:
```bash ```bash
git remote add upstream https://github.com/openimsdk/open-im-server.git git remote add upstream https://github.com/openimsdk/open-im-server.git
@@ -112,18 +158,18 @@ To propose PR for the Open-IM-Server item, we assume you have registered a GitHu
```bash ```bash
git remote -v git remote -v
origin https://github.com/<your-username>/Open-IM-Server.git (fetch) origin https://github.com/<your-username>/open-im-server.git (fetch)
origin https://github.com/<your-username>/Open-IM-Server.git (push) origin https://github.com/<your-username>/open-im-server.git (push)
upstream https://github.com/openimsdk/open-im-server.git (fetch) upstream https://github.com/openimsdk/open-im-server.git (fetch)
upstream no-pushing (push) upstream no-pushing (push)
``` ```
Adding this, we can easily synchronize local branches with upstream branches. Adding this, we can easily synchronize local branches with upstream branches.
4. Create a new branch for your changes (use a descriptive name, such as `fix-bug-123` or `add-new-feature`). 5. Create a new branch for your changes (use a descriptive name, such as `fix-bug-123` or `add-new-feature`).
```bash ```bash
cd Open-IM-Server cd open-im-server
git fetch upstream git fetch upstream
git checkout upstream/main git checkout upstream/main
``` ```
@@ -136,7 +182,8 @@ To propose PR for the Open-IM-Server item, we assume you have registered a GitHu
Make any change on the `new-branch` then use [Makefile](./Makefile) build and test your codes. Make any change on the `new-branch` then use [Makefile](./Makefile) build and test your codes.
5. **Commit your changes** to your local branch, lint before committing and commit with sign-off
6. **Commit your changes** to your local branch, lint before committing and commit with sign-off
```bash ```bash
git rebase upstream/main git rebase upstream/main
@@ -145,7 +192,7 @@ To propose PR for the Open-IM-Server item, we assume you have registered a GitHu
git commit -a -s -m "message for your changes" # -s adds a Signed-off-by trailer git commit -a -s -m "message for your changes" # -s adds a Signed-off-by trailer
``` ```
6. **Push your branch** to your forked repository, it is recommended to have only one commit for a PR. 7. **Push your branch** to your forked repository, it is recommended to have only one commit for a PR.
```bash ```bash
# sync up with upstream # sync up with upstream
@@ -177,12 +224,78 @@ To propose PR for the Open-IM-Server item, we assume you have registered a GitHu
git rebase upstream/main # rebase the current branch to upstream/main branch git rebase upstream/main # rebase the current branch to upstream/main branch
git add -A git add -A
git commit -m -s "feat: feature two" git commit -m -s "feat: feature two"
# then create pull request, and merge
``` ```
7. **Open a pull request** to `openimsdk/open-im-server:main` **Verifying Your Pull Request with `make all` Command**
Before verifying, you may need to complete the basic deployment of OpenIM to get familiar with the deployment status of OpenIM. Please read [this deployment document](https://docs.openim.io/zh-Hans/guides/gettingStarted/imSourceCodeDeployment), which will tell you how to deploy OpenIM middleware and OpenIM services in detail
Before submitting your Pull Request (PR), it's crucial to ensure that it passes all the necessary checks and verifications to maintain the quality and integrity of the OpenIM server project. To facilitate this process, we have encapsulated a series of validation steps into the `make all` command.
- **Purpose of `make all` Command**: The `make all` command serves as a comprehensive pre-PR verification tool. It sequentially executes a variety of tasks designed to scrutinize your changes from multiple angles, ensuring they are ready for submission.
- **Included Commands**:
- `tidy`: Cleans up the module by removing unused dependencies.
- `gen`: Generates necessary files from templates or specifications, ensuring that your codebase is up-to-date with its dependencies.
- `add-copyright`: Checks for and adds copyright notices to files, ensuring compliance with legal requirements.
- `verify`: Verifies the integrity and consistency of the code, dependencies, and various checks.
- `test-api`: Runs API tests to ensure that your changes do not break any existing functionality and adhere to the expected behaviors.
- `lint`: Analyzes the code for potential stylistic or programming errors, enforcing the project's coding standards.
- `cover`: Measures the code coverage of tests, helping you understand how much of the code is being tested.
- `restart`: (Optionally) restarts services or applications to ensure that changes are correctly applied and functioning in a live environment.
- **Executing the Command**: To run the `make all` command, simply navigate to the root directory of your cloned repository in your terminal and execute:
```bash
make all
```
This command will sequentially perform all the listed actions, outputting any warnings or errors encountered during the process. It's a vital step to catch any issues early and ensure your contribution meets the quality standards set by the OpenIM community.
- **Benefits**: By using `make all` for pre-PR verification, you significantly increase the likelihood of your PR being accepted on the first review. It not only demonstrates your commitment to quality but also streamlines the review process by minimizing back-and-forth due to common issues that can be caught automatically.
**Troubleshooting Git Push Failures**
When working with Git, encountering errors during push operations is not uncommon. Two primary reasons you might face push failures are due to firewall restrictions or authentication issues. Heres how you can troubleshoot and resolve these problems.
**Firewall Errors**
If you're behind a corporate firewall or your network restricts certain types of traffic, you might encounter issues when trying to push your changes via HTTPS. This is because firewalls can block the ports used by the HTTPS protocol. To resolve this issue, you can configure Git to use a proxy.
If you have a local proxy server set up, you can direct Git to use it by setting the `https_proxy` and `http_proxy` environment variables. Open your terminal or command prompt and run the following commands:
```bash
export https_proxy="http://127.0.0.1:7890"
export http_proxy="http://127.0.0.1:7890"
```
Replace `127.0.0.1:7890` with the address and port of your proxy server. These commands set the proxy for the current session. If you want to make these changes permanent, add them to your `.bashrc`, `.bash_profile`, or equivalent shell configuration file.
**Using SSH Instead of HTTPS**
An alternative to using HTTPS is to set up an SSH connection for Git operations. SSH connections are often not blocked by firewalls and do not require proxy settings. Additionally, SSH provides a secure channel and can simplify the authentication process since it relies on SSH keys rather than username and password credentials.
To use SSH with Git, you first need to generate an SSH key pair and add the public key to your GitHub account (or another Git hosting service).
1. **Generate SSH Key Pair**: Open your terminal and run `ssh-keygen -t rsa -b 4096 -C "your_email@example.com"`, replacing `your_email@example.com` with your email. Press enter to accept the default file location and passphrase prompts.
2. **Add SSH Key to SSH-Agent**: Ensure the ssh-agent is running with `eval "$(ssh-agent -s)"` and then add your SSH private key to the ssh-agent using `ssh-add ~/.ssh/id_rsa`.
3. **Add SSH Key to GitHub**: Copy your SSH public key to your clipboard with `cat ~/.ssh/id_rsa.pub | clip` (Windows) or `pbcopy < ~/.ssh/id_rsa.pub` (Mac). Go to GitHub, navigate to Settings > SSH and GPG keys, and add a new SSH key, pasting your key into the field provided.
4. **Switch to SSH in Your Repository**: Change your repository's remote URL from HTTPS to SSH. You can find the SSH URL in your repository settings on GitHub and use `git remote set-url origin git@github.com:username/repository.git` to switch.
**Authentication Errors**
If you're experiencing authentication errors, it might be due to missing or incorrect credentials. Ensure you have added your SSH key to your Git hosting service. You can test your SSH connection with `ssh -T git@github.com` (replace `github.com` with your Git hosting service's domain). If successful, you'll receive a welcome message.
For HTTPS users, check that your username and password (or personal access token for services like GitHub that no longer accept password authentication for Git operations) are correct.
8. **Open a pull request** to `openimsdk/open-im-server:main`
It is recommended to review your changes before filing a pull request. Check if your code doesn't conflict with the main branch and no redundant code is included. It is recommended to review your changes before filing a pull request. Check if your code doesn't conflict with the main branch and no redundant code is included.
> [!TIP] There is a [good blog post documenting](https://nsddd.top/posts/participating-in-this-project/) the entire push contribution process.
## Style and Specification ## Style and Specification
@@ -190,15 +303,15 @@ We divide the problem into security and general problems:
#### Reporting security issues #### Reporting security issues
Security issues are always treated seriously. As our usual principle, we discourage anyone to spread security issues. If you find a security issue of Open-IM-Server, please do not discuss it in public and even do not open a public issue. Security issues are always treated seriously. As our usual principle, we discourage anyone to spread security issues. If you find a security issue of open-im-server, please do not discuss it in public and even do not open a public issue.
Instead we encourage you to send us a private email to info@openim.io to report this. Instead we encourage you to send us a private email to info@openim.io to report this.
#### Reporting general issues #### Reporting general issues
To be honest, we regard every user of Open-IM-Serveras a very kind contributor. After experiencing Open-IM-Server, you may have some feedback for the project. Then feel free to open an issue via [NEW ISSUE](https://github.com/openimsdk/open-im-server/issues/new/choose). To be honest, we regard every user of open-im-serveras a very kind contributor. After experiencing open-im-server, you may have some feedback for the project. Then feel free to open an issue via [NEW ISSUE](https://github.com/openimsdk/open-im-server/issues/new/choose).
Since we collaborate project Open-IM-Server in a distributed way, we appreciate **WELL-WRITTEN**, **DETAILED**, **EXPLICIT** issue reports. To make the communication more efficient, we wish everyone could search if your issue is an existing one in the searching list. If you find it existing, please add your details in comments under the existing issue instead of opening a brand new one. Since we collaborate project open-im-server in a distributed way, we appreciate **WELL-WRITTEN**, **DETAILED**, **EXPLICIT** issue reports. To make the communication more efficient, we wish everyone could search if your issue is an existing one in the searching list. If you find it existing, please add your details in comments under the existing issue instead of opening a brand new one.
To make the issue details as standard as possible, we setup an [ISSUE TEMPLATE](https://github.com/OpenIMSDK/.github/tree/main/.github/ISSUE_TEMPLATE) for issue reporters. You can find three kinds of issue templates there: question, bug report and feature request. Please **BE SURE** to follow the instructions to fill fields in template. To make the issue details as standard as possible, we setup an [ISSUE TEMPLATE](https://github.com/OpenIMSDK/.github/tree/main/.github/ISSUE_TEMPLATE) for issue reporters. You can find three kinds of issue templates there: question, bug report and feature request. Please **BE SURE** to follow the instructions to fill fields in template.
@@ -206,20 +319,20 @@ To make the issue details as standard as possible, we setup an [ISSUE TEMPLATE](
+ bug report + bug report
+ feature request + feature request
+ Open-IM-Server performance issues + open-im-server performance issues
+ feature proposal + feature proposal
+ feature design + feature design
+ help wanted + help wanted
+ doc incomplete + doc incomplete
+ test improvement + test improvement
+ any questions on Open-IM-Server project + any questions on open-im-server project
+ and so on + and so on
Also, we must be reminded when submitting a new question about Open-IM-Server, please remember to remove the sensitive data from your post. Sensitive data could be password, secret key, network locations, private business data and so on. Also, we must be reminded when submitting a new question about open-im-server, please remember to remove the sensitive data from your post. Sensitive data could be password, secret key, network locations, private business data and so on.
#### Commit Rules #### Commit Rules
Actually in Open-IM-Server, we take two rules serious when committing: Actually in open-im-server, we take two rules serious when committing:
**🥇 Commit Message:** **🥇 Commit Message:**
@@ -262,7 +375,7 @@ An example for this could be:
#### PR Description #### PR Description
PR is the only way to make change to Open-IM-Server project files. To help reviewers better get your purpose, PR description could not be too detailed. We encourage contributors to follow the [PR template](https://github.com/OpenIMSDK/.github/tree/main/.github/PULL_REQUEST_TEMPLATE.md) to finish the pull request. PR is the only way to make change to open-im-server project files. To help reviewers better get your purpose, PR description could not be too detailed. We encourage contributors to follow the [PR template](https://github.com/OpenIMSDK/.github/tree/main/.github/PULL_REQUEST_TEMPLATE.md) to finish the pull request.
You can find some very formal PR in [RFC](https://github.com/openimsdk/open-im-server/issues?q=is%3Aissue+is%3Aopen+RFC+label%3ARFC) issues and learn about them. You can find some very formal PR in [RFC](https://github.com/openimsdk/open-im-server/issues?q=is%3Aissue+is%3Aopen+RFC+label%3ARFC) issues and learn about them.
@@ -311,11 +424,11 @@ git() {
#### Docs Contribution #### Docs Contribution
The documentation for Open-IM-Server includes: The documentation for open-im-server includes:
+ [README.md](https://github.com/openimsdk/open-im-server/blob/main/README.md): This file includes the basic information and instructions for getting started with Open-IM-Server. + [README.md](https://github.com/openimsdk/open-im-server/blob/main/README.md): This file includes the basic information and instructions for getting started with open-im-server.
+ [CONTRIBUTING.md](https://github.com/openimsdk/open-im-server/blob/main/CONTRIBUTING.md): This file contains guidelines for contributing to Open-IM-Server's codebase, such as how to submit issues, pull requests, and code reviews. + [CONTRIBUTING.md](https://github.com/openimsdk/open-im-server/blob/main/CONTRIBUTING.md): This file contains guidelines for contributing to open-im-server's codebase, such as how to submit issues, pull requests, and code reviews.
+ [Official Documentation](https://doc.rentsoft.cn/): This is the official documentation for Open-IM-Server, which includes comprehensive information on all of its features, configuration options, and troubleshooting tips. + [Official Documentation](https://doc.rentsoft.cn/): This is the official documentation for open-im-server, which includes comprehensive information on all of its features, configuration options, and troubleshooting tips.
Please obey the following rules to better format the docs, which would greatly improve the reading experience. Please obey the following rules to better format the docs, which would greatly improve the reading experience.
@@ -328,20 +441,20 @@ Please obey the following rules to better format the docs, which would greatly i
## Engage to help anything ## Engage to help anything
We choose GitHub as the primary place for Open-IM-Server to collaborate. So the latest updates of Open-IM-Server are always here. Although contributions via PR is an explicit way to help, we still call for any other ways. We choose GitHub as the primary place for open-im-server to collaborate. So the latest updates of open-im-server are always here. Although contributions via PR is an explicit way to help, we still call for any other ways.
+ reply to other's [issues](https://github.com/openimsdk/open-im-server/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc) if you could; + reply to other's [issues](https://github.com/openimsdk/open-im-server/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc) if you could;
+ help solve other user's problems; + help solve other user's problems;
+ help review other's [PR](https://github.com/openimsdk/open-im-server/pulls?q=is%3Apr+is%3Aopen+sort%3Aupdated-desc) design; + help review other's [PR](https://github.com/openimsdk/open-im-server/pulls?q=is%3Apr+is%3Aopen+sort%3Aupdated-desc) design;
+ discuss about Open-IM-Server to make things clearer; + discuss about open-im-server to make things clearer;
+ advocate [Open-IM-Server](https://google.com/search?q=Open-IM-Server) technology beyond GitHub; + advocate [open-im-server](https://google.com/search?q=open-im-server) technology beyond GitHub;
+ write blogs on Open-IM-Server and so on. + write blogs on open-im-server and so on.
In a word, **ANY HELP IS CONTRIBUTION.** In a word, **ANY HELP IS CONTRIBUTION.**
## Release version ## Release version
Releases of Open-IM-Server are done using [Release Please](https://github.com/googleapis/release-please) and [GoReleaser](https://goreleaser.com/). The workflow looks like this: Releases of open-im-server are done using [Release Please](https://github.com/googleapis/release-please) and [GoReleaser](https://goreleaser.com/). The workflow looks like this:
🎯 A PR is merged to the `main` branch: 🎯 A PR is merged to the `main` branch:
@@ -366,17 +479,23 @@ Such a commit can get produced as follows:
git commit --allow-empty -m "chore: release 0.0.3" -m "Release-As: 0.0.3 git commit --allow-empty -m "chore: release 0.0.3" -m "Release-As: 0.0.3
```` ````
For the complex release process, in fact, and encapsulation as CICD, you only need to tag locally, and then publish the tag to OpenIM github to complete the entire OpenIM release process.
In addition to CICD, we also do a complex release command locally, which can help you complete the full platform compilation, testing, and release to Minio, just by using the `make release` command.
Please [read the detailed documents](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/release.md)
## Contact Us ## Contact Us
We value close connections with our users, developers, and contributors here at Open-IM-Server. With a large community and maintainer team, we're always here to help and support you. Whether you're looking to join our community or have any questions or suggestions, we welcome you to get in touch with us. We value close connections with our users, developers, and contributors here at open-im-server. With a large community and maintainer team, we're always here to help and support you. Whether you're looking to join our community or have any questions or suggestions, we welcome you to get in touch with us.
Our most recommended way to get in touch is through [Slack](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q). Even if you're in China, Slack is usually not blocked by firewalls, making it an easy way to connect with us. Our Slack community is the ideal place to discuss and share ideas and suggestions with other users and developers of Open-IM-Server. You can ask technical questions, seek help, or share your experiences with other users of Open-IM-Server. Our most recommended way to get in touch is through [Slack](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q). Even if you're in China, Slack is usually not blocked by firewalls, making it an easy way to connect with us. Our Slack community is the ideal place to discuss and share ideas and suggestions with other users and developers of open-im-server. You can ask technical questions, seek help, or share your experiences with other users of open-im-server.
In addition to Slack, we also offer the following ways to get in touch: In addition to Slack, we also offer the following ways to get in touch:
+ <a href="https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q" target="_blank"><img src="https://img.shields.io/badge/slack-%40OpenIMSDKCore-informational?logo=slack&style=flat-square"></a>: We also have Slack channels for you to communicate and discuss. To join, visit https://slack.com/ and join our [👀 Open-IM-Server slack](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q) team channel. + <a href="https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q" target="_blank"><img src="https://img.shields.io/badge/slack-%40OpenIMSDKCore-informational?logo=slack&style=flat-square"></a>: We also have Slack channels for you to communicate and discuss. To join, visit https://slack.com/ and join our [👀 open-im-server slack](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q) team channel.
+ <a href="https://mail.google.com/mail/u/0/?fs=1&tf=cm&to=4closetool3@gmail.com" target="_blank"><img src="https://img.shields.io/badge/gmail-%40OOpenIMSDKCore?style=social&logo=gmail"></a>: Get in touch with us on [Gmail](info@openim.io). If you have any questions or issues that need resolving, or any suggestions and feedback for our open source projects, please feel free to contact us via email. + <a href="https://mail.google.com/mail/u/0/?fs=1&tf=cm&to=4closetool3@gmail.com" target="_blank"><img src="https://img.shields.io/badge/gmail-%40OOpenIMSDKCore?style=social&logo=gmail"></a>: Get in touch with us on [Gmail](info@openim.io). If you have any questions or issues that need resolving, or any suggestions and feedback for our open source projects, please feel free to contact us via email.
+ <a href="https://doc.rentsoft.cn/" target="_blank"><img src="https://img.shields.io/badge/%E5%8D%9A%E5%AE%A2-%40OpenIMSDKCore-blue?style=social&logo=Octopus%20Deploy"></a>: Read our [blog](https://doc.rentsoft.cn/). Our blog is a great place to stay up-to-date with Open-IM-Server projects and trends. On the blog, we share our latest developments, tech trends, and other interesting information. + <a href="https://doc.rentsoft.cn/" target="_blank"><img src="https://img.shields.io/badge/%E5%8D%9A%E5%AE%A2-%40OpenIMSDKCore-blue?style=social&logo=Octopus%20Deploy"></a>: Read our [blog](https://doc.rentsoft.cn/). Our blog is a great place to stay up-to-date with open-im-server projects and trends. On the blog, we share our latest developments, tech trends, and other interesting information.
+ <a href="https://github.com/OpenIMSDK/OpenIM-Docs/blob/main/docs/images/WechatIMG20.jpeg" target="_blank"><img src="https://img.shields.io/badge/%E5%BE%AE%E4%BF%A1-OpenIMSDKCore-brightgreen?logo=wechat&style=flat-square"></a>: Add [Wechat](https://github.com/OpenIMSDK/OpenIM-Docs/blob/main/docs/images/WechatIMG20.jpeg) and indicate that you are a user or developer of Open-IM-Server. We will process your request as soon as possible. + <a href="https://github.com/OpenIMSDK/OpenIM-Docs/blob/main/docs/images/WechatIMG20.jpeg" target="_blank"><img src="https://img.shields.io/badge/%E5%BE%AE%E4%BF%A1-OpenIMSDKCore-brightgreen?logo=wechat&style=flat-square"></a>: Add [Wechat](https://github.com/OpenIMSDK/OpenIM-Docs/blob/main/docs/images/WechatIMG20.jpeg) and indicate that you are a user or developer of open-im-server. We will process your request as soon as possible.
Whether you're looking to join our community or have any questions or suggestions, we welcome you to get in touch with us. Whether you're looking to join our community or have any questions or suggestions, we welcome you to get in touch with us.

View File

@@ -4,29 +4,51 @@
</a> </a>
</p> </p>
<h3 align="center" style="border-bottom: none"> <div align="center">
⭐️ Open source Instant Messaging Server ⭐️ <br>
<h3>
[![Stars](https://img.shields.io/github/stars/openimsdk/open-im-server?style=for-the-badge&logo=github&colorB=ff69b4)](https://github.com/openimsdk/open-im-server/stargazers)
[![Forks](https://img.shields.io/github/forks/openimsdk/open-im-server?style=for-the-badge&logo=github&colorB=blue)](https://github.com/openimsdk/open-im-server/network/members)
[![Codecov](https://img.shields.io/codecov/c/github/openimsdk/open-im-server?style=for-the-badge&logo=codecov&colorB=orange)](https://app.codecov.io/gh/openimsdk/open-im-server)
[![Go Report Card](https://goreportcard.com/badge/github.com/openimsdk/open-im-server?style=for-the-badge)](https://goreportcard.com/report/github.com/openimsdk/open-im-server)
[![Go Reference](https://img.shields.io/badge/Go%20Reference-blue.svg?style=for-the-badge&logo=go&logoColor=white)](https://pkg.go.dev/github.com/openimsdk/open-im-server/v3)
[![License](https://img.shields.io/badge/license-Apache--2.0-green?style=for-the-badge)](https://github.com/openimsdk/open-im-server/blob/main/LICENSE)
[![Slack](https://img.shields.io/badge/Slack-500%2B-blueviolet?style=for-the-badge&logo=slack&logoColor=white)](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q)
[![Best Practices](https://img.shields.io/badge/Best%20Practices-purple?style=for-the-badge)](https://www.bestpractices.dev/projects/8045)
[![Good First Issues](https://img.shields.io/github/issues/openimsdk/open-im-server/good%20first%20issue?style=for-the-badge&logo=github)](https://github.com/openimsdk/open-im-server/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc+label%3A%22good+first+issue%22)
[![Language](https://img.shields.io/badge/Language-Go-blue.svg?style=for-the-badge&logo=go&logoColor=white)](https://golang.org/)
<p align=center>
<a href="https://goreportcard.com/report/github.com/openimsdk/open-im-server"><img src="https://goreportcard.com/badge/github.com/openimsdk/open-im-server" alt="A+"></a>
<a href="https://github.com/openimsdk/open-im-server/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc+label%3A%22good+first+issue%22"><img src="https://img.shields.io/github/issues/openimsdk/open-im-server/good%20first%20issue?logo=%22github%22" alt="good first"></a>
<a href="https://github.com/openimsdk/open-im-server"><img src="https://img.shields.io/github/stars/openimsdk/open-im-server.svg?style=flat&logo=github&colorB=deeppink&label=stars"></a>
<a href="https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q"><img src="https://img.shields.io/badge/Slack-300%2B-blueviolet?logo=slack&amp;logoColor=white"></a>
<a href="https://github.com/openimsdk/open-im-server/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-Apache--2.0-green"></a>
<a href="https://golang.org/"><img src="https://img.shields.io/badge/Language-Go-blue.svg"></a>
</p>
</p>
<p align="center"> <p align="center">
<a href="./README.md"><b> English </b></a> <a href="./README.md">Englist</a> ·
<a href="./README-zh_CN.md"><b> 简体中文 </b></a> <a href="./README-zh_CN.md">中文</a> ·
<a href="https://openim.io/en"><b> Docs </b></a> <a href="docs/readme/README-UA.md">Українська</a> ·
<a href="docs/readme/README-CS.md">Česky</a> ·
<a href="docs/readme/README-HU.md">Magyar</a> ·
<a href="docs/readme/README-ES.md">Español</a> ·
<a href="docs/readme/README-FA.md">فارسی</a> ·
<a href="docs/readme/README-FR.md">Français</a> ·
<a href="docs/readme/README-DE.md">Deutsch</a> ·
<a href="docs/readme/README-PL.md">Polski</a> ·
<a href="docs/readme/README-ID.md">Indonesian</a> ·
<a href="docs/readme/README-FI.md">Suomi</a> ·
<a href="docs/readme/README-ML.md">മലയാളം</a> ·
<a href="docs/readme/README-JP.md">日本語</a> ·
<a href="docs/readme/README-NL.md">Nederlands</a> ·
<a href="docs/readme/README-IT.md">Italiano</a> ·
<a href="docs/readme/README-RU.md">Русский</a> ·
<a href="docs/readme/README-PTBR.md">Português (Brasil)</a> ·
<a href="docs/readme/README-EO.md">Esperanto</a> ·
<a href="docs/readme/README-KR.md">한국어</a> ·
<a href="docs/readme/README-AR.md">العربي</a> ·
<a href="docs/readme/README-VN.md">Tiếng Việt</a> ·
<a href="docs/readme/README-DA.md">Dansk</a> ·
<a href="docs/readme/README-GR.md">Ελληνικά</a> ·
<a href="docs/readme/README-TR.md">Türkçe</a>
</p> </p>
</div>
</p> </p>
## 🟢 扫描微信进群交流 ## 🟢 扫描微信进群交流
@@ -39,8 +61,6 @@ OpenIM 是一个专门设计用于在应用程序中集成聊天、音视频通
![App-OpenIM 关系](./docs/images/oepnim-design.png) ![App-OpenIM 关系](./docs/images/oepnim-design.png)
## 🚀 关于 OpenIMSDK ## 🚀 关于 OpenIMSDK

View File

@@ -17,9 +17,35 @@
[![Good First Issues](https://img.shields.io/github/issues/openimsdk/open-im-server/good%20first%20issue?style=for-the-badge&logo=github)](https://github.com/openimsdk/open-im-server/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc+label%3A%22good+first+issue%22) [![Good First Issues](https://img.shields.io/github/issues/openimsdk/open-im-server/good%20first%20issue?style=for-the-badge&logo=github)](https://github.com/openimsdk/open-im-server/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc+label%3A%22good+first+issue%22)
[![Language](https://img.shields.io/badge/Language-Go-blue.svg?style=for-the-badge&logo=go&logoColor=white)](https://golang.org/) [![Language](https://img.shields.io/badge/Language-Go-blue.svg?style=for-the-badge&logo=go&logoColor=white)](https://golang.org/)
[**English**](./README.md) •
[**简体中文**](./README-zh_CN.md) • <p align="center">
[**Docs**](https://openim.io/en) <a href="./README.md">Englist</a> ·
<a href="./README-zh_CN.md">中文</a> ·
<a href="docs/readme/README-UA.md">Українська</a> ·
<a href="docs/readme/README-CS.md">Česky</a> ·
<a href="docs/readme/README-HU.md">Magyar</a> ·
<a href="docs/readme/README-ES.md">Español</a> ·
<a href="docs/readme/README-FA.md">فارسی</a> ·
<a href="docs/readme/README-FR.md">Français</a> ·
<a href="docs/readme/README-DE.md">Deutsch</a> ·
<a href="docs/readme/README-PL.md">Polski</a> ·
<a href="docs/readme/README-ID.md">Indonesian</a> ·
<a href="docs/readme/README-FI.md">Suomi</a> ·
<a href="docs/readme/README-ML.md">മലയാളം</a> ·
<a href="docs/readme/README-JP.md">日本語</a> ·
<a href="docs/readme/README-NL.md">Nederlands</a> ·
<a href="docs/readme/README-IT.md">Italiano</a> ·
<a href="docs/readme/README-RU.md">Русский</a> ·
<a href="docs/readme/README-PTBR.md">Português (Brasil)</a> ·
<a href="docs/readme/README-EO.md">Esperanto</a> ·
<a href="docs/readme/README-KR.md">한국어</a> ·
<a href="docs/readme/README-AR.md">العربي</a> ·
<a href="docs/readme/README-VN.md">Tiếng Việt</a> ·
<a href="docs/readme/README-DA.md">Dansk</a> ·
<a href="docs/readme/README-GR.md">Ελληνικά</a> ·
<a href="docs/readme/README-TR.md">Türkçe</a>
</p>
</div> </div>
@@ -68,6 +94,13 @@ It is built using Golang and supports cross-platform deployment, ensuring a cons
👉 **[Learn more](https://docs.openim.io/guides/introduction/product)** 👉 **[Learn more](https://docs.openim.io/guides/introduction/product)**
## :building_construction: Overall Architecture
Delve into the heart of Open-IM-Server's functionality with our architecture diagram.
![Overall Architecture](./docs/images/architecture-layers.png)
## :rocket: Quick Start ## :rocket: Quick Start
We support many platforms. Here are the addresses for quick experience on the web side We support many platforms. Here are the addresses for quick experience on the web side

View File

@@ -26,9 +26,10 @@ import (
"syscall" "syscall"
"time" "time"
"github.com/OpenIMSDK/tools/errs"
"github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/protocol/constant"
"github.com/OpenIMSDK/tools/discoveryregistry" "github.com/OpenIMSDK/tools/discoveryregistry"
"github.com/OpenIMSDK/tools/log"
"github.com/openimsdk/open-im-server/v3/internal/api" "github.com/openimsdk/open-im-server/v3/internal/api"
"github.com/openimsdk/open-im-server/v3/pkg/common/cmd" "github.com/openimsdk/open-im-server/v3/pkg/common/cmd"
@@ -44,55 +45,43 @@ func main() {
apiCmd.AddPortFlag() apiCmd.AddPortFlag()
apiCmd.AddApi(run) apiCmd.AddApi(run)
if err := apiCmd.Execute(); err != nil { if err := apiCmd.Execute(); err != nil {
log.ZError(context.Background(), "API command execution failed", err) fmt.Fprintf(os.Stderr, "\n\nexit -1: \n%+v\n\n", err)
panic(err.Error()) os.Exit(-1)
} }
} }
func run(port int, proPort int) error { func run(port int, proPort int) error {
log.ZInfo(context.Background(), "Openim api port:", "port", port, "proPort", proPort)
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) return errs.Wrap(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)
return err return err
} }
log.ZInfo(context.Background(), "api start init discov client")
var client discoveryregistry.SvcDiscoveryRegistry var client discoveryregistry.SvcDiscoveryRegistry
// Determine whether zk is passed according to whether it is a clustered deployment // Determine whether zk is passed according to whether it is a clustered deployment
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) return errs.Wrap(err, "register discovery 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) return errs.Wrap(err, "create rpc root nodes error")
return err
} }
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)
return err return err
} }
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")
var address string var address string
if config.Config.Api.ListenIP != "" { if config.Config.Api.ListenIP != "" {
@@ -100,13 +89,11 @@ func run(port int, proPort int) error {
} else { } else {
address = net.JoinHostPort("0.0.0.0", strconv.Itoa(port)) address = net.JoinHostPort("0.0.0.0", strconv.Itoa(port))
} }
log.ZInfo(context.Background(), "start api server", "address", address, "OpenIM version", config.Version)
server := http.Server{Addr: address, Handler: router} server := http.Server{Addr: address, Handler: router}
go func() { go func() {
err = server.ListenAndServe() err = server.ListenAndServe()
if err != nil && err != http.ErrServerClosed { if err != nil && err != http.ErrServerClosed {
log.ZError(context.Background(), "api run failed", err, "address", address)
os.Exit(1) os.Exit(1)
} }
}() }()
@@ -120,7 +107,6 @@ func run(port int, proPort int) error {
// graceful shutdown operation. // graceful shutdown operation.
if err := server.Shutdown(ctx); err != nil { if err := server.Shutdown(ctx); err != nil {
log.ZError(context.Background(), "failed to api-server shutdown", err)
return err return err
} }

View File

@@ -15,6 +15,9 @@
package main package main
import ( import (
"fmt"
"os"
"github.com/openimsdk/open-im-server/v3/pkg/common/cmd" "github.com/openimsdk/open-im-server/v3/pkg/common/cmd"
) )
@@ -54,6 +57,7 @@ func main() {
// openIM clear msg --clearAll // openIM clear msg --clearAll
msgUtilsCmd.AddCommand(&getCmd.Command, &fixCmd.Command, &clearCmd.Command) msgUtilsCmd.AddCommand(&getCmd.Command, &fixCmd.Command, &clearCmd.Command)
if err := msgUtilsCmd.Execute(); err != nil { if err := msgUtilsCmd.Execute(); err != nil {
panic(err) fmt.Fprintf(os.Stderr, "\n\nexit -1: \n%+v\n\n", err)
os.Exit(-1)
} }
} }

View File

@@ -15,6 +15,9 @@
package main package main
import ( import (
"fmt"
"os"
"github.com/openimsdk/open-im-server/v3/internal/tools" "github.com/openimsdk/open-im-server/v3/internal/tools"
"github.com/openimsdk/open-im-server/v3/pkg/common/cmd" "github.com/openimsdk/open-im-server/v3/pkg/common/cmd"
) )
@@ -22,6 +25,7 @@ import (
func main() { func main() {
cronTaskCmd := cmd.NewCronTaskCmd() cronTaskCmd := cmd.NewCronTaskCmd()
if err := cronTaskCmd.Exec(tools.StartTask); err != nil { if err := cronTaskCmd.Exec(tools.StartTask); err != nil {
panic(err.Error()) fmt.Fprintf(os.Stderr, "\n\nexit -1: \n%+v\n\n", err)
os.Exit(-1)
} }
} }

View File

@@ -15,6 +15,9 @@
package main package main
import ( import (
"fmt"
"os"
"github.com/openimsdk/open-im-server/v3/pkg/common/cmd" "github.com/openimsdk/open-im-server/v3/pkg/common/cmd"
) )
@@ -25,6 +28,7 @@ func main() {
msgGatewayCmd.AddPrometheusPortFlag() msgGatewayCmd.AddPrometheusPortFlag()
if err := msgGatewayCmd.Exec(); err != nil { if err := msgGatewayCmd.Exec(); err != nil {
panic(err.Error()) fmt.Fprintf(os.Stderr, "\n\nexit -1: \n%+v\n\n", err)
os.Exit(-1)
} }
} }

View File

@@ -15,6 +15,9 @@
package main package main
import ( import (
"fmt"
"os"
"github.com/openimsdk/open-im-server/v3/pkg/common/cmd" "github.com/openimsdk/open-im-server/v3/pkg/common/cmd"
) )
@@ -23,6 +26,7 @@ func main() {
msgTransferCmd.AddPrometheusPortFlag() msgTransferCmd.AddPrometheusPortFlag()
msgTransferCmd.AddTransferProgressFlag() msgTransferCmd.AddTransferProgressFlag()
if err := msgTransferCmd.Exec(); err != nil { if err := msgTransferCmd.Exec(); err != nil {
panic(err.Error()) fmt.Fprintf(os.Stderr, "\n\nexit -1: \n%+v\n\n", err)
os.Exit(-1)
} }
} }

View File

@@ -15,6 +15,9 @@
package main package main
import ( import (
"fmt"
"os"
"github.com/openimsdk/open-im-server/v3/internal/push" "github.com/openimsdk/open-im-server/v3/internal/push"
"github.com/openimsdk/open-im-server/v3/pkg/common/cmd" "github.com/openimsdk/open-im-server/v3/pkg/common/cmd"
"github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/config"
@@ -28,6 +31,7 @@ func main() {
panic(err.Error()) panic(err.Error())
} }
if err := pushCmd.StartSvr(config.Config.RpcRegisterName.OpenImPushName, push.Start); err != nil { if err := pushCmd.StartSvr(config.Config.RpcRegisterName.OpenImPushName, push.Start); err != nil {
panic(err.Error()) fmt.Fprintf(os.Stderr, "\n\nexit -1: \n%+v\n\n", err)
os.Exit(-1)
} }
} }

View File

@@ -15,6 +15,9 @@
package main package main
import ( import (
"fmt"
"os"
"github.com/openimsdk/open-im-server/v3/internal/rpc/auth" "github.com/openimsdk/open-im-server/v3/internal/rpc/auth"
"github.com/openimsdk/open-im-server/v3/pkg/common/cmd" "github.com/openimsdk/open-im-server/v3/pkg/common/cmd"
"github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/config"
@@ -28,6 +31,7 @@ func main() {
panic(err.Error()) panic(err.Error())
} }
if err := authCmd.StartSvr(config.Config.RpcRegisterName.OpenImAuthName, auth.Start); err != nil { if err := authCmd.StartSvr(config.Config.RpcRegisterName.OpenImAuthName, auth.Start); err != nil {
panic(err.Error()) fmt.Fprintf(os.Stderr, "\n\nexit -1: \n%+v\n\n", err)
os.Exit(-1)
} }
} }

View File

@@ -15,6 +15,9 @@
package main package main
import ( import (
"fmt"
"os"
"github.com/openimsdk/open-im-server/v3/internal/rpc/conversation" "github.com/openimsdk/open-im-server/v3/internal/rpc/conversation"
"github.com/openimsdk/open-im-server/v3/pkg/common/cmd" "github.com/openimsdk/open-im-server/v3/pkg/common/cmd"
"github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/config"
@@ -28,6 +31,7 @@ func main() {
panic(err.Error()) panic(err.Error())
} }
if err := rpcCmd.StartSvr(config.Config.RpcRegisterName.OpenImConversationName, conversation.Start); err != nil { if err := rpcCmd.StartSvr(config.Config.RpcRegisterName.OpenImConversationName, conversation.Start); err != nil {
panic(err.Error()) fmt.Fprintf(os.Stderr, "\n\nexit -1: \n%+v\n\n", err)
os.Exit(-1)
} }
} }

View File

@@ -15,6 +15,9 @@
package main package main
import ( import (
"fmt"
"os"
"github.com/openimsdk/open-im-server/v3/internal/rpc/friend" "github.com/openimsdk/open-im-server/v3/internal/rpc/friend"
"github.com/openimsdk/open-im-server/v3/pkg/common/cmd" "github.com/openimsdk/open-im-server/v3/pkg/common/cmd"
"github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/config"
@@ -28,6 +31,7 @@ func main() {
panic(err.Error()) panic(err.Error())
} }
if err := rpcCmd.StartSvr(config.Config.RpcRegisterName.OpenImFriendName, friend.Start); err != nil { if err := rpcCmd.StartSvr(config.Config.RpcRegisterName.OpenImFriendName, friend.Start); err != nil {
panic(err.Error()) fmt.Fprintf(os.Stderr, "\n\nexit -1: \n%+v\n\n", err)
os.Exit(-1)
} }
} }

View File

@@ -15,6 +15,9 @@
package main package main
import ( import (
"fmt"
"os"
"github.com/openimsdk/open-im-server/v3/internal/rpc/group" "github.com/openimsdk/open-im-server/v3/internal/rpc/group"
"github.com/openimsdk/open-im-server/v3/pkg/common/cmd" "github.com/openimsdk/open-im-server/v3/pkg/common/cmd"
"github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/config"
@@ -28,6 +31,7 @@ func main() {
panic(err.Error()) panic(err.Error())
} }
if err := rpcCmd.StartSvr(config.Config.RpcRegisterName.OpenImGroupName, group.Start); err != nil { if err := rpcCmd.StartSvr(config.Config.RpcRegisterName.OpenImGroupName, group.Start); err != nil {
panic(err.Error()) fmt.Fprintf(os.Stderr, "\n\nexit -1: \n%+v\n\n", err)
os.Exit(-1)
} }
} }

View File

@@ -15,6 +15,9 @@
package main package main
import ( import (
"fmt"
"os"
"github.com/openimsdk/open-im-server/v3/internal/rpc/msg" "github.com/openimsdk/open-im-server/v3/internal/rpc/msg"
"github.com/openimsdk/open-im-server/v3/pkg/common/cmd" "github.com/openimsdk/open-im-server/v3/pkg/common/cmd"
"github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/config"
@@ -28,6 +31,7 @@ func main() {
panic(err.Error()) panic(err.Error())
} }
if err := rpcCmd.StartSvr(config.Config.RpcRegisterName.OpenImMsgName, msg.Start); err != nil { if err := rpcCmd.StartSvr(config.Config.RpcRegisterName.OpenImMsgName, msg.Start); err != nil {
panic(err.Error()) fmt.Fprintf(os.Stderr, "\n\nexit -1: \n%+v\n\n", err)
os.Exit(-1)
} }
} }

View File

@@ -15,6 +15,9 @@
package main package main
import ( import (
"fmt"
"os"
"github.com/openimsdk/open-im-server/v3/internal/rpc/third" "github.com/openimsdk/open-im-server/v3/internal/rpc/third"
"github.com/openimsdk/open-im-server/v3/pkg/common/cmd" "github.com/openimsdk/open-im-server/v3/pkg/common/cmd"
"github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/config"
@@ -28,6 +31,7 @@ func main() {
panic(err.Error()) panic(err.Error())
} }
if err := rpcCmd.StartSvr(config.Config.RpcRegisterName.OpenImThirdName, third.Start); err != nil { if err := rpcCmd.StartSvr(config.Config.RpcRegisterName.OpenImThirdName, third.Start); err != nil {
panic(err.Error()) fmt.Fprintf(os.Stderr, "\n\nexit -1: \n%+v\n\n", err)
os.Exit(-1)
} }
} }

View File

@@ -15,6 +15,9 @@
package main package main
import ( import (
"fmt"
"os"
"github.com/openimsdk/open-im-server/v3/internal/rpc/user" "github.com/openimsdk/open-im-server/v3/internal/rpc/user"
"github.com/openimsdk/open-im-server/v3/pkg/common/cmd" "github.com/openimsdk/open-im-server/v3/pkg/common/cmd"
"github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/config"
@@ -28,6 +31,7 @@ func main() {
panic(err.Error()) panic(err.Error())
} }
if err := rpcCmd.StartSvr(config.Config.RpcRegisterName.OpenImUserName, user.Start); err != nil { if err := rpcCmd.StartSvr(config.Config.RpcRegisterName.OpenImUserName, user.Start); err != nil {
panic(err.Error()) fmt.Fprintf(os.Stderr, "\n\nexit -1: \n%+v\n\n", err)
os.Exit(-1)
} }
} }

View File

@@ -243,9 +243,10 @@ push:
# #
# Built-in app manager user IDs # Built-in app manager user IDs
# Built-in app manager nicknames # Built-in app manager nicknames
# Attention, this configure is discarded. If you have used him before, configure your own
manager: manager:
userID: [ "${MANAGER_USERID_1}", "${MANAGER_USERID_2}", "${MANAGER_USERID_3}" ] userID:
nickname: [ "${NICKNAME_1}", "${NICKNAME_2}", "${NICKNAME_3}" ] nickname:
# chatAdmin, use for send notification # chatAdmin, use for send notification
# #
@@ -329,7 +330,7 @@ callback:
timeout: ${CALLBACK_TIMEOUT} timeout: ${CALLBACK_TIMEOUT}
failedContinue: ${CALLBACK_FAILED_CONTINUE} failedContinue: ${CALLBACK_FAILED_CONTINUE}
afterSendSingleMsg: afterSendSingleMsg:
enable: true enable: ${CALLBACK_ENABLE}
timeout: ${CALLBACK_TIMEOUT} timeout: ${CALLBACK_TIMEOUT}
failedContinue: ${CALLBACK_FAILED_CONTINUE} failedContinue: ${CALLBACK_FAILED_CONTINUE}
beforeSendGroupMsg: beforeSendGroupMsg:
@@ -527,39 +528,3 @@ prometheus:
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
###################### LocalCache configuration information ######################
# topic: redis subscriber channel
# slotNum: number of slots, multiple slots can prevent too many keys from competing for a lock
# slotSize: number of slots, the number of cached keys per slot, the overall cache quantity is slotNum * slotSize
# successExpire: successful cache time seconds
# failedExpire: failed cache time seconds
# disable local caching and annotate topic, slotNum, and slotSize
localCache:
user:
topic: DELETE_CACHE_USER
slotNum: 100
slotSize: 2000
successExpire: 300
failedExpire: 5
group:
topic: DELETE_CACHE_GROUP
slotNum: 100
slotSize: 2000
successExpire: 300
failedExpire: 5
friend:
topic: DELETE_CACHE_FRIEND
slotNum: 100
slotSize: 2000
successExpire: 300
failedExpire: 5
conversation:
topic: DELETE_CACHE_CONVERSATION
slotNum: 100
slotSize: 2000
successExpire: 300
failedExpire: 5

View File

@@ -100,7 +100,7 @@ ZOOKEEPER_PORT=${ZOOKEEPER_PORT}
# MongoDB service port configuration. # MongoDB service port configuration.
# Default: MONGO_PORT=37017 # Default: MONGO_PORT=37017
# MONGO_PORT=${MONGO_PORT} MONGO_PORT=${MONGO_PORT}
# Password for MongoDB admin user. Used for service authentication. # Password for MongoDB admin user. Used for service authentication.
# Default: MONGO_PASSWORD=openIM123 # Default: MONGO_PASSWORD=openIM123

View File

@@ -7,7 +7,6 @@ Welcome to the OpenIM Documentation hub! This center provides a comprehensive ra
1. [Contrib](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib) - Guidance on contributing and configurations for developers 1. [Contrib](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib) - Guidance on contributing and configurations for developers
2. [Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib) - Coding conventions, logging policies, and other transformation tools 2. [Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib) - Coding conventions, logging policies, and other transformation tools
------
## Contrib ## Contrib

View File

@@ -305,13 +305,14 @@ Feel free to explore the MinIO documentation for more advanced configurations an
This section involves setting up MongoDB, including its port, address, and credentials. This section involves setting up MongoDB, including its port, address, and credentials.
| Parameter | Example Value | Description | | Parameter | Example Value | Description |
| -------------- | -------------- | ----------------------- | | -------------- | -------------- | ----------------------- |
| MONGO_PORT | "27017" | Port used by MongoDB. | | MONGO_PORT | "27017" | Port used by MongoDB. |
| MONGO_ADDRESS | [Generated IP] | IP address for MongoDB. | | MONGO_ADDRESS | [Generated IP] | IP address for MongoDB. |
| MONGO_USERNAME | [User Defined] | Admin Username for MongoDB. | | MONGO_USERNAME | [User Defined] | Admin Username for MongoDB. |
| MONGO_PASSWORD | [User Defined] | Admin Password for MongoDB. | | MONGO_PASSWORD | [User Defined] | Admin Password for MongoDB. |
| MONGO_OPENIM_PASSWORD | [User Defined] | OpenIM Username for MongoDB. | | MONGO_OPENIM_USERNAME | [User Defined] | OpenIM Username for MongoDB. |
| MONGO_OPENIM_PASSWORD | [User Defined] | OpenIM Password for MongoDB. | | MONGO_OPENIM_PASSWORD | [User Defined] | OpenIM Password for MongoDB. |
### 2.8. <a name='TencentCloudCOSConfiguration'></a>Tencent Cloud COS Configuration ### 2.8. <a name='TencentCloudCOSConfiguration'></a>Tencent Cloud COS Configuration
@@ -477,12 +478,6 @@ This section involves setting up additional configuration variables for Websocke
| JPNS_MASTER_SECRET | [User Defined] | JPNS Master Secret | | JPNS_MASTER_SECRET | [User Defined] | JPNS Master Secret |
| JPNS_PUSH_URL | [User Defined] | JPNS Push Notification URL | | JPNS_PUSH_URL | [User Defined] | JPNS Push Notification URL |
| JPNS_PUSH_INTENT | [User Defined] | JPNS Push Intent | | JPNS_PUSH_INTENT | [User Defined] | JPNS Push Intent |
| MANAGER_USERID_1 | "openIM123456" | Administrator ID 1 |
| MANAGER_USERID_2 | "openIM654321" | Administrator ID 2 |
| MANAGER_USERID_3 | "openIMAdmin" | Administrator ID 3 |
| NICKNAME_1 | "system1" | Nickname 1 |
| NICKNAME_2 | "system2" | Nickname 2 |
| NICKNAME_3 | "system3" | Nickname 3 |
| IM_ADMIN_USERID | "imAdmin" | IM Administrator ID | | IM_ADMIN_USERID | "imAdmin" | IM Administrator ID |
| IM_ADMIN_NAME | "imAdmin" | IM Administrator Nickname | | IM_ADMIN_NAME | "imAdmin" | IM Administrator Nickname |
| MULTILOGIN_POLICY | "1" | Multi-login Policy | | MULTILOGIN_POLICY | "1" | Multi-login Policy |

View File

@@ -1,5 +1,3 @@
# OpenIM Offline Deployment Design # OpenIM Offline Deployment Design
## 1. Base Images ## 1. Base Images
@@ -10,7 +8,7 @@ Below are the base images and their versions you'll need:
- [ ] redis:7.0.0 - [ ] redis:7.0.0
- [ ] mongo:6.0.2 - [ ] mongo:6.0.2
- [ ] bitnami/zookeeper:3.8 - [ ] bitnami/zookeeper:3.8
- [ ] minio/minio:latest - [ ] minio/minio:RELEASE.2024-01-11T07-46-16Z
> [!IMPORTANT] > [!IMPORTANT]
> It is important to note that OpenIM removed mysql components from versions v3.5.0 (release-v3.5) and above, so mysql can be deployed without this requirement or above > It is important to note that OpenIM removed mysql components from versions v3.5.0 (release-v3.5) and above, so mysql can be deployed without this requirement or above
@@ -22,10 +20,10 @@ OpenIM:
> [!TIP] > [!TIP]
> If you need to install more IM components or monitoring products [images.md](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/images.md) > If you need to install more IM components or monitoring products [images.md](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/images.md)
- [ ] ghcr.io/openimsdk/openim-web:latest - [ ] ghcr.io/openimsdk/openim-web:<version-name>
- [ ] ghcr.io/openimsdk/openim-admin:latest - [ ] ghcr.io/openimsdk/openim-admin:<version-name>
- [ ] ghcr.io/openimsdk/openim-chat:latest - [ ] ghcr.io/openimsdk/openim-chat:<version-name>
- [ ] ghcr.io/openimsdk/openim-server:latest - [ ] ghcr.io/openimsdk/openim-server:<version-name>
Monitoring: Monitoring:
@@ -42,9 +40,9 @@ Use the following commands to pull these base images:
docker pull bitnami/kafka:3.5.1 docker pull bitnami/kafka:3.5.1
docker pull redis:7.0.0 docker pull redis:7.0.0
docker pull mongo:6.0.2 docker pull mongo:6.0.2
docker pull mysql:5.7 docker pull mariadb:10.6
docker pull bitnami/zookeeper:3.8 docker pull bitnami/zookeeper:3.8
docker pull minio/minio:latest docker pull minio/minio:2024-01-11T07-46-16Z
``` ```
If you need to install more IM components or monitoring products: If you need to install more IM components or monitoring products:
@@ -177,4 +175,4 @@ docker compose ps # Verify
- [openimsdk Issue #432](https://github.com/openimsdk/open-im-server/issues/432) - [openimsdk Issue #432](https://github.com/openimsdk/open-im-server/issues/432)
- [Notion Link](https://nsddd.notion.site/435ee747c0bc44048da9300a2d745ad3?pvs=25) - [Notion Link](https://nsddd.notion.site/435ee747c0bc44048da9300a2d745ad3?pvs=25)
- [openimsdk Issue #474](https://github.com/openimsdk/open-im-server/issues/474) - [openimsdk Issue #474](https://github.com/openimsdk/open-im-server/issues/474)

View File

@@ -0,0 +1,33 @@
# How do I contribute code to OpenIM
<p align="center">
<a href="./CONTRIBUTING.md">Englist</a> ·
<a href="./CONTRIBUTING-zh_CN.md">中文</a> ·
<a href="docs/contributing/CONTRIBUTING-UA.md">Українська</a> ·
<a href="docs/contributing/CONTRIBUTING-CS.md">Česky</a> ·
<a href="docs/contributing/CONTRIBUTING-HU.md">Magyar</a> ·
<a href="docs/contributing/CONTRIBUTING-ES.md">Español</a> ·
<a href="docs/contributing/CONTRIBUTING-FA.md">فارسی</a> ·
<a href="docs/contributing/CONTRIBUTING-FR.md">Français</a> ·
<a href="docs/contributing/CONTRIBUTING-DE.md">Deutsch</a> ·
<a href="docs/contributing/CONTRIBUTING-PL.md">Polski</a> ·
<a href="docs/contributing/CONTRIBUTING-ID.md">Indonesian</a> ·
<a href="docs/contributing/CONTRIBUTING-FI.md">Suomi</a> ·
<a href="docs/contributing/CONTRIBUTING-ML.md">മലയാളം</a> ·
<a href="docs/contributing/CONTRIBUTING-JP.md">日本語</a> ·
<a href="docs/contributing/CONTRIBUTING-NL.md">Nederlands</a> ·
<a href="docs/contributing/CONTRIBUTING-IT.md">Italiano</a> ·
<a href="docs/contributing/CONTRIBUTING-RU.md">Русский</a> ·
<a href="docs/contributing/CONTRIBUTING-PTBR.md">Português (Brasil)</a> ·
<a href="docs/contributing/CONTRIBUTING-EO.md">Esperanto</a> ·
<a href="docs/contributing/CONTRIBUTING-KR.md">한국어</a> ·
<a href="docs/contributing/CONTRIBUTING-AR.md">العربي</a> ·
<a href="docs/contributing/CONTRIBUTING-VN.md">Tiếng Việt</a> ·
<a href="docs/contributing/CONTRIBUTING-DA.md">Dansk</a> ·
<a href="docs/contributing/CONTRIBUTING-GR.md">Ελληνικά</a> ·
<a href="docs/contributing/CONTRIBUTING-TR.md">Türkçe</a>
</p>
</div>
</p>

View File

@@ -0,0 +1,33 @@
# How do I contribute code to OpenIM
<p align="center">
<a href="./CONTRIBUTING.md">Englist</a> ·
<a href="./CONTRIBUTING-zh_CN.md">中文</a> ·
<a href="docs/contributing/CONTRIBUTING-UA.md">Українська</a> ·
<a href="docs/contributing/CONTRIBUTING-CS.md">Česky</a> ·
<a href="docs/contributing/CONTRIBUTING-HU.md">Magyar</a> ·
<a href="docs/contributing/CONTRIBUTING-ES.md">Español</a> ·
<a href="docs/contributing/CONTRIBUTING-FA.md">فارسی</a> ·
<a href="docs/contributing/CONTRIBUTING-FR.md">Français</a> ·
<a href="docs/contributing/CONTRIBUTING-DE.md">Deutsch</a> ·
<a href="docs/contributing/CONTRIBUTING-PL.md">Polski</a> ·
<a href="docs/contributing/CONTRIBUTING-ID.md">Indonesian</a> ·
<a href="docs/contributing/CONTRIBUTING-FI.md">Suomi</a> ·
<a href="docs/contributing/CONTRIBUTING-ML.md">മലയാളം</a> ·
<a href="docs/contributing/CONTRIBUTING-JP.md">日本語</a> ·
<a href="docs/contributing/CONTRIBUTING-NL.md">Nederlands</a> ·
<a href="docs/contributing/CONTRIBUTING-IT.md">Italiano</a> ·
<a href="docs/contributing/CONTRIBUTING-RU.md">Русский</a> ·
<a href="docs/contributing/CONTRIBUTING-PTBR.md">Português (Brasil)</a> ·
<a href="docs/contributing/CONTRIBUTING-EO.md">Esperanto</a> ·
<a href="docs/contributing/CONTRIBUTING-KR.md">한국어</a> ·
<a href="docs/contributing/CONTRIBUTING-AR.md">العربي</a> ·
<a href="docs/contributing/CONTRIBUTING-VN.md">Tiếng Việt</a> ·
<a href="docs/contributing/CONTRIBUTING-DA.md">Dansk</a> ·
<a href="docs/contributing/CONTRIBUTING-GR.md">Ελληνικά</a> ·
<a href="docs/contributing/CONTRIBUTING-TR.md">Türkçe</a>
</p>
</div>
</p>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 286 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 57 KiB

7
docs/readme/README-UA.md Normal file
View File

@@ -0,0 +1,7 @@
<p align="center">
<a href="https://openim.io">
<img src="./assets/logo-gif/openim-logo.gif" width="60%" height="30%"/>
</a>
</p>
<div align="center">

21
go.mod
View File

@@ -4,8 +4,8 @@ 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.49 github.com/OpenIMSDK/protocol v0.0.48
github.com/OpenIMSDK/tools v0.0.28 github.com/OpenIMSDK/tools v0.0.33
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
@@ -18,7 +18,6 @@ require (
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
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 // indirect github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 // indirect
github.com/openimsdk/localcache v0.0.1
github.com/pkg/errors v0.9.1 // indirect github.com/pkg/errors v0.9.1 // indirect
github.com/prometheus/client_golang v1.17.0 github.com/prometheus/client_golang v1.17.0
github.com/robfig/cron/v3 v3.0.1 github.com/robfig/cron/v3 v3.0.1
@@ -32,7 +31,7 @@ require (
gopkg.in/yaml.v3 v3.0.1 gopkg.in/yaml.v3 v3.0.1
) )
require github.com/google/uuid v1.3.1 require github.com/google/uuid v1.5.0
require ( require (
github.com/IBM/sarama v1.41.3 github.com/IBM/sarama v1.41.3
@@ -42,7 +41,6 @@ require (
github.com/spf13/pflag v1.0.5 github.com/spf13/pflag v1.0.5
github.com/stathat/consistent v1.0.0 github.com/stathat/consistent v1.0.0
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
golang.org/x/sync v0.4.0 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
@@ -83,7 +81,6 @@ require (
github.com/hashicorp/errwrap v1.0.0 // indirect github.com/hashicorp/errwrap v1.0.0 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/hashicorp/go-uuid v1.0.3 // indirect github.com/hashicorp/go-uuid v1.0.3 // indirect
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
github.com/jcmturner/aescts/v2 v2.0.0 // indirect github.com/jcmturner/aescts/v2 v2.0.0 // indirect
@@ -96,8 +93,8 @@ require (
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
github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd // indirect github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd // indirect
github.com/klauspost/compress v1.16.7 // indirect github.com/klauspost/compress v1.17.4 // indirect
github.com/klauspost/cpuid/v2 v2.2.5 // indirect github.com/klauspost/cpuid/v2 v2.2.6 // indirect
github.com/leodido/go-urn v1.2.4 // indirect github.com/leodido/go-urn v1.2.4 // indirect
github.com/lithammer/shortuuid v3.0.0+incompatible // indirect github.com/lithammer/shortuuid v3.0.0+incompatible // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
@@ -129,9 +126,9 @@ require (
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect
go.opencensus.io v0.24.0 // indirect go.opencensus.io v0.24.0 // indirect
go.uber.org/atomic v1.7.0 // indirect go.uber.org/atomic v1.7.0 // indirect
go.uber.org/multierr v1.6.0 // indirect go.uber.org/multierr v1.11.0 // indirect
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.19.0 // indirect
golang.org/x/oauth2 v0.13.0 // indirect golang.org/x/oauth2 v0.13.0 // indirect
golang.org/x/sys v0.15.0 // indirect golang.org/x/sys v0.15.0 // indirect
golang.org/x/text v0.14.0 // indirect golang.org/x/text v0.14.0 // indirect
@@ -143,7 +140,7 @@ 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 gorm.io/gorm v1.25.4 // indirect
stathat.com/c/consistent v1.0.0 // indirect stathat.com/c/consistent v1.0.0 // indirect
) )
@@ -159,4 +156,4 @@ require (
gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect
) )
replace github.com/openimsdk/localcache => ./pkg/localcache replace github.com/OpenIMSDK/protocol v0.0.47 => github.com/AndrewZuo01/protocol v0.0.0-20240112093520-fd9c53e27b94

38
go.sum
View File

@@ -18,10 +18,10 @@ firebase.google.com/go v3.13.0+incompatible/go.mod h1:xlah6XbEyW6tbfSklcfe5FHJIw
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/IBM/sarama v1.41.3 h1:MWBEJ12vHC8coMjdEXFq/6ftO6DUZnQlFYcxtOJFa7c= 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.49 h1:wcqJOMBis7f153zNI7V82Fc4WyqA1GanMgXUQgL618k= github.com/OpenIMSDK/protocol v0.0.48 h1:8MIMjyzJRsruYhVv2ZKArFiOveroaofDOb3dlAdgjsw=
github.com/OpenIMSDK/protocol v0.0.49/go.mod h1:F25dFrwrIx3lkNoiuf6FkCfxuwf8L4Z8UIsdTHP/r0Y= github.com/OpenIMSDK/protocol v0.0.48/go.mod h1:F25dFrwrIx3lkNoiuf6FkCfxuwf8L4Z8UIsdTHP/r0Y=
github.com/OpenIMSDK/tools v0.0.27 h1:J/kSRqM+y9U4XK/pQ9RkEB31oQ5BTYD1oA5r1PITPRA= github.com/OpenIMSDK/tools v0.0.33 h1:rvFCxXaXxLv1MJFC4qcoWRGwKBnV+hR68UN2N0/zZhE=
github.com/OpenIMSDK/tools v0.0.27/go.mod h1:eg+q4A34Qmu73xkY0mt37FHGMCMfC6CtmOnm0kFEGFI= github.com/OpenIMSDK/tools v0.0.33/go.mod h1:wBfR5CYmEyvxl03QJbTkhz1CluK6J4/lX0lviu8JAjE=
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=
@@ -152,8 +152,8 @@ github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o=
github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= github.com/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU=
github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/enterprise-certificate-proxy v0.3.1 h1:SBWmZhjUDRorQxrN0nwzf+AHBxnbFjViHQS4P0yVpmQ= github.com/googleapis/enterprise-certificate-proxy v0.3.1 h1:SBWmZhjUDRorQxrN0nwzf+AHBxnbFjViHQS4P0yVpmQ=
github.com/googleapis/enterprise-certificate-proxy v0.3.1/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= github.com/googleapis/enterprise-certificate-proxy v0.3.1/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0=
github.com/googleapis/gax-go/v2 v2.12.0 h1:A+gCJKdRfqXkr+BIRGtZLibNXf0m1f9E4HG56etFpas= github.com/googleapis/gax-go/v2 v2.12.0 h1:A+gCJKdRfqXkr+BIRGtZLibNXf0m1f9E4HG56etFpas=
@@ -171,8 +171,6 @@ github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9
github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=
github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
@@ -196,7 +194,6 @@ github.com/jinzhu/copier v0.3.5 h1:GlvfUwHk62RokgqVNvYsku0TATCF7bAHVwEXoBh3iJg=
github.com/jinzhu/copier v0.3.5/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg= github.com/jinzhu/copier v0.3.5/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=
@@ -207,12 +204,12 @@ github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd/go.mod h1:CT
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I= github.com/klauspost/compress v1.17.4 h1:Ej5ixsIri7BrIjBkRZLTo6ghwrEtHFk7ijlczPW4fZ4=
github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/klauspost/compress v1.17.4/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM=
github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg= github.com/klauspost/cpuid/v2 v2.2.6 h1:ndNyv040zDGIDh8thGkXYjnFtiN02M1PVVF+JE/48xc=
github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= github.com/klauspost/cpuid/v2 v2.2.6/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
@@ -280,7 +277,6 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g=
github.com/prometheus/client_golang v1.17.0 h1:rl2sfwZMtSthVU752MqfjQozy7blglC+1SOtjMAMh+Q= github.com/prometheus/client_golang v1.17.0 h1:rl2sfwZMtSthVU752MqfjQozy7blglC+1SOtjMAMh+Q=
github.com/prometheus/client_golang v1.17.0/go.mod h1:VeL+gMmOAxkS2IqfCq0ZmHSL+LjWfWDUmp1mBz9JgUY= github.com/prometheus/client_golang v1.17.0/go.mod h1:VeL+gMmOAxkS2IqfCq0ZmHSL+LjWfWDUmp1mBz9JgUY=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
@@ -355,11 +351,9 @@ go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/automaxprocs v1.5.3 h1:kWazyxZUrS3Gs4qUpbwo5kEIMGe/DAvi5Z4tl2NW4j8=
go.uber.org/automaxprocs v1.5.3/go.mod h1:eRbA25aqJrxAbsLO0xy5jVwPt7FQnRgjW+efnwa1WM0=
go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI=
go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60= go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60=
go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg=
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
@@ -404,8 +398,8 @@ golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qx
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c=
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.13.0 h1:jDDenyj+WgFtmV3zYVoi8aE2BwtXFLWOA67ZfNWftiY= golang.org/x/oauth2 v0.13.0 h1:jDDenyj+WgFtmV3zYVoi8aE2BwtXFLWOA67ZfNWftiY=
golang.org/x/oauth2 v0.13.0/go.mod h1:/JMhi4ZRXAf4HG9LiNmxvk+45+96RUlVThiH8FzNBn0= golang.org/x/oauth2 v0.13.0/go.mod h1:/JMhi4ZRXAf4HG9LiNmxvk+45+96RUlVThiH8FzNBn0=
@@ -533,8 +527,8 @@ 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/gorm v1.25.4 h1:iyNd8fNAe8W9dvtlgeRI5zSVZPsq3OpcTu37cYcpCmw=
gorm.io/gorm v1.23.8/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk= gorm.io/gorm v1.25.4/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k=
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=

View File

@@ -105,7 +105,7 @@ func CallbackUserKickOff(ctx context.Context, userID string, platformID int) err
// func callbackUserOnline(operationID, userID string, platformID int, token string, isAppBackground bool, connID // func callbackUserOnline(operationID, userID string, platformID int, token string, isAppBackground bool, connID
// string) cbApi.CommonCallbackResp { // string) cbApi.CommonCallbackResp {
// callbackResp := cbApi.CommonCallbackResp{OperationID: operationID} // callbackResp := cbApi.CommonCallbackResp{OperationID: operationID}
// if !config.Config.Callback.CallbackUserOnline.WithEnable { // if !config.Config.Callback.CallbackUserOnline.Enable {
// return callbackResp // return callbackResp
// } // }
// callbackUserOnlineReq := cbApi.CallbackUserOnlineReq{ // callbackUserOnlineReq := cbApi.CallbackUserOnlineReq{
@@ -134,7 +134,7 @@ func CallbackUserKickOff(ctx context.Context, userID string, platformID int) err
//} //}
//func callbackUserOffline(operationID, userID string, platformID int, connID string) cbApi.CommonCallbackResp { //func callbackUserOffline(operationID, userID string, platformID int, connID string) cbApi.CommonCallbackResp {
// callbackResp := cbApi.CommonCallbackResp{OperationID: operationID} // callbackResp := cbApi.CommonCallbackResp{OperationID: operationID}
// if !config.Config.Callback.CallbackUserOffline.WithEnable { // if !config.Config.Callback.CallbackUserOffline.Enable {
// return callbackResp // return callbackResp
// } // }
// callbackOfflineReq := cbApi.CallbackUserOfflineReq{ // callbackOfflineReq := cbApi.CallbackUserOfflineReq{
@@ -161,7 +161,7 @@ func CallbackUserKickOff(ctx context.Context, userID string, platformID int) err
//} //}
//func callbackUserKickOff(operationID string, userID string, platformID int) cbApi.CommonCallbackResp { //func callbackUserKickOff(operationID string, userID string, platformID int) cbApi.CommonCallbackResp {
// callbackResp := cbApi.CommonCallbackResp{OperationID: operationID} // callbackResp := cbApi.CommonCallbackResp{OperationID: operationID}
// if !config.Config.Callback.CallbackUserKickOff.WithEnable { // if !config.Config.Callback.CallbackUserKickOff.Enable {
// return callbackResp // return callbackResp
// } // }
// callbackUserKickOffReq := cbApi.CallbackUserKickOffReq{ // callbackUserKickOffReq := cbApi.CallbackUserKickOffReq{

View File

@@ -25,6 +25,8 @@ import (
"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/mcontext"
"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/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"
@@ -57,7 +59,7 @@ type Server struct {
rpcPort int rpcPort int
prometheusPort int prometheusPort int
LongConnServer LongConnServer LongConnServer LongConnServer
pushTerminal map[int]struct{} pushTerminal []int
} }
func (s *Server) SetLongConnServer(LongConnServer LongConnServer) { func (s *Server) SetLongConnServer(LongConnServer LongConnServer) {
@@ -65,15 +67,12 @@ func (s *Server) SetLongConnServer(LongConnServer LongConnServer) {
} }
func NewServer(rpcPort int, proPort int, longConnServer LongConnServer) *Server { func NewServer(rpcPort int, proPort int, longConnServer LongConnServer) *Server {
s := &Server{ return &Server{
rpcPort: rpcPort, rpcPort: rpcPort,
prometheusPort: proPort, prometheusPort: proPort,
LongConnServer: longConnServer, LongConnServer: longConnServer,
pushTerminal: make(map[int]struct{}), pushTerminal: []int{constant.IOSPlatformID, constant.AndroidPlatformID},
} }
s.pushTerminal[constant.IOSPlatformID] = struct{}{}
s.pushTerminal[constant.AndroidPlatformID] = struct{}{}
return s
} }
func (s *Server) OnlinePushMsg( func (s *Server) OnlinePushMsg(
@@ -127,9 +126,13 @@ func (s *Server) OnlineBatchPushOneMsg(
panic("implement me") panic("implement me")
} }
func (s *Server) SuperGroupOnlineBatchPushOneMsg(ctx context.Context, req *msggateway.OnlineBatchPushOneMsgReq, func (s *Server) SuperGroupOnlineBatchPushOneMsg(
ctx context.Context,
req *msggateway.OnlineBatchPushOneMsgReq,
) (*msggateway.OnlineBatchPushOneMsgResp, error) { ) (*msggateway.OnlineBatchPushOneMsgResp, error) {
var singleUserResults []*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{ results := &msggateway.SingleMsgToUserResults{
@@ -150,22 +153,23 @@ func (s *Server) SuperGroupOnlineBatchPushOneMsg(ctx context.Context, req *msgga
} }
userPlatform := &msggateway.SingleMsgToUserPlatform{ userPlatform := &msggateway.SingleMsgToUserPlatform{
PlatFormID: int32(client.PlatformID), RecvID: v,
RecvPlatFormID: int32(client.PlatformID),
} }
if !client.IsBackground || if !client.IsBackground ||
(client.IsBackground && client.PlatformID != constant.IOSPlatformID) { (client.IsBackground && client.PlatformID != constant.IOSPlatformID) {
err := client.PushMessage(ctx, req.MsgData) err := client.PushMessage(ctx, req.MsgData)
if err != nil { if err != nil {
userPlatform.ResultCode = int64(errs.ErrPushMsgErr.Code()) userPlatform.ResultCode = -2
resp = append(resp, userPlatform) resp = append(resp, userPlatform)
} else { } else {
if _, ok := s.pushTerminal[client.PlatformID]; ok { if utils.IsContainInt(client.PlatformID, s.pushTerminal) {
results.OnlinePush = true results.OnlinePush = true
resp = append(resp, userPlatform) resp = append(resp, userPlatform)
} }
} }
} else { } else {
userPlatform.ResultCode = int64(errs.ErrIOSBackgroundPushErr.Code()) userPlatform.ResultCode = -3
resp = append(resp, userPlatform) resp = append(resp, userPlatform)
} }
} }

View File

@@ -15,12 +15,15 @@
package msgtransfer package msgtransfer
import ( import (
"context"
"errors" "errors"
"fmt" "fmt"
"log" "log"
"net/http" "net/http"
"sync" "sync"
"github.com/OpenIMSDK/tools/errs"
"github.com/OpenIMSDK/tools/mw" "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"
@@ -69,40 +72,47 @@ func StartTransfer(prometheusPort int) error {
client.AddOption(mw.GrpcClient(), grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithDefaultServiceConfig(fmt.Sprintf(`{"LoadBalancingPolicy": "%s"}`, "round_robin"))) client.AddOption(mw.GrpcClient(), grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithDefaultServiceConfig(fmt.Sprintf(`{"LoadBalancingPolicy": "%s"}`, "round_robin")))
msgModel := cache.NewMsgCacheModel(rdb) msgModel := cache.NewMsgCacheModel(rdb)
msgDocModel := unrelation.NewMsgMongoDriver(mongo.GetDatabase()) msgDocModel := unrelation.NewMsgMongoDriver(mongo.GetDatabase())
msgDatabase := controller.NewCommonMsgDatabase(msgDocModel, msgModel) msgDatabase, err := controller.NewCommonMsgDatabase(msgDocModel, msgModel)
if err != nil {
return err
}
conversationRpcClient := rpcclient.NewConversationRpcClient(client) conversationRpcClient := rpcclient.NewConversationRpcClient(client)
groupRpcClient := rpcclient.NewGroupRpcClient(client) groupRpcClient := rpcclient.NewGroupRpcClient(client)
msgTransfer := NewMsgTransfer(msgDatabase, &conversationRpcClient, &groupRpcClient) msgTransfer, err := NewMsgTransfer(msgDatabase, &conversationRpcClient, &groupRpcClient)
if err != nil {
return err
}
return msgTransfer.Start(prometheusPort) return msgTransfer.Start(prometheusPort)
} }
func NewMsgTransfer(msgDatabase controller.CommonMsgDatabase, conversationRpcClient *rpcclient.ConversationRpcClient, groupRpcClient *rpcclient.GroupRpcClient) *MsgTransfer { func NewMsgTransfer(msgDatabase controller.CommonMsgDatabase, conversationRpcClient *rpcclient.ConversationRpcClient, groupRpcClient *rpcclient.GroupRpcClient) (*MsgTransfer, error) {
return &MsgTransfer{ historyCH, err := NewOnlineHistoryRedisConsumerHandler(msgDatabase, conversationRpcClient, groupRpcClient)
historyCH: NewOnlineHistoryRedisConsumerHandler(msgDatabase, conversationRpcClient, groupRpcClient), if err != nil {
historyMongoCH: NewOnlineHistoryMongoConsumerHandler(msgDatabase), return nil, err
} }
historyMongoCH, err := NewOnlineHistoryMongoConsumerHandler(msgDatabase)
if err != nil {
return nil, err
}
return &MsgTransfer{
historyCH: historyCH,
historyMongoCH: historyMongoCH,
}, nil
} }
func (m *MsgTransfer) Start(prometheusPort int) error { func (m *MsgTransfer) Start(prometheusPort int) error {
ctx := context.Background()
var wg sync.WaitGroup var wg sync.WaitGroup
wg.Add(1) wg.Add(1)
fmt.Println("start msg transfer", "prometheusPort:", prometheusPort) fmt.Println("start msg transfer", "prometheusPort:", prometheusPort)
if prometheusPort <= 0 { if prometheusPort <= 0 {
return errors.New("prometheusPort not correct") return errs.Wrap(errors.New("prometheusPort not correct"))
} }
if config.Config.ChatPersistenceMysql {
// go m.persistentCH.persistentConsumerGroup.RegisterHandleAndConsumer(m.persistentCH) go m.historyCH.historyConsumerGroup.RegisterHandleAndConsumer(ctx, m.historyCH)
} else { go m.historyMongoCH.historyConsumerGroup.RegisterHandleAndConsumer(ctx, m.historyMongoCH)
fmt.Println("msg transfer not start mysql consumer")
}
go m.historyCH.historyConsumerGroup.RegisterHandleAndConsumer(m.historyCH)
go m.historyMongoCH.historyConsumerGroup.RegisterHandleAndConsumer(m.historyMongoCH)
// go m.modifyCH.modifyMsgConsumerGroup.RegisterHandleAndConsumer(m.modifyCH)
/*err := prome.StartPrometheusSrv(prometheusPort)
if err != nil {
return err
}*/
////////////////////////////
if config.Config.Prometheus.Enable { if config.Config.Prometheus.Enable {
reg := prometheus.NewRegistry() reg := prometheus.NewRegistry()
reg.MustRegister( reg.MustRegister(

View File

@@ -87,7 +87,7 @@ func NewOnlineHistoryRedisConsumerHandler(
database controller.CommonMsgDatabase, database controller.CommonMsgDatabase,
conversationRpcClient *rpcclient.ConversationRpcClient, conversationRpcClient *rpcclient.ConversationRpcClient,
groupRpcClient *rpcclient.GroupRpcClient, groupRpcClient *rpcclient.GroupRpcClient,
) *OnlineHistoryRedisConsumerHandler { ) (*OnlineHistoryRedisConsumerHandler, error) {
var och OnlineHistoryRedisConsumerHandler var och OnlineHistoryRedisConsumerHandler
och.msgDatabase = database och.msgDatabase = database
och.msgDistributionCh = make(chan Cmd2Value) // no buffer channel och.msgDistributionCh = make(chan Cmd2Value) // no buffer channel
@@ -98,14 +98,15 @@ func NewOnlineHistoryRedisConsumerHandler(
} }
och.conversationRpcClient = conversationRpcClient och.conversationRpcClient = conversationRpcClient
och.groupRpcClient = groupRpcClient och.groupRpcClient = groupRpcClient
och.historyConsumerGroup = kafka.NewMConsumerGroup(&kafka.MConsumerGroupConfig{ var err error
och.historyConsumerGroup, err = kafka.NewMConsumerGroup(&kafka.MConsumerGroupConfig{
KafkaVersion: sarama.V2_0_0_0, KafkaVersion: sarama.V2_0_0_0,
OffsetsInitial: sarama.OffsetNewest, IsReturnErr: false, OffsetsInitial: sarama.OffsetNewest, IsReturnErr: false,
}, []string{config.Config.Kafka.LatestMsgToRedis.Topic}, }, []string{config.Config.Kafka.LatestMsgToRedis.Topic},
config.Config.Kafka.Addr, config.Config.Kafka.ConsumerGroupID.MsgToRedis) config.Config.Kafka.Addr, config.Config.Kafka.ConsumerGroupID.MsgToRedis)
// statistics.NewStatistics(&och.singleMsgSuccessCount, config.Config.ModuleName.MsgTransferName, fmt.Sprintf("%d // statistics.NewStatistics(&och.singleMsgSuccessCount, config.Config.ModuleName.MsgTransferName, fmt.Sprintf("%d
// second singleMsgCount insert to mongo", constant.StatisticsTimeInterval), constant.StatisticsTimeInterval) // second singleMsgCount insert to mongo", constant.StatisticsTimeInterval), constant.StatisticsTimeInterval)
return &och return &och, err
} }
func (och *OnlineHistoryRedisConsumerHandler) Run(channelID int) { func (och *OnlineHistoryRedisConsumerHandler) Run(channelID int) {

View File

@@ -34,16 +34,21 @@ type OnlineHistoryMongoConsumerHandler struct {
msgDatabase controller.CommonMsgDatabase msgDatabase controller.CommonMsgDatabase
} }
func NewOnlineHistoryMongoConsumerHandler(database controller.CommonMsgDatabase) *OnlineHistoryMongoConsumerHandler { func NewOnlineHistoryMongoConsumerHandler(database controller.CommonMsgDatabase) (*OnlineHistoryMongoConsumerHandler, error) {
mc := &OnlineHistoryMongoConsumerHandler{ historyConsumerGroup, err := kfk.NewMConsumerGroup(&kfk.MConsumerGroupConfig{
historyConsumerGroup: kfk.NewMConsumerGroup(&kfk.MConsumerGroupConfig{ KafkaVersion: sarama.V2_0_0_0,
KafkaVersion: sarama.V2_0_0_0, OffsetsInitial: sarama.OffsetNewest, IsReturnErr: false,
OffsetsInitial: sarama.OffsetNewest, IsReturnErr: false, }, []string{config.Config.Kafka.MsgToMongo.Topic},
}, []string{config.Config.Kafka.MsgToMongo.Topic}, config.Config.Kafka.Addr, config.Config.Kafka.ConsumerGroupID.MsgToMongo)
config.Config.Kafka.Addr, config.Config.Kafka.ConsumerGroupID.MsgToMongo), if err != nil {
msgDatabase: database, return nil, err
} }
return mc
mc := &OnlineHistoryMongoConsumerHandler{
historyConsumerGroup: historyConsumerGroup,
msgDatabase: database,
}
return mc, nil
} }
func (mc *OnlineHistoryMongoConsumerHandler) handleChatWs2Mongo( func (mc *OnlineHistoryMongoConsumerHandler) handleChatWs2Mongo(

View File

@@ -16,7 +16,6 @@ package push
import ( import (
"context" "context"
"encoding/json"
"github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/protocol/constant"
"github.com/OpenIMSDK/protocol/sdkws" "github.com/OpenIMSDK/protocol/sdkws"
@@ -137,14 +136,3 @@ func callbackBeforeSuperGroupOnlinePush(
} }
return nil return nil
} }
func GetContent(msg *sdkws.MsgData) string {
if msg.ContentType >= constant.NotificationBegin && msg.ContentType <= constant.NotificationEnd {
var notification sdkws.NotificationElem
if err := json.Unmarshal(msg.Content, &notification); err != nil {
return ""
}
return notification.Detail
} else {
return string(msg.Content)
}
}

View File

@@ -0,0 +1,37 @@
// 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 push
import "context"
type Consumer struct {
pushCh ConsumerHandler
successCount uint64
}
func NewConsumer(pusher *Pusher) (*Consumer, error) {
c, err := NewConsumerHandler(pusher)
if err != nil {
return nil, err
}
return &Consumer{
pushCh: *c,
}, nil
}
func (c *Consumer) Start() {
go c.pushCh.pushConsumerGroup.RegisterHandleAndConsumer(context.Background(), &c.pushCh)
}

View File

@@ -16,16 +16,17 @@ package dummy
import ( import (
"context" "context"
"github.com/openimsdk/open-im-server/v3/internal/push/offlinepush/options"
"github.com/openimsdk/open-im-server/v3/internal/push/offlinepush"
) )
func NewDummy() *Dummy { func NewClient() *Dummy {
return &Dummy{} return &Dummy{}
} }
type Dummy struct { type Dummy struct {
} }
func (d *Dummy) Push(ctx context.Context, userIDs []string, title, content string, opts *options.Opts) error { func (d *Dummy) Push(ctx context.Context, userIDs []string, title, content string, opts *offlinepush.Opts) error {
return nil return nil
} }

View File

@@ -16,7 +16,6 @@ package fcm
import ( import (
"context" "context"
"github.com/openimsdk/open-im-server/v3/internal/push/offlinepush/options"
"path/filepath" "path/filepath"
firebase "firebase.google.com/go" firebase "firebase.google.com/go"
@@ -26,6 +25,7 @@ import (
"github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/protocol/constant"
"github.com/openimsdk/open-im-server/v3/internal/push/offlinepush"
"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"
) )
@@ -39,7 +39,7 @@ type Fcm struct {
cache cache.MsgModel cache cache.MsgModel
} }
func NewFcm(cache cache.MsgModel) *Fcm { func NewClient(cache cache.MsgModel) *Fcm {
projectRoot := config.GetProjectRoot() projectRoot := config.GetProjectRoot()
credentialsFilePath := filepath.Join(projectRoot, "config", config.Config.Push.Fcm.ServiceAccount) credentialsFilePath := filepath.Join(projectRoot, "config", config.Config.Push.Fcm.ServiceAccount)
opt := option.WithCredentialsFile(credentialsFilePath) opt := option.WithCredentialsFile(credentialsFilePath)
@@ -56,7 +56,7 @@ func NewFcm(cache cache.MsgModel) *Fcm {
return &Fcm{fcmMsgCli: fcmMsgClient, cache: cache} return &Fcm{fcmMsgCli: fcmMsgClient, cache: cache}
} }
func (f *Fcm) Push(ctx context.Context, userIDs []string, title, content string, opts *options.Opts) error { func (f *Fcm) Push(ctx context.Context, userIDs []string, title, content string, opts *offlinepush.Opts) error {
// accounts->registrationToken // accounts->registrationToken
allTokens := make(map[string][]string, 0) allTokens := make(map[string][]string, 0)
for _, account := range userIDs { for _, account := range userIDs {

View File

@@ -19,7 +19,6 @@ import (
"crypto/sha256" "crypto/sha256"
"encoding/hex" "encoding/hex"
"errors" "errors"
"github.com/openimsdk/open-im-server/v3/internal/push/offlinepush/options"
"strconv" "strconv"
"sync" "sync"
"time" "time"
@@ -31,6 +30,7 @@ import (
"github.com/OpenIMSDK/tools/mcontext" "github.com/OpenIMSDK/tools/mcontext"
"github.com/OpenIMSDK/tools/utils/splitter" "github.com/OpenIMSDK/tools/utils/splitter"
"github.com/openimsdk/open-im-server/v3/internal/push/offlinepush"
"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"
http2 "github.com/openimsdk/open-im-server/v3/pkg/common/http" http2 "github.com/openimsdk/open-im-server/v3/pkg/common/http"
@@ -55,17 +55,17 @@ const (
taskIDTTL = 1000 * 60 * 60 * 24 taskIDTTL = 1000 * 60 * 60 * 24
) )
type GeTui struct { type Client struct {
cache cache.MsgModel cache cache.MsgModel
tokenExpireTime int64 tokenExpireTime int64
taskIDTTL int64 taskIDTTL int64
} }
func NewGeTui(cache cache.MsgModel) *GeTui { func NewClient(cache cache.MsgModel) *Client {
return &GeTui{cache: cache, tokenExpireTime: tokenExpireTime, taskIDTTL: taskIDTTL} return &Client{cache: cache, tokenExpireTime: tokenExpireTime, taskIDTTL: taskIDTTL}
} }
func (g *GeTui) Push(ctx context.Context, userIDs []string, title, content string, opts *options.Opts) error { func (g *Client) Push(ctx context.Context, userIDs []string, title, content string, opts *offlinepush.Opts) error {
token, err := g.cache.GetGetuiToken(ctx) token, err := g.cache.GetGetuiToken(ctx)
if err != nil { if err != nil {
if errs.Unwrap(err) == redis.Nil { if errs.Unwrap(err) == redis.Nil {
@@ -111,7 +111,7 @@ func (g *GeTui) Push(ctx context.Context, userIDs []string, title, content strin
return err return err
} }
func (g *GeTui) Auth(ctx context.Context, timeStamp int64) (token string, expireTime int64, err error) { func (g *Client) Auth(ctx context.Context, timeStamp int64) (token string, expireTime int64, err error) {
h := sha256.New() h := sha256.New()
h.Write( h.Write(
[]byte(config.Config.Push.GeTui.AppKey + strconv.Itoa(int(timeStamp)) + config.Config.Push.GeTui.MasterSecret), []byte(config.Config.Push.GeTui.AppKey + strconv.Itoa(int(timeStamp)) + config.Config.Push.GeTui.MasterSecret),
@@ -131,7 +131,7 @@ func (g *GeTui) Auth(ctx context.Context, timeStamp int64) (token string, expire
return respAuth.Token, int64(expire), err return respAuth.Token, int64(expire), err
} }
func (g *GeTui) GetTaskID(ctx context.Context, token string, pushReq PushReq) (string, error) { func (g *Client) GetTaskID(ctx context.Context, token string, pushReq PushReq) (string, error) {
respTask := TaskResp{} respTask := TaskResp{}
ttl := int64(1000 * 60 * 5) ttl := int64(1000 * 60 * 5)
pushReq.Settings = &Settings{TTL: &ttl} pushReq.Settings = &Settings{TTL: &ttl}
@@ -143,7 +143,7 @@ func (g *GeTui) GetTaskID(ctx context.Context, token string, pushReq PushReq) (s
} }
// max num is 999. // max num is 999.
func (g *GeTui) batchPush(ctx context.Context, token string, userIDs []string, pushReq PushReq) error { func (g *Client) batchPush(ctx context.Context, token string, userIDs []string, pushReq PushReq) error {
taskID, err := g.GetTaskID(ctx, token, pushReq) taskID, err := g.GetTaskID(ctx, token, pushReq)
if err != nil { if err != nil {
return err return err
@@ -152,21 +152,21 @@ func (g *GeTui) batchPush(ctx context.Context, token string, userIDs []string, p
return g.request(ctx, batchPushURL, pushReq, token, nil) return g.request(ctx, batchPushURL, pushReq, token, nil)
} }
func (g *GeTui) singlePush(ctx context.Context, token, userID string, pushReq PushReq) error { func (g *Client) singlePush(ctx context.Context, token, userID string, pushReq PushReq) error {
operationID := mcontext.GetOperationID(ctx) operationID := mcontext.GetOperationID(ctx)
pushReq.RequestID = &operationID pushReq.RequestID = &operationID
pushReq.Audience = &Audience{Alias: []string{userID}} pushReq.Audience = &Audience{Alias: []string{userID}}
return g.request(ctx, pushURL, pushReq, token, nil) return g.request(ctx, pushURL, pushReq, token, nil)
} }
func (g *GeTui) request(ctx context.Context, url string, input any, token string, output any) error { func (g *Client) request(ctx context.Context, url string, input any, token string, output any) error {
header := map[string]string{"token": token} header := map[string]string{"token": token}
resp := &Resp{} resp := &Resp{}
resp.Data = output resp.Data = output
return g.postReturn(ctx, config.Config.Push.GeTui.PushUrl+url, header, input, resp, 3) return g.postReturn(ctx, config.Config.Push.GeTui.PushUrl+url, header, input, resp, 3)
} }
func (g *GeTui) postReturn( func (g *Client) postReturn(
ctx context.Context, ctx context.Context,
url string, url string,
header map[string]string, header map[string]string,
@@ -181,7 +181,7 @@ func (g *GeTui) postReturn(
return output.parseError() return output.parseError()
} }
func (g *GeTui) getTokenAndSave2Redis(ctx context.Context) (token string, err error) { func (g *Client) getTokenAndSave2Redis(ctx context.Context) (token string, err error) {
token, _, err = g.Auth(ctx, time.Now().UnixNano()/1e6) token, _, err = g.Auth(ctx, time.Now().UnixNano()/1e6)
if err != nil { if err != nil {
return return
@@ -193,7 +193,7 @@ func (g *GeTui) getTokenAndSave2Redis(ctx context.Context) (token string, err er
return token, nil return token, nil
} }
func (g *GeTui) GetTaskIDAndSave2Redis(ctx context.Context, token string, pushReq PushReq) (taskID string, err error) { func (g *Client) GetTaskIDAndSave2Redis(ctx context.Context, token string, pushReq PushReq) (taskID string, err error) {
pushReq.Settings = &Settings{TTL: &g.taskIDTTL} pushReq.Settings = &Settings{TTL: &g.taskIDTTL}
taskID, err = g.GetTaskID(ctx, token, pushReq) taskID, err = g.GetTaskID(ctx, token, pushReq)
if err != nil { if err != nil {

View File

@@ -18,8 +18,8 @@ import (
"context" "context"
"encoding/base64" "encoding/base64"
"fmt" "fmt"
"github.com/openimsdk/open-im-server/v3/internal/push/offlinepush/options"
"github.com/openimsdk/open-im-server/v3/internal/push/offlinepush"
"github.com/openimsdk/open-im-server/v3/internal/push/offlinepush/jpush/body" "github.com/openimsdk/open-im-server/v3/internal/push/offlinepush/jpush/body"
"github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/config"
http2 "github.com/openimsdk/open-im-server/v3/pkg/common/http" http2 "github.com/openimsdk/open-im-server/v3/pkg/common/http"
@@ -27,7 +27,7 @@ import (
type JPush struct{} type JPush struct{}
func NewJPush() *JPush { func NewClient() *JPush {
return &JPush{} return &JPush{}
} }
@@ -46,7 +46,7 @@ func (j *JPush) getAuthorization(appKey string, masterSecret string) string {
return Authorization return Authorization
} }
func (j *JPush) Push(ctx context.Context, userIDs []string, title, content string, opts *options.Opts) error { func (j *JPush) Push(ctx context.Context, userIDs []string, title, content string, opts *offlinepush.Opts) error {
var pf body.Platform var pf body.Platform
pf.SetAll() pf.SetAll()
var au body.Audience var au body.Audience

View File

@@ -0,0 +1,37 @@
// 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 offlinepush
import (
"context"
)
// OfflinePusher Offline Pusher.
type OfflinePusher interface {
Push(ctx context.Context, userIDs []string, title, content string, opts *Opts) error
}
// Opts opts.
type Opts struct {
Signal *Signal
IOSPushSound string
IOSBadgeCount bool
Ex string
}
// Signal message id.
type Signal struct {
ClientMsgID string
}

View File

@@ -1,52 +0,0 @@
// Copyright © 2023 OpenIM. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package offlinepush
import (
"context"
"github.com/openimsdk/open-im-server/v3/internal/push/offlinepush/dummy"
"github.com/openimsdk/open-im-server/v3/internal/push/offlinepush/fcm"
"github.com/openimsdk/open-im-server/v3/internal/push/offlinepush/getui"
"github.com/openimsdk/open-im-server/v3/internal/push/offlinepush/jpush"
"github.com/openimsdk/open-im-server/v3/internal/push/offlinepush/options"
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/cache"
)
const (
GETUI = "getui"
FIREBASE = "fcm"
JPUSH = "jpush"
)
// OfflinePusher Offline Pusher.
type OfflinePusher interface {
Push(ctx context.Context, userIDs []string, title, content string, opts *options.Opts) error
}
func NewOfflinePusher(cache cache.MsgModel) OfflinePusher {
var offlinePusher OfflinePusher
switch config.Config.Push.Enable {
case GETUI:
offlinePusher = getui.NewGeTui(cache)
case FIREBASE:
offlinePusher = fcm.NewFcm(cache)
case JPUSH:
offlinePusher = jpush.NewJPush()
default:
offlinePusher = dummy.NewDummy()
}
return offlinePusher
}

View File

@@ -1,14 +0,0 @@
package options
// Opts opts.
type Opts struct {
Signal *Signal
IOSPushSound string
IOSBadgeCount bool
Ex string
}
// Signal message id.
type Signal struct {
ClientMsgID string
}

View File

@@ -1,211 +0,0 @@
package push
import (
"context"
"github.com/OpenIMSDK/protocol/msggateway"
"github.com/OpenIMSDK/protocol/sdkws"
"github.com/OpenIMSDK/tools/discoveryregistry"
"github.com/OpenIMSDK/tools/log"
"github.com/OpenIMSDK/tools/utils"
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
"golang.org/x/sync/errgroup"
"google.golang.org/grpc"
"os"
"sync"
)
const (
ENVNAME = "ENVS_DISCOVERY"
KUBERNETES = "k8s"
ZOOKEEPER = "zookeeper"
)
type OnlinePusher interface {
GetConnsAndOnlinePush(ctx context.Context, msg *sdkws.MsgData,
pushToUserIDs []string) (wsResults []*msggateway.SingleMsgToUserResults, err error)
GetOnlinePushFailedUserIDs(ctx context.Context, msg *sdkws.MsgData, wsResults []*msggateway.SingleMsgToUserResults,
pushToUserIDs *[]string) []string
}
type emptyOnlinePUsher struct{}
func newEmptyOnlinePUsher() *emptyOnlinePUsher {
return &emptyOnlinePUsher{}
}
func (emptyOnlinePUsher) GetConnsAndOnlinePush(ctx context.Context, msg *sdkws.MsgData,
pushToUserIDs []string) (wsResults []*msggateway.SingleMsgToUserResults, err error) {
log.ZWarn(ctx, "emptyOnlinePUsher GetConnsAndOnlinePush", nil)
return nil, nil
}
func (u emptyOnlinePUsher) GetOnlinePushFailedUserIDs(ctx context.Context, msg *sdkws.MsgData,
wsResults []*msggateway.SingleMsgToUserResults, pushToUserIDs *[]string) []string {
log.ZWarn(ctx, "emptyOnlinePUsher GetOnlinePushFailedUserIDs", nil)
return nil
}
func NewOnlinePusher(disCov discoveryregistry.SvcDiscoveryRegistry) OnlinePusher {
var envType string
if value := os.Getenv(ENVNAME); value != "" {
envType = os.Getenv(ENVNAME)
} else {
envType = config.Config.Envs.Discovery
}
switch envType {
case KUBERNETES:
return NewK8sStaticConsistentHash(disCov)
case ZOOKEEPER:
return NewDefaultAllNode(disCov)
default:
return newEmptyOnlinePUsher()
}
}
type DefaultAllNode struct {
disCov discoveryregistry.SvcDiscoveryRegistry
}
func NewDefaultAllNode(disCov discoveryregistry.SvcDiscoveryRegistry) *DefaultAllNode {
return &DefaultAllNode{disCov: disCov}
}
func (d *DefaultAllNode) GetConnsAndOnlinePush(ctx context.Context, msg *sdkws.MsgData,
pushToUserIDs []string) (wsResults []*msggateway.SingleMsgToUserResults, err error) {
conns, err := d.disCov.GetConns(ctx, config.Config.RpcRegisterName.OpenImMessageGatewayName)
log.ZDebug(ctx, "get gateway conn", "conn length", len(conns))
if err != nil {
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
for _, conn := range conns {
conn := conn // loop var safe
wg.Go(func() error {
msgClient := msggateway.NewMsgGatewayClient(conn)
reply, err := msgClient.SuperGroupOnlineBatchPushOneMsg(ctx, input)
if err != nil {
return nil
}
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
}
func (d *DefaultAllNode) GetOnlinePushFailedUserIDs(_ context.Context, msg *sdkws.MsgData,
wsResults []*msggateway.SingleMsgToUserResults, pushToUserIDs *[]string) []string {
onlineSuccessUserIDs := []string{msg.SendID}
for _, v := range wsResults {
//message sender do not need offline push
if msg.SendID == v.UserID {
continue
}
// mobile online push success
if v.OnlinePush {
onlineSuccessUserIDs = append(onlineSuccessUserIDs, v.UserID)
}
}
return utils.SliceSub(*pushToUserIDs, onlineSuccessUserIDs)
}
type K8sStaticConsistentHash struct {
disCov discoveryregistry.SvcDiscoveryRegistry
}
func NewK8sStaticConsistentHash(disCov discoveryregistry.SvcDiscoveryRegistry) *K8sStaticConsistentHash {
return &K8sStaticConsistentHash{disCov: disCov}
}
func (k *K8sStaticConsistentHash) GetConnsAndOnlinePush(ctx context.Context, msg *sdkws.MsgData,
pushToUserIDs []string) (wsResults []*msggateway.SingleMsgToUserResults, err error) {
var usersHost = make(map[string][]string)
for _, v := range pushToUserIDs {
tHost, err := k.disCov.GetUserIdHashGatewayHost(ctx, v)
if err != nil {
log.ZError(ctx, "get msg gateway hash error", err)
return nil, err
}
tUsers, tbl := usersHost[tHost]
if tbl {
tUsers = append(tUsers, v)
usersHost[tHost] = tUsers
} else {
usersHost[tHost] = []string{v}
}
}
log.ZDebug(ctx, "genUsers send hosts struct:", "usersHost", usersHost)
var usersConns = make(map[*grpc.ClientConn][]string)
for host, userIds := range usersHost {
tconn, _ := k.disCov.GetConn(ctx, host)
usersConns[tconn] = userIds
}
var (
mu sync.Mutex
wg = errgroup.Group{}
maxWorkers = config.Config.Push.MaxConcurrentWorkers
)
if maxWorkers < 3 {
maxWorkers = 3
}
wg.SetLimit(maxWorkers)
for conn, userIds := range usersConns {
tcon := conn
tuserIds := userIds
wg.Go(func() error {
input := &msggateway.OnlineBatchPushOneMsgReq{MsgData: msg, PushToUserIDs: tuserIds}
msgClient := msggateway.NewMsgGatewayClient(tcon)
reply, err := msgClient.SuperGroupOnlineBatchPushOneMsg(ctx, input)
if err != nil {
return nil
}
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()
return wsResults, nil
}
func (k *K8sStaticConsistentHash) GetOnlinePushFailedUserIDs(_ context.Context, _ *sdkws.MsgData,
wsResults []*msggateway.SingleMsgToUserResults, _ *[]string) []string {
var needOfflinePushUserIDs []string
for _, v := range wsResults {
if !v.OnlinePush {
needOfflinePushUserIDs = append(needOfflinePushUserIDs, v.UserID)
}
}
return needOfflinePushUserIDs
}

View File

@@ -1,51 +0,0 @@
package push
import (
"context"
pbpush "github.com/OpenIMSDK/protocol/push"
"github.com/OpenIMSDK/tools/discoveryregistry"
"github.com/openimsdk/open-im-server/v3/internal/push/offlinepush"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/cache"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/controller"
"google.golang.org/grpc"
)
type pushServer struct {
database controller.PushDatabase
disCov discoveryregistry.SvcDiscoveryRegistry
offlinePusher offlinepush.OfflinePusher
pushCh *ConsumerHandler
}
func (p pushServer) PushMsg(ctx context.Context, req *pbpush.PushMsgReq) (*pbpush.PushMsgResp, error) {
//todo reserved Interface
return nil, nil
}
func (p pushServer) DelUserPushToken(ctx context.Context,
req *pbpush.DelUserPushTokenReq) (resp *pbpush.DelUserPushTokenResp, err error) {
if err = p.database.DelFcmToken(ctx, req.UserID, int(req.PlatformID)); err != nil {
return nil, err
}
return &pbpush.DelUserPushTokenResp{}, nil
}
func Start(disCov discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) error {
rdb, err := cache.NewRedis()
if err != nil {
return err
}
cacheModel := cache.NewMsgCacheModel(rdb)
offlinePusher := offlinepush.NewOfflinePusher(cacheModel)
database := controller.NewPushDatabase(cacheModel)
consumer := NewConsumerHandler(offlinePusher, rdb, disCov)
pbpush.RegisterPushMsgServiceServer(server, &pushServer{
database: database,
disCov: disCov,
offlinePusher: offlinePusher,
pushCh: consumer,
})
go consumer.pushConsumerGroup.RegisterHandleAndConsumer(consumer)
return nil
}

View File

@@ -16,17 +16,6 @@ package push
import ( import (
"context" "context"
"encoding/json"
"github.com/OpenIMSDK/protocol/sdkws"
"github.com/OpenIMSDK/tools/discoveryregistry"
"github.com/OpenIMSDK/tools/mcontext"
"github.com/openimsdk/open-im-server/v3/internal/push/offlinepush"
"github.com/openimsdk/open-im-server/v3/internal/push/offlinepush/options"
"github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics"
"github.com/openimsdk/open-im-server/v3/pkg/msgprocessor"
"github.com/openimsdk/open-im-server/v3/pkg/rpccache"
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
"github.com/redis/go-redis/v9"
"github.com/IBM/sarama" "github.com/IBM/sarama"
"google.golang.org/protobuf/proto" "google.golang.org/protobuf/proto"
@@ -42,32 +31,23 @@ import (
) )
type ConsumerHandler struct { type ConsumerHandler struct {
pushConsumerGroup *kfk.MConsumerGroup pushConsumerGroup *kfk.MConsumerGroup
offlinePusher offlinepush.OfflinePusher pusher *Pusher
onlinePusher OnlinePusher
groupLocalCache *rpccache.GroupLocalCache
conversationLocalCache *rpccache.ConversationLocalCache
msgRpcClient rpcclient.MessageRpcClient
conversationRpcClient rpcclient.ConversationRpcClient
groupRpcClient rpcclient.GroupRpcClient
} }
func NewConsumerHandler(offlinePusher offlinepush.OfflinePusher, func NewConsumerHandler(pusher *Pusher) (*ConsumerHandler, error) {
rdb redis.UniversalClient, disCov discoveryregistry.SvcDiscoveryRegistry) *ConsumerHandler {
var consumerHandler ConsumerHandler var consumerHandler ConsumerHandler
consumerHandler.pushConsumerGroup = kfk.NewMConsumerGroup(&kfk.MConsumerGroupConfig{ consumerHandler.pusher = pusher
var err error
consumerHandler.pushConsumerGroup, err = kfk.NewMConsumerGroup(&kfk.MConsumerGroupConfig{
KafkaVersion: sarama.V2_0_0_0, KafkaVersion: sarama.V2_0_0_0,
OffsetsInitial: sarama.OffsetNewest, IsReturnErr: false, OffsetsInitial: sarama.OffsetNewest, IsReturnErr: false,
}, []string{config.Config.Kafka.MsgToPush.Topic}, config.Config.Kafka.Addr, }, []string{config.Config.Kafka.MsgToPush.Topic}, config.Config.Kafka.Addr,
config.Config.Kafka.ConsumerGroupID.MsgToPush) config.Config.Kafka.ConsumerGroupID.MsgToPush)
consumerHandler.offlinePusher = offlinePusher if err != nil {
consumerHandler.onlinePusher = NewOnlinePusher(disCov) return nil, err
consumerHandler.groupRpcClient = rpcclient.NewGroupRpcClient(disCov) }
consumerHandler.groupLocalCache = rpccache.NewGroupLocalCache(consumerHandler.groupRpcClient, rdb) return &consumerHandler, nil
consumerHandler.msgRpcClient = rpcclient.NewMessageRpcClient(disCov)
consumerHandler.conversationRpcClient = rpcclient.NewConversationRpcClient(disCov)
consumerHandler.conversationLocalCache = rpccache.NewConversationLocalCache(consumerHandler.conversationRpcClient, rdb)
return &consumerHandler
} }
func (c *ConsumerHandler) handleMs2PsChat(ctx context.Context, msg []byte) { func (c *ConsumerHandler) handleMs2PsChat(ctx context.Context, msg []byte) {
@@ -89,7 +69,7 @@ func (c *ConsumerHandler) handleMs2PsChat(ctx context.Context, msg []byte) {
var err error var err error
switch msgFromMQ.MsgData.SessionType { switch msgFromMQ.MsgData.SessionType {
case constant.SuperGroupChatType: case constant.SuperGroupChatType:
err = c.Push2SuperGroup(ctx, pbData.MsgData.GroupID, pbData.MsgData) err = c.pusher.Push2SuperGroup(ctx, pbData.MsgData.GroupID, pbData.MsgData)
default: default:
var pushUserIDList []string var pushUserIDList []string
isSenderSync := utils.GetSwitchFromOptions(pbData.MsgData.Options, constant.IsSenderSync) isSenderSync := utils.GetSwitchFromOptions(pbData.MsgData.Options, constant.IsSenderSync)
@@ -98,14 +78,18 @@ func (c *ConsumerHandler) handleMs2PsChat(ctx context.Context, msg []byte) {
} else { } else {
pushUserIDList = append(pushUserIDList, pbData.MsgData.RecvID, pbData.MsgData.SendID) pushUserIDList = append(pushUserIDList, pbData.MsgData.RecvID, pbData.MsgData.SendID)
} }
err = c.Push2User(ctx, pushUserIDList, pbData.MsgData) err = c.pusher.Push2User(ctx, pushUserIDList, pbData.MsgData)
} }
if err != nil { if err != nil {
log.ZError(ctx, "push failed", err, "msg", pbData.String()) if err == errNoOfflinePusher {
log.ZWarn(ctx, "offline push failed", err, "msg", pbData.String())
} else {
log.ZError(ctx, "push failed", err, "msg", pbData.String())
}
} }
} }
func (*ConsumerHandler) Setup(_ sarama.ConsumerGroupSession) error { return nil } func (ConsumerHandler) Setup(_ sarama.ConsumerGroupSession) error { return nil }
func (*ConsumerHandler) Cleanup(_ sarama.ConsumerGroupSession) error { return nil } func (ConsumerHandler) Cleanup(_ sarama.ConsumerGroupSession) error { return nil }
func (c *ConsumerHandler) ConsumeClaim(sess sarama.ConsumerGroupSession, func (c *ConsumerHandler) ConsumeClaim(sess sarama.ConsumerGroupSession,
claim sarama.ConsumerGroupClaim, claim sarama.ConsumerGroupClaim,
) error { ) error {
@@ -116,243 +100,3 @@ func (c *ConsumerHandler) ConsumeClaim(sess sarama.ConsumerGroupSession,
} }
return nil return nil
} }
// Push2User Suitable for two types of conversations, one is SingleChatType and the other is NotificationChatType.
func (c *ConsumerHandler) Push2User(ctx context.Context, userIDs []string, msg *sdkws.MsgData) error {
log.ZDebug(ctx, "Get msg from msg_transfer And push msg", "userIDs", userIDs, "msg", msg.String())
if err := callbackOnlinePush(ctx, userIDs, msg); err != nil {
return err
}
wsResults, err := c.onlinePusher.GetConnsAndOnlinePush(ctx, msg, userIDs)
if err != nil {
return err
}
log.ZDebug(ctx, "single and notification push result", "result", wsResults, "msg", msg, "push_to_userID", userIDs)
if !c.shouldPushOffline(ctx, msg) {
return nil
}
for _, v := range wsResults {
//message sender do not need offline push
if msg.SendID == v.UserID {
continue
}
//receiver online push success
if v.OnlinePush {
return nil
}
}
offlinePUshUserID := []string{msg.RecvID}
//receiver offline push
if err = callbackOfflinePush(ctx, offlinePUshUserID, msg, nil); err != nil {
return err
}
err = c.offlinePushMsg(ctx, msg, offlinePUshUserID)
if err != nil {
return err
}
return nil
}
func (c *ConsumerHandler) Push2SuperGroup(ctx context.Context, groupID string, msg *sdkws.MsgData) (err error) {
log.ZDebug(ctx, "Get super group msg from msg_transfer and push msg", "msg", msg.String(), "groupID", groupID)
var pushToUserIDs []string
if err = callbackBeforeSuperGroupOnlinePush(ctx, groupID, msg, &pushToUserIDs); err != nil {
return err
}
err = c.groupMessagesHandler(ctx, groupID, &pushToUserIDs, msg)
if err != nil {
return err
}
wsResults, err := c.onlinePusher.GetConnsAndOnlinePush(ctx, msg, pushToUserIDs)
if err != nil {
return err
}
log.ZDebug(ctx, "group push result", "result", wsResults, "msg", msg)
if !c.shouldPushOffline(ctx, msg) {
return nil
}
needOfflinePushUserIDs := c.onlinePusher.GetOnlinePushFailedUserIDs(ctx, msg, wsResults, &pushToUserIDs)
//filter some user, like don not disturb or don't need offline push etc.
needOfflinePushUserIDs, err = c.filterGroupMessageOfflinePush(ctx, groupID, msg, needOfflinePushUserIDs)
if err != nil {
return err
}
// Use offline push messaging
if len(needOfflinePushUserIDs) > 0 {
var offlinePushUserIDs []string
err = callbackOfflinePush(ctx, needOfflinePushUserIDs, msg, &offlinePushUserIDs)
if err != nil {
return err
}
if len(offlinePushUserIDs) > 0 {
needOfflinePushUserIDs = offlinePushUserIDs
}
err = c.offlinePushMsg(ctx, msg, needOfflinePushUserIDs)
if err != nil {
log.ZError(ctx, "offlinePushMsg failed", err, "groupID", groupID, "msg", msg)
return err
}
}
return nil
}
func (c *ConsumerHandler) offlinePushMsg(ctx context.Context, msg *sdkws.MsgData, offlinePushUserIDs []string) error {
title, content, opts, err := c.getOfflinePushInfos(msg)
if err != nil {
return err
}
err = c.offlinePusher.Push(ctx, offlinePushUserIDs, title, content, opts)
if err != nil {
prommetrics.MsgOfflinePushFailedCounter.Inc()
return err
}
return nil
}
func (c *ConsumerHandler) filterGroupMessageOfflinePush(ctx context.Context, groupID string, msg *sdkws.MsgData,
offlinePushUserIDs []string) (userIDs []string, err error) {
//todo local cache Obtain the difference set through local comparison.
needOfflinePushUserIDs, err := c.conversationRpcClient.GetConversationOfflinePushUserIDs(
ctx, utils.GenGroupConversationID(groupID), offlinePushUserIDs)
if err != nil {
return nil, err
}
return needOfflinePushUserIDs, nil
}
func (c *ConsumerHandler) getOfflinePushInfos(msg *sdkws.MsgData) (title, content string, opts *options.Opts, err error) {
type AtTextElem struct {
Text string `json:"text,omitempty"`
AtUserList []string `json:"atUserList,omitempty"`
IsAtSelf bool `json:"isAtSelf"`
}
opts = &options.Opts{Signal: &options.Signal{}}
if msg.OfflinePushInfo != nil {
opts.IOSBadgeCount = msg.OfflinePushInfo.IOSBadgeCount
opts.IOSPushSound = msg.OfflinePushInfo.IOSPushSound
opts.Ex = msg.OfflinePushInfo.Ex
}
if msg.OfflinePushInfo != nil {
title = msg.OfflinePushInfo.Title
content = msg.OfflinePushInfo.Desc
}
if title == "" {
switch msg.ContentType {
case constant.Text:
fallthrough
case constant.Picture:
fallthrough
case constant.Voice:
fallthrough
case constant.Video:
fallthrough
case constant.File:
title = constant.ContentType2PushContent[int64(msg.ContentType)]
case constant.AtText:
ac := AtTextElem{}
_ = utils.JsonStringToStruct(string(msg.Content), &ac)
case constant.SignalingNotification:
title = constant.ContentType2PushContent[constant.SignalMsg]
default:
title = constant.ContentType2PushContent[constant.Common]
}
}
if content == "" {
content = title
}
return
}
func (c *ConsumerHandler) groupMessagesHandler(ctx context.Context, groupID string, pushToUserIDs *[]string, msg *sdkws.MsgData) (err error) {
if len(*pushToUserIDs) == 0 {
*pushToUserIDs, err = c.groupLocalCache.GetGroupMemberIDs(ctx, groupID)
if err != nil {
return err
}
switch msg.ContentType {
case constant.MemberQuitNotification:
var tips sdkws.MemberQuitTips
if unmarshalNotificationElem(msg.Content, &tips) != nil {
return err
}
if err = c.DeleteMemberAndSetConversationSeq(ctx, groupID, []string{tips.QuitUser.UserID}); err != nil {
log.ZError(ctx, "MemberQuitNotification DeleteMemberAndSetConversationSeq", err, "groupID", groupID, "userID", tips.QuitUser.UserID)
}
*pushToUserIDs = append(*pushToUserIDs, tips.QuitUser.UserID)
case constant.MemberKickedNotification:
var tips sdkws.MemberKickedTips
if unmarshalNotificationElem(msg.Content, &tips) != nil {
return err
}
kickedUsers := utils.Slice(tips.KickedUserList, func(e *sdkws.GroupMemberFullInfo) string { return e.UserID })
if err = c.DeleteMemberAndSetConversationSeq(ctx, groupID, kickedUsers); err != nil {
log.ZError(ctx, "MemberKickedNotification DeleteMemberAndSetConversationSeq", err, "groupID", groupID, "userIDs", kickedUsers)
}
*pushToUserIDs = append(*pushToUserIDs, kickedUsers...)
case constant.GroupDismissedNotification:
if msgprocessor.IsNotification(msgprocessor.GetConversationIDByMsg(msg)) { // 消息先到,通知后到
var tips sdkws.GroupDismissedTips
if unmarshalNotificationElem(msg.Content, &tips) != nil {
return err
}
log.ZInfo(ctx, "GroupDismissedNotificationInfo****", "groupID", groupID, "num", len(*pushToUserIDs), "list", pushToUserIDs)
if len(config.Config.Manager.UserID) > 0 {
ctx = mcontext.WithOpUserIDContext(ctx, config.Config.Manager.UserID[0])
}
defer func(groupID string) {
if err = c.groupRpcClient.DismissGroup(ctx, groupID); err != nil {
log.ZError(ctx, "DismissGroup Notification clear members", err, "groupID", groupID)
}
}(groupID)
}
}
}
return err
}
func (c *ConsumerHandler) DeleteMemberAndSetConversationSeq(ctx context.Context, groupID string, userIDs []string) error {
conversationID := msgprocessor.GetConversationIDBySessionType(constant.SuperGroupChatType, groupID)
maxSeq, err := c.msgRpcClient.GetConversationMaxSeq(ctx, conversationID)
if err != nil {
return err
}
return c.conversationRpcClient.SetConversationMaxSeq(ctx, userIDs, conversationID, maxSeq)
}
func unmarshalNotificationElem(bytes []byte, t any) error {
var notification sdkws.NotificationElem
if err := json.Unmarshal(bytes, &notification); err != nil {
return err
}
return json.Unmarshal([]byte(notification.Detail), t)
}
func (c *ConsumerHandler) shouldPushOffline(_ context.Context, msg *sdkws.MsgData) bool {
isOfflinePush := utils.GetSwitchFromOptions(msg.Options, constant.IsOfflinePush)
if !isOfflinePush {
return false
}
if msg.ContentType == constant.SignalingNotification {
return false
}
return true
}

View File

@@ -0,0 +1,113 @@
// 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 push
import (
"context"
"sync"
"github.com/OpenIMSDK/tools/utils"
"google.golang.org/grpc"
"github.com/OpenIMSDK/protocol/constant"
pbpush "github.com/OpenIMSDK/protocol/push"
"github.com/OpenIMSDK/tools/discoveryregistry"
"github.com/OpenIMSDK/tools/log"
"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/localcache"
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
)
type pushServer struct {
pusher *Pusher
}
func Start(client discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) error {
rdb, err := cache.NewRedis()
if err != nil {
return err
}
cacheModel := cache.NewMsgCacheModel(rdb)
offlinePusher := NewOfflinePusher(cacheModel)
database := controller.NewPushDatabase(cacheModel)
groupRpcClient := rpcclient.NewGroupRpcClient(client)
conversationRpcClient := rpcclient.NewConversationRpcClient(client)
msgRpcClient := rpcclient.NewMessageRpcClient(client)
pusher := NewPusher(
client,
offlinePusher,
database,
localcache.NewGroupLocalCache(&groupRpcClient),
localcache.NewConversationLocalCache(&conversationRpcClient),
&conversationRpcClient,
&groupRpcClient,
&msgRpcClient,
)
var wg sync.WaitGroup
wg.Add(2)
go func() {
defer wg.Done()
pbpush.RegisterPushMsgServiceServer(server, &pushServer{
pusher: pusher,
})
}()
consumer, err := NewConsumer(pusher)
if err != nil {
return err
}
go func() {
defer wg.Done()
consumer.Start()
}()
wg.Wait()
return nil
}
func (r *pushServer) PushMsg(ctx context.Context, pbData *pbpush.PushMsgReq) (resp *pbpush.PushMsgResp, err error) {
switch pbData.MsgData.SessionType {
case constant.SuperGroupChatType:
err = r.pusher.Push2SuperGroup(ctx, pbData.MsgData.GroupID, pbData.MsgData)
default:
var pushUserIDList []string
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 != errNoOfflinePusher {
return nil, err
} else {
log.ZWarn(ctx, "offline push failed", err, "msg", pbData.String())
}
}
return &pbpush.PushMsgResp{}, nil
}
func (r *pushServer) DelUserPushToken(
ctx context.Context,
req *pbpush.DelUserPushTokenReq,
) (resp *pbpush.DelUserPushTokenResp, err error) {
if err = r.pusher.database.DelFcmToken(ctx, req.UserID, int(req.PlatformID)); err != nil {
return nil, err
}
return &pbpush.DelUserPushTokenResp{}, nil
}

View File

@@ -0,0 +1,522 @@
// 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 push
import (
"context"
"encoding/json"
"errors"
"sync"
"google.golang.org/grpc"
"golang.org/x/sync/errgroup"
"github.com/OpenIMSDK/protocol/constant"
"github.com/OpenIMSDK/protocol/conversation"
"github.com/OpenIMSDK/protocol/msggateway"
"github.com/OpenIMSDK/protocol/sdkws"
"github.com/OpenIMSDK/tools/discoveryregistry"
"github.com/OpenIMSDK/tools/log"
"github.com/OpenIMSDK/tools/mcontext"
"github.com/OpenIMSDK/tools/utils"
"github.com/openimsdk/open-im-server/v3/internal/push/offlinepush"
"github.com/openimsdk/open-im-server/v3/internal/push/offlinepush/dummy"
"github.com/openimsdk/open-im-server/v3/internal/push/offlinepush/fcm"
"github.com/openimsdk/open-im-server/v3/internal/push/offlinepush/getui"
"github.com/openimsdk/open-im-server/v3/internal/push/offlinepush/jpush"
"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/controller"
"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/msgprocessor"
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
)
type Pusher struct {
database controller.PushDatabase
discov discoveryregistry.SvcDiscoveryRegistry
offlinePusher offlinepush.OfflinePusher
groupLocalCache *localcache.GroupLocalCache
conversationLocalCache *localcache.ConversationLocalCache
msgRpcClient *rpcclient.MessageRpcClient
conversationRpcClient *rpcclient.ConversationRpcClient
groupRpcClient *rpcclient.GroupRpcClient
}
var errNoOfflinePusher = errors.New("no offlinePusher is configured")
func NewPusher(discov discoveryregistry.SvcDiscoveryRegistry, offlinePusher offlinepush.OfflinePusher, database controller.PushDatabase,
groupLocalCache *localcache.GroupLocalCache, conversationLocalCache *localcache.ConversationLocalCache,
conversationRpcClient *rpcclient.ConversationRpcClient, groupRpcClient *rpcclient.GroupRpcClient, msgRpcClient *rpcclient.MessageRpcClient,
) *Pusher {
return &Pusher{
discov: discov,
database: database,
offlinePusher: offlinePusher,
groupLocalCache: groupLocalCache,
conversationLocalCache: conversationLocalCache,
msgRpcClient: msgRpcClient,
conversationRpcClient: conversationRpcClient,
groupRpcClient: groupRpcClient,
}
}
func NewOfflinePusher(cache cache.MsgModel) offlinepush.OfflinePusher {
var offlinePusher offlinepush.OfflinePusher
switch config.Config.Push.Enable {
case "getui":
offlinePusher = getui.NewClient(cache)
case "fcm":
offlinePusher = fcm.NewClient(cache)
case "jpush":
offlinePusher = jpush.NewClient()
default:
offlinePusher = dummy.NewClient()
}
return offlinePusher
}
func (p *Pusher) DeleteMemberAndSetConversationSeq(ctx context.Context, groupID string, userIDs []string) error {
conevrsationID := msgprocessor.GetConversationIDBySessionType(constant.SuperGroupChatType, groupID)
maxSeq, err := p.msgRpcClient.GetConversationMaxSeq(ctx, conevrsationID)
if err != nil {
return err
}
return p.conversationRpcClient.SetConversationMaxSeq(ctx, userIDs, conevrsationID, maxSeq)
}
func (p *Pusher) Push2User(ctx context.Context, userIDs []string, msg *sdkws.MsgData) error {
log.ZDebug(ctx, "Get msg from msg_transfer And push msg", "userIDs", userIDs, "msg", msg.String())
if err := callbackOnlinePush(ctx, userIDs, msg); err != nil {
return err
}
// push
wsResults, err := p.GetConnsAndOnlinePush(ctx, msg, userIDs)
if err != nil {
return err
}
isOfflinePush := utils.GetSwitchFromOptions(msg.Options, constant.IsOfflinePush)
log.ZDebug(ctx, "push_result", "ws push result", wsResults, "sendData", msg, "isOfflinePush", isOfflinePush, "push_to_userID", userIDs)
if !isOfflinePush {
return nil
}
if len(wsResults) == 0 {
return nil
}
onlinePushSuccUserIDSet := utils.SliceSet(utils.Filter(wsResults, func(e *msggateway.SingleMsgToUserResults) (string, bool) {
return e.UserID, e.OnlinePush && e.UserID != ""
}))
offlinePushUserIDList := utils.Filter(wsResults, func(e *msggateway.SingleMsgToUserResults) (string, bool) {
_, exist := onlinePushSuccUserIDSet[e.UserID]
return e.UserID, !exist && e.UserID != "" && e.UserID != msg.SendID
})
if len(offlinePushUserIDList) > 0 {
if err = callbackOfflinePush(ctx, offlinePushUserIDList, msg, &[]string{}); err != nil {
return err
}
err = p.offlinePushMsg(ctx, msg.SendID, msg, offlinePushUserIDList)
if err != nil {
return err
}
}
return nil
}
func (p *Pusher) UnmarshalNotificationElem(bytes []byte, t any) error {
var notification sdkws.NotificationElem
if err := json.Unmarshal(bytes, &notification); err != nil {
return err
}
return json.Unmarshal([]byte(notification.Detail), t)
}
/*
k8s deployment,offline push group messages function.
*/
func (p *Pusher) k8sOfflinePush2SuperGroup(ctx context.Context, groupID string, msg *sdkws.MsgData, wsResults []*msggateway.SingleMsgToUserResults) error {
var needOfflinePushUserIDs []string
for _, v := range wsResults {
if !v.OnlinePush {
needOfflinePushUserIDs = append(needOfflinePushUserIDs, v.UserID)
}
}
if len(needOfflinePushUserIDs) > 0 {
var offlinePushUserIDs []string
err := callbackOfflinePush(ctx, needOfflinePushUserIDs, msg, &offlinePushUserIDs)
if err != nil {
return err
}
if len(offlinePushUserIDs) > 0 {
needOfflinePushUserIDs = offlinePushUserIDs
}
if msg.ContentType != constant.SignalingNotification {
resp, err := p.conversationRpcClient.Client.GetConversationOfflinePushUserIDs(
ctx,
&conversation.GetConversationOfflinePushUserIDsReq{ConversationID: utils.GenGroupConversationID(groupID), UserIDs: needOfflinePushUserIDs},
)
if err != nil {
return err
}
if len(resp.UserIDs) > 0 {
err = p.offlinePushMsg(ctx, groupID, msg, resp.UserIDs)
if err != nil {
log.ZError(ctx, "offlinePushMsg failed", err, "groupID", groupID, "msg", msg)
return err
}
}
}
}
return nil
}
func (p *Pusher) Push2SuperGroup(ctx context.Context, groupID string, msg *sdkws.MsgData) (err error) {
log.ZDebug(ctx, "Get super group msg from msg_transfer and push msg", "msg", msg.String(), "groupID", groupID)
var pushToUserIDs []string
if err = callbackBeforeSuperGroupOnlinePush(ctx, groupID, msg, &pushToUserIDs); err != nil {
return err
}
if len(pushToUserIDs) == 0 {
pushToUserIDs, err = p.groupLocalCache.GetGroupMemberIDs(ctx, groupID)
if err != nil {
return err
}
switch msg.ContentType {
case constant.MemberQuitNotification:
var tips sdkws.MemberQuitTips
if p.UnmarshalNotificationElem(msg.Content, &tips) != nil {
return err
}
defer func(groupID string, userIDs []string) {
if err = p.DeleteMemberAndSetConversationSeq(ctx, groupID, userIDs); err != nil {
log.ZError(ctx, "MemberQuitNotification DeleteMemberAndSetConversationSeq", err, "groupID", groupID, "userIDs", userIDs)
}
}(groupID, []string{tips.QuitUser.UserID})
pushToUserIDs = append(pushToUserIDs, tips.QuitUser.UserID)
case constant.MemberKickedNotification:
var tips sdkws.MemberKickedTips
if p.UnmarshalNotificationElem(msg.Content, &tips) != nil {
return err
}
kickedUsers := utils.Slice(tips.KickedUserList, func(e *sdkws.GroupMemberFullInfo) string { return e.UserID })
defer func(groupID string, userIDs []string) {
if err = p.DeleteMemberAndSetConversationSeq(ctx, groupID, userIDs); err != nil {
log.ZError(ctx, "MemberKickedNotification DeleteMemberAndSetConversationSeq", err, "groupID", groupID, "userIDs", userIDs)
}
}(groupID, kickedUsers)
pushToUserIDs = append(pushToUserIDs, kickedUsers...)
case constant.GroupDismissedNotification:
if msgprocessor.IsNotification(msgprocessor.GetConversationIDByMsg(msg)) { // 消息先到,通知后到
var tips sdkws.GroupDismissedTips
if p.UnmarshalNotificationElem(msg.Content, &tips) != nil {
return err
}
log.ZInfo(ctx, "GroupDismissedNotificationInfo****", "groupID", groupID, "num", len(pushToUserIDs), "list", pushToUserIDs)
if len(config.Config.Manager.UserID) > 0 {
ctx = mcontext.WithOpUserIDContext(ctx, config.Config.Manager.UserID[0])
}
if len(config.Config.Manager.UserID) == 0 && len(config.Config.IMAdmin.UserID) > 0 {
ctx = mcontext.WithOpUserIDContext(ctx, config.Config.IMAdmin.UserID[0])
}
defer func(groupID string) {
if err = p.groupRpcClient.DismissGroup(ctx, groupID); err != nil {
log.ZError(ctx, "DismissGroup Notification clear members", err, "groupID", groupID)
}
}(groupID)
}
}
}
wsResults, err := p.GetConnsAndOnlinePush(ctx, msg, pushToUserIDs)
if err != nil {
return err
}
log.ZDebug(ctx, "get conn and online push success", "result", wsResults, "msg", msg)
isOfflinePush := utils.GetSwitchFromOptions(msg.Options, constant.IsOfflinePush)
if isOfflinePush && config.Config.Envs.Discovery == "k8s" {
return p.k8sOfflinePush2SuperGroup(ctx, groupID, msg, wsResults)
}
if isOfflinePush && config.Config.Envs.Discovery == "zookeeper" {
var (
onlineSuccessUserIDs = []string{msg.SendID}
webAndPcBackgroundUserIDs []string
)
for _, v := range wsResults {
if v.OnlinePush && v.UserID != msg.SendID {
onlineSuccessUserIDs = append(onlineSuccessUserIDs, v.UserID)
}
if v.OnlinePush {
continue
}
if len(v.Resp) == 0 {
continue
}
for _, singleResult := range v.Resp {
if singleResult.ResultCode != -2 {
continue
}
isPC := constant.PlatformIDToName(int(singleResult.RecvPlatFormID)) == constant.TerminalPC
isWebID := singleResult.RecvPlatFormID == constant.WebPlatformID
if isPC || isWebID {
webAndPcBackgroundUserIDs = append(webAndPcBackgroundUserIDs, v.UserID)
}
}
}
needOfflinePushUserIDs := utils.DifferenceString(onlineSuccessUserIDs, pushToUserIDs)
// Use offline push messaging
if len(needOfflinePushUserIDs) > 0 {
var offlinePushUserIDs []string
err = callbackOfflinePush(ctx, needOfflinePushUserIDs, msg, &offlinePushUserIDs)
if err != nil {
return err
}
if len(offlinePushUserIDs) > 0 {
needOfflinePushUserIDs = offlinePushUserIDs
}
if msg.ContentType != constant.SignalingNotification {
resp, err := p.conversationRpcClient.Client.GetConversationOfflinePushUserIDs(
ctx,
&conversation.GetConversationOfflinePushUserIDsReq{ConversationID: utils.GenGroupConversationID(groupID), UserIDs: needOfflinePushUserIDs},
)
if err != nil {
return err
}
if len(resp.UserIDs) > 0 {
err = p.offlinePushMsg(ctx, groupID, msg, resp.UserIDs)
if err != nil {
log.ZError(ctx, "offlinePushMsg failed", err, "groupID", groupID, "msg", msg)
return err
}
if _, err := p.GetConnsAndOnlinePush(ctx, msg, utils.IntersectString(resp.UserIDs, webAndPcBackgroundUserIDs)); err != nil {
log.ZError(ctx, "offlinePushMsg failed", err, "groupID", groupID, "msg", msg, "userIDs", utils.IntersectString(needOfflinePushUserIDs, webAndPcBackgroundUserIDs))
return err
}
}
}
}
}
return nil
}
func (p *Pusher) k8sOnlinePush(ctx context.Context, msg *sdkws.MsgData, pushToUserIDs []string) (wsResults []*msggateway.SingleMsgToUserResults, err error) {
var usersHost = make(map[string][]string)
for _, v := range pushToUserIDs {
tHost, err := p.discov.GetUserIdHashGatewayHost(ctx, v)
if err != nil {
log.ZError(ctx, "get msggateway hash error", err)
return nil, err
}
tUsers, tbl := usersHost[tHost]
if tbl {
tUsers = append(tUsers, v)
usersHost[tHost] = tUsers
} else {
usersHost[tHost] = []string{v}
}
}
log.ZDebug(ctx, "genUsers send hosts struct:", "usersHost", usersHost)
var usersConns = make(map[*grpc.ClientConn][]string)
for host, userIds := range usersHost {
tconn, _ := p.discov.GetConn(ctx, host)
usersConns[tconn] = userIds
}
var (
mu sync.Mutex
wg = errgroup.Group{}
maxWorkers = config.Config.Push.MaxConcurrentWorkers
)
if maxWorkers < 3 {
maxWorkers = 3
}
wg.SetLimit(maxWorkers)
for conn, userIds := range usersConns {
tcon := conn
tuserIds := userIds
wg.Go(func() error {
input := &msggateway.OnlineBatchPushOneMsgReq{MsgData: msg, PushToUserIDs: tuserIds}
msgClient := msggateway.NewMsgGatewayClient(tcon)
reply, err := msgClient.SuperGroupOnlineBatchPushOneMsg(ctx, input)
if err != nil {
return nil
}
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()
return wsResults, nil
}
func (p *Pusher) GetConnsAndOnlinePush(ctx context.Context, msg *sdkws.MsgData, pushToUserIDs []string) (wsResults []*msggateway.SingleMsgToUserResults, err error) {
if config.Config.Envs.Discovery == "k8s" {
return p.k8sOnlinePush(ctx, msg, pushToUserIDs)
}
conns, err := p.discov.GetConns(ctx, config.Config.RpcRegisterName.OpenImMessageGatewayName)
log.ZDebug(ctx, "get gateway conn", "conn length", len(conns))
if err != nil {
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
for _, conn := range conns {
conn := conn // loop var safe
wg.Go(func() error {
msgClient := msggateway.NewMsgGatewayClient(conn)
reply, err := msgClient.SuperGroupOnlineBatchPushOneMsg(ctx, input)
if err != nil {
return nil
}
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
}
func (p *Pusher) offlinePushMsg(ctx context.Context, conversationID string, msg *sdkws.MsgData, offlinePushUserIDs []string) error {
title, content, opts, err := p.getOfflinePushInfos(conversationID, msg)
if err != nil {
return err
}
err = p.offlinePusher.Push(ctx, offlinePushUserIDs, title, content, opts)
if err != nil {
prommetrics.MsgOfflinePushFailedCounter.Inc()
return err
}
return nil
}
func (p *Pusher) GetOfflinePushOpts(msg *sdkws.MsgData) (opts *offlinepush.Opts, err error) {
opts = &offlinepush.Opts{Signal: &offlinepush.Signal{}}
// if msg.ContentType > constant.SignalingNotificationBegin && msg.ContentType < constant.SignalingNotificationEnd {
// req := &sdkws.SignalReq{}
// if err := proto.Unmarshal(msg.Content, req); err != nil {
// return nil, utils.Wrap(err, "")
// }
// switch req.Payload.(type) {
// case *sdkws.SignalReq_Invite, *sdkws.SignalReq_InviteInGroup:
// opts.Signal = &offlinepush.Signal{ClientMsgID: msg.ClientMsgID}
// }
// }
if msg.OfflinePushInfo != nil {
opts.IOSBadgeCount = msg.OfflinePushInfo.IOSBadgeCount
opts.IOSPushSound = msg.OfflinePushInfo.IOSPushSound
opts.Ex = msg.OfflinePushInfo.Ex
}
return opts, nil
}
func (p *Pusher) getOfflinePushInfos(conversationID string, msg *sdkws.MsgData) (title, content string, opts *offlinepush.Opts, err error) {
if p.offlinePusher == nil {
err = errNoOfflinePusher
return
}
type atContent struct {
Text string `json:"text"`
AtUserList []string `json:"atUserList"`
IsAtSelf bool `json:"isAtSelf"`
}
opts, err = p.GetOfflinePushOpts(msg)
if err != nil {
return
}
if msg.OfflinePushInfo != nil {
title = msg.OfflinePushInfo.Title
content = msg.OfflinePushInfo.Desc
}
if title == "" {
switch msg.ContentType {
case constant.Text:
fallthrough
case constant.Picture:
fallthrough
case constant.Voice:
fallthrough
case constant.Video:
fallthrough
case constant.File:
title = constant.ContentType2PushContent[int64(msg.ContentType)]
case constant.AtText:
ac := atContent{}
_ = utils.JsonStringToStruct(string(msg.Content), &ac)
if utils.IsContain(conversationID, ac.AtUserList) {
title = constant.ContentType2PushContent[constant.AtText] + constant.ContentType2PushContent[constant.Common]
} else {
title = constant.ContentType2PushContent[constant.GroupMsg]
}
case constant.SignalingNotification:
title = constant.ContentType2PushContent[constant.SignalMsg]
default:
title = constant.ContentType2PushContent[constant.Common]
}
}
if content == "" {
content = title
}
return
}

32
internal/push/tools.go Normal file
View File

@@ -0,0 +1,32 @@
// 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 push
import (
"github.com/OpenIMSDK/protocol/constant"
"github.com/OpenIMSDK/protocol/sdkws"
"google.golang.org/protobuf/proto"
)
func GetContent(msg *sdkws.MsgData) string {
if msg.ContentType >= constant.NotificationBegin && msg.ContentType <= constant.NotificationEnd {
var tips sdkws.TipsComm
_ = proto.Unmarshal(msg.Content, &tips)
content := tips.JsonDetail
return content
} else {
return string(msg.Content)
}
}

View File

@@ -16,6 +16,7 @@ package friend
import ( import (
"context" "context"
"github.com/OpenIMSDK/tools/tx" "github.com/OpenIMSDK/tools/tx"
"github.com/OpenIMSDK/protocol/sdkws" "github.com/OpenIMSDK/protocol/sdkws"

View File

@@ -44,7 +44,7 @@ func (m *msgServer) GetConversationsHasReadAndMaxSeq(ctx context.Context, req *m
if err != nil { if err != nil {
return nil, err return nil, err
} }
conversations, err := m.ConversationLocalCache.GetConversations(ctx, req.UserID, conversationIDs) conversations, err := m.Conversation.GetConversations(ctx, req.UserID, conversationIDs)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -107,7 +107,7 @@ func (m *msgServer) MarkMsgsAsRead(
if hasReadSeq > maxSeq { if hasReadSeq > maxSeq {
return nil, errs.ErrArgs.Wrap("hasReadSeq must not be bigger than maxSeq") return nil, errs.ErrArgs.Wrap("hasReadSeq must not be bigger than maxSeq")
} }
conversation, err := m.ConversationLocalCache.GetConversation(ctx, req.UserID, req.ConversationID) conversation, err := m.Conversation.GetConversation(ctx, req.UserID, req.ConversationID)
if err != nil { if err != nil {
return return
} }
@@ -147,7 +147,7 @@ func (m *msgServer) MarkConversationAsRead(
ctx context.Context, ctx context.Context,
req *msg.MarkConversationAsReadReq, req *msg.MarkConversationAsReadReq,
) (resp *msg.MarkConversationAsReadResp, err error) { ) (resp *msg.MarkConversationAsReadResp, err error) {
conversation, err := m.ConversationLocalCache.GetConversation(ctx, req.UserID, req.ConversationID) conversation, err := m.Conversation.GetConversation(ctx, req.UserID, req.ConversationID)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@@ -47,7 +47,7 @@ func (m *msgServer) RevokeMsg(ctx context.Context, req *msg.RevokeMsgReq) (*msg.
if err := authverify.CheckAccessV3(ctx, req.UserID); err != nil { if err := authverify.CheckAccessV3(ctx, req.UserID); err != nil {
return nil, err return nil, err
} }
user, err := m.UserLocalCache.GetUserInfo(ctx, req.UserID) user, err := m.User.GetUserInfo(ctx, req.UserID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -73,7 +73,12 @@ func (m *msgServer) RevokeMsg(ctx context.Context, req *msg.RevokeMsgReq) (*msg.
} }
role = user.AppMangerLevel role = user.AppMangerLevel
case constant.SuperGroupChatType: case constant.SuperGroupChatType:
members, err := m.GroupLocalCache.GetGroupMemberInfoMap(ctx, msgs[0].GroupID, utils.Distinct([]string{req.UserID, msgs[0].SendID})) members, err := m.Group.GetGroupMemberInfoMap(
ctx,
msgs[0].GroupID,
utils.Distinct([]string{req.UserID, msgs[0].SendID}),
true,
)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -106,6 +111,13 @@ func (m *msgServer) RevokeMsg(ctx context.Context, req *msg.RevokeMsgReq) (*msg.
return nil, err return nil, err
} }
revokerUserID := mcontext.GetOpUserID(ctx) revokerUserID := mcontext.GetOpUserID(ctx)
var flag bool
if len(config.Config.Manager.UserID) > 0 {
flag = utils.Contain(revokerUserID, config.Config.Manager.UserID...)
}
if len(config.Config.Manager.UserID) == 0 && len(config.Config.IMAdmin.UserID) > 0 {
flag = utils.Contain(revokerUserID, config.Config.IMAdmin.UserID...)
}
tips := sdkws.RevokeMsgTips{ tips := sdkws.RevokeMsgTips{
RevokerUserID: revokerUserID, RevokerUserID: revokerUserID,
ClientMsgID: msgs[0].ClientMsgID, ClientMsgID: msgs[0].ClientMsgID,
@@ -113,7 +125,7 @@ func (m *msgServer) RevokeMsg(ctx context.Context, req *msg.RevokeMsgReq) (*msg.
Seq: req.Seq, Seq: req.Seq,
SesstionType: msgs[0].SessionType, SesstionType: msgs[0].SessionType,
ConversationID: req.ConversationID, ConversationID: req.ConversationID,
IsAdminRevoke: utils.Contain(revokerUserID, config.Config.Manager.UserID...), IsAdminRevoke: flag,
} }
var recvID string var recvID string
if msgs[0].SessionType == constant.SuperGroupChatType { if msgs[0].SessionType == constant.SuperGroupChatType {

View File

@@ -98,7 +98,7 @@ func (m *msgServer) setConversationAtInfo(nctx context.Context, msg *sdkws.MsgDa
} }
tagAll := utils.IsContain(constant.AtAllString, msg.AtUserIDList) tagAll := utils.IsContain(constant.AtAllString, msg.AtUserIDList)
if tagAll { if tagAll {
memberUserIDList, err := m.GroupLocalCache.GetGroupMemberIDs(ctx, msg.GroupID) memberUserIDList, err := m.Group.GetGroupMemberIDs(ctx, msg.GroupID)
if err != nil { if err != nil {
log.ZWarn(ctx, "GetGroupMemberIDs", err) log.ZWarn(ctx, "GetGroupMemberIDs", err)
return return
@@ -144,7 +144,6 @@ func (m *msgServer) sendMsgNotification(
} }
func (m *msgServer) sendMsgSingleChat(ctx context.Context, req *pbmsg.SendMsgReq) (resp *pbmsg.SendMsgResp, err error) { func (m *msgServer) sendMsgSingleChat(ctx context.Context, req *pbmsg.SendMsgReq) (resp *pbmsg.SendMsgResp, err error) {
log.ZDebug(ctx, "sendMsgSingleChat return")
if err := m.messageVerification(ctx, req); err != nil { if err := m.messageVerification(ctx, req); err != nil {
return nil, err return nil, err
} }

View File

@@ -16,7 +16,6 @@ package msg
import ( import (
"context" "context"
"github.com/openimsdk/open-im-server/v3/pkg/rpccache"
"google.golang.org/grpc" "google.golang.org/grpc"
@@ -27,6 +26,7 @@ import (
"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/localcache"
"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"
) )
@@ -36,11 +36,12 @@ type (
msgServer struct { msgServer struct {
RegisterCenter discoveryregistry.SvcDiscoveryRegistry RegisterCenter discoveryregistry.SvcDiscoveryRegistry
MsgDatabase controller.CommonMsgDatabase MsgDatabase controller.CommonMsgDatabase
Group *rpcclient.GroupRpcClient
User *rpcclient.UserRpcClient
Conversation *rpcclient.ConversationRpcClient Conversation *rpcclient.ConversationRpcClient
UserLocalCache *rpccache.UserLocalCache friend *rpcclient.FriendRpcClient
FriendLocalCache *rpccache.FriendLocalCache GroupLocalCache *localcache.GroupLocalCache
GroupLocalCache *rpccache.GroupLocalCache ConversationLocalCache *localcache.ConversationLocalCache
ConversationLocalCache *rpccache.ConversationLocalCache
Handlers MessageInterceptorChain Handlers MessageInterceptorChain
notificationSender *rpcclient.NotificationSender notificationSender *rpcclient.NotificationSender
} }
@@ -79,16 +80,19 @@ func Start(client discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) e
userRpcClient := rpcclient.NewUserRpcClient(client) userRpcClient := rpcclient.NewUserRpcClient(client)
groupRpcClient := rpcclient.NewGroupRpcClient(client) groupRpcClient := rpcclient.NewGroupRpcClient(client)
friendRpcClient := rpcclient.NewFriendRpcClient(client) friendRpcClient := rpcclient.NewFriendRpcClient(client)
msgDatabase := controller.NewCommonMsgDatabase(msgDocModel, cacheModel) msgDatabase, err := controller.NewCommonMsgDatabase(msgDocModel, cacheModel)
if err != nil {
return err
}
s := &msgServer{ s := &msgServer{
Conversation: &conversationClient, Conversation: &conversationClient,
User: &userRpcClient,
Group: &groupRpcClient,
MsgDatabase: msgDatabase, MsgDatabase: msgDatabase,
RegisterCenter: client, RegisterCenter: client,
UserLocalCache: rpccache.NewUserLocalCache(userRpcClient, rdb), GroupLocalCache: localcache.NewGroupLocalCache(&groupRpcClient),
GroupLocalCache: rpccache.NewGroupLocalCache(groupRpcClient, rdb), ConversationLocalCache: localcache.NewConversationLocalCache(&conversationClient),
ConversationLocalCache: rpccache.NewConversationLocalCache(conversationClient, rdb), friend: &friendRpcClient,
FriendLocalCache: rpccache.NewFriendLocalCache(friendRpcClient, rdb),
} }
s.notificationSender = rpcclient.NewNotificationSender(rpcclient.WithLocalSendMsg(s.SendMsg)) s.notificationSender = rpcclient.NewNotificationSender(rpcclient.WithLocalSendMsg(s.SendMsg))
s.addInterceptorHandler(MessageHasReadEnabled) s.addInterceptorHandler(MessageHasReadEnabled)

View File

@@ -41,7 +41,7 @@ func (m *msgServer) GetActiveUser(ctx context.Context, req *msg.GetActiveUserReq
var pbUsers []*msg.ActiveUser var pbUsers []*msg.ActiveUser
if len(users) > 0 { if len(users) > 0 {
userIDs := utils.Slice(users, func(e *unrelation.UserCount) string { return e.UserID }) userIDs := utils.Slice(users, func(e *unrelation.UserCount) string { return e.UserID })
userMap, err := m.UserLocalCache.GetUsersInfoMap(ctx, userIDs) userMap, err := m.User.GetUsersInfoMap(ctx, userIDs)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -83,7 +83,7 @@ func (m *msgServer) GetActiveGroup(ctx context.Context, req *msg.GetActiveGroupR
var pbgroups []*msg.ActiveGroup var pbgroups []*msg.ActiveGroup
if len(groups) > 0 { if len(groups) > 0 {
groupIDs := utils.Slice(groups, func(e *unrelation.GroupCount) string { return e.GroupID }) groupIDs := utils.Slice(groups, func(e *unrelation.GroupCount) string { return e.GroupID })
resp, err := m.GroupLocalCache.GetGroupInfos(ctx, groupIDs) resp, err := m.Group.GetGroupInfos(ctx, groupIDs, false)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@@ -37,7 +37,7 @@ func (m *msgServer) PullMessageBySeqs(
resp.NotificationMsgs = make(map[string]*sdkws.PullMsgs) resp.NotificationMsgs = make(map[string]*sdkws.PullMsgs)
for _, seq := range req.SeqRanges { for _, seq := range req.SeqRanges {
if !msgprocessor.IsNotification(seq.ConversationID) { if !msgprocessor.IsNotification(seq.ConversationID) {
conversation, err := m.ConversationLocalCache.GetConversation(ctx, req.UserID, seq.ConversationID) conversation, err := m.Conversation.GetConversation(ctx, req.UserID, seq.ConversationID)
if err != nil { if err != nil {
log.ZError(ctx, "GetConversation error", err, "conversationID", seq.ConversationID) log.ZError(ctx, "GetConversation error", err, "conversationID", seq.ConversationID)
continue continue
@@ -140,7 +140,7 @@ func (m *msgServer) SearchMessage(ctx context.Context, req *msg.SearchMessageReq
} }
} }
if len(sendIDs) != 0 { if len(sendIDs) != 0 {
sendInfos, err := m.UserLocalCache.GetUsersInfo(ctx, sendIDs) sendInfos, err := m.User.GetUsersInfo(ctx, sendIDs)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -149,7 +149,7 @@ func (m *msgServer) SearchMessage(ctx context.Context, req *msg.SearchMessageReq
} }
} }
if len(recvIDs) != 0 { if len(recvIDs) != 0 {
recvInfos, err := m.UserLocalCache.GetUsersInfo(ctx, recvIDs) recvInfos, err := m.User.GetUsersInfo(ctx, recvIDs)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -158,7 +158,7 @@ func (m *msgServer) SearchMessage(ctx context.Context, req *msg.SearchMessageReq
} }
} }
if len(groupIDs) != 0 { if len(groupIDs) != 0 {
groupInfos, err := m.GroupLocalCache.GetGroupInfos(ctx, groupIDs) groupInfos, err := m.Group.GetGroupInfos(ctx, groupIDs, true)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@@ -16,7 +16,6 @@ package msg
import ( import (
"context" "context"
"github.com/OpenIMSDK/tools/log"
"math/rand" "math/rand"
"strconv" "strconv"
"time" "time"
@@ -52,14 +51,17 @@ type MessageRevoked struct {
func (m *msgServer) messageVerification(ctx context.Context, data *msg.SendMsgReq) error { func (m *msgServer) messageVerification(ctx context.Context, data *msg.SendMsgReq) error {
switch data.MsgData.SessionType { switch data.MsgData.SessionType {
case constant.SingleChatType: case constant.SingleChatType:
if utils.IsContain(data.MsgData.SendID, config.Config.Manager.UserID) { if len(config.Config.Manager.UserID) > 0 && utils.IsContain(data.MsgData.SendID, config.Config.Manager.UserID) {
return nil
}
if utils.IsContain(data.MsgData.SendID, config.Config.IMAdmin.UserID) {
return nil return nil
} }
if data.MsgData.ContentType <= constant.NotificationEnd && if data.MsgData.ContentType <= constant.NotificationEnd &&
data.MsgData.ContentType >= constant.NotificationBegin { data.MsgData.ContentType >= constant.NotificationBegin {
return nil return nil
} }
black, err := m.FriendLocalCache.IsBlack(ctx, data.MsgData.SendID, data.MsgData.RecvID) black, err := m.friend.IsBlocked(ctx, data.MsgData.SendID, data.MsgData.RecvID)
if err != nil { if err != nil {
return err return err
} }
@@ -67,7 +69,7 @@ func (m *msgServer) messageVerification(ctx context.Context, data *msg.SendMsgRe
return errs.ErrBlockedByPeer.Wrap() return errs.ErrBlockedByPeer.Wrap()
} }
if *config.Config.MessageVerify.FriendVerify { if *config.Config.MessageVerify.FriendVerify {
friend, err := m.FriendLocalCache.IsFriend(ctx, data.MsgData.SendID, data.MsgData.RecvID) friend, err := m.friend.IsFriend(ctx, data.MsgData.SendID, data.MsgData.RecvID)
if err != nil { if err != nil {
return err return err
} }
@@ -78,7 +80,7 @@ func (m *msgServer) messageVerification(ctx context.Context, data *msg.SendMsgRe
} }
return nil return nil
case constant.SuperGroupChatType: case constant.SuperGroupChatType:
groupInfo, err := m.GroupLocalCache.GetGroupInfo(ctx, data.MsgData.GroupID) groupInfo, err := m.Group.GetGroupInfoCache(ctx, data.MsgData.GroupID)
if err != nil { if err != nil {
return err return err
} }
@@ -89,24 +91,27 @@ func (m *msgServer) messageVerification(ctx context.Context, data *msg.SendMsgRe
if groupInfo.GroupType == constant.SuperGroup { if groupInfo.GroupType == constant.SuperGroup {
return nil return nil
} }
if utils.IsContain(data.MsgData.SendID, config.Config.Manager.UserID) { if len(config.Config.Manager.UserID) > 0 && utils.IsContain(data.MsgData.SendID, config.Config.Manager.UserID) {
return nil
}
if utils.IsContain(data.MsgData.SendID, config.Config.IMAdmin.UserID) {
return nil return nil
} }
if data.MsgData.ContentType <= constant.NotificationEnd && if data.MsgData.ContentType <= constant.NotificationEnd &&
data.MsgData.ContentType >= constant.NotificationBegin { data.MsgData.ContentType >= constant.NotificationBegin {
return nil return nil
} }
memberIDs, err := m.GroupLocalCache.GetGroupMemberIDMap(ctx, data.MsgData.GroupID) // memberIDs, err := m.GroupLocalCache.GetGroupMemberIDs(ctx, data.MsgData.GroupID)
if err != nil { // if err != nil {
return err // return err
} // }
if _, ok := memberIDs[data.MsgData.SendID]; !ok { // if !utils.IsContain(data.MsgData.SendID, memberIDs) {
return errs.ErrNotInGroupYet.Wrap() // return errs.ErrNotInGroupYet.Wrap()
} // }
groupMemberInfo, err := m.GroupLocalCache.GetGroupMember(ctx, data.MsgData.GroupID, data.MsgData.SendID) groupMemberInfo, err := m.Group.GetGroupMemberCache(ctx, data.MsgData.GroupID, data.MsgData.SendID)
if err != nil { if err != nil {
if errs.ErrRecordNotFound.Is(err) { if err == errs.ErrRecordNotFound {
return errs.ErrNotInGroupYet.Wrap(err.Error()) return errs.ErrNotInGroupYet.Wrap(err.Error())
} }
return err return err
@@ -187,8 +192,7 @@ func (m *msgServer) modifyMessageByUserMessageReceiveOpt(
sessionType int, sessionType int,
pb *msg.SendMsgReq, pb *msg.SendMsgReq,
) (bool, error) { ) (bool, error) {
defer log.ZDebug(ctx, "modifyMessageByUserMessageReceiveOpt return") opt, err := m.User.GetUserGlobalMsgRecvOpt(ctx, userID)
opt, err := m.UserLocalCache.GetUserGlobalMsgRecvOpt(ctx, userID)
if err != nil { if err != nil {
return false, err return false, err
} }
@@ -204,7 +208,7 @@ func (m *msgServer) modifyMessageByUserMessageReceiveOpt(
return true, nil return true, nil
} }
// conversationID := utils.GetConversationIDBySessionType(conversationID, sessionType) // conversationID := utils.GetConversationIDBySessionType(conversationID, sessionType)
singleOpt, err := m.ConversationLocalCache.GetSingleConversationRecvMsgOpt(ctx, userID, conversationID) singleOpt, err := m.Conversation.GetSingleConversationRecvMsgOpt(ctx, userID, conversationID)
if errs.ErrRecordNotFound.Is(err) { if errs.ErrRecordNotFound.Is(err) {
return true, nil return true, nil
} else if err != nil { } else if err != nil {

View File

@@ -61,7 +61,6 @@ type userServer struct {
RegisterCenter registry.SvcDiscoveryRegistry RegisterCenter registry.SvcDiscoveryRegistry
} }
func Start(client registry.SvcDiscoveryRegistry, server *grpc.Server) error { func Start(client registry.SvcDiscoveryRegistry, server *grpc.Server) error {
rdb, err := cache.NewRedis() rdb, err := cache.NewRedis()
if err != nil { if err != nil {
@@ -72,12 +71,6 @@ func Start(client registry.SvcDiscoveryRegistry, server *grpc.Server) error {
return err return err
} }
users := make([]*tablerelation.UserModel, 0) users := make([]*tablerelation.UserModel, 0)
if len(config.Config.Manager.UserID) != len(config.Config.Manager.Nickname) {
return errors.New("len(config.Config.Manager.AppManagerUid) != len(config.Config.Manager.Nickname)")
}
for k, v := range config.Config.Manager.UserID {
users = append(users, &tablerelation.UserModel{UserID: v, Nickname: config.Config.Manager.Nickname[k], AppMangerLevel: constant.AppAdmin})
}
if len(config.Config.IMAdmin.UserID) != len(config.Config.IMAdmin.Nickname) { if len(config.Config.IMAdmin.UserID) != len(config.Config.IMAdmin.Nickname) {
return errors.New("len(config.Config.AppNotificationAdmin.AppManagerUid) != len(config.Config.AppNotificationAdmin.Nickname)") return errors.New("len(config.Config.AppNotificationAdmin.AppManagerUid) != len(config.Config.AppNotificationAdmin.Nickname)")
} }

View File

@@ -22,17 +22,18 @@ import (
"syscall" "syscall"
"time" "time"
"github.com/OpenIMSDK/tools/errs"
"github.com/redis/go-redis/v9" "github.com/redis/go-redis/v9"
"github.com/robfig/cron/v3" "github.com/robfig/cron/v3"
"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" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache"
) )
func StartTask() error { func StartTask() error {
fmt.Println("cron task start, config", config.Config.ChatRecordsClearTime) fmt.Println("cron task start, config", config.Config.ChatRecordsClearTime)
msgTool, err := InitMsgTool() msgTool, err := InitMsgTool()
if err != nil { if err != nil {
return err return err
@@ -47,18 +48,16 @@ func StartTask() error {
// register cron tasks // register cron tasks
var crontab = cron.New() var crontab = cron.New()
log.ZInfo(context.Background(), "start chatRecordsClearTime cron task", "cron config", config.Config.ChatRecordsClearTime) fmt.Println("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 = crontab.AddFunc(config.Config.ChatRecordsClearTime, cronWrapFunc(rdb, "cron_clear_msg_and_fix_seq", msgTool.AllConversationClearMsgAndFixSeq))
if err != nil { if err != nil {
log.ZError(context.Background(), "start allConversationClearMsgAndFixSeq cron failed", err) return errs.Wrap(err)
panic(err)
} }
log.ZInfo(context.Background(), "start msgDestruct cron task", "cron config", config.Config.MsgDestructTime) fmt.Println("start msgDestruct cron task", "cron config", config.Config.MsgDestructTime)
_, err = crontab.AddFunc(config.Config.MsgDestructTime, cronWrapFunc(rdb, "cron_conversations_destruct_msgs", msgTool.ConversationsDestructMsgs)) _, err = crontab.AddFunc(config.Config.MsgDestructTime, cronWrapFunc(rdb, "cron_conversations_destruct_msgs", msgTool.ConversationsDestructMsgs))
if err != nil { if err != nil {
log.ZError(context.Background(), "start conversationsDestructMsgs cron failed", err) return errs.Wrap(err)
panic(err)
} }
// start crontab // start crontab

View File

@@ -84,7 +84,10 @@ func InitMsgTool() (*MsgTool, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
msgDatabase := controller.InitCommonMsgDatabase(rdb, mongo.GetDatabase()) msgDatabase, err := controller.InitCommonMsgDatabase(rdb, mongo.GetDatabase())
if err != nil {
return nil, err
}
userMongoDB := unrelation.NewUserMongoDriver(mongo.GetDatabase()) userMongoDB := unrelation.NewUserMongoDriver(mongo.GetDatabase())
ctxTx := tx.NewMongo(mongo.GetClient()) ctxTx := tx.NewMongo(mongo.GetClient())
userDatabase := controller.NewUserDatabase( userDatabase := controller.NewUserDatabase(

View File

@@ -35,7 +35,7 @@ func Secret() jwt.Keyfunc {
func CheckAccessV3(ctx context.Context, ownerUserID string) (err error) { func CheckAccessV3(ctx context.Context, ownerUserID string) (err error) {
opUserID := mcontext.GetOpUserID(ctx) opUserID := mcontext.GetOpUserID(ctx)
if utils.IsContain(opUserID, config.Config.Manager.UserID) { if len(config.Config.Manager.UserID) > 0 && utils.IsContain(opUserID, config.Config.Manager.UserID) {
return nil return nil
} }
if utils.IsContain(opUserID, config.Config.IMAdmin.UserID) { if utils.IsContain(opUserID, config.Config.IMAdmin.UserID) {
@@ -48,11 +48,12 @@ func CheckAccessV3(ctx context.Context, ownerUserID string) (err error) {
} }
func IsAppManagerUid(ctx context.Context) bool { func IsAppManagerUid(ctx context.Context) bool {
return utils.IsContain(mcontext.GetOpUserID(ctx), config.Config.Manager.UserID) || utils.IsContain(mcontext.GetOpUserID(ctx), config.Config.IMAdmin.UserID) return (len(config.Config.Manager.UserID) > 0 && utils.IsContain(mcontext.GetOpUserID(ctx), config.Config.Manager.UserID)) ||
utils.IsContain(mcontext.GetOpUserID(ctx), config.Config.IMAdmin.UserID)
} }
func CheckAdmin(ctx context.Context) error { func CheckAdmin(ctx context.Context) error {
if utils.IsContain(mcontext.GetOpUserID(ctx), config.Config.Manager.UserID) { if len(config.Config.Manager.UserID) > 0 && utils.IsContain(mcontext.GetOpUserID(ctx), config.Config.Manager.UserID) {
return nil return nil
} }
if utils.IsContain(mcontext.GetOpUserID(ctx), config.Config.IMAdmin.UserID) { if utils.IsContain(mcontext.GetOpUserID(ctx), config.Config.IMAdmin.UserID) {
@@ -64,7 +65,7 @@ func CheckIMAdmin(ctx context.Context) error {
if utils.IsContain(mcontext.GetOpUserID(ctx), config.Config.IMAdmin.UserID) { if utils.IsContain(mcontext.GetOpUserID(ctx), config.Config.IMAdmin.UserID) {
return nil return nil
} }
if utils.IsContain(mcontext.GetOpUserID(ctx), config.Config.Manager.UserID) { if len(config.Config.Manager.UserID) > 0 && utils.IsContain(mcontext.GetOpUserID(ctx), config.Config.Manager.UserID) {
return nil return nil
} }
return errs.ErrNoPermission.Wrap(fmt.Sprintf("user %s is not CheckIMAdmin userID", mcontext.GetOpUserID(ctx))) return errs.ErrNoPermission.Wrap(fmt.Sprintf("user %s is not CheckIMAdmin userID", mcontext.GetOpUserID(ctx)))
@@ -75,7 +76,7 @@ func ParseRedisInterfaceToken(redisToken any) (*tokenverify.Claims, error) {
} }
func IsManagerUserID(opUserID string) bool { func IsManagerUserID(opUserID string) bool {
return utils.IsContain(opUserID, config.Config.Manager.UserID) || utils.IsContain(opUserID, config.Config.IMAdmin.UserID) return (len(config.Config.Manager.UserID) > 0 && utils.IsContain(opUserID, config.Config.Manager.UserID)) || utils.IsContain(opUserID, config.Config.IMAdmin.UserID)
} }
func WsVerifyToken(token, userID string, platformID int) error { func WsVerifyToken(token, userID string, platformID int) error {

View File

@@ -1,15 +0,0 @@
package cachekey
const (
BlackIDsKey = "BLACK_IDS:"
IsBlackKey = "IS_BLACK:" // local cache
)
func GetBlackIDsKey(ownerUserID string) string {
return BlackIDsKey + ownerUserID
}
func GetIsBlackIDsKey(possibleBlackUserID, userID string) string {
return IsBlackKey + userID + "-" + possibleBlackUserID
}

View File

@@ -1,44 +0,0 @@
package cachekey
const (
ConversationKey = "CONVERSATION:"
ConversationIDsKey = "CONVERSATION_IDS:"
ConversationIDsHashKey = "CONVERSATION_IDS_HASH:"
ConversationHasReadSeqKey = "CONVERSATION_HAS_READ_SEQ:"
RecvMsgOptKey = "RECV_MSG_OPT:"
SuperGroupRecvMsgNotNotifyUserIDsKey = "SUPER_GROUP_RECV_MSG_NOT_NOTIFY_USER_IDS:"
SuperGroupRecvMsgNotNotifyUserIDsHashKey = "SUPER_GROUP_RECV_MSG_NOT_NOTIFY_USER_IDS_HASH:"
ConversationNotReceiveMessageUserIDsKey = "CONVERSATION_NOT_RECEIVE_MESSAGE_USER_IDS:"
)
func GetConversationKey(ownerUserID, conversationID string) string {
return ConversationKey + ownerUserID + ":" + conversationID
}
func GetConversationIDsKey(ownerUserID string) string {
return ConversationIDsKey + ownerUserID
}
func GetSuperGroupRecvNotNotifyUserIDsKey(groupID string) string {
return SuperGroupRecvMsgNotNotifyUserIDsKey + groupID
}
func GetRecvMsgOptKey(ownerUserID, conversationID string) string {
return RecvMsgOptKey + ownerUserID + ":" + conversationID
}
func GetSuperGroupRecvNotNotifyUserIDsHashKey(groupID string) string {
return SuperGroupRecvMsgNotNotifyUserIDsHashKey + groupID
}
func GetConversationHasReadSeqKey(ownerUserID, conversationID string) string {
return ConversationHasReadSeqKey + ownerUserID + ":" + conversationID
}
func GetConversationNotReceiveMessageUserIDsKey(conversationID string) string {
return ConversationNotReceiveMessageUserIDsKey + conversationID
}
func GetUserConversationIDsHashKey(ownerUserID string) string {
return ConversationIDsHashKey + ownerUserID
}

View File

@@ -1,24 +0,0 @@
package cachekey
const (
FriendIDsKey = "FRIEND_IDS:"
TwoWayFriendsIDsKey = "COMMON_FRIENDS_IDS:"
FriendKey = "FRIEND_INFO:"
IsFriendKey = "IS_FRIEND:" // local cache key
)
func GetFriendIDsKey(ownerUserID string) string {
return FriendIDsKey + ownerUserID
}
func GetTwoWayFriendsIDsKey(ownerUserID string) string {
return TwoWayFriendsIDsKey + ownerUserID
}
func GetFriendKey(ownerUserID, friendUserID string) string {
return FriendKey + ownerUserID + "-" + friendUserID
}
func GetIsFriendKey(possibleFriendUserID, userID string) string {
return IsFriendKey + possibleFriendUserID + "-" + userID
}

View File

@@ -1,45 +0,0 @@
package cachekey
import (
"strconv"
"time"
)
const (
groupExpireTime = time.Second * 60 * 60 * 12
GroupInfoKey = "GROUP_INFO:"
GroupMemberIDsKey = "GROUP_MEMBER_IDS:"
GroupMembersHashKey = "GROUP_MEMBERS_HASH2:"
GroupMemberInfoKey = "GROUP_MEMBER_INFO:"
JoinedGroupsKey = "JOIN_GROUPS_KEY:"
GroupMemberNumKey = "GROUP_MEMBER_NUM_CACHE:"
GroupRoleLevelMemberIDsKey = "GROUP_ROLE_LEVEL_MEMBER_IDS:"
)
func GetGroupInfoKey(groupID string) string {
return GroupInfoKey + groupID
}
func GetJoinedGroupsKey(userID string) string {
return JoinedGroupsKey + userID
}
func GetGroupMembersHashKey(groupID string) string {
return GroupMembersHashKey + groupID
}
func GetGroupMemberIDsKey(groupID string) string {
return GroupMemberIDsKey + groupID
}
func GetGroupMemberInfoKey(groupID, userID string) string {
return GroupMemberInfoKey + groupID + "-" + userID
}
func GetGroupMemberNumKey(groupID string) string {
return GroupMemberNumKey + groupID
}
func GetGroupRoleLevelMemberIDsKey(groupID string, roleLevel int32) string {
return GroupRoleLevelMemberIDsKey + groupID + "-" + strconv.Itoa(int(roleLevel))
}

View File

@@ -1,14 +0,0 @@
package cachekey
const (
UserInfoKey = "USER_INFO:"
UserGlobalRecvMsgOptKey = "USER_GLOBAL_RECV_MSG_OPT_KEY:"
)
func GetUserInfoKey(userID string) string {
return UserInfoKey + userID
}
func GetUserGlobalRecvMsgOptKey(userID string) string {
return UserGlobalRecvMsgOptKey + userID
}

View File

@@ -20,7 +20,6 @@ import (
config2 "github.com/openimsdk/open-im-server/v3/pkg/common/config" config2 "github.com/openimsdk/open-im-server/v3/pkg/common/config"
"github.com/spf13/cobra" "github.com/spf13/cobra"
_ "go.uber.org/automaxprocs"
"github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/protocol/constant"
"github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/log"

View File

@@ -16,7 +16,6 @@ package config
import ( import (
"bytes" "bytes"
"time"
"github.com/OpenIMSDK/tools/discoveryregistry" "github.com/OpenIMSDK/tools/discoveryregistry"
"gopkg.in/yaml.v3" "gopkg.in/yaml.v3"
@@ -259,8 +258,6 @@ type configStruct struct {
FriendVerify *bool `yaml:"friendVerify"` FriendVerify *bool `yaml:"friendVerify"`
} `yaml:"messageVerify"` } `yaml:"messageVerify"`
LocalCache localCache `yaml:"localCache"`
IOSPush struct { IOSPush struct {
PushSound string `yaml:"pushSound"` PushSound string `yaml:"pushSound"`
BadgeCount bool `yaml:"badgeCount"` BadgeCount bool `yaml:"badgeCount"`
@@ -373,33 +370,6 @@ type notification struct {
ConversationSetPrivate NotificationConf `yaml:"conversationSetPrivate"` ConversationSetPrivate NotificationConf `yaml:"conversationSetPrivate"`
} }
type LocalCache struct {
Topic string `yaml:"topic"`
SlotNum int `yaml:"slotNum"`
SlotSize int `yaml:"slotSize"`
SuccessExpire int `yaml:"successExpire"` // second
FailedExpire int `yaml:"failedExpire"` // second
}
func (l LocalCache) Failed() time.Duration {
return time.Second * time.Duration(l.FailedExpire)
}
func (l LocalCache) Success() time.Duration {
return time.Second * time.Duration(l.SuccessExpire)
}
func (l LocalCache) Enable() bool {
return l.Topic != "" && l.SlotNum > 0 && l.SlotSize > 0
}
type localCache struct {
User LocalCache `yaml:"user"`
Group LocalCache `yaml:"group"`
Friend LocalCache `yaml:"friend"`
Conversation LocalCache `yaml:"conversation"`
}
func (c *configStruct) GetServiceNames() []string { func (c *configStruct) GetServiceNames() []string {
return []string{ return []string{
c.RpcRegisterName.OpenImUserName, c.RpcRegisterName.OpenImUserName,

View File

@@ -16,8 +16,6 @@ package config
import ( import (
_ "embed" _ "embed"
"fmt"
"gopkg.in/yaml.v3"
"reflect" "reflect"
"testing" "testing"
@@ -117,13 +115,3 @@ func TestInitConfig(t *testing.T) {
}) })
} }
} }
func TestName(t *testing.T) {
Config.LocalCache.Friend.Topic = "friend"
Config.LocalCache.Friend.SlotNum = 500
Config.LocalCache.Friend.SlotSize = 20000
data, _ := yaml.Marshal(&Config)
fmt.Println(string(data))
}

View File

@@ -1 +1 @@
v3.5.0 3.5.1

View File

@@ -16,9 +16,6 @@ package cache
import ( import (
"context" "context"
"github.com/OpenIMSDK/tools/log"
"github.com/openimsdk/open-im-server/v3/pkg/common/cachekey"
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
"time" "time"
"github.com/dtm-labs/rockscache" "github.com/dtm-labs/rockscache"
@@ -55,15 +52,11 @@ func NewBlackCacheRedis(
options rockscache.Options, options rockscache.Options,
) BlackCache { ) BlackCache {
rcClient := rockscache.NewClient(rdb, options) rcClient := rockscache.NewClient(rdb, options)
mc := NewMetaCacheRedis(rcClient)
b := config.Config.LocalCache.Friend
log.ZDebug(context.Background(), "black local cache init", "Topic", b.Topic, "SlotNum", b.SlotNum, "SlotSize", b.SlotSize, "enable", b.Enable())
mc.SetTopic(b.Topic)
mc.SetRawRedisClient(rdb)
return &BlackCacheRedis{ return &BlackCacheRedis{
expireTime: blackExpireTime, expireTime: blackExpireTime,
rcClient: rcClient, rcClient: rcClient,
metaCache: mc, metaCache: NewMetaCacheRedis(rcClient),
blackDB: blackDB, blackDB: blackDB,
} }
} }
@@ -73,12 +66,12 @@ func (b *BlackCacheRedis) NewCache() BlackCache {
expireTime: b.expireTime, expireTime: b.expireTime,
rcClient: b.rcClient, rcClient: b.rcClient,
blackDB: b.blackDB, blackDB: b.blackDB,
metaCache: b.Copy(), metaCache: NewMetaCacheRedis(b.rcClient, b.metaCache.GetPreDelKeys()...),
} }
} }
func (b *BlackCacheRedis) getBlackIDsKey(ownerUserID string) string { func (b *BlackCacheRedis) getBlackIDsKey(ownerUserID string) string {
return cachekey.GetBlackIDsKey(ownerUserID) return blackIDsKey + ownerUserID
} }
func (b *BlackCacheRedis) GetBlackIDs(ctx context.Context, userID string) (blackIDs []string, err error) { func (b *BlackCacheRedis) GetBlackIDs(ctx context.Context, userID string) (blackIDs []string, err error) {

View File

@@ -1,66 +0,0 @@
package cache
import (
"github.com/openimsdk/open-im-server/v3/pkg/common/cachekey"
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
"strings"
"sync"
)
var (
once sync.Once
subscribe map[string][]string
)
func getPublishKey(topic string, key []string) []string {
if topic == "" || len(key) == 0 {
return nil
}
once.Do(func() {
list := []struct {
Local config.LocalCache
Keys []string
}{
{
Local: config.Config.LocalCache.User,
Keys: []string{cachekey.UserInfoKey, cachekey.UserGlobalRecvMsgOptKey},
},
{
Local: config.Config.LocalCache.Group,
Keys: []string{cachekey.GroupMemberIDsKey, cachekey.GroupInfoKey, cachekey.GroupMemberInfoKey},
},
{
Local: config.Config.LocalCache.Friend,
Keys: []string{cachekey.FriendIDsKey, cachekey.BlackIDsKey},
},
{
Local: config.Config.LocalCache.Conversation,
Keys: []string{cachekey.ConversationIDsKey, cachekey.ConversationKey},
},
}
subscribe = make(map[string][]string)
for _, v := range list {
if v.Local.Enable() {
subscribe[v.Local.Topic] = v.Keys
}
}
})
prefix, ok := subscribe[topic]
if !ok {
return nil
}
res := make([]string, 0, len(key))
for _, k := range key {
var exist bool
for _, p := range prefix {
if strings.HasPrefix(k, p) {
exist = true
break
}
}
if exist {
res = append(res, k)
}
}
return res
}

View File

@@ -17,9 +17,6 @@ package cache
import ( import (
"context" "context"
"errors" "errors"
"github.com/OpenIMSDK/tools/log"
"github.com/openimsdk/open-im-server/v3/pkg/common/cachekey"
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
"math/big" "math/big"
"strings" "strings"
"time" "time"
@@ -33,14 +30,14 @@ import (
) )
const ( const (
//conversationKey = "CONVERSATION:" conversationKey = "CONVERSATION:"
//conversationIDsKey = "CONVERSATION_IDS:" conversationIDsKey = "CONVERSATION_IDS:"
//conversationIDsHashKey = "CONVERSATION_IDS_HASH:" conversationIDsHashKey = "CONVERSATION_IDS_HASH:"
//conversationHasReadSeqKey = "CONVERSATION_HAS_READ_SEQ:" conversationHasReadSeqKey = "CONVERSATION_HAS_READ_SEQ:"
//recvMsgOptKey = "RECV_MSG_OPT:" recvMsgOptKey = "RECV_MSG_OPT:"
//superGroupRecvMsgNotNotifyUserIDsKey = "SUPER_GROUP_RECV_MSG_NOT_NOTIFY_USER_IDS:" superGroupRecvMsgNotNotifyUserIDsKey = "SUPER_GROUP_RECV_MSG_NOT_NOTIFY_USER_IDS:"
//superGroupRecvMsgNotNotifyUserIDsHashKey = "SUPER_GROUP_RECV_MSG_NOT_NOTIFY_USER_IDS_HASH:" superGroupRecvMsgNotNotifyUserIDsHashKey = "SUPER_GROUP_RECV_MSG_NOT_NOTIFY_USER_IDS_HASH:"
//conversationNotReceiveMessageUserIDsKey = "CONVERSATION_NOT_RECEIVE_MESSAGE_USER_IDS:" conversationNotReceiveMessageUserIDsKey = "CONVERSATION_NOT_RECEIVE_MESSAGE_USER_IDS:"
conversationExpireTime = time.Second * 60 * 60 * 12 conversationExpireTime = time.Second * 60 * 60 * 12
) )
@@ -87,14 +84,10 @@ type ConversationCache interface {
func NewConversationRedis(rdb redis.UniversalClient, opts rockscache.Options, db relationtb.ConversationModelInterface) ConversationCache { func NewConversationRedis(rdb redis.UniversalClient, opts rockscache.Options, db relationtb.ConversationModelInterface) ConversationCache {
rcClient := rockscache.NewClient(rdb, opts) rcClient := rockscache.NewClient(rdb, opts)
mc := NewMetaCacheRedis(rcClient)
c := config.Config.LocalCache.Conversation
log.ZDebug(context.Background(), "black local cache init", "Topic", c.Topic, "SlotNum", c.SlotNum, "SlotSize", c.SlotSize, "enable", c.Enable())
mc.SetTopic(c.Topic)
mc.SetRawRedisClient(rdb)
return &ConversationRedisCache{ return &ConversationRedisCache{
rcClient: rcClient, rcClient: rcClient,
metaCache: mc, metaCache: NewMetaCacheRedis(rcClient),
conversationDB: db, conversationDB: db,
expireTime: conversationExpireTime, expireTime: conversationExpireTime,
} }
@@ -125,42 +118,38 @@ type ConversationRedisCache struct {
func (c *ConversationRedisCache) NewCache() ConversationCache { func (c *ConversationRedisCache) NewCache() ConversationCache {
return &ConversationRedisCache{ return &ConversationRedisCache{
rcClient: c.rcClient, rcClient: c.rcClient,
metaCache: c.Copy(), metaCache: NewMetaCacheRedis(c.rcClient, c.metaCache.GetPreDelKeys()...),
conversationDB: c.conversationDB, conversationDB: c.conversationDB,
expireTime: c.expireTime, expireTime: c.expireTime,
} }
} }
func (c *ConversationRedisCache) getConversationKey(ownerUserID, conversationID string) string { func (c *ConversationRedisCache) getConversationKey(ownerUserID, conversationID string) string {
return cachekey.GetConversationKey(ownerUserID, conversationID) return conversationKey + ownerUserID + ":" + conversationID
} }
func (c *ConversationRedisCache) getConversationIDsKey(ownerUserID string) string { func (c *ConversationRedisCache) getConversationIDsKey(ownerUserID string) string {
return cachekey.GetConversationIDsKey(ownerUserID) return conversationIDsKey + ownerUserID
} }
func (c *ConversationRedisCache) getSuperGroupRecvNotNotifyUserIDsKey(groupID string) string { func (c *ConversationRedisCache) getSuperGroupRecvNotNotifyUserIDsKey(groupID string) string {
return cachekey.GetSuperGroupRecvNotNotifyUserIDsKey(groupID) return superGroupRecvMsgNotNotifyUserIDsKey + groupID
} }
func (c *ConversationRedisCache) getRecvMsgOptKey(ownerUserID, conversationID string) string { func (c *ConversationRedisCache) getRecvMsgOptKey(ownerUserID, conversationID string) string {
return cachekey.GetRecvMsgOptKey(ownerUserID, conversationID) return recvMsgOptKey + ownerUserID + ":" + conversationID
} }
func (c *ConversationRedisCache) getSuperGroupRecvNotNotifyUserIDsHashKey(groupID string) string { func (c *ConversationRedisCache) getSuperGroupRecvNotNotifyUserIDsHashKey(groupID string) string {
return cachekey.GetSuperGroupRecvNotNotifyUserIDsHashKey(groupID) return superGroupRecvMsgNotNotifyUserIDsHashKey + groupID
} }
func (c *ConversationRedisCache) getConversationHasReadSeqKey(ownerUserID, conversationID string) string { func (c *ConversationRedisCache) getConversationHasReadSeqKey(ownerUserID, conversationID string) string {
return cachekey.GetConversationHasReadSeqKey(ownerUserID, conversationID) return conversationHasReadSeqKey + ownerUserID + ":" + conversationID
} }
func (c *ConversationRedisCache) getConversationNotReceiveMessageUserIDsKey(conversationID string) string { func (c *ConversationRedisCache) getConversationNotReceiveMessageUserIDsKey(conversationID string) string {
return cachekey.GetConversationNotReceiveMessageUserIDsKey(conversationID) return conversationNotReceiveMessageUserIDsKey + conversationID
}
func (c *ConversationRedisCache) getUserConversationIDsHashKey(ownerUserID string) string {
return cachekey.GetUserConversationIDsHashKey(ownerUserID)
} }
func (c *ConversationRedisCache) GetUserConversationIDs(ctx context.Context, ownerUserID string) ([]string, error) { func (c *ConversationRedisCache) GetUserConversationIDs(ctx context.Context, ownerUserID string) ([]string, error) {
@@ -180,6 +169,10 @@ func (c *ConversationRedisCache) DelConversationIDs(userIDs ...string) Conversat
return cache return cache
} }
func (c *ConversationRedisCache) getUserConversationIDsHashKey(ownerUserID string) string {
return conversationIDsHashKey + ownerUserID
}
func (c *ConversationRedisCache) GetUserConversationIDsHash(ctx context.Context, ownerUserID string) (hash uint64, err error) { func (c *ConversationRedisCache) GetUserConversationIDsHash(ctx context.Context, ownerUserID string) (hash uint64, err error) {
return getCache( return getCache(
ctx, ctx,

View File

@@ -16,9 +16,6 @@ package cache
import ( import (
"context" "context"
"github.com/OpenIMSDK/tools/log"
"github.com/openimsdk/open-im-server/v3/pkg/common/cachekey"
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
"time" "time"
"github.com/dtm-labs/rockscache" "github.com/dtm-labs/rockscache"
@@ -30,10 +27,10 @@ import (
) )
const ( const (
friendExpireTime = time.Second * 60 * 60 * 12 friendExpireTime = time.Second * 60 * 60 * 12
//friendIDsKey = "FRIEND_IDS:" friendIDsKey = "FRIEND_IDS:"
//TwoWayFriendsIDsKey = "COMMON_FRIENDS_IDS:" TwoWayFriendsIDsKey = "COMMON_FRIENDS_IDS:"
//friendKey = "FRIEND_INFO:" friendKey = "FRIEND_INFO:"
) )
// FriendCache is an interface for caching friend-related data. // FriendCache is an interface for caching friend-related data.
@@ -63,13 +60,8 @@ type FriendCacheRedis struct {
func NewFriendCacheRedis(rdb redis.UniversalClient, friendDB relationtb.FriendModelInterface, func NewFriendCacheRedis(rdb redis.UniversalClient, friendDB relationtb.FriendModelInterface,
options rockscache.Options) FriendCache { options rockscache.Options) FriendCache {
rcClient := rockscache.NewClient(rdb, options) rcClient := rockscache.NewClient(rdb, options)
mc := NewMetaCacheRedis(rcClient)
f := config.Config.LocalCache.Friend
log.ZDebug(context.Background(), "friend local cache init", "Topic", f.Topic, "SlotNum", f.SlotNum, "SlotSize", f.SlotSize, "enable", f.Enable())
mc.SetTopic(f.Topic)
mc.SetRawRedisClient(rdb)
return &FriendCacheRedis{ return &FriendCacheRedis{
metaCache: mc, metaCache: NewMetaCacheRedis(rcClient),
friendDB: friendDB, friendDB: friendDB,
expireTime: friendExpireTime, expireTime: friendExpireTime,
rcClient: rcClient, rcClient: rcClient,
@@ -80,7 +72,7 @@ func NewFriendCacheRedis(rdb redis.UniversalClient, friendDB relationtb.FriendMo
func (f *FriendCacheRedis) NewCache() FriendCache { func (f *FriendCacheRedis) NewCache() FriendCache {
return &FriendCacheRedis{ return &FriendCacheRedis{
rcClient: f.rcClient, rcClient: f.rcClient,
metaCache: f.Copy(), metaCache: NewMetaCacheRedis(f.rcClient, f.metaCache.GetPreDelKeys()...),
friendDB: f.friendDB, friendDB: f.friendDB,
expireTime: f.expireTime, expireTime: f.expireTime,
} }
@@ -88,17 +80,17 @@ func (f *FriendCacheRedis) NewCache() FriendCache {
// getFriendIDsKey returns the key for storing friend IDs in the cache. // getFriendIDsKey returns the key for storing friend IDs in the cache.
func (f *FriendCacheRedis) getFriendIDsKey(ownerUserID string) string { func (f *FriendCacheRedis) getFriendIDsKey(ownerUserID string) string {
return cachekey.GetFriendIDsKey(ownerUserID) return friendIDsKey + ownerUserID
} }
// getTwoWayFriendsIDsKey returns the key for storing two-way friend IDs in the cache. // getTwoWayFriendsIDsKey returns the key for storing two-way friend IDs in the cache.
func (f *FriendCacheRedis) getTwoWayFriendsIDsKey(ownerUserID string) string { func (f *FriendCacheRedis) getTwoWayFriendsIDsKey(ownerUserID string) string {
return cachekey.GetTwoWayFriendsIDsKey(ownerUserID) return TwoWayFriendsIDsKey + ownerUserID
} }
// getFriendKey returns the key for storing friend info in the cache. // getFriendKey returns the key for storing friend info in the cache.
func (f *FriendCacheRedis) getFriendKey(ownerUserID, friendUserID string) string { func (f *FriendCacheRedis) getFriendKey(ownerUserID, friendUserID string) string {
return cachekey.GetFriendKey(ownerUserID, friendUserID) return friendKey + ownerUserID + "-" + friendUserID
} }
// GetFriendIDs retrieves friend IDs from the cache or the database if not found. // GetFriendIDs retrieves friend IDs from the cache or the database if not found.

View File

@@ -17,8 +17,7 @@ package cache
import ( import (
"context" "context"
"fmt" "fmt"
"github.com/openimsdk/open-im-server/v3/pkg/common/cachekey" "strconv"
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
"time" "time"
"github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/protocol/constant"
@@ -35,14 +34,15 @@ import (
) )
const ( const (
groupExpireTime = time.Second * 60 * 60 * 12 groupExpireTime = time.Second * 60 * 60 * 12
//groupInfoKey = "GROUP_INFO:" groupInfoKey = "GROUP_INFO:"
//groupMemberIDsKey = "GROUP_MEMBER_IDS:" groupMemberIDsKey = "GROUP_MEMBER_IDS:"
//groupMembersHashKey = "GROUP_MEMBERS_HASH2:" groupMembersHashKey = "GROUP_MEMBERS_HASH2:"
//groupMemberInfoKey = "GROUP_MEMBER_INFO:" groupMemberInfoKey = "GROUP_MEMBER_INFO:"
//joinedGroupsKey = "JOIN_GROUPS_KEY:" //groupOwnerInfoKey = "GROUP_OWNER_INFO:".
//groupMemberNumKey = "GROUP_MEMBER_NUM_CACHE:" joinedGroupsKey = "JOIN_GROUPS_KEY:"
//groupRoleLevelMemberIDsKey = "GROUP_ROLE_LEVEL_MEMBER_IDS:" groupMemberNumKey = "GROUP_MEMBER_NUM_CACHE:"
groupRoleLevelMemberIDsKey = "GROUP_ROLE_LEVEL_MEMBER_IDS:"
) )
type GroupHash interface { type GroupHash interface {
@@ -105,16 +105,12 @@ func NewGroupCacheRedis(
opts rockscache.Options, opts rockscache.Options,
) GroupCache { ) GroupCache {
rcClient := rockscache.NewClient(rdb, opts) rcClient := rockscache.NewClient(rdb, opts)
mc := NewMetaCacheRedis(rcClient)
g := config.Config.LocalCache.Group
mc.SetTopic(g.Topic)
log.ZDebug(context.Background(), "group local cache init", "Topic", g.Topic, "SlotNum", g.SlotNum, "SlotSize", g.SlotSize, "enable", g.Enable())
mc.SetRawRedisClient(rdb)
return &GroupCacheRedis{ return &GroupCacheRedis{
rcClient: rcClient, expireTime: groupExpireTime, rcClient: rcClient, expireTime: groupExpireTime,
groupDB: groupDB, groupMemberDB: groupMemberDB, groupRequestDB: groupRequestDB, groupDB: groupDB, groupMemberDB: groupMemberDB, groupRequestDB: groupRequestDB,
groupHash: hashCode, groupHash: hashCode,
metaCache: mc, metaCache: NewMetaCacheRedis(rcClient),
} }
} }
@@ -125,36 +121,36 @@ func (g *GroupCacheRedis) NewCache() GroupCache {
groupDB: g.groupDB, groupDB: g.groupDB,
groupMemberDB: g.groupMemberDB, groupMemberDB: g.groupMemberDB,
groupRequestDB: g.groupRequestDB, groupRequestDB: g.groupRequestDB,
metaCache: g.Copy(), metaCache: NewMetaCacheRedis(g.rcClient, g.metaCache.GetPreDelKeys()...),
} }
} }
func (g *GroupCacheRedis) getGroupInfoKey(groupID string) string { func (g *GroupCacheRedis) getGroupInfoKey(groupID string) string {
return cachekey.GetGroupInfoKey(groupID) return groupInfoKey + groupID
} }
func (g *GroupCacheRedis) getJoinedGroupsKey(userID string) string { func (g *GroupCacheRedis) getJoinedGroupsKey(userID string) string {
return cachekey.GetJoinedGroupsKey(userID) return joinedGroupsKey + userID
} }
func (g *GroupCacheRedis) getGroupMembersHashKey(groupID string) string { func (g *GroupCacheRedis) getGroupMembersHashKey(groupID string) string {
return cachekey.GetGroupMembersHashKey(groupID) return groupMembersHashKey + groupID
} }
func (g *GroupCacheRedis) getGroupMemberIDsKey(groupID string) string { func (g *GroupCacheRedis) getGroupMemberIDsKey(groupID string) string {
return cachekey.GetGroupMemberIDsKey(groupID) return groupMemberIDsKey + groupID
} }
func (g *GroupCacheRedis) getGroupMemberInfoKey(groupID, userID string) string { func (g *GroupCacheRedis) getGroupMemberInfoKey(groupID, userID string) string {
return cachekey.GetGroupMemberInfoKey(groupID, userID) return groupMemberInfoKey + groupID + "-" + userID
} }
func (g *GroupCacheRedis) getGroupMemberNumKey(groupID string) string { func (g *GroupCacheRedis) getGroupMemberNumKey(groupID string) string {
return cachekey.GetGroupMemberNumKey(groupID) return groupMemberNumKey + groupID
} }
func (g *GroupCacheRedis) getGroupRoleLevelMemberIDsKey(groupID string, roleLevel int32) string { func (g *GroupCacheRedis) getGroupRoleLevelMemberIDsKey(groupID string, roleLevel int32) string {
return cachekey.GetGroupRoleLevelMemberIDsKey(groupID, roleLevel) return groupRoleLevelMemberIDsKey + groupID + "-" + strconv.Itoa(int(roleLevel))
} }
func (g *GroupCacheRedis) GetGroupIndex(group *relationtb.GroupModel, keys []string) (int, error) { func (g *GroupCacheRedis) GetGroupIndex(group *relationtb.GroupModel, keys []string) (int, error) {

View File

@@ -49,7 +49,7 @@ func NewRedis() (redis.UniversalClient, error) {
overrideConfigFromEnv() overrideConfigFromEnv()
if len(config.Config.Redis.Address) == 0 { if len(config.Config.Redis.Address) == 0 {
return nil, errors.New("redis address is empty") return nil, errs.Wrap(errors.New("redis address is empty"))
} }
specialerror.AddReplace(redis.Nil, errs.ErrRecordNotFound) specialerror.AddReplace(redis.Nil, errs.ErrRecordNotFound)
var rdb redis.UniversalClient var rdb redis.UniversalClient
@@ -77,9 +77,10 @@ func NewRedis() (redis.UniversalClient, error) {
defer cancel() defer cancel()
err = rdb.Ping(ctx).Err() err = rdb.Ping(ctx).Err()
if err != nil { if err != nil {
return nil, fmt.Errorf("redis ping %w", err) uriFormat := "address:%s, username:%s, password:%s, clusterMode:%t, enablePipeline:%t"
errMsg := fmt.Sprintf(uriFormat, config.Config.Redis.Address, config.Config.Redis.Username, config.Config.Redis.Password, config.Config.Redis.ClusterMode, config.Config.Redis.EnablePipeline)
return nil, errs.Wrap(err, errMsg)
} }
redisClient = rdb redisClient = rdb
return rdb, err return rdb, err
} }

View File

@@ -18,7 +18,6 @@ import (
"context" "context"
"encoding/json" "encoding/json"
"errors" "errors"
"github.com/redis/go-redis/v9"
"time" "time"
"github.com/OpenIMSDK/tools/mw/specialerror" "github.com/OpenIMSDK/tools/mw/specialerror"
@@ -45,9 +44,6 @@ type metaCache interface {
AddKeys(keys ...string) AddKeys(keys ...string)
ClearKeys() ClearKeys()
GetPreDelKeys() []string GetPreDelKeys() []string
SetTopic(topic string)
SetRawRedisClient(cli redis.UniversalClient)
Copy() metaCache
} }
func NewMetaCacheRedis(rcClient *rockscache.Client, keys ...string) metaCache { func NewMetaCacheRedis(rcClient *rockscache.Client, keys ...string) metaCache {
@@ -55,36 +51,10 @@ func NewMetaCacheRedis(rcClient *rockscache.Client, keys ...string) metaCache {
} }
type metaCacheRedis struct { type metaCacheRedis struct {
topic string
rcClient *rockscache.Client rcClient *rockscache.Client
keys []string keys []string
maxRetryTimes int maxRetryTimes int
retryInterval time.Duration retryInterval time.Duration
redisClient redis.UniversalClient
}
func (m *metaCacheRedis) Copy() metaCache {
var keys []string
if len(m.keys) > 0 {
keys = make([]string, 0, len(m.keys)*2)
keys = append(keys, m.keys...)
}
return &metaCacheRedis{
topic: m.topic,
rcClient: m.rcClient,
keys: keys,
maxRetryTimes: m.maxRetryTimes,
retryInterval: m.retryInterval,
redisClient: redisClient,
}
}
func (m *metaCacheRedis) SetTopic(topic string) {
m.topic = topic
}
func (m *metaCacheRedis) SetRawRedisClient(cli redis.UniversalClient) {
m.redisClient = cli
} }
func (m *metaCacheRedis) ExecDel(ctx context.Context, distinct ...bool) error { func (m *metaCacheRedis) ExecDel(ctx context.Context, distinct ...bool) error {
@@ -92,7 +62,7 @@ func (m *metaCacheRedis) ExecDel(ctx context.Context, distinct ...bool) error {
m.keys = utils.Distinct(m.keys) m.keys = utils.Distinct(m.keys)
} }
if len(m.keys) > 0 { if len(m.keys) > 0 {
log.ZDebug(ctx, "delete cache", "topic", m.topic, "keys", m.keys) log.ZDebug(ctx, "delete cache", "keys", m.keys)
for _, key := range m.keys { for _, key := range m.keys {
for i := 0; i < m.maxRetryTimes; i++ { for i := 0; i < m.maxRetryTimes; i++ {
if err := m.rcClient.TagAsDeleted(key); err != nil { if err := m.rcClient.TagAsDeleted(key); err != nil {
@@ -102,18 +72,31 @@ func (m *metaCacheRedis) ExecDel(ctx context.Context, distinct ...bool) error {
} }
break break
} }
}
if pk := getPublishKey(m.topic, m.keys); len(pk) > 0 { //retryTimes := 0
data, err := json.Marshal(pk) //for {
if err != nil { // m.rcClient.TagAsDeleted()
log.ZError(ctx, "keys json marshal failed", err, "topic", m.topic, "keys", pk) // if err := m.rcClient.TagAsDeletedBatch2(ctx, []string{key}); err != nil {
} else { // if retryTimes >= m.maxRetryTimes {
if err := m.redisClient.Publish(ctx, m.topic, string(data)).Err(); err != nil { // err = errs.ErrInternalServer.Wrap(
log.ZError(ctx, "redis publish cache delete error", err, "topic", m.topic, "keys", pk) // fmt.Sprintf(
} // "delete cache error: %v, keys: %v, retry times %d, please check redis server",
} // err,
// key,
// retryTimes,
// ),
// )
// log.ZWarn(ctx, "delete cache failed, please handle keys", err, "keys", key)
// return err
// }
// retryTimes++
// } else {
// break
// }
//}
} }
} }
return nil return nil
} }

View File

@@ -17,7 +17,6 @@ package cache
import ( import (
"context" "context"
"errors" "errors"
"github.com/dtm-labs/rockscache"
"strconv" "strconv"
"time" "time"
@@ -45,12 +44,12 @@ const (
conversationUserMinSeq = "CON_USER_MIN_SEQ:" conversationUserMinSeq = "CON_USER_MIN_SEQ:"
hasReadSeq = "HAS_READ_SEQ:" hasReadSeq = "HAS_READ_SEQ:"
//appleDeviceToken = "DEVICE_TOKEN" appleDeviceToken = "DEVICE_TOKEN"
getuiToken = "GETUI_TOKEN" getuiToken = "GETUI_TOKEN"
getuiTaskID = "GETUI_TASK_ID" getuiTaskID = "GETUI_TASK_ID"
//signalCache = "SIGNAL_CACHE:" signalCache = "SIGNAL_CACHE:"
//signalListCache = "SIGNAL_LIST_CACHE:" signalListCache = "SIGNAL_LIST_CACHE:"
FCM_TOKEN = "FCM_TOKEN:" FCM_TOKEN = "FCM_TOKEN:"
messageCache = "MESSAGE_CACHE:" messageCache = "MESSAGE_CACHE:"
messageDelUserList = "MESSAGE_DEL_USER_LIST:" messageDelUserList = "MESSAGE_DEL_USER_LIST:"
@@ -129,8 +128,7 @@ type MsgModel interface {
} }
func NewMsgCacheModel(client redis.UniversalClient) MsgModel { func NewMsgCacheModel(client redis.UniversalClient) MsgModel {
rcClient := rockscache.NewClient(client, rockscache.NewDefaultOptions()) return &msgCache{rdb: client}
return &msgCache{metaCache: NewMetaCacheRedis(rcClient), rdb: client}
} }
type msgCache struct { type msgCache struct {
@@ -150,10 +148,6 @@ func (c *msgCache) getHasReadSeqKey(conversationID string, userID string) string
return hasReadSeq + userID + ":" + conversationID return hasReadSeq + userID + ":" + conversationID
} }
func (c *msgCache) getConversationUserMinSeqKey(conversationID, userID string) string {
return conversationUserMinSeq + conversationID + "u:" + userID
}
func (c *msgCache) setSeq(ctx context.Context, conversationID string, seq int64, getkey func(conversationID string) string) error { func (c *msgCache) setSeq(ctx context.Context, conversationID string, seq int64, getkey func(conversationID string) string) error {
return utils.Wrap1(c.rdb.Set(ctx, getkey(conversationID), seq, 0).Err()) return utils.Wrap1(c.rdb.Set(ctx, getkey(conversationID), seq, 0).Err())
} }
@@ -215,6 +209,10 @@ func (c *msgCache) GetMinSeq(ctx context.Context, conversationID string) (int64,
return c.getSeq(ctx, conversationID, c.getMinSeqKey) return c.getSeq(ctx, conversationID, c.getMinSeqKey)
} }
func (c *msgCache) getConversationUserMinSeqKey(conversationID, userID string) string {
return conversationUserMinSeq + conversationID + "u:" + userID
}
func (c *msgCache) GetConversationUserMinSeq(ctx context.Context, conversationID string, userID string) (int64, error) { func (c *msgCache) GetConversationUserMinSeq(ctx context.Context, conversationID string, userID string) (int64, error) {
return utils.Wrap2(c.rdb.Get(ctx, c.getConversationUserMinSeqKey(conversationID, userID)).Int64()) return utils.Wrap2(c.rdb.Get(ctx, c.getConversationUserMinSeqKey(conversationID, userID)).Int64())
} }

View File

@@ -18,8 +18,6 @@ import (
"context" "context"
"encoding/json" "encoding/json"
"errors" "errors"
"github.com/openimsdk/open-im-server/v3/pkg/common/cachekey"
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
"hash/crc32" "hash/crc32"
"strconv" "strconv"
"time" "time"
@@ -38,8 +36,8 @@ import (
) )
const ( const (
userExpireTime = time.Second * 60 * 60 * 12 userExpireTime = time.Second * 60 * 60 * 12
//userInfoKey = "USER_INFO:" userInfoKey = "USER_INFO:"
userGlobalRecvMsgOptKey = "USER_GLOBAL_RECV_MSG_OPT_KEY:" userGlobalRecvMsgOptKey = "USER_GLOBAL_RECV_MSG_OPT_KEY:"
olineStatusKey = "ONLINE_STATUS:" olineStatusKey = "ONLINE_STATUS:"
userOlineStatusExpireTime = time.Second * 60 * 60 * 24 userOlineStatusExpireTime = time.Second * 60 * 60 * 24
@@ -74,11 +72,7 @@ func NewUserCacheRedis(
options rockscache.Options, options rockscache.Options,
) UserCache { ) UserCache {
rcClient := rockscache.NewClient(rdb, options) rcClient := rockscache.NewClient(rdb, options)
mc := NewMetaCacheRedis(rcClient)
u := config.Config.LocalCache.User
log.ZDebug(context.Background(), "user local cache init", "Topic", u.Topic, "SlotNum", u.SlotNum, "SlotSize", u.SlotSize, "enable", u.Enable())
mc.SetTopic(u.Topic)
mc.SetRawRedisClient(rdb)
return &UserCacheRedis{ return &UserCacheRedis{
rdb: rdb, rdb: rdb,
metaCache: NewMetaCacheRedis(rcClient), metaCache: NewMetaCacheRedis(rcClient),
@@ -91,7 +85,7 @@ func NewUserCacheRedis(
func (u *UserCacheRedis) NewCache() UserCache { func (u *UserCacheRedis) NewCache() UserCache {
return &UserCacheRedis{ return &UserCacheRedis{
rdb: u.rdb, rdb: u.rdb,
metaCache: u.Copy(), metaCache: NewMetaCacheRedis(u.rcClient, u.metaCache.GetPreDelKeys()...),
userDB: u.userDB, userDB: u.userDB,
expireTime: u.expireTime, expireTime: u.expireTime,
rcClient: u.rcClient, rcClient: u.rcClient,
@@ -99,17 +93,18 @@ func (u *UserCacheRedis) NewCache() UserCache {
} }
func (u *UserCacheRedis) getUserInfoKey(userID string) string { func (u *UserCacheRedis) getUserInfoKey(userID string) string {
return cachekey.GetUserInfoKey(userID) return userInfoKey + userID
} }
func (u *UserCacheRedis) getUserGlobalRecvMsgOptKey(userID string) string { func (u *UserCacheRedis) getUserGlobalRecvMsgOptKey(userID string) string {
return cachekey.GetUserGlobalRecvMsgOptKey(userID) return userGlobalRecvMsgOptKey + userID
} }
func (u *UserCacheRedis) GetUserInfo(ctx context.Context, userID string) (userInfo *relationtb.UserModel, err error) { func (u *UserCacheRedis) GetUserInfo(ctx context.Context, userID string) (userInfo *relationtb.UserModel, err error) {
return getCache(ctx, u.rcClient, u.getUserInfoKey(userID), u.expireTime, func(ctx context.Context) (*relationtb.UserModel, error) { return getCache(ctx, u.rcClient, u.getUserInfoKey(userID), u.expireTime, func(ctx context.Context) (*relationtb.UserModel, error) {
return u.userDB.Take(ctx, userID) return u.userDB.Take(ctx, userID)
}) },
)
} }
func (u *UserCacheRedis) GetUsersInfo(ctx context.Context, userIDs []string) ([]*relationtb.UserModel, error) { func (u *UserCacheRedis) GetUsersInfo(ctx context.Context, userIDs []string) ([]*relationtb.UserModel, error) {

View File

@@ -126,21 +126,32 @@ type CommonMsgDatabase interface {
ConvertMsgsDocLen(ctx context.Context, conversationIDs []string) ConvertMsgsDocLen(ctx context.Context, conversationIDs []string)
} }
func NewCommonMsgDatabase(msgDocModel unrelationtb.MsgDocModelInterface, cacheModel cache.MsgModel) CommonMsgDatabase { func NewCommonMsgDatabase(msgDocModel unrelationtb.MsgDocModelInterface, cacheModel cache.MsgModel) (CommonMsgDatabase, error) {
producerToRedis, err := kafka.NewKafkaProducer(config.Config.Kafka.Addr, config.Config.Kafka.LatestMsgToRedis.Topic)
if err != nil {
return nil, err
}
producerToMongo, err := kafka.NewKafkaProducer(config.Config.Kafka.Addr, config.Config.Kafka.MsgToMongo.Topic)
if err != nil {
return nil, err
}
producerToPush, err := kafka.NewKafkaProducer(config.Config.Kafka.Addr, config.Config.Kafka.MsgToPush.Topic)
if err != nil {
return nil, err
}
return &commonMsgDatabase{ return &commonMsgDatabase{
msgDocDatabase: msgDocModel, msgDocDatabase: msgDocModel,
cache: cacheModel, cache: cacheModel,
producer: kafka.NewKafkaProducer(config.Config.Kafka.Addr, config.Config.Kafka.LatestMsgToRedis.Topic), producer: producerToRedis,
producerToMongo: kafka.NewKafkaProducer(config.Config.Kafka.Addr, config.Config.Kafka.MsgToMongo.Topic), producerToMongo: producerToMongo,
producerToPush: kafka.NewKafkaProducer(config.Config.Kafka.Addr, config.Config.Kafka.MsgToPush.Topic), producerToPush: producerToPush,
} }, nil
} }
func InitCommonMsgDatabase(rdb redis.UniversalClient, database *mongo.Database) CommonMsgDatabase { func InitCommonMsgDatabase(rdb redis.UniversalClient, database *mongo.Database) (CommonMsgDatabase, error) {
cacheModel := cache.NewMsgCacheModel(rdb) cacheModel := cache.NewMsgCacheModel(rdb)
msgDocModel := unrelation.NewMsgMongoDriver(database) msgDocModel := unrelation.NewMsgMongoDriver(database)
CommonMsgDatabase := NewCommonMsgDatabase(msgDocModel, cacheModel) return NewCommonMsgDatabase(msgDocModel, cacheModel)
return CommonMsgDatabase
} }
type commonMsgDatabase struct { type commonMsgDatabase struct {

View File

@@ -0,0 +1,87 @@
// 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 localcache
import (
"context"
"sync"
"github.com/OpenIMSDK/protocol/conversation"
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
)
type ConversationLocalCache struct {
lock sync.Mutex
superGroupRecvMsgNotNotifyUserIDs map[string]Hash
conversationIDs map[string]Hash
client *rpcclient.ConversationRpcClient
}
type Hash struct {
hash uint64
ids []string
}
func NewConversationLocalCache(client *rpcclient.ConversationRpcClient) *ConversationLocalCache {
return &ConversationLocalCache{
superGroupRecvMsgNotNotifyUserIDs: make(map[string]Hash),
conversationIDs: make(map[string]Hash),
client: client,
}
}
func (g *ConversationLocalCache) GetRecvMsgNotNotifyUserIDs(ctx context.Context, groupID string) ([]string, error) {
resp, err := g.client.Client.GetRecvMsgNotNotifyUserIDs(ctx, &conversation.GetRecvMsgNotNotifyUserIDsReq{
GroupID: groupID,
})
if err != nil {
return nil, err
}
return resp.UserIDs, nil
}
func (g *ConversationLocalCache) GetConversationIDs(ctx context.Context, userID string) ([]string, error) {
resp, err := g.client.Client.GetUserConversationIDsHash(ctx, &conversation.GetUserConversationIDsHashReq{
OwnerUserID: userID,
})
if err != nil {
return nil, err
}
g.lock.Lock()
hash, ok := g.conversationIDs[userID]
g.lock.Unlock()
if !ok || hash.hash != resp.Hash {
conversationIDsResp, err := g.client.Client.GetConversationIDs(ctx, &conversation.GetConversationIDsReq{
UserID: userID,
})
if err != nil {
return nil, err
}
g.lock.Lock()
defer g.lock.Unlock()
g.conversationIDs[userID] = Hash{
hash: resp.Hash,
ids: conversationIDsResp.ConversationIDs,
}
return conversationIDsResp.ConversationIDs, nil
}
return hash.ids, nil
}

View File

@@ -0,0 +1,15 @@
// 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 localcache // import "github.com/openimsdk/open-im-server/v3/pkg/common/db/localcache"

View File

@@ -0,0 +1,78 @@
// 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 localcache
import (
"context"
"sync"
"github.com/OpenIMSDK/protocol/group"
"github.com/OpenIMSDK/tools/errs"
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
)
type GroupLocalCache struct {
lock sync.Mutex
cache map[string]GroupMemberIDsHash
client *rpcclient.GroupRpcClient
}
type GroupMemberIDsHash struct {
memberListHash uint64
userIDs []string
}
func NewGroupLocalCache(client *rpcclient.GroupRpcClient) *GroupLocalCache {
return &GroupLocalCache{
cache: make(map[string]GroupMemberIDsHash, 0),
client: client,
}
}
func (g *GroupLocalCache) GetGroupMemberIDs(ctx context.Context, groupID string) ([]string, error) {
resp, err := g.client.Client.GetGroupAbstractInfo(ctx, &group.GetGroupAbstractInfoReq{
GroupIDs: []string{groupID},
})
if err != nil {
return nil, err
}
if len(resp.GroupAbstractInfos) < 1 {
return nil, errs.ErrGroupIDNotFound
}
g.lock.Lock()
localHashInfo, ok := g.cache[groupID]
if ok && localHashInfo.memberListHash == resp.GroupAbstractInfos[0].GroupMemberListHash {
g.lock.Unlock()
return localHashInfo.userIDs, nil
}
g.lock.Unlock()
groupMembersResp, err := g.client.Client.GetGroupMemberUserIDs(ctx, &group.GetGroupMemberUserIDsReq{
GroupID: groupID,
})
if err != nil {
return nil, err
}
g.lock.Lock()
defer g.lock.Unlock()
g.cache[groupID] = GroupMemberIDsHash{
memberListHash: resp.GroupAbstractInfos[0].GroupMemberListHash,
userIDs: groupMembersResp.UserIDs,
}
return g.cache[groupID].userIDs, nil
}

View File

@@ -0,0 +1,15 @@
// 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 localcache

View File

@@ -18,6 +18,8 @@ import (
"context" "context"
"time" "time"
"github.com/OpenIMSDK/tools/errs"
"github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/protocol/constant"
"github.com/OpenIMSDK/tools/mgoutil" "github.com/OpenIMSDK/tools/mgoutil"
"github.com/OpenIMSDK/tools/pagination" "github.com/OpenIMSDK/tools/pagination"
@@ -38,7 +40,7 @@ func NewConversationMongo(db *mongo.Database) (*ConversationMgo, error) {
Options: options.Index().SetUnique(true), Options: options.Index().SetUnique(true),
}) })
if err != nil { if err != nil {
return nil, err return nil, errs.Wrap(err)
} }
return &ConversationMgo{coll: coll}, nil return &ConversationMgo{coll: coll}, nil
} }
@@ -114,7 +116,8 @@ func (c *ConversationMgo) GetAllConversationIDs(ctx context.Context) ([]string,
func (c *ConversationMgo) GetAllConversationIDsNumber(ctx context.Context) (int64, error) { func (c *ConversationMgo) GetAllConversationIDsNumber(ctx context.Context) (int64, error) {
counts, err := mgoutil.Aggregate[int64](ctx, c.coll, []bson.M{ counts, err := mgoutil.Aggregate[int64](ctx, c.coll, []bson.M{
{"$group": bson.M{"_id": "$conversation_id"}}, {"$group": bson.M{"_id": "$conversation_id"}},
{"$project": bson.M{"_id": 0, "conversation_id": "$_id"}}, {"$group": bson.M{"_id": nil, "count": bson.M{"$sum": 1}}},
{"$project": bson.M{"_id": 0}},
}) })
if err != nil { if err != nil {
return 0, err return 0, err

View File

@@ -18,6 +18,8 @@ import (
"context" "context"
"time" "time"
"github.com/OpenIMSDK/tools/errs"
"github.com/OpenIMSDK/tools/mgoutil" "github.com/OpenIMSDK/tools/mgoutil"
"github.com/OpenIMSDK/tools/pagination" "github.com/OpenIMSDK/tools/pagination"
"go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson"
@@ -36,7 +38,7 @@ func NewGroupMongo(db *mongo.Database) (relation.GroupModelInterface, error) {
Options: options.Index().SetUnique(true), Options: options.Index().SetUnique(true),
}) })
if err != nil { if err != nil {
return nil, err return nil, errs.Wrap(err)
} }
return &GroupMgo{coll: coll}, nil return &GroupMgo{coll: coll}, nil
} }

View File

@@ -17,6 +17,8 @@ package mgo
import ( import (
"context" "context"
"github.com/OpenIMSDK/tools/errs"
"github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/protocol/constant"
"github.com/OpenIMSDK/tools/mgoutil" "github.com/OpenIMSDK/tools/mgoutil"
"github.com/OpenIMSDK/tools/pagination" "github.com/OpenIMSDK/tools/pagination"
@@ -37,7 +39,7 @@ func NewGroupMember(db *mongo.Database) (relation.GroupMemberModelInterface, err
Options: options.Index().SetUnique(true), Options: options.Index().SetUnique(true),
}) })
if err != nil { if err != nil {
return nil, err return nil, errs.Wrap(err)
} }
return &GroupMemberMgo{coll: coll}, nil return &GroupMemberMgo{coll: coll}, nil
} }

View File

@@ -17,6 +17,8 @@ package mgo
import ( import (
"context" "context"
"github.com/OpenIMSDK/tools/errs"
"github.com/OpenIMSDK/tools/mgoutil" "github.com/OpenIMSDK/tools/mgoutil"
"github.com/OpenIMSDK/tools/pagination" "github.com/OpenIMSDK/tools/pagination"
"go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson"
@@ -36,7 +38,7 @@ func NewGroupRequestMgo(db *mongo.Database) (relation.GroupRequestModelInterface
Options: options.Index().SetUnique(true), Options: options.Index().SetUnique(true),
}) })
if err != nil { if err != nil {
return nil, err return nil, errs.Wrap(err)
} }
return &GroupRequestMgo{coll: coll}, nil return &GroupRequestMgo{coll: coll}, nil
} }

View File

@@ -40,7 +40,7 @@ func NewUserMongo(db *mongo.Database) (relation.UserModelInterface, error) {
Options: options.Index().SetUnique(true), Options: options.Index().SetUnique(true),
}) })
if err != nil { if err != nil {
return nil, err return nil, errs.Wrap(err)
} }
return &UserMgo{coll: coll}, nil return &UserMgo{coll: coll}, nil
} }

View File

@@ -27,7 +27,6 @@ import (
"github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/errs"
"github.com/OpenIMSDK/tools/mw/specialerror" "github.com/OpenIMSDK/tools/mw/specialerror"
"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/table/unrelation" "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/unrelation"
@@ -56,16 +55,17 @@ func NewMongo() (*Mongo, error) {
defer cancel() defer cancel()
mongoClient, err = mongo.Connect(ctx, options.Client().ApplyURI(uri)) mongoClient, err = mongo.Connect(ctx, options.Client().ApplyURI(uri))
if err == nil { if err == nil {
if err = mongoClient.Ping(ctx, nil); err != nil {
return nil, errs.Wrap(err, uri)
}
return &Mongo{db: mongoClient}, nil return &Mongo{db: mongoClient}, nil
} }
if shouldRetry(err) { if shouldRetry(err) {
fmt.Printf("Failed to connect to MongoDB, retrying: %s\n", err)
time.Sleep(time.Second) // exponential backoff could be implemented here time.Sleep(time.Second) // exponential backoff could be implemented here
continue continue
} }
return nil, err
} }
return nil, err return nil, errs.Wrap(err, uri)
} }
func buildMongoURI() string { func buildMongoURI() string {
@@ -150,7 +150,7 @@ func (m *Mongo) createMongoIndex(collection string, isUnique bool, keys ...strin
_, err := indexView.CreateOne(context.Background(), index, opts) _, err := indexView.CreateOne(context.Background(), index, opts)
if err != nil { if err != nil {
return utils.Wrap(err, "CreateIndex") return errs.Wrap(err, "CreateIndex")
} }
return nil return nil
} }

View File

@@ -1,11 +1,26 @@
// Copyright © 2024 OpenIM. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package direct package direct
import ( import (
"context" "context"
"github.com/OpenIMSDK/tools/log"
"google.golang.org/grpc/resolver"
"math/rand" "math/rand"
"strings" "strings"
"github.com/OpenIMSDK/tools/log"
"google.golang.org/grpc/resolver"
) )
const ( const (

View File

@@ -1,13 +1,29 @@
// Copyright © 2024 OpenIM. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package direct package direct
import ( import (
"context" "context"
"errors" "errors"
"fmt" "fmt"
"github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/errs"
config2 "github.com/openimsdk/open-im-server/v3/pkg/common/config"
"google.golang.org/grpc" "google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure" "google.golang.org/grpc/credentials/insecure"
config2 "github.com/openimsdk/open-im-server/v3/pkg/common/config"
) )
type ServiceAddresses map[string][]int type ServiceAddresses map[string][]int

View File

@@ -16,9 +16,10 @@ package discoveryregister
import ( import (
"errors" "errors"
"github.com/openimsdk/open-im-server/v3/pkg/common/discoveryregister/direct"
"os" "os"
"github.com/openimsdk/open-im-server/v3/pkg/common/discoveryregister/direct"
"github.com/openimsdk/open-im-server/v3/pkg/common/discoveryregister/kubernetes" "github.com/openimsdk/open-im-server/v3/pkg/common/discoveryregister/kubernetes"
"github.com/openimsdk/open-im-server/v3/pkg/common/discoveryregister/zookeeper" "github.com/openimsdk/open-im-server/v3/pkg/common/discoveryregister/zookeeper"

View File

@@ -15,10 +15,13 @@
package zookeeper package zookeeper
import ( import (
"fmt"
"os" "os"
"strings" "strings"
"time" "time"
"github.com/OpenIMSDK/tools/errs"
"github.com/OpenIMSDK/tools/discoveryregistry" "github.com/OpenIMSDK/tools/discoveryregistry"
openkeeper "github.com/OpenIMSDK/tools/discoveryregistry/zookeeper" openkeeper "github.com/OpenIMSDK/tools/discoveryregistry/zookeeper"
"github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/log"
@@ -33,7 +36,7 @@ func NewZookeeperDiscoveryRegister() (discoveryregistry.SvcDiscoveryRegistry, er
username := getEnv("ZOOKEEPER_USERNAME", config.Config.Zookeeper.Username) username := getEnv("ZOOKEEPER_USERNAME", config.Config.Zookeeper.Username)
password := getEnv("ZOOKEEPER_PASSWORD", config.Config.Zookeeper.Password) password := getEnv("ZOOKEEPER_PASSWORD", config.Config.Zookeeper.Password)
return openkeeper.NewClient( zk, err := openkeeper.NewClient(
zkAddr, zkAddr,
schema, schema,
openkeeper.WithFreq(time.Hour), openkeeper.WithFreq(time.Hour),
@@ -42,6 +45,16 @@ func NewZookeeperDiscoveryRegister() (discoveryregistry.SvcDiscoveryRegistry, er
openkeeper.WithTimeout(10), openkeeper.WithTimeout(10),
openkeeper.WithLogger(log.NewZkLogger()), openkeeper.WithLogger(log.NewZkLogger()),
) )
if err != nil {
uriFormat := "address:%s, username:%s, password:%s, schema:%s."
errInfo := fmt.Sprintf(uriFormat,
config.Config.Zookeeper.ZkAddr,
config.Config.Zookeeper.Username,
config.Config.Zookeeper.Password,
config.Config.Zookeeper.Schema)
return nil, errs.Wrap(err, errInfo)
}
return zk, nil
} }
// getEnv returns the value of an environment variable if it exists, otherwise it returns the fallback value. // getEnv returns the value of an environment variable if it exists, otherwise it returns the fallback value.

View File

@@ -16,6 +16,9 @@ package kafka
import ( import (
"context" "context"
"strings"
"github.com/OpenIMSDK/tools/errs"
"github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/log"
@@ -36,7 +39,7 @@ type MConsumerGroupConfig struct {
IsReturnErr bool IsReturnErr bool
} }
func NewMConsumerGroup(consumerConfig *MConsumerGroupConfig, topics, addrs []string, groupID string) *MConsumerGroup { func NewMConsumerGroup(consumerConfig *MConsumerGroupConfig, topics, addrs []string, groupID string) (*MConsumerGroup, error) {
consumerGroupConfig := sarama.NewConfig() consumerGroupConfig := sarama.NewConfig()
consumerGroupConfig.Version = consumerConfig.KafkaVersion consumerGroupConfig.Version = consumerConfig.KafkaVersion
consumerGroupConfig.Consumer.Offsets.Initial = consumerConfig.OffsetsInitial consumerGroupConfig.Consumer.Offsets.Initial = consumerConfig.OffsetsInitial
@@ -49,26 +52,28 @@ func NewMConsumerGroup(consumerConfig *MConsumerGroupConfig, topics, addrs []str
SetupTLSConfig(consumerGroupConfig) SetupTLSConfig(consumerGroupConfig)
consumerGroup, err := sarama.NewConsumerGroup(addrs, groupID, consumerGroupConfig) consumerGroup, err := sarama.NewConsumerGroup(addrs, groupID, consumerGroupConfig)
if err != nil { if err != nil {
panic(err.Error()) return nil, errs.Wrap(err, strings.Join(topics, ","), strings.Join(addrs, ","), groupID, config.Config.Kafka.Username, config.Config.Kafka.Password)
} }
return &MConsumerGroup{ return &MConsumerGroup{
consumerGroup, consumerGroup,
groupID, groupID,
topics, topics,
} }, nil
} }
func (mc *MConsumerGroup) GetContextFromMsg(cMsg *sarama.ConsumerMessage) context.Context { func (mc *MConsumerGroup) GetContextFromMsg(cMsg *sarama.ConsumerMessage) context.Context {
return GetContextWithMQHeader(cMsg.Headers) return GetContextWithMQHeader(cMsg.Headers)
} }
func (mc *MConsumerGroup) RegisterHandleAndConsumer(handler sarama.ConsumerGroupHandler) { func (mc *MConsumerGroup) RegisterHandleAndConsumer(ctx context.Context, handler sarama.ConsumerGroupHandler) {
log.ZDebug(context.Background(), "register consumer group", "groupID", mc.groupID) log.ZDebug(context.Background(), "register consumer group", "groupID", mc.groupID)
ctx := context.Background()
for { for {
err := mc.ConsumerGroup.Consume(ctx, mc.topics, handler) err := mc.ConsumerGroup.Consume(ctx, mc.topics, handler)
if err != nil { if err != nil {
panic(err.Error()) log.ZWarn(ctx, "consume err", err, "topic", mc.topics, "groupID", mc.groupID)
}
if ctx.Err() != nil {
return
} }
} }
} }

View File

@@ -21,6 +21,8 @@ import (
"strings" "strings"
"time" "time"
"github.com/OpenIMSDK/tools/errs"
"github.com/IBM/sarama" "github.com/IBM/sarama"
"github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/protocol/constant"
"github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/log"
@@ -44,7 +46,7 @@ type Producer struct {
} }
// NewKafkaProducer initializes a new Kafka producer. // NewKafkaProducer initializes a new Kafka producer.
func NewKafkaProducer(addr []string, topic string) *Producer { func NewKafkaProducer(addr []string, topic string) (*Producer, error) {
p := Producer{ p := Producer{
addr: addr, addr: addr,
topic: topic, topic: topic,
@@ -87,17 +89,17 @@ func NewKafkaProducer(addr []string, topic string) *Producer {
for i := 0; i <= maxRetry; i++ { for i := 0; i <= maxRetry; i++ {
p.producer, err = sarama.NewSyncProducer(p.addr, p.config) p.producer, err = sarama.NewSyncProducer(p.addr, p.config)
if err == nil { if err == nil {
return &p return &p, nil
} }
time.Sleep(1 * time.Second) // Wait before retrying time.Sleep(1 * time.Second) // Wait before retrying
} }
// Panic if unable to create producer after retries // Panic if unable to create producer after retries
if err != nil { if err != nil {
panic("Failed to create Kafka producer: " + err.Error()) return nil, errs.Wrap(errors.New("failed to create Kafka producer: " + err.Error()))
} }
return &p return &p, nil
} }
// configureProducerAck configures the producer's acknowledgement level. // configureProducerAck configures the producer's acknowledgement level.

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