Compare commits
85 Commits
cubxxw-pat
...
optimizati
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
24a0479761 | ||
|
|
b2ca1366f8 | ||
|
|
1a14191d66 | ||
|
|
9d313cb308 | ||
|
|
38e11dc678 | ||
|
|
b940bcaafe | ||
|
|
efa74a95a7 | ||
|
|
119a2c2247 | ||
|
|
4266fed44f | ||
|
|
c81e199698 | ||
|
|
9660556f35 | ||
|
|
c7067bc48a | ||
|
|
84f97a72f4 | ||
|
|
5a81a7a560 | ||
|
|
0ee68e57b9 | ||
|
|
59529718bb | ||
|
|
e3d78de887 | ||
|
|
e3ff304394 | ||
|
|
899f1f15a4 | ||
|
|
33094ec532 | ||
|
|
e26a582836 | ||
|
|
77894b104e | ||
|
|
c16f17582a | ||
|
|
445db67568 | ||
|
|
30ef247a59 | ||
|
|
025eb44113 | ||
|
|
af5e191144 | ||
|
|
4a042489bf | ||
|
|
9e4a7d082d | ||
|
|
000f6ce595 | ||
|
|
f53dd855aa | ||
|
|
f1506e40c4 | ||
|
|
b9eb642616 | ||
|
|
1c93f87e95 | ||
|
|
b2eae0999c | ||
|
|
1afdd0bcf7 | ||
|
|
45859d9cab | ||
|
|
d26a1b2090 | ||
|
|
1e81d29e86 | ||
|
|
6e1f96a720 | ||
|
|
656bfef069 | ||
|
|
1db6e3b389 | ||
|
|
32221da613 | ||
|
|
ad5e4e1540 | ||
|
|
c9193302a8 | ||
|
|
640c363eee | ||
|
|
abbb701192 | ||
|
|
b87e366d74 | ||
|
|
3e30e50a09 | ||
|
|
41d2c7be7a | ||
|
|
166d51ab23 | ||
|
|
749eb11830 | ||
|
|
a81bc3fc23 | ||
|
|
9908e2c658 | ||
|
|
45064ae5ca | ||
|
|
1f1ab65375 | ||
|
|
48ff03f854 | ||
|
|
a00d77a705 | ||
|
|
ad979d493d | ||
|
|
f5f2cf4746 | ||
|
|
4c3c4555a3 | ||
|
|
006e4a1e93 | ||
|
|
8ff8861603 | ||
|
|
2d21ab3aeb | ||
|
|
a84ad774f7 | ||
|
|
ee9c9eb97c | ||
|
|
da2c0d11f5 | ||
|
|
7a67beb7a1 | ||
|
|
28292be37d | ||
|
|
1ea5fe04f1 | ||
|
|
c16cd0bf7c | ||
|
|
03e15766ab | ||
|
|
f0e5c587ad | ||
|
|
b0ec48d35d | ||
|
|
8360c72300 | ||
|
|
18ad656087 | ||
|
|
22c00c411e | ||
|
|
f0075265d5 | ||
|
|
86aebfc0bd | ||
|
|
bbb5ef5ccc | ||
|
|
0248fbb47d | ||
|
|
938622b1fe | ||
|
|
3d77c1c8cf | ||
|
|
1ae523dcc2 | ||
|
|
d9921248a7 |
52
.github/workflows/pull-request.yml
vendored
52
.github/workflows/pull-request.yml
vendored
@@ -14,6 +14,12 @@
|
|||||||
|
|
||||||
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 * * *'
|
||||||
@@ -31,18 +37,24 @@ 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 and lint
|
- name: Run go format
|
||||||
run: |
|
run: |
|
||||||
sudo make format
|
sudo make format
|
||||||
echo "Run go format successfully"
|
echo "Run go format successfully"
|
||||||
@@ -60,20 +72,6 @@ jobs:
|
|||||||
echo "Generate all necessary files successfully"
|
echo "Generate all necessary files successfully"
|
||||||
continue-on-error: true
|
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
|
|
||||||
|
|
||||||
- name: Run unit test and get test coverage
|
- name: Run unit test and get test coverage
|
||||||
run: |
|
run: |
|
||||||
make cover
|
make cover
|
||||||
@@ -82,6 +80,7 @@ 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
|
||||||
@@ -91,27 +90,22 @@ 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 <3293172751ysy@gmail.com>
|
author: kubbot <kubbot@3293172751ysy@gmail.com>
|
||||||
committer: kubbot <3293172751ysy@gmail.com>
|
signoff: false
|
||||||
# signoff: false
|
draft: false
|
||||||
# draft: false
|
branch: ''
|
||||||
branch: "asf-auto-updates"
|
|
||||||
assignees: cubxxw
|
assignees: cubxxw
|
||||||
reviewers: cubxxw
|
reviewers: cubxxw
|
||||||
title: "[Auto PR 🤖] Bump League Patch auto PR"
|
delete-branch: true
|
||||||
|
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:
|
This is an automated PR. @ $(date +'%Y%m%d')
|
||||||
|
|
||||||
[](https://github.com/openimsdk/open-im-server/actions/workflows/pull-request.yml)
|
|
||||||
|
|
||||||
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
|
||||||
|
|||||||
@@ -1,33 +0,0 @@
|
|||||||
# 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>
|
|
||||||
209
CONTRIBUTING.md
209
CONTRIBUTING.md
@@ -1,38 +1,6 @@
|
|||||||
# How do I contribute code to OpenIM
|
# Contributing to Open-IM-Server
|
||||||
|
|
||||||
<p align="center">
|
So, you want to hack on Open-IM-Server? Yay!
|
||||||
<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.
|
||||||
|
|
||||||
@@ -44,7 +12,7 @@ This document provides guidelines and best practices to help you contribute effe
|
|||||||
|
|
||||||
## 📇Topics
|
## 📇Topics
|
||||||
|
|
||||||
- [How do I contribute code to OpenIM](#how-do-i-contribute-code-to-openim)
|
- [Contributing to Open-IM-Server](#contributing-to-open-im-server)
|
||||||
- [📇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)
|
||||||
@@ -64,13 +32,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 tHow do I contribute code to OpenIMo 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 to 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.
|
||||||
|
|
||||||
@@ -84,7 +52,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!
|
||||||
@@ -99,8 +67,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.
|
||||||
|
|
||||||
@@ -117,7 +85,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.
|
||||||
@@ -127,27 +95,13 @@ 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. **Initialize Git Hooks with `make init-githooks`**
|
3. **Set Remote** upstream to be `https://github.com/openimsdk/open-im-server.git` using the following two commands:
|
||||||
|
|
||||||
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
|
||||||
@@ -158,18 +112,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.
|
||||||
|
|
||||||
5. Create a new branch for your changes (use a descriptive name, such as `fix-bug-123` or `add-new-feature`).
|
4. 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
|
||||||
```
|
```
|
||||||
@@ -182,8 +136,7 @@ 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
|
||||||
@@ -192,7 +145,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
|
||||||
```
|
```
|
||||||
|
|
||||||
7. **Push your branch** to your forked repository, it is recommended to have only one commit for a PR.
|
6. **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
|
||||||
@@ -224,94 +177,28 @@ 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
|
||||||
```
|
```
|
||||||
|
|
||||||
**Verifying Your Pull Request with `make all` Command**
|
7. **Open a pull request** to `openimsdk/open-im-server:main`
|
||||||
|
|
||||||
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. Here’s 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
|
||||||
|
|
||||||
We divide the problem into security and general problems:
|
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.
|
||||||
|
|
||||||
@@ -319,20 +206,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:**
|
||||||
|
|
||||||
@@ -375,7 +262,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.
|
||||||
|
|
||||||
@@ -424,11 +311,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.
|
||||||
|
|
||||||
@@ -441,20 +328,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:
|
||||||
|
|
||||||
@@ -479,23 +366,17 @@ 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.
|
||||||
|
|||||||
@@ -4,50 +4,28 @@
|
|||||||
</a>
|
</a>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<div align="center">
|
<h3 align="center" style="border-bottom: none">
|
||||||
|
⭐️ Open source Instant Messaging Server ⭐️ <br>
|
||||||
[](https://github.com/openimsdk/open-im-server/stargazers)
|
<h3>
|
||||||
[](https://github.com/openimsdk/open-im-server/network/members)
|
|
||||||
[](https://app.codecov.io/gh/openimsdk/open-im-server)
|
|
||||||
[](https://goreportcard.com/report/github.com/openimsdk/open-im-server)
|
|
||||||
[](https://pkg.go.dev/github.com/openimsdk/open-im-server/v3)
|
|
||||||
[](https://github.com/openimsdk/open-im-server/blob/main/LICENSE)
|
|
||||||
[](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q)
|
|
||||||
[](https://www.bestpractices.dev/projects/8045)
|
|
||||||
[](https://github.com/openimsdk/open-im-server/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc+label%3A%22good+first+issue%22)
|
|
||||||
[](https://golang.org/)
|
|
||||||
|
|
||||||
|
|
||||||
<p align="center">
|
<p align=center>
|
||||||
<a href="./README.md">Englist</a> ·
|
<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="./README-zh_CN.md">中文</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="docs/readme/README-UA.md">Українська</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="docs/readme/README-CS.md">Česky</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&logoColor=white"></a>
|
||||||
<a href="docs/readme/README-HU.md">Magyar</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="docs/readme/README-ES.md">Español</a> ·
|
<a href="https://golang.org/"><img src="https://img.shields.io/badge/Language-Go-blue.svg"></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>
|
||||||
|
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<a href="./README.md"><b> English </b></a> •
|
||||||
|
<a href="./README-zh_CN.md"><b> 简体中文 </b></a> •
|
||||||
|
<a href="https://openim.io/en"><b> Docs </b></a>
|
||||||
|
</p>
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
@@ -61,6 +39,8 @@ OpenIM 是一个专门设计用于在应用程序中集成聊天、音视频通
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
## 🚀 关于 OpenIMSDK
|
## 🚀 关于 OpenIMSDK
|
||||||
|
|||||||
39
README.md
39
README.md
@@ -17,35 +17,9 @@
|
|||||||
[](https://github.com/openimsdk/open-im-server/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc+label%3A%22good+first+issue%22)
|
[](https://github.com/openimsdk/open-im-server/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc+label%3A%22good+first+issue%22)
|
||||||
[](https://golang.org/)
|
[](https://golang.org/)
|
||||||
|
|
||||||
|
[**English**](./README.md) •
|
||||||
<p align="center">
|
[**简体中文**](./README-zh_CN.md) •
|
||||||
<a href="./README.md">Englist</a> ·
|
[**Docs**](https://openim.io/en)
|
||||||
<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>
|
||||||
|
|
||||||
@@ -94,13 +68,6 @@ 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.
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
|
|
||||||
## :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:
|
||||||
|
|||||||
@@ -26,10 +26,9 @@ 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"
|
||||||
@@ -45,43 +44,55 @@ func main() {
|
|||||||
apiCmd.AddPortFlag()
|
apiCmd.AddPortFlag()
|
||||||
apiCmd.AddApi(run)
|
apiCmd.AddApi(run)
|
||||||
if err := apiCmd.Execute(); err != nil {
|
if err := apiCmd.Execute(); err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "\n\nexit -1: \n%+v\n\n", err)
|
log.ZError(context.Background(), "API command execution failed", err)
|
||||||
os.Exit(-1)
|
panic(err.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
||||||
return errs.Wrap(fmt.Errorf(err))
|
log.ZError(context.Background(), err, nil)
|
||||||
|
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 {
|
||||||
return errs.Wrap(err, "register discovery err")
|
log.ZError(context.Background(), "Failed to initialize discovery register", err)
|
||||||
}
|
|
||||||
|
|
||||||
if err = client.CreateRpcRootNodes(config.Config.GetServiceNames()); err != nil {
|
|
||||||
return errs.Wrap(err, "create rpc root nodes error")
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = client.RegisterConf2Registry(constant.OpenIMCommonConfigKey, config.Config.EncodeConfig()); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err = client.CreateRpcRootNodes(config.Config.GetServiceNames()); err != nil {
|
||||||
|
log.ZError(context.Background(), "Failed to create RPC root nodes", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.ZInfo(context.Background(), "api register public config to discov")
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
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 != "" {
|
||||||
@@ -89,11 +100,13 @@ 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)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
@@ -107,6 +120,7 @@ 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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,9 +15,6 @@
|
|||||||
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"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -57,7 +54,6 @@ 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 {
|
||||||
fmt.Fprintf(os.Stderr, "\n\nexit -1: \n%+v\n\n", err)
|
panic(err)
|
||||||
os.Exit(-1)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,9 +15,6 @@
|
|||||||
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"
|
||||||
)
|
)
|
||||||
@@ -25,7 +22,6 @@ 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 {
|
||||||
fmt.Fprintf(os.Stderr, "\n\nexit -1: \n%+v\n\n", err)
|
panic(err.Error())
|
||||||
os.Exit(-1)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,9 +15,6 @@
|
|||||||
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"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -28,7 +25,6 @@ func main() {
|
|||||||
msgGatewayCmd.AddPrometheusPortFlag()
|
msgGatewayCmd.AddPrometheusPortFlag()
|
||||||
|
|
||||||
if err := msgGatewayCmd.Exec(); err != nil {
|
if err := msgGatewayCmd.Exec(); err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "\n\nexit -1: \n%+v\n\n", err)
|
panic(err.Error())
|
||||||
os.Exit(-1)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,9 +15,6 @@
|
|||||||
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"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -26,7 +23,6 @@ func main() {
|
|||||||
msgTransferCmd.AddPrometheusPortFlag()
|
msgTransferCmd.AddPrometheusPortFlag()
|
||||||
msgTransferCmd.AddTransferProgressFlag()
|
msgTransferCmd.AddTransferProgressFlag()
|
||||||
if err := msgTransferCmd.Exec(); err != nil {
|
if err := msgTransferCmd.Exec(); err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "\n\nexit -1: \n%+v\n\n", err)
|
panic(err.Error())
|
||||||
os.Exit(-1)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,9 +15,6 @@
|
|||||||
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"
|
||||||
@@ -31,7 +28,6 @@ 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 {
|
||||||
fmt.Fprintf(os.Stderr, "\n\nexit -1: \n%+v\n\n", err)
|
panic(err.Error())
|
||||||
os.Exit(-1)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,9 +15,6 @@
|
|||||||
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"
|
||||||
@@ -31,7 +28,6 @@ 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 {
|
||||||
fmt.Fprintf(os.Stderr, "\n\nexit -1: \n%+v\n\n", err)
|
panic(err.Error())
|
||||||
os.Exit(-1)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,9 +15,6 @@
|
|||||||
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"
|
||||||
@@ -31,7 +28,6 @@ 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 {
|
||||||
fmt.Fprintf(os.Stderr, "\n\nexit -1: \n%+v\n\n", err)
|
panic(err.Error())
|
||||||
os.Exit(-1)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,9 +15,6 @@
|
|||||||
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"
|
||||||
@@ -31,7 +28,6 @@ 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 {
|
||||||
fmt.Fprintf(os.Stderr, "\n\nexit -1: \n%+v\n\n", err)
|
panic(err.Error())
|
||||||
os.Exit(-1)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,9 +15,6 @@
|
|||||||
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"
|
||||||
@@ -31,7 +28,6 @@ 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 {
|
||||||
fmt.Fprintf(os.Stderr, "\n\nexit -1: \n%+v\n\n", err)
|
panic(err.Error())
|
||||||
os.Exit(-1)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,9 +15,6 @@
|
|||||||
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"
|
||||||
@@ -31,7 +28,6 @@ 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 {
|
||||||
fmt.Fprintf(os.Stderr, "\n\nexit -1: \n%+v\n\n", err)
|
panic(err.Error())
|
||||||
os.Exit(-1)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,9 +15,6 @@
|
|||||||
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"
|
||||||
@@ -31,7 +28,6 @@ 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 {
|
||||||
fmt.Fprintf(os.Stderr, "\n\nexit -1: \n%+v\n\n", err)
|
panic(err.Error())
|
||||||
os.Exit(-1)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,9 +15,6 @@
|
|||||||
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"
|
||||||
@@ -31,7 +28,6 @@ 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 {
|
||||||
fmt.Fprintf(os.Stderr, "\n\nexit -1: \n%+v\n\n", err)
|
panic(err.Error())
|
||||||
os.Exit(-1)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -243,10 +243,9 @@ 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:
|
userID: [ "${MANAGER_USERID_1}", "${MANAGER_USERID_2}", "${MANAGER_USERID_3}" ]
|
||||||
nickname:
|
nickname: [ "${NICKNAME_1}", "${NICKNAME_2}", "${NICKNAME_3}" ]
|
||||||
|
|
||||||
# chatAdmin, use for send notification
|
# chatAdmin, use for send notification
|
||||||
#
|
#
|
||||||
@@ -330,7 +329,7 @@ callback:
|
|||||||
timeout: ${CALLBACK_TIMEOUT}
|
timeout: ${CALLBACK_TIMEOUT}
|
||||||
failedContinue: ${CALLBACK_FAILED_CONTINUE}
|
failedContinue: ${CALLBACK_FAILED_CONTINUE}
|
||||||
afterSendSingleMsg:
|
afterSendSingleMsg:
|
||||||
enable: ${CALLBACK_ENABLE}
|
enable: true
|
||||||
timeout: ${CALLBACK_TIMEOUT}
|
timeout: ${CALLBACK_TIMEOUT}
|
||||||
failedContinue: ${CALLBACK_FAILED_CONTINUE}
|
failedContinue: ${CALLBACK_FAILED_CONTINUE}
|
||||||
beforeSendGroupMsg:
|
beforeSendGroupMsg:
|
||||||
@@ -528,3 +527,39 @@ 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
|
||||||
@@ -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
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ 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
|
||||||
|
|
||||||
|
|||||||
@@ -305,14 +305,13 @@ 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_USERNAME | [User Defined] | OpenIM Username for MongoDB. |
|
| MONGO_OPENIM_PASSWORD | [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
|
||||||
@@ -478,6 +477,12 @@ 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 |
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
|
||||||
|
|
||||||
# OpenIM Offline Deployment Design
|
# OpenIM Offline Deployment Design
|
||||||
|
|
||||||
## 1. Base Images
|
## 1. Base Images
|
||||||
@@ -8,7 +10,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:RELEASE.2024-01-11T07-46-16Z
|
- [ ] minio/minio:latest
|
||||||
|
|
||||||
> [!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
|
||||||
@@ -20,10 +22,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:<version-name>
|
- [ ] ghcr.io/openimsdk/openim-web:latest
|
||||||
- [ ] ghcr.io/openimsdk/openim-admin:<version-name>
|
- [ ] ghcr.io/openimsdk/openim-admin:latest
|
||||||
- [ ] ghcr.io/openimsdk/openim-chat:<version-name>
|
- [ ] ghcr.io/openimsdk/openim-chat:latest
|
||||||
- [ ] ghcr.io/openimsdk/openim-server:<version-name>
|
- [ ] ghcr.io/openimsdk/openim-server:latest
|
||||||
|
|
||||||
|
|
||||||
Monitoring:
|
Monitoring:
|
||||||
@@ -40,9 +42,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 mariadb:10.6
|
docker pull mysql:5.7
|
||||||
docker pull bitnami/zookeeper:3.8
|
docker pull bitnami/zookeeper:3.8
|
||||||
docker pull minio/minio:2024-01-11T07-46-16Z
|
docker pull minio/minio:latest
|
||||||
```
|
```
|
||||||
|
|
||||||
If you need to install more IM components or monitoring products:
|
If you need to install more IM components or monitoring products:
|
||||||
|
|||||||
@@ -1,33 +0,0 @@
|
|||||||
# 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>
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
# 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>
|
|
||||||
BIN
docs/images/Open-IM-Servers-on-System.png
Normal file
BIN
docs/images/Open-IM-Servers-on-System.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 21 KiB |
BIN
docs/images/Open-IM-Servers-on-docker.png
Normal file
BIN
docs/images/Open-IM-Servers-on-docker.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 9.9 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 286 KiB |
BIN
docs/images/build.png
Normal file
BIN
docs/images/build.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 61 KiB |
BIN
docs/images/docker_build.png
Normal file
BIN
docs/images/docker_build.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 57 KiB |
@@ -1,7 +0,0 @@
|
|||||||
<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
21
go.mod
@@ -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.48
|
github.com/OpenIMSDK/protocol v0.0.49
|
||||||
github.com/OpenIMSDK/tools v0.0.33
|
github.com/OpenIMSDK/tools v0.0.28
|
||||||
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,6 +18,7 @@ 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
|
||||||
@@ -31,7 +32,7 @@ require (
|
|||||||
gopkg.in/yaml.v3 v3.0.1
|
gopkg.in/yaml.v3 v3.0.1
|
||||||
)
|
)
|
||||||
|
|
||||||
require github.com/google/uuid v1.5.0
|
require github.com/google/uuid v1.3.1
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/IBM/sarama v1.41.3
|
github.com/IBM/sarama v1.41.3
|
||||||
@@ -41,6 +42,7 @@ 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
|
||||||
@@ -81,6 +83,7 @@ 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
|
||||||
@@ -93,8 +96,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.17.4 // indirect
|
github.com/klauspost/compress v1.16.7 // indirect
|
||||||
github.com/klauspost/cpuid/v2 v2.2.6 // indirect
|
github.com/klauspost/cpuid/v2 v2.2.5 // 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
|
||||||
@@ -126,9 +129,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.11.0 // indirect
|
go.uber.org/multierr v1.6.0 // indirect
|
||||||
golang.org/x/arch v0.3.0 // indirect
|
golang.org/x/arch v0.3.0 // indirect
|
||||||
golang.org/x/net v0.19.0 // indirect
|
golang.org/x/net v0.17.0 // indirect
|
||||||
golang.org/x/oauth2 v0.13.0 // indirect
|
golang.org/x/oauth2 v0.13.0 // indirect
|
||||||
golang.org/x/sys v0.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
|
||||||
@@ -140,7 +143,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.25.4 // indirect
|
gorm.io/gorm v1.23.8 // indirect
|
||||||
stathat.com/c/consistent v1.0.0 // indirect
|
stathat.com/c/consistent v1.0.0 // indirect
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -156,4 +159,4 @@ require (
|
|||||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||||
)
|
)
|
||||||
|
|
||||||
replace github.com/OpenIMSDK/protocol v0.0.47 => github.com/AndrewZuo01/protocol v0.0.0-20240112093520-fd9c53e27b94
|
replace github.com/openimsdk/localcache => ./pkg/localcache
|
||||||
|
|||||||
38
go.sum
38
go.sum
@@ -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.48 h1:8MIMjyzJRsruYhVv2ZKArFiOveroaofDOb3dlAdgjsw=
|
github.com/OpenIMSDK/protocol v0.0.49 h1:wcqJOMBis7f153zNI7V82Fc4WyqA1GanMgXUQgL618k=
|
||||||
github.com/OpenIMSDK/protocol v0.0.48/go.mod h1:F25dFrwrIx3lkNoiuf6FkCfxuwf8L4Z8UIsdTHP/r0Y=
|
github.com/OpenIMSDK/protocol v0.0.49/go.mod h1:F25dFrwrIx3lkNoiuf6FkCfxuwf8L4Z8UIsdTHP/r0Y=
|
||||||
github.com/OpenIMSDK/tools v0.0.33 h1:rvFCxXaXxLv1MJFC4qcoWRGwKBnV+hR68UN2N0/zZhE=
|
github.com/OpenIMSDK/tools v0.0.27 h1:J/kSRqM+y9U4XK/pQ9RkEB31oQ5BTYD1oA5r1PITPRA=
|
||||||
github.com/OpenIMSDK/tools v0.0.33/go.mod h1:wBfR5CYmEyvxl03QJbTkhz1CluK6J4/lX0lviu8JAjE=
|
github.com/OpenIMSDK/tools v0.0.27/go.mod h1:eg+q4A34Qmu73xkY0mt37FHGMCMfC6CtmOnm0kFEGFI=
|
||||||
github.com/QcloudApi/qcloud_sign_golang v0.0.0-20141224014652-e4130a326409/go.mod h1:1pk82RBxDY/JZnPQrtqHlUFfCctgdorsd9M06fMynOM=
|
github.com/QcloudApi/qcloud_sign_golang v0.0.0-20141224014652-e4130a326409/go.mod h1:1pk82RBxDY/JZnPQrtqHlUFfCctgdorsd9M06fMynOM=
|
||||||
github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7 h1:uSoVVbwJiQipAclBbw+8quDsfcvFjOpI5iCf4p/cqCs=
|
github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7 h1:uSoVVbwJiQipAclBbw+8quDsfcvFjOpI5iCf4p/cqCs=
|
||||||
github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs=
|
github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs=
|
||||||
@@ -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.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU=
|
github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4=
|
||||||
github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.3.1/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,6 +171,8 @@ 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=
|
||||||
@@ -194,6 +196,7 @@ 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=
|
||||||
@@ -204,12 +207,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.17.4 h1:Ej5ixsIri7BrIjBkRZLTo6ghwrEtHFk7ijlczPW4fZ4=
|
github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I=
|
||||||
github.com/klauspost/compress v1.17.4/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM=
|
github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
|
||||||
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.6 h1:ndNyv040zDGIDh8thGkXYjnFtiN02M1PVVF+JE/48xc=
|
github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg=
|
||||||
github.com/klauspost/cpuid/v2 v2.2.6/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
|
github.com/klauspost/cpuid/v2 v2.2.5/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=
|
||||||
@@ -277,6 +280,7 @@ 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=
|
||||||
@@ -351,9 +355,11 @@ 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.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4=
|
||||||
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
|
||||||
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=
|
||||||
@@ -398,8 +404,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.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c=
|
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
|
||||||
golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U=
|
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
|
||||||
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=
|
||||||
@@ -527,8 +533,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.25.4 h1:iyNd8fNAe8W9dvtlgeRI5zSVZPsq3OpcTu37cYcpCmw=
|
gorm.io/gorm v1.23.8 h1:h8sGJ+biDgBA1AD1Ha9gFCx7h8npU7AsLdlkX0n2TpE=
|
||||||
gorm.io/gorm v1.25.4/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k=
|
gorm.io/gorm v1.23.8/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk=
|
||||||
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=
|
||||||
|
|||||||
@@ -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.Enable {
|
// if !config.Config.Callback.CallbackUserOnline.WithEnable {
|
||||||
// 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.Enable {
|
// if !config.Config.Callback.CallbackUserOffline.WithEnable {
|
||||||
// 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.Enable {
|
// if !config.Config.Callback.CallbackUserKickOff.WithEnable {
|
||||||
// return callbackResp
|
// return callbackResp
|
||||||
// }
|
// }
|
||||||
// callbackUserKickOffReq := cbApi.CallbackUserKickOffReq{
|
// callbackUserKickOffReq := cbApi.CallbackUserKickOffReq{
|
||||||
|
|||||||
@@ -25,8 +25,6 @@ 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"
|
||||||
@@ -59,7 +57,7 @@ type Server struct {
|
|||||||
rpcPort int
|
rpcPort int
|
||||||
prometheusPort int
|
prometheusPort int
|
||||||
LongConnServer LongConnServer
|
LongConnServer LongConnServer
|
||||||
pushTerminal []int
|
pushTerminal map[int]struct{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) SetLongConnServer(LongConnServer LongConnServer) {
|
func (s *Server) SetLongConnServer(LongConnServer LongConnServer) {
|
||||||
@@ -67,12 +65,15 @@ func (s *Server) SetLongConnServer(LongConnServer LongConnServer) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func NewServer(rpcPort int, proPort int, longConnServer LongConnServer) *Server {
|
func NewServer(rpcPort int, proPort int, longConnServer LongConnServer) *Server {
|
||||||
return &Server{
|
s := &Server{
|
||||||
rpcPort: rpcPort,
|
rpcPort: rpcPort,
|
||||||
prometheusPort: proPort,
|
prometheusPort: proPort,
|
||||||
LongConnServer: longConnServer,
|
LongConnServer: longConnServer,
|
||||||
pushTerminal: []int{constant.IOSPlatformID, constant.AndroidPlatformID},
|
pushTerminal: make(map[int]struct{}),
|
||||||
}
|
}
|
||||||
|
s.pushTerminal[constant.IOSPlatformID] = struct{}{}
|
||||||
|
s.pushTerminal[constant.AndroidPlatformID] = struct{}{}
|
||||||
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) OnlinePushMsg(
|
func (s *Server) OnlinePushMsg(
|
||||||
@@ -126,13 +127,9 @@ func (s *Server) OnlineBatchPushOneMsg(
|
|||||||
panic("implement me")
|
panic("implement me")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) SuperGroupOnlineBatchPushOneMsg(
|
func (s *Server) SuperGroupOnlineBatchPushOneMsg(ctx context.Context, req *msggateway.OnlineBatchPushOneMsgReq,
|
||||||
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{
|
||||||
@@ -153,23 +150,22 @@ func (s *Server) SuperGroupOnlineBatchPushOneMsg(
|
|||||||
}
|
}
|
||||||
|
|
||||||
userPlatform := &msggateway.SingleMsgToUserPlatform{
|
userPlatform := &msggateway.SingleMsgToUserPlatform{
|
||||||
RecvID: v,
|
PlatFormID: int32(client.PlatformID),
|
||||||
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 = -2
|
userPlatform.ResultCode = int64(errs.ErrPushMsgErr.Code())
|
||||||
resp = append(resp, userPlatform)
|
resp = append(resp, userPlatform)
|
||||||
} else {
|
} else {
|
||||||
if utils.IsContainInt(client.PlatformID, s.pushTerminal) {
|
if _, ok := s.pushTerminal[client.PlatformID]; ok {
|
||||||
results.OnlinePush = true
|
results.OnlinePush = true
|
||||||
resp = append(resp, userPlatform)
|
resp = append(resp, userPlatform)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
userPlatform.ResultCode = -3
|
userPlatform.ResultCode = int64(errs.ErrIOSBackgroundPushErr.Code())
|
||||||
resp = append(resp, userPlatform)
|
resp = append(resp, userPlatform)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,15 +15,12 @@
|
|||||||
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"
|
||||||
@@ -72,47 +69,40 @@ 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, err := controller.NewCommonMsgDatabase(msgDocModel, msgModel)
|
msgDatabase := 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, err := NewMsgTransfer(msgDatabase, &conversationRpcClient, &groupRpcClient)
|
msgTransfer := 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, error) {
|
func NewMsgTransfer(msgDatabase controller.CommonMsgDatabase, conversationRpcClient *rpcclient.ConversationRpcClient, groupRpcClient *rpcclient.GroupRpcClient) *MsgTransfer {
|
||||||
historyCH, err := NewOnlineHistoryRedisConsumerHandler(msgDatabase, conversationRpcClient, groupRpcClient)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
historyMongoCH, err := NewOnlineHistoryMongoConsumerHandler(msgDatabase)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &MsgTransfer{
|
return &MsgTransfer{
|
||||||
historyCH: historyCH,
|
historyCH: NewOnlineHistoryRedisConsumerHandler(msgDatabase, conversationRpcClient, groupRpcClient),
|
||||||
historyMongoCH: historyMongoCH,
|
historyMongoCH: NewOnlineHistoryMongoConsumerHandler(msgDatabase),
|
||||||
}, 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 errs.Wrap(errors.New("prometheusPort not correct"))
|
return errors.New("prometheusPort not correct")
|
||||||
}
|
}
|
||||||
|
if config.Config.ChatPersistenceMysql {
|
||||||
go m.historyCH.historyConsumerGroup.RegisterHandleAndConsumer(ctx, m.historyCH)
|
// go m.persistentCH.persistentConsumerGroup.RegisterHandleAndConsumer(m.persistentCH)
|
||||||
go m.historyMongoCH.historyConsumerGroup.RegisterHandleAndConsumer(ctx, m.historyMongoCH)
|
} else {
|
||||||
|
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(
|
||||||
|
|||||||
@@ -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, error) {
|
) *OnlineHistoryRedisConsumerHandler {
|
||||||
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,15 +98,14 @@ func NewOnlineHistoryRedisConsumerHandler(
|
|||||||
}
|
}
|
||||||
och.conversationRpcClient = conversationRpcClient
|
och.conversationRpcClient = conversationRpcClient
|
||||||
och.groupRpcClient = groupRpcClient
|
och.groupRpcClient = groupRpcClient
|
||||||
var err error
|
och.historyConsumerGroup = kafka.NewMConsumerGroup(&kafka.MConsumerGroupConfig{
|
||||||
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, err
|
return &och
|
||||||
}
|
}
|
||||||
|
|
||||||
func (och *OnlineHistoryRedisConsumerHandler) Run(channelID int) {
|
func (och *OnlineHistoryRedisConsumerHandler) Run(channelID int) {
|
||||||
|
|||||||
@@ -34,21 +34,16 @@ type OnlineHistoryMongoConsumerHandler struct {
|
|||||||
msgDatabase controller.CommonMsgDatabase
|
msgDatabase controller.CommonMsgDatabase
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewOnlineHistoryMongoConsumerHandler(database controller.CommonMsgDatabase) (*OnlineHistoryMongoConsumerHandler, error) {
|
func NewOnlineHistoryMongoConsumerHandler(database controller.CommonMsgDatabase) *OnlineHistoryMongoConsumerHandler {
|
||||||
historyConsumerGroup, err := kfk.NewMConsumerGroup(&kfk.MConsumerGroupConfig{
|
|
||||||
KafkaVersion: sarama.V2_0_0_0,
|
|
||||||
OffsetsInitial: sarama.OffsetNewest, IsReturnErr: false,
|
|
||||||
}, []string{config.Config.Kafka.MsgToMongo.Topic},
|
|
||||||
config.Config.Kafka.Addr, config.Config.Kafka.ConsumerGroupID.MsgToMongo)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
mc := &OnlineHistoryMongoConsumerHandler{
|
mc := &OnlineHistoryMongoConsumerHandler{
|
||||||
historyConsumerGroup: historyConsumerGroup,
|
historyConsumerGroup: kfk.NewMConsumerGroup(&kfk.MConsumerGroupConfig{
|
||||||
msgDatabase: database,
|
KafkaVersion: sarama.V2_0_0_0,
|
||||||
|
OffsetsInitial: sarama.OffsetNewest, IsReturnErr: false,
|
||||||
|
}, []string{config.Config.Kafka.MsgToMongo.Topic},
|
||||||
|
config.Config.Kafka.Addr, config.Config.Kafka.ConsumerGroupID.MsgToMongo),
|
||||||
|
msgDatabase: database,
|
||||||
}
|
}
|
||||||
return mc, nil
|
return mc
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mc *OnlineHistoryMongoConsumerHandler) handleChatWs2Mongo(
|
func (mc *OnlineHistoryMongoConsumerHandler) handleChatWs2Mongo(
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ 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"
|
||||||
@@ -136,3 +137,14 @@ 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, ¬ification); err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return notification.Detail
|
||||||
|
} else {
|
||||||
|
return string(msg.Content)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,37 +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 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)
|
|
||||||
}
|
|
||||||
@@ -16,17 +16,16 @@ 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 NewClient() *Dummy {
|
func NewDummy() *Dummy {
|
||||||
return &Dummy{}
|
return &Dummy{}
|
||||||
}
|
}
|
||||||
|
|
||||||
type Dummy struct {
|
type Dummy struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Dummy) Push(ctx context.Context, userIDs []string, title, content string, opts *offlinepush.Opts) error {
|
func (d *Dummy) Push(ctx context.Context, userIDs []string, title, content string, opts *options.Opts) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ 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"
|
||||||
@@ -25,7 +26,6 @@ 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 NewClient(cache cache.MsgModel) *Fcm {
|
func NewFcm(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 NewClient(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 *offlinepush.Opts) error {
|
func (f *Fcm) Push(ctx context.Context, userIDs []string, title, content string, opts *options.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 {
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ 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"
|
||||||
@@ -30,7 +31,6 @@ 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 Client struct {
|
type GeTui struct {
|
||||||
cache cache.MsgModel
|
cache cache.MsgModel
|
||||||
tokenExpireTime int64
|
tokenExpireTime int64
|
||||||
taskIDTTL int64
|
taskIDTTL int64
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewClient(cache cache.MsgModel) *Client {
|
func NewGeTui(cache cache.MsgModel) *GeTui {
|
||||||
return &Client{cache: cache, tokenExpireTime: tokenExpireTime, taskIDTTL: taskIDTTL}
|
return &GeTui{cache: cache, tokenExpireTime: tokenExpireTime, taskIDTTL: taskIDTTL}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *Client) Push(ctx context.Context, userIDs []string, title, content string, opts *offlinepush.Opts) error {
|
func (g *GeTui) Push(ctx context.Context, userIDs []string, title, content string, opts *options.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 *Client) Push(ctx context.Context, userIDs []string, title, content stri
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *Client) Auth(ctx context.Context, timeStamp int64) (token string, expireTime int64, err error) {
|
func (g *GeTui) 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 *Client) Auth(ctx context.Context, timeStamp int64) (token string, expir
|
|||||||
return respAuth.Token, int64(expire), err
|
return respAuth.Token, int64(expire), err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *Client) GetTaskID(ctx context.Context, token string, pushReq PushReq) (string, error) {
|
func (g *GeTui) 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 *Client) GetTaskID(ctx context.Context, token string, pushReq PushReq) (
|
|||||||
}
|
}
|
||||||
|
|
||||||
// max num is 999.
|
// max num is 999.
|
||||||
func (g *Client) batchPush(ctx context.Context, token string, userIDs []string, pushReq PushReq) error {
|
func (g *GeTui) 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 *Client) batchPush(ctx context.Context, token string, userIDs []string,
|
|||||||
return g.request(ctx, batchPushURL, pushReq, token, nil)
|
return g.request(ctx, batchPushURL, pushReq, token, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *Client) singlePush(ctx context.Context, token, userID string, pushReq PushReq) error {
|
func (g *GeTui) 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 *Client) request(ctx context.Context, url string, input any, token string, output any) error {
|
func (g *GeTui) 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 *Client) postReturn(
|
func (g *GeTui) 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 *Client) postReturn(
|
|||||||
return output.parseError()
|
return output.parseError()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *Client) getTokenAndSave2Redis(ctx context.Context) (token string, err error) {
|
func (g *GeTui) 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 *Client) getTokenAndSave2Redis(ctx context.Context) (token string, err e
|
|||||||
return token, nil
|
return token, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *Client) GetTaskIDAndSave2Redis(ctx context.Context, token string, pushReq PushReq) (taskID string, err error) {
|
func (g *GeTui) 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 {
|
||||||
|
|||||||
@@ -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 NewClient() *JPush {
|
func NewJPush() *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 *offlinepush.Opts) error {
|
func (j *JPush) Push(ctx context.Context, userIDs []string, title, content string, opts *options.Opts) error {
|
||||||
var pf body.Platform
|
var pf body.Platform
|
||||||
pf.SetAll()
|
pf.SetAll()
|
||||||
var au body.Audience
|
var au body.Audience
|
||||||
|
|||||||
@@ -1,37 +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"
|
|
||||||
)
|
|
||||||
|
|
||||||
// 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
|
|
||||||
}
|
|
||||||
52
internal/push/offlinepush/offlinepusher.go
Normal file
52
internal/push/offlinepush/offlinepusher.go
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
// 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
|
||||||
|
}
|
||||||
14
internal/push/offlinepush/options/options.go
Normal file
14
internal/push/offlinepush/options/options.go
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
package options
|
||||||
|
|
||||||
|
// Opts opts.
|
||||||
|
type Opts struct {
|
||||||
|
Signal *Signal
|
||||||
|
IOSPushSound string
|
||||||
|
IOSBadgeCount bool
|
||||||
|
Ex string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Signal message id.
|
||||||
|
type Signal struct {
|
||||||
|
ClientMsgID string
|
||||||
|
}
|
||||||
211
internal/push/onlinepusher.go
Normal file
211
internal/push/onlinepusher.go
Normal file
@@ -0,0 +1,211 @@
|
|||||||
|
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
|
||||||
|
}
|
||||||
51
internal/push/push.go
Normal file
51
internal/push/push.go
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
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
|
||||||
|
}
|
||||||
@@ -16,6 +16,17 @@ 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"
|
||||||
@@ -31,23 +42,32 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type ConsumerHandler struct {
|
type ConsumerHandler struct {
|
||||||
pushConsumerGroup *kfk.MConsumerGroup
|
pushConsumerGroup *kfk.MConsumerGroup
|
||||||
pusher *Pusher
|
offlinePusher offlinepush.OfflinePusher
|
||||||
|
onlinePusher OnlinePusher
|
||||||
|
groupLocalCache *rpccache.GroupLocalCache
|
||||||
|
conversationLocalCache *rpccache.ConversationLocalCache
|
||||||
|
msgRpcClient rpcclient.MessageRpcClient
|
||||||
|
conversationRpcClient rpcclient.ConversationRpcClient
|
||||||
|
groupRpcClient rpcclient.GroupRpcClient
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewConsumerHandler(pusher *Pusher) (*ConsumerHandler, error) {
|
func NewConsumerHandler(offlinePusher offlinepush.OfflinePusher,
|
||||||
|
rdb redis.UniversalClient, disCov discoveryregistry.SvcDiscoveryRegistry) *ConsumerHandler {
|
||||||
var consumerHandler ConsumerHandler
|
var consumerHandler ConsumerHandler
|
||||||
consumerHandler.pusher = pusher
|
consumerHandler.pushConsumerGroup = kfk.NewMConsumerGroup(&kfk.MConsumerGroupConfig{
|
||||||
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)
|
||||||
if err != nil {
|
consumerHandler.offlinePusher = offlinePusher
|
||||||
return nil, err
|
consumerHandler.onlinePusher = NewOnlinePusher(disCov)
|
||||||
}
|
consumerHandler.groupRpcClient = rpcclient.NewGroupRpcClient(disCov)
|
||||||
return &consumerHandler, nil
|
consumerHandler.groupLocalCache = rpccache.NewGroupLocalCache(consumerHandler.groupRpcClient, rdb)
|
||||||
|
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) {
|
||||||
@@ -69,7 +89,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.pusher.Push2SuperGroup(ctx, pbData.MsgData.GroupID, pbData.MsgData)
|
err = c.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)
|
||||||
@@ -78,18 +98,14 @@ 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.pusher.Push2User(ctx, pushUserIDList, pbData.MsgData)
|
err = c.Push2User(ctx, pushUserIDList, pbData.MsgData)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == errNoOfflinePusher {
|
log.ZError(ctx, "push failed", err, "msg", pbData.String())
|
||||||
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 {
|
||||||
@@ -100,3 +116,243 @@ 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, ¬ification); 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
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,113 +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 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
|
|
||||||
}
|
|
||||||
@@ -1,522 +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 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, ¬ification); 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
|
|
||||||
}
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
// Copyright © 2023 OpenIM. All rights reserved.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package 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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -16,7 +16,6 @@ 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"
|
||||||
|
|||||||
@@ -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.Conversation.GetConversations(ctx, req.UserID, conversationIDs)
|
conversations, err := m.ConversationLocalCache.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.Conversation.GetConversation(ctx, req.UserID, req.ConversationID)
|
conversation, err := m.ConversationLocalCache.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.Conversation.GetConversation(ctx, req.UserID, req.ConversationID)
|
conversation, err := m.ConversationLocalCache.GetConversation(ctx, req.UserID, req.ConversationID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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.User.GetUserInfo(ctx, req.UserID)
|
user, err := m.UserLocalCache.GetUserInfo(ctx, req.UserID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -73,12 +73,7 @@ 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.Group.GetGroupMemberInfoMap(
|
members, err := m.GroupLocalCache.GetGroupMemberInfoMap(ctx, msgs[0].GroupID, utils.Distinct([]string{req.UserID, msgs[0].SendID}))
|
||||||
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
|
||||||
}
|
}
|
||||||
@@ -111,13 +106,6 @@ 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,
|
||||||
@@ -125,7 +113,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: flag,
|
IsAdminRevoke: utils.Contain(revokerUserID, config.Config.Manager.UserID...),
|
||||||
}
|
}
|
||||||
var recvID string
|
var recvID string
|
||||||
if msgs[0].SessionType == constant.SuperGroupChatType {
|
if msgs[0].SessionType == constant.SuperGroupChatType {
|
||||||
|
|||||||
@@ -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.Group.GetGroupMemberIDs(ctx, msg.GroupID)
|
memberUserIDList, err := m.GroupLocalCache.GetGroupMemberIDs(ctx, msg.GroupID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.ZWarn(ctx, "GetGroupMemberIDs", err)
|
log.ZWarn(ctx, "GetGroupMemberIDs", err)
|
||||||
return
|
return
|
||||||
@@ -144,6 +144,7 @@ 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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ package msg
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"github.com/openimsdk/open-im-server/v3/pkg/rpccache"
|
||||||
|
|
||||||
"google.golang.org/grpc"
|
"google.golang.org/grpc"
|
||||||
|
|
||||||
@@ -26,7 +27,6 @@ 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,12 +36,11 @@ 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
|
||||||
friend *rpcclient.FriendRpcClient
|
UserLocalCache *rpccache.UserLocalCache
|
||||||
GroupLocalCache *localcache.GroupLocalCache
|
FriendLocalCache *rpccache.FriendLocalCache
|
||||||
ConversationLocalCache *localcache.ConversationLocalCache
|
GroupLocalCache *rpccache.GroupLocalCache
|
||||||
|
ConversationLocalCache *rpccache.ConversationLocalCache
|
||||||
Handlers MessageInterceptorChain
|
Handlers MessageInterceptorChain
|
||||||
notificationSender *rpcclient.NotificationSender
|
notificationSender *rpcclient.NotificationSender
|
||||||
}
|
}
|
||||||
@@ -80,19 +79,16 @@ 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, err := controller.NewCommonMsgDatabase(msgDocModel, cacheModel)
|
msgDatabase := 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,
|
||||||
GroupLocalCache: localcache.NewGroupLocalCache(&groupRpcClient),
|
UserLocalCache: rpccache.NewUserLocalCache(userRpcClient, rdb),
|
||||||
ConversationLocalCache: localcache.NewConversationLocalCache(&conversationClient),
|
GroupLocalCache: rpccache.NewGroupLocalCache(groupRpcClient, rdb),
|
||||||
friend: &friendRpcClient,
|
ConversationLocalCache: rpccache.NewConversationLocalCache(conversationClient, rdb),
|
||||||
|
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)
|
||||||
|
|||||||
@@ -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.User.GetUsersInfoMap(ctx, userIDs)
|
userMap, err := m.UserLocalCache.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.Group.GetGroupInfos(ctx, groupIDs, false)
|
resp, err := m.GroupLocalCache.GetGroupInfos(ctx, groupIDs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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.Conversation.GetConversation(ctx, req.UserID, seq.ConversationID)
|
conversation, err := m.ConversationLocalCache.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.User.GetUsersInfo(ctx, sendIDs)
|
sendInfos, err := m.UserLocalCache.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.User.GetUsersInfo(ctx, recvIDs)
|
recvInfos, err := m.UserLocalCache.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.Group.GetGroupInfos(ctx, groupIDs, true)
|
groupInfos, err := m.GroupLocalCache.GetGroupInfos(ctx, groupIDs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ package msg
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"github.com/OpenIMSDK/tools/log"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
@@ -51,17 +52,14 @@ 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 len(config.Config.Manager.UserID) > 0 && utils.IsContain(data.MsgData.SendID, config.Config.Manager.UserID) {
|
if 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.friend.IsBlocked(ctx, data.MsgData.SendID, data.MsgData.RecvID)
|
black, err := m.FriendLocalCache.IsBlack(ctx, data.MsgData.SendID, data.MsgData.RecvID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -69,7 +67,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.friend.IsFriend(ctx, data.MsgData.SendID, data.MsgData.RecvID)
|
friend, err := m.FriendLocalCache.IsFriend(ctx, data.MsgData.SendID, data.MsgData.RecvID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -80,7 +78,7 @@ func (m *msgServer) messageVerification(ctx context.Context, data *msg.SendMsgRe
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
case constant.SuperGroupChatType:
|
case constant.SuperGroupChatType:
|
||||||
groupInfo, err := m.Group.GetGroupInfoCache(ctx, data.MsgData.GroupID)
|
groupInfo, err := m.GroupLocalCache.GetGroupInfo(ctx, data.MsgData.GroupID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -91,27 +89,24 @@ 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 len(config.Config.Manager.UserID) > 0 && utils.IsContain(data.MsgData.SendID, config.Config.Manager.UserID) {
|
if 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.GetGroupMemberIDs(ctx, data.MsgData.GroupID)
|
memberIDs, err := m.GroupLocalCache.GetGroupMemberIDMap(ctx, data.MsgData.GroupID)
|
||||||
// if err != nil {
|
|
||||||
// return err
|
|
||||||
// }
|
|
||||||
// if !utils.IsContain(data.MsgData.SendID, memberIDs) {
|
|
||||||
// return errs.ErrNotInGroupYet.Wrap()
|
|
||||||
// }
|
|
||||||
|
|
||||||
groupMemberInfo, err := m.Group.GetGroupMemberCache(ctx, data.MsgData.GroupID, data.MsgData.SendID)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == errs.ErrRecordNotFound {
|
return err
|
||||||
|
}
|
||||||
|
if _, ok := memberIDs[data.MsgData.SendID]; !ok {
|
||||||
|
return errs.ErrNotInGroupYet.Wrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
groupMemberInfo, err := m.GroupLocalCache.GetGroupMember(ctx, data.MsgData.GroupID, data.MsgData.SendID)
|
||||||
|
if err != nil {
|
||||||
|
if errs.ErrRecordNotFound.Is(err) {
|
||||||
return errs.ErrNotInGroupYet.Wrap(err.Error())
|
return errs.ErrNotInGroupYet.Wrap(err.Error())
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
@@ -192,7 +187,8 @@ func (m *msgServer) modifyMessageByUserMessageReceiveOpt(
|
|||||||
sessionType int,
|
sessionType int,
|
||||||
pb *msg.SendMsgReq,
|
pb *msg.SendMsgReq,
|
||||||
) (bool, error) {
|
) (bool, error) {
|
||||||
opt, err := m.User.GetUserGlobalMsgRecvOpt(ctx, userID)
|
defer log.ZDebug(ctx, "modifyMessageByUserMessageReceiveOpt return")
|
||||||
|
opt, err := m.UserLocalCache.GetUserGlobalMsgRecvOpt(ctx, userID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
@@ -208,7 +204,7 @@ func (m *msgServer) modifyMessageByUserMessageReceiveOpt(
|
|||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
// conversationID := utils.GetConversationIDBySessionType(conversationID, sessionType)
|
// conversationID := utils.GetConversationIDBySessionType(conversationID, sessionType)
|
||||||
singleOpt, err := m.Conversation.GetSingleConversationRecvMsgOpt(ctx, userID, conversationID)
|
singleOpt, err := m.ConversationLocalCache.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 {
|
||||||
|
|||||||
@@ -61,6 +61,7 @@ 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 {
|
||||||
@@ -71,6 +72,12 @@ 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)")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,18 +22,17 @@ 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
|
||||||
@@ -48,16 +47,18 @@ func StartTask() error {
|
|||||||
|
|
||||||
// register cron tasks
|
// register cron tasks
|
||||||
var crontab = cron.New()
|
var crontab = cron.New()
|
||||||
fmt.Println("start chatRecordsClearTime cron task", "cron config", config.Config.ChatRecordsClearTime)
|
log.ZInfo(context.Background(), "start chatRecordsClearTime cron task", "cron config", config.Config.ChatRecordsClearTime)
|
||||||
_, err = crontab.AddFunc(config.Config.ChatRecordsClearTime, cronWrapFunc(rdb, "cron_clear_msg_and_fix_seq", msgTool.AllConversationClearMsgAndFixSeq))
|
_, err = crontab.AddFunc(config.Config.ChatRecordsClearTime, cronWrapFunc(rdb, "cron_clear_msg_and_fix_seq", msgTool.AllConversationClearMsgAndFixSeq))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errs.Wrap(err)
|
log.ZError(context.Background(), "start allConversationClearMsgAndFixSeq cron failed", err)
|
||||||
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println("start msgDestruct cron task", "cron config", config.Config.MsgDestructTime)
|
log.ZInfo(context.Background(), "start msgDestruct cron task", "cron config", config.Config.MsgDestructTime)
|
||||||
_, err = crontab.AddFunc(config.Config.MsgDestructTime, cronWrapFunc(rdb, "cron_conversations_destruct_msgs", msgTool.ConversationsDestructMsgs))
|
_, err = crontab.AddFunc(config.Config.MsgDestructTime, cronWrapFunc(rdb, "cron_conversations_destruct_msgs", msgTool.ConversationsDestructMsgs))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errs.Wrap(err)
|
log.ZError(context.Background(), "start conversationsDestructMsgs cron failed", err)
|
||||||
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// start crontab
|
// start crontab
|
||||||
|
|||||||
@@ -84,10 +84,7 @@ func InitMsgTool() (*MsgTool, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
msgDatabase, err := controller.InitCommonMsgDatabase(rdb, mongo.GetDatabase())
|
msgDatabase := 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(
|
||||||
|
|||||||
@@ -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 len(config.Config.Manager.UserID) > 0 && utils.IsContain(opUserID, config.Config.Manager.UserID) {
|
if 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,12 +48,11 @@ func CheckAccessV3(ctx context.Context, ownerUserID string) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func IsAppManagerUid(ctx context.Context) bool {
|
func IsAppManagerUid(ctx context.Context) bool {
|
||||||
return (len(config.Config.Manager.UserID) > 0 && utils.IsContain(mcontext.GetOpUserID(ctx), config.Config.Manager.UserID)) ||
|
return utils.IsContain(mcontext.GetOpUserID(ctx), config.Config.Manager.UserID) || utils.IsContain(mcontext.GetOpUserID(ctx), config.Config.IMAdmin.UserID)
|
||||||
utils.IsContain(mcontext.GetOpUserID(ctx), config.Config.IMAdmin.UserID)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func CheckAdmin(ctx context.Context) error {
|
func CheckAdmin(ctx context.Context) error {
|
||||||
if len(config.Config.Manager.UserID) > 0 && utils.IsContain(mcontext.GetOpUserID(ctx), config.Config.Manager.UserID) {
|
if 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) {
|
||||||
@@ -65,7 +64,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 len(config.Config.Manager.UserID) > 0 && utils.IsContain(mcontext.GetOpUserID(ctx), config.Config.Manager.UserID) {
|
if 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)))
|
||||||
@@ -76,7 +75,7 @@ func ParseRedisInterfaceToken(redisToken any) (*tokenverify.Claims, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func IsManagerUserID(opUserID string) bool {
|
func IsManagerUserID(opUserID string) bool {
|
||||||
return (len(config.Config.Manager.UserID) > 0 && utils.IsContain(opUserID, config.Config.Manager.UserID)) || utils.IsContain(opUserID, config.Config.IMAdmin.UserID)
|
return 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 {
|
||||||
|
|||||||
15
pkg/common/cachekey/black.go
Normal file
15
pkg/common/cachekey/black.go
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
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
|
||||||
|
}
|
||||||
44
pkg/common/cachekey/conversation.go
Normal file
44
pkg/common/cachekey/conversation.go
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
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
|
||||||
|
}
|
||||||
24
pkg/common/cachekey/friend.go
Normal file
24
pkg/common/cachekey/friend.go
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
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
|
||||||
|
}
|
||||||
45
pkg/common/cachekey/group.go
Normal file
45
pkg/common/cachekey/group.go
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
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))
|
||||||
|
}
|
||||||
14
pkg/common/cachekey/user.go
Normal file
14
pkg/common/cachekey/user.go
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
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
|
||||||
|
}
|
||||||
@@ -20,6 +20,7 @@ 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"
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ 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"
|
||||||
@@ -258,6 +259,8 @@ 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"`
|
||||||
@@ -370,6 +373,33 @@ 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,
|
||||||
|
|||||||
@@ -16,6 +16,8 @@ package config
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
_ "embed"
|
_ "embed"
|
||||||
|
"fmt"
|
||||||
|
"gopkg.in/yaml.v3"
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
@@ -115,3 +117,13 @@ 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))
|
||||||
|
}
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
3.5.1
|
v3.5.0
|
||||||
15
pkg/common/db/cache/black.go
vendored
15
pkg/common/db/cache/black.go
vendored
@@ -16,6 +16,9 @@ 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"
|
||||||
@@ -52,11 +55,15 @@ 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: NewMetaCacheRedis(rcClient),
|
metaCache: mc,
|
||||||
blackDB: blackDB,
|
blackDB: blackDB,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -66,12 +73,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: NewMetaCacheRedis(b.rcClient, b.metaCache.GetPreDelKeys()...),
|
metaCache: b.Copy(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *BlackCacheRedis) getBlackIDsKey(ownerUserID string) string {
|
func (b *BlackCacheRedis) getBlackIDsKey(ownerUserID string) string {
|
||||||
return blackIDsKey + ownerUserID
|
return cachekey.GetBlackIDsKey(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) {
|
||||||
|
|||||||
66
pkg/common/db/cache/config.go
vendored
Normal file
66
pkg/common/db/cache/config.go
vendored
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
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
|
||||||
|
}
|
||||||
51
pkg/common/db/cache/conversation.go
vendored
51
pkg/common/db/cache/conversation.go
vendored
@@ -17,6 +17,9 @@ 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"
|
||||||
@@ -30,14 +33,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
|
||||||
)
|
)
|
||||||
@@ -84,10 +87,14 @@ 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: NewMetaCacheRedis(rcClient),
|
metaCache: mc,
|
||||||
conversationDB: db,
|
conversationDB: db,
|
||||||
expireTime: conversationExpireTime,
|
expireTime: conversationExpireTime,
|
||||||
}
|
}
|
||||||
@@ -118,38 +125,42 @@ type ConversationRedisCache struct {
|
|||||||
func (c *ConversationRedisCache) NewCache() ConversationCache {
|
func (c *ConversationRedisCache) NewCache() ConversationCache {
|
||||||
return &ConversationRedisCache{
|
return &ConversationRedisCache{
|
||||||
rcClient: c.rcClient,
|
rcClient: c.rcClient,
|
||||||
metaCache: NewMetaCacheRedis(c.rcClient, c.metaCache.GetPreDelKeys()...),
|
metaCache: c.Copy(),
|
||||||
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 conversationKey + ownerUserID + ":" + conversationID
|
return cachekey.GetConversationKey(ownerUserID, conversationID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ConversationRedisCache) getConversationIDsKey(ownerUserID string) string {
|
func (c *ConversationRedisCache) getConversationIDsKey(ownerUserID string) string {
|
||||||
return conversationIDsKey + ownerUserID
|
return cachekey.GetConversationIDsKey(ownerUserID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ConversationRedisCache) getSuperGroupRecvNotNotifyUserIDsKey(groupID string) string {
|
func (c *ConversationRedisCache) getSuperGroupRecvNotNotifyUserIDsKey(groupID string) string {
|
||||||
return superGroupRecvMsgNotNotifyUserIDsKey + groupID
|
return cachekey.GetSuperGroupRecvNotNotifyUserIDsKey(groupID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ConversationRedisCache) getRecvMsgOptKey(ownerUserID, conversationID string) string {
|
func (c *ConversationRedisCache) getRecvMsgOptKey(ownerUserID, conversationID string) string {
|
||||||
return recvMsgOptKey + ownerUserID + ":" + conversationID
|
return cachekey.GetRecvMsgOptKey(ownerUserID, conversationID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ConversationRedisCache) getSuperGroupRecvNotNotifyUserIDsHashKey(groupID string) string {
|
func (c *ConversationRedisCache) getSuperGroupRecvNotNotifyUserIDsHashKey(groupID string) string {
|
||||||
return superGroupRecvMsgNotNotifyUserIDsHashKey + groupID
|
return cachekey.GetSuperGroupRecvNotNotifyUserIDsHashKey(groupID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ConversationRedisCache) getConversationHasReadSeqKey(ownerUserID, conversationID string) string {
|
func (c *ConversationRedisCache) getConversationHasReadSeqKey(ownerUserID, conversationID string) string {
|
||||||
return conversationHasReadSeqKey + ownerUserID + ":" + conversationID
|
return cachekey.GetConversationHasReadSeqKey(ownerUserID, conversationID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ConversationRedisCache) getConversationNotReceiveMessageUserIDsKey(conversationID string) string {
|
func (c *ConversationRedisCache) getConversationNotReceiveMessageUserIDsKey(conversationID string) string {
|
||||||
return conversationNotReceiveMessageUserIDsKey + conversationID
|
return cachekey.GetConversationNotReceiveMessageUserIDsKey(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) {
|
||||||
@@ -169,10 +180,6 @@ 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,
|
||||||
|
|||||||
26
pkg/common/db/cache/friend.go
vendored
26
pkg/common/db/cache/friend.go
vendored
@@ -16,6 +16,9 @@ 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"
|
||||||
@@ -27,10 +30,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.
|
||||||
@@ -60,8 +63,13 @@ 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: NewMetaCacheRedis(rcClient),
|
metaCache: mc,
|
||||||
friendDB: friendDB,
|
friendDB: friendDB,
|
||||||
expireTime: friendExpireTime,
|
expireTime: friendExpireTime,
|
||||||
rcClient: rcClient,
|
rcClient: rcClient,
|
||||||
@@ -72,7 +80,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: NewMetaCacheRedis(f.rcClient, f.metaCache.GetPreDelKeys()...),
|
metaCache: f.Copy(),
|
||||||
friendDB: f.friendDB,
|
friendDB: f.friendDB,
|
||||||
expireTime: f.expireTime,
|
expireTime: f.expireTime,
|
||||||
}
|
}
|
||||||
@@ -80,17 +88,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 friendIDsKey + ownerUserID
|
return cachekey.GetFriendIDsKey(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 TwoWayFriendsIDsKey + ownerUserID
|
return cachekey.GetTwoWayFriendsIDsKey(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 friendKey + ownerUserID + "-" + friendUserID
|
return cachekey.GetFriendKey(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.
|
||||||
|
|||||||
44
pkg/common/db/cache/group.go
vendored
44
pkg/common/db/cache/group.go
vendored
@@ -17,7 +17,8 @@ package cache
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
"github.com/openimsdk/open-im-server/v3/pkg/common/cachekey"
|
||||||
|
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/OpenIMSDK/protocol/constant"
|
"github.com/OpenIMSDK/protocol/constant"
|
||||||
@@ -34,15 +35,14 @@ 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:"
|
||||||
//groupOwnerInfoKey = "GROUP_OWNER_INFO:".
|
//joinedGroupsKey = "JOIN_GROUPS_KEY:"
|
||||||
joinedGroupsKey = "JOIN_GROUPS_KEY:"
|
//groupMemberNumKey = "GROUP_MEMBER_NUM_CACHE:"
|
||||||
groupMemberNumKey = "GROUP_MEMBER_NUM_CACHE:"
|
//groupRoleLevelMemberIDsKey = "GROUP_ROLE_LEVEL_MEMBER_IDS:"
|
||||||
groupRoleLevelMemberIDsKey = "GROUP_ROLE_LEVEL_MEMBER_IDS:"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type GroupHash interface {
|
type GroupHash interface {
|
||||||
@@ -105,12 +105,16 @@ 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: NewMetaCacheRedis(rcClient),
|
metaCache: mc,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -121,36 +125,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: NewMetaCacheRedis(g.rcClient, g.metaCache.GetPreDelKeys()...),
|
metaCache: g.Copy(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GroupCacheRedis) getGroupInfoKey(groupID string) string {
|
func (g *GroupCacheRedis) getGroupInfoKey(groupID string) string {
|
||||||
return groupInfoKey + groupID
|
return cachekey.GetGroupInfoKey(groupID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GroupCacheRedis) getJoinedGroupsKey(userID string) string {
|
func (g *GroupCacheRedis) getJoinedGroupsKey(userID string) string {
|
||||||
return joinedGroupsKey + userID
|
return cachekey.GetJoinedGroupsKey(userID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GroupCacheRedis) getGroupMembersHashKey(groupID string) string {
|
func (g *GroupCacheRedis) getGroupMembersHashKey(groupID string) string {
|
||||||
return groupMembersHashKey + groupID
|
return cachekey.GetGroupMembersHashKey(groupID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GroupCacheRedis) getGroupMemberIDsKey(groupID string) string {
|
func (g *GroupCacheRedis) getGroupMemberIDsKey(groupID string) string {
|
||||||
return groupMemberIDsKey + groupID
|
return cachekey.GetGroupMemberIDsKey(groupID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GroupCacheRedis) getGroupMemberInfoKey(groupID, userID string) string {
|
func (g *GroupCacheRedis) getGroupMemberInfoKey(groupID, userID string) string {
|
||||||
return groupMemberInfoKey + groupID + "-" + userID
|
return cachekey.GetGroupMemberInfoKey(groupID, userID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GroupCacheRedis) getGroupMemberNumKey(groupID string) string {
|
func (g *GroupCacheRedis) getGroupMemberNumKey(groupID string) string {
|
||||||
return groupMemberNumKey + groupID
|
return cachekey.GetGroupMemberNumKey(groupID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GroupCacheRedis) getGroupRoleLevelMemberIDsKey(groupID string, roleLevel int32) string {
|
func (g *GroupCacheRedis) getGroupRoleLevelMemberIDsKey(groupID string, roleLevel int32) string {
|
||||||
return groupRoleLevelMemberIDsKey + groupID + "-" + strconv.Itoa(int(roleLevel))
|
return cachekey.GetGroupRoleLevelMemberIDsKey(groupID, roleLevel)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GroupCacheRedis) GetGroupIndex(group *relationtb.GroupModel, keys []string) (int, error) {
|
func (g *GroupCacheRedis) GetGroupIndex(group *relationtb.GroupModel, keys []string) (int, error) {
|
||||||
|
|||||||
7
pkg/common/db/cache/init_redis.go
vendored
7
pkg/common/db/cache/init_redis.go
vendored
@@ -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, errs.Wrap(errors.New("redis address is empty"))
|
return nil, 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,10 +77,9 @@ 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 {
|
||||||
uriFormat := "address:%s, username:%s, password:%s, clusterMode:%t, enablePipeline:%t"
|
return nil, fmt.Errorf("redis ping %w", err)
|
||||||
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
|
||||||
}
|
}
|
||||||
|
|||||||
65
pkg/common/db/cache/meta_cache.go
vendored
65
pkg/common/db/cache/meta_cache.go
vendored
@@ -18,6 +18,7 @@ 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"
|
||||||
@@ -44,6 +45,9 @@ 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 {
|
||||||
@@ -51,10 +55,36 @@ 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 {
|
||||||
@@ -62,7 +92,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", "keys", m.keys)
|
log.ZDebug(ctx, "delete cache", "topic", m.topic, "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 {
|
||||||
@@ -72,31 +102,18 @@ func (m *metaCacheRedis) ExecDel(ctx context.Context, distinct ...bool) error {
|
|||||||
}
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
}
|
||||||
//retryTimes := 0
|
if pk := getPublishKey(m.topic, m.keys); len(pk) > 0 {
|
||||||
//for {
|
data, err := json.Marshal(pk)
|
||||||
// m.rcClient.TagAsDeleted()
|
if err != nil {
|
||||||
// if err := m.rcClient.TagAsDeletedBatch2(ctx, []string{key}); err != nil {
|
log.ZError(ctx, "keys json marshal failed", err, "topic", m.topic, "keys", pk)
|
||||||
// if retryTimes >= m.maxRetryTimes {
|
} else {
|
||||||
// err = errs.ErrInternalServer.Wrap(
|
if err := m.redisClient.Publish(ctx, m.topic, string(data)).Err(); err != nil {
|
||||||
// fmt.Sprintf(
|
log.ZError(ctx, "redis publish cache delete error", err, "topic", m.topic, "keys", pk)
|
||||||
// "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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
24
pkg/common/db/cache/msg.go
vendored
24
pkg/common/db/cache/msg.go
vendored
@@ -17,6 +17,7 @@ package cache
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
|
"github.com/dtm-labs/rockscache"
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -44,12 +45,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:"
|
||||||
@@ -128,7 +129,8 @@ type MsgModel interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func NewMsgCacheModel(client redis.UniversalClient) MsgModel {
|
func NewMsgCacheModel(client redis.UniversalClient) MsgModel {
|
||||||
return &msgCache{rdb: client}
|
rcClient := rockscache.NewClient(client, rockscache.NewDefaultOptions())
|
||||||
|
return &msgCache{metaCache: NewMetaCacheRedis(rcClient), rdb: client}
|
||||||
}
|
}
|
||||||
|
|
||||||
type msgCache struct {
|
type msgCache struct {
|
||||||
@@ -148,6 +150,10 @@ 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())
|
||||||
}
|
}
|
||||||
@@ -209,10 +215,6 @@ 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())
|
||||||
}
|
}
|
||||||
|
|||||||
21
pkg/common/db/cache/user.go
vendored
21
pkg/common/db/cache/user.go
vendored
@@ -18,6 +18,8 @@ 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"
|
||||||
@@ -36,8 +38,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
|
||||||
@@ -72,7 +74,11 @@ 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),
|
||||||
@@ -85,7 +91,7 @@ func NewUserCacheRedis(
|
|||||||
func (u *UserCacheRedis) NewCache() UserCache {
|
func (u *UserCacheRedis) NewCache() UserCache {
|
||||||
return &UserCacheRedis{
|
return &UserCacheRedis{
|
||||||
rdb: u.rdb,
|
rdb: u.rdb,
|
||||||
metaCache: NewMetaCacheRedis(u.rcClient, u.metaCache.GetPreDelKeys()...),
|
metaCache: u.Copy(),
|
||||||
userDB: u.userDB,
|
userDB: u.userDB,
|
||||||
expireTime: u.expireTime,
|
expireTime: u.expireTime,
|
||||||
rcClient: u.rcClient,
|
rcClient: u.rcClient,
|
||||||
@@ -93,18 +99,17 @@ func (u *UserCacheRedis) NewCache() UserCache {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (u *UserCacheRedis) getUserInfoKey(userID string) string {
|
func (u *UserCacheRedis) getUserInfoKey(userID string) string {
|
||||||
return userInfoKey + userID
|
return cachekey.GetUserInfoKey(userID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *UserCacheRedis) getUserGlobalRecvMsgOptKey(userID string) string {
|
func (u *UserCacheRedis) getUserGlobalRecvMsgOptKey(userID string) string {
|
||||||
return userGlobalRecvMsgOptKey + userID
|
return cachekey.GetUserGlobalRecvMsgOptKey(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) {
|
||||||
|
|||||||
@@ -126,32 +126,21 @@ type CommonMsgDatabase interface {
|
|||||||
ConvertMsgsDocLen(ctx context.Context, conversationIDs []string)
|
ConvertMsgsDocLen(ctx context.Context, conversationIDs []string)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewCommonMsgDatabase(msgDocModel unrelationtb.MsgDocModelInterface, cacheModel cache.MsgModel) (CommonMsgDatabase, error) {
|
func NewCommonMsgDatabase(msgDocModel unrelationtb.MsgDocModelInterface, cacheModel cache.MsgModel) CommonMsgDatabase {
|
||||||
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: producerToRedis,
|
producer: kafka.NewKafkaProducer(config.Config.Kafka.Addr, config.Config.Kafka.LatestMsgToRedis.Topic),
|
||||||
producerToMongo: producerToMongo,
|
producerToMongo: kafka.NewKafkaProducer(config.Config.Kafka.Addr, config.Config.Kafka.MsgToMongo.Topic),
|
||||||
producerToPush: producerToPush,
|
producerToPush: kafka.NewKafkaProducer(config.Config.Kafka.Addr, config.Config.Kafka.MsgToPush.Topic),
|
||||||
}, nil
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func InitCommonMsgDatabase(rdb redis.UniversalClient, database *mongo.Database) (CommonMsgDatabase, error) {
|
func InitCommonMsgDatabase(rdb redis.UniversalClient, database *mongo.Database) CommonMsgDatabase {
|
||||||
cacheModel := cache.NewMsgCacheModel(rdb)
|
cacheModel := cache.NewMsgCacheModel(rdb)
|
||||||
msgDocModel := unrelation.NewMsgMongoDriver(database)
|
msgDocModel := unrelation.NewMsgMongoDriver(database)
|
||||||
return NewCommonMsgDatabase(msgDocModel, cacheModel)
|
CommonMsgDatabase := NewCommonMsgDatabase(msgDocModel, cacheModel)
|
||||||
|
return CommonMsgDatabase
|
||||||
}
|
}
|
||||||
|
|
||||||
type commonMsgDatabase struct {
|
type commonMsgDatabase struct {
|
||||||
|
|||||||
@@ -1,87 +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 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
|
|
||||||
}
|
|
||||||
@@ -1,15 +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 localcache // import "github.com/openimsdk/open-im-server/v3/pkg/common/db/localcache"
|
|
||||||
@@ -1,78 +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 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
|
|
||||||
}
|
|
||||||
@@ -1,15 +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 localcache
|
|
||||||
@@ -18,8 +18,6 @@ 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"
|
||||||
@@ -40,7 +38,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, errs.Wrap(err)
|
return nil, err
|
||||||
}
|
}
|
||||||
return &ConversationMgo{coll: coll}, nil
|
return &ConversationMgo{coll: coll}, nil
|
||||||
}
|
}
|
||||||
@@ -116,8 +114,7 @@ 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"}},
|
||||||
{"$group": bson.M{"_id": nil, "count": bson.M{"$sum": 1}}},
|
{"$project": bson.M{"_id": 0, "conversation_id": "$_id"}},
|
||||||
{"$project": bson.M{"_id": 0}},
|
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
|
|||||||
@@ -18,8 +18,6 @@ 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"
|
||||||
@@ -38,7 +36,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, errs.Wrap(err)
|
return nil, err
|
||||||
}
|
}
|
||||||
return &GroupMgo{coll: coll}, nil
|
return &GroupMgo{coll: coll}, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,8 +17,6 @@ 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"
|
||||||
@@ -39,7 +37,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, errs.Wrap(err)
|
return nil, err
|
||||||
}
|
}
|
||||||
return &GroupMemberMgo{coll: coll}, nil
|
return &GroupMemberMgo{coll: coll}, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,8 +17,6 @@ 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"
|
||||||
@@ -38,7 +36,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, errs.Wrap(err)
|
return nil, err
|
||||||
}
|
}
|
||||||
return &GroupRequestMgo{coll: coll}, nil
|
return &GroupRequestMgo{coll: coll}, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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, errs.Wrap(err)
|
return nil, err
|
||||||
}
|
}
|
||||||
return &UserMgo{coll: coll}, nil
|
return &UserMgo{coll: coll}, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ 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"
|
||||||
@@ -55,17 +56,16 @@ 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, errs.Wrap(err, uri)
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
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 errs.Wrap(err, "CreateIndex")
|
return utils.Wrap(err, "CreateIndex")
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,26 +1,11 @@
|
|||||||
// 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"
|
||||||
"math/rand"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/OpenIMSDK/tools/log"
|
"github.com/OpenIMSDK/tools/log"
|
||||||
"google.golang.org/grpc/resolver"
|
"google.golang.org/grpc/resolver"
|
||||||
|
"math/rand"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|||||||
@@ -1,29 +1,13 @@
|
|||||||
// 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
|
||||||
|
|||||||
@@ -16,9 +16,8 @@ package discoveryregister
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"os"
|
|
||||||
|
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/common/discoveryregister/direct"
|
"github.com/openimsdk/open-im-server/v3/pkg/common/discoveryregister/direct"
|
||||||
|
"os"
|
||||||
|
|
||||||
"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"
|
||||||
|
|||||||
@@ -15,13 +15,10 @@
|
|||||||
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"
|
||||||
@@ -36,7 +33,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)
|
||||||
|
|
||||||
zk, err := openkeeper.NewClient(
|
return openkeeper.NewClient(
|
||||||
zkAddr,
|
zkAddr,
|
||||||
schema,
|
schema,
|
||||||
openkeeper.WithFreq(time.Hour),
|
openkeeper.WithFreq(time.Hour),
|
||||||
@@ -45,16 +42,6 @@ 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.
|
||||||
|
|||||||
@@ -16,9 +16,6 @@ package kafka
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/OpenIMSDK/tools/errs"
|
|
||||||
|
|
||||||
"github.com/OpenIMSDK/tools/log"
|
"github.com/OpenIMSDK/tools/log"
|
||||||
|
|
||||||
@@ -39,7 +36,7 @@ type MConsumerGroupConfig struct {
|
|||||||
IsReturnErr bool
|
IsReturnErr bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewMConsumerGroup(consumerConfig *MConsumerGroupConfig, topics, addrs []string, groupID string) (*MConsumerGroup, error) {
|
func NewMConsumerGroup(consumerConfig *MConsumerGroupConfig, topics, addrs []string, groupID string) *MConsumerGroup {
|
||||||
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
|
||||||
@@ -52,28 +49,26 @@ 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 {
|
||||||
return nil, errs.Wrap(err, strings.Join(topics, ","), strings.Join(addrs, ","), groupID, config.Config.Kafka.Username, config.Config.Kafka.Password)
|
panic(err.Error())
|
||||||
}
|
}
|
||||||
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(ctx context.Context, handler sarama.ConsumerGroupHandler) {
|
func (mc *MConsumerGroup) RegisterHandleAndConsumer(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 {
|
||||||
log.ZWarn(ctx, "consume err", err, "topic", mc.topics, "groupID", mc.groupID)
|
panic(err.Error())
|
||||||
}
|
|
||||||
if ctx.Err() != nil {
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,8 +21,6 @@ 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"
|
||||||
@@ -46,7 +44,7 @@ type Producer struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewKafkaProducer initializes a new Kafka producer.
|
// NewKafkaProducer initializes a new Kafka producer.
|
||||||
func NewKafkaProducer(addr []string, topic string) (*Producer, error) {
|
func NewKafkaProducer(addr []string, topic string) *Producer {
|
||||||
p := Producer{
|
p := Producer{
|
||||||
addr: addr,
|
addr: addr,
|
||||||
topic: topic,
|
topic: topic,
|
||||||
@@ -89,17 +87,17 @@ func NewKafkaProducer(addr []string, topic string) (*Producer, error) {
|
|||||||
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, nil
|
return &p
|
||||||
}
|
}
|
||||||
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 {
|
||||||
return nil, errs.Wrap(errors.New("failed to create Kafka producer: " + err.Error()))
|
panic("Failed to create Kafka producer: " + err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
return &p, nil
|
return &p
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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
Reference in New Issue
Block a user