diff --git a/.devcontainer/README.md b/.devcontainer/README.md
deleted file mode 100644
index 24778f8ee..000000000
--- a/.devcontainer/README.md
+++ /dev/null
@@ -1,140 +0,0 @@
-# OpenIM - OSS Development Container
-
-[](https://vscode.dev/redirect?url=vscode://ms-vscode-remote.remote-containers/cloneInVolume?url=https://github.com/openimsdk/open-im-server)
-
-This repository includes configuration for a development container for working with OpenIM - OSS in a local container or using [GitHub Codespaces](https://github.com/features/codespaces).
-
-> **Tip:** The default VNC password is `openIM123`. The VNC server runs on port `5901` and a web client is available on port `11001`, openim-admin on port `11002`.
-
-## Quick start - local
-
-If you already have VS Code and Docker installed, you can click the badge above or [here](https://vscode.dev/redirect?url=vscode://ms-vscode-remote.remote-containers/cloneInVolume?url=https://github.com/openimsdk/open-im-server) to get started. Clicking these links will cause VS Code to automatically install the Dev Containers extension if needed, clone the source code into a container volume, and spin up a dev container for use.
-
-1. Install Docker Desktop or Docker for Linux on your local machine. (See [docs](https://aka.ms/vscode-remote/containers/getting-started) for additional details.)
-
-2. **Important**: Docker needs at least **4 Cores and 8 GB of RAM** to run a full build with **9 GB of RAM** being recommended. If you are on macOS, or are using the old Hyper-V engine for Windows, update these values for Docker Desktop by right-clicking on the Docker status bar item and going to **Preferences/Settings > Resources > Advanced**.
-
- > **Note:** The [Resource Monitor](https://marketplace.visualstudio.com/items?itemName=mutantdino.resourcemonitor) extension is included in the container so you can keep an eye on CPU/Memory in the status bar.
-
-3. Install [Visual Studio Code Stable](https://code.visualstudio.com/) or [Insiders](https://code.visualstudio.com/insiders/) and the [Dev Containers](https://aka.ms/vscode-remote/download/containers) extension.
-
- 
-
- > **Note:** The Dev Containers extension requires the Visual Studio Code distribution of OpenIM - OSS. See the [FAQ](https://aka.ms/vscode-remote/faq/license) for details.
-
-4. Press Ctrl/Cmd + Shift + P or F1 and select **Dev Containers: Clone Repository in Container Volume...**.
-
- > **Tip:** While you can use your local source tree instead, operations like `yarn install` can be slow on macOS or when using the Hyper-V engine on Windows. We recommend using the WSL filesystem on Windows or the "clone repository in container" approach on Windows and macOS instead since it uses "named volume" rather than the local filesystem.
-
-5. Type `https://github.com/openimsdk/open-im-server` (or a branch or PR URL) in the input box and press Enter.
-
-6. After the container is running:
- 1. If you have the `DISPLAY` or `WAYLAND_DISPLAY` environment variables set locally (or in WSL on Windows), desktop apps in the container will be shown in local windows.
- 2. If these are not set, open a web browser and go to [http://localhost:11001](http://localhost:11001), or use a [VNC Viewer][def] to connect to `localhost:11001` and enter `vscode` as the password. Anything you start in VS Code, or the integrated terminal, will appear here.
-
-Next: **[Try it out!](#try-it)**
-
-## Quick start - GitHub Codespaces
-
-1. From the [openimsdk/open-im-server GitHub repository](https://github.com/openimsdk/open-im-server), click on the **Code** dropdown, select **Open with Codespaces**, and then click on **New codespace**. If prompted, select the **Standard** machine size (which is also the default).
-
- > **Note:** You will not see these options within GitHub if you are not in the Codespaces beta.
-
-2. After the codespace is up and running in your browser, press Ctrl/Cmd + Shift + P or F1 and select **Ports: Focus on Ports View**.
-
-3. You should see **VNC web client (11001)** under in the list of ports. Select the line and click on the globe icon to open it in a browser tab.
-
- > **Tip:** If you do not see the port, Ctrl/Cmd + Shift + P or F1, select **Forward a Port** and enter port `11001`.
-
-4. In the new tab, you should see noVNC. Click **Connect** and enter `vscode` as the password.
-
-Anything you start in VS Code, or the integrated terminal, will appear here.
-
-Next: **[Try it out!](#try-it)**
-
-### Using VS Code with GitHub Codespaces
-
-You may see improved VNC responsiveness when accessing a codespace from VS Code client since you can use a [VNC Viewer][def]. Here's how to do it.
-
-1. Install [Visual Studio Code Stable](https://code.visualstudio.com/) or [Insiders](https://code.visualstudio.com/insiders/) and the the [GitHub Codespaces extension](https://marketplace.visualstudio.com/items?itemName=GitHub.codespaces).
-
- > **Note:** The GitHub Codespaces extension requires the Visual Studio Code distribution of OpenIM - OSS.
-
-2. After the VS Code is up and running, press Ctrl/Cmd + Shift + P or F1, choose **Codespaces: Create New Codespace**, and use the following settings:
-
-- `openimsdk/open-im-server` for the repository.
-- Select any branch (e.g. **main**) - you can select a different one later.
-- Choose **Standard** (4-core, 8GB) as the size.
-
-3. After you have connected to the codespace, you can use a [VNC Viewer][def] to connect to `localhost:5901` and enter `vscode` as the password.
-
- > **Tip:** You may also need change your VNC client's **Picture Quality** setting to **High** to get a full color desktop.
-
-4. Anything you start in VS Code, or the integrated terminal, will appear here.
-
-Next: **[Try it out!](#try-it)**
-
-## Try it
-
-This container uses the [Fluxbox](http://fluxbox.org/) window manager to keep things lean. **Right-click on the desktop** to see menu options. It works with GNOME and GTK applications, so other tools can be installed if needed.
-
- > **Note:** You can also set the resolution from the command line by typing `set-resolution`.
-
-To start working with OpenIM - OSS, follow these steps:
-
-1. In your local VS Code client, open a terminal (Ctrl/Cmd + Shift + \`) and type the following commands:
-
- ```bash
- yarn install
- bash scripts/code.sh
- ```
-
-2. After the build is complete, open a web browser or a [VNC Viewer][def] to connect to the desktop environment as described in the quick start and enter `vscode` as the password.
-
-3. You should now see OpenIM - OSS!
-
-Next, let's try debugging.
-
-1. Shut down OpenIM - OSS by clicking the box in the upper right corner of the OpenIM - OSS window through your browser or VNC viewer.
-
-2. Go to your local VS Code client, and use the **Run / Debug** view to launch the **VS Code** configuration. (Typically the default, so you can likely just press F5).
-
- > **Note:** If launching times out, you can increase the value of `timeout` in the "VS Code", "Attach Main Process", "Attach Extension Host", and "Attach to Shared Process" configurations in [launch.json](../../.vscode/launch.json). However, running `./scripts/code.sh` first will set up Electron which will usually solve timeout issues.
-
-3. After a bit, OpenIM - OSS will appear with the debugger attached!
-
-Enjoy!
-
-
-### Dotfiles
-
-Dotfiles are files and folders on Unix-like systems starting with `.` that control the configuration of applications and shells on your system. You can store and manage your dotfiles in a repository on GitHub. For advice and tutorials about what to include in your dotfiles repository, see [GitHub does dotfiles](https://dotfiles.github.io/).
-
-Your dotfiles repository might include your shell aliases and preferences, any tools you want to install, or any other codespace personalization you want to make.
-
-You can configure GitHub Codespaces to use dotfiles from any repository you own by selecting that repository in your [personal GitHub Codespaces settings](https://github.com/settings/codespaces).
-
-When you create a new codespace, GitHub clones your selected dotfiles repository to the codespace environment, and looks for one of the following files to set up the environment.
-
-- *install.sh*
-- *install*
-- *bootstrap.sh*
-- *bootstrap*
-- *script/bootstrap*
-- *setup.sh*
-- *setup*
-- *script/setup*
-
-If none of these files are found, then any files or folders in your selected dotfiles repository starting with `.` are symlinked to the codespace's `~` or `$HOME` directory.
-
-Any changes to your selected dotfiles repository will apply only to each new codespace, and do not affect any existing codespace.
-
-**Note:** Currently, Codespaces does not support personalizing the User-scoped settings for VS Code with your `dotfiles` repository. You can set default Workspace and Remote [Codespaces] settings for a specific project in the project's repository. For more information, see "[Introduction to dev containers](https://docs.github.com/en/codespaces/setting-up-your-project-for-codespaces/adding-a-dev-container-configuration/introduction-to-dev-containers#creating-a-custom-dev-container-configuration)."
-
-In addition, you can also configure Codespaces secrets on your personal profile page at [github.com/settings/codespaces](https://github.com/settings/codespaces). Development environment secrets are environment variables that are encrypted, and they are accessible to any codespace you create using repositories that have access to these secrets.
-
-### Notes
-
-The container comes with VS Code Insiders installed. To run it from an Integrated Terminal use `VSCODE_IPC_HOOK_CLI= /usr/bin/code-insiders .`.
-
-[def]: https://www.realvnc.com/en/connect/download/viewer/
diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json
deleted file mode 100644
index 69a35f66a..000000000
--- a/.devcontainer/devcontainer.json
+++ /dev/null
@@ -1,72 +0,0 @@
-{
- // Reference Doc: https://code.visualstudio.com/remote/advancedcontainers/overview
- "name": "OpenIM Dev Environment",
- // Update the container version when you publish dev-container
- "build": { "dockerfile": "Dockerfile" },
- // Replace with uncommented line below to build your own local copy of the image
- // "dockerFile": "../docker/Dockerfile-dev",
- "remoteEnv": {
- "GO111MODULE": "on",
- "GOPROXY": "https://goproxy.cn",
- "GOSUMDB": "sum.golang.org",
- "GONOPROXY": "github.com/openimsdk",
- "GONOSUMDB": "github.com/openimsdk",
- "GOPRIVATE": "github.com/openimsdk"
- },
- "customizations": {
- "vscode": {
- "extensions": [
- "davidanson.vscode-markdownlint",
- "golang.go",
- "ms-azuretools.vscode-dapr",
- "ms-azuretools.vscode-docker",
- "ms-kubernetes-tools.vscode-kubernetes-tools"
- ],
- "settings": {
- "go.toolsManagement.checkForUpdates": "local",
- "go.useLanguageServer": true,
- "go.gopath": "/go"
- }
- }
- },
- "mounts": [
- // Mount docker-in-docker library volume
- "type=volume,source=dind-var-lib-docker,target=/var/lib/docker",
-
- // Bind mount docker socket under an alias to support docker-from-docker
- "type=bind,source=/var/run/docker.sock,target=/var/run/docker-host.sock",
-
- // Bind mount docker socket under an alias to support docker-from-docker
- // "type=bind,source=${env:HOME}${env:USERPROFILE}/.minikube/cache,target=/home/openim/.minikube/cache",
-
- // Uncomment to clone local .kube/config into devcontainer
- "type=bind,source=${env:HOME}${env:USERPROFILE}/.kube,target=/home/openim/.kube-localhost"
-
- // Uncomment to additionally clone minikube certs into devcontainer for use with .kube/config
- // "type=bind,source=${env:HOME}${env:USERPROFILE}/.minikube,target=/home/openim/.minikube-localhost"
- ],
- // Always run image-defined default command
- "overrideCommand": false,
- // On Linux, this will prevent new files getting created as root, but you
- // may need to update the USER_UID and USER_GID in docker/Dockerfile-dev
- // to match your user if not 1000.
- // "remoteUser": "openimsdk",
- "runArgs": [
- // Enable ptrace-based debugging for go
- "--cap-add=SYS_PTRACE",
- "--security-opt",
- "seccomp=unconfined",
-
- // Uncomment to bind to host network for local devcontainer; this is necessary if using the
- // bind-mounted /var/run/docker-host.sock directly.
- "--net=host",
-
- // Enable docker-in-docker configuration. Comment out if not using for better security.
- "--privileged",
-
- // Run the entrypoint defined in container image.
- "--init"
- ],
- "workspaceFolder": "/workspaces/openim",
- "workspaceMount": "type=bind,source=${localWorkspaceFolder},target=/workspaces/openim"
-}
diff --git a/.github/workflows/auto-gh-pr.yml b/.github/workflows/auto-gh-pr.yml
index d58f35510..45454275e 100644
--- a/.github/workflows/auto-gh-pr.yml
+++ b/.github/workflows/auto-gh-pr.yml
@@ -28,7 +28,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout code
- uses: actions/checkout@v2
+ uses: actions/checkout@v4
- name: Sync Issue to PR
if: github.event_name == 'pull_request' && github.event.pull_request.base.ref == 'main'
diff --git a/.github/workflows/auto-invite.yml b/.github/workflows/auto-invite.yml
index 0276a33a4..350de30ab 100644
--- a/.github/workflows/auto-invite.yml
+++ b/.github/workflows/auto-invite.yml
@@ -27,7 +27,7 @@ jobs:
steps:
- name: Invite user to join our group
- uses: peter-evans/create-or-update-comment@v3
+ uses: peter-evans/create-or-update-comment@v4
with:
token: ${{ secrets.BOT_GITHUB_TOKEN }}
issue-number: ${{ github.event.issue.number }}
diff --git a/.github/workflows/bot-auto-cherry-pick.yml b/.github/workflows/bot-auto-cherry-pick.yml
index 7c2ad49ca..baafecad7 100644
--- a/.github/workflows/bot-auto-cherry-pick.yml
+++ b/.github/workflows/bot-auto-cherry-pick.yml
@@ -23,7 +23,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Comment cherry-pick command
- uses: actions/github-script@v6
+ uses: actions/github-script@v7
with:
script: |
const pr = context.payload.pull_request;
diff --git a/.github/workflows/build-docker-image.yml b/.github/workflows/build-docker-image.yml
index 619744987..1e9711d2c 100644
--- a/.github/workflows/build-docker-image.yml
+++ b/.github/workflows/build-docker-image.yml
@@ -43,7 +43,7 @@ jobs:
# docker.io/openim/openim-server:latest
- name: Extract metadata (tags, labels) for Docker
id: meta
- uses: docker/metadata-action@v5.0.0
+ uses: docker/metadata-action@v5.5.1
with:
images: openim/openim-server
# generate Docker tags based on the following events/attributes
@@ -86,7 +86,7 @@ jobs:
# registry.cn-hangzhou.aliyuncs.com/openimsdk/openim-server:latest
- name: Extract metadata (tags, labels) for Docker
id: meta2
- uses: docker/metadata-action@v5.0.0
+ uses: docker/metadata-action@v5.5.1
with:
images: registry.cn-hangzhou.aliyuncs.com/openimsdk/openim-server
# generate Docker tags based on the following events/attributes
@@ -130,7 +130,7 @@ jobs:
# ghcr.io/openimsdk/openim-server:latest
- name: Extract metadata (tags, labels) for Docker
id: meta3
- uses: docker/metadata-action@v5.0.0
+ uses: docker/metadata-action@v5.5.1
with:
images: ghcr.io/openimsdk/openim-server
# generate Docker tags based on the following events/attributes
diff --git a/.github/workflows/check-coverage.yml b/.github/workflows/check-coverage.yml
index 7b3935730..09d43d7cd 100644
--- a/.github/workflows/check-coverage.yml
+++ b/.github/workflows/check-coverage.yml
@@ -56,4 +56,4 @@ jobs:
continue-on-error: true
- name: Upload Coverage to Codecov
- uses: codecov/codecov-action@v3
+ uses: codecov/codecov-action@v4
diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml
index d6ff39371..29f9382cc 100644
--- a/.github/workflows/codeql-analysis.yml
+++ b/.github/workflows/codeql-analysis.yml
@@ -51,7 +51,7 @@ jobs:
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
- uses: github/codeql-action/init@v2
+ uses: github/codeql-action/init@v3
# Override language selection by uncommenting this and choosing your languages
with:
languages: go
@@ -59,7 +59,7 @@ jobs:
# Autobuild attempts to build any compiled languages (C/C++, C#, Go, or Java).
# If this step fails, then you should remove it and run the build manually (see below).
- name: Autobuild
- uses: github/codeql-action/autobuild@v2
+ uses: github/codeql-action/autobuild@v3
# ℹ️ Command-line programs to run using the OS shell.
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
@@ -73,4 +73,4 @@ jobs:
# make release
- name: Perform CodeQL Analysis
- uses: github/codeql-action/analyze@v2
\ No newline at end of file
+ uses: github/codeql-action/analyze@v3
\ No newline at end of file
diff --git a/.github/workflows/create-branch-on-tag.yml b/.github/workflows/create-branch-on-tag.yml
index b6b9eb8e8..fbacd261b 100644
--- a/.github/workflows/create-branch-on-tag.yml
+++ b/.github/workflows/create-branch-on-tag.yml
@@ -70,7 +70,7 @@ jobs:
- name: Push CHANGELOG to Main
if: steps.create-and-commit-changelog.outputs.changes == 'true'
- uses: ad-m/github-push-action@v0.6.0
+ uses: ad-m/github-push-action@v0.8.0
with:
github_token: ${{ secrets.BOT_GITHUB_TOKEN }}
branch: main
diff --git a/.github/workflows/depsreview.yaml b/.github/workflows/depsreview.yaml
index c80929c8c..aff7e3d9e 100644
--- a/.github/workflows/depsreview.yaml
+++ b/.github/workflows/depsreview.yaml
@@ -15,4 +15,4 @@ jobs:
- name: 'Checkout Repository'
uses: actions/checkout@v4
- name: 'Dependency Review'
- uses: actions/dependency-review-action@v3
\ No newline at end of file
+ uses: actions/dependency-review-action@v4
\ No newline at end of file
diff --git a/.github/workflows/docker-buildx.yml b/.github/workflows/docker-buildx.yml
index b3b0b5683..7e7b8229c 100644
--- a/.github/workflows/docker-buildx.yml
+++ b/.github/workflows/docker-buildx.yml
@@ -40,7 +40,7 @@ jobs:
install: true
- name: Cache Docker layers
- uses: actions/cache@v3
+ uses: actions/cache@v4
with:
path: /tmp/.buildx-cache
key: ${{ runner.os }}-buildx-${{ github.sha }}
@@ -100,7 +100,7 @@ jobs:
- name: Extract metadata (tags, labels) for Docker openim-api
id: meta1
- uses: docker/metadata-action@v5.0.0
+ uses: docker/metadata-action@v5.5.1
with:
images: |
ghcr.io/openimsdk/openim-api
@@ -131,7 +131,7 @@ jobs:
- name: Extract metadata (tags, labels) for Docker openim-cmdutils
id: meta2
- uses: docker/metadata-action@v5.0.0
+ uses: docker/metadata-action@v5.5.1
with:
images: |
ghcr.io/openimsdk/openim-cmdutils
@@ -162,7 +162,7 @@ jobs:
- name: Extract metadata (tags, labels) for Docker openim-crontask
id: meta3
- uses: docker/metadata-action@v5.0.0
+ uses: docker/metadata-action@v5.5.1
with:
images: |
ghcr.io/openimsdk/openim-crontask
@@ -193,7 +193,7 @@ jobs:
- name: Extract metadata (tags, labels) for Docker openim-msggateway
id: meta4
- uses: docker/metadata-action@v5.0.0
+ uses: docker/metadata-action@v5.5.1
with:
images: |
ghcr.io/openimsdk/openim-msggateway
@@ -224,7 +224,7 @@ jobs:
- name: Extract metadata (tags, labels) for Docker openim-msgtransfer
id: meta5
- uses: docker/metadata-action@v5.0.0
+ uses: docker/metadata-action@v5.5.1
with:
images: |
ghcr.io/openimsdk/openim-msgtransfer
@@ -255,7 +255,7 @@ jobs:
- name: Extract metadata (tags, labels) for Docker openim-push
id: meta6
- uses: docker/metadata-action@v5.0.0
+ uses: docker/metadata-action@v5.5.1
with:
images: |
ghcr.io/openimsdk/openim-push
@@ -286,7 +286,7 @@ jobs:
- name: Extract metadata (tags, labels) for Docker openim-rpc-auth
id: meta7
- uses: docker/metadata-action@v5.0.0
+ uses: docker/metadata-action@v5.5.1
with:
images: |
ghcr.io/openimsdk/openim-rpc-auth
@@ -317,7 +317,7 @@ jobs:
- name: Extract metadata (tags, labels) for Docker openim-rpc-conversation
id: meta8
- uses: docker/metadata-action@v5.0.0
+ uses: docker/metadata-action@v5.5.1
with:
images: |
ghcr.io/openimsdk/openim-rpc-conversation
@@ -348,7 +348,7 @@ jobs:
- name: Extract metadata (tags, labels) for Docker openim-rpc-friend
id: meta9
- uses: docker/metadata-action@v5.0.0
+ uses: docker/metadata-action@v5.5.1
with:
images: |
ghcr.io/openimsdk/openim-rpc-friend
@@ -379,7 +379,7 @@ jobs:
- name: Extract metadata (tags, labels) for Docker openim-rpc-group
id: meta10
- uses: docker/metadata-action@v5.0.0
+ uses: docker/metadata-action@v5.5.1
with:
images: |
ghcr.io/openimsdk/openim-rpc-group
@@ -410,7 +410,7 @@ jobs:
- name: Extract metadata (tags, labels) for Docker openim-rpc-msg
id: meta11
- uses: docker/metadata-action@v5.0.0
+ uses: docker/metadata-action@v5.5.1
with:
images: |
ghcr.io/openimsdk/openim-rpc-msg
@@ -441,7 +441,7 @@ jobs:
- name: Extract metadata (tags, labels) for Docker openim-rpc-third
id: meta12
- uses: docker/metadata-action@v5.0.0
+ uses: docker/metadata-action@v5.5.1
with:
images: |
ghcr.io/openimsdk/openim-rpc-third
@@ -472,7 +472,7 @@ jobs:
- name: Extract metadata (tags, labels) for Docker openim-rpc-user
id: meta13
- uses: docker/metadata-action@v5.0.0
+ uses: docker/metadata-action@v5.5.1
with:
images: |
ghcr.io/openimsdk/openim-rpc-user
diff --git a/.github/workflows/e2e-test.yml b/.github/workflows/e2e-test.yml
index 21bb4986e..b5f901d25 100644
--- a/.github/workflows/e2e-test.yml
+++ b/.github/workflows/e2e-test.yml
@@ -34,7 +34,7 @@ jobs:
steps:
- name: Set up Go 1.21
- uses: actions/setup-go@v4
+ uses: actions/setup-go@v5
with:
go-version: 1.21
id: go
@@ -60,7 +60,7 @@ jobs:
uses: actions/checkout@v4
- name: Set up Go ${{ matrix.go_version }}
- uses: actions/setup-go@v4
+ uses: actions/setup-go@v5
with:
go-version: ${{ matrix.go_version }}
id: go
@@ -92,6 +92,7 @@ jobs:
- name: Exec OpenIM API test
run: |
+ sudo make test-api
mkdir -p ./tmp
touch ./tmp/test.md
echo "# OpenIM Test" >> ./tmp/test.md
@@ -104,6 +105,7 @@ jobs:
- name: Exec OpenIM E2E Test
run: |
+ sudo make test-e2e
echo "" >> ./tmp/test.md
echo "## OpenIM E2E Test" >> ./tmp/test.md
echo "Command Output for OpenIM E2E Test
" >> ./tmp/test.md
diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml
index 67dc5a6b8..31e491d6b 100644
--- a/.github/workflows/golangci-lint.yml
+++ b/.github/workflows/golangci-lint.yml
@@ -24,12 +24,14 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- - uses: actions/setup-go@v4
+ - uses: actions/setup-go@v5
with:
go-version: '1.21'
cache: false
+ - name: OpenIM Scripts Verification(make verify)
+ run: sudo make verify
- name: golangci-lint
- uses: golangci/golangci-lint-action@v3.7.0
+ uses: golangci/golangci-lint-action@v4.0.0
with:
# Require: version of golangci-lint to use in form of v1.2 or v1.2.3 or `latest` to use the latest version
version: v1.54
@@ -47,4 +49,4 @@ jobs:
only-new-issues: true
# Optional:The mode to install golangci-lint. It can be 'binary' or 'goinstall'.
- # install-mode: "goinstall"
\ No newline at end of file
+ # install-mode: "goinstall"
diff --git a/.github/workflows/greetings.yml b/.github/workflows/greetings.yml
index a92ed40ad..b1c85ee37 100644
--- a/.github/workflows/greetings.yml
+++ b/.github/workflows/greetings.yml
@@ -26,7 +26,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- - uses: actions/first-interaction@v1.2.0
+ - uses: actions/first-interaction@v1.3.0
with:
repo-token: ${{ secrets.BOT_GITHUB_TOKEN }}
pr-message: |
diff --git a/.github/workflows/help-comment-issue.yml b/.github/workflows/help-comment-issue.yml
index dce858197..c4e72ffc6 100644
--- a/.github/workflows/help-comment-issue.yml
+++ b/.github/workflows/help-comment-issue.yml
@@ -26,7 +26,7 @@ jobs:
issues: write
steps:
- name: Add comment
- uses: peter-evans/create-or-update-comment@v3
+ uses: peter-evans/create-or-update-comment@v4
with:
issue-number: ${{ github.event.issue.number }}
token: ${{ secrets.BOT_GITHUB_TOKEN }}
diff --git a/.github/workflows/link-pr.yml b/.github/workflows/link-pr.yml
index 768742eee..6c5ff6c5b 100644
--- a/.github/workflows/link-pr.yml
+++ b/.github/workflows/link-pr.yml
@@ -27,7 +27,7 @@ jobs:
- name: Link Checker
id: lychee
- uses: lycheeverse/lychee-action@v1.8.0
+ uses: lycheeverse/lychee-action@v1.9.3
with:
# For parameter description, see https://github.com/lycheeverse/lychee#commandline-parameters
# Actions Link address -> https://github.com/lycheeverse/lychee-action
@@ -45,7 +45,7 @@ jobs:
- name: Create Issue From File
if: env.lychee_exit_code != 0
- uses: peter-evans/create-issue-from-file@v4
+ uses: peter-evans/create-issue-from-file@v5
with:
title: Bug reports for links in OpenIM docs
content-filepath: ./lychee/out.md
diff --git a/.github/workflows/lock-issue.yml b/.github/workflows/lock-issue.yml
index 6a9aed9ba..edf280965 100644
--- a/.github/workflows/lock-issue.yml
+++ b/.github/workflows/lock-issue.yml
@@ -30,7 +30,7 @@ jobs:
action:
runs-on: ubuntu-latest
steps:
- - uses: dessant/lock-threads@v4
+ - uses: dessant/lock-threads@v5
with:
github-token: ${{ secrets.BOT_GITHUB_TOKEN }}
issue-inactive-days: '365'
diff --git a/.github/workflows/milestone.yml b/.github/workflows/milestone.yml
index e0731b25f..ecd64656a 100644
--- a/.github/workflows/milestone.yml
+++ b/.github/workflows/milestone.yml
@@ -39,7 +39,7 @@ jobs:
statuses: none
steps:
- - uses: actions/github-script@v6 # v6
+ - uses: actions/github-script@v7 # v6
with:
script: |
if (!context.payload.pull_request.merged) {
diff --git a/.github/workflows/opencommit.yml b/.github/workflows/opencommit.yml
index 629a67aae..d483ef1f6 100644
--- a/.github/workflows/opencommit.yml
+++ b/.github/workflows/opencommit.yml
@@ -28,10 +28,10 @@ jobs:
permissions: write-all
steps:
- name: Setup Node.js Environment
- uses: actions/setup-node@v2
+ uses: actions/setup-node@v4
with:
node-version: '16'
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: di-sukharev/opencommit@github-action-v1.0.4
diff --git a/.github/workflows/openimci.yml b/.github/workflows/openimci.yml
index 8aa38d941..d10033a1c 100644
--- a/.github/workflows/openimci.yml
+++ b/.github/workflows/openimci.yml
@@ -59,7 +59,7 @@ jobs:
uses: actions/checkout@v4
- name: Set up Go ${{ matrix.go_version }}
- uses: actions/setup-go@v4
+ uses: actions/setup-go@v5
with:
go-version: ${{ matrix.go_version }}
id: go
@@ -70,9 +70,6 @@ jobs:
version: '3.x' # If available, use the latest major version that's compatible
repo-token: ${{ secrets.GITHUB_TOKEN }}
- - name: OpenIM Scripts Verification(make verify)
- run: sudo make verify
-
- name: Module Operations
run: |
sudo make tidy
@@ -194,7 +191,7 @@ jobs:
uses: actions/checkout@v4
- name: Set up Go ${{ matrix.go_version }}
- uses: actions/setup-go@v4
+ uses: actions/setup-go@v5
with:
go-version: ${{ matrix.go_version }}
id: go
@@ -279,7 +276,7 @@ jobs:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Go ${{ matrix.go_version }}
- uses: actions/setup-go@v4
+ uses: actions/setup-go@v5
with:
go-version: ${{ matrix.go_version }}
id: go
diff --git a/.github/workflows/project-progress.yml b/.github/workflows/project-progress.yml
index 3ec8b7b1f..87a4c1381 100644
--- a/.github/workflows/project-progress.yml
+++ b/.github/workflows/project-progress.yml
@@ -24,13 +24,16 @@ on:
pull_request:
types:
- assigned
+ branches-ignore:
+ - 'asf-auto-updates'
+ - 'ignore'
jobs:
move-assigned-card:
runs-on: ubuntu-latest
steps:
- - uses: alex-page/github-project-automation-plus@v0.8.3
+ - uses: alex-page/github-project-automation-plus@v0.9.0
with:
project: openim-powerful
column: In Progress
- repo-token: ${{ secrets.BOT_GITHUB_TOKEN }}
\ No newline at end of file
+ repo-token: ${{ secrets.BOT_GITHUB_TOKEN }}
diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml
index 6f39c93b2..c123566f1 100644
--- a/.github/workflows/pull-request.yml
+++ b/.github/workflows/pull-request.yml
@@ -33,7 +33,7 @@ jobs:
- uses: actions/setup-node@v4
- name: Setup Go
- uses: actions/setup-go@v4
+ uses: actions/setup-go@v5
- name: Run go modules tidy
run: |
sudo apt-get install jq
@@ -74,6 +74,17 @@ jobs:
echo $latest_tag > pkg/common/config/version
continue-on-error: true
+ - name: Gen CHANGELOG file
+ run: |
+ current_tag=$(git describe --tags --abbrev=0)
+ version=$(echo "$current_tag" | sed -E 's/^v?([0-9]+)\.([0-9]+)\..*$/\1.\2/')
+ echo "OpenIM Version: $version"
+ make tools.install.git-chglog
+ cd CHANGELOG
+ git-chglog --tag-filter-pattern "v${version}.*" -o CHANGELOG-${version}.md
+ cd ..
+ continue-on-error: true
+
- name: Run unit test and get test coverage
run: |
make cover
@@ -87,7 +98,7 @@ jobs:
continue-on-error: true
- name: Create Pull Request
- uses: peter-evans/create-pull-request@v5
+ uses: peter-evans/create-pull-request@v6
with:
token: ${{ secrets.BOT_GITHUB_TOKEN }}
commit-message: "cicd: bump League Patch"
diff --git a/.github/workflows/release-drafter.yml b/.github/workflows/release-drafter.yml
index 0eed80911..251f55876 100644
--- a/.github/workflows/release-drafter.yml
+++ b/.github/workflows/release-drafter.yml
@@ -46,7 +46,7 @@ jobs:
# echo "GHE_HOST=${GITHUB_SERVER_URL##https:\/\/}" >> $GITHUB_ENV
# Drafts your next Release notes as Pull Requests are merged into "master"
- - uses: release-drafter/release-drafter@v5
+ - uses: release-drafter/release-drafter@v6
# (Optional) specify config name to use, relative to .github/. Default: release-drafter.yml
# with:
# config-name: my-config.yml
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index f2147c865..9950bdabb 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -33,7 +33,7 @@ jobs:
with:
fetch-depth: 0
- run: git fetch --force --tags
- - uses: actions/setup-go@v4
+ - uses: actions/setup-go@v5
with:
go-version: stable
# More assembly might be required: Docker logins, GPG, etc. It all depends
@@ -71,7 +71,7 @@ jobs:
version: 3.x
repo-token: ${{ secrets.GITHUB_TOKEN }}
- uses: docker/setup-qemu-action@326560df218a7ea9cf6ab49bbc88b8b306bb437e # v2
- - uses: actions/cache@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8 # v3
+ - uses: actions/cache@a2ed59d39b352305bdd2f628719a53b2cc4f9613 # v3
with:
path: |
./_output/dist/*.deb
diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml
index ba767f167..da44cb7f3 100644
--- a/.github/workflows/stale.yml
+++ b/.github/workflows/stale.yml
@@ -32,7 +32,7 @@ jobs:
pull-requests: write
steps:
- - uses: actions/stale@v8
+ - uses: actions/stale@v9
with:
repo-token: ${{ secrets.BOT_GITHUB_TOKEN }}
days-before-stale: 60
diff --git a/.golangci.yml b/.golangci.yml
index b129ffd68..9c7960642 100644
--- a/.golangci.yml
+++ b/.golangci.yml
@@ -40,10 +40,14 @@ run:
# "/" will be replaced by current OS file path separator to properly work
# on Windows.
skip-dirs:
+ - components
+ - docs
- util
- .*~
- api/swagger/docs
- server/docs
+ - components/mnt/config/certs
+ - logs
# default is true. Enables skipping of directories:
# vendor$, third_party$, testdata$, examples$, Godeps$, builtin$
@@ -58,6 +62,12 @@ run:
skip-files:
- ".*\\.my\\.go$"
- _test.go
+ - ".*_test.go"
+ - "mocks/"
+ - ".github/"
+ - "logs/"
+ - "_output/"
+ - "components/"
# by default isn't set. If set we pass it to "go list -mod={option}". From "go help modules":
# If invoked with -mod=readonly, the go command is disallowed from the implicit
@@ -108,7 +118,6 @@ linters-settings:
right-to-left-isolate: true
first-strong-isolate: true
pop-directional-isolate: true
- dogsled:
# checks assignments with too many blank identifiers; default is 2
max-blank-identifiers: 2
dupl:
@@ -131,8 +140,8 @@ linters-settings:
# path to a file containing a list of functions to exclude from checking
# see https://github.com/kisielk/errcheck#excluding-functions for details
- #exclude: errcheck.txt
-
+ # exclude: errcheck.txt
+
errorlint:
# Check whether fmt.Errorf uses the %w verb for formatting errors. See the readme for caveats
errorf: true
@@ -418,7 +427,7 @@ linters-settings:
govet:
# report about shadowed variables
- check-shadowing: true
+ check-shadowing: false
# settings per analyzer
settings:
@@ -489,9 +498,9 @@ linters-settings:
- github.com\/user\/package\/v4\.Type
lll:
- # max line length, lines longer will be reported. Default is 120.
+ # max line length, lines longer will be reported. Default is 250.
# '\t' is counted as 1 character by default, and can be changed with the tab-width option
- line-length: 240
+ line-length: 250
# tab width in spaces. Default to 1.
tab-width: 4
maligned:
@@ -715,17 +724,33 @@ linters:
# enable-all: true
disable-all: true
enable:
- - typecheck # 基本的类型检查
- - gofmt # 格式检查
- - govet # Go 语言的标准检查工具
- - gosimple # 简化代码的建议
- - misspell # 拼写错误
- - staticcheck # 静态检查
- - unused # 未使用的代码检查
- - goimports # 检查导入是否正确排序和格式化
- - godot # 注释句点检查
- - bodyclose # 确保 HTTP response body 被关闭
- - errcheck # 检查是否遗漏了错误返回值
+ - typecheck # Basic type checking
+ - gofmt # Format check
+ - govet # Go's standard linting tool
+ - gosimple # Suggestions for simplifying code
+ - errcheck
+ - decorder
+ - ineffassign
+ - revive
+ - reassign
+ - tparallel
+ - unconvert
+ - dupl
+ - dupword
+ - errname
+ - gci
+ - goheader
+ - goprintffuncname
+ - gosec
+ - misspell # Spelling mistakes
+ - staticcheck # Static analysis
+ - unused # Checks for unused code
+ - goimports # Checks if imports are correctly sorted and formatted
+ - godot # Checks for comment punctuation
+ - bodyclose # Ensures HTTP response body is closed
+ - stylecheck # Style checker for Go code
+ - unused # Checks for unused code
+ - errcheck # Checks for missed error returns
fast: true
issues:
@@ -792,6 +817,11 @@ issues:
- lll
source: "^//go:generate "
+ - text: ".*[\u4e00-\u9fa5]+.*"
+ linters:
+ - golint
+ source: "^//.*$"
+
# Independently from option `exclude` we use default exclude patterns,
# it can be disabled by this option. To list all
# excluded by default patterns execute `golangci-lint run --help`.
@@ -852,4 +882,4 @@ severity:
rules:
- linters:
- dupl
- severity: info
\ No newline at end of file
+ severity: info
diff --git a/CHANGELOG/CHANGELOG-3.5.md b/CHANGELOG/CHANGELOG-3.5.md
index ed9ba77c6..b929922f1 100644
--- a/CHANGELOG/CHANGELOG-3.5.md
+++ b/CHANGELOG/CHANGELOG-3.5.md
@@ -8,6 +8,12 @@
## [Unreleased]
+
+## [v3.5.1-alpha.2] - 2024-01-26
+
+
+## [v3.5.1-rc.1] - 2024-01-23
+
## [v3.5.1-alpha.1] - 2024-01-09
@@ -59,7 +65,9 @@
- Merge branch 'tuoyun'
-[Unreleased]: https://github.com/openimsdk/open-im-server/compare/v3.5.1-alpha.1...HEAD
+[Unreleased]: https://github.com/openimsdk/open-im-server/compare/v3.5.1-alpha.2...HEAD
+[v3.5.1-alpha.2]: https://github.com/openimsdk/open-im-server/compare/v3.5.1-rc.1...v3.5.1-alpha.2
+[v3.5.1-rc.1]: https://github.com/openimsdk/open-im-server/compare/v3.5.1-alpha.1...v3.5.1-rc.1
[v3.5.1-alpha.1]: https://github.com/openimsdk/open-im-server/compare/v3.5.0...v3.5.1-alpha.1
[v3.5.0]: https://github.com/openimsdk/open-im-server/compare/v3.5.1...v3.5.0
[v3.5.1]: https://github.com/openimsdk/open-im-server/compare/v3.5.1-bate.1...v3.5.1
diff --git a/CONTRIBUTING-zh_CN.md b/CONTRIBUTING-zh_CN.md
new file mode 100644
index 000000000..ee3c0b8f8
--- /dev/null
+++ b/CONTRIBUTING-zh_CN.md
@@ -0,0 +1,33 @@
+# How do I contribute code to OpenIM
+
+
+ Englist ·
+ 中文 ·
+ Українська ·
+ Česky ·
+ Magyar ·
+ Español ·
+ فارسی ·
+ Français ·
+ Deutsch ·
+ Polski ·
+ Indonesian ·
+ Suomi ·
+ മലയാളം ·
+ 日本語 ·
+ Nederlands ·
+ Italiano ·
+ Русский ·
+ Português (Brasil) ·
+ Esperanto ·
+ 한국어 ·
+ العربي ·
+ Tiếng Việt ·
+ Dansk ·
+ Ελληνικά ·
+ Türkçe
+
+
+
+
+
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index ee275e7ad..f7d2c0749 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -1,6 +1,38 @@
-# Contributing to Open-IM-Server
+# How do I contribute code to OpenIM
-So, you want to hack on Open-IM-Server? Yay!
+
+ Englist ·
+ 中文 ·
+ Українська ·
+ Česky ·
+ Magyar ·
+ Español ·
+ فارسی ·
+ Français ·
+ Deutsch ·
+ Polski ·
+ Indonesian ·
+ Suomi ·
+ മലയാളം ·
+ 日本語 ·
+ Nederlands ·
+ Italiano ·
+ Русский ·
+ Português (Brasil) ·
+ Esperanto ·
+ 한국어 ·
+ العربي ·
+ Tiếng Việt ·
+ Dansk ·
+ Ελληνικά ·
+ Türkçe
+
+
+
+
+
+
+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.
@@ -12,7 +44,7 @@ This document provides guidelines and best practices to help you contribute effe
## 📇Topics
-- [Contributing to Open-IM-Server](#contributing-to-open-im-server)
+- [How do I contribute code to OpenIM](#how-do-i-contribute-code-to-openim)
- [📇Topics](#topics)
- [What we expect of you](#what-we-expect-of-you)
- [Code of ConductCode of Conduct](#code-of-conductcode-of-conduct)
@@ -32,13 +64,13 @@ This document provides guidelines and best practices to help you contribute effe
## What we expect of you
-We hope that anyone can join Open-IM-Server , even if you are a student, writer, translator
+We hope that anyone can join open-im-server , even if you are a student, writer, translator
-Please meet the minimum version of the Go language published in [go.mod](./go.mod). If you want to manage the Go language version, we provide tools to install [gvm](https://github.com/moovweb/gvm) in our [Makefile](./Makefile)
+Please meet the minimum version of the Go language published in [go.mod](./go.mod). If you want to manage the Go language version, we provide tools tHow do I contribute code to OpenIMo install [gvm](https://github.com/moovweb/gvm) in our [Makefile](./Makefile)
-You'd better use Linux OR WSL as the development environment, Linux with [Makefile](./Makefile) can help you quickly build and test Open-IM-Server project.
+You'd better use Linux OR WSL as the development environment, Linux with [Makefile](./Makefile) can help you quickly build and test open-im-server project.
-If you are familiar with [Makefile](./Makefile) , you can easily see the clever design of the Open-IM-Server Makefile. Storing the necessary tools such as golangci in the `/tools` directory can avoid some tool version issues.
+If you are familiar with [Makefile](./Makefile) , you can easily see the clever design of the open-im-server Makefile. Storing the necessary tools such as golangci in the `/tools` directory can avoid some tool version issues.
The [Makefile](./Makefile) is for every developer, even if you don't know how to use the Makefile tool, don't worry, we provide two great commands to get you up to speed with the Makefile architecture, `make help` and `make help-all`, it can reduce problems of the developing environment.
@@ -52,7 +84,7 @@ In accordance with the naming conventions adopted by OpenIM and drawing referenc
#### 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 bug, try to fix it!
@@ -67,8 +99,8 @@ Every action to make project Open-IM-Server better is encouraged. On GitHub, eve
#### Where should I start?
-+ 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.
++ 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.
+ 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.
@@ -85,7 +117,7 @@ When documenting a new design, we recommend a 2-step approach:
1. Use the short-form RFC template to outline your ideas and get early feedback.
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.
+ Once there is general agreement that the feature is useful, create a GitHub issue to track the discussion. The issue should include information about the requirements and use cases that it is trying to address.
@@ -95,13 +127,27 @@ But keep in mind that there is no guarantee of it being accepted and so it is us
## Getting Started
-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//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//open-im-server.git` to clone repository to your local machine. Then you can create new branches to finish the change you wish to make.
-3. **Set Remote** upstream to be `https://github.com/openimsdk/open-im-server.git` using the following two commands:
+3. **Initialize Git Hooks with `make init-githooks`**
+
+ After cloning the repository, it's recommended to set up Git hooks to streamline your workflow and ensure your contributions adhere to OpenIM's community standards. Git hooks are scripts that run automatically every time a particular event occurs in a Git repository, such as before a commit or push. To initialize Git hooks for the OpenIM server repository, use the `make init-githooks` command.
+
+ - **Enabling Git Hooks Mode**: By running `make init-githooks` and entering `1` when prompted, you enable Git hooks mode. This action will generate a series of hooks within the `.git/hooks/` directory. These hooks impose certain checks on your commits and pushes, ensuring they meet the quality and standards expected by the OpenIM community. For instance, commit hooks might enforce a specific commit message format, while push hooks could check for code style or linting issues.
+
+ - **Benefits for First-Time Contributors**: This setup is especially beneficial for new contributors. It guides you to make professional, community-standard-compliant Pull Requests (PRs) and PR descriptions right from your first contribution. By automating checks and balances, it reduces the chances of common mistakes and speeds up the review process.
+
+ - **Disabling Git Hooks**: If for any reason you wish to remove the Git hooks, simply run `make init-githooks` again and enter `2` when prompted. This will delete the existing Git hooks, removing the automatic checks and constraints from your Git operations. However, keep in mind that manually ensuring your contributions adhere to community standards without the aid of Git hooks requires diligence.
+
+ > [!NOTE] Utilizing Git hooks through the `make init-githooks` command is a straightforward yet powerful way to ensure your contributions are consistent and high-quality. It's a step towards fostering a professional and efficient development environment in the OpenIM project.
+
+
+
+4. **Set Remote** upstream to be `https://github.com/openimsdk/open-im-server.git` using the following two commands:
```bash
❯ git remote add upstream https://github.com/openimsdk/open-im-server.git
@@ -112,18 +158,18 @@ To propose PR for the Open-IM-Server item, we assume you have registered a GitHu
```bash
❯ git remote -v
- origin https://github.com//Open-IM-Server.git (fetch)
- origin https://github.com//Open-IM-Server.git (push)
+ origin https://github.com//open-im-server.git (fetch)
+ origin https://github.com//open-im-server.git (push)
upstream https://github.com/openimsdk/open-im-server.git (fetch)
upstream no-pushing (push)
```
Adding this, we can easily synchronize local branches with upstream branches.
-4. Create a new branch for your changes (use a descriptive name, such as `fix-bug-123` or `add-new-feature`).
+5. Create a new branch for your changes (use a descriptive name, such as `fix-bug-123` or `add-new-feature`).
```bash
- ❯ cd Open-IM-Server
+ ❯ cd open-im-server
❯ git fetch upstream
❯ git checkout upstream/main
```
@@ -136,7 +182,8 @@ To propose PR for the Open-IM-Server item, we assume you have registered a GitHu
Make any change on the `new-branch` then use [Makefile](./Makefile) build and test your codes.
-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
❯ git rebase upstream/main
@@ -145,7 +192,7 @@ To propose PR for the Open-IM-Server item, we assume you have registered a GitHu
❯ git commit -a -s -m "message for your changes" # -s adds a Signed-off-by trailer
```
-6. **Push your branch** to your forked repository, it is recommended to have only one commit for a PR.
+7. **Push your branch** to your forked repository, it is recommended to have only one commit for a PR.
```bash
# sync up with upstream
@@ -177,12 +224,78 @@ To propose PR for the Open-IM-Server item, we assume you have registered a GitHu
❯ git rebase upstream/main # rebase the current branch to upstream/main branch
❯ git add -A
❯ git commit -m -s "feat: feature two"
- # then create pull request, and merge
```
-7. **Open a pull request** to `openimsdk/open-im-server:main`
+ **Verifying Your Pull Request with `make all` Command**
+
+ Before verifying, you may need to complete the basic deployment of OpenIM to get familiar with the deployment status of OpenIM. Please read [this deployment document](https://docs.openim.io/zh-Hans/guides/gettingStarted/imSourceCodeDeployment), which will tell you how to deploy OpenIM middleware and OpenIM services in detail
+
+ Before submitting your Pull Request (PR), it's crucial to ensure that it passes all the necessary checks and verifications to maintain the quality and integrity of the OpenIM server project. To facilitate this process, we have encapsulated a series of validation steps into the `make all` command.
+
+ - **Purpose of `make all` Command**: The `make all` command serves as a comprehensive pre-PR verification tool. It sequentially executes a variety of tasks designed to scrutinize your changes from multiple angles, ensuring they are ready for submission.
+
+ - **Included Commands**:
+ - `tidy`: Cleans up the module by removing unused dependencies.
+ - `gen`: Generates necessary files from templates or specifications, ensuring that your codebase is up-to-date with its dependencies.
+ - `add-copyright`: Checks for and adds copyright notices to files, ensuring compliance with legal requirements.
+ - `verify`: Verifies the integrity and consistency of the code, dependencies, and various checks.
+ - `test-api`: Runs API tests to ensure that your changes do not break any existing functionality and adhere to the expected behaviors.
+ - `lint`: Analyzes the code for potential stylistic or programming errors, enforcing the project's coding standards.
+ - `cover`: Measures the code coverage of tests, helping you understand how much of the code is being tested.
+ - `restart`: (Optionally) restarts services or applications to ensure that changes are correctly applied and functioning in a live environment.
+
+ - **Executing the Command**: To run the `make all` command, simply navigate to the root directory of your cloned repository in your terminal and execute:
+ ```bash
+ make all
+ ```
+ This command will sequentially perform all the listed actions, outputting any warnings or errors encountered during the process. It's a vital step to catch any issues early and ensure your contribution meets the quality standards set by the OpenIM community.
+
+ - **Benefits**: By using `make all` for pre-PR verification, you significantly increase the likelihood of your PR being accepted on the first review. It not only demonstrates your commitment to quality but also streamlines the review process by minimizing back-and-forth due to common issues that can be caught automatically.
+
+
+ **Troubleshooting Git Push Failures**
+
+ When working with Git, encountering errors during push operations is not uncommon. Two primary reasons you might face push failures are due to firewall restrictions or authentication issues. 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.
+
+ > [!TIP] There is a [good blog post documenting](https://nsddd.top/posts/participating-in-this-project/) the entire push contribution process.
+
## Style and Specification
@@ -190,15 +303,15 @@ We divide the problem into security and general problems:
#### 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.
#### 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.
@@ -206,20 +319,20 @@ To make the issue details as standard as possible, we setup an [ISSUE TEMPLATE](
+ bug report
+ feature request
-+ Open-IM-Server performance issues
++ open-im-server performance issues
+ feature proposal
+ feature design
+ help wanted
+ doc incomplete
+ test improvement
-+ any questions on Open-IM-Server project
++ any questions on open-im-server project
+ 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
-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:**
@@ -262,7 +375,7 @@ An example for this could be:
#### 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.
@@ -311,11 +424,11 @@ git() {
#### 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.
-+ [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.
++ [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.
++ [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.
@@ -328,20 +441,20 @@ Please obey the following rules to better format the docs, which would greatly i
## 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;
+ 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;
-+ discuss about Open-IM-Server to make things clearer;
-+ advocate [Open-IM-Server](https://google.com/search?q=Open-IM-Server) technology beyond GitHub;
-+ write blogs on Open-IM-Server and so on.
++ discuss about open-im-server to make things clearer;
++ advocate [open-im-server](https://google.com/search?q=open-im-server) technology beyond GitHub;
++ write blogs on open-im-server and so on.
In a word, **ANY HELP IS CONTRIBUTION.**
## 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:
@@ -366,17 +479,23 @@ Such a commit can get produced as follows:
❯ git commit --allow-empty -m "chore: release 0.0.3" -m "Release-As: 0.0.3
````
+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
-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:
-+
: 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.
++
: 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.
+
: 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.
-+
: 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.
-+
: 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.
++
: 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.
++
: 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.
diff --git a/Makefile b/Makefile
index 4faf1c21d..89b9e4152 100644
--- a/Makefile
+++ b/Makefile
@@ -184,7 +184,7 @@ test-e2e:
imports:
@$(MAKE) go.imports
-## clean: Remove all files that are created by building. ✨
+## clean: Delete all files created by the build, as well as all log files. ✨
.PHONY: clean
clean:
@$(MAKE) go.clean
diff --git a/README.md b/README.md
index 3876fcd7a..175db3326 100644
--- a/README.md
+++ b/README.md
@@ -17,14 +17,49 @@
[](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/)
-[**English**](./README.md) •
-[**简体中文**](./README-zh_CN.md) •
-[**Docs**](https://openim.io/en)
+
+
+ Englist ·
+ 中文 ·
+ Українська ·
+ Česky ·
+ Magyar ·
+ Español ·
+ فارسی ·
+ Français ·
+ Deutsch ·
+ Polski ·
+ Indonesian ·
+ Suomi ·
+ മലയാളം ·
+ 日本語 ·
+ Nederlands ·
+ Italiano ·
+ Русский ·
+ Português (Brasil) ·
+ Esperanto ·
+ 한국어 ·
+ العربي ·
+ Tiếng Việt ·
+ Dansk ·
+ Ελληνικά ·
+ Türkçe
+
+
+## :busts_in_silhouette: Community
+
++ 💬 [Follow our Twitter account](https://twitter.com/founder_im63606)
++ 👫 [Join our Reddit](https://www.reddit.com/r/OpenIMessaging)
++ 🚀 [Join our Slack community](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q)
++ :eyes: [Join our wechat (微信群)](https://openim-1253691595.cos.ap-nanjing.myqcloud.com/WechatIMG20.jpeg)
++ 📚 [OpenIM Community](https://github.com/OpenIMSDK/community)
++ 💕 [OpenIM Interest Group](https://github.com/Openim-sigs)
+
## Ⓜ️ About OpenIM
OpenIM is a service platform specifically designed for integrating chat, audio-video calls, notifications, and AI chatbots into applications. It provides a range of powerful APIs and Webhooks, enabling developers to easily incorporate these interactive features into their applications. OpenIM is not a standalone chat application, but rather serves as a platform to support other applications in achieving rich communication functionalities. The following diagram illustrates the interaction between AppServer, AppClient, OpenIMServer, and OpenIMSDK to explain in detail.
@@ -68,6 +103,13 @@ It is built using Golang and supports cross-platform deployment, ensuring a cons
👉 **[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
We support many platforms. Here are the addresses for quick experience on the web side:
@@ -85,6 +127,8 @@ We support many platforms. Here are the addresses for quick experience on the we
[](https://vscode.dev/github/openimsdk/open-im-server)
+[](https://codespaces.new/openimsdk/open-im-server)
+
OpenIM Our goal is to build a top-level open source community. We have a set of standards, in the [Community repository](https://github.com/OpenIMSDK/community).
If you'd like to contribute to this Open-IM-Server repository, please read our [contributor documentation](https://github.com/openimsdk/open-im-server/blob/main/CONTRIBUTING.md).
@@ -121,14 +165,6 @@ Before you start, please make sure your changes are in demand. The best for that
- [Manage backend and monitor deployment](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/prometheus-grafana.md)
- [Mac Developer Deployment Guide for OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/mac-developer-deployment-guide.md)
-
-## :busts_in_silhouette: Community
-
-+ 📚 [OpenIM Community](https://github.com/OpenIMSDK/community)
-+ 💕 [OpenIM Interest Group](https://github.com/Openim-sigs)
-+ 🚀 [Join our Slack community](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q)
-+ :eyes: [Join our wechat (微信群)](https://openim-1253691595.cos.ap-nanjing.myqcloud.com/WechatIMG20.jpeg)
-
## :calendar: Community Meetings
We want anyone to get involved in our community and contributing code, we offer gifts and rewards, and we welcome you to join us every Thursday night.
diff --git a/README-zh_CN.md b/README_zh_CN.md
similarity index 66%
rename from README-zh_CN.md
rename to README_zh_CN.md
index 12a56d4f6..7eabfa509 100644
--- a/README-zh_CN.md
+++ b/README_zh_CN.md
@@ -4,29 +4,51 @@
-
- ⭐️ Open source Instant Messaging Server ⭐️
-
+
+[](https://github.com/openimsdk/open-im-server/stargazers)
+[](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/)
-
-
-
-
-
-
-
-
-
-
- English •
- 简体中文 •
- Docs
+ Englist ·
+ 中文 ·
+ Українська ·
+ Česky ·
+ Magyar ·
+ Español ·
+ فارسی ·
+ Français ·
+ Deutsch ·
+ Polski ·
+ Indonesian ·
+ Suomi ·
+ മലയാളം ·
+ 日本語 ·
+ Nederlands ·
+ Italiano ·
+ Русский ·
+ Português (Brasil) ·
+ Esperanto ·
+ 한국어 ·
+ العربي ·
+ Tiếng Việt ·
+ Dansk ·
+ Ελληνικά ·
+ Türkçe
+
+
## 🟢 扫描微信进群交流
@@ -39,8 +61,6 @@ OpenIM 是一个专门设计用于在应用程序中集成聊天、音视频通
-
-

## 🚀 关于 OpenIMSDK
diff --git a/cmd/openim-api/main.go b/cmd/openim-api/main.go
index f0b62e31f..ee19a5c60 100644
--- a/cmd/openim-api/main.go
+++ b/cmd/openim-api/main.go
@@ -15,114 +15,17 @@
package main
import (
- "context"
- "fmt"
- "net"
- "net/http"
_ "net/http/pprof"
- "os"
- "os/signal"
- "strconv"
- "syscall"
- "time"
- "github.com/OpenIMSDK/protocol/constant"
- "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/pkg/common/cmd"
- "github.com/openimsdk/open-im-server/v3/pkg/common/config"
- "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache"
- kdisc "github.com/openimsdk/open-im-server/v3/pkg/common/discoveryregister"
- ginprom "github.com/openimsdk/open-im-server/v3/pkg/common/ginprometheus"
- "github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics"
+ util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil"
)
func main() {
apiCmd := cmd.NewApiCmd()
apiCmd.AddPortFlag()
- apiCmd.AddApi(run)
+ apiCmd.AddPrometheusPortFlag()
if err := apiCmd.Execute(); err != nil {
- log.ZError(context.Background(), "API command execution failed", err)
- panic(err.Error())
+ util.ExitWithError(err)
}
}
-
-func run(port int, proPort int) error {
- log.ZInfo(context.Background(), "Openim api port:", "port", port, "proPort", proPort)
-
- if port == 0 || proPort == 0 {
- err := "port or proPort is empty:" + strconv.Itoa(port) + "," + strconv.Itoa(proPort)
- log.ZError(context.Background(), err, nil)
- return fmt.Errorf(err)
- }
-
- rdb, err := cache.NewRedis()
- if err != nil {
- log.ZError(context.Background(), "Failed to initialize Redis", err)
- return err
- }
- log.ZInfo(context.Background(), "api start init discov client")
-
- var client discoveryregistry.SvcDiscoveryRegistry
-
- // Determine whether zk is passed according to whether it is a clustered deployment
- client, err = kdisc.NewDiscoveryRegister(config.Config.Envs.Discovery)
- if err != nil {
- log.ZError(context.Background(), "Failed to initialize discovery register", 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)
- if config.Config.Prometheus.Enable {
- p := ginprom.NewPrometheus("app", prommetrics.GetGinCusMetrics("Api"))
- p.SetListenAddress(fmt.Sprintf(":%d", proPort))
- p.Use(router)
- }
- log.ZInfo(context.Background(), "api init router success")
-
- var address string
- if config.Config.Api.ListenIP != "" {
- address = net.JoinHostPort(config.Config.Api.ListenIP, strconv.Itoa(port))
- } else {
- 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}
- go func() {
- err = server.ListenAndServe()
- if err != nil && err != http.ErrServerClosed {
- log.ZError(context.Background(), "api run failed", err, "address", address)
- os.Exit(1)
- }
- }()
-
- sigs := make(chan os.Signal, 1)
- signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)
- <-sigs
-
- ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
- defer cancel()
-
- // graceful shutdown operation.
- if err := server.Shutdown(ctx); err != nil {
- log.ZError(context.Background(), "failed to api-server shutdown", err)
- return err
- }
-
- return nil
-}
diff --git a/cmd/openim-cmdutils/main.go b/cmd/openim-cmdutils/main.go
index 058aa2e29..f6b788933 100644
--- a/cmd/openim-cmdutils/main.go
+++ b/cmd/openim-cmdutils/main.go
@@ -16,6 +16,7 @@ package main
import (
"github.com/openimsdk/open-im-server/v3/pkg/common/cmd"
+ util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil"
)
func main() {
@@ -54,6 +55,6 @@ func main() {
// openIM clear msg --clearAll
msgUtilsCmd.AddCommand(&getCmd.Command, &fixCmd.Command, &clearCmd.Command)
if err := msgUtilsCmd.Execute(); err != nil {
- panic(err)
+ util.ExitWithError(err)
}
}
diff --git a/cmd/openim-crontask/main.go b/cmd/openim-crontask/main.go
index 3bd0d882b..b52029c64 100644
--- a/cmd/openim-crontask/main.go
+++ b/cmd/openim-crontask/main.go
@@ -15,13 +15,13 @@
package main
import (
- "github.com/openimsdk/open-im-server/v3/internal/tools"
"github.com/openimsdk/open-im-server/v3/pkg/common/cmd"
+ util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil"
)
func main() {
cronTaskCmd := cmd.NewCronTaskCmd()
- if err := cronTaskCmd.Exec(tools.StartTask); err != nil {
- panic(err.Error())
+ if err := cronTaskCmd.Exec(); err != nil {
+ util.ExitWithError(err)
}
}
diff --git a/cmd/openim-msggateway/main.go b/cmd/openim-msggateway/main.go
index 6d212e467..01b13560d 100644
--- a/cmd/openim-msggateway/main.go
+++ b/cmd/openim-msggateway/main.go
@@ -16,6 +16,7 @@ package main
import (
"github.com/openimsdk/open-im-server/v3/pkg/common/cmd"
+ util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil"
)
func main() {
@@ -23,8 +24,7 @@ func main() {
msgGatewayCmd.AddWsPortFlag()
msgGatewayCmd.AddPortFlag()
msgGatewayCmd.AddPrometheusPortFlag()
-
if err := msgGatewayCmd.Exec(); err != nil {
- panic(err.Error())
+ util.ExitWithError(err)
}
}
diff --git a/cmd/openim-msgtransfer/main.go b/cmd/openim-msgtransfer/main.go
index 6895bcecc..84fbbd2ea 100644
--- a/cmd/openim-msgtransfer/main.go
+++ b/cmd/openim-msgtransfer/main.go
@@ -16,6 +16,7 @@ package main
import (
"github.com/openimsdk/open-im-server/v3/pkg/common/cmd"
+ util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil"
)
func main() {
@@ -23,6 +24,6 @@ func main() {
msgTransferCmd.AddPrometheusPortFlag()
msgTransferCmd.AddTransferProgressFlag()
if err := msgTransferCmd.Exec(); err != nil {
- panic(err.Error())
+ util.ExitWithError(err)
}
}
diff --git a/cmd/openim-push/main.go b/cmd/openim-push/main.go
index c19cfda60..c7d29fc97 100644
--- a/cmd/openim-push/main.go
+++ b/cmd/openim-push/main.go
@@ -17,17 +17,14 @@ package main
import (
"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/config"
+ util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil"
)
func main() {
- pushCmd := cmd.NewRpcCmd(cmd.RpcPushServer)
+ pushCmd := cmd.NewRpcCmd(cmd.RpcPushServer, push.Start)
pushCmd.AddPortFlag()
pushCmd.AddPrometheusPortFlag()
if err := pushCmd.Exec(); err != nil {
- panic(err.Error())
- }
- if err := pushCmd.StartSvr(config.Config.RpcRegisterName.OpenImPushName, push.Start); err != nil {
- panic(err.Error())
+ util.ExitWithError(err)
}
}
diff --git a/cmd/openim-rpc/openim-rpc-auth/main.go b/cmd/openim-rpc/openim-rpc-auth/main.go
index 645d8cab8..da281b70e 100644
--- a/cmd/openim-rpc/openim-rpc-auth/main.go
+++ b/cmd/openim-rpc/openim-rpc-auth/main.go
@@ -17,17 +17,14 @@ package main
import (
"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/config"
+ util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil"
)
func main() {
- authCmd := cmd.NewRpcCmd(cmd.RpcAuthServer)
+ authCmd := cmd.NewRpcCmd(cmd.RpcAuthServer, auth.Start)
authCmd.AddPortFlag()
authCmd.AddPrometheusPortFlag()
if err := authCmd.Exec(); err != nil {
- panic(err.Error())
- }
- if err := authCmd.StartSvr(config.Config.RpcRegisterName.OpenImAuthName, auth.Start); err != nil {
- panic(err.Error())
+ util.ExitWithError(err)
}
}
diff --git a/cmd/openim-rpc/openim-rpc-conversation/main.go b/cmd/openim-rpc/openim-rpc-conversation/main.go
index 13d7db605..6e74b3251 100644
--- a/cmd/openim-rpc/openim-rpc-conversation/main.go
+++ b/cmd/openim-rpc/openim-rpc-conversation/main.go
@@ -17,17 +17,14 @@ package main
import (
"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/config"
+ util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil"
)
func main() {
- rpcCmd := cmd.NewRpcCmd(cmd.RpcConversationServer)
+ rpcCmd := cmd.NewRpcCmd(cmd.RpcConversationServer, conversation.Start)
rpcCmd.AddPortFlag()
rpcCmd.AddPrometheusPortFlag()
if err := rpcCmd.Exec(); err != nil {
- panic(err.Error())
- }
- if err := rpcCmd.StartSvr(config.Config.RpcRegisterName.OpenImConversationName, conversation.Start); err != nil {
- panic(err.Error())
+ util.ExitWithError(err)
}
}
diff --git a/cmd/openim-rpc/openim-rpc-friend/main.go b/cmd/openim-rpc/openim-rpc-friend/main.go
index ec18306a2..a307c01a1 100644
--- a/cmd/openim-rpc/openim-rpc-friend/main.go
+++ b/cmd/openim-rpc/openim-rpc-friend/main.go
@@ -17,17 +17,14 @@ package main
import (
"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/config"
+ util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil"
)
func main() {
- rpcCmd := cmd.NewRpcCmd(cmd.RpcFriendServer)
+ rpcCmd := cmd.NewRpcCmd(cmd.RpcFriendServer, friend.Start)
rpcCmd.AddPortFlag()
rpcCmd.AddPrometheusPortFlag()
if err := rpcCmd.Exec(); err != nil {
- panic(err.Error())
- }
- if err := rpcCmd.StartSvr(config.Config.RpcRegisterName.OpenImFriendName, friend.Start); err != nil {
- panic(err.Error())
+ util.ExitWithError(err)
}
}
diff --git a/cmd/openim-rpc/openim-rpc-group/main.go b/cmd/openim-rpc/openim-rpc-group/main.go
index 887329926..2afb7963c 100644
--- a/cmd/openim-rpc/openim-rpc-group/main.go
+++ b/cmd/openim-rpc/openim-rpc-group/main.go
@@ -17,17 +17,14 @@ package main
import (
"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/config"
+ util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil"
)
func main() {
- rpcCmd := cmd.NewRpcCmd(cmd.RpcGroupServer)
+ rpcCmd := cmd.NewRpcCmd(cmd.RpcGroupServer, group.Start)
rpcCmd.AddPortFlag()
rpcCmd.AddPrometheusPortFlag()
if err := rpcCmd.Exec(); err != nil {
- panic(err.Error())
- }
- if err := rpcCmd.StartSvr(config.Config.RpcRegisterName.OpenImGroupName, group.Start); err != nil {
- panic(err.Error())
+ util.ExitWithError(err)
}
}
diff --git a/cmd/openim-rpc/openim-rpc-msg/main.go b/cmd/openim-rpc/openim-rpc-msg/main.go
index dcc3abef5..bbffbcae7 100644
--- a/cmd/openim-rpc/openim-rpc-msg/main.go
+++ b/cmd/openim-rpc/openim-rpc-msg/main.go
@@ -17,17 +17,14 @@ package main
import (
"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/config"
+ util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil"
)
func main() {
- rpcCmd := cmd.NewRpcCmd(cmd.RpcMsgServer)
+ rpcCmd := cmd.NewRpcCmd(cmd.RpcMsgServer, msg.Start)
rpcCmd.AddPortFlag()
rpcCmd.AddPrometheusPortFlag()
if err := rpcCmd.Exec(); err != nil {
- panic(err.Error())
- }
- if err := rpcCmd.StartSvr(config.Config.RpcRegisterName.OpenImMsgName, msg.Start); err != nil {
- panic(err.Error())
+ util.ExitWithError(err)
}
}
diff --git a/cmd/openim-rpc/openim-rpc-third/main.go b/cmd/openim-rpc/openim-rpc-third/main.go
index cf0bf4b70..09a8409e6 100644
--- a/cmd/openim-rpc/openim-rpc-third/main.go
+++ b/cmd/openim-rpc/openim-rpc-third/main.go
@@ -17,17 +17,14 @@ package main
import (
"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/config"
+ util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil"
)
func main() {
- rpcCmd := cmd.NewRpcCmd(cmd.RpcThirdServer)
+ rpcCmd := cmd.NewRpcCmd(cmd.RpcThirdServer, third.Start)
rpcCmd.AddPortFlag()
rpcCmd.AddPrometheusPortFlag()
if err := rpcCmd.Exec(); err != nil {
- panic(err.Error())
- }
- if err := rpcCmd.StartSvr(config.Config.RpcRegisterName.OpenImThirdName, third.Start); err != nil {
- panic(err.Error())
+ util.ExitWithError(err)
}
}
diff --git a/cmd/openim-rpc/openim-rpc-user/main.go b/cmd/openim-rpc/openim-rpc-user/main.go
index cbf2a8fc3..18adbfae5 100644
--- a/cmd/openim-rpc/openim-rpc-user/main.go
+++ b/cmd/openim-rpc/openim-rpc-user/main.go
@@ -17,17 +17,14 @@ package main
import (
"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/config"
+ util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil"
)
func main() {
- rpcCmd := cmd.NewRpcCmd(cmd.RpcUserServer)
+ rpcCmd := cmd.NewRpcCmd(cmd.RpcUserServer, user.Start)
rpcCmd.AddPortFlag()
rpcCmd.AddPrometheusPortFlag()
if err := rpcCmd.Exec(); err != nil {
- panic(err.Error())
- }
- if err := rpcCmd.StartSvr(config.Config.RpcRegisterName.OpenImUserName, user.Start); err != nil {
- panic(err.Error())
+ util.ExitWithError(err)
}
}
diff --git a/config/templates/config.yaml.template b/config/templates/config.yaml.template
index 32ac14361..03413c595 100644
--- a/config/templates/config.yaml.template
+++ b/config/templates/config.yaml.template
@@ -153,6 +153,13 @@ object:
accessKeySecret: ''
sessionToken: ''
publicRead: false
+ aws:
+ endpoint: ""
+ region: ""
+ bucket: "demo-9999999"
+ accessKeyID: ''
+ accessKeySecret: ''
+ publicRead: false
###################### RPC Port Configuration ######################
# RPC service ports
diff --git a/config/templates/prometheus-dashboard.yaml b/config/templates/prometheus-dashboard.yaml
index 417f3d343..2e1ae7760 100644
--- a/config/templates/prometheus-dashboard.yaml
+++ b/config/templates/prometheus-dashboard.yaml
@@ -53,7 +53,7 @@
},
"id": 16,
"panels": [],
- "title": "openim自定义指标",
+ "title": "openim Custom Metrics",
"type": "row"
},
{
@@ -144,7 +144,7 @@
"refId": "A"
}
],
- "title": "在线人数",
+ "title": "Online population",
"type": "timeseries"
},
{
@@ -235,7 +235,7 @@
"refId": "A"
}
],
- "title": "登入/注册人数",
+ "title": "Login/registration numbers",
"type": "timeseries"
},
{
@@ -1345,7 +1345,7 @@
"type": "timeseries"
}
],
- "title": "应用服务器流量指标",
+ "title": "Traffic indicators of the application server",
"type": "row"
}
],
diff --git a/deployments/templates/config.yaml b/deployments/templates/config.yaml
index 8bf197566..5da6d5d0b 100644
--- a/deployments/templates/config.yaml
+++ b/deployments/templates/config.yaml
@@ -153,6 +153,13 @@ object:
accessKeySecret: ${KODO_ACCESS_KEY_SECRET}
sessionToken: ${KODO_SESSION_TOKEN}
publicRead: ${KODO_PUBLIC_READ}
+ aws:
+ endpoint: "${AWS_ENDPOINT}" # This might not be necessary unless you're using a custom endpoint
+ region: "${AWS_REGION}"
+ bucket: "${AWS_BUCKET}"
+ accessKeyID: ${AWS_ACCESS_KEY_ID}
+ accessKeySecret: ${AWS_SECRET_ACCESS_KEY}
+ publicRead: ${AWS_PUBLIC_READ}
###################### RPC Port Configuration ######################
# RPC service ports
diff --git a/docker-compose-1.yml b/docker-compose-1.yml
new file mode 100644
index 000000000..39fc944ce
--- /dev/null
+++ b/docker-compose-1.yml
@@ -0,0 +1,298 @@
+#fixme Clone openIM Server project before using docker-compose,project address:https://github.com/OpenIMSDK/Open-IM-Server.git
+# The command that triggers this file to pull the image is "docker compose up -f"
+version: '3'
+
+networks:
+ server:
+ driver: bridge
+ ipam:
+ driver: default
+ config:
+ - subnet: '${DOCKER_BRIDGE_SUBNET:-172.28.0.0/16}'
+ gateway: '${DOCKER_BRIDGE_GATEWAY:-172.28.0.1}'
+
+services:
+ mongodb:
+ image: mongo:${MONGODB_IMAGE_VERSION-6.0.2}
+ ports:
+ - "${MONGO_PORT:-37017}:27017"
+ container_name: mongo
+ command: ["/bin/bash", "-c", "/docker-entrypoint-initdb.d/mongo-init.sh || true; docker-entrypoint.sh mongod --wiredTigerCacheSizeGB 1 --auth"]
+ volumes:
+ - "${DATA_DIR:-./}/components/mongodb/data/db:/data/db"
+ - "${DATA_DIR:-./}/components/mongodb/data/logs:/data/logs"
+ - "${DATA_DIR:-./}/components/mongodb/data/conf:/etc/mongo"
+ - "./scripts/mongo-init.sh:/docker-entrypoint-initdb.d/mongo-init.sh:ro"
+ environment:
+ - TZ=Asia/Shanghai
+ - wiredTigerCacheSizeGB=1
+ - MONGO_INITDB_ROOT_USERNAME=${MONGO_USERNAME:-root}
+ - MONGO_INITDB_ROOT_PASSWORD=${MONGO_PASSWORD:-openIM123}
+ - MONGO_INITDB_DATABASE=${MONGO_DATABASE:-openim_v3}
+ - MONGO_OPENIM_USERNAME=${MONGO_OPENIM_USERNAME:-openIM} # Non-root username
+ - MONGO_OPENIM_PASSWORD=${MONGO_OPENIM_PASSWORD:-openIM123456} # Non-root password
+ restart: always
+ networks:
+ server:
+ ipv4_address: ${MONGO_NETWORK_ADDRESS:-172.28.0.2}
+
+ redis:
+ image: redis:${REDIS_IMAGE_VERSION:-7.0.0}
+ container_name: redis
+ ports:
+ - "${REDIS_PORT:-16379}:6379"
+ volumes:
+ - "${DATA_DIR:-./}/components/redis/data:/data"
+ - "${DATA_DIR:-./}/components/redis/config/redis.conf:/usr/local/redis/config/redis.conf"
+ environment:
+ TZ: Asia/Shanghai
+ restart: always
+ sysctls:
+ net.core.somaxconn: 1024
+ command: redis-server --requirepass ${REDIS_PASSWORD:-openIM123} --appendonly yes
+ networks:
+ server:
+ ipv4_address: ${REDIS_NETWORK_ADDRESS:-172.28.0.3}
+
+ zookeeper:
+ image: bitnami/zookeeper:${ZOOKEEPER_IMAGE_VERSION:-3.8}
+ container_name: zookeeper
+ ports:
+ - "${ZOOKEEPER_PORT:-12181}:2181"
+ volumes:
+ - "/etc/localtime:/etc/localtime"
+ environment:
+ - ALLOW_ANONYMOUS_LOGIN=yes
+ - TZ="Asia/Shanghai"
+ restart: always
+ networks:
+ server:
+ ipv4_address: ${ZOOKEEPER_NETWORK_ADDRESS:-172.28.0.5}
+
+ kafka:
+ image: 'bitnami/kafka:${KAFKA_IMAGE_VERSION:-3.5.1}'
+ container_name: kafka
+ restart: always
+ user: ${KAFKA_USER:-root}
+ ports:
+ - "${KAFKA_PORT:-19094}:9094"
+ volumes:
+ - ./scripts/create-topic.sh:/opt/bitnami/kafka/create-topic.sh
+ - "${DATA_DIR:-./}/components/kafka:/bitnami/kafka"
+ command: >
+ bash -c "/opt/bitnami/scripts/kafka/run.sh & sleep 5; /opt/bitnami/kafka/create-topic.sh; wait"
+ environment:
+ - TZ=Asia/Shanghai
+ - KAFKA_CFG_NODE_ID=0
+ - KAFKA_CFG_PROCESS_ROLES=controller,broker
+ - KAFKA_CFG_CONTROLLER_QUORUM_VOTERS=0@:9093
+ - KAFKA_CFG_LISTENERS=PLAINTEXT://:9092,CONTROLLER://:9093,EXTERNAL://:9094
+ - KAFKA_CFG_ADVERTISED_LISTENERS=PLAINTEXT://kafka:9092,EXTERNAL://${DOCKER_BRIDGE_GATEWAY:-172.28.0.1}:${KAFKA_PORT:-19094}
+ # - KAFKA_CFG_ADVERTISED_LISTENERS=PLAINTEXT://kafka:9092,EXTERNAL://127.0.0.1:${KAFKA_PORT:-19094} # Mac Deployment
+ - KAFKA_CFG_LISTENER_SECURITY_PROTOCOL_MAP=CONTROLLER:PLAINTEXT,EXTERNAL:PLAINTEXT,PLAINTEXT:PLAINTEXT
+ - KAFKA_CFG_CONTROLLER_LISTENER_NAMES=CONTROLLER
+ networks:
+ server:
+ ipv4_address: ${KAFKA_NETWORK_ADDRESS:-172.28.0.4}
+
+ minio:
+ image: minio/minio:${MINIO_IMAGE_VERSION:-RELEASE.2024-01-11T07-46-16Z}
+ ports:
+ - "${MINIO_PORT:-10005}:9000"
+ - "9090:9090"
+ container_name: minio
+ volumes:
+ - "${DATA_DIR:-./}/components/mnt/data:/data"
+ - "${DATA_DIR:-./}/components/mnt/config:/root/.minio"
+ environment:
+ MINIO_ROOT_USER: "${MINIO_ACCESS_KEY:-root}"
+ MINIO_ROOT_PASSWORD: "${MINIO_SECRET_KEY:-openIM123}"
+ restart: always
+ command: minio server /data --console-address ':9090'
+ networks:
+ server:
+ ipv4_address: ${MINIO_NETWORK_ADDRESS:-172.28.0.6}
+
+ openim-web:
+ image: ${IMAGE_REGISTRY:-ghcr.io/openimsdk}/openim-web:${OPENIM_WEB_IMAGE_VERSION:-v3.5.0-docker}
+ container_name: openim-web
+ platform: linux/amd64
+ restart: always
+ ports:
+ - "${OPENIM_WEB_PORT:-11001}:80"
+ networks:
+ server:
+ ipv4_address: ${OPENIM_WEB_NETWORK_ADDRESS:-172.28.0.7}
+
+ openim-admin:
+ # https://github.com/openimsdk/open-im-server/issues/1662
+ image: ${IMAGE_REGISTRY:-ghcr.io/openimsdk}/openim-admin:${ADMIN_FRONT_VERSION:-toc-base-open-docker.35}
+ container_name: openim-admin
+ platform: linux/amd64
+ restart: always
+ ports:
+ - "${OPENIM_ADMIN_FRONT_PORT:-11002}:80"
+ networks:
+ server:
+ ipv4_address: ${OPENIM_ADMIN_FRONT_NETWORK_ADDRESS:-172.28.0.13}
+
+ prometheus:
+ image: prom/prometheus
+ container_name: prometheus
+ hostname: prometheus
+ restart: always
+ volumes:
+ - "${DATA_DIR:-./}/config/instance-down-rules.yml:/etc/prometheus/instance-down-rules.yml"
+ - "${DATA_DIR:-./}/config/prometheus.yml:/etc/prometheus/prometheus.yml"
+ ports:
+ - "${PROMETHEUS_PORT:-19090}:9090"
+ networks:
+ server:
+ ipv4_address: ${PROMETHEUS_NETWORK_ADDRESS:-172.28.0.10}
+
+ alertmanager:
+ image: prom/alertmanager
+ container_name: alertmanager
+ hostname: alertmanager
+ restart: always
+ volumes:
+ - ${DATA_DIR:-./}/config/alertmanager.yml:/etc/alertmanager/alertmanager.yml
+ - ${DATA_DIR:-./}/config/email.tmpl:/etc/alertmanager/email.tmpl
+ ports:
+ - "${ALERT_MANAGER_PORT:-19093}:9093"
+ networks:
+ server:
+ ipv4_address: ${ALERT_MANAGER_NETWORK_ADDRESS:-172.28.0.14}
+
+ grafana:
+ image: grafana/grafana
+ container_name: grafana
+ hostname: grafana
+ user: root
+ restart: always
+ ports:
+ - "${GRAFANA_PORT:-13000}:3000"
+ volumes:
+ - "${DATA_DIR:-./}/components/grafana:/var/lib/grafana"
+ networks:
+ server:
+ ipv4_address: ${GRAFANA_NETWORK_ADDRESS:-172.28.0.11}
+
+ node-exporter:
+ image: quay.io/prometheus/node-exporter
+ container_name: node-exporter
+ hostname: node-exporter
+ restart: always
+ ports:
+ - "${NODE_EXPORTER_PORT:-19100}:9100"
+ networks:
+ server:
+ ipv4_address: ${NODE_EXPORTER_NETWORK_ADDRESS:-172.28.0.12}
+
+### Source code deployment does not require pulling the following mirrors
+
+ # openim-server:
+ # image: ${IMAGE_REGISTRY:-ghcr.io/openimsdk}/openim-server:${SERVER_IMAGE_VERSION:-main}
+ # container_name: openim-server
+ # ports:
+ # - "${OPENIM_WS_PORT:-10001}:${OPENIM_WS_PORT:-10001}"
+ # - "${API_OPENIM_PORT:-10002}:${API_OPENIM_PORT:-10002}"
+ # - "${API_PROM_PORT:-20100}:${API_PROM_PORT:-20100}"
+ # - "${USER_PROM_PORT:-20110}:${USER_PROM_PORT:-20110}"
+ # - "${FRIEND_PROM_PORT:-20120}:${FRIEND_PROM_PORT:-20120}"
+ # - "${MESSAGE_PROM_PORT:-20130}:${MESSAGE_PROM_PORT:-20130}"
+ # - "${MSG_GATEWAY_PROM_PORT:-20140}:${MSG_GATEWAY_PROM_PORT:-20140}"
+ # - "${GROUP_PROM_PORT:-20150}:${GROUP_PROM_PORT:-20150}"
+ # - "${AUTH_PROM_PORT:-20160}:${AUTH_PROM_PORT:-20160}"
+ # - "${PUSH_PROM_PORT:-20170}:${PUSH_PROM_PORT:-20170}"
+ # - "${CONVERSATION_PROM_PORT:-20230}:${CONVERSATION_PROM_PORT:-20230}"
+ # - "${RTC_PROM_PORT:-21300}:${RTC_PROM_PORT:-21300}"
+ # - "${THIRD_PROM_PORT:-21301}:${THIRD_PROM_PORT:-21301}"
+ # - "21400-21403:21400-21403"
+ # healthcheck:
+ # test: ["CMD", "/openim/openim-server/scripts/check-all.sh"]
+ # interval: 120s
+ # timeout: 30s
+ # retries: 5
+ # env_file:
+ # - .env
+ # environment:
+ # - OPENIM_IP=${OPENIM_IP:-127.0.0.1}
+ # volumes:
+ # - "${DATA_DIR:-./}/openim-server/logs:/openim/openim-server/logs"
+ # - "${DATA_DIR:-./}/openim-server/_output/logs:/openim/openim-server/_output/logs"
+ # - "${DATA_DIR:-./}/openim-server/config:/openim/openim-server/config"
+ # restart: always
+ # depends_on:
+ # - kafka
+ # - mysql
+ # - mongodb
+ # - redis
+ # - minio
+ # logging:
+ # driver: json-file
+ # options:
+ # max-size: "1g"
+ # max-file: "2"
+ # networks:
+ # server:
+ # ipv4_address: ${OPENIM_SERVER_NETWORK_ADDRESS:-172.28.0.8}
+
+ ### TODO: mysql is required to deploy the openim-chat component
+ # mysql:
+ # image: mysql:${MYSQL_IMAGE_VERSION:-5.7}
+ # platform: linux/amd64
+ # ports:
+ # - "${MYSQL_PORT:-13306}:3306"
+ # container_name: mysql
+ # volumes:
+ # - "${DATA_DIR:-./}/components/mysql/data:/var/lib/mysql"
+ # - "/etc/localtime:/etc/localtime"
+ # environment:
+ # MYSQL_ROOT_PASSWORD: "${MYSQL_PASSWORD:-openIM123}"
+ # restart: always
+ # networks:
+ # server:
+ # ipv4_address: ${MYSQL_NETWORK_ADDRESS:-172.28.0.15}
+
+ # openim-chat:
+ # image: ${IMAGE_REGISTRY:-ghcr.io/openimsdk}/openim-chat:${CHAT_IMAGE_VERSION:-main}
+ # container_name: openim-chat
+ # healthcheck:
+ # test: ["CMD", "/openim/openim-chat/scripts/check_all.sh"]
+ # interval: 60s
+ # timeout: 30s
+ # retries: 5
+ # env_file:
+ # - .env
+ # environment:
+ # - ZOOKEEPER_ADDRESS=${DOCKER_BRIDGE_GATEWAY:-172.28.0.1}
+ # - ZOOKEEPER_PORT=${ZOOKEEPER_PORT:-12181}
+ # - OPENIM_SERVER_ADDRESS=http://${OPENIM_SERVER_ADDRESS:-172.28.0.1}
+ # - API_OPENIM_PORT=${API_OPENIM_PORT:-10002}
+ # - MYSQL_ADDRESS=${DOCKER_BRIDGE_GATEWAY:-172.28.0.1}
+ # - MYSQL_PORT=${MYSQL_PORT:-13306}
+ # - REDIS_ADDRESS=${DOCKER_BRIDGE_GATEWAY:-172.28.0.1}
+ # - REDIS_PORT=${REDIS_PORT:-16379}
+ # ports:
+ # - "${OPENIM_CHAT_API_PORT:-10008}:10008"
+ # - "${OPENIM_ADMIN_API_PORT:-10009}:10009"
+ # volumes:
+ # - "${DATA_DIR:-./}/components/openim-chat/logs:/openim/openim-chat/logs"
+ # - "${DATA_DIR:-./}/components/openim-chat/_output/logs:/openim/openim-chat/_output/logs"
+ # - "${DATA_DIR:-./}/components/openim-chat/config:/openim/openim-chat/config"
+ # restart: always
+ # # user: root:root
+ # depends_on:
+ # - mysql
+ # - kafka
+ # - redis
+ # - zookeeper
+ # logging:
+ # driver: json-file
+ # options:
+ # max-size: "1g"
+ # max-file: "2"
+ # networks:
+ # server:
+ # ipv4_address: ${OPENIM_CHAT_NETWORK_ADDRESS:-172.28.0.9}
diff --git a/docker-compose.yml b/docker-compose.yml
index dcf7518e2..8538eec83 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -1,4 +1,5 @@
#fixme Clone openIM Server project before using docker-compose,project address:https://github.com/OpenIMSDK/Open-IM-Server.git
+# The command that triggers this file to pull the image is "docker compose up -d".
version: '3'
networks:
@@ -123,6 +124,18 @@ services:
server:
ipv4_address: ${OPENIM_WEB_NETWORK_ADDRESS:-172.28.0.7}
+ openim-admin:
+ # https://github.com/openimsdk/open-im-server/issues/1662
+ image: ${IMAGE_REGISTRY:-ghcr.io/openimsdk}/openim-admin:${ADMIN_FRONT_VERSION:-toc-base-open-docker.35}
+ container_name: openim-admin
+ platform: linux/amd64
+ restart: always
+ ports:
+ - "${OPENIM_ADMIN_FRONT_PORT:-11002}:80"
+ networks:
+ server:
+ ipv4_address: ${OPENIM_ADMIN_FRONT_NETWORK_ADDRESS:-172.28.0.13}
+
### TODO: Uncomment, or deploy using openim docker: https://github.com/openimsdk/openim-docker
### Uncomment and configure the following services as needed
@@ -232,18 +245,6 @@ services:
# server:
# ipv4_address: ${OPENIM_CHAT_NETWORK_ADDRESS:-172.28.0.9}
- # openim-admin:
- # # https://github.com/openimsdk/open-im-server/issues/1662
- # image: ${IMAGE_REGISTRY:-ghcr.io/openimsdk}/openim-admin:${ADMIN_FRONT_VERSION:-toc-base-open-docker.35}
- # container_name: openim-admin
- # platform: linux/amd64
- # restart: always
- # ports:
- # - "${OPENIM_ADMIN_FRONT_PORT:-11002}:80"
- # networks:
- # server:
- # ipv4_address: ${OPENIM_ADMIN_FRONT_NETWORK_ADDRESS:-172.28.0.13}
-
# prometheus:
# image: prom/prometheus
# container_name: prometheus
diff --git a/docs/README.md b/docs/README.md
index 32fc8d015..92ba2c620 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -7,7 +7,6 @@ Welcome to the OpenIM Documentation hub! This center provides a comprehensive ra
1. [Contrib](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib) - Guidance on contributing and configurations for developers
2. [Conversions](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib) - Coding conventions, logging policies, and other transformation tools
-------
## Contrib
diff --git a/docs/contrib/code-conventions.md b/docs/contrib/code-conventions.md
index 049df6381..6b534779b 100644
--- a/docs/contrib/code-conventions.md
+++ b/docs/contrib/code-conventions.md
@@ -3,7 +3,15 @@
- [Code conventions](#code-conventions)
- [POSIX shell](#posix-shell)
- [Go](#go)
- - [Directory and file conventions](#directory-and-file-conventions)
+ - [OpenIM Naming Conventions Guide](#openim-naming-conventions-guide)
+ - [1. General File Naming](#1-general-file-naming)
+ - [2. Special File Types](#2-special-file-types)
+ - [a. Script and Markdown Files](#a-script-and-markdown-files)
+ - [b. Uppercase Markdown Documentation](#b-uppercase-markdown-documentation)
+ - [3. Directory Naming](#3-directory-naming)
+ - [4. Configuration Files](#4-configuration-files)
+ - [Best Practices](#best-practices)
+ - [Directory and File Conventions](#directory-and-file-conventions)
- [Testing conventions](#testing-conventions)
## POSIX shell
@@ -67,12 +75,13 @@ Files within the OpenIM project should adhere to the following rules:
+ Stick to lowercase naming where possible for consistency and to prevent issues with case-sensitive systems.
+ Include version numbers or dates in file names if the file is subject to updates, following the format: `project-plan-v1.2.md` or `backup-2023-03-15.sql`.
-## Directory and file conventions
+## Directory and File Conventions
+
+- Avoid generic utility packages. Instead of naming a package "util", choose a name that clearly describes its purpose. For instance, functions related to waiting operations are contained within the `wait` package, which includes methods like `Poll`, fully named as `wait.Poll`.
+- All filenames, script files, configuration files, and directories should be in lowercase and use dashes (`-`) as separators.
+- For Go language files, filenames should be in lowercase and use underscores (`_`).
+- Package names should match their directory names to ensure consistency. For example, within the `openim-api` directory, the Go file should be named `openim-api.go`, following the convention of using dashes for directory names and aligning package names with directory names.
-- Avoid general utility packages. Packages called "util" are suspect. Instead, derive a name that describes your desired function. For example, the utility functions dealing with waiting for operations are in the `wait` package and include functionality like `Poll`. The full name is `wait.Poll`.
-- All filenames should be lowercase.
-- All source files and directories should use underscores, not dashes.
- - Package directories should generally avoid using separators as much as possible. When package names are multiple words, they usually should be in nested subdirectories.
## Testing conventions
diff --git a/docs/contrib/environment.md b/docs/contrib/environment.md
index fb696eb54..d2db7cbf3 100644
--- a/docs/contrib/environment.md
+++ b/docs/contrib/environment.md
@@ -305,13 +305,14 @@ Feel free to explore the MinIO documentation for more advanced configurations an
This section involves setting up MongoDB, including its port, address, and credentials.
+
| Parameter | Example Value | Description |
| -------------- | -------------- | ----------------------- |
| MONGO_PORT | "27017" | Port used by MongoDB. |
| MONGO_ADDRESS | [Generated IP] | IP address for MongoDB. |
| MONGO_USERNAME | [User Defined] | Admin Username for MongoDB. |
| MONGO_PASSWORD | [User Defined] | Admin Password for MongoDB. |
-| MONGO_OPENIM_PASSWORD | [User Defined] | OpenIM Username for MongoDB. |
+| MONGO_OPENIM_USERNAME | [User Defined] | OpenIM Username for MongoDB. |
| MONGO_OPENIM_PASSWORD | [User Defined] | OpenIM Password for MongoDB. |
### 2.8. Tencent Cloud COS Configuration
@@ -448,7 +449,7 @@ This section involves configuring the log settings, including storage location,
| Parameter | Example Value | Description |
| ------------------------- | ------------------------ | --------------------------------- |
-| LOG_STORAGE_LOCATION | "${OPENIM_ROOT}/logs/" | Location for storing logs |
+| LOG_STORAGE_LOCATION | "${OPENIM_ROOT}/_output/logs/" | Location for storing logs |
| LOG_ROTATION_TIME | "24" | Log rotation time (in hours) |
| LOG_REMAIN_ROTATION_COUNT | "2" | Number of log rotations to retain |
| LOG_REMAIN_LOG_LEVEL | "6" | Log level to retain |
diff --git a/docs/contrib/go-code.md b/docs/contrib/go-code.md
index 1de448da7..b122917ca 100644
--- a/docs/contrib/go-code.md
+++ b/docs/contrib/go-code.md
@@ -26,19 +26,19 @@ jwt "github.com/dgrijalva/jwt-go/v4"
```go
import (
-// go standard package
-"fmt"
-
-// third party package
-"github.com/jinzhu/gorm"
-"github.com/spf13/cobra"
-"github.com/spf13/viper"
-
-// Anonymous packages are grouped separately, and anonymous package references are explained
-// import mysql driver
-_ "github.com/jinzhu/gorm/dialects/mysql"
-
-// inner package
+ // go standard package
+ "fmt"
+
+ // third party package
+ "github.com/jinzhu/gorm"
+ "github.com/spf13/cobra"
+ "github.com/spf13/viper"
+
+ // Anonymous packages are grouped separately, and anonymous package references are explained
+ // import mysql driver
+ _ "github.com/jinzhu/gorm/dialects/mysql"
+
+ // inner package
)
```
@@ -48,33 +48,33 @@ When multiple variables need to be used in a function, the `var` declaration can
```go
var (
-Width int
-Height int
+ Width int
+ Height int
)
```
- When initializing a structure reference, please use `&T{}` instead of `new(T)` to make it consistent with structure initialization.
```go
-// bad
-sptr := new(T)
-sptr.Name = "bar"
-
-// good
-sptr := &T{Name: "bar"}
+ // bad
+ sptr := new(T)
+ sptr.Name = "bar"
+
+ // good
+ sptr := &T{Name: "bar"}
```
- The struct declaration and initialization format takes multiple lines and is defined as follows.
```go
-type User struct{
- Username string
- Email string
-}
+ type User struct{
+ Username string
+ Email string
+ }
-user := User{
-Username: "belm",
-Email: "nosbelm@qq.com",
+ user := User{
+ Username: "belm",
+ Email: "nosbelm@qq.com",
}
```
@@ -217,20 +217,20 @@ if err != nil {
// bad
v, err := foo()
if err != nil || v == nil {
-// error handling
-return err
+ // error handling
+ return err
}
//good
v, err := foo()
if err != nil {
-// error handling
-return err
+ // error handling
+ return err
}
if v == nil {
-// error handling
-return errors. New("invalid value v")
+ // error handling
+ return errors. New("invalid value v")
}
```
@@ -239,13 +239,14 @@ return errors. New("invalid value v")
```go
v, err := f()
if err != nil {
- // error handling
- return // or continue.
+ // error handling
+ return // or continue.
}
```
- Bug description suggestions
- Error descriptions start with a lowercase letter and do not end with punctuation, for example:
+
```go
// bad
errors.New("Redis connection failed")
@@ -254,6 +255,7 @@ errors.New("redis connection failed.")
// good
errors.New("redis connection failed")
```
+
- Tell users what they can do, not what they can't.
- When declaring a requirement, use must instead of should. For example, `must be greater than 0, must match regex '[a-z]+'`.
- When declaring that a format is incorrect, use must not. For example, `must not contain`.
@@ -359,18 +361,18 @@ u := User{
For example:
-```
+```go
// Seeking to an offset before the start of the file is an error.
// Seeking to any positive offset is legal, but the behavior of subsequent
// I/O operations on the underlying object are implementation-dependent.
type Seeker interface {
-Seek(offset int64, whence int) (int64, error)
+ Seek(offset int64, whence int) (int64, error)
}
// ReadWriter is the interface that groups the basic Read and Write methods.
type ReadWriter interface {
-reader
-Writer
+ reader
+ Writer
}
```
@@ -386,7 +388,7 @@ Writer
Some common nouns are listed below.
-```
+```go
// A GonicMapper that contains a list of common initialisms taken from golang/lint
var LintGonicMapper = GonicMapper{
"API": true,
@@ -523,6 +525,7 @@ package genericclioptions
// ErrSigningMethod defines invalid signing method error.
var ErrSigningMethod = errors. New("Invalid signing method")
```
+
- When there is a large block of constant or variable definition, you can comment a general description in front, and then comment the definition of the constant in detail before or at the end of each line of constant, for example:
```go
// Code must start with 1xxxxx.
@@ -567,7 +570,7 @@ Each function or method that needs to be exported must have a comment, the forma
// BeforeUpdate run before update database record.
func (p *Policy) BeforeUpdate() (err error) {
// normal code
-return nil
+ return nil
}
```
@@ -743,9 +746,9 @@ for i := 0; i < 10; i++ {
```go
// bad
for file := range files {
-fd, err := os. Open(file)
-if err != nil {
-return err
+ fd, err := os. Open(file)
+ if err != nil {
+ return err
}
defer fd. Close()
// normal code
@@ -753,14 +756,14 @@ defer fd. Close()
//good
for file := range files {
-func() {
-fd, err := os. Open(file)
-if err != nil {
-return err
-}
-defer fd. Close()
-// normal code
-}()
+ func() {
+ fd, err := os. Open(file)
+ if err != nil {
+ return err
+ }
+ defer fd. Close()
+ // normal code
+ }()
}
```
@@ -888,6 +891,7 @@ type LogHandler struct {
}
var_http.Handler = LogHandler{}
```
+
- When the server processes a request, it should create a context, save the relevant information of the request (such as requestID), and pass it in the function call chain.
### 9.1 Performance
@@ -900,3 +904,246 @@ var_http.Handler = LogHandler{}
- If you want to directly modify the value of the map, the value can only be a pointer, otherwise the original value must be overwritten.
- map needs to be locked during concurrency.
- The conversion of interface{} cannot be checked during compilation, it can only be checked at runtime, be careful to cause panic.
+
+## 10 Golang CI Lint
+
+- Golang CI Lint is a fast Go linters runner. It runs linters in parallel, uses caching, and works well with all environments, including CI.
+
+**In local development, you can use the following command to install Golang CI Lint: **
+
+```bash
+make lint
+```
+
+**In CI/CD, Check the Github Actions status code below after you submit the code directly**
+
+[](https://github.com/openimsdk/open-im-server/actions/workflows/golangci-lint.yml)
+
+golangci lint can select the types of tools, refer to the official documentation: [https://golangci-lint.run/usage/linters/](https://golangci-lint.run/usage/linters/)
+
+The types of comments we currently use include: [https://github.com/openimsdk/open-im-server/blob/main/.golangci.yml](https://github.com/openimsdk/open-im-server/blob/main/.golangci.yml) the `linters.enable` field in the file.
+
+e.g:
+```yaml
+linters:
+ # please, do not use `enable-all`: it's deprecated and will be removed soon.
+ # inverted configuration with `enable-all` and `disable` is not scalable during updates of golangci-lint
+ # enable-all: true
+ disable-all: true
+ enable:
+ - typecheck # Basic type checking
+ - gofmt # Format check
+ - govet # Go's standard linting tool
+ - gosimple # Suggestions for simplifying code
+ - misspell # Spelling mistakes
+ - staticcheck # Static analysis
+ - unused # Checks for unused code
+ - goimports # Checks if imports are correctly sorted and formatted
+ - godot # Checks for comment punctuation
+ - bodyclose # Ensures HTTP response body is closed
+ - errcheck # Checks for missed error returns
+ fast: true
+```
+
+Add that Chinese comments are not allowed in go code, please write a complete golangci lint specification on the basis of the above.
+
+
+### 10.1 Configuration Document
+
+This configuration document is designed to configure the operational parameters of OpenIM (a hypothetical or specific code analysis tool), customize output formats, and provide detailed settings for specific code checkers (linters). Below is a summary of the document drafted based on the provided configuration information.
+
+#### 10.1 Runtime Options
+
+- **Concurrency** (`concurrency`): Default to use the available CPU count, can be manually set to 4 for parallel analysis.
+- **Timeout** (`timeout`): Timeout duration for analysis operations, default is 1 minute, set here to 5 minutes.
+- **Issue Exit Code** (`issues-exit-code`): Exit code defaults to 1 if at least one issue is found.
+- **Test Files** (`tests`): Whether to include test files, defaults to true.
+- **Build Tags** (`build-tags`): Specify build tags used by all linters, defaults to an empty list. Example adds `mytag`.
+- **Skip Directories** (`skip-dirs`): Configure which directories' issues are not reported, defaults to empty, but some default directories are independently skipped.
+- **Skip Files** (`skip-files`): Specify files where issues should not be reported, supports regular expressions.
+
+#### 10.2 Output Configuration
+
+- **Format** (`format`): Set output format, default is "colored-line-number".
+- **Print Issued Lines** (`print-issued-lines`): Whether to print the lines where issues occur, defaults to true.
+- **Print Linter Name** (`print-linter-name`): Whether to print the linter name at the end of issue text, defaults to true.
+- **Uniqueness Filter** (`uniq-by-line`): Whether to make issue outputs unique per line, defaults to true.
+- **Path Prefix** (`path-prefix`): Prefix to add to output file references, defaults to no prefix.
+- **Sort Results** (`sort-results`): Sort results by file path, line number, and column number.
+
+#### 10.3 Linters Settings
+
+In the configuration file, the `linters-settings` section allows detailed configuration of individual linters. Below are examples of specific linters settings and their purposes:
+
+- **bidichk**: Used to check bidirectional text characters, ensuring correct display direction of text, especially when dealing with mixed left-to-right (LTR) and right-to-left (RTL) text.
+
+- **dogsled**: Monitors excessive use of blank identifiers (`_`) in assignment operations, which may obscure data processing errors or unclear logic.
+
+- **dupl**: Identifies duplicate code blocks, helping developers avoid code redundancy. The `threshold` parameter in settings allows adjustment of code similarity threshold triggering warnings.
+
+- **errcheck**: Checks for unhandled errors. In Go, error handling is achieved by checking function return values. This linter helps ensure all errors are properly handled.
+
+- **exhaustive**: Checks if `switch` statements include all possible values of an enum type, ensuring exhaustiveness of code. This helps avoid forgetting to handle certain cases.
+
+#### 10.4 Example: `errcheck`
+
+**Incorrect Code Example**:
+```go
+package main
+
+import (
+ "fmt"
+ "os"
+)
+
+func main() {
+ f, _ := os.Open("filename.ext")
+ defer f.Close()
+}
+```
+
+**Issue**: In the above code, the error return value of `os.Open` function is explicitly ignored. This is a common mistake as it may lead to unhandled errors and hard-to-trace bugs.
+
+**Correct Form**:
+```go
+package main
+
+import (
+ "fmt"
+ "os"
+)
+
+func main() {
+ f, err := os.Open("filename.ext")
+ if err != nil {
+ fmt.Printf("error opening file: %v\n", err)
+ return
+ }
+ defer f.Close()
+}
+```
+
+In the correct form, by checking the error (`err`) returned by `os.Open`, we gracefully handle error cases rather than simply ignoring them.
+
+#### 10.5 Example: `gofmt`
+
+**Incorrect Code Example**:
+```go
+package main
+import "fmt"
+func main() {
+fmt.Println("Hello, world!")
+}
+```
+
+**Issue**: This code snippet doesn't follow Go's standard formatting rules, for example, incorrect indentation of `fmt.Println`.
+
+**Correct Form**:
+```go
+package main
+
+import "fmt"
+
+func main() {
+ fmt.Println("Hello, world!")
+}
+```
+
+Using `gofmt` tool can automatically fix such formatting issues, ensuring the code adheres to the coding standards of the Go community.
+
+#### 10.6 Example: `unused`
+
+**Incorrect Code Example**:
+```go
+package main
+
+func helper() {}
+
+func main() {}
+```
+
+**Issue**: The `helper` function is defined but not called anywhere, indicating potential redundant code or missing functionality implementation.
+
+**Correct Form**:
+```go
+package main
+
+// If the helper function is indeed needed, ensure it's used properly.
+func helper() {
+ // Implement the function's functionality or ensure it's called elsewhere
+}
+
+func main() {
+ helper()
+}
+```
+
+To improve the section on Linters settings in the document, we'll expand with more detailed explanations and reinforce understanding through examples.
+
+#### 10.7 Example: `dogsled`
+
+**Incorrect Code Example**:
+```go
+func getValues() (int, int, int) {
+ return 1, 2, 3
+}
+
+func main() {
+ _, _, val := getValues()
+ fmt.Println(val) // Only interested in the third return value
+}
+```
+
+**Explanation**: In the above code, we use two blank identifiers to ignore the first two return values. Excessive use of blank identifiers can make code reading difficult.
+
+**Improved Code**:
+Consider refactoring the function or the usage of return values to reduce the need for blank identifiers or explicitly comment why ignoring certain values is safe.
+
+#### 10.8: `exhaustive`
+
+**Incorrect Code Example**:
+```go
+type Fruit int
+
+const (
+ Apple Fruit = iota
+ Banana
+ Orange
+)
+
+func getFruitName(f Fruit) string {
+ switch f {
+ case Apple:
+ return "Apple"
+ case Banana:
+ return "Banana"
+ // Missing handling for Orange
+ }
+ return "Unknown"
+}
+```
+
+**Explanation**: In this code, the `switch` statement doesn't cover all possible values of the `Fruit` type; the case for `Orange` is missing.
+
+**Improved Code**:
+```go
+func getFruitName(f Fruit) string {
+ switch f {
+ case Apple:
+ return "Apple"
+ case Banana:
+ return "Banana"
+ case Orange:
+ return "Orange"
+ }
+ return "Unknown"
+}
+```
+
+By adding the missing `case`, we ensure the `switch` statement is exhaustive, handling every possible enum value.
+
+#### 10.9 Optimization of Configuration Files and Application of Code Analysis Tools
+
+Through these examples, we demonstrate how to improve code quality by identifying and fixing common coding issues. OpenIM's configuration files allow developers to customize linters' behavior according to project requirements, ensuring code compliance with predefined quality standards and style guidelines.
+
+By employing these tools and configuration strategies, teams can reduce the number of bugs, enhance code maintainability, and facilitate efficient collaboration during code review processes.
diff --git a/docs/contributing/CONTRIBUTING-JP.md b/docs/contributing/CONTRIBUTING-JP.md
new file mode 100644
index 000000000..86bbfefcd
--- /dev/null
+++ b/docs/contributing/CONTRIBUTING-JP.md
@@ -0,0 +1,33 @@
+# How do I contribute code to OpenIM
+
+
+ Englist ·
+ 中文 ·
+ Українська ·
+ Česky ·
+ Magyar ·
+ Español ·
+ فارسی ·
+ Français ·
+ Deutsch ·
+ Polski ·
+ Indonesian ·
+ Suomi ·
+ മലയാളം ·
+ 日本語 ·
+ Nederlands ·
+ Italiano ·
+ Русский ·
+ Português (Brasil) ·
+ Esperanto ·
+ 한국어 ·
+ العربي ·
+ Tiếng Việt ·
+ Dansk ·
+ Ελληνικά ·
+ Türkçe
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/contributing/CONTRIBUTING-PL.md b/docs/contributing/CONTRIBUTING-PL.md
new file mode 100644
index 000000000..86bbfefcd
--- /dev/null
+++ b/docs/contributing/CONTRIBUTING-PL.md
@@ -0,0 +1,33 @@
+# How do I contribute code to OpenIM
+
+
+ Englist ·
+ 中文 ·
+ Українська ·
+ Česky ·
+ Magyar ·
+ Español ·
+ فارسی ·
+ Français ·
+ Deutsch ·
+ Polski ·
+ Indonesian ·
+ Suomi ·
+ മലയാളം ·
+ 日本語 ·
+ Nederlands ·
+ Italiano ·
+ Русский ·
+ Português (Brasil) ·
+ Esperanto ·
+ 한국어 ·
+ العربي ·
+ Tiếng Việt ·
+ Dansk ·
+ Ελληνικά ·
+ Türkçe
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/images/Open-IM-Servers-on-System.png b/docs/images/Open-IM-Servers-on-System.png
deleted file mode 100644
index 3c8a10202..000000000
Binary files a/docs/images/Open-IM-Servers-on-System.png and /dev/null differ
diff --git a/docs/images/Open-IM-Servers-on-docker.png b/docs/images/Open-IM-Servers-on-docker.png
deleted file mode 100644
index c66f7fb09..000000000
Binary files a/docs/images/Open-IM-Servers-on-docker.png and /dev/null differ
diff --git a/docs/images/architecture-layers.png b/docs/images/architecture-layers.png
new file mode 100644
index 000000000..d9e6e4d59
Binary files /dev/null and b/docs/images/architecture-layers.png differ
diff --git a/docs/images/build.png b/docs/images/build.png
deleted file mode 100644
index 7c5914c82..000000000
Binary files a/docs/images/build.png and /dev/null differ
diff --git a/docs/images/docker_build.png b/docs/images/docker_build.png
deleted file mode 100644
index f4be10f68..000000000
Binary files a/docs/images/docker_build.png and /dev/null differ
diff --git a/docs/readme/README_cs.md b/docs/readme/README_cs.md
new file mode 100644
index 000000000..5a9eeb232
--- /dev/null
+++ b/docs/readme/README_cs.md
@@ -0,0 +1,187 @@
+
+
+
+
+
+
+
+
+[](https://github.com/openimsdk/open-im-server/stargazers)
+[](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/)
+
+
+
+ Englist ·
+ 中文 ·
+ Українська ·
+ Česky ·
+ Magyar ·
+ Español ·
+ فارسی ·
+ Français ·
+ Deutsch ·
+ Polski ·
+ Indonesian ·
+ Suomi ·
+ മലയാളം ·
+ 日本語 ·
+ Nederlands ·
+ Italiano ·
+ Русский ·
+ Português (Brasil) ·
+ Esperanto ·
+ 한국어 ·
+ العربي ·
+ Tiếng Việt ·
+ Dansk ·
+ Ελληνικά ·
+ Türkçe
+
+
+
+
+
+
+
+## Ⓜ️ O OpenIM
+
+OpenIM je platforma služeb speciálně navržená pro integraci chatu, audio-video hovorů, upozornění a chatbotů AI do aplikací. Poskytuje řadu výkonných rozhraní API a webhooků, které vývojářům umožňují snadno začlenit tyto interaktivní funkce do svých aplikací. OpenIM není samostatná chatovací aplikace, ale spíše slouží jako platforma pro podporu jiných aplikací při dosahování bohatých komunikačních funkcí. Následující diagram ilustruje interakci mezi AppServer, AppClient, OpenIMServer a OpenIMSDK pro podrobné vysvětlení.
+
+
+
+## 🚀 O OpenIMSDK
+
+**OpenIMSDK** je IM SDK navržený pro**OpenIMServer**, vytvořený speciálně pro vkládání do klientských aplikací. Jeho hlavní vlastnosti a moduly jsou následující:
+
++ 🌟 Hlavní vlastnosti:
+
+ - 📦 Místní úložiště
+ - 🔔 Zpětná volání posluchačů
+ - 🛡️ API obalování
+ - 🌐 Správa připojení
+
++ 📚 hlavní moduly:
+
+ 1. 🚀 Inicializace a přihlášení
+ 2. 👤 Správa uživatelů
+ 3. 👫 Správa přátel
+ 4. 🤖 Skupinové funkce
+ 5. 💬 Zpracování konverzace
+
+Je postaven pomocí Golang a podporuje nasazení napříč platformami, což zajišťuje konzistentní přístup na všech platformách.
+
+👉 **[Prozkoumat GO SDK](https://github.com/openimsdk/openim-sdk-core)**
+
+## 🌐 O OpenIMServeru
+
++ **OpenIMServer** má následující vlastnosti:
+ - 🌐 Architektura mikroslužeb: Podporuje režim clusteru, včetně brány a více služeb RPC.
+ - 🚀 Různé metody nasazení: Podporuje nasazení prostřednictvím zdrojového kódu, Kubernetes nebo Docker.
+ - Podpora masivní uživatelské základny: Super velké skupiny se stovkami tisíc uživatelů, desítkami milionů uživatelů a miliardami zpráv.
+
+### Vylepšené obchodní funkce:
+
++ **REST API**: OpenIMServer nabízí REST API pro podnikové systémy, jejichž cílem je poskytnout podnikům více funkcí, jako je vytváření skupin a odesílání push zpráv přes backendová rozhraní.
++ **Webhooks**: OpenIMServer poskytuje možnosti zpětného volání pro rozšíření více obchodních formulářů. Zpětné volání znamená, že OpenIMServer odešle požadavek na obchodní server před nebo po určité události, jako jsou zpětná volání před nebo po odeslání zprávy.
+
+👉 **[Další informace](https://docs.openim.io/guides/introduction/product)**
+
+## :building_construction: Celková architektura
+
+Ponořte se do srdce funkčnosti Open-IM-Server s naším diagramem architektury.
+
+
+
+
+## :rocket: Rychlý start
+
+Podporujeme mnoho platforem. Zde jsou adresy pro rychlou práci na webové stránce:
+
+👉 **[Online webová ukázka OpenIM](https://web-enterprise.rentsoft.cn/)**
+
+🤲 Pro usnadnění uživatelské zkušenosti nabízíme různá řešení nasazení. Způsob nasazení si můžete vybrat ze seznamu níže:
+
++ **[Průvodce nasazením zdrojového kódu](https://docs.openim.io/guides/gettingStarted/imSourceCodeDeployment)**
++ **[Docker Deployment Guide](https://docs.openim.io/guides/gettingStarted/dockerCompose)**
++ **[Průvodce nasazením Kubernetes](https://docs.openim.io/guides/gettingStarted/k8s-deployment)**
++ **[Průvodce nasazením pro vývojáře Mac](https://docs.openim.io/guides/gettingstarted/mac-deployment-guide)**
+
+## :hammer_and_wrench: Chcete-li začít vyvíjet OpenIM
+
+[](https://vscode.dev/github/openimsdk/open-im-server)
+
+OpenIM Naším cílem je vybudovat špičkovou open source komunitu. Máme soubor standardů v [komunitním repozitáři](https://github.com/OpenIMSDK/community).
+
+Pokud byste chtěli přispět do tohoto úložiště Open-IM-Server, přečtěte si naši [dokumentaci pro přispěvatele](https://github.com/openimsdk/open-im-server/blob/main/CONTRIBUTING.md).
+
+Než začnete, ujistěte se, že jsou vaše změny vyžadovány. Nejlepší pro to je vytvořit [nová diskuze](https://github.com/openimsdk/open-im-server/discussions/new/choose) NEBO [Slack Communication](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q), nebo pokud narazíte na problém, [nahlásit jej](https://github.com/openimsdk/open-im-server/issues/new/choose) jako první.
+
+- [OpenIM API Reference](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/api.md)
+- [Protokolování OpenIM Bash](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/bash-log.md)
+- [Akce OpenIM CI/CD](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/cicd-actions.md)
+- [Konvence kódu OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/code-conventions.md)
+- [Pokyny k zavázání OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/commit.md)
+- [Průvodce vývojem OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/development.md)
+- [Struktura adresáře OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/directory.md)
+- [Nastavení prostředí OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/environment.md)
+- [Referenční kód chybového kódu OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/error-code.md)
+- [Pracovní postup OpenIM Git](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/git-workflow.md)
+- [OpenIM Git Cherry Pick Guide](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/gitcherry-pick.md)
+- [Pracovní postup OpenIM GitHub](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/github-workflow.md)
+- [standardy kódu OpenIM Go](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/go-code.md)
+- [Pokyny pro obrázky OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/images.md)
+- [Počáteční konfigurace OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/init-config.md)
+- [Průvodce instalací OpenIM Docker](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/install-docker.md)
+- [nstalace systému OpenIM OpenIM Linux](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/install-openim-linux-system.md)
+- [OpenIM Linux Development Guide](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/linux-development.md)
+- [Průvodce místními akcemi OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/local-actions.md)
+- [Konvence protokolování OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/logging.md)
+- [Offline nasazení OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/offline-deployment.md)
+- [Nástroje protokolu OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/protoc-tools.md)
+- [Příručka testování OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/test.md)
+- [OpenIM Utility Go](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/util-go.md)
+- [OpenIM Makefile Utilities](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/util-makefile.md)
+- [OpenIM Script Utilities](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/util-scripts.md)
+- [OpenIM Versioning](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/version.md)
+- [Spravovat backend a monitorovat nasazení](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/prometheus-grafana.md)
+- [Průvodce nasazením pro vývojáře Mac pro OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/mac-developer-deployment-guide.md)
+
+
+## :busts_in_silhouette: Společenství
+
++ 📚 [Komunita OpenIM](https://github.com/OpenIMSDK/community)
++ 💕 [Zájmová skupina OpenIM](https://github.com/Openim-sigs)
++ 🚀 [Připojte se k naší komunitě Slack](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q)
++ :eyes: [Připojte se k našemu wechatu](https://openim-1253691595.cos.ap-nanjing.myqcloud.com/WechatIMG20.jpeg)
+
+## :calendar: Komunitní setkání
+
+Chceme, aby se do naší komunity a přispívání kódu zapojil kdokoli, nabízíme dárky a odměny a vítáme vás, abyste se k nám připojili každý čtvrtek večer.
+
+Naše konference je v [OpenIM Slack](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q) 🎯, pak můžete vyhledat kanál Open-IM-Server a připojit se
+
+Zaznamenáváme si každou [dvoutýdenní schůzku](https://github.com/orgs/OpenIMSDK/discussions/categories/meeting)do [diskuzí na GitHubu](https://github.com/openimsdk/open-im-server/discussions/categories/meeting), naše historické poznámky ze schůzek a také záznamy schůzek jsou k dispozici na [Dokumenty Google :bookmark_tabs:](https://docs.google.com/document/d/1nx8MDpuG74NASx081JcCpxPgDITNTpIIos0DS6Vr9GU/edit?usp=sharing).
+
+## :eyes: Kdo používá OpenIM
+
+Podívejte se na naši stránku [případové studie uživatelů](https://github.com/OpenIMSDK/community/blob/main/ADOPTERS.md), kde najdete seznam uživatelů projektu. Neváhejte zanechat[📝komentář](https://github.com/openimsdk/open-im-server/issues/379) a podělte se o svůj případ použití.
+
+## :page_facing_up: License
+
+OpenIM je licencován pod licencí Apache 2.0. Úplný text licence naleznete v [LICENCE](https://github.com/openimsdk/open-im-server/tree/main/LICENSE).
+
+Logo OpenIM, včetně jeho variací a animovaných verzí, zobrazené v tomto úložišti [OpenIM](https://github.com/openimsdk/open-im-server)v adresářích [assets/logo](./assets/logo) a [assets/logo-gif](assets/logo-gif) je chráněno autorským právem.
+
+## 🔮 Děkujeme našim přispěvatelům!
+
+
+
+
diff --git a/docs/readme/README_da.md b/docs/readme/README_da.md
new file mode 100644
index 000000000..1b776ddb8
--- /dev/null
+++ b/docs/readme/README_da.md
@@ -0,0 +1,192 @@
+
+
+
+
+
+
+
+
+[](https://github.com/openimsdk/open-im-server/stargazers)
+[](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/)
+
+
+
+ Englist ·
+ 中文 ·
+ Українська ·
+ Česky ·
+ Magyar ·
+ Español ·
+ فارسی ·
+ Français ·
+ Deutsch ·
+ Polski ·
+ Indonesian ·
+ Suomi ·
+ മലയാളം ·
+ 日本語 ·
+ Nederlands ·
+ Italiano ·
+ Русский ·
+ Português (Brasil) ·
+ Esperanto ·
+ 한국어 ·
+ العربي ·
+ Tiếng Việt ·
+ Dansk ·
+ Ελληνικά ·
+ Türkçe
+
+
+
+
+
+
+
+
+## :busts_in_silhouette: Fællesskab
+
++ 📚 [OpenIM-fællesskab](https://github.com/OpenIMSDK/community)
++ 💕 [OpenIM-interessegruppe](https://github.com/Openim-sigs)
++ 🚀 [Deltag i vores Slack-fællesskab](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q)
++ :eyes: [Deltag i vores WeChat (微信群)](https://openim-1253691595.cos.ap-nanjing.myqcloud.com/WechatIMG20.jpeg)
++ 👫 [Deltag i vores Reddit](https://www.reddit.com/r/OpenIMessaging)
++ 💬 [Følg vores Twitter-konto](https://twitter.com/openimsdk)
+
+
+## Ⓜ️ Om OpenIM
+
+OpenIM er en serviceplatform designet specifikt til integration af chat, lyd-videoopkald, notifikationer og AI-chatbots i applikationer. Den tilbyder en række kraftfulde API'er og Webhooks, som gør det let for udviklere at integrere disse interaktive funktioner i deres applikationer. OpenIM er ikke en selvstændig chatapplikation, men fungerer snarere som en platform, der understøtter andre applikationer i at opnå omfattende kommunikationsfunktionaliteter. Følgende diagram illustrerer interaktionen mellem AppServer, AppClient, OpenIMServer og OpenIMSDK for at forklare detaljeret.
+
+
+
+
+
+## 🚀 Om OpenIMSDK
+
+ **OpenIMSDK** er en IM SDK designet til **OpenIMServer**, skabt specifikt til indlejring i klientapplikationer. Dens vigtigste funktioner og moduler er som følger:
+
++ 🌟 Hovedfunktioner:
+
+ - 📦 Lokal lagring
+ - 🔔 Lytter-callbacks
+ - 🛡️ API-indkapsling
+ - 🌐 Forbindelsesstyring
+
+ ## 📚 Hovedmoduler:
+
+ 1. 🚀 Initialisering og login
+ 2. 👤 Brugerstyring
+ 3. 👫 Venstyring
+ 4. 🤖 Gruppefunktioner
+ 5. 💬 Håndtering af samtaler
+
+Det er bygget ved hjælp af Golang og understøtter tværplatformsudrulning, hvilket sikrer en konsekvent adgangsoplevelse på tværs af alle platforme.
+
+👉 **[Udforsk GO SDK](https://github.com/openimsdk/openim-sdk-core)**
+
+## 🌐 Om OpenIMServer
+
++ **OpenIMServer** har følgende karakteristika:
+ - 🌐 Mikroservicarkitektur: Understøtter klyngetilstand, inklusive en gateway og flere rpc-tjenester.
+ - 🚀 Forskellige udrulningsmetoder: Understøtter udrulning via kildekode, Kubernetes eller Docker.
+ - Støtte til massiv brugerbase: Super store grupper med hundredtusinder af brugere, titusinder af brugere og milliarder af beskeder.
+
+### Forbedret forretningsfunktionalitet:
+
++ **REST API**:OpenIMServer tilbyder REST API'er til forretningssystemer, med det formål at give virksomheder flere funktioner, såsom at oprette grupper og sende push-beskeder gennem backend-grænseflader.
++ **Webhooks**:OpenIMServer giver mulighed for callback-funktionalitet for at udvide flere forretningsformer. Et callback betyder, at OpenIMServer sender en anmodning til forretningsserveren før eller efter en bestemt begivenhed, som callbacks før eller efter at have sendt en besked.
+
+👉 **[Lær mere](https://docs.openim.io/guides/introduction/product)**
+
+## :building_construction: Samlet Arkitektur
+
+Dyk ned i hjertet af Open-IM-Servers funktionalitet med vores arkitekturdiagram.
+
+
+
+## :rocket: Hurtig start
+
+Vi understøtter mange platforme. Her er adresserne for hurtig oplevelse på websiden:
+
+👉 **[OpenIM online demo](https://www.openim.io/zh/commercial)**
+
+🤲 For at lette brugeroplevelsen tilbyder vi forskellige udrulningsløsninger. Du kan vælge din udrulningsmetode fra listen nedenfor:
+
++ **[Vejledning til udrulning af kildekode](https://docs.openim.io/guides/gettingStarted/imSourceCodeDeployment)**
++ **[Vejledning til Docker-udrulning](https://docs.openim.io/guides/gettingStarted/dockerCompose)**
++ **[Vejledning til Kubernetes-udrulning](https://docs.openim.io/guides/gettingStarted/k8s-deployment)**
++ **[Vejledning til Mac-udviklerudrulning](https://docs.openim.io/guides/gettingstarted/mac-deployment-guide)**
+
+## :hammer_and_wrench: For at starte udviklingen af OpenIM
+
+[](https://vscode.dev/github/openimsdk/open-im-server)
+
+OpenIM Vores mål er at bygge et topniveau åben kildekode-fællesskab. Vi har et sæt standarder i [Community-repositoriet](https://github.com/OpenIMSDK/community).
+
+Hvis du gerne vil bidrage til dette Open-IM-Server-repositorium, bedes du læse vores [dokumentation for bidragydere](https://github.com/openimsdk/open-im-server/blob/main/CONTRIBUTING.md).
+
+Før du starter, skal du sikre dig, at dine ændringer er efterspurgte. Det bedste for det er at oprette en [ny diskussion](https://github.com/openimsdk/open-im-server/discussions/new/choose) ELLER [Slack-kommunikation](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q), eller hvis du finder et problem, [rapportere det](https://github.com/openimsdk/open-im-server/issues/new/choose) først.
+
+- [OpenIM API-referencer](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/api.md)
+- [OpenIM Bash-logging](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/bash-log.md)
+- [OpenIM CI/CD-handlinger](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/cicd-actions.md)
+- [OpenIM kodekonventioner](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/code-conventions.md)
+- [OpenIM commit-retningslinjer](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/commit.md)
+- [OpenIM udviklingsguide](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/development.md)
+- [OpenIM mappestruktur](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/directory.md)
+- [OpenIM miljøopsætning](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/environment.md)
+- [OpenIM fejlkode-reference](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/error-code.md)
+- [OpenIM Git-arbejdsgang](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/git-workflow.md)
+- [OpenIM Git Cherry Pick-guide](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/gitcherry-pick.md)
+- [OpenIM GitHub-arbejdsgang](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/github-workflow.md)
+- [OpenIM Go kode-standarder](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/go-code.md)
+- [OpenIM billedretningslinjer](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/images.md)
+- [OpenIM initialkonfiguration](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/init-config.md)
+- [OpenIM Docker installationsguide](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/install-docker.md)
+- [OpenIM OpenIM Linux-systeminstallation](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/install-openim-linux-system.md)
+- [OpenIM Linux-udviklingsguide](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/linux-development.md)
+- [OpenIM lokale handlingsguide](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/local-actions.md)
+- [OpenIM logningskonventioner](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/logging.md)
+- [OpenIM offline-udrulning](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/offline-deployment.md)
+- [OpenIM Protoc-værktøjer](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/protoc-tools.md)
+- [OpenIM testguide](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/test.md)
+- [OpenIM Utility Go](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/util-go.md)
+- [OpenIM Makefile-værktøjer](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/util-makefile.md)
+- [OpenIM skriptværktøjer](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/util-scripts.md)
+- [OpenIM versionsstyring](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/version.md)
+- [Administrer backend og overvåg udrulning](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/prometheus-grafana.md)
+- [Mac-udviklerudrulningsguide for OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/mac-developer-deployment-guide.md)
+
+
+## :calendar: Fællesskabsmøder
+
+Vi ønsker, at alle involverer sig i vores fællesskab og bidrager med kode, vi tilbyder gaver og belønninger, og vi byder dig velkommen til at deltage hver torsdag aften.
+
+Vores konference er på [OpenIM Slack](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q) 🎯, derefter kan du søge Open-IM-Server pipeline for at deltage.
+
+Vi tager [notater](https://github.com/orgs/OpenIMSDK/discussions/categories/meeting) af hvert fjortendages møde i [GitHub-diskussioner](https://github.com/openimsdk/open-im-server/discussions/categories/meeting), Vores historiske mødenotater samt genudsendelser af møderne er tilgængelige på [Google Docs](https://docs.google.com/document/d/1nx8MDpuG74NASx081JcCpxPgDITNTpIIos0DS6Vr9GU/edit?usp=sharing) 📑.
+
+## :eyes: Hvem Bruger OpenIM
+
+Tjek vores side med [brugercasestudier](https://github.com/OpenIMSDK/community/blob/main/ADOPTERS.md) for en liste over projektbrugerne. Tøv ikke med at efterlade en 📝[kommentar](https://github.com/openimsdk/open-im-server/issues/379) og dele dit brugstilfælde.
+
+## :page_facing_up: Licens
+
+OpenIM er licenseret under Apache 2.0-licensen. Se [LICENSE](https://github.com/openimsdk/open-im-server/tree/main/LICENSE) for den fulde licens tekst.
+
+OpenIM-logoet, inklusive dets variationer og animerede versioner, vist i dette repositorium [OpenIM](https://github.com/openimsdk/open-im-server) under mapperne [assets/logo](../../assets/logo) og [assets/logo-gif](../../assets/logo-gif), er beskyttet af ophavsretslove.
+
+## 🔮 Tak til vores bidragydere!
+
+
+
+
\ No newline at end of file
diff --git a/docs/readme/README_el.md b/docs/readme/README_el.md
new file mode 100644
index 000000000..252521f35
--- /dev/null
+++ b/docs/readme/README_el.md
@@ -0,0 +1,186 @@
+
+
+
+
+
+
+
+
+[](https://github.com/openimsdk/open-im-server/stargazers)
+[](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/)
+
+
+
+ Englist ·
+ 中文 ·
+ Українська ·
+ Česky ·
+ Magyar ·
+ Español ·
+ فارسی ·
+ Français ·
+ Deutsch ·
+ Polski ·
+ Indonesian ·
+ Suomi ·
+ മലയാളം ·
+ 日本語 ·
+ Nederlands ·
+ Italiano ·
+ Русский ·
+ Português (Brasil) ·
+ Esperanto ·
+ 한국어 ·
+ العربي ·
+ Tiếng Việt ·
+ Dansk ·
+ Ελληνικά ·
+ Türkçe
+
+
+
+
+
+
+
+## Ⓜ️ Σχετικά με το OpenIM
+
+Το OpenIM είναι μια πλατφόρμα υπηρεσιών σχεδιασμένη ειδικά για την ενσωμάτωση συνομιλίας, κλήσεων ήχου-βίντεο, ειδοποιήσεων και chatbots AI σε εφαρμογές. Παρέχει μια σειρά από ισχυρά API και Webhooks, επιτρέποντας στους προγραμματιστές να ενσωματώσουν εύκολα αυτές τις αλληλεπιδραστικές λειτουργίες στις εφαρμογές τους. Το OpenIM δεν είναι μια αυτόνομη εφαρμογή συνομιλίας, αλλά λειτουργεί ως πλατφόρμα υποστήριξης άλλων εφαρμογών για την επίτευξη πλούσιων λειτουργιών επικοινωνίας. Το παρακάτω διάγραμμα απεικονίζει την αλληλεπίδραση μεταξύ AppServer, AppClient, OpenIMServer και OpenIMSDK για να εξηγήσει αναλυτικά.
+
+
+
+## 🚀 Σχετικά με το OpenIMSDK
+
+Το **OpenIMSDK** είναι ένα SDK για αμεση ανταλλαγή μηνυμάτων σχεδιασμένο για το **OpenIMServer**, δημιουργήθηκε ειδικά για ενσωμάτωση σε εφαρμογές πελατών. Οι κύριες δυνατότητες και μονάδες του είναι οι εξής:
+
++ 🌟 Κύριες Δυνατότητες:
+
+ - 📦 Τοπική αποθήκευση
+ - 🔔 Callbacks ακροατών
+ - 🛡️ Περιτύλιγμα API
+ - 🌐 Διαχείριση σύνδεσης
+
++ 📚 Κύριες Μονάδες:
+
+ 1. 🚀 Αρχικοποίηση και Σύνδεση
+ 2. 👤 Διαχείριση Χρηστών
+ 3. 👫 Διαχείριση Φίλων
+ 4. 🤖 Λειτουργίες Ομάδας
+ 5. 💬 Διαχείριση Συνομιλιών
+
+Είναι κατασκευασμένο χρησιμοποιώντας Golang και υποστηρίζει διασταυρούμενη πλατφόρμα ανάπτυξης, διασφαλίζοντας μια συνεπή εμπειρία πρόσβασης σε όλες τις πλατφόρμες.
+
+👉 **[Εξερευνήστε το GO SDK](https://github.com/openimsdk/openim-sdk-core)**
+
+## 🌐 Σχετικά με το OpenIMServer
+
++ Το **OpenIMServer** έχει τις ακόλουθες χαρακτηριστικές:
+ - 🌐 Αρχιτεκτονική μικροϋπηρεσιών: Υποστηρίζει λειτουργία σε σύμπλεγμα, περιλαμβάνοντας έναν πύλη και πολλαπλές υπηρεσίες rpc.
+ - 🚀 Διάφοροι τρόποι ανάπτυξης: Υποστηρίζει ανάπτυξη μέσω πηγαίου κώδικα, Kubernetes, ή Docker.
+ - Υποστήριξη για τεράστια βάση χρηστών: Πολύ μεγάλες ομάδες με εκατοντάδες χιλιάδες χρήστες, δεκάδες εκατομμύρια χρήστες και δισεκατομμύρια μηνύματα.
+
+### Ενισχυμένη Επιχειρηματική Λειτουργικότητα:
+
++ **REST API**: Το OpenIMServer προσφέρει REST APIs για επιχειρηματικά συστήματα, με στόχο την ενδυνάμωση των επιχειρήσεων με περισσότερες λειτουργικότητες, όπως η δημιουργία ομάδων και η αποστολή μηνυμάτων push μέσω backend διεπαφών.
++ **Webhooks**: Το OpenIMServer παρέχει δυνατότητες επανάκλησης για την επέκταση περισσότερων επιχειρηματικών μορφών. Μια επανάκληση σημαίνει ότι το OpenIMServer στέλνει ένα αίτημα στον επιχειρηματικό διακομιστή πριν ή μετά από ένα συγκεκριμένο γεγονός, όπως επανακλήσεις πριν ή μετά την αποστολή ενός μηνύματος.
+
+👉 **[Μάθετε περισσότερα](https://docs.openim.io/guides/introduction/product)**
+
+## :building_construction: Συνολική Αρχιτεκτονική
+
+Εξερευνήστε σε βάθος τη λειτουργικότητα του Open-IM-Server με το διάγραμμα αρχιτεκτονικής μας.
+
+
+
+
+## :rocket: Γρήγορη Εκκίνηση
+
+Υποστηρίζουμε πολλές πλατφόρμες. Εδώ είναι οι διευθύνσεις για γρήγορη εμπειρία στην πλευρά του διαδικτύου:
+
+👉 **[Διαδικτυακή επίδειξη του OpenIM](https://web-enterprise.rentsoft.cn/)**
+
+🤲 Για να διευκολύνουμε την εμπειρία του χρήστη, προσφέρουμε διάφορες λύσεις ανάπτυξης. Μπορείτε να επιλέξετε τη μέθοδο ανάπτυξης σας από την παρακάτω λίστα:
+
++ **[Οδηγός Ανάπτυξης Κώδικα Πηγής](https://docs.openim.io/guides/gettingStarted/imSourceCodeDeployment)**
++ **[δηγός Ανάπτυξης μέσω Docker](https://docs.openim.io/guides/gettingStarted/dockerCompose)**
++ **[Οδηγός Ανάπτυξης Kubernetes](https://docs.openim.io/guides/gettingStarted/k8s-deployment)**
++ **[Οδηγός Ανάπτυξης για Αναπτυξιακούς στο Mac](https://docs.openim.io/guides/gettingstarted/mac-deployment-guide)**
+
+## :hammer_and_wrench: Για να Αρχίσετε την Ανάπτυξη του OpenIM
+
+[](https://vscode.dev/github/openimsdk/open-im-server)
+
+OpenIM Στόχος μας είναι να δημιουργήσουμε μια κορυφαίου επιπέδου ανοιχτή πηγή κοινότητας. Διαθέτουμε ένα σύνολο προτύπων, στο [Αποθετήριο Κοινότητας](https://github.com/OpenIMSDK/community).
+
+Εάν θέλετε να συνεισφέρετε σε αυτό το αποθετήριο Open-IM-Server, παρακαλούμε διαβάστε την [τεκμηρίωση συνεισφέροντος](https://github.com/openimsdk/open-im-server/blob/main/CONTRIBUTING.md).
+
+Πριν ξεκινήσετε, παρακαλούμε βεβαιωθείτε ότι οι αλλαγές σας είναι ζητούμενες. Το καλύτερο για αυτό είναι να δημιουργήσετε ένα [νέα συζήτηση](https://github.com/openimsdk/open-im-server/discussions/new/choose) ή [Επικοινωνία Slack](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q), ή αν βρείτε ένα ζήτημα, [αναφέρετέ το](https://github.com/openimsdk/open-im-server/issues/new/choose) πρώτα.
+
+- [Αναφορά API του OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/api.md)
+- [Καταγραφή Bash του OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/bash-log.md)
+- [Ενέργειες CI/CD του OpenIMs](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/cicd-actions.md)
+- [Συμβάσεις Κώδικα του OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/code-conventions.md)
+- [Οδηγίες Commit του OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/commit.md)
+- [Οδηγός Ανάπτυξης του OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/development.md)
+- [Δομή Καταλόγου του OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/directory.md)
+- [Ρύθμιση Περιβάλλοντος του OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/environment.md)
+- [Αναφορά Κωδικών Σφάλματος του OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/error-code.md)
+- [Ροή Εργασίας Git του OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/git-workflow.md)
+- [Οδηγός Cherry Pick του Git του OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/gitcherry-pick.md)
+- [Ροή Εργασίας GitHub του OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/github-workflow.md)
+- [Πρότυπα Κώδικα Go του OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/go-code.md)
+- [Οδηγίες Εικόνας του OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/images.md)
+- [Αρχική Διαμόρφωση του OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/init-config.md)
+- [Οδηγός Εγκατάστασης Docker του OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/install-docker.md)
+- [Οδηγός Εγκατάστασης Συστήματος Linux του Open](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/install-openim-linux-system.md)
+- [Οδηγός Ανάπτυξης Linux του OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/linux-development.md)
+- [Οδηγός Τοπικών Δράσεων του OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/local-actions.md)
+- [Συμβάσεις Καταγραφής του OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/logging.md)
+- [Αποστολή Εκτός Σύνδεσης του OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/offline-deployment.md)
+- [Εργαλεία Protoc του OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/protoc-tools.md)
+- [Οδηγός Δοκιμών του OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/test.md)
+- [Χρησιμότητα Go του OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/util-go.md)
+- [Χρησιμότητες Makefile του OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/util-makefile.md)
+- [Χρησιμότητες Σεναρίου του OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/util-scripts.md)
+- [Έκδοση του OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/version.md)
+- [Διαχείριση backend και παρακολούθηση ανάπτυξης](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/prometheus-grafana.md)
+- [Οδηγός Ανάπτυξης για Προγραμματιστές Mac του OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/mac-developer-deployment-guide.md)
+
+
+## :busts_in_silhouette: Κοινότητα
+
++ 📚 [Κοινότητα OpenIM](https://github.com/OpenIMSDK/community)
++ 💕 [Ομάδα Ενδιαφέροντος OpenIM](https://github.com/Openim-sigs)
++ 🚀 [Εγγραφείτε στην κοινότητα Slack μας](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q)
++ :eyes: [γγραφείτε στην ομάδα μας wechat (微信群)](https://openim-1253691595.cos.ap-nanjing.myqcloud.com/WechatIMG20.jpeg)
+
+## :calendar: Συναντήσεις της κοινότητας
+
+Θέλουμε οποιονδήποτε να εμπλακεί στην κοινότητά μας και να συνεισφέρει κώδικα. Προσφέρουμε δώρα και ανταμοιβές και σας καλωσορίζουμε να μας ενταχθείτε κάθε Πέμπτη βράδυ.
+
+Η διάσκεψή μας είναι στο [OpenIM Slack](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q) 🎯, στη συνέχεια μπορείτε να αναζητήσετε τη διαδικασία Open-IM-Server για να συμμετάσχετε
+
+Κάνουμε σημειώσεις για κάθε μια [Σημειώνουμε κάθε διμηνιαία συνάντηση](https://github.com/orgs/OpenIMSDK/discussions/categories/meeting) στις [συζητήσεις του GitHub](https://github.com/openimsdk/open-im-server/discussions/categories/meeting), Οι ιστορικές μας σημειώσεις συναντήσεων, καθώς και οι επαναλήψεις των συναντήσεων είναι διαθέσιμες στο[Έγγραφα της Google :bookmark_tabs:](https://docs.google.com/document/d/1nx8MDpuG74NASx081JcCpxPgDITNTpIIos0DS6Vr9GU/edit?usp=sharing).
+
+## :eyes: Ποιοί Χρησιμοποιούν το OpenIM
+
+Ελέγξτε τη σελίδα με τις [μελέτες περίπτωσης χρήσης ](https://github.com/OpenIMSDK/community/blob/main/ADOPTERS.md) μας για μια λίστα των χρηστών του έργου. Μην διστάσετε να αφήσετε ένα[📝σχόλιο](https://github.com/openimsdk/open-im-server/issues/379) και να μοιραστείτε την περίπτωση χρήσης σας.
+## :page_facing_up: Άδεια Χρήσης
+
+Το OpenIM διατίθεται υπό την άδεια Apache 2.0. Δείτε τη [ΑΔΕΙΑ ΧΡΗΣΗΣ](https://github.com/openimsdk/open-im-server/tree/main/LICENSE) για το πλήρες κείμενο της άδειας.
+
+Το λογότυπο του OpenIM, συμπεριλαμβανομένων των παραλλαγών και των κινούμενων εικόνων, που εμφανίζονται σε αυτό το αποθετήριο[OpenIM](https://github.com/openimsdk/open-im-server) υπό τις διευθύνσεις [assets/logo](../../assets/logo) και [assets/logo-gif](../../assets/logo-gif) προστατεύονται από τους νόμους περί πνευματικής ιδιοκτησίας.
+
+## 🔮 Ευχαριστούμε τους συνεισφέροντες μας!
+
+
+
+
diff --git a/docs/readme/README_es.md b/docs/readme/README_es.md
new file mode 100644
index 000000000..cd1b7290e
--- /dev/null
+++ b/docs/readme/README_es.md
@@ -0,0 +1,193 @@
+
+
+
+
+
+
+
+
+[](https://github.com/openimsdk/open-im-server/stargazers)
+[](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/)
+
+
+
+ Englist ·
+ 中文 ·
+ Українська ·
+ Česky ·
+ Magyar ·
+ Español ·
+ فارسی ·
+ Français ·
+ Deutsch ·
+ Polski ·
+ Indonesian ·
+ Suomi ·
+ മലയാളം ·
+ 日本語 ·
+ Nederlands ·
+ Italiano ·
+ Русский ·
+ Português (Brasil) ·
+ Esperanto ·
+ 한국어 ·
+ العربي ·
+ Tiếng Việt ·
+ Dansk ·
+ Ελληνικά ·
+ Türkçe
+
+
+
+
+
+
+
+## Ⓜ️ Acerca de OpenIM
+
+OpenIM es una plataforma de servicio diseñada específicamente para integrar chat, llamadas de audio y video, notificaciones y chatbots de IA en aplicaciones. Proporciona una gama de potentes API y Webhooks, lo que permite a los desarrolladores incorporar fácilmente estas características interactivas en sus aplicaciones. OpenIM no es una aplicación de chat independiente, sino que sirve como una plataforma para apoyar a otras aplicaciones en lograr funcionalidades de comunicación enriquecidas. El siguiente diagrama ilustra la interacción entre AppServer, AppClient, OpenIMServer y OpenIMSDK para explicar en detalle.
+
+
+
+## 🚀 Acerca de OpenIMSDK
+
+**OpenIMSDK** es un SDK de mensajería instantánea diseñado para **OpenIMServer**, creado específicamente para su incorporación en aplicaciones cliente. Sus principales características y módulos son los siguientes:
+
++ 🌟 Características Principales:
+
+ - 📦 Almacenamiento local
+ - 🔔 Callbacks de escuchas
+ - 🛡️ Envoltura de API
+ - 🌐 Gestión de conexiones
+
++ 📚 Módulos Principales:
+
+ 1. 🚀 Inicialización y acceso
+ 2. 👤 Gestión de usuarios
+ 3. 👫 Gestión de amigos
+ 4. 🤖 Funciones de grupo
+ 5. 💬 Manejo de conversaciones
+
+Está construido con Golang y soporta despliegue multiplataforma, asegurando una experiencia de acceso consistente en todas las plataformas.
+
+👉 **[Explora el SDK de GO](https://github.com/openimsdk/openim-sdk-core)**
+
+## 🌐 Acerca de OpenIMServer
+
++ **OpenIMServer** tiene las siguientes características:
+ - 🌐 Arquitectura de microservicios: Soporta modo cluster, incluyendo un gateway y múltiples servicios rpc.
+ - 🚀 Métodos de despliegue diversos: Soporta el despliegue a través de código fuente, Kubernetes o Docker.
+ - Soporte para una base de usuarios masiva: Grupos super grandes con cientos de miles de usuarios, decenas de millones de usuarios y miles de millones de mensajes.
+
+
+
+### Funcionalidad Empresarial Mejorada:
+
++ **API REST**: OpenIMServer ofrece APIs REST para sistemas empresariales, destinadas a empoderar a las empresas con más funcionalidades, como la creación de grupos y el envío de mensajes push a través de interfaces de backend.
++ **Webhooks**: OpenIMServer proporciona capacidades de callback para extender más formas de negocio. Un callback significa que OpenIMServer envía una solicitud al servidor empresarial antes o después de un cierto evento, como callbacks antes o después de enviar un mensaje.
+
+👉 **[Aprende más](https://docs.openim.io/guides/introduction/product)**
+
+## :building_construction: Arquitectura General
+
+Adéntrate en el corazón de la funcionalidad de Open-IM-Server con nuestro diagrama de arquitectura.
+
+
+
+
+## :rocket: Inicio Rápido
+
+
+:rocket: Inicio Rápido
+Apoyamos muchas plataformas. Aquí están las direcciones para una experiencia rápida en el lado web:
+
+👉 **[ Demostración web en línea de OpenIM](https://web-enterprise.rentsoft.cn/)**
+
+🤲 Para facilitar la experiencia del usuario, ofrecemos varias soluciones de despliegue. Puedes elegir tu método de despliegue de la lista a continuación:
+
++ **[Guía de Despliegue de Código Fuente](https://docs.openim.io/guides/gettingStarted/imSourceCodeDeployment)**
++ **[Guía de Despliegue con Docker](https://docs.openim.io/guides/gettingStarted/dockerCompose)**
++ **[Guía de Despliegue con Kubernetes](https://docs.openim.io/guides/gettingStarted/k8s-deployment)**
++ **[Guía de Despliegue para Desarrolladores en Mac](https://docs.openim.io/guides/gettingstarted/mac-deployment-guide)**
+
+## :hammer_and_wrench: Para Comenzar a Desarrollar en OpenIM
+
+[](https://vscode.dev/github/openimsdk/open-im-server)
+
+Nuestro objetivo en OpenIM es construir una comunidad de código abierto de nivel superior. Tenemos un conjunto de estándares,
+en el [repositorio de la Comunidad.](https://github.com/OpenIMSDK/community).
+
+Si te gustaría contribuir a este repositorio de Open-IM-Server, por favor lee nuestra [documentación para colaboradores](https://github.com/openimsdk/open-im-server/blob/main/CONTRIBUTING.md).
+
+
+Antes de comenzar, asegúrate de que tus cambios sean demandados. Lo mejor para eso es crear una [nueva discusión](https://github.com/openimsdk/open-im-server/discussions/new/choose) O [Comunicación en Slack](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q), o si encuentras un problema, [repórtalo](https://github.com/openimsdk/open-im-server/issues/new/choose) primero.
+
+- [Referencia de API de OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/api.md)
+- [Registro de Bash de OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/bash-log.md)
+- [Acciones de CI/CD de OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/cicd-actions.md)
+- [Convenciones de Código de OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/code-conventions.md)
+- [Guías de Commit de OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/commit.md)
+- [Guía de Desarrollo de OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/development.md)
+- [Estructura de Directorios de OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/directory.md)
+- [Configuración de Entorno de OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/environment.md)
+- [Referencia de Códigos de Error de OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/error-code.md)
+- [Flujo de Trabajo de Git de OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/git-workflow.md)
+- [Guía de Cherry Pick de Git de OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/gitcherry-pick.md)
+- [Flujo de Trabajo de GitHub de OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/github-workflow.md)
+- [Estándares de Código Go de OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/go-code.md)
+- [Guías de Imágenes de OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/images.md)
+- [Configuración Inicial de OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/init-config.md)
+- [Guía de Instalación de Docker de OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/install-docker.md)
+- [Instalación del Sistema Linux de OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/install-openim-linux-system.md)
+- [Guía de Desarrollo Linux de OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/linux-development.md)
+- [Guía de Acciones Locales de OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/local-actions.md)
+- [Convenciones de Registro de OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/logging.md)
+- [Despliegue sin Conexión de OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/offline-deployment.md)
+- [Herramientas Protoc de OpenIMM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/protoc-tools.md)
+- [Guía de Pruebas de OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/test.md)
+- [Utilidades Go de OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/util-go.md)
+- [Utilidades de Makefile de OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/util-makefile.md)
+- [Utilidades de Script de OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/util-scripts.md)
+- [Versionado de OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/version.md)
+- [Gestión de backend y despliegue de monitoreo](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/prometheus-grafana.md)
+- [Guía de Despliegue para Desarrolladores Mac de OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/mac-developer-deployment-guide.md)
+
+
+## :busts_in_silhouette: Comunidad
+
++ 📚 [Comunidad de OpenIM](https://github.com/OpenIMSDK/community)
++ 💕 [Grupo de Interés de OpenIM](https://github.com/Openim-sigs)
++ 🚀 [Únete a nuestra comunidad de Slack](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q)
++ :eyes: [Únete a nuestro wechat (微信群)](https://openim-1253691595.cos.ap-nanjing.myqcloud.com/WechatIMG20.jpeg)
+
+## :calendar: Reuniones de la Comunidad
+
+Queremos que cualquiera se involucre en nuestra comunidad y contribuya con código, ofrecemos regalos y recompensas, y te damos la bienvenida para que te unas a nosotros cada jueves por la noche.
+
+Nuestra conferencia está en [OpenIM Slack](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q) 🎯, luego puedes buscar el pipeline de Open-IM-Server para unirte
+
+Tomamos notas de cada [reunión quincenal](https://github.com/orgs/OpenIMSDK/discussions/categories/meeting) en [discusiones de GitHub](https://github.com/openimsdk/open-im-server/discussions/categories/meeting), Nuestras notas de reuniones históricas, así como las repeticiones de las reuniones están disponibles en [Google Docs :bookmark_tabs:](https://docs.google.com/document/d/1nx8MDpuG74NASx081JcCpxPgDITNTpIIos0DS6Vr9GU/edit?usp=sharing).
+
+## :eyes: Quiénes Están Usando OpenIM
+
+Consulta nuestros [estudios de caso de usuarios](https://github.com/OpenIMSDK/community/blob/main/ADOPTERS.md) página para obtener una lista de los usuarios del proyecto. No dudes en dejar un [📝comentario](https://github.com/openimsdk/open-im-server/issues/379) y compartir tu caso de uso.
+## :page_facing_up: Licencia
+
+
+OpenIM está bajo la licencia Apache 2.0. Consulta [LICENSE](https://github.com/openimsdk/open-im-server/tree/main/LICENSE) para ver el texto completo de la licencia.
+
+
+El logotipo de OpenIM, incluyendo sus variaciones y versiones animadas, que se muestran en este repositorio [OpenIM](https://github.com/openimsdk/open-im-server) en los directorios [assets/logo](../../assets/logo) y [assets/logo-gif](assets/logo-gif) están protegidos por las leyes de derechos de autor.
+## 🔮 iGracias a nuestros colaboradores!
+
+
+
+
diff --git a/docs/readme/README_fa.md b/docs/readme/README_fa.md
new file mode 100644
index 000000000..49f05cd4c
--- /dev/null
+++ b/docs/readme/README_fa.md
@@ -0,0 +1,187 @@
+
+
+
+
+
+
+
+
+[](https://github.com/openimsdk/open-im-server/stargazers)
+[](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/)
+
+
+
+ Englist ·
+ 中文 ·
+ Українська ·
+ Česky ·
+ Magyar ·
+ Español ·
+ فارسی ·
+ Français ·
+ Deutsch ·
+ Polski ·
+ Indonesian ·
+ Suomi ·
+ മലയാളം ·
+ 日本語 ·
+ Nederlands ·
+ Italiano ·
+ Русский ·
+ Português (Brasil) ·
+ Esperanto ·
+ 한국어 ·
+ العربي ·
+ Tiếng Việt ·
+ Dansk ·
+ Ελληνικά ·
+ Türkçe
+
+
+
+
+
+
+
+## درباره OpenIM Ⓜ️
+
+OpenIM یک پلتفرم خدماتی است که به طور خاص برای ادغام چت، تماس های صوتی و تصویری، اعلان ها و چت ربات های هوش مصنوعی در برنامه ها طراحی شده است. این مجموعه ای از API ها و Webhook های قدرتمند را ارائه می دهد که به توسعه دهندگان این امکان را می دهد تا به راحتی این ویژگی های تعاملی را در برنامه های خود بگنجانند. OpenIM یک برنامه چت مستقل نیست، بلکه به عنوان یک پلتفرم برای پشتیبانی از برنامه های کاربردی دیگر در دستیابی به قابلیت های ارتباطی غنی عمل می کند. نمودار زیر تعامل بین AppServer، AppClient، OpenIMServer و OpenIMSDK را برای توضیح جزئیات نشان می دهد.
+
+
+
+## 🚀 درباره OpenIMSDK
+
+**OpenIMSDK** یک IM SDK است که برای **OpenIMServer** طراحی شده است که به طور خاص برای جاسازی در برنامه های مشتری ایجاد شده است. ویژگی ها و ماژول های اصلی آن به شرح زیر است:
+
++ 🌟 ویژگی های اصلی:
+
+ - 📦 ذخیره سازی محلی
+ - 🔔 پاسخ تماس شنونده
+ - 🛡️ بسته بندی API
+ - 🌐 مدیریت اتصال
+
++ 📚 ماژول های اصلی:
+
+ 1. 🚀 مقداردهی اولیه و ورود
+ 2. 👤 مدیریت کاربر
+ 3. 👫 مدیریت دوست
+ 4. 🤖 توابع گروه
+ 5. 💬 مدیریت مکالمه
+
+این برنامه با استفاده از Golang ساخته شده است و از استقرار چند پلت فرم پشتیبانی می کند و تجربه دسترسی ثابت را در تمام پلتفرم ها تضمین می کند.
+
+👉 **[کاوش GO SDK](https://github.com/openimsdk/openim-sdk-core)**
+
+## 🌐 درباره OpenIMServer
+
++ **OpenIMServer** دارای ویژگی های زیر است:
+ - 🌐 معماری Microservice: از حالت کلاستر، از جمله یک دروازه و چندین سرویس rpc پشتیبانی می کند.
+ - 🚀 روشهای استقرار متنوع: از استقرار از طریق کد منبع، Kubernetes یا Docker پشتیبانی میکند.
+ - پشتیبانی از پایگاه عظیم کاربران: گروه های فوق العاده بزرگ با صدها هزار کاربر، ده ها میلیون کاربر و میلیاردها پیام.
+
+### عملکردهای تجاری پیشرفته:
+
++ **REST API**: OpenIMServer APIهای REST را برای سیستمهای تجاری ارائه میکند، با هدف توانمندسازی کسبوکارها با قابلیتهای بیشتر، مانند ایجاد گروهها و ارسال پیامهای فشار از طریق رابطهای باطنی.
++ **Webhooks**: OpenIMServer قابلیت های پاسخ به تماس را برای گسترش بیشتر فرم های تجاری ارائه می دهد. پاسخ به تماس به این معنی است که OpenIMServer درخواستی را قبل یا بعد از یک رویداد خاص به سرور تجاری ارسال می کند، مانند تماس های قبل یا بعد از ارسال یک پیام.
+
+👉 **[بیشتر بدانید](https://docs.openim.io/guides/introduction/product)**
+
+## :building_construction: معماری کلی
+
+با نمودار معماری ما به قلب عملکرد Open-IM-Server بپردازید.
+
+
+
+
+## :rocket: شروع سریع
+
+ما از بسیاری از پلتفرم ها پشتیبانی می کنیم. در اینجا آدرس هایی برای تجربه سریع در سمت وب آمده است:
+
+👉 **[نسخه نمایشی وب آنلاین OpenIM](https://web-enterprise.rentsoft.cn/)**
+
+🤲 برای تسهیل تجربه کاربر، ما راه حل های مختلف استقرار را ارائه می دهیم. می توانید روش استقرار خود را از لیست زیر انتخاب کنید:
+
++ **[راهنمای استقرار کد منبع](https://docs.openim.io/guides/gettingStarted/imSourceCodeDeployment)**
++ **[راهنمای استقرار داکر](https://docs.openim.io/guides/gettingStarted/dockerCompose)**
++ **[راهنمای استقرار Kubernetes](https://docs.openim.io/guides/gettingStarted/k8s-deployment)**
++ **[راهنمای استقرار توسعه دهنده مک](https://docs.openim.io/guides/gettingstarted/mac-deployment-guide)**
+
+## :hammer_and_wrench: برای شروع توسعه OpenIM
+
+[](https://vscode.dev/github/openimsdk/open-im-server)
+
+OpenIM هدف ما ایجاد یک جامعه منبع باز سطح بالا است. ما مجموعه ای از استانداردها را در [مخزن انجمن](https://github.com/OpenIMSDK/community) داریم..
+
+اگر میخواهید در این مخزن Open-IM-Server مشارکت کنید، لطفاً [مستندات مشارکتکننده](https://github.com/openimsdk/open-im-server/blob/main/CONTRIBUTING.md) ما را بخوانید.
+
+قبل از شروع، لطفاً مطمئن شوید که تغییرات شما مورد تقاضا هستند. بهترین کار برای آن این است که یک [بحث جدید](https://github.com/openimsdk/open-im-server/discussions/new/choose) یا [ارتباط اسلک](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q) ایجاد کنید، یا اگر مشکلی پیدا کردید، ابتدا [آن را گزارش کنید](https://github.com/openimsdk/open-im-server/issues/new/choose).
+
+- [مرجع OpenIM API](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/api.md)
+- [OpenIM Bash Logging](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/bash-log.md)
+- [OpenIM CI/CD Actions](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/cicd-actions.md)
+- [کنوانسیون کد OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/code-conventions.md)
+- [دستورالعمل های تعهد OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/commit.md)
+- [راهنمای توسعه OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/development.md)
+- [ساختار دایرکتوری OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/directory.md)
+- [تنظیم محیط OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/environment.md)
+- [مرجع کد خطا OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/error-code.md)
+- [OpenIM Git Workflow](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/git-workflow.md)
+- [راهنمای انتخاب گیلاس OpenIM Git](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/gitcherry-pick.md)
+- [OpenIM GitHub Workflow](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/github-workflow.md)
+- [استانداردهای کد OpenIM Go](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/go-code.md)
+- [دستورالعمل های تصویر OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/images.md)
+- [پیکربندی اولیه OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/init-config.md)
+- [راهنمای نصب OpenIM Docker](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/install-docker.md)
+- [نصب سیستم OpenIM Linux OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/install-openim-linux-system.md)
+- [راهنمای توسعه OpenIM Linux](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/linux-development.md)
+- [راهنمای اقدامات محلی OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/local-actions.md)
+- [OpenIM Logging Conventions](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/logging.md)
+- [استقرار آفلاین OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/offline-deployment.md)
+- [OpenIM Protoc Tools](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/protoc-tools.md)
+- [راهنمای تست OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/test.md)
+- [OpenIM Utility Go](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/util-go.md)
+- [OpenIM Makefile Utilities](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/util-makefile.md)
+- [ابزارهای OpenIM Script](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/util-scripts.md)
+- [نسخه OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/version.md)
+- [مدیریت استقرار باطن و نظارت](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/prometheus-grafana.md)
+- [راهنمای استقرار توسعه دهنده مک برای OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/mac-developer-deployment-guide.md)
+
+
+## :busts_in_silhouette: انجمن
+
++ 📚 [انجمن OpenIM](https://github.com/OpenIMSDK/community)
++ 💕 [گروه علاقه OpenIM](https://github.com/Openim-sigs)
++ 🚀 [به انجمن Slack ما بپیوندید](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q)
++ :eyes: [به وی چت ما بپیوندید](https://openim-1253691595.cos.ap-nanjing.myqcloud.com/WechatIMG20.jpeg)
+
+## :calendar: جلسات جامعه
+
+ما میخواهیم هر کسی در انجمن ما مشارکت کند و در کد مشارکت کند، ما هدایا و جوایزی ارائه میکنیم، و از شما استقبال میکنیم که هر پنجشنبه شب به ما بپیوندید.
+
+کنفرانس ما در [OpenIM Slack](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q) 🎯 است، سپس می توانید خط لوله Open-IM-Server را برای پیوستن جستجو کنید.
+
+ما از هر [جلسه دو هفتهای](https://github.com/orgs/OpenIMSDK/discussions/categories/meeting) در [بحثهای GitHub](https://github.com/openimsdk/open-im-server/discussions/categories/meeting) یادداشتبرداری میکنیم، یادداشتهای جلسه تاریخی ما، و همچنین بازپخش جلسات در [Google Docs :bookmark_tabs:](https://docs.google.com/document/d/1nx8MDpuG74NASx081JcCpxPgDITNTpIIos0DS6Vr9GU/edit?usp=sharing) موجود است.
+
+## :eyes: چه کسانی از OpenIM استفاده می کنند
+
+صفحه [مطالعات موردی کاربر](https://github.com/OpenIMSDK/community/blob/main/ADOPTERS.md) ما را برای لیستی از کاربران پروژه بررسی کنید. از گذاشتن [نظر📝](https://github.com/openimsdk/open-im-server/issues/379) و به اشتراک گذاری مورد استفاده خود دریغ نکنید.
+
+## :page_facing_up: مجوز
+
+OpenIM تحت مجوز Apache 2.0 مجوز دارد. برای متن کامل مجوز به [LICENSE](https://github.com/openimsdk/open-im-server/tree/main/LICENSE) مراجعه کنید.
+
+نشانواره OpenIM، شامل انواع و نسخههای متحرک آن، که در این مخزن [OpenIM](https://github.com/openimsdk/open-im-server) تحت فهرستهای [assets/logo](./assets/logo) و [assets/logo-gif](assets/logo-gif) نمایش داده میشود، توسط قوانین حق چاپ محافظت میشود.
+
+## 🔮 با تشکر از همکاران ما!
+
+
+
+
diff --git a/docs/readme/README_fr.md b/docs/readme/README_fr.md
new file mode 100644
index 000000000..e707fc59b
--- /dev/null
+++ b/docs/readme/README_fr.md
@@ -0,0 +1,178 @@
+
+
+
+
+
+
+
+
+[](https://github.com/openimsdk/open-im-server/stargazers)
+[](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/)
+
+
+
+ Englist ·
+ 中文 ·
+ Українська ·
+ Česky ·
+ Magyar ·
+ Español ·
+ فارسی ·
+ Français ·
+ Deutsch ·
+ Polski ·
+ Indonesian ·
+ Suomi ·
+ മലയാളം ·
+ 日本語 ·
+ Nederlands ·
+ Italiano ·
+ Русский ·
+ Português (Brasil) ·
+ Esperanto ·
+ 한국어 ·
+ العربي ·
+ Tiếng Việt ·
+ Dansk ·
+ Ελληνικά ·
+ Türkçe
+
+
+
+
+
+
+
+
+## Ⓜ️ À propos de OpenIM
+
+OpenIM est une plateforme de services conçue spécifiquement pour intégrer des fonctionnalités de communication telles que le chat, les appels audio et vidéo, les notifications, ainsi que les robots de chat IA dans les applications. Elle offre une série d'API puissantes et de Webhooks, permettant aux développeurs d'incorporer facilement ces caractéristiques interactives dans leurs applications. OpenIM n'est pas en soi une application de chat autonome, mais sert de plateforme supportant d'autres applications pour réaliser des fonctionnalités de communication enrichies. L'image ci-dessous montre les relations d'interaction entre AppServer, AppClient, OpenIMServer et OpenIMSDK pour illustrer spécifiquement.
+
+
+
+
+
+## 🚀 À propos de OpenIMSDK
+
+**OpenIMSDK** est un SDK IM conçu pour **OpenIMServer** spécialement créé pour être intégré dans les applications clientes. Ses principales fonctionnalités et modules comprennent :
+
++ 🌟 Fonctionnalités clés :
+
+ - 📦 Stockage local
+ - 🔔 Rappels de l'écouteur
+ - 🛡️ Encapsulation d'API
+ - 🌐 Gestion de la connexion
+
+ ## 📚 Modules principaux :
+
+ 1. 🚀 Initialisation et connexion
+ 2. 👤 Gestion des utilisateurs
+ 3. 👫 Gestion des amis
+ 4. 🤖 Fonctionnalités de groupe
+ 5. 💬 Traitement des conversations
+
+Il est construit avec Golang et supporte le déploiement multiplateforme, assurant une expérience d'accès cohérente sur toutes les plateformes。
+
+👉 **[Explorer le SDK GO](https://github.com/openimsdk/openim-sdk-core)**
+
+## 🌐 À propos de OpenIMServer
+
++ **OpenIMServer** présente les caractéristiques suivantes :
+ - 🌐 Architecture microservices : prend en charge le mode cluster, incluant le gateway (passerelle) et plusieurs services rpc。
+ - 🚀 Divers modes de déploiement : supporte le déploiement via le code source, Kubernetes ou Docker。
+ - Support d'une masse d'utilisateurs : plus de cent mille pour les super grands groupes, des millions d'utilisateurs, et des milliards de messages。
+
+### Fonctionnalités commerciales améliorées :
+
++ **REST API**:OpenIMServer fournit une REST API pour les systèmes commerciaux, visant à accorder plus de fonctionnalités, telles que la création de groupes via l'interface backend, l'envoi de messages push, etc。
++ **Webhooks**:OpenIMServer offre des capacités de rappel pour étendre davantage les formes d'entreprise. Un rappel signifie que OpenIMServer enverra une requête au serveur d'entreprise avant ou après qu'un événement se soit produit, comme un rappel avant ou après l'envoi d'un message。
+
+👉 **[En savoir plus](https://docs.openim.io/guides/introduction/product)**
+
+## :building_construction: Architecture globale
+
+Plongez dans le cœur de la fonctionnalité d'Open-IM-Server avec notre diagramme d'architecture.
+
+
+
+
+## :rocket: Démarrage rapide
+
+Nous prenons en charge de nombreuses plateformes. Voici les adresses pour une expérience rapide du côté web :
+
+👉 **[Démo web en ligne OpenIM](https://www.openim.io/zh/commercial)**
+
+🤲 Pour faciliter l'expérience utilisateur, nous proposons plusieurs solutions de déploiement. Vous pouvez choisir votre méthode de déploiement selon la liste ci-dessous :
+
++ **[Guide de déploiement du code source](https://docs.openim.io/guides/gettingStarted/imSourceCodeDeployment)**
++ **[Guide de déploiement Docker](https://docs.openim.io/guides/gettingStarted/dockerCompose)**
++ **[Guide de déploiement Kubernetes](https://docs.openim.io/guides/gettingStarted/k8s-deployment)**
++ **[Guide de déploiement pour développeur Mac](https://docs.openim.io/guides/gettingstarted/mac-deployment-guide)**
+
+## :hammer_and_wrench: Commencer à développer avec OpenIM
+
+Chez OpenIM, notre objectif est de construire une communauté open source de premier plan. Nous avons un ensemble de standards, disponibles dans le[ dépôt communautaire](https://github.com/OpenIMSDK/community)。
+Si vous souhaitez contribuer à ce dépôt Open-IM-Server, veuillez lire notre[ document pour les contributeurs](https://github.com/openimsdk/open-im-server/blob/main/CONTRIBUTING.md)。
+
+Avant de commencer, assurez-vous que vos modifications sont nécessaires. La meilleure manière est de créer une[ nouvelle discussion ](https://github.com/openimsdk/open-im-server/discussions/new/choose) ou une [ communication Slack,](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q),ou si vous identifiez un problème, de[ signaler d'abord ](https://github.com/openimsdk/open-im-server/issues/new/choose)。
+- [Référence de l'API OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/api.md)
+- [Journalisation Bash OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/bash-log.md)
+- [Actions CI/CD OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/cicd-actions.md)
+- [Conventions de code OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/code-conventions.md)
+- [Directives de commit OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/commit.md)
+- [Guide de développement OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/development.md)
+- [Structure de répertoire OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/directory.md)
+- [Configuration de l'environnement OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/environment.md)
+- [Référence des codes d'erreur OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/error-code.md)
+- [Workflow Git OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/git-workflow.md)
+- [Guide Cherry Pick Git OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/gitcherry-pick.md)
+- [Workflow GitHub OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/github-workflow.md)
+- [Normes de code Go OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/go-code.md)
+- [Directives d'image OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/images.md)
+- [Configuration initiale OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/init-config.md)
+- [Guide d'installation Docker OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/install-docker.md)
+- [Installation du système Linux OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/install-openim-linux-system.md)
+- [Guide de développement Linux OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/linux-development.md)
+- [Guide des actions locales OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/local-actions.md)
+- [Conventions de journalisation OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/logging.md)
+- [Déploiement hors ligne OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/offline-deployment.md)
+- [Outils Protoc OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/protoc-tools.md)
+- [Guide de test OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/test.md)
+- [Utilitaire Go OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/util-go.md)
+- [Utilitaires Makefile OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/util-makefile.md)
+- [Utilitaires de script OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/util-scripts.md)
+- [Versionnement OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/version.md)
+- [Gérer le déploiement du backend et la surveillance](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/prometheus-grafana.md)
+- [Guide de déploiement pour développeur Mac pour OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/mac-developer-deployment-guide.md)
+
+
+>## :calendar: Réunions de la Communauté
+
+Nous voulons que tout le monde s'implique dans notre communauté et contribue au code, nous offrons des cadeaux et des récompenses, et nous vous invitons à nous rejoindre chaque jeudi soir.
+Notre conférence se trouve dans le [ Slack OpenIM ](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q) 🎯, ensuite vous pouvez rechercher le pipeline Open-IM-Server pour rejoindre
+
+Nous prenons des notes de chaque [réunion bihebdomadaire ](https://github.com/orgs/OpenIMSDK/discussions/categories/meeting) dans les [discussions GitHub](https://github.com/openimsdk/open-im-server/discussions/categories/meeting), Nos notes de réunion historiques, ainsi que les rediffusions des réunions sont disponibles sur [ Google Docs :bookmark_tabs:](https://docs.google.com/document/d/1nx8MDpuG74NASx081JcCpxPgDITNTpIIos0DS6Vr9GU/edit?usp=sharing).
+
+## :eyes: Qui Utilise OpenIM
+
+Consultez notre page [ études de cas d'utilisateurs ](https://github.com/OpenIMSDK/community/blob/main/ADOPTERS.md) pour une liste des utilisateurs du projet. N'hésitez pas à laisser un [📝commentaire](https://github.com/openimsdk/open-im-server/issues/379) et partager votre cas d'utilisation.
+
+## :page_facing_up: License
+
+OpenIM est sous licence Apache 2.0. Voir [LICENSE](https://github.com/openimsdk/open-im-server/tree/main/LICENSE) pour le texte complet de la licence.
+
+Le logo OpenIM, y compris ses variations et versions animées, affiché dans ce dépôt[OpenIM](https://github.com/openimsdk/open-im-server) sous les répertoires [assets/logo](../../assets/logo) et [assets/logo-gif](assets/logo-gif) sont protégés par les lois sur le droit d'auteur.
+
+## 🔮 Merci à nos contributeurs !
+
+
+
+
diff --git a/docs/readme/README_hu.md b/docs/readme/README_hu.md
new file mode 100644
index 000000000..57f006692
--- /dev/null
+++ b/docs/readme/README_hu.md
@@ -0,0 +1,187 @@
+
+
+
+
+
+
+
+
+[](https://github.com/openimsdk/open-im-server/stargazers)
+[](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/)
+
+
+
+ Englist ·
+ 中文 ·
+ Українська ·
+ Česky ·
+ Magyar ·
+ Español ·
+ فارسی ·
+ Français ·
+ Deutsch ·
+ Polski ·
+ Indonesian ·
+ Suomi ·
+ മലയാളം ·
+ 日本語 ·
+ Nederlands ·
+ Italiano ·
+ Русский ·
+ Português (Brasil) ·
+ Esperanto ·
+ 한국어 ·
+ العربي ·
+ Tiếng Việt ·
+ Dansk ·
+ Ελληνικά ·
+ Türkçe
+
+
+
+
+
+
+
+## Ⓜ️ Az OpenIM-ről
+
+Az OpenIM egy szolgáltatási platform, amelyet kifejezetten a csevegés, az audio-video hívások, az értesítések és az AI chatbotok alkalmazásokba történő integrálására terveztek. Számos hatékony API-t és Webhookot kínál, lehetővé téve a fejlesztők számára, hogy ezeket az interaktív szolgáltatásokat könnyen beépítsék alkalmazásaikba. Az OpenIM nem egy önálló csevegőalkalmazás, hanem platformként szolgál más alkalmazások támogatására a gazdag kommunikációs funkciók elérésében. A következő diagram az AppServer, az AppClient, az OpenIMServer és az OpenIMSDK közötti interakciót szemlélteti részletesen.
+
+
+
+## 🚀 Az OpenIMSDK-ról
+
+Az **OpenIMSDK** egy **OpenIMServer** számára készült azonnali üzenetküldő SDK, amelyet kifejezetten ügyfélalkalmazásokba való beágyazáshoz hoztak létre. Fő jellemzői és moduljai a következők:
+
++ 🌟 Főbb jellemzők:
+
+ - 📦 Helyi raktár
+ - 🔔 Hallgatói visszahívások
+ - 🛡️ API-csomagolás
+ - 🌐 Kapcsolatkezelés
+
++ 📚 Fő modulok:
+
+ 1. 🚀 Inicializálás és bejelentkezés
+ 2. 👤 Felhasználókezelés
+ 3. 👫 Barátkezelés
+ 4. 🤖 Csoportfunkciók
+ 5. 💬 Beszélgetéskezelés
+
+Golang használatával készült, és támogatja a többplatformos telepítést, biztosítva a konzisztens hozzáférési élményt minden platformon.
+
+👉 **[Fedezze fel a GO SDK-t](https://github.com/openimsdk/openim-sdk-core)**
+
+## 🌐 Az OpenIMServerről
+
++ **OpenIMServer** a következő jellemzőkkel rendelkezik:
+ - 🌐 Mikroszolgáltatási architektúra: Támogatja a fürt módot, beleértve az átjárót és több rpc szolgáltatást.
+ - 🚀 Változatos telepítési módszerek: Támogatja a forráskódon, Kubernetesen vagy Dockeren keresztül történő telepítést.
+ - Hatalmas felhasználói bázis támogatása: Szuper nagy csoportok több százezer felhasználóval, több tízmillió felhasználóval és több milliárd üzenettel.
+
+### Továbbfejlesztett üzleti funkcionalitás:
+
++ **REST API**: Az OpenIMServer REST API-kat kínál az üzleti rendszerek számára, amelyek célja, hogy a vállalkozásokat több funkcióval ruházza fel, mint például csoportok létrehozása és push üzenetek küldése háttérfelületeken keresztül.
++ **Webhooks**: Az OpenIMServer visszahívási lehetőségeket biztosít több üzleti forma kiterjesztéséhez. A visszahívás azt jelenti, hogy az OpenIMServer kérelmet küld az üzleti szervernek egy bizonyos esemény előtt vagy után, például visszahívásokat üzenet küldése előtt vagy után.
+
+👉 **[Tudj meg többet](https://docs.openim.io/guides/introduction/product)**
+
+## :building_construction: Általános építészet
+
+Merüljön el az Open-IM-Server funkcióinak szívében az architektúra diagramunk segítségével.
+
+
+
+
+## :rocket: Gyors indítás
+
+Számos platformot támogatunk. Íme a címek a gyors weboldali használathoz:
+
+👉 **[OpenIM online webdemó](https://web-enterprise.rentsoft.cn/)**
+
+🤲 A felhasználói élmény megkönnyítése érdekében különféle telepítési megoldásokat kínálunk. Az alábbi listából választhatja ki a telepítési módot:
+
++ **[Forráskód-telepítési útmutató](https://docs.openim.io/guides/gettingStarted/imSourceCodeDeployment)**
++ **[Docker telepítési útmutató](https://docs.openim.io/guides/gettingStarted/dockerCompose)**
++ **[Kubernetes telepítési útmutató](https://docs.openim.io/guides/gettingStarted/k8s-deployment)**
++ **[Mac fejlesztői telepítési útmutató](https://docs.openim.io/guides/gettingstarted/mac-deployment-guide)**
+
+## :hammer_and_wrench: Az OpenIM fejlesztésének megkezdéséhez
+
+[](https://vscode.dev/github/openimsdk/open-im-server)
+
+OpenIM Célunk egy felső szintű nyílt forráskódú közösség felépítése. Van egy szabványkészletünk a [Közösségi adattárban](https://github.com/OpenIMSDK/community).
+
+Ha hozzá szeretne járulni ehhez az Open-IM-Server adattárhoz, kérjük, olvassa el [közreműködői dokumentációnkat](https://github.com/openimsdk/open-im-server/blob/main/CONTRIBUTING.md).
+
+Mielőtt elkezdené, győződjön meg arról, hogy a változtatásokra van-e igény. Erre a legjobb egy [új beszélgetés](https://github.com/openimsdk/open-im-server/discussions/new/choose) VAGY [Slack Communication](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q)létrehozása, vagy ha problémát talál, először [jelentse](https://github.com/openimsdk/open-im-server/issues/new/choose) first.
+
+- [OpenIM API referencia](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/api.md)
+- [OpenIM Bash naplózás](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/bash-log.md)
+- [OpenIM CI/CD műveletek](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/cicd-actions.md)
+- [OpenIM Code-egyezmények](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/code-conventions.md)
+- [OpenIM Commit Guidelines](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/commit.md)
+- [OpenIM fejlesztési útmutató](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/development.md)
+- [OpenIM címtárszerkezet](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/directory.md)
+- [OpenIM környezet beállítása](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/environment.md)
+- [OpenIM hibakód hivatkozás](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/error-code.md)
+- [OpenIM Git Workflow](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/git-workflow.md)
+- [OpenIM Git Cherry Pick Guide](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/gitcherry-pick.md)
+- [OpenIM GitHub munkafolyamat](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/github-workflow.md)
+- [OpenIM Go Code szabványok](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/go-code.md)
+- [OpenIM képre vonatkozó irányelvek](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/images.md)
+- [OpenIM kezdeti konfiguráció](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/init-config.md)
+- [OpenIM Docker telepítési útmutató](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/install-docker.md)
+- [OpenIM OpenIM Linux rendszertelepítés](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/install-openim-linux-system.md)
+- [OpenIM Linux fejlesztési útmutató](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/linux-development.md)
+- [OpenIM helyi műveletek útmutatója](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/local-actions.md)
+- [OpenIM naplózási egyezmények](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/logging.md)
+- [OpenIM offline telepítés](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/offline-deployment.md)
+- [OpenIM Protoc Tools](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/protoc-tools.md)
+- [OpenIM tesztelési útmutató](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/test.md)
+- [OpenIM Utility Go](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/util-go.md)
+- [OpenIM Makefile Utilities](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/util-makefile.md)
+- [OpenIM Script Utilities](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/util-scripts.md)
+- [OpenIM verzió](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/version.md)
+- [A háttérrendszer kezelése és a telepítés figyelése](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/prometheus-grafana.md)
+- [Mac Developer Deployment Guide for OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/mac-developer-deployment-guide.md)
+
+
+## :busts_in_silhouette: Közösség
+
++ 📚 [OpenIM közösség](https://github.com/OpenIMSDK/community)
++ 💕 [OpenIM érdeklődési csoport](https://github.com/Openim-sigs)
++ 🚀 [Csatlakozz a Slack közösségünkhöz](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q)
++ :eyes: [Csatlakozz a wechathez](https://openim-1253691595.cos.ap-nanjing.myqcloud.com/WechatIMG20.jpeg)
+
+## :calendar: Közösségi Találkozók
+
+Szeretnénk, ha bárki bekapcsolódna közösségünkbe és hozzájárulna kódunkhoz, ajándékokat és jutalmakat kínálunk, és szeretettel várjuk, hogy csatlakozzon hozzánk minden csütörtök este.
+
+Konferenciánk az [OpenIM Slack](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q) 🎯alatt van, akkor kereshet az Open-IM-Server folyamatban a csatlakozáshoz
+
+A [GitHub-beszélgetések](https://github.com/orgs/OpenIMSDK/discussions/categories/meeting)minden [kéthetente történő megbeszélésről](https://github.com/openimsdk/open-im-server/discussions/categories/meeting) jegyzeteket készítünk. A találkozók történeti feljegyzései, valamint az értekezletek visszajátszásai a [Google Dokumentumok :bookmark_tabs:](https://docs.google.com/document/d/1nx8MDpuG74NASx081JcCpxPgDITNTpIIos0DS6Vr9GU/edit?usp=sharing) webhelyen érhetők el.
+
+## :eyes: Kik használják az OpenIM-et
+
+Tekintse meg [felhasználói esettanulmányok](https://github.com/OpenIMSDK/community/blob/main/ADOPTERS.md) oldalunkat a projekt felhasználóinak listájáért. Ne habozzon, hagyjon [📝megjegyzést](https://github.com/openimsdk/open-im-server/issues/379), és ossza meg használati esetét.
+
+## :page_facing_up: Engedély
+
+Az OpenIM licence az Apache 2.0 licence alá tartozik. A teljes licencszövegért lásd: [LICENSE](https://github.com/openimsdk/open-im-server/tree/main/LICENSE).
+
+Az ebben az [OpenIM](https://github.com/openimsdk/open-im-server) tárolóban az [assets/logo](./assets/logo) és [assets/logo-gif](assets/logo-gif) könyvtárak alatt megjelenő OpenIM logót, beleértve annak változatait és animált változatait, szerzői jogi törvények védik.
+
+## 🔮 Köszönjük közreműködőinknek!
+
+
+
+
diff --git a/docs/readme/README_ja.md b/docs/readme/README_ja.md
new file mode 100644
index 000000000..bd94b1153
--- /dev/null
+++ b/docs/readme/README_ja.md
@@ -0,0 +1,190 @@
+
+
+
+
+
+
+
+
+[](https://github.com/openimsdk/open-im-server/stargazers)
+[](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/)
+
+
+
+ Englist ·
+ 中文 ·
+ Українська ·
+ Česky ·
+ Magyar ·
+ Español ·
+ فارسی ·
+ Français ·
+ Deutsch ·
+ Polski ·
+ Indonesian ·
+ Suomi ·
+ മലയാളം ·
+ 日本語 ·
+ Nederlands ·
+ Italiano ·
+ Русский ·
+ Português (Brasil) ·
+ Esperanto ·
+ 한국어 ·
+ العربي ·
+ Tiếng Việt ·
+ Dansk ·
+ Ελληνικά ·
+ Türkçe
+
+
+
+
+
+
+
+
+## Ⓜ️ OpenIMについて
+
+OpenIMは、アプリケーション内でチャット、音声通話、通知、AIチャットボットなどの通信機能を統合するために特別に設計されたサービスプラットフォームです。一連の強力なAPIとWebhooksを提供することで、開発者はアプリケーションに簡単にこれらの通信機能を統合できます。OpenIM自体は独立したチャットアプリではなく、アプリケーションにサポートを提供し、豊富な通信機能を実現するプラットフォームです。以下の図は、AppServer、AppClient、OpenIMServer、OpenIMSDK間の相互作用を示しています。
+
+
+
+
+
+## 🚀 OpenIMSDKについて
+
+ **OpenIMSDK**は、**OpenIMServer**用に設計されたIM SDKで、クライアントアプリケーションに組み込むためのものです。主な機能とモジュールは以下の通りです:
+
++ 🌟 主な機能:
+
+ - 📦 ローカルストレージ
+ - 🔔 リスナーコールバック
+ - 🛡️ APIのラッピング
+ - 🌐 接続管理
+
+ ## 📚 主なモジュール:
+
+ 1. 🚀 初初期化とログイン
+ 2. 👤 ユーザー管理
+ 3. 👫 友達管理
+ 4. 🤖 グループ機能
+ 5. 💬 会話処理
+
+Golangを使用して構築され、クロスプラットフォームの導入をサポートし、すべてのプラットフォームで一貫したアクセス体験を提供します。
+
+👉 **[GO SDKを探索する](https://github.com/openimsdk/openim-sdk-core)**
+
+## 🌐 OpenIMServerについて
+
++ **OpenIMServer** には以下の特徴があります:
+ - 🌐 マイクロサービスアーキテクチャ:クラスターモードをサポートし、ゲートウェイ(gateway)と複数のrpcサービスを含みます。
+ - 🚀 多様なデプロイメント方法:ソースコード、kubernetes、またはdockerでのデプロイメントをサポートします。
+ - 海量ユーザーサポート:十万人規模の超大型グループ、千万人のユーザー、および百億のメッセージ
+
+### 強化されたビジネス機能:
+
++ **REST API**:OpenIMServerは、ビジネスシステム用のREST APIを提供しており、ビジネスにさらに多くの機能を提供することを目指しています。たとえば、バックエンドインターフェースを通じてグループを作成したり、プッシュメッセージを送信したりするなどです。
++ **Webhooks**:OpenIMServerは、より多くのビジネス形態を拡張するためのコールバック機能を提供しています。コールバックとは、特定のイベントが発生する前後に、OpenIMServerがビジネスサーバーにリクエストを送信することを意味します。例えば、メッセージ送信の前後のコールバックなどです。
+
+👉 **[もっと詳しく知る](https://docs.openim.io/guides/introduction/product)**
+
+## :building_construction: 全体のアーキテクチャ
+
+Open-IM-Serverの機能の核心に迫るために、アーキテクチャダイアグラムをご覧ください。
+
+
+
+## :rocket: クイックスタート
+
+iOS/Android/H5/PC/Webでのオンライン体験:
+
+👉 **[OpenIM online demo](https://www.openim.io/zh/commercial)**
+
+🤲 ユーザー体験を容易にするために、私たちは様々なデプロイメントソリューションを提供しています。以下のリストから、ご自身のデプロイメント方法を選択できます:
+
++ **[ソースコードデプロイメントガイド](https://docs.openim.io/guides/gettingStarted/imSourceCodeDeployment)**
++ **[Docker デプロイメントガイド](https://docs.openim.io/guides/gettingStarted/dockerCompose)**
++ **[Kubernetes デプロイメントガイド](https://docs.openim.io/guides/gettingStarted/k8s-deployment)**
++ **[Mac 開発者向けデプロイメントガイド](https://docs.openim.io/guides/gettingstarted/mac-deployment-guide)**
+
+## :hammer_and_wrench: OpenIMの開発を始める
+
+[](https://vscode.dev/github/openimsdk/open-im-server)
+
+OpenIM 私たちの目標は、トップレベルのオープンソースコミュニティを構築することです。[コミュニティリポジトリ](https://github.com/OpenIMSDK/community)には一連の基準があります。
+
+このOpen-IM-Serverリポジトリに貢献したい場合は、[貢献者ドキュメントをお読みください](https://github.com/openimsdk/open-im-server/blob/main/CONTRIBUTING.md)。
+
+始める前に、変更に必要があることを確認してください。最良の方法は、[新しいディスカッション](https://github.com/openimsdk/open-im-server/discussions/new/choose)や[Slack](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q)での通信を作成すること、または問題を発見した場合は、まずそれを[報告](https://github.com/openimsdk/open-im-server/issues/new/choose)することです。
+
+- [OpenIM APIリファレンス](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/api.md)
+- [OpenIM Bash ロギング](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/bash-log.md)
+- [OpenIM CI/CD アクション](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/cicd-actions.md)
+- [OpenIM コード規約](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/code-conventions.md)
+- [OpenIM コミットガイドライン](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/commit.md)
+- [OpenIM 開発ガイド](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/development.md)
+- [OpenIM ディレクトリ構造](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/directory.md)
+- [OpenIM 環境設定](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/environment.md)
+- [OpenIM エラーコードリファレンス](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/error-code.md)
+- [OpenIM Git ワークフロー](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/git-workflow.md)
+- [OpenIM Git チェリーピックガイド](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/gitcherry-pick.md)
+- [OpenIM GitHub ワークフロー](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/github-workflow.md)
+- [OpenIM Go コード基準](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/go-code.md)
+- [OpenIM 画像ガイドライン](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/images.md)
+- [OpenIM 初期設定](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/init-config.md)
+- [OpenIM Docker インストールガイド](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/install-docker.md)
+- [OpenIM Linux システムインストール](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/install-openim-linux-system.md)
+- [OpenIM Linux 開発ガイド](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/linux-development.md)
+- [OpenIM ローカルアクションガイド](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/local-actions.md)
+- [OpenIM ロギング規約](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/logging.md)
+- [OpenIM オフラインデプロイメント](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/offline-deployment.md)
+- [OpenIM Protoc ツール](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/protoc-tools.md)
+- [OpenIM テスティングガイド](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/test.md)
+- [OpenIM ユーティリティGo](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/util-go.md)
+- [OpenIM Makefile ユーティリティ](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/util-makefile.md)
+- [OpenIM スクリプトユーティリティ](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/util-scripts.md)
+- [OpenIM バージョニング](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/version.md)
+- [バックエンド管理とモニターデプロイメント](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/prometheus-grafana.md)
+- [OpenIM用Mac開発者デプロイメントガイド](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/mac-developer-deployment-guide.md)
+
+
+## :busts_in_silhouette: コミュニティ
+
++ 📚 [OpenIM コミュニティ](https://github.com/OpenIMSDK/community)
++ 💕 [OpenIM 興味グループ](https://github.com/Openim-sigs)
++ 🚀 [私たちのSlackコミュニティに参加する](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q)
++ :eyes: [私たちのWeChat(微信群)に参加する](https://openim-1253691595.cos.ap-nanjing.myqcloud.com/WechatIMG20.jpeg)
+
+## :calendar: コミュニティミーティング
+
+私たちは、誰もがコミュニティに参加し、コードに貢献してもらいたいと考えています。私たちは、ギフトや報酬を提供し、毎週木曜日の夜に参加していただくことを歓迎します。
+
+私たちの会議は[OpenIM Slack](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q)🎯で行われます。そこでOpen-IM-Serverパイプラインを検索して参加できます。
+
+
+私たちは[隔週の会議](https://github.com/orgs/OpenIMSDK/discussions/categories/meeting)のメモを[GitHubディスカッション](https://github.com/openimsdk/open-im-server/discussions/categories/meeting)に記録しています。歴史的な会議のメモや会議のリプレイは[Google Docs📑](https://docs.google.com/document/d/1nx8MDpuG74NASx081JcCpxPgDITNTpIIos0DS6Vr9GU/edit?usp=sharing)で利用可能です。
+
+## :eyes: OpenIMを使用している人たち
+
+プロジェクトユーザーのリストについては、[ユーザーケーススタディ](https://github.com/OpenIMSDK/community/blob/main/ADOPTERS.md)ページをご覧ください。[コメント📝](https://github.com/openimsdk/open-im-server/issues/379)を残して、あなたの使用例を共有することを躊躇しないでください。
+
+## :page_facing_up: ライセンス
+
+OpenIMはApache 2.0ライセンスの下でライセンスされています。完全なライセンステキストについては、[LICENSE](https://github.com/openimsdk/open-im-server/tree/main/LICENSE)を参照してください。
+
+このリポジトリに表示される[OpenIM](https://github.com/openimsdk/open-im-server)ロゴ、そのバリエーション、およびアニメーションバージョン([assets/logo](./assets/logo)および[assets/logo-gif](assets/logo-gif)ディレクトリ内)は、著作権法によって保護されています。
+
+## 🔮 貢献者の皆様に感謝します!
+
+
+
+
\ No newline at end of file
diff --git a/docs/readme/README_ko.md b/docs/readme/README_ko.md
new file mode 100644
index 000000000..bd7a1aed3
--- /dev/null
+++ b/docs/readme/README_ko.md
@@ -0,0 +1,192 @@
+
+
+
+
+
+
+
+
+[](https://github.com/openimsdk/open-im-server/stargazers)
+[](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/)
+
+
+
+ Englist ·
+ 中文 ·
+ Українська ·
+ Česky ·
+ Magyar ·
+ Español ·
+ فارسی ·
+ Français ·
+ Deutsch ·
+ Polski ·
+ Indonesian ·
+ Suomi ·
+ മലയാളം ·
+ 日本語 ·
+ Nederlands ·
+ Italiano ·
+ Русский ·
+ Português (Brasil) ·
+ Esperanto ·
+ 한국어 ·
+ العربي ·
+ Tiếng Việt ·
+ Dansk ·
+ Ελληνικά ·
+ Türkçe
+
+
+
+
+
+
+
+
+## Ⓜ️ OpenIM에 대하여
+
+OpenIM은 채팅, 오디오-비디오 통화, 알림 및 AI 챗봇을 애플리케이션에 통합하기 위해 특별히 설계된 서비스 플랫폼입니다. 이 플랫폼은 강력한 API와 웹훅을 제공하여 개발자가 이러한 상호작용 기능을 애플리케이션에 쉽게 통합할 수 있게 합니다. OpenIM은 독립 실행형 채팅 애플리케이션이 아니라, 다른 애플리케이션들이 풍부한 커뮤니케이션 기능을 달성할 수 있도록 지원하는 플랫폼으로서의 역할을 합니다. 다음 다이어그램은 AppServer, AppClient, OpenIMServer, 및 OpenIMSDK 간의 상호작용을 자세히 설명하기 위해 제시되었습니다.
+
+
+
+
+
+## 🚀 OpenIMSDK에 대하여
+
+ **OpenIMSDK**는**OpenIMServer**를 위해 특별히 제작된 IM SDK로, 클라이언트 애플리케이션 내에 내장하기 위해 설계되었습니다. 그 주요 기능 및 모듈은 다음과 같습니다:
+
+
++ 🌟 주요 기능:
+
+ - 📦 로컬 스토리지
+ - 🔔 리스너 콜백
+ - 🛡️ API 래핑
+ - 🌐 연결 관리
+
+ ## 📚 주요 모듈:
+
+ 1. 🚀 초기화 및 로그인
+ 2. 👤 사용자 관리
+ 3. 👫 친구 관리
+ 4. 🤖 그룹 기능
+ 5. 💬 대화 처리
+
+이는 Golang을 사용하여 구축되었으며, 모든 플랫폼에서 일관된 접근 경험을 보장하는 크로스 플랫폼 배포를 지원합니다.
+
+👉 **[GO SDK 탐색하기](https://github.com/openimsdk/openim-sdk-core)**
+
+## 🌐 OpenIMServer에 대하여
+
++ **OpenIMServer** 는 다음과 같은 특성을 가지고 있습니다:
+ - 🌐 마이크로서비스 아키텍처: 게이트웨이 및 다수의 rpc 서비스를 포함하는 클러스터 모드를 지원합니다.
+ - 🚀 다양한 배포 방법: 소스 코드, 쿠버네티스 또는 도커를 통한 배포를 지원합니다.
+ - 대규모 사용자 기반 지원: 수십만 명의 사용자를 포함하는 초대형 그룹, 수천만 명의 사용자 및 수십억 건의 메시지를 지원합니다.
+
+### 강화된 비즈니스 기능:
+
++ **REST API**:OpenIMServer는 비즈니스 시스템을 위한 REST API를 제공하여, 백엔드 인터페이스를 통해 그룹 생성 및 푸시 메시지 전송과 같은 더 많은 기능을 비즈니스에 제공하기 위해 설계되었습니다.
++ **Webhooks**:OpenIMServer는 더 많은 비즈니스 형태를 확장할 수 있는 콜백 기능을 제공합니다. 콜백이란 메시지 전송 전후와 같은 특정 이벤트 전후에 OpenIMServer가 비즈니스 서버로 요청을 보내는 것을 의미합니다.
+
+👉 **[더 알아보기](https://docs.openim.io/guides/introduction/product)**
+
+## :building_construction: 전체 아키텍처
+
+Open-IM-Server의 기능의 핵심으로 들어가 우리의 아키텍처 다이어그램을 자세히 살펴보세요.
+
+
+
+## :rocket: 빠른 시작
+
+우리는 많은 플랫폼을 지원합니다. 웹 측에서 빠른 체험을 위한 주소는 다음과 같습니다:
+
+👉 **[OpenIM online demo](https://www.openim.io/zh/commercial)**
+
+🤲 사용자 경험을 용이하게 하기 위해, 다양한 배포 솔루션을 제공합니다. 아래 목록에서 배포 방법을 선택할 수 있습니다:
+
++ **[소스 코드 배포 가이드](https://docs.openim.io/guides/gettingStarted/imSourceCodeDeployment)**
++ **[docker 배포 가이드](https://docs.openim.io/guides/gettingStarted/dockerCompose)**
++ **[Kubernetes 배포 가이드](https://docs.openim.io/guides/gettingStarted/k8s-deployment)**
++ **[Mac 개발자 배포 가이드](https://docs.openim.io/guides/gettingstarted/mac-deployment-guide)**
+
+## :hammer_and_wrench: OpenIM 개발 시작하기
+
+[](https://vscode.dev/github/openimsdk/open-im-server)
+
+OpenIM의 목표는 최상위 수준의 오픈 소스 커뮤니티를 구축하는 것입니다. 우리는 [커뮤니티 리포지토리에서](https://github.com/OpenIMSDK/community) 일련의 표준을 가지고 있습니다.
+
+이 Open-IM-Server 리포지토리에 기여하고 싶다면, 우리의 [기여자 문서](https://github.com/openimsdk/open-im-server/blob/main/CONTRIBUTING.md)를 읽어주세요.
+
+시작하기 전에, 변경 사항이 필요한지 확인해 주세요. 가장 좋은 방법은 [새로운 토론](https://github.com/openimsdk/open-im-server/discussions/new/choose)을 생성하거나 [Slack 통신을](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q) 하거나, 문제를 발견했다면 먼저 [보고](https://github.com/openimsdk/open-im-server/issues/new/choose)하는 것입니다.
+
+- [OpenIM API 참조](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/api.md)
+- [OpenIM Bash 로깅](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/bash-log.md)
+- [OpenIM CI/CD 액션](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/cicd-actions.md)
+- [OpenIM 코드 규칙](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/code-conventions.md)
+- [OpenIM 커밋 가이드라인](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/commit.md)
+- [OpenIM 개발 가이드](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/development.md)
+- [OpenIM 디렉토리 구조](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/directory.md)
+- [OpenIM 환경 설정](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/environment.md)
+- [OpenIM 오류 코드 참조](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/error-code.md)
+- [OpenIM Git 작업 흐름](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/git-workflow.md)
+- [OpenIM Git 체리 픽 가이드](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/gitcherry-pick.md)
+- [OpenIM GitHub 작업 흐름](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/github-workflow.md)
+- [OpenIM Go 코드 표준](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/go-code.md)
+- [OpenIM 이미지 가이드라인](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/images.md)
+- [OpenIM 초기 구성](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/init-config.md)
+- [OpenIM docker 설치 가이드](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/install-docker.md)
+- [OpenIM OpenIM Linux 설치](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/install-openim-linux-system.md)
+- [OpenIM Linux 개발 가이드](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/linux-development.md)
+- [OpenIM 로컬 액션 가이드](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/local-actions.md)
+- [OpenIM 로깅 규칙](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/logging.md)
+- [OpenIM 오프라인 배포](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/offline-deployment.md)
+- [OpenIM Protoc 도구](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/protoc-tools.md)
+- [OpenIM 테스트 가이드](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/test.md)
+- [OpenIM 유틸리티 Go](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/util-go.md)
+- [OpenIM 메이크파일 유틸리티](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/util-makefile.md)
+- [OpenIM 스크립트 유틸리티](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/util-scripts.md)
+- [OpenIM 버전 관리](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/version.md)
+- [백엔드 관리 및 모니터 배포](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/prometheus-grafana.md)
+- [맥 개발자 배포 가이드 for OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/mac-developer-deployment-guide.md)
+
+
+## :busts_in_silhouette: 커뮤니티
+
++ 📚 [OpenIM 커뮤니티](https://github.com/OpenIMSDK/community)
++ 💕 [OpenIM 관심 그룹](https://github.com/Openim-sigs)
++ 🚀 [우리의 Slack 커뮤니티에 가입하기](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q)
++ :eyes: [우리의 위챗(微信群)에 가입하기](https://openim-1253691595.cos.ap-nanjing.myqcloud.com/WechatIMG20.jpeg)
+
+## :calendar: 커뮤니티 미팅
+
+우리는 누구나 커뮤니티에 참여하고 코드를 기여할 수 있도록 하며, 선물과 보상을 제공하며, 매주 목요일 밤에 여러분을 환영합니다.
+
+우리의 회의는 [OpenIM Slack](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q) 🎯에서 이루어지며, Open-IM-Server 파이프라인을 검색하여 참여할 수 있습니다.
+
+우리는 격주 회의의 메모를 [GitHub 토론](https://github.com/openimsdk/open-im-server/discussions/categories/meeting)에서 기록하며, 우리의 역사적 [회의](https://github.com/orgs/OpenIMSDK/discussions/categories/meeting) 노트와 회의 재생은 [Google Docs 📑](https://docs.google.com/document/d/1nx8MDpuG74NASx081JcCpxPgDITNTpIIos0DS6Vr9GU/edit?usp=sharing)에서 이용할 수 있습니다.
+
+
+## :eyes: OpenIM을 사용하는 사람들
+
+프로젝트 사용자 목록을 위한 우리의 [사용자 사례 연구](https://github.com/OpenIMSDK/community/blob/main/ADOPTERS.md) 페이지를 확인하세요. 사용 사례를 공유하고 싶다면 주저하지 말고 [📝코멘트](https://github.com/openimsdk/open-im-server/issues/379)를 남겨주세요.
+
+## :page_facing_up: 라이선스
+
+OpenIM은 Apache 2.0 라이선스에 따라 라이선스가 부여됩니다. 전체 라이선스 텍스트는 [LICENSE](https://github.com/openimsdk/open-im-server/tree/main/LICENSE)에서 확인할 수 있습니다.
+
+이 리포지토리 [OpenIM](https://github.com/openimsdk/open-im-server)에 표시된 OpenIM 로고, 그 변형 및 애니메이션 버전은 [assets/logo](../../assets/logo) 및 [assets/logo-gif](../../assets/logo-gif) 디렉토리 아래에 있으며, 저작권 법에 의해 보호됩니다.
+
+
+## 🔮 우리의 기여자들에게 감사합니다!
+
+
+
+
\ No newline at end of file
diff --git a/docs/readme/README_tr.md b/docs/readme/README_tr.md
new file mode 100644
index 000000000..ca2a816db
--- /dev/null
+++ b/docs/readme/README_tr.md
@@ -0,0 +1,189 @@
+
+
+
+
+
+
+
+
+[](https://github.com/openimsdk/open-im-server/stargazers)
+[](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/)
+
+
+
+ Englist ·
+ 中文 ·
+ Українська ·
+ Česky ·
+ Magyar ·
+ Español ·
+ فارسی ·
+ Français ·
+ Deutsch ·
+ Polski ·
+ Indonesian ·
+ Suomi ·
+ മലയാളം ·
+ 日本語 ·
+ Nederlands ·
+ Italiano ·
+ Русский ·
+ Português (Brasil) ·
+ Esperanto ·
+ 한국어 ·
+ العربي ·
+ Tiếng Việt ·
+ Dansk ·
+ Ελληνικά ·
+ Türkçe
+
+
+
+
+
+
+
+
+## Ⓜ️ OpenIM Hakkında
+
+OpenIM, uygulamalara sohbet, sesli-görüntülü aramalar, bildirimler ve AI sohbet robotları entegre etmek için özel olarak tasarlanmış bir hizmet platformudur. Güçlü API'ler ve Webhook'lar sunarak, geliştiricilerin bu etkileşimli özellikleri uygulamalarına kolayca dahil etmelerini sağlar. OpenIM bağımsız bir sohbet uygulaması değildir, ancak zengin iletişim işlevselliği sağlama amacıyla diğer uygulamaları destekleyen bir platform olarak hizmet verir. Aşağıdaki diyagram, AppServer, AppClient, OpenIMServer ve OpenIMSDK arasındaki etkileşimi detaylandırmak için açıklar.
+
+
+
+
+
+## 🚀 OpenIMSDK Hakkında
+
+ **OpenIMSDK**, müşteri uygulamalarına gömülmek üzere özel olarak oluşturulan **OpenIMServer** için tasarlanmış bir IM SDK'sıdır. Ana özellikleri ve modülleri aşağıdaki gibidir:
+
++ 🌟 Ana Özellikler:
+
+ - 📦 Yerel depolama
+ - 🔔 Dinleyici geri çağırmaları
+ - 🛡️ API sarımı
+ - 🌐 Bağlantı yönetimi
+
+ ## 📚 Ana Modüller:
+
+ 1. 🚀 Başlatma ve Giriş
+ 2. 👤 Kullanıcı Yönetimi
+ 3. 👫 Arkadaş Yönetimi
+ 4. 🤖 Grup Fonksiyonları
+ 5. 💬 Konuşma Yönetimi
+
+Golang kullanılarak inşa edilmiş ve tüm platformlarda tutarlı bir erişim deneyimi sağlayacak şekilde çapraz platform dağıtımını destekler.
+
+👉 **[GO SDK Keşfet](https://github.com/openimsdk/openim-sdk-core)**
+
+## 🌐 OpenIMServer Hakkında
+
++ **OpenIMServer** aşağıdaki özelliklere sahiptir:
+ - 🌐 Mikroservis mimarisi: Bir kapı ve çoklu rpc servisleri içeren küme modunu destekler.
+ - 🚀 Çeşitli dağıtım yöntemleri: Kaynak kodu, Kubernetes veya Docker aracılığıyla dağıtımı destekler.
+ - Büyük kullanıcı tabanı desteği: Yüz binlerce kullanıcısı olan süper büyük gruplar, on milyonlarca kullanıcı ve milyarlarca mesaj.
+
+### Geliştirilmiş İşlevsellik:
+
++ **REST API**:OpenIMServer, işletmeleri gruplar oluşturma ve arka plan arayüzleri aracılığıyla itme mesajları gönderme gibi daha fazla işlevsellikle güçlendirmeyi amaçlayan iş sistemleri için REST API'leri sunar.
++ **Webhooks**:OpenIMServer, daha fazla iş formunu genişletme yetenekleri sağlayan geri çağırma özellikleri sunar. Geri çağırma, OpenIMServer'ın belirli bir olaydan önce veya sonra, örneğin bir mesaj göndermeden önce veya sonra iş sunucusuna bir istek göndermesi anlamına gelir.
+
+👉 **[Daha fazla bilgi edinin](https://docs.openim.io/guides/introduction/product)**
+
+## :building_construction: Genel Mimarisi
+
+Mimari diyagramımızla Open-IM-Server'ın işlevselliğinin kalbine dalın.
+
+
+
+## :rocket: Hızlı Başlangıç
+
+Birçok platformu destekliyoruz. Web tarafında hızlı deneyim için adresler şunlardır:
+
+👉 **[OpenIM online demo](https://www.openim.io/zh/commercial)**
+
+🤲 Kullanıcı deneyimini kolaylaştırmak için çeşitli dağıtım çözümleri sunuyoruz. Aşağıdaki listeden dağıtım yönteminizi seçebilirsiniz:
+
++ **[Kaynak Kodu Dağıtım Kılavuzu](https://docs.openim.io/guides/gettingStarted/imSourceCodeDeployment)**
++ **[Docker Dağıtım Kılavuzu](https://docs.openim.io/guides/gettingStarted/dockerCompose)**
++ **[Kubernetes Dağıtım Kılavuzu](https://docs.openim.io/guides/gettingStarted/k8s-deployment)**
++ **[Mac Geliştirici Dağıtım Kılavuzu](https://docs.openim.io/guides/gettingstarted/mac-deployment-guide)**
+
+## :hammer_and_wrench: OpenIM Geliştirmeye Başlamak
+
+[](https://vscode.dev/github/openimsdk/open-im-server)
+
+OpenIM Amacımız, üst düzey bir açık kaynak topluluğu oluşturmaktır. [Topluluk deposunda](https://github.com/OpenIMSDK/community) bir dizi standartımız var.
+
+Bu Open-IM-Server deposuna katkıda bulunmak istiyorsanız, lütfen katkıda bulunanlar için [dokümantasyonumuzu](https://github.com/openimsdk/open-im-server/blob/main/CONTRIBUTING.md) okuyun.
+
+Başlamadan önce, lütfen değişikliklerinizin talep edildiğinden emin olun. Bunun için en iyisi, [yeni bir tartışma OLUŞTURMAK](https://github.com/openimsdk/open-im-server/discussions/new/choose) veya [Slack İletişimi](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q) kurmak, ya da bir sorun bulursanız, önce bunu [rapor](https://github.com/openimsdk/open-im-server/issues/new/choose) etmektir.
+
+- [OpenIM API Referansı](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/api.md)
+- [OpenIM Bash Günlüğü](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/bash-log.md)
+- [OpenIM CI/CD İşlemleri](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/cicd-actions.md)
+- [OpenIM Kod Kuralları](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/code-conventions.md)
+- [OpenIM Taahhüt Kuralları](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/commit.md)
+- [OpenIM Geliştirme Kılavuzu](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/development.md)
+- [OpenIM Dizin Yapısı](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/directory.md)
+- [OpenIM Ortam Kurulumu](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/environment.md)
+- [OpenIM Hata Kodu Referansı](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/error-code.md)
+- [OpenIM Git İş Akışı](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/git-workflow.md)
+- [OpenIM Git Cherry Pick Kılavuzu](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/gitcherry-pick.md)
+- [OpenIM GitHub İş Akışı](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/github-workflow.md)
+- [OpenIM Go Kod Standartları](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/go-code.md)
+- [OpenIM Görüntü Kuralları](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/images.md)
+- [OpenIM İlk Yapılandırma](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/init-config.md)
+- [OpenIM Docker Kurulum Kılavuzu](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/install-docker.md)
+- [OpenIM Linux Sistem Kurulumu](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/install-openim-linux-system.md)
+- [OpenIM Linux Geliştirme Kılavuzu](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/linux-development.md)
+- [OpenIM Yerel İşlemler Kılavuzu](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/local-actions.md)
+- [OpenIM Günlük Kuralları](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/logging.md)
+- [OpenIM Çevrimdışı Dağıtım](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/offline-deployment.md)
+- [OpenIM Protoc Araçları](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/protoc-tools.md)
+- [OpenIM Test Kılavuzu](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/test.md)
+- [OpenIM Yardımcı Go](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/util-go.md)
+- [OpenIM Makefile Yardımcı Programları](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/util-makefile.md)
+- [OOpenIM Betik Yardımcı Programları](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/util-scripts.md)
+- [OpenIM Sürümleme](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/version.md)
+- [Arka uç yönetimi ve izleme dağıtımı](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/prometheus-grafana.md)
+- [Mac Geliştirici Dağıtım Kılavuzu for OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/mac-developer-deployment-guide.md)
+
+
+## :busts_in_silhouette: Topluluk
+
++ 📚 [OpenIM Topluluğu](https://github.com/OpenIMSDK/community)
++ 💕 [OpenIM İlgi Grubu](https://github.com/Openim-sigs)
++ 🚀 [Slack topluluğumuza katılın](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q)
++ :eyes: [Wechat grubumuza katılın (微信群)](https://openim-1253691595.cos.ap-nanjing.myqcloud.com/WechatIMG20.jpeg)
+
+## :calendar: Topluluk Toplantıları
+
+Topluluğumuza herkesin katılmasını ve kod katkısında bulunmasını istiyoruz, hediyeler ve ödüller sunuyoruz ve sizi her Perşembe gecesi bize katılmaya davet ediyoruz.
+
+Konferansımız [OpenIM Slack'te](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q) 🎯, ardından Open-IM-Server boru hattını arayıp katılabilirsiniz.
+
+İki haftada bir yapılan toplantının [notlarını](https://github.com/orgs/OpenIMSDK/discussions/categories/meeting) [GitHub tartışmalarında alıyoruz](https://github.com/openimsdk/open-im-server/discussions/categories/meeting), Tarihi toplantı notlarımız ve toplantıların tekrarları [Google Docs'ta](https://docs.google.com/document/d/1nx8MDpuG74NASx081JcCpxPgDITNTpIIos0DS6Vr9GU/edit?usp=sharing) 📑 mevcut.
+
+## :eyes: Kimler OpenIM Kullanıyor
+
+Proje kullanıcılarının bir listesi için [kullanıcı vaka çalışmaları](https://github.com/OpenIMSDK/community/blob/main/ADOPTERS.md) sayfamıza göz atın. Bir 📝[yorum](https://github.com/openimsdk/open-im-server/issues/379) bırakmaktan ve kullanım durumunuzu paylaşmaktan çekinmeyin.
+
+## :page_facing_up: Lisans
+
+OpenIM, Apache 2.0 lisansı altında lisanslanmıştır. Tam lisans metni için [LICENSE'ı](https://github.com/openimsdk/open-im-server/tree/main/LICENSE) görün.
+
+Bu depoda, [assets/logo](../../assets/logo) ve [assets/logo-gif](../../assets/logo-gif) dizinlerinde görüntülenen [OpenIM](https://github.com/openimsdk/open-im-server) logosu, çeşitleri ve animasyonlu versiyonları, telif hakkı yasaları tarafından korunmaktadır.
+
+## 🔮 Katkıda bulunanlarımıza teşekkürler!
+
+
+
+
\ No newline at end of file
diff --git a/docs/readme/README_uk.md b/docs/readme/README_uk.md
new file mode 100644
index 000000000..30bc76730
--- /dev/null
+++ b/docs/readme/README_uk.md
@@ -0,0 +1,187 @@
+
+
+
+
+
+
+
+
+[](https://github.com/openimsdk/open-im-server/stargazers)
+[](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/)
+
+
+
+ Englist ·
+ 中文 ·
+ Українська ·
+ Česky ·
+ Magyar ·
+ Español ·
+ فارسی ·
+ Français ·
+ Deutsch ·
+ Polski ·
+ Indonesian ·
+ Suomi ·
+ മലയാളം ·
+ 日本語 ·
+ Nederlands ·
+ Italiano ·
+ Русский ·
+ Português (Brasil) ·
+ Esperanto ·
+ 한국어 ·
+ العربي ·
+ Tiếng Việt ·
+ Dansk ·
+ Ελληνικά ·
+ Türkçe
+
+
+
+
+
+
+
+## Ⓜ️ Про OpenIM
+
+OpenIM — це сервісна платформа, спеціально розроблена для інтеграції чату, аудіо-відеодзвінків, сповіщень і чат-ботів штучного інтелекту в програми. Він надає ряд потужних API і веб-хуків, що дозволяє розробникам легко включати ці інтерактивні функції у свої програми. OpenIM не є окремою програмою для чату, а скоріше служить платформою для підтримки інших програм у досягненні широких можливостей спілкування. На наступній діаграмі детально показано взаємодію між AppServer, AppClient, OpenIMServer і OpenIMSDK.
+
+
+
+## 🚀 Про OpenIMSDK
+
+**OpenIMSDK** – це пакет IM SDK, розроблений для **OpenIMServer**, створений спеціально для вбудовування в клієнтські програми. Його основні функції та модулі такі:
+
++ 🌟 Основні характеристики:
+
+ - 📦 Локальне сховище
+ - 🔔 Зворотні виклики слухача
+ - 🛡️ Обгортка API
+ - 🌐 Керування підключенням
+
++ 📚 Основні модулі:
+
+ 1. 🚀 Ініціалізація та вхід
+ 2. 👤 Керування користувачами
+ 3. 👫 Керування друзями
+ 4. 🤖 Групові функції
+ 5. 💬 Ведення розмови
+
+Він створений за допомогою Golang і підтримує кросплатформне розгортання, забезпечуючи послідовний доступ на всіх платформах.
+
+👉 **[Дослідити GO SDK](https://github.com/openimsdk/openim-sdk-core)**
+
+## 🌐 Про OpenIMServer
+
++ **OpenIMServer** має такі характеристики:
+ - 🌐 Архітектура мікросервісу: підтримує режим кластера, включаючи шлюз і кілька служб rpc.
+ - 🚀 Різноманітні методи розгортання: підтримує розгортання через вихідний код, Kubernetes або Docker.
+ - Підтримка величезної бази користувачів: надвеликі групи із сотнями тисяч користувачів, десятками мільйонів користувачів і мільярдами повідомлень.
+
+### Розширена бізнес-функціональність:
+
++ **REST API**: OpenIMServer пропонує REST API для бізнес-систем, спрямованих на надання компаніям додаткових можливостей, таких як створення груп і надсилання push-повідомлень через серверні інтерфейси.
++ **Веб-перехоплення**: OpenIMServer надає можливості зворотного виклику, щоб розширити більше бізнес-форм. Зворотний виклик означає, що OpenIMServer надсилає запит на бізнес-сервер до або після певної події, як зворотні виклики до або після надсилання повідомлення.
+
+👉 **[Докладніше](https://docs.openim.io/guides/introduction/product)**
+
+## :building_construction: Загальна архітектура
+
+Пориньте в серце функціональності Open-IM-Server за допомогою нашої діаграми архітектури.
+
+
+
+
+## :rocket: Швидкий початок
+
+Ми підтримуємо багато платформ. Ось адреси для швидкого використання веб-сайту:
+
+👉 **[Онлайн-демонстрація OpenIM](https://web-enterprise.rentsoft.cn/)**
+
+🤲 Щоб полегшити роботу користувача, ми пропонуємо різні рішення для розгортання. Ви можете вибрати спосіб розгортання зі списку нижче:
+
++ **[Посібник із розгортання вихідного коду](https://docs.openim.io/guides/gettingStarted/imSourceCodeDeployment)**
++ **[Посібник із розгортання Docker](https://docs.openim.io/guides/gettingStarted/dockerCompose)**
++ **[Посібник із розгортання Kubernetes](https://docs.openim.io/guides/gettingStarted/k8s-deployment)**
++ **[Посібник із розгортання розробника Mac](https://docs.openim.io/guides/gettingstarted/mac-deployment-guide)**
+
+## :hammer_and_wrench: Щоб розпочати розробку OpenIM
+
+[](https://vscode.dev/github/openimsdk/open-im-server)
+
+OpenIM. Наша мета — побудувати спільноту з відкритим кодом найвищого рівня. У нас є набір стандартів у [репозиторії спільноти](https://github.com/OpenIMSDK/community).
+
+Якщо ви хочете внести свій внесок у це сховище Open-IM-Server, прочитайте нашу [документацію для учасників](https://github.com/openimsdk/open-im-server/blob/main/CONTRIBUTING.md).
+
+Перш ніж почати, переконайтеся, що ваші зміни затребувані. Найкраще для цього створити [нове обговорення](https://github.com/openimsdk/open-im-server/discussions/new/choose) АБО [Нездійснене спілкування](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q)або, якщо ви виявите проблему, спершу [повідомити про неї](https://github.com/openimsdk/open-im-server/issues/new/choose).
+
+- [Довідка щодо API OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/api.md)
+- [Ведення журналу OpenIM Bash](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/bash-log.md)
+- [Дії OpenIM CI/CD](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/cicd-actions.md)
+- [Положення про код OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/code-conventions.md)
+- [Інструкції щодо фіксації OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/commit.md)
+- [Посібник з розробки OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/development.md)
+- [Структура каталогу OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/directory.md)
+- [Налаштування середовища OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/environment.md)
+- [Довідка про код помилки OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/error-code.md)
+- [Робочий процес OpenIM Git](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/git-workflow.md)
+- [Посібник із вибору OpenIM Git Cherry](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/gitcherry-pick.md)
+- [Робочий процес OpenIM GitHub](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/github-workflow.md)
+- [Стандарти коду OpenIM Go](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/go-code.md)
+- [Інструкції щодо зображення OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/images.md)
+- [Початкова конфігурація OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/init-config.md)
+- [Посібник із встановлення OpenIM Docker](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/install-docker.md)
+- [Встановлення системи OpenIM OpenIM Linux](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/install-openim-linux-system.md)
+- [Посібник із розробки OpenIM Linux](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/linux-development.md)
+- [Локальний посібник із дій OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/local-actions.md)
+- [Положення про протоколювання OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/logging.md)
+- [Офлайн-розгортання OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/offline-deployment.md)
+- [Інструменти OpenIM Protoc](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/protoc-tools.md)
+- [Посібник з тестування OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/test.md)
+- [Утиліта OpenIM Go](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/util-go.md)
+- [Утиліти OpenIM Makefile](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/util-makefile.md)
+- [Утиліти сценарію OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/util-scripts.md)
+- [Версії OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/version.md)
+- [Керування серверною частиною та моніторинг розгортання](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/prometheus-grafana.md)
+- [Посібник із розгортання розробника Mac для OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/mac-developer-deployment-guide.md)
+
+
+## :busts_in_silhouette: Спільнота
+
++ 📚 [Спільнота OpenIM](https://github.com/OpenIMSDK/community)
++ 💕 [Група інтересів OpenIM](https://github.com/Openim-sigs)
++ 🚀 [Приєднайтеся до нашої спільноти Slack](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q)
++ :eyes: [Приєднайтеся до нашого wechat](https://openim-1253691595.cos.ap-nanjing.myqcloud.com/WechatIMG20.jpeg)
+
+## :calendar: Збори громади
+
+Ми хочемо, щоб будь-хто долучився до нашої спільноти та додав код, ми пропонуємо подарунки та нагороди, і ми запрошуємо вас приєднатися до нас щочетверга ввечері.
+
+Наша конференція знаходиться в [OpenIM Slack](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q) 🎯, тоді ви можете шукати конвеєр Open-IM-Server, щоб приєднатися.
+
+Ми робимо нотатки про кожну [двотижневу зустріч](https://github.com/orgs/OpenIMSDK/discussions/categories/meeting)в [обговореннях GitHub](https://github.com/openimsdk/open-im-server/discussions/categories/meeting). Наші історичні нотатки зустрічей, а також повтори зустрічей доступні в[Google Docs :bookmark_tabs:](https://docs.google.com/document/d/1nx8MDpuG74NASx081JcCpxPgDITNTpIIos0DS6Vr9GU/edit?usp=sharing).
+
+## :eyes: Хто використовує OpenIM
+
+Перегляньте нашу сторінку [тематичні дослідження користувачів](https://github.com/OpenIMSDK/community/blob/main/ADOPTERS.md), щоб отримати список користувачів проекту. Не соромтеся залишити [📝коментар](https://github.com/openimsdk/open-im-server/issues/379)і поділитися своїм випадком використання.
+
+## :page_facing_up: Ліцензія
+
+OpenIM ліцензовано за ліцензією Apache 2.0. Див. [ЛІЦЕНЗІЯ](https://github.com/openimsdk/open-im-server/tree/main/LICENSE) для повного тексту ліцензії.
+
+Логотип OpenIM, включаючи його варіації та анімовані версії, що відображаються в цьому сховищі[OpenIM](https://github.com/openimsdk/open-im-server)у каталогах [assets/logo](./assets/logo)і [assets/logo-gif](assets/logo-gif) , захищені законами про авторське право.
+
+## 🔮 Дякуємо нашим дописувачам!
+
+
+
+
diff --git a/docs/readme/README_vi.md b/docs/readme/README_vi.md
new file mode 100644
index 000000000..e500da6d2
--- /dev/null
+++ b/docs/readme/README_vi.md
@@ -0,0 +1,188 @@
+
+
+
+
+
+
+
+
+[](https://github.com/openimsdk/open-im-server/stargazers)
+[](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/)
+
+
+
+ Englist ·
+ 中文 ·
+ Українська ·
+ Česky ·
+ Magyar ·
+ Español ·
+ فارسی ·
+ Français ·
+ Deutsch ·
+ Polski ·
+ Indonesian ·
+ Suomi ·
+ മലയാളം ·
+ 日本語 ·
+ Nederlands ·
+ Italiano ·
+ Русский ·
+ Português (Brasil) ·
+ Esperanto ·
+ 한국어 ·
+ العربي ·
+ Tiếng Việt ·
+ Dansk ·
+ Ελληνικά ·
+ Türkçe
+
+
+
+
+
+
+
+## Ⓜ️ Về OpenIM
+
+OpenIM là một nền tảng dịch vụ được thiết kế đặc biệt cho việc tích hợp chat, cuộc gọi âm thanh-video, thông báo và chatbot AI vào các ứng dụng. Nó cung cấp một loạt các API mạnh mẽ và Webhooks, giúp các nhà phát triển dễ dàng tích hợp các tính năng tương tác này vào ứng dụng của mình. OpenIM không phải là một ứng dụng chat độc lập, mà là một nền tảng hỗ trợ các ứng dụng khác để đạt được các chức năng giao tiếp phong phú. Sơ đồ sau đây minh họa sự tương tác giữa AppServer, AppClient, OpenIMServer và OpenIMSDK để giải thích chi tiết.
+
+
+
+## 🚀 Về OpenIMSDK
+
+**OpenIMSDK** là một SDK IM được thiết kế cho **OpenIMServer**, được tạo ra đặc biệt để nhúng vào các ứng dụng khách. Các tính năng chính và các mô-đun của nó như sau:
+
++ 🌟 Các Tính Năng Chính:
+
+ - 📦 Lưu trữ cục bộ
+ - 🔔 Gọi lại sự kiện (Listener callbacks)
+ - 🛡️ Bọc API
+ - 🌐 Quản lý kết nối
+
++ 📚 Các Mô-đun Chính:
+
+ 1. 🚀 Khởi tạo và Đăng nhập
+ 2. 👤 Quản lý Người dùng
+ 3. 👫 Quản lý Bạn bè
+ 4. 🤖 Chức năng Nhóm
+ 5. 💬 Xử lý Cuộc trò chuyện
+
+Nó được xây dựng bằng Golang và hỗ trợ triển khai đa nền tảng, đảm bảo trải nghiệm truy cập nhất quán trên tất cả các nền tảng
+
+👉 **[Khám phá GO SDK](https://github.com/openimsdk/openim-sdk-core)**
+
+## 🌐 Về OpenIMServer
+
++ **OpenIMServer** có những đặc điểm sau:
+ - 🌐 Kiến trúc vi dịch vụ: Hỗ trợ chế độ cluster, bao gồm một gateway và nhiều dịch vụ rpc.
+ - 🚀 Phương pháp triển khai đa dạng: Hỗ trợ triển khai qua mã nguồn, Kubernetes hoặc Docker.
+ - Hỗ trợ cho cơ sở người dùng lớn: Nhóm siêu lớn với hàng trăm nghìn người dùng, hàng chục triệu người dùng và hàng tỷ tin nhắn.
+
+### Tăng cường Chức năng Kinh doanh:
+
++ **REST API**: OpenIMServer cung cấp REST APIs cho các hệ thống kinh doanh, nhằm tăng cường khả năng cho doanh nghiệp với nhiều chức năng hơn, như tạo nhóm và gửi tin nhắn đẩy qua giao diện backend.
++ **Webhooks**: OpenIMServer cung cấp khả năng gọi lại để mở rộng thêm hình thức kinh doanh. Một gọi lại có nghĩa là OpenIMServer gửi một yêu cầu đến máy chủ kinh doanh trước hoặc sau một sự kiện nhất định, giống như gọi lại trước hoặc sau khi gửi một tin nhắn.
+
+👉 **[Learn more](https://docs.openim.io/guides/introduction/product)**
+
+## :building_construction: Kiến trúc tổng thể
+
+ Làm sâu sắc vào trái tim của chức năng Open-IM-Server với sơ đồ kiến trúc của chúng tôi.
+
+
+
+
+## :rocket: Bắt đầu nhanh
+
+Chúng tôi hỗ trợ nhiều nền tảng. Dưới đây là các địa chỉ để trải nghiệm nhanh trên phía web:
+
+👉 **[Demo web trực tuyến OpenIM](https://web-enterprise.rentsoft.cn/)**
+
+🤲 Để tạo thuận lợi cho trải nghiệm người dùng, chúng tôi cung cấp các giải pháp triển khai đa dạng. Bạn có thể chọn phương thức triển khai từ danh sách dưới đây:
+
++ **[Hướng dẫn Triển khai Mã Nguồn](https://docs.openim.io/guides/gettingStarted/imSourceCodeDeployment)**
++ **[Hướng dẫn Triển khai Docker](https://docs.openim.io/guides/gettingStarted/dockerCompose)**
++ **[Hướng dẫn Triển khai Kubernetes](https://docs.openim.io/guides/gettingStarted/k8s-deployment)**
++ **[Hướng dẫn Triển khai cho Nhà Phát Triển Mac](https://docs.openim.io/guides/gettingstarted/mac-deployment-guide)**
+
+## :hammer_and_wrench: Để Bắt Đầu Phát Triển OpenIM
+
+[](https://vscode.dev/github/openimsdk/open-im-server)
+
+Mục tiêu của OpenIM là xây dựng một cộng đồng mã nguồn mở cấp cao. Chúng tôi có một bộ tiêu chuẩn, Trong [kho lưu trữ Cộng đồng](https://github.com/OpenIMSDK/community).
+
+Nếu bạn muốn đóng góp cho kho lưu trữ Open-IM-Server này, vui lòng đọc [tài liệu hướng dẫn cho người đóng góp](https://github.com/openimsdk/open-im-server/blob/main/CONTRIBUTING.md).
+
+
+Trước khi bạn bắt đầu, hãy chắc chắn rằng các thay đổi của bạn được yêu cầu. Cách tốt nhất là tạo một [cuộc thảo luận mới](https://github.com/openimsdk/open-im-server/discussions/new/choose) hoặc [Giao tiếp Slack](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q), hoặc nếu bạn tìm thấy một vấn đề, [báo cáo nó ](https://github.com/openimsdk/open-im-server/issues/new/choose) trước.
+
+- [Tham khảo API OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/api.md)
+- [Nhật ký Bash OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/bash-log.md)
+- [Hành động CI/CD OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/cicd-actions.md)
+- [Quy ước Mã OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/code-conventions.md)
+- [Hướng dẫn Commit OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/commit.md)
+- [Hướng dẫn Phát triển OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/development.md)
+- [Cấu trúc Thư mục OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/directory.md)
+- [Cài đặt Môi trường OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/environment.md)
+- [Tham khảo Mã Lỗi OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/error-code.md)
+- [Quy trình Git OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/git-workflow.md)
+- [Hướng dẫn Cherry Pick Git OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/gitcherry-pick.md)
+- [Quy trình GitHub OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/github-workflow.md)
+- [Tiêu chuẩn Mã Go OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/go-code.md)
+- [Hướng dẫn Hình ảnh OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/images.md)
+- [Cấu hình Ban đầu OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/init-config.md)
+- [Hướng dẫn Cài đặt Docker OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/install-docker.md)
+- [Hướng dẫn Cài đặt Hệ thống Linux OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/install-openim-linux-system.md)
+- [Hướng dẫn Phát triển Linux OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/linux-development.md)
+- [Hướng dẫn Hành động Địa phương OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/local-actions.md)
+- [Quy ước Nhật ký OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/logging.md)
+- [Triển khai Ngoại tuyến OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/offline-deployment.md)
+- [Công cụ Protoc OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/protoc-tools.md)
+- [Hướng dẫn Kiểm thử OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/test.md)
+- [Utility Go OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/util-go.md)
+- [Tiện ích Makefile OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/util-makefile.md)
+- [Tiện ích Kịch bản OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/util-scripts.md)
+- [Quản lý Phiên bản OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/version.md)
+- [Quản lý triển khai và giám sát backend](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/prometheus-grafana.md)
+- [Hướng dẫn Triển khai cho Nhà Phát triển Mac OpenIM](https://github.com/openimsdk/open-im-server/tree/main/docs/contrib/mac-developer-deployment-guide.md)
+
+
+## :busts_in_silhouette: Cộng đồng
+
++ 📚 [Cộng đồng OpenIM](https://github.com/OpenIMSDK/community)
++ 💕 [Nhóm Quan tâm OpenIM](https://github.com/Openim-sigs)
++ 🚀 [Tham gia cộng đồng Slack của chúng tôi](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q)
++ :eyes: [Tham gia nhóm WeChat của chúng tôi (微信群)](https://openim-1253691595.cos.ap-nanjing.myqcloud.com/WechatIMG20.jpeg)
+
+## :calendar: Cuộc họp Cộng đồng
+
+Chúng tôi muốn bất kỳ ai cũng có thể tham gia cộng đồng và đóng góp mã nguồn, chúng tôi cung cấp quà tặng và phần thưởng, và chúng tôi chào đón bạn tham gia cùng chúng tôi mỗi tối thứ Năm.
+
+Hội nghị của chúng tôi được tổ chức trên Slack của [OpenIM Slack](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q) 🎯, sau đó bạn có thể tìm kiếm pipeline Open-IM-Server để tham gia
+
+Chúng tôi ghi chú mỗi [cuộc họp hai tuần một lần](https://github.com/orgs/OpenIMSDK/discussions/categories/meeting) trong [các cuộc thảo luận GitHub](https://github.com/openimsdk/open-im-server/discussions/categories/meeting), ghi chú cuộc họp lịch sử của chúng tôi cũng như các bản ghi lại của cuộc họp có sẵn tại [Google Docs :bookmark_tabs:](https://docs.google.com/document/d/1nx8MDpuG74NASx081JcCpxPgDITNTpIIos0DS6Vr9GU/edit?usp=sharing).
+
+## :eyes: Ai Đang Sử Dụng OpenIM
+
+Xem trangr [các nghiên cứu trường hợp người dùng](https://github.com/OpenIMSDK/community/blob/main/ADOPTERS.md) của chúng tôi để biết danh sách các người dùng dự án. Đừng ngần ngại để lại [📝bình luận](https://github.com/openimsdk/open-im-server/issues/379) và chia sẻ trường hợp sử dụng của bạn.
+
+## :page_facing_up: Giấy phép
+
+OpenIM được cấp phép theo giấy phép Apache 2.0. Xem [GIẤY PHÉP](https://github.com/openimsdk/open-im-server/tree/main/LICENSE) để biết toàn bộ nội dung giấy phép.
+
+Logo OpenIM, bao gồm các biến thể và phiên bản hoạt hình, được hiển thị trong kho lưu trữ này [OpenIM](https://github.com/openimsdk/open-im-server) dưới các thư mục [assets/logo](../../assets/logo) và [assets/logo-gif](assets/logo-gif) được bảo vệ bởi luật bản quyền.
+
+## 🔮 Cảm ơn các đóng góp của bạn!
+
+
+
+
diff --git a/go.mod b/go.mod
index d496aac12..10f08fa53 100644
--- a/go.mod
+++ b/go.mod
@@ -4,58 +4,57 @@ go 1.19
require (
firebase.google.com/go v3.13.0+incompatible
- github.com/OpenIMSDK/protocol v0.0.53
- github.com/OpenIMSDK/tools v0.0.29
+ github.com/OpenIMSDK/protocol v0.0.55
+ github.com/OpenIMSDK/tools v0.0.37
github.com/bwmarrin/snowflake v0.3.0 // indirect
github.com/dtm-labs/rockscache v0.1.1
github.com/gin-gonic/gin v1.9.1
- github.com/go-playground/validator/v10 v10.15.5
+ github.com/go-playground/validator/v10 v10.18.0
github.com/gogo/protobuf v1.3.2
github.com/golang-jwt/jwt/v4 v4.5.0
- github.com/gorilla/websocket v1.5.0
+ github.com/gorilla/websocket v1.5.1
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0
github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible // indirect
- github.com/minio/minio-go/v7 v7.0.63
+ github.com/minio/minio-go/v7 v7.0.67
github.com/mitchellh/mapstructure v1.5.0
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/prometheus/client_golang v1.17.0
+ github.com/prometheus/client_golang v1.18.0
github.com/robfig/cron/v3 v3.0.1
github.com/sirupsen/logrus v1.9.3 // indirect
github.com/stretchr/testify v1.8.4
- go.mongodb.org/mongo-driver v1.12.1
- golang.org/x/image v0.13.0
- google.golang.org/api v0.148.0
- google.golang.org/grpc v1.59.0
- google.golang.org/protobuf v1.31.0
+ go.mongodb.org/mongo-driver v1.14.0
+ golang.org/x/image v0.15.0
+ google.golang.org/api v0.165.0
+ google.golang.org/grpc v1.61.0
+ google.golang.org/protobuf v1.32.0
gopkg.in/yaml.v3 v3.0.1
)
-require github.com/google/uuid v1.3.1
+require github.com/google/uuid v1.6.0
require (
- github.com/IBM/sarama v1.41.3
- github.com/aliyun/aliyun-oss-go-sdk v2.2.9+incompatible
+ github.com/IBM/sarama v1.42.2
+ github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible
github.com/go-redis/redis v6.15.9+incompatible
- github.com/redis/go-redis/v9 v9.2.1
+ github.com/redis/go-redis/v9 v9.4.0
github.com/spf13/pflag v1.0.5
github.com/stathat/consistent v1.0.0
- github.com/tencentyun/cos-go-sdk-v5 v0.7.45
- go.uber.org/automaxprocs v1.5.3
- golang.org/x/sync v0.4.0
+ github.com/tencentyun/cos-go-sdk-v5 v0.7.46
+ golang.org/x/sync v0.6.0
gopkg.in/src-d/go-git.v4 v4.13.1
gotest.tools v2.2.0+incompatible
)
require (
- cloud.google.com/go v0.110.8 // indirect
- cloud.google.com/go/compute v1.23.0 // indirect
+ cloud.google.com/go v0.112.0 // indirect
+ cloud.google.com/go/compute v1.23.3 // indirect
cloud.google.com/go/compute/metadata v0.2.3 // indirect
- cloud.google.com/go/firestore v1.13.0 // indirect
- cloud.google.com/go/iam v1.1.2 // indirect
- cloud.google.com/go/longrunning v0.5.1 // indirect
- cloud.google.com/go/storage v1.30.1 // indirect
+ cloud.google.com/go/firestore v1.14.0 // indirect
+ cloud.google.com/go/iam v1.1.5 // indirect
+ cloud.google.com/go/longrunning v0.5.4 // indirect
+ cloud.google.com/go/storage v1.36.0 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/bytedance/sonic v1.9.1 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
@@ -64,12 +63,15 @@ require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
- github.com/eapache/go-resiliency v1.4.0 // indirect
+ github.com/eapache/go-resiliency v1.5.0 // indirect
github.com/eapache/go-xerial-snappy v0.0.0-20230731223053-c322873962e3 // indirect
github.com/eapache/queue v1.1.0 // indirect
github.com/emirpasic/gods v1.12.0 // indirect
- github.com/gabriel-vasile/mimetype v1.4.2 // indirect
+ github.com/felixge/httpsnoop v1.0.4 // indirect
+ github.com/gabriel-vasile/mimetype v1.4.3 // indirect
github.com/gin-contrib/sse v0.1.0 // indirect
+ github.com/go-logr/logr v1.4.1 // indirect
+ github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/go-zookeeper/zk v1.0.3 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
@@ -78,7 +80,7 @@ require (
github.com/google/go-cmp v0.6.0 // indirect
github.com/google/go-querystring v1.1.0 // indirect
github.com/google/s2a-go v0.1.7 // indirect
- github.com/googleapis/enterprise-certificate-proxy v0.3.1 // indirect
+ github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect
github.com/googleapis/gax-go/v2 v2.12.0 // indirect
github.com/hashicorp/errwrap v1.0.0 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect
@@ -96,11 +98,11 @@ require (
github.com/jinzhu/now v1.1.5 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd // indirect
- github.com/klauspost/compress v1.16.7 // indirect
- github.com/klauspost/cpuid/v2 v2.2.5 // indirect
- github.com/leodido/go-urn v1.2.4 // indirect
+ github.com/klauspost/compress v1.17.4 // indirect
+ github.com/klauspost/cpuid/v2 v2.2.6 // indirect
+ github.com/leodido/go-urn v1.4.0 // 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/v2 v2.0.0 // indirect
github.com/minio/md5-simd v1.1.2 // indirect
github.com/minio/sha256-simd v1.0.1 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
@@ -111,11 +113,11 @@ require (
github.com/onsi/ginkgo v1.16.5 // indirect
github.com/onsi/gomega v1.18.1 // indirect
github.com/pelletier/go-toml/v2 v2.0.8 // indirect
- github.com/pierrec/lz4/v4 v4.1.18 // indirect
+ github.com/pierrec/lz4/v4 v4.1.21 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
- github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16 // indirect
- github.com/prometheus/common v0.44.0 // indirect
- github.com/prometheus/procfs v0.11.1 // indirect
+ github.com/prometheus/client_model v0.5.0 // indirect
+ github.com/prometheus/common v0.45.0 // indirect
+ github.com/prometheus/procfs v0.12.0 // indirect
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect
github.com/rs/xid v1.5.0 // indirect
github.com/sergi/go-diff v1.0.0 // indirect
@@ -128,22 +130,26 @@ require (
github.com/xdg-go/stringprep v1.0.4 // indirect
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect
go.opencensus.io v0.24.0 // indirect
+ go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.47.0 // indirect
+ go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.47.0 // indirect
+ go.opentelemetry.io/otel v1.23.0 // indirect
+ go.opentelemetry.io/otel/metric v1.23.0 // indirect
+ go.opentelemetry.io/otel/trace v1.23.0 // indirect
go.uber.org/atomic v1.7.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
golang.org/x/arch v0.3.0 // indirect
- golang.org/x/net v0.17.0 // indirect
- golang.org/x/oauth2 v0.13.0 // indirect
- golang.org/x/sys v0.15.0 // indirect
+ golang.org/x/net v0.21.0 // indirect
+ golang.org/x/oauth2 v0.17.0 // indirect
+ golang.org/x/sys v0.17.0 // indirect
golang.org/x/text v0.14.0 // indirect
golang.org/x/time v0.5.0 // indirect
- golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
- google.golang.org/appengine v1.6.7 // indirect
- google.golang.org/genproto v0.0.0-20231002182017-d307bd883b97 // indirect
- google.golang.org/genproto/googleapis/api v0.0.0-20231002182017-d307bd883b97 // indirect
- google.golang.org/genproto/googleapis/rpc v0.0.0-20231012201019-e917dd12ba7a // indirect
+ google.golang.org/appengine v1.6.8 // indirect
+ google.golang.org/genproto v0.0.0-20240125205218-1f4bbc51befe // indirect
+ google.golang.org/genproto/googleapis/api v0.0.0-20240116215550-a9fa1716bcac // indirect
+ google.golang.org/genproto/googleapis/rpc v0.0.0-20240205150955-31a09d347014 // indirect
gopkg.in/src-d/go-billy.v4 v4.3.2 // indirect
gopkg.in/warnings.v0 v0.1.2 // indirect
- gorm.io/gorm v1.23.8 // indirect
+ gorm.io/gorm v1.25.4 // indirect
stathat.com/c/consistent v1.0.0 // indirect
)
@@ -152,10 +158,10 @@ require (
github.com/goccy/go-json v0.10.2 // indirect
github.com/lestrrat-go/strftime v1.0.6 // indirect
github.com/mattn/go-isatty v0.0.19 // indirect
- github.com/spf13/cobra v1.7.0
+ github.com/spf13/cobra v1.8.0
github.com/ugorji/go/codec v1.2.11 // indirect
go.uber.org/zap v1.24.0 // indirect
- golang.org/x/crypto v0.17.0 // indirect
+ golang.org/x/crypto v0.19.0 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
)
diff --git a/go.sum b/go.sum
index 81604661d..0bba2d65f 100644
--- a/go.sum
+++ b/go.sum
@@ -1,18 +1,18 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
-cloud.google.com/go v0.110.8 h1:tyNdfIxjzaWctIiLYOTalaLKZ17SI44SKFW26QbOhME=
-cloud.google.com/go v0.110.8/go.mod h1:Iz8AkXJf1qmxC3Oxoep8R1T36w8B92yU29PcBhHO5fk=
-cloud.google.com/go/compute v1.23.0 h1:tP41Zoavr8ptEqaW6j+LQOnyBBhO7OkOMAGrgLopTwY=
-cloud.google.com/go/compute v1.23.0/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM=
+cloud.google.com/go v0.112.0 h1:tpFCD7hpHFlQ8yPwT3x+QeXqc2T6+n6T+hmABHfDUSM=
+cloud.google.com/go v0.112.0/go.mod h1:3jEEVwZ/MHU4djK5t5RHuKOA/GbLddgTdVubX1qnPD4=
+cloud.google.com/go/compute v1.23.3 h1:6sVlXXBmbd7jNX0Ipq0trII3e4n1/MsADLK6a+aiVlk=
+cloud.google.com/go/compute v1.23.3/go.mod h1:VCgBUoMnIVIR0CscqQiPJLAG25E3ZRZMzcFZeQ+h8CI=
cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY=
cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA=
-cloud.google.com/go/firestore v1.13.0 h1:/3S4RssUV4GO/kvgJZB+tayjhOfyAHs+KcpJgRVu/Qk=
-cloud.google.com/go/firestore v1.13.0/go.mod h1:QojqqOh8IntInDUSTAh0c8ZsPYAr68Ma8c5DWOy8xb8=
-cloud.google.com/go/iam v1.1.2 h1:gacbrBdWcoVmGLozRuStX45YKvJtzIjJdAolzUs1sm4=
-cloud.google.com/go/iam v1.1.2/go.mod h1:A5avdyVL2tCppe4unb0951eI9jreack+RJ0/d+KUZOU=
-cloud.google.com/go/longrunning v0.5.1 h1:Fr7TXftcqTudoyRJa113hyaqlGdiBQkp0Gq7tErFDWI=
-cloud.google.com/go/longrunning v0.5.1/go.mod h1:spvimkwdz6SPWKEt/XBij79E9fiTkHSQl/fRUUQJYJc=
-cloud.google.com/go/storage v1.30.1 h1:uOdMxAs8HExqBlnLtnQyP0YkvbiDpdGShGKtx6U/oNM=
-cloud.google.com/go/storage v1.30.1/go.mod h1:NfxhC0UJE1aXSx7CIIbCf7y9HKT7BiccwkR7+P7gN8E=
+cloud.google.com/go/firestore v1.14.0 h1:8aLcKnMPoldYU3YHgu4t2exrKhLQkqaXAGqT0ljrFVw=
+cloud.google.com/go/firestore v1.14.0/go.mod h1:96MVaHLsEhbvkBEdZgfN+AS/GIkco1LRpH9Xp9YZfzQ=
+cloud.google.com/go/iam v1.1.5 h1:1jTsCu4bcsNsE4iiqNT5SHwrDRCfRmIaaaVFhRveTJI=
+cloud.google.com/go/iam v1.1.5/go.mod h1:rB6P/Ic3mykPbFio+vo7403drjlgvoWfYpJhMXEbzv8=
+cloud.google.com/go/longrunning v0.5.4 h1:w8xEcbZodnA2BbW6sVirkkoC+1gP8wS57EUUgGS0GVg=
+cloud.google.com/go/longrunning v0.5.4/go.mod h1:zqNVncI0BOP8ST6XQD1+VcvuShMmq7+xFSzOL++V0dI=
+cloud.google.com/go/storage v1.36.0 h1:P0mOkAcaJxhCTvAkMhxMfrTKiNcub4YmmPBtlhAyTr8=
+cloud.google.com/go/storage v1.36.0/go.mod h1:M6M/3V/D3KpzMTJyPOR/HU6n2Si5QdaXYEsng2xgOs8=
firebase.google.com/go v3.13.0+incompatible h1:3TdYC3DDi6aHn20qoRkxwGqNgdjtblwVAyRLQwGn/+4=
firebase.google.com/go v3.13.0+incompatible/go.mod h1:xlah6XbEyW6tbfSklcfe5FHJIwjt8toICdV5Wh9ptHs=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
@@ -22,11 +22,17 @@ github.com/OpenIMSDK/protocol v0.0.53 h1:PtePLTqMYRHjWSf8XIL3x5JRC3YoySTMA6tRKfb
github.com/OpenIMSDK/protocol v0.0.53/go.mod h1:F25dFrwrIx3lkNoiuf6FkCfxuwf8L4Z8UIsdTHP/r0Y=
github.com/OpenIMSDK/tools v0.0.29 h1:NS4PEwYl9sX3SWsMjDOLVxMo3LcTWREMr+2cjzWjcqc=
github.com/OpenIMSDK/tools v0.0.29/go.mod h1:eg+q4A34Qmu73xkY0mt37FHGMCMfC6CtmOnm0kFEGFI=
+github.com/IBM/sarama v1.42.2 h1:VoY4hVIZ+WQJ8G9KNY/SQlWguBQXQ9uvFPOnrcu8hEw=
+github.com/IBM/sarama v1.42.2/go.mod h1:FLPGUGwYqEs62hq2bVG6Io2+5n+pS6s/WOXVKWSLFtE=
+github.com/OpenIMSDK/protocol v0.0.55 h1:eBjg8DyuhxGmuCUjpoZjg6MJJJXU/xJ3xJwFhrn34yA=
+github.com/OpenIMSDK/protocol v0.0.55/go.mod h1:F25dFrwrIx3lkNoiuf6FkCfxuwf8L4Z8UIsdTHP/r0Y=
+github.com/OpenIMSDK/tools v0.0.37 h1:qvDqmA4RbEJtPjZouWCkVuf/pjm6Y8nUrG5iH2gcnOg=
+github.com/OpenIMSDK/tools v0.0.37/go.mod h1:wBfR5CYmEyvxl03QJbTkhz1CluK6J4/lX0lviu8JAjE=
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/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs=
-github.com/aliyun/aliyun-oss-go-sdk v2.2.9+incompatible h1:Sg/2xHwDrioHpxTN6WMiwbXTpUEinBpHsN7mG21Rc2k=
-github.com/aliyun/aliyun-oss-go-sdk v2.2.9+incompatible/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8=
+github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible h1:8psS8a+wKfiLt1iVDX79F7Y6wUM49Lcha2FMXt4UM8g=
+github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8=
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA=
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
@@ -54,7 +60,8 @@ github.com/clbanning/mxj v1.8.4 h1:HuhwZtbyvyOw+3Z1AowPkU87JkJUSv751ELWaiTpj8I=
github.com/clbanning/mxj v1.8.4/go.mod h1:BVjHeAH+rl9rs6f+QIpeRl0tfu10SXn1pUSa5PVGJng=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
-github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
+github.com/cncf/xds/go v0.0.0-20231109132714-523115ebc101 h1:7To3pQ+pZo0i3dsWEbinPNFs5gPSBOsJtx3wTT94VBY=
+github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
@@ -66,8 +73,8 @@ github.com/dtm-labs/rockscache v0.1.1 h1:6S1vgaHvGqrLd8Ka4hRTKeKPV7v+tT0MSkTIX81
github.com/dtm-labs/rockscache v0.1.1/go.mod h1:c76WX0kyIibmQ2ACxUXvDvaLykoPakivMqIxt+UzE7A=
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
-github.com/eapache/go-resiliency v1.4.0 h1:3OK9bWpPk5q6pbFAaYSEwD9CLUSHG8bnZuqX2yMt3B0=
-github.com/eapache/go-resiliency v1.4.0/go.mod h1:5yPzW0MIvSe0JDsv0v+DvcjEv2FyD6iZYSs1ZI+iQho=
+github.com/eapache/go-resiliency v1.5.0 h1:dRsaR00whmQD+SgVKlq/vCRFNgtEb5yppyeVos3Yce0=
+github.com/eapache/go-resiliency v1.5.0/go.mod h1:5yPzW0MIvSe0JDsv0v+DvcjEv2FyD6iZYSs1ZI+iQho=
github.com/eapache/go-xerial-snappy v0.0.0-20230731223053-c322873962e3 h1:Oy0F4ALJ04o5Qqpdz8XLIpNA3WM/iSIXqxtqo7UGVws=
github.com/eapache/go-xerial-snappy v0.0.0-20230731223053-c322873962e3/go.mod h1:YvSRo5mw33fLEx1+DlK6L2VV43tJt5Eyel9n9XBcR+0=
github.com/eapache/queue v1.1.0 h1:YOEu7KNc61ntiQlcEeUIoDTJ2o8mQznoNvUhiigpIqc=
@@ -78,26 +85,34 @@ github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymF
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
+github.com/envoyproxy/protoc-gen-validate v1.0.2 h1:QkIBuU5k+x7/QXPvPPnWXWlCdaBFApVqftFV6k087DA=
+github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
+github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
-github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU=
-github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA=
+github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
+github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk=
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg=
github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU=
github.com/gliderlabs/ssh v0.2.2 h1:6zsha5zo/TWhRhwqCD3+EarCAgZ2yN28ipRnGPnwkI0=
github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
+github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
+github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
+github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
+github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
+github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
-github.com/go-playground/validator/v10 v10.15.5 h1:LEBecTWb/1j5TNY1YYG2RcOUN3R7NLylN+x8TTueE24=
-github.com/go-playground/validator/v10 v10.15.5/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
+github.com/go-playground/validator/v10 v10.18.0 h1:BvolUXjp4zuvkZ5YN5t7ebzbhlUtPsPm2S9NAZ5nl9U=
+github.com/go-playground/validator/v10 v10.18.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
github.com/go-redis/redis v6.15.9+incompatible h1:K0pv1D7EQUjfyoMql+r/jZqCLizCGKFlFgcHWWmHQjg=
github.com/go-redis/redis v6.15.9+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
@@ -115,7 +130,6 @@ github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
-github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
@@ -129,7 +143,6 @@ github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaS
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
-github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
@@ -152,16 +165,16 @@ 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/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.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4=
-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/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0=
+github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
+github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs=
+github.com/googleapis/enterprise-certificate-proxy v0.3.2/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/go.mod h1:y+aIqrI5eb1YGMVJfuV3185Ts/D7qKpsEkdD5+I6QGU=
github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM=
-github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
-github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
+github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY=
+github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
@@ -196,7 +209,6 @@ github.com/jinzhu/copier v0.3.5 h1:GlvfUwHk62RokgqVNvYsku0TATCF7bAHVwEXoBh3iJg=
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/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/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/jonboulle/clockwork v0.4.0 h1:p4Cf1aMWXnXAUh8lVfewRBx1zaTSYKrKMF2g3ST4RZ4=
@@ -206,21 +218,20 @@ github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd h1:Coekwdh0v
github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
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/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
-github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I=
-github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
+github.com/klauspost/compress v1.17.4 h1:Ej5ixsIri7BrIjBkRZLTo6ghwrEtHFk7ijlczPW4fZ4=
+github.com/klauspost/compress v1.17.4/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM=
github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
-github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg=
-github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
+github.com/klauspost/cpuid/v2 v2.2.6 h1:ndNyv040zDGIDh8thGkXYjnFtiN02M1PVVF+JE/48xc=
+github.com/klauspost/cpuid/v2 v2.2.6/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
-github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q=
-github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4=
+github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
+github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
github.com/lestrrat-go/envload v0.0.0-20180220234015-a3eb8ddeffcc h1:RKf14vYWi2ttpEmkA4aQ3j4u9dStX2t4M8UM6qqNsG8=
github.com/lestrrat-go/envload v0.0.0-20180220234015-a3eb8ddeffcc/go.mod h1:kopuH9ugFRkIXf3YoqHKyrJ9YfUFsckUU9S7B+XP+is=
github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible h1:Y6sqxHMyB1D2YSzWkLibYKgg+SwmyFU9dF2hn6MdTj4=
@@ -231,12 +242,12 @@ github.com/lithammer/shortuuid v3.0.0+incompatible h1:NcD0xWW/MZYXEHa6ITy6kaXN5n
github.com/lithammer/shortuuid v3.0.0+incompatible/go.mod h1:FR74pbAuElzOUuenUHTK2Tciko1/vKuIKS9dSkDrA4w=
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
-github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
-github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
+github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg=
+github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k=
github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34=
github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM=
-github.com/minio/minio-go/v7 v7.0.63 h1:GbZ2oCvaUdgT5640WJOpyDhhDxvknAJU2/T3yurwcbQ=
-github.com/minio/minio-go/v7 v7.0.63/go.mod h1:Q6X7Qjb7WMhvG65qKf4gUgA5XaiSox74kR1uAEjxRS4=
+github.com/minio/minio-go/v7 v7.0.67 h1:BeBvZWAS+kRJm1vGTMJYVjKUNoo0FoEt/wUWdUtfmh8=
+github.com/minio/minio-go/v7 v7.0.67/go.mod h1:+UXocnUeZ3wHvVh5s95gcrA4YjMIbccT6ubB+1m054A=
github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dzMM=
github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8=
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
@@ -273,27 +284,26 @@ github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5h
github.com/pelletier/go-buffruneio v0.2.0/go.mod h1:JkE26KsDizTr40EUHkXVtNPvgGtbSNq5BcowyYOWdKo=
github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ=
github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4=
-github.com/pierrec/lz4/v4 v4.1.18 h1:xaKrnTkyoqfh1YItXl56+6KJNVYWlEEPuAQW9xsplYQ=
-github.com/pierrec/lz4/v4 v4.1.18/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
+github.com/pierrec/lz4/v4 v4.1.21 h1:yOVMLb6qSIDP67pl/5F7RepeKYu/VmTyEXvuMI5d9mQ=
+github.com/pierrec/lz4/v4 v4.1.21/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
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/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/go.mod h1:VeL+gMmOAxkS2IqfCq0ZmHSL+LjWfWDUmp1mBz9JgUY=
+github.com/prometheus/client_golang v1.18.0 h1:HzFfmkOzH5Q8L8G+kSJKUx5dtG87sewO+FoDDqP5Tbk=
+github.com/prometheus/client_golang v1.18.0/go.mod h1:T+GXkCk5wSJyOqMIzVgvvjFDlkOQntgjkJWKrN5txjA=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
-github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16 h1:v7DLqVdK4VrYkVD5diGdl4sxJurKJEMnODWRJlxV9oM=
-github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU=
-github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY=
-github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY=
-github.com/prometheus/procfs v0.11.1 h1:xRC8Iq1yyca5ypa9n1EZnWZkt7dwcoRPQwX/5gwaUuI=
-github.com/prometheus/procfs v0.11.1/go.mod h1:eesXgaPo1q7lBpVMoMy0ZOFTth9hBn4W/y0/p/ScXhY=
+github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw=
+github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI=
+github.com/prometheus/common v0.45.0 h1:2BGz0eBc2hdMDLnO/8n0jeB3oPrt2D08CekT0lneoxM=
+github.com/prometheus/common v0.45.0/go.mod h1:YJmSTw9BoKxJplESWWxlbyttQR4uaEcGyv9MZjVOJsY=
+github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo=
+github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 h1:N/ElC8H3+5XpJzTSTfLsJV/mx9Q9g7kxmchpfZyxgzM=
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
-github.com/redis/go-redis/v9 v9.2.1 h1:WlYJg71ODF0dVspZZCpYmoF1+U1Jjk9Rwd7pq6QmlCg=
-github.com/redis/go-redis/v9 v9.2.1/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0b/CLO2V2M=
+github.com/redis/go-redis/v9 v9.4.0 h1:Yzoz33UZw9I/mFhx4MNrB6Fk+XHO1VukNcCa1+lwyKk=
+github.com/redis/go-redis/v9 v9.4.0/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0b/CLO2V2M=
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
@@ -304,8 +314,8 @@ github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ=
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
-github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I=
-github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0=
+github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0=
+github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/src-d/gcfg v1.4.0 h1:xXbNR5AlLSA315x2UO+fTSSAXCDf+Ar38/6oyGbDKQ4=
@@ -324,14 +334,13 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
-github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.563/go.mod h1:7sCQWVkxcsR38nffDW057DRGk8mUjK1Ing/EFOK8s8Y=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/kms v1.0.563/go.mod h1:uom4Nvi9W+Qkom0exYiJ9VWJjXwyxtPYTkKkaLMlfE0=
-github.com/tencentyun/cos-go-sdk-v5 v0.7.45 h1:5/ZGOv846tP6+2X7w//8QjLgH2KcUK+HciFbfjWquFU=
-github.com/tencentyun/cos-go-sdk-v5 v0.7.45/go.mod h1:DH9US8nB+AJXqwu/AMOrCFN1COv3dpytXuJWHgdg7kE=
+github.com/tencentyun/cos-go-sdk-v5 v0.7.46 h1:IeTiMR8qZ7iQWhAGb1niw5vt0T1TfAwPeB8Gn/oTkuk=
+github.com/tencentyun/cos-go-sdk-v5 v0.7.46/go.mod h1:DH9US8nB+AJXqwu/AMOrCFN1COv3dpytXuJWHgdg7kE=
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU=
@@ -349,14 +358,23 @@ github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7Jul
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
-go.mongodb.org/mongo-driver v1.12.1 h1:nLkghSU8fQNaK7oUmDhQFsnrtcoNy7Z6LVFKsEecqgE=
-go.mongodb.org/mongo-driver v1.12.1/go.mod h1:/rGBTebI3XYboVmgz+Wv3Bcbl3aD0QF9zl6kDDw18rQ=
+go.mongodb.org/mongo-driver v1.14.0 h1:P98w8egYRjYe3XDjxhYJagTokP/H6HzlsnojRgZRd80=
+go.mongodb.org/mongo-driver v1.14.0/go.mod h1:Vzb0Mk/pa7e6cWw85R4F/endUC3u0U9jGcNU603k65c=
go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
+go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.47.0 h1:UNQQKPfTDe1J81ViolILjTKPr9WetKW6uei2hFgJmFs=
+go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.47.0/go.mod h1:r9vWsPS/3AQItv3OSlEJ/E4mbrhUbbw18meOjArPtKQ=
+go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.47.0 h1:sv9kVfal0MK0wBMCOGr+HeJm9v803BkJxGrk2au7j08=
+go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.47.0/go.mod h1:SK2UL73Zy1quvRPonmOmRDiWk1KBV3LyIeeIxcEApWw=
+go.opentelemetry.io/otel v1.23.0 h1:Df0pqjqExIywbMCMTxkAwzjLZtRf+bBKLbUcpxO2C9E=
+go.opentelemetry.io/otel v1.23.0/go.mod h1:YCycw9ZeKhcJFrb34iVSkyT0iczq/zYDtZYFufObyB0=
+go.opentelemetry.io/otel/metric v1.23.0 h1:pazkx7ss4LFVVYSxYew7L5I6qvLXHA0Ap2pwV+9Cnpo=
+go.opentelemetry.io/otel/metric v1.23.0/go.mod h1:MqUW2X2a6Q8RN96E2/nqNoT+z9BSms20Jb7Bbp+HiTo=
+go.opentelemetry.io/otel/sdk v1.21.0 h1:FTt8qirL1EysG6sTQRZ5TokkU8d0ugCj8htOgThZXQ8=
+go.opentelemetry.io/otel/trace v1.23.0 h1:37Ik5Ib7xfYVb4V1UtnT97T1jI+AoIYkJyPkuL4iJgI=
+go.opentelemetry.io/otel/trace v1.23.0/go.mod h1:GSGTbIClEsuZrGIzoEHqsVfxgn5UkggkflQwDScNUsk=
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
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/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
@@ -371,13 +389,12 @@ golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
-golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
-golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k=
-golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
+golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo=
+golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
-golang.org/x/image v0.13.0 h1:3cge/F/QTkNLauhf2QoE9zp+7sr+ZcL4HnoZmdwg9sg=
-golang.org/x/image v0.13.0/go.mod h1:6mmbMOeV28HuMTgA6OSRkdXKYw/t5W9Uwn2Yv1r3Yxk=
+golang.org/x/image v0.15.0 h1:kOELfmgrmJlw4Cdb7g/QGuB3CvDrXbqEIww/pNtNBm8=
+golang.org/x/image v0.15.0/go.mod h1:HUYqC05R2ZcZ3ejNQsIHQDQiwWM4JBqmm6MKANTp4LE=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
@@ -390,7 +407,6 @@ golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73r
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
@@ -400,24 +416,22 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
-golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
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.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
-golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
-golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
+golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4=
+golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
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/go.mod h1:/JMhi4ZRXAf4HG9LiNmxvk+45+96RUlVThiH8FzNBn0=
+golang.org/x/oauth2 v0.17.0 h1:6m3ZPmLEFdVxKKWnKq4VqZ60gutO35zm+zrAHVmHyDQ=
+golang.org/x/oauth2 v0.17.0/go.mod h1:OzPDGQiuQMguemayvdylqddI7qcD9lnSDb+1FiwQ5HA=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ=
-golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
+golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
+golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -440,12 +454,12 @@ golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
-golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y=
+golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
-golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4=
+golang.org/x/term v0.17.0 h1:mkTF7LCd6WGJNL3K1Ad7kwxNfYAW6a8a8QqtMblp/4U=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
@@ -473,29 +487,28 @@ golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8T
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk=
-golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
-google.golang.org/api v0.148.0 h1:HBq4TZlN4/1pNcu0geJZ/Q50vIwIXT532UIMYoo0vOs=
-google.golang.org/api v0.148.0/go.mod h1:8/TBgwaKjfqTdacOJrOv2+2Q6fBDU1uHKK06oGSkxzU=
+google.golang.org/api v0.165.0 h1:zd5d4JIIIaYYsfVy1HzoXYZ9rWCSBxxAglbczzo7Bgc=
+google.golang.org/api v0.165.0/go.mod h1:2OatzO7ZDQsoS7IFf3rvsE17/TldiU3F/zxFHeqUB5o=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
-google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
-google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
+google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM=
+google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
-google.golang.org/genproto v0.0.0-20231002182017-d307bd883b97 h1:SeZZZx0cP0fqUyA+oRzP9k7cSwJlvDFiROO72uwD6i0=
-google.golang.org/genproto v0.0.0-20231002182017-d307bd883b97/go.mod h1:t1VqOqqvce95G3hIDCT5FeO3YUc6Q4Oe24L/+rNMxRk=
-google.golang.org/genproto/googleapis/api v0.0.0-20231002182017-d307bd883b97 h1:W18sezcAYs+3tDZX4F80yctqa12jcP1PUS2gQu1zTPU=
-google.golang.org/genproto/googleapis/api v0.0.0-20231002182017-d307bd883b97/go.mod h1:iargEX0SFPm3xcfMI0d1domjg0ZF4Aa0p2awqyxhvF0=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20231012201019-e917dd12ba7a h1:a2MQQVoTo96JC9PMGtGBymLp7+/RzpFc2yX/9WfFg1c=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20231012201019-e917dd12ba7a/go.mod h1:4cYg8o5yUbm77w8ZX00LhMVNl/YVBFJRYWDc0uYWMs0=
+google.golang.org/genproto v0.0.0-20240125205218-1f4bbc51befe h1:USL2DhxfgRchafRvt/wYyyQNzwgL7ZiURcozOE/Pkvo=
+google.golang.org/genproto v0.0.0-20240125205218-1f4bbc51befe/go.mod h1:cc8bqMqtv9gMOr0zHg2Vzff5ULhhL2IXP4sbcn32Dro=
+google.golang.org/genproto/googleapis/api v0.0.0-20240116215550-a9fa1716bcac h1:OZkkudMUu9LVQMCoRUbI/1p5VCo9BOrlvkqMvWtqa6s=
+google.golang.org/genproto/googleapis/api v0.0.0-20240116215550-a9fa1716bcac/go.mod h1:B5xPO//w8qmBDjGReYLpR6UJPnkldGkCSMoH/2vxJeg=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20240205150955-31a09d347014 h1:FSL3lRCkhaPFxqi0s9o+V4UI2WTzAVOvkgbd4kVV4Wg=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20240205150955-31a09d347014/go.mod h1:SaPjaZGWb0lPqs6Ittu0spdfrOArqji4ZdeP5IC/9N4=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
-google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk=
-google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98=
+google.golang.org/grpc v1.61.0 h1:TOvOcuXn30kRao+gfcvsebNEa5iZIiLkisYEkf7R7o0=
+google.golang.org/grpc v1.61.0/go.mod h1:VUbo7IFqmF1QtCAstipjG0GIoq49KvMe9+h1jFLBNJs=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
@@ -507,8 +520,8 @@ google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpAD
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
-google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
-google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
+google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I=
+google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
@@ -533,8 +546,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.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
-gorm.io/gorm v1.23.8 h1:h8sGJ+biDgBA1AD1Ha9gFCx7h8npU7AsLdlkX0n2TpE=
-gorm.io/gorm v1.23.8/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk=
+gorm.io/gorm v1.25.4 h1:iyNd8fNAe8W9dvtlgeRI5zSVZPsq3OpcTu37cYcpCmw=
+gorm.io/gorm v1.25.4/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k=
gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
diff --git a/go.work b/go.work
index 97d2816d6..be67ce842 100644
--- a/go.work
+++ b/go.work
@@ -3,6 +3,7 @@ go 1.19
use (
.
./test/typecheck
+ ./tools/codescan
./tools/changelog
./tools/component
./tools/data-conversion
diff --git a/install.sh b/install.sh
index 7ff0f8739..4b8e74c55 100755
--- a/install.sh
+++ b/install.sh
@@ -18,7 +18,7 @@
#
set -e
-set -o pipefail
+
############################## OpenIM Github ##############################
# ... rest of the script ...
diff --git a/internal/api/auth.go b/internal/api/auth.go
index 44a97a013..0f7a3933b 100644
--- a/internal/api/auth.go
+++ b/internal/api/auth.go
@@ -15,11 +15,9 @@
package api
import (
- "github.com/gin-gonic/gin"
-
"github.com/OpenIMSDK/protocol/auth"
"github.com/OpenIMSDK/tools/a2r"
-
+ "github.com/gin-gonic/gin"
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
)
@@ -33,6 +31,10 @@ func (o *AuthApi) UserToken(c *gin.Context) {
a2r.Call(auth.AuthClient.UserToken, o.Client, c)
}
+func (o *AuthApi) GetUserToken(c *gin.Context) {
+ a2r.Call(auth.AuthClient.GetUserToken, o.Client, c)
+}
+
func (o *AuthApi) ParseToken(c *gin.Context) {
a2r.Call(auth.AuthClient.ParseToken, o.Client, c)
}
diff --git a/internal/api/conversation.go b/internal/api/conversation.go
index eb735e550..fe6c67001 100644
--- a/internal/api/conversation.go
+++ b/internal/api/conversation.go
@@ -15,11 +15,9 @@
package api
import (
- "github.com/gin-gonic/gin"
-
"github.com/OpenIMSDK/protocol/conversation"
"github.com/OpenIMSDK/tools/a2r"
-
+ "github.com/gin-gonic/gin"
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
)
diff --git a/internal/api/custom_validator.go b/internal/api/custom_validator.go
index 8c5890501..d135b0dc4 100644
--- a/internal/api/custom_validator.go
+++ b/internal/api/custom_validator.go
@@ -15,24 +15,20 @@
package api
import (
- "github.com/go-playground/validator/v10"
-
"github.com/OpenIMSDK/protocol/constant"
+ "github.com/go-playground/validator/v10"
)
+// RequiredIf validates if the specified field is required based on the session type.
func RequiredIf(fl validator.FieldLevel) bool {
sessionType := fl.Parent().FieldByName("SessionType").Int()
+
switch sessionType {
case constant.SingleChatType, constant.NotificationChatType:
- if fl.FieldName() == "RecvID" {
- return fl.Field().String() != ""
- }
+ return fl.FieldName() != "RecvID" || fl.Field().String() != ""
case constant.GroupChatType, constant.SuperGroupChatType:
- if fl.FieldName() == "GroupID" {
- return fl.Field().String() != ""
- }
+ return fl.FieldName() != "GroupID" || fl.Field().String() != ""
default:
return true
}
- return true
}
diff --git a/internal/api/friend.go b/internal/api/friend.go
index 7dc898a02..24bcbf899 100644
--- a/internal/api/friend.go
+++ b/internal/api/friend.go
@@ -17,10 +17,8 @@ package api
import (
"github.com/OpenIMSDK/protocol/friend"
"github.com/OpenIMSDK/tools/a2r"
-
- "github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
-
"github.com/gin-gonic/gin"
+ "github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
)
type FriendApi rpcclient.Friend
diff --git a/internal/api/group.go b/internal/api/group.go
index e525cd495..c18ded64b 100644
--- a/internal/api/group.go
+++ b/internal/api/group.go
@@ -17,10 +17,8 @@ package api
import (
"github.com/OpenIMSDK/protocol/group"
"github.com/OpenIMSDK/tools/a2r"
-
- "github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
-
"github.com/gin-gonic/gin"
+ "github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
)
type GroupApi rpcclient.Group
diff --git a/internal/api/msg.go b/internal/api/msg.go
index 9348596ac..d38c14d4e 100644
--- a/internal/api/msg.go
+++ b/internal/api/msg.go
@@ -27,11 +27,9 @@ import (
"github.com/gin-gonic/gin"
"github.com/go-playground/validator/v10"
"github.com/mitchellh/mapstructure"
-
+ "github.com/openimsdk/open-im-server/v3/pkg/apistruct"
"github.com/openimsdk/open-im-server/v3/pkg/authverify"
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
-
- "github.com/openimsdk/open-im-server/v3/pkg/apistruct"
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
)
@@ -200,7 +198,7 @@ func (m *MessageApi) SendMessage(c *gin.Context) {
}
// Check if the user has the app manager role.
- if !authverify.IsAppManagerUid(c) {
+ if !authverify.IsAppManagerUid(c, m.Config) {
// Respond with a permission error if the user is not an app manager.
apiresp.GinError(c, errs.ErrNoPermission.Wrap("only app manager can send message"))
return
@@ -210,7 +208,6 @@ func (m *MessageApi) SendMessage(c *gin.Context) {
sendMsgReq, err := m.getSendMsgReq(c, req.SendMsg)
if err != nil {
// Log and respond with an error if preparation fails.
- log.ZError(c, "decodeData failed", err)
apiresp.GinError(c, err)
return
}
@@ -226,7 +223,6 @@ func (m *MessageApi) SendMessage(c *gin.Context) {
if err != nil {
// Set the status to failed and respond with an error if sending fails.
status = constant.MsgSendFailed
- log.ZError(c, "send message err", err)
apiresp.GinError(c, err)
return
}
@@ -240,7 +236,8 @@ func (m *MessageApi) SendMessage(c *gin.Context) {
})
if err != nil {
// Log the error if updating the status fails.
- log.ZError(c, "SetSendMsgStatus failed", err)
+ apiresp.GinError(c, err)
+ return
}
// Respond with a success message and the response payload.
@@ -259,7 +256,7 @@ func (m *MessageApi) SendBusinessNotification(c *gin.Context) {
return
}
- if !authverify.IsAppManagerUid(c) {
+ if !authverify.IsAppManagerUid(c, m.Config) {
apiresp.GinError(c, errs.ErrNoPermission.Wrap("only app manager can send message"))
return
}
@@ -299,25 +296,22 @@ func (m *MessageApi) BatchSendMsg(c *gin.Context) {
resp apistruct.BatchSendMsgResp
)
if err := c.BindJSON(&req); err != nil {
- log.ZError(c, "BatchSendMsg BindJSON failed", err)
apiresp.GinError(c, errs.ErrArgs.WithDetail(err.Error()).Wrap())
return
}
log.ZInfo(c, "BatchSendMsg", "req", req)
- if err := authverify.CheckAdmin(c); err != nil {
+ if err := authverify.CheckAdmin(c, m.Config); err != nil {
apiresp.GinError(c, errs.ErrNoPermission.Wrap("only app manager can send message"))
return
}
var recvIDs []string
- var err error
if req.IsSendAll {
pageNumber := 1
showNumber := 500
for {
recvIDsPart, err := m.userRpcClient.GetAllUserIDs(c, int32(pageNumber), int32(showNumber))
if err != nil {
- log.ZError(c, "GetAllUserIDs failed", err)
apiresp.GinError(c, err)
return
}
@@ -333,7 +327,6 @@ func (m *MessageApi) BatchSendMsg(c *gin.Context) {
log.ZDebug(c, "BatchSendMsg nums", "nums ", len(recvIDs))
sendMsgReq, err := m.getSendMsgReq(c, req.SendMsg)
if err != nil {
- log.ZError(c, "decodeData failed", err)
apiresp.GinError(c, err)
return
}
diff --git a/internal/api/route.go b/internal/api/route.go
index 10907d086..92fa83fb0 100644
--- a/internal/api/route.go
+++ b/internal/api/route.go
@@ -17,53 +17,138 @@ package api
import (
"context"
"fmt"
+ "net"
"net/http"
+ "os"
+ "os/signal"
+ "strconv"
+ "syscall"
+ "time"
"github.com/OpenIMSDK/protocol/constant"
"github.com/OpenIMSDK/tools/apiresp"
+ "github.com/OpenIMSDK/tools/discoveryregistry"
"github.com/OpenIMSDK/tools/errs"
+ "github.com/OpenIMSDK/tools/log"
+ "github.com/OpenIMSDK/tools/mw"
"github.com/OpenIMSDK/tools/tokenverify"
-
- "github.com/openimsdk/open-im-server/v3/pkg/authverify"
- "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache"
- "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller"
-
"github.com/gin-gonic/gin"
"github.com/gin-gonic/gin/binding"
"github.com/go-playground/validator/v10"
+ "github.com/openimsdk/open-im-server/v3/pkg/authverify"
+ "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"
+ kdisc "github.com/openimsdk/open-im-server/v3/pkg/common/discoveryregister"
+ ginprom "github.com/openimsdk/open-im-server/v3/pkg/common/ginprometheus"
+ "github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics"
+ "github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
+ util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil"
"github.com/redis/go-redis/v9"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
-
- "github.com/OpenIMSDK/tools/discoveryregistry"
- "github.com/OpenIMSDK/tools/log"
- "github.com/OpenIMSDK/tools/mw"
-
- "github.com/openimsdk/open-im-server/v3/pkg/common/config"
- "github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
)
-func NewGinRouter(discov discoveryregistry.SvcDiscoveryRegistry, rdb redis.UniversalClient) *gin.Engine {
- discov.AddOption(mw.GrpcClient(), grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithDefaultServiceConfig(fmt.Sprintf(`{"LoadBalancingPolicy": "%s"}`, "round_robin"))) // 默认RPC中间件
+func Start(config *config.GlobalConfig, port int, proPort int) error {
+ log.ZDebug(context.Background(), "configAPI1111111111111111111", config, "port", port, "javafdasfs")
+ if port == 0 || proPort == 0 {
+ err := "port or proPort is empty:" + strconv.Itoa(port) + "," + strconv.Itoa(proPort)
+ return errs.Wrap(fmt.Errorf(err))
+ }
+ rdb, err := cache.NewRedis(config)
+ if err != nil {
+ return err
+ }
+
+ var client discoveryregistry.SvcDiscoveryRegistry
+
+ // Determine whether zk is passed according to whether it is a clustered deployment
+ client, err = kdisc.NewDiscoveryRegister(config)
+ if err != nil {
+ return errs.Wrap(err, "register discovery err")
+ }
+
+ if err = client.CreateRpcRootNodes(config.GetServiceNames()); err != nil {
+ return errs.Wrap(err, "create rpc root nodes error")
+ }
+
+ if err = client.RegisterConf2Registry(constant.OpenIMCommonConfigKey, config.EncodeConfig()); err != nil {
+ return errs.Wrap(err)
+ }
+ var (
+ netDone = make(chan struct{}, 1)
+ netErr error
+ )
+ router := newGinRouter(client, rdb, config)
+ if config.Prometheus.Enable {
+ go func() {
+ p := ginprom.NewPrometheus("app", prommetrics.GetGinCusMetrics("Api"))
+ p.SetListenAddress(fmt.Sprintf(":%d", proPort))
+ if err = p.Use(router); err != nil && err != http.ErrServerClosed {
+ netErr = errs.Wrap(err, fmt.Sprintf("prometheus start err: %d", proPort))
+ netDone <- struct{}{}
+ }
+ }()
+
+ }
+
+ var address string
+ if config.Api.ListenIP != "" {
+ address = net.JoinHostPort(config.Api.ListenIP, strconv.Itoa(port))
+ } else {
+ address = net.JoinHostPort("0.0.0.0", strconv.Itoa(port))
+ }
+
+ server := http.Server{Addr: address, Handler: router}
+
+ go func() {
+ err = server.ListenAndServe()
+ if err != nil && err != http.ErrServerClosed {
+ netErr = errs.Wrap(err, fmt.Sprintf("api start err: %s", server.Addr))
+ netDone <- struct{}{}
+
+ }
+ }()
+
+ sigs := make(chan os.Signal, 1)
+ signal.Notify(sigs, syscall.SIGTERM)
+
+ ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
+ defer cancel()
+ select {
+ case <-sigs:
+ util.SIGTERMExit()
+ err := server.Shutdown(ctx)
+ if err != nil {
+ return errs.Wrap(err, "shutdown err")
+ }
+ case <-netDone:
+ close(netDone)
+ return netErr
+ }
+ return nil
+}
+
+func newGinRouter(disCov discoveryregistry.SvcDiscoveryRegistry, rdb redis.UniversalClient, config *config.GlobalConfig) *gin.Engine {
+ disCov.AddOption(mw.GrpcClient(), grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithDefaultServiceConfig(fmt.Sprintf(`{"LoadBalancingPolicy": "%s"}`, "round_robin")))
gin.SetMode(gin.ReleaseMode)
r := gin.New()
if v, ok := binding.Validator.Engine().(*validator.Validate); ok {
_ = v.RegisterValidation("required_if", RequiredIf)
}
- log.ZInfo(context.Background(), "load config", "config", config.Config)
r.Use(gin.Recovery(), mw.CorsHandler(), mw.GinParseOperationID())
// init rpc client here
- userRpc := rpcclient.NewUser(discov)
- groupRpc := rpcclient.NewGroup(discov)
- friendRpc := rpcclient.NewFriend(discov)
- messageRpc := rpcclient.NewMessage(discov)
- conversationRpc := rpcclient.NewConversation(discov)
- authRpc := rpcclient.NewAuth(discov)
- thirdRpc := rpcclient.NewThird(discov)
+ userRpc := rpcclient.NewUser(disCov, config)
+ groupRpc := rpcclient.NewGroup(disCov, config)
+ friendRpc := rpcclient.NewFriend(disCov, config)
+ messageRpc := rpcclient.NewMessage(disCov, config)
+ conversationRpc := rpcclient.NewConversation(disCov, config)
+ authRpc := rpcclient.NewAuth(disCov, config)
+ thirdRpc := rpcclient.NewThird(disCov, config)
u := NewUserApi(*userRpc)
m := NewMessageApi(messageRpc, userRpc)
- ParseToken := GinParseToken(rdb)
+ ParseToken := GinParseToken(rdb, config)
userRouterGroup := r.Group("/user")
{
userRouterGroup.POST("/user_register", u.UserRegister)
@@ -150,14 +235,15 @@ func NewGinRouter(discov discoveryregistry.SvcDiscoveryRegistry, rdb redis.Unive
{
a := NewAuthApi(*authRpc)
authRouterGroup.POST("/user_token", a.UserToken)
+ authRouterGroup.POST("/get_user_token", ParseToken, a.GetUserToken)
authRouterGroup.POST("/parse_token", a.ParseToken)
authRouterGroup.POST("/force_logout", ParseToken, a.ForceLogout)
}
// Third service
thirdGroup := r.Group("/third", ParseToken)
{
- thirdGroup.GET("/prometheus", GetPrometheus)
t := NewThirdApi(*thirdRpc)
+ thirdGroup.GET("/prometheus", t.GetPrometheus)
thirdGroup.POST("/fcm_update_token", t.FcmUpdateToken)
thirdGroup.POST("/set_app_badge", t.SetAppBadge)
@@ -224,11 +310,12 @@ func NewGinRouter(discov discoveryregistry.SvcDiscoveryRegistry, rdb redis.Unive
return r
}
-func GinParseToken(rdb redis.UniversalClient) gin.HandlerFunc {
+func GinParseToken(rdb redis.UniversalClient, config *config.GlobalConfig) gin.HandlerFunc {
dataBase := controller.NewAuthDatabase(
- cache.NewMsgCacheModel(rdb),
- config.Config.Secret,
- config.Config.TokenPolicy.Expire,
+ cache.NewMsgCacheModel(rdb, config),
+ config.Secret,
+ config.TokenPolicy.Expire,
+ config,
)
return func(c *gin.Context) {
switch c.Request.Method {
@@ -240,7 +327,7 @@ func GinParseToken(rdb redis.UniversalClient) gin.HandlerFunc {
c.Abort()
return
}
- claims, err := tokenverify.GetClaimFromToken(token, authverify.Secret())
+ claims, err := tokenverify.GetClaimFromToken(token, authverify.Secret(config.Secret))
if err != nil {
log.ZWarn(c, "jwt get token error", errs.ErrTokenUnknown.Wrap())
apiresp.GinError(c, errs.ErrTokenUnknown.Wrap())
@@ -249,13 +336,11 @@ func GinParseToken(rdb redis.UniversalClient) gin.HandlerFunc {
}
m, err := dataBase.GetTokensWithoutError(c, claims.UserID, claims.PlatformID)
if err != nil {
- log.ZWarn(c, "cache get token error", errs.ErrTokenNotExist.Wrap())
apiresp.GinError(c, errs.ErrTokenNotExist.Wrap())
c.Abort()
return
}
if len(m) == 0 {
- log.ZWarn(c, "cache do not exist token error", errs.ErrTokenNotExist.Wrap())
apiresp.GinError(c, errs.ErrTokenNotExist.Wrap())
c.Abort()
return
@@ -264,12 +349,10 @@ func GinParseToken(rdb redis.UniversalClient) gin.HandlerFunc {
switch v {
case constant.NormalToken:
case constant.KickedToken:
- log.ZWarn(c, "cache kicked token error", errs.ErrTokenKicked.Wrap())
apiresp.GinError(c, errs.ErrTokenKicked.Wrap())
c.Abort()
return
default:
- log.ZWarn(c, "cache unknown token error", errs.ErrTokenUnknown.Wrap())
apiresp.GinError(c, errs.ErrTokenUnknown.Wrap())
c.Abort()
return
@@ -285,3 +368,10 @@ func GinParseToken(rdb redis.UniversalClient) gin.HandlerFunc {
}
}
}
+
+// // handleGinError logs and returns an error response through Gin context.
+// func handleGinError(c *gin.Context, logMessage string, errType errs.CodeError, detail string) {
+// wrappedErr := errType.Wrap(detail)
+// apiresp.GinError(c, wrappedErr)
+// c.Abort()
+// }
diff --git a/internal/api/statistics.go b/internal/api/statistics.go
index 5750a7315..2b80a1585 100644
--- a/internal/api/statistics.go
+++ b/internal/api/statistics.go
@@ -15,11 +15,9 @@
package api
import (
- "github.com/gin-gonic/gin"
-
"github.com/OpenIMSDK/protocol/user"
"github.com/OpenIMSDK/tools/a2r"
-
+ "github.com/gin-gonic/gin"
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
)
diff --git a/internal/api/third.go b/internal/api/third.go
index 0a1ef0fbe..30448ae4d 100644
--- a/internal/api/third.go
+++ b/internal/api/third.go
@@ -19,15 +19,11 @@ import (
"net/http"
"strconv"
- config2 "github.com/openimsdk/open-im-server/v3/pkg/common/config"
-
- "github.com/gin-gonic/gin"
-
"github.com/OpenIMSDK/protocol/third"
"github.com/OpenIMSDK/tools/a2r"
"github.com/OpenIMSDK/tools/errs"
"github.com/OpenIMSDK/tools/mcontext"
-
+ "github.com/gin-gonic/gin"
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
)
@@ -129,6 +125,6 @@ func (o *ThirdApi) SearchLogs(c *gin.Context) {
a2r.Call(third.ThirdClient.SearchLogs, o.Client, c)
}
-func GetPrometheus(c *gin.Context) {
- c.Redirect(http.StatusFound, config2.Config.Prometheus.GrafanaUrl)
+func (o *ThirdApi) GetPrometheus(c *gin.Context) {
+ c.Redirect(http.StatusFound, o.Config.Prometheus.GrafanaUrl)
}
diff --git a/internal/api/user.go b/internal/api/user.go
index e7bbd4bfb..16b453e46 100644
--- a/internal/api/user.go
+++ b/internal/api/user.go
@@ -23,8 +23,6 @@ import (
"github.com/OpenIMSDK/tools/errs"
"github.com/OpenIMSDK/tools/log"
"github.com/gin-gonic/gin"
-
- "github.com/openimsdk/open-im-server/v3/pkg/common/config"
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
)
@@ -68,10 +66,10 @@ func (u *UserApi) GetUsers(c *gin.Context) {
func (u *UserApi) GetUsersOnlineStatus(c *gin.Context) {
var req msggateway.GetUsersOnlineStatusReq
if err := c.BindJSON(&req); err != nil {
- apiresp.GinError(c, errs.ErrArgs.WithDetail(err.Error()).Wrap())
+ apiresp.GinError(c, err)
return
}
- conns, err := u.Discov.GetConns(c, config.Config.RpcRegisterName.OpenImMessageGatewayName)
+ conns, err := u.Discov.GetConns(c, u.Config.RpcRegisterName.OpenImMessageGatewayName)
if err != nil {
apiresp.GinError(c, err)
return
@@ -86,7 +84,7 @@ func (u *UserApi) GetUsersOnlineStatus(c *gin.Context) {
msgClient := msggateway.NewMsgGatewayClient(v)
reply, err := msgClient.GetUsersOnlineStatus(c, &req)
if err != nil {
- log.ZWarn(c, "GetUsersOnlineStatus rpc err", err)
+ log.ZDebug(c, "GetUsersOnlineStatus rpc error", err)
parseError := apiresp.ParseError(err)
if parseError.ErrCode == errs.NoPermissionError {
@@ -135,7 +133,7 @@ func (u *UserApi) GetUsersOnlineTokenDetail(c *gin.Context) {
apiresp.GinError(c, errs.ErrArgs.WithDetail(err.Error()).Wrap())
return
}
- conns, err := u.Discov.GetConns(c, config.Config.RpcRegisterName.OpenImMessageGatewayName)
+ conns, err := u.Discov.GetConns(c, u.Config.RpcRegisterName.OpenImMessageGatewayName)
if err != nil {
apiresp.GinError(c, err)
return
@@ -145,7 +143,7 @@ func (u *UserApi) GetUsersOnlineTokenDetail(c *gin.Context) {
msgClient := msggateway.NewMsgGatewayClient(v)
reply, err := msgClient.GetUsersOnlineStatus(c, &req)
if err != nil {
- log.ZWarn(c, "GetUsersOnlineStatus rpc err", err)
+ log.ZWarn(c, "GetUsersOnlineStatus rpc err", err)
continue
} else {
wsResult = append(wsResult, reply.SuccessResult...)
diff --git a/internal/msggateway/callback.go b/internal/msggateway/callback.go
index d9507c85e..afb83bcc4 100644
--- a/internal/msggateway/callback.go
+++ b/internal/msggateway/callback.go
@@ -20,18 +20,13 @@ import (
"github.com/OpenIMSDK/protocol/constant"
"github.com/OpenIMSDK/tools/mcontext"
-
cbapi "github.com/openimsdk/open-im-server/v3/pkg/callbackstruct"
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
"github.com/openimsdk/open-im-server/v3/pkg/common/http"
)
-func callBackURL() string {
- return config.Config.Callback.CallbackUrl
-}
-
-func CallbackUserOnline(ctx context.Context, userID string, platformID int, isAppBackground bool, connID string) error {
- if !config.Config.Callback.CallbackUserOnline.Enable {
+func CallbackUserOnline(ctx context.Context, globalConfig *config.GlobalConfig, userID string, platformID int, isAppBackground bool, connID string) error {
+ if !globalConfig.Callback.CallbackUserOnline.Enable {
return nil
}
req := cbapi.CallbackUserOnlineReq{
@@ -49,14 +44,14 @@ func CallbackUserOnline(ctx context.Context, userID string, platformID int, isAp
ConnID: connID,
}
resp := cbapi.CommonCallbackResp{}
- if err := http.CallBackPostReturn(ctx, callBackURL(), &req, &resp, config.Config.Callback.CallbackUserOnline); err != nil {
+ if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, &req, &resp, globalConfig.Callback.CallbackUserOnline); err != nil {
return err
}
return nil
}
-func CallbackUserOffline(ctx context.Context, userID string, platformID int, connID string) error {
- if !config.Config.Callback.CallbackUserOffline.Enable {
+func CallbackUserOffline(ctx context.Context, globalConfig *config.GlobalConfig, userID string, platformID int, connID string) error {
+ if !globalConfig.Callback.CallbackUserOffline.Enable {
return nil
}
req := &cbapi.CallbackUserOfflineReq{
@@ -73,14 +68,14 @@ func CallbackUserOffline(ctx context.Context, userID string, platformID int, con
ConnID: connID,
}
resp := &cbapi.CallbackUserOfflineResp{}
- if err := http.CallBackPostReturn(ctx, callBackURL(), req, resp, config.Config.Callback.CallbackUserOffline); err != nil {
+ if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, req, resp, globalConfig.Callback.CallbackUserOffline); err != nil {
return err
}
return nil
}
-func CallbackUserKickOff(ctx context.Context, userID string, platformID int) error {
- if !config.Config.Callback.CallbackUserKickOff.Enable {
+func CallbackUserKickOff(ctx context.Context, globalConfig *config.GlobalConfig, userID string, platformID int) error {
+ if !globalConfig.Callback.CallbackUserKickOff.Enable {
return nil
}
req := &cbapi.CallbackUserKickOffReq{
@@ -96,7 +91,7 @@ func CallbackUserKickOff(ctx context.Context, userID string, platformID int) err
Seq: time.Now().UnixMilli(),
}
resp := &cbapi.CommonCallbackResp{}
- if err := http.CallBackPostReturn(ctx, callBackURL(), req, resp, config.Config.Callback.CallbackUserOffline); err != nil {
+ if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, req, resp, globalConfig.Callback.CallbackUserOffline); err != nil {
return err
}
return nil
diff --git a/internal/msggateway/client.go b/internal/msggateway/client.go
index 43047fd73..4e843821e 100644
--- a/internal/msggateway/client.go
+++ b/internal/msggateway/client.go
@@ -22,16 +22,15 @@ import (
"sync"
"sync/atomic"
- "github.com/openimsdk/open-im-server/v3/pkg/msgprocessor"
-
- "google.golang.org/protobuf/proto"
-
"github.com/OpenIMSDK/protocol/constant"
"github.com/OpenIMSDK/protocol/sdkws"
"github.com/OpenIMSDK/tools/apiresp"
+ "github.com/OpenIMSDK/tools/errs"
"github.com/OpenIMSDK/tools/log"
"github.com/OpenIMSDK/tools/mcontext"
"github.com/OpenIMSDK/tools/utils"
+ "github.com/openimsdk/open-im-server/v3/pkg/msgprocessor"
+ "google.golang.org/protobuf/proto"
)
var (
@@ -76,25 +75,20 @@ type Client struct {
token string
}
-func newClient(ctx *UserConnContext, conn LongConn, isCompress bool) *Client {
- return &Client{
- w: new(sync.Mutex),
- conn: conn,
- PlatformID: utils.StringToInt(ctx.GetPlatformID()),
- IsCompress: isCompress,
- UserID: ctx.GetUserID(),
- ctx: ctx,
- }
-}
+// function not used
+// func newClient(ctx *UserConnContext, conn LongConn, isCompress bool) *Client {
+// return &Client{
+// w: new(sync.Mutex),
+// conn: conn,
+// PlatformID: utils.StringToInt(ctx.GetPlatformID()),
+// IsCompress: isCompress,
+// UserID: ctx.GetUserID(),
+// ctx: ctx,
+// }
+// }
// ResetClient updates the client's state with new connection and context information.
-func (c *Client) ResetClient(
- ctx *UserConnContext,
- conn LongConn,
- isBackground, isCompress bool,
- longConnServer LongConnServer,
- token string,
-) {
+func (c *Client) ResetClient(ctx *UserConnContext, conn LongConn, isBackground, isCompress bool, longConnServer LongConnServer, token string) {
c.w = new(sync.Mutex)
c.conn = conn
c.PlatformID = utils.StringToInt(ctx.GetPlatformID())
@@ -109,9 +103,11 @@ func (c *Client) ResetClient(
c.token = token
}
-// pingHandler handles ping messages and sends pong responses.
func (c *Client) pingHandler(_ string) error {
- _ = c.conn.SetReadDeadline(pongWait)
+ if err := c.conn.SetReadDeadline(pongWait); err != nil {
+ return err
+ }
+
return c.writePongMsg()
}
@@ -138,7 +134,8 @@ func (c *Client) readMessage() {
}
log.ZDebug(c.ctx, "readMessage", "messageType", messageType)
- if c.closed.Load() { // 连接刚置位已经关闭,但是协程还没退出的场景
+ if c.closed.Load() {
+ // The scenario where the connection has just been closed, but the coroutine has not exited
c.closedErr = ErrConnClosed
return
}
@@ -173,7 +170,7 @@ func (c *Client) handleMessage(message []byte) error {
var err error
message, err = c.longConnServer.DecompressWithPool(message)
if err != nil {
- return utils.Wrap(err, "")
+ return errs.Wrap(err)
}
}
@@ -182,15 +179,15 @@ func (c *Client) handleMessage(message []byte) error {
err := c.longConnServer.Decode(message, binaryReq)
if err != nil {
- return utils.Wrap(err, "")
+ return err
}
if err := c.longConnServer.Validate(binaryReq); err != nil {
- return utils.Wrap(err, "")
+ return err
}
if binaryReq.SendID != c.UserID {
- return utils.Wrap(errors.New("exception conn userID not same to req userID"), binaryReq.String())
+ return errs.Wrap(errors.New("exception conn userID not same to req userID"), binaryReq.String())
}
ctx := mcontext.WithMustInfoCtx(
@@ -236,7 +233,7 @@ func (c *Client) setAppBackgroundStatus(ctx context.Context, req *Req) ([]byte,
}
c.IsBackground = isBackground
- // todo callback
+ // TODO: callback
return resp, nil
}
@@ -270,7 +267,7 @@ func (c *Client) replyMessage(ctx context.Context, binaryReq *Req, err error, re
}
if binaryReq.ReqIdentifier == WsLogoutMsg {
- return errors.New("user logout")
+ return errs.Wrap(errors.New("user logout"))
}
return nil
}
@@ -313,17 +310,21 @@ func (c *Client) writeBinaryMsg(resp Resp) error {
encodedBuf, err := c.longConnServer.Encode(resp)
if err != nil {
- return utils.Wrap(err, "")
+ return err
}
c.w.Lock()
defer c.w.Unlock()
- _ = c.conn.SetWriteDeadline(writeWait)
+ err = c.conn.SetWriteDeadline(writeWait)
+ if err != nil {
+ return err
+ }
+
if c.IsCompress {
resultBuf, compressErr := c.longConnServer.CompressWithPool(encodedBuf)
if compressErr != nil {
- return utils.Wrap(compressErr, "")
+ return compressErr
}
return c.conn.WriteMessage(MessageBinary, resultBuf)
}
@@ -341,7 +342,7 @@ func (c *Client) writePongMsg() error {
err := c.conn.SetWriteDeadline(writeWait)
if err != nil {
- return utils.Wrap(err, "")
+ return err
}
return c.conn.WriteMessage(PongMessage, nil)
diff --git a/internal/msggateway/compressor.go b/internal/msggateway/compressor.go
index ae5e9cdd0..140aac4d8 100644
--- a/internal/msggateway/compressor.go
+++ b/internal/msggateway/compressor.go
@@ -17,11 +17,10 @@ package msggateway
import (
"bytes"
"compress/gzip"
- "errors"
"io"
"sync"
- "github.com/OpenIMSDK/tools/utils"
+ "github.com/OpenIMSDK/tools/errs"
)
var (
@@ -46,12 +45,15 @@ func NewGzipCompressor() *GzipCompressor {
func (g *GzipCompressor) Compress(rawData []byte) ([]byte, error) {
gzipBuffer := bytes.Buffer{}
gz := gzip.NewWriter(&gzipBuffer)
+
if _, err := gz.Write(rawData); err != nil {
- return nil, utils.Wrap(err, "")
+ return nil, errs.Wrap(err, "GzipCompressor.Compress: writing to gzip writer failed")
}
+
if err := gz.Close(); err != nil {
- return nil, utils.Wrap(err, "")
+ return nil, errs.Wrap(err, "GzipCompressor.Compress: closing gzip writer failed")
}
+
return gzipBuffer.Bytes(), nil
}
@@ -63,10 +65,10 @@ func (g *GzipCompressor) CompressWithPool(rawData []byte) ([]byte, error) {
gz.Reset(&gzipBuffer)
if _, err := gz.Write(rawData); err != nil {
- return nil, utils.Wrap(err, "")
+ return nil, errs.Wrap(err, "GzipCompressor.CompressWithPool: error writing data")
}
if err := gz.Close(); err != nil {
- return nil, utils.Wrap(err, "")
+ return nil, errs.Wrap(err, "GzipCompressor.CompressWithPool: error closing gzip writer")
}
return gzipBuffer.Bytes(), nil
}
@@ -75,32 +77,36 @@ func (g *GzipCompressor) DeCompress(compressedData []byte) ([]byte, error) {
buff := bytes.NewBuffer(compressedData)
reader, err := gzip.NewReader(buff)
if err != nil {
- return nil, utils.Wrap(err, "NewReader failed")
+ return nil, errs.Wrap(err, "GzipCompressor.DeCompress: NewReader creation failed")
}
- compressedData, err = io.ReadAll(reader)
+ decompressedData, err := io.ReadAll(reader)
if err != nil {
- return nil, utils.Wrap(err, "ReadAll failed")
+ return nil, errs.Wrap(err, "GzipCompressor.DeCompress: reading from gzip reader failed")
}
- _ = reader.Close()
- return compressedData, nil
+ if err = reader.Close(); err != nil {
+ // Even if closing the reader fails, we've successfully read the data,
+ // so we return the decompressed data and an error indicating the close failure.
+ return decompressedData, errs.Wrap(err, "GzipCompressor.DeCompress: closing gzip reader failed")
+ }
+ return decompressedData, nil
}
func (g *GzipCompressor) DecompressWithPool(compressedData []byte) ([]byte, error) {
reader := gzipReaderPool.Get().(*gzip.Reader)
- if reader == nil {
- return nil, errors.New("NewReader failed")
- }
defer gzipReaderPool.Put(reader)
err := reader.Reset(bytes.NewReader(compressedData))
if err != nil {
- return nil, utils.Wrap(err, "NewReader failed")
+ return nil, errs.Wrap(err, "GzipCompressor.DecompressWithPool: resetting gzip reader failed")
}
- compressedData, err = io.ReadAll(reader)
+ decompressedData, err := io.ReadAll(reader)
if err != nil {
- return nil, utils.Wrap(err, "ReadAll failed")
+ return nil, errs.Wrap(err, "GzipCompressor.DecompressWithPool: reading from pooled gzip reader failed")
}
- _ = reader.Close()
- return compressedData, nil
+ if err = reader.Close(); err != nil {
+ // Similar to DeCompress, return the data and error for close failure.
+ return decompressedData, errs.Wrap(err, "GzipCompressor.DecompressWithPool: closing pooled gzip reader failed")
+ }
+ return decompressedData, nil
}
diff --git a/internal/msggateway/compressor_test.go b/internal/msggateway/compressor_test.go
index b1544f063..173c9bb20 100644
--- a/internal/msggateway/compressor_test.go
+++ b/internal/msggateway/compressor_test.go
@@ -37,10 +37,16 @@ func TestCompressDecompress(t *testing.T) {
// compress
dest, err := compressor.CompressWithPool(src)
+ if err != nil {
+ t.Log(err)
+ }
assert.Equal(t, nil, err)
// decompress
res, err := compressor.DecompressWithPool(dest)
+ if err != nil {
+ t.Log(err)
+ }
assert.Equal(t, nil, err)
// check
@@ -60,10 +66,16 @@ func TestCompressDecompressWithConcurrency(t *testing.T) {
// compress
dest, err := compressor.CompressWithPool(src)
+ if err != nil {
+ t.Log(err)
+ }
assert.Equal(t, nil, err)
// decompress
res, err := compressor.DecompressWithPool(dest)
+ if err != nil {
+ t.Log(err)
+ }
assert.Equal(t, nil, err)
// check
@@ -99,6 +111,7 @@ func BenchmarkDecompress(b *testing.B) {
compressor := NewGzipCompressor()
comdata, err := compressor.Compress(src)
+
assert.Equal(b, nil, err)
for i := 0; i < b.N; i++ {
diff --git a/internal/msggateway/encoder.go b/internal/msggateway/encoder.go
index c5f1d00a8..cd2c50d96 100644
--- a/internal/msggateway/encoder.go
+++ b/internal/msggateway/encoder.go
@@ -18,7 +18,7 @@ import (
"bytes"
"encoding/gob"
- "github.com/OpenIMSDK/tools/utils"
+ "github.com/OpenIMSDK/tools/errs"
)
type Encoder interface {
@@ -37,7 +37,7 @@ func (g *GobEncoder) Encode(data any) ([]byte, error) {
enc := gob.NewEncoder(&buff)
err := enc.Encode(data)
if err != nil {
- return nil, err
+ return nil, errs.Wrap(err, "GobEncoder.Encode failed")
}
return buff.Bytes(), nil
}
@@ -47,7 +47,7 @@ func (g *GobEncoder) Decode(encodeData []byte, decodeData any) error {
dec := gob.NewDecoder(buff)
err := dec.Decode(decodeData)
if err != nil {
- return utils.Wrap(err, "")
+ return errs.Wrap(err, "GobEncoder.Decode failed")
}
return nil
}
diff --git a/internal/msggateway/hub_server.go b/internal/msggateway/hub_server.go
index abf834225..c0d5a5999 100644
--- a/internal/msggateway/hub_server.go
+++ b/internal/msggateway/hub_server.go
@@ -17,38 +17,39 @@ package msggateway
import (
"context"
- "google.golang.org/grpc"
-
"github.com/OpenIMSDK/protocol/constant"
"github.com/OpenIMSDK/protocol/msggateway"
"github.com/OpenIMSDK/tools/discoveryregistry"
"github.com/OpenIMSDK/tools/errs"
"github.com/OpenIMSDK/tools/log"
"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/common/config"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/cache"
"github.com/openimsdk/open-im-server/v3/pkg/common/startrpc"
+ "google.golang.org/grpc"
)
-func (s *Server) InitServer(disCov discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) error {
- rdb, err := cache.NewRedis()
+func (s *Server) InitServer(config *config.GlobalConfig, disCov discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) error {
+ rdb, err := cache.NewRedis(config)
if err != nil {
return err
}
- msgModel := cache.NewMsgCacheModel(rdb)
- s.LongConnServer.SetDiscoveryRegistry(disCov)
+ msgModel := cache.NewMsgCacheModel(rdb, config)
+ s.LongConnServer.SetDiscoveryRegistry(disCov, config)
s.LongConnServer.SetCacheHandler(msgModel)
msggateway.RegisterMsgGatewayServer(server, s)
return nil
}
-func (s *Server) Start() error {
+func (s *Server) Start(conf *config.GlobalConfig) error {
return startrpc.Start(
s.rpcPort,
- config.Config.RpcRegisterName.OpenImMessageGatewayName,
+ conf.RpcRegisterName.OpenImMessageGatewayName,
s.prometheusPort,
+ conf,
s.InitServer,
)
}
@@ -57,6 +58,7 @@ type Server struct {
rpcPort int
prometheusPort int
LongConnServer LongConnServer
+ config *config.GlobalConfig
pushTerminal map[int]struct{}
}
@@ -66,10 +68,13 @@ func (s *Server) SetLongConnServer(LongConnServer LongConnServer) {
func NewServer(rpcPort int, proPort int, longConnServer LongConnServer) *Server {
s := &Server{
+func NewServer(rpcPort int, proPort int, longConnServer LongConnServer, config *config.GlobalConfig) *Server {
+ return &Server{
rpcPort: rpcPort,
prometheusPort: proPort,
LongConnServer: longConnServer,
pushTerminal: make(map[int]struct{}),
+ config: config,
}
s.pushTerminal[constant.IOSPlatformID] = struct{}{}
s.pushTerminal[constant.AndroidPlatformID] = struct{}{}
@@ -87,7 +92,7 @@ func (s *Server) GetUsersOnlineStatus(
ctx context.Context,
req *msggateway.GetUsersOnlineStatusReq,
) (*msggateway.GetUsersOnlineStatusResp, error) {
- if !authverify.IsAppManagerUid(ctx) {
+ if !authverify.IsAppManagerUid(ctx, s.config) {
return nil, errs.ErrNoPermission.Wrap("only app manager")
}
var resp msggateway.GetUsersOnlineStatusResp
diff --git a/internal/msggateway/init.go b/internal/msggateway/init.go
index aeba0a24a..4efbb7cdf 100644
--- a/internal/msggateway/init.go
+++ b/internal/msggateway/init.go
@@ -18,48 +18,29 @@ import (
"fmt"
"time"
- "github.com/OpenIMSDK/tools/utils"
- "golang.org/x/sync/errgroup"
-
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
)
// RunWsAndServer run ws server.
-func RunWsAndServer(rpcPort, wsPort, prometheusPort int) error {
- fmt.Println(
- "start rpc/msg_gateway server, port: ",
- rpcPort,
- wsPort,
- prometheusPort,
- ", OpenIM version: ",
- config.Version,
- )
+func RunWsAndServer(conf *config.GlobalConfig, rpcPort, wsPort, prometheusPort int) error {
+ fmt.Println("start rpc/msg_gateway server, port: ", rpcPort, wsPort, prometheusPort, ", OpenIM version: ", config.Version)
longServer, err := NewWsServer(
+ conf,
WithPort(wsPort),
- WithMaxConnNum(int64(config.Config.LongConnSvr.WebsocketMaxConnNum)),
- WithHandshakeTimeout(time.Duration(config.Config.LongConnSvr.WebsocketTimeout)*time.Second),
- WithMessageMaxMsgLength(config.Config.LongConnSvr.WebsocketMaxMsgLen),
- WithWriteBufferSize(config.Config.LongConnSvr.WebsocketWriteBufferSize),
+ WithMaxConnNum(int64(conf.LongConnSvr.WebsocketMaxConnNum)),
+ WithHandshakeTimeout(time.Duration(conf.LongConnSvr.WebsocketTimeout)*time.Second),
+ WithMessageMaxMsgLength(conf.LongConnSvr.WebsocketMaxMsgLen),
+ WithWriteBufferSize(conf.LongConnSvr.WebsocketWriteBufferSize),
)
if err != nil {
return err
}
- hubServer := NewServer(rpcPort, prometheusPort, longServer)
-
- wg := errgroup.Group{}
- wg.Go(func() error {
- err = hubServer.Start()
- if err != nil {
- return utils.Wrap1(err)
- }
- return err
- })
-
- wg.Go(func() error {
- return hubServer.LongConnServer.Run()
- })
-
- err = wg.Wait()
- return err
+ hubServer := NewServer(rpcPort, prometheusPort, longServer, conf)
+ netDone := make(chan error)
+ go func() {
+ err = hubServer.Start(conf)
+ netDone <- err
+ }()
+ return hubServer.LongConnServer.Run(netDone)
}
diff --git a/internal/msggateway/long_conn.go b/internal/msggateway/long_conn.go
index 93e5cc33f..7dc79c834 100644
--- a/internal/msggateway/long_conn.go
+++ b/internal/msggateway/long_conn.go
@@ -15,9 +15,11 @@
package msggateway
import (
+ "errors"
"net/http"
"time"
+ "github.com/OpenIMSDK/tools/errs"
"github.com/gorilla/websocket"
)
@@ -72,7 +74,8 @@ func (d *GWebSocket) GenerateLongConn(w http.ResponseWriter, r *http.Request) er
conn, err := upgrader.Upgrade(w, r, nil)
if err != nil {
- return err
+ // The upgrader.Upgrade method usually returns enough error messages to diagnose problems that may occur during the upgrade
+ return errs.Wrap(err, "GenerateLongConn: WebSocket upgrade failed")
}
d.conn = conn
return nil
@@ -96,7 +99,16 @@ func (d *GWebSocket) SetReadDeadline(timeout time.Duration) error {
}
func (d *GWebSocket) SetWriteDeadline(timeout time.Duration) error {
- return d.conn.SetWriteDeadline(time.Now().Add(timeout))
+ // TODO add error
+ if timeout <= 0 {
+ return errs.Wrap(errors.New("timeout must be greater than 0"))
+ }
+
+ // TODO SetWriteDeadline Future add error handling
+ if err := d.conn.SetWriteDeadline(time.Now().Add(timeout)); err != nil {
+ return errs.Wrap(err, "GWebSocket.SetWriteDeadline failed")
+ }
+ return nil
}
func (d *GWebSocket) Dial(urlStr string, requestHeader http.Header) (*http.Response, error) {
@@ -108,10 +120,12 @@ func (d *GWebSocket) Dial(urlStr string, requestHeader http.Header) (*http.Respo
}
func (d *GWebSocket) IsNil() bool {
- if d.conn != nil {
- return false
- }
- return true
+ return d.conn == nil
+ //
+ // if d.conn != nil {
+ // return false
+ // }
+ // return true
}
func (d *GWebSocket) SetConnNil() {
diff --git a/internal/msggateway/message_handler.go b/internal/msggateway/message_handler.go
index dd5e00f18..2fbdd5683 100644
--- a/internal/msggateway/message_handler.go
+++ b/internal/msggateway/message_handler.go
@@ -18,17 +18,16 @@ import (
"context"
"sync"
- "github.com/OpenIMSDK/protocol/push"
- "github.com/OpenIMSDK/tools/discoveryregistry"
-
- "github.com/go-playground/validator/v10"
- "google.golang.org/protobuf/proto"
-
"github.com/OpenIMSDK/protocol/msg"
+ "github.com/OpenIMSDK/protocol/push"
"github.com/OpenIMSDK/protocol/sdkws"
+ "github.com/OpenIMSDK/tools/discoveryregistry"
+ "github.com/OpenIMSDK/tools/errs"
"github.com/OpenIMSDK/tools/utils"
-
+ "github.com/go-playground/validator/v10"
+ "github.com/openimsdk/open-im-server/v3/pkg/common/config"
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
+ "google.golang.org/protobuf/proto"
)
type Req struct {
@@ -107,9 +106,9 @@ type GrpcHandler struct {
validate *validator.Validate
}
-func NewGrpcHandler(validate *validator.Validate, client discoveryregistry.SvcDiscoveryRegistry) *GrpcHandler {
- msgRpcClient := rpcclient.NewMessageRpcClient(client)
- pushRpcClient := rpcclient.NewPushRpcClient(client)
+func NewGrpcHandler(validate *validator.Validate, client discoveryregistry.SvcDiscoveryRegistry, config *config.GlobalConfig) *GrpcHandler {
+ msgRpcClient := rpcclient.NewMessageRpcClient(client, config)
+ pushRpcClient := rpcclient.NewPushRpcClient(client, config)
return &GrpcHandler{
msgRpcClient: &msgRpcClient,
pushClient: &pushRpcClient, validate: validate,
@@ -119,10 +118,10 @@ func NewGrpcHandler(validate *validator.Validate, client discoveryregistry.SvcDi
func (g GrpcHandler) GetSeq(context context.Context, data *Req) ([]byte, error) {
req := sdkws.GetMaxSeqReq{}
if err := proto.Unmarshal(data.Data, &req); err != nil {
- return nil, err
+ return nil, errs.Wrap(err, "GetSeq: error unmarshaling request")
}
if err := g.validate.Struct(&req); err != nil {
- return nil, err
+ return nil, errs.Wrap(err, "GetSeq: validation failed")
}
resp, err := g.msgRpcClient.GetMaxSeq(context, &req)
if err != nil {
@@ -130,28 +129,37 @@ func (g GrpcHandler) GetSeq(context context.Context, data *Req) ([]byte, error)
}
c, err := proto.Marshal(resp)
if err != nil {
- return nil, err
+ return nil, errs.Wrap(err, "GetSeq: error marshaling response")
}
return c, nil
}
-func (g GrpcHandler) SendMessage(context context.Context, data *Req) ([]byte, error) {
- msgData := sdkws.MsgData{}
+// SendMessage handles the sending of messages through gRPC. It unmarshals the request data,
+// validates the message, and then sends it using the message RPC client.
+func (g GrpcHandler) SendMessage(ctx context.Context, data *Req) ([]byte, error) {
+ // Unmarshal the message data from the request.
+ var msgData sdkws.MsgData
if err := proto.Unmarshal(data.Data, &msgData); err != nil {
- return nil, err
+ return nil, errs.Wrap(err, "error unmarshalling message data")
}
+
+ // Validate the message data structure.
if err := g.validate.Struct(&msgData); err != nil {
- return nil, err
+ return nil, errs.Wrap(err, "message data validation failed")
}
+
req := msg.SendMsgReq{MsgData: &msgData}
- resp, err := g.msgRpcClient.SendMsg(context, &req)
+
+ resp, err := g.msgRpcClient.SendMsg(ctx, &req)
if err != nil {
return nil, err
}
+
c, err := proto.Marshal(resp)
if err != nil {
- return nil, err
+ return nil, errs.Wrap(err, "error marshaling response")
}
+
return c, nil
}
@@ -162,7 +170,7 @@ func (g GrpcHandler) SendSignalMessage(context context.Context, data *Req) ([]by
}
c, err := proto.Marshal(resp)
if err != nil {
- return nil, err
+ return nil, errs.Wrap(err, "error marshaling response")
}
return c, nil
}
@@ -170,10 +178,10 @@ func (g GrpcHandler) SendSignalMessage(context context.Context, data *Req) ([]by
func (g GrpcHandler) PullMessageBySeqList(context context.Context, data *Req) ([]byte, error) {
req := sdkws.PullMessageBySeqsReq{}
if err := proto.Unmarshal(data.Data, &req); err != nil {
- return nil, err
+ return nil, errs.Wrap(err, "error unmarshaling request")
}
if err := g.validate.Struct(data); err != nil {
- return nil, err
+ return nil, errs.Wrap(err, "validation failed")
}
resp, err := g.msgRpcClient.PullMessageBySeqList(context, &req)
if err != nil {
@@ -181,7 +189,7 @@ func (g GrpcHandler) PullMessageBySeqList(context context.Context, data *Req) ([
}
c, err := proto.Marshal(resp)
if err != nil {
- return nil, err
+ return nil, errs.Wrap(err, "error marshaling response")
}
return c, nil
}
@@ -189,7 +197,7 @@ func (g GrpcHandler) PullMessageBySeqList(context context.Context, data *Req) ([
func (g GrpcHandler) UserLogout(context context.Context, data *Req) ([]byte, error) {
req := push.DelUserPushTokenReq{}
if err := proto.Unmarshal(data.Data, &req); err != nil {
- return nil, err
+ return nil, errs.Wrap(err, "error unmarshaling request")
}
resp, err := g.pushClient.DelUserPushToken(context, &req)
if err != nil {
@@ -197,7 +205,7 @@ func (g GrpcHandler) UserLogout(context context.Context, data *Req) ([]byte, err
}
c, err := proto.Marshal(resp)
if err != nil {
- return nil, err
+ return nil, errs.Wrap(err, "error marshaling response")
}
return c, nil
}
@@ -205,10 +213,10 @@ func (g GrpcHandler) UserLogout(context context.Context, data *Req) ([]byte, err
func (g GrpcHandler) SetUserDeviceBackground(_ context.Context, data *Req) ([]byte, bool, error) {
req := sdkws.SetAppBackgroundStatusReq{}
if err := proto.Unmarshal(data.Data, &req); err != nil {
- return nil, false, err
+ return nil, false, errs.Wrap(err, "error unmarshaling request")
}
if err := g.validate.Struct(data); err != nil {
- return nil, false, err
+ return nil, false, errs.Wrap(err, "validation failed")
}
return nil, req.IsBackground, nil
}
diff --git a/internal/msggateway/n_ws_server.go b/internal/msggateway/n_ws_server.go
index 01d92b92a..f5838c703 100644
--- a/internal/msggateway/n_ws_server.go
+++ b/internal/msggateway/n_ws_server.go
@@ -20,42 +20,36 @@ import (
"errors"
"fmt"
"net/http"
- "os"
- "os/signal"
"strconv"
"sync"
"sync/atomic"
- "syscall"
"time"
- "github.com/OpenIMSDK/tools/apiresp"
-
- "github.com/go-playground/validator/v10"
- "github.com/redis/go-redis/v9"
- "golang.org/x/sync/errgroup"
-
"github.com/OpenIMSDK/protocol/constant"
"github.com/OpenIMSDK/protocol/msggateway"
+ "github.com/OpenIMSDK/tools/apiresp"
"github.com/OpenIMSDK/tools/discoveryregistry"
"github.com/OpenIMSDK/tools/errs"
"github.com/OpenIMSDK/tools/log"
"github.com/OpenIMSDK/tools/utils"
-
+ "github.com/go-playground/validator/v10"
"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/db/cache"
"github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics"
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
+ "github.com/redis/go-redis/v9"
+ "golang.org/x/sync/errgroup"
)
type LongConnServer interface {
- Run() error
+ Run(done chan error) error
wsHandler(w http.ResponseWriter, r *http.Request)
GetUserAllCons(userID string) ([]*Client, bool)
GetUserPlatformCons(userID string, platform int) ([]*Client, bool, bool)
Validate(s any) error
SetCacheHandler(cache cache.MsgModel)
- SetDiscoveryRegistry(client discoveryregistry.SvcDiscoveryRegistry)
+ SetDiscoveryRegistry(client discoveryregistry.SvcDiscoveryRegistry, config *config.GlobalConfig)
KickUserConn(client *Client) error
UnRegister(c *Client)
SetKickHandlerInfo(i *kickHandler)
@@ -64,13 +58,15 @@ type LongConnServer interface {
MessageHandler
}
-var bufferPool = sync.Pool{
- New: func() any {
- return make([]byte, 1024)
- },
-}
+// bufferPool is unused
+// var bufferPool = sync.Pool{
+// New: func() any {
+// return make([]byte, 1024)
+// },
+// }
type WsServer struct {
+ globalConfig *config.GlobalConfig
port int
wsMaxConnNum int64
registerChan chan *Client
@@ -90,15 +86,16 @@ type WsServer struct {
Encoder
MessageHandler
}
+
type kickHandler struct {
clientOK bool
oldClients []*Client
newClient *Client
}
-func (ws *WsServer) SetDiscoveryRegistry(disCov discoveryregistry.SvcDiscoveryRegistry) {
- ws.MessageHandler = NewGrpcHandler(ws.validate, disCov)
- u := rpcclient.NewUserRpcClient(disCov)
+func (ws *WsServer) SetDiscoveryRegistry(disCov discoveryregistry.SvcDiscoveryRegistry, config *config.GlobalConfig) {
+ ws.MessageHandler = NewGrpcHandler(ws.validate, disCov, config)
+ u := rpcclient.NewUserRpcClient(disCov, config)
ws.userClient = &u
ws.disCov = disCov
}
@@ -110,12 +107,12 @@ func (ws *WsServer) SetUserOnlineStatus(ctx context.Context, client *Client, sta
}
switch status {
case constant.Online:
- err := CallbackUserOnline(ctx, client.UserID, client.PlatformID, client.IsBackground, client.ctx.GetConnID())
+ err := CallbackUserOnline(ctx, ws.globalConfig, client.UserID, client.PlatformID, client.IsBackground, client.ctx.GetConnID())
if err != nil {
log.ZWarn(ctx, "CallbackUserOnline err", err)
}
case constant.Offline:
- err := CallbackUserOffline(ctx, client.UserID, client.PlatformID, client.ctx.GetConnID())
+ err := CallbackUserOffline(ctx, ws.globalConfig, client.UserID, client.PlatformID, client.ctx.GetConnID())
if err != nil {
log.ZWarn(ctx, "CallbackUserOffline err", err)
}
@@ -131,7 +128,9 @@ func (ws *WsServer) UnRegister(c *Client) {
}
func (ws *WsServer) Validate(s any) error {
- //?question?
+ if s == nil {
+ return errs.Wrap(errors.New("input cannot be nil"))
+ }
return nil
}
@@ -143,13 +142,14 @@ func (ws *WsServer) GetUserPlatformCons(userID string, platform int) ([]*Client,
return ws.clients.Get(userID, platform)
}
-func NewWsServer(opts ...Option) (*WsServer, error) {
+func NewWsServer(globalConfig *config.GlobalConfig, opts ...Option) (*WsServer, error) {
var config configs
for _, o := range opts {
o(&config)
}
v := validator.New()
return &WsServer{
+ globalConfig: globalConfig,
port: config.port,
wsMaxConnNum: config.maxConnNum,
writeBufferSize: config.writeBufferSize,
@@ -169,23 +169,20 @@ func NewWsServer(opts ...Option) (*WsServer, error) {
}, nil
}
-func (ws *WsServer) Run() error {
+func (ws *WsServer) Run(done chan error) error {
var (
- client *Client
- wg errgroup.Group
-
- sigs = make(chan os.Signal, 1)
- done = make(chan struct{}, 1)
+ client *Client
+ netErr error
+ shutdownDone = make(chan struct{}, 1)
)
server := http.Server{Addr: ":" + utils.IntToString(ws.port), Handler: nil}
- wg.Go(func() error {
+ go func() {
for {
select {
- case <-done:
- return nil
-
+ case <-shutdownDone:
+ return
case client = <-ws.registerChan:
ws.registerClient(client)
case client = <-ws.unregisterChan:
@@ -194,40 +191,39 @@ func (ws *WsServer) Run() error {
ws.multiTerminalLoginChecker(onlineInfo.clientOK, onlineInfo.oldClients, onlineInfo.newClient)
}
}
- })
-
- wg.Go(func() error {
- http.HandleFunc("/", ws.wsHandler)
- return server.ListenAndServe()
- })
-
- signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)
- <-sigs
-
- go func() {
- ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
- defer cancel()
-
- // graceful exit operation for server
- _ = server.Shutdown(ctx)
- _ = wg.Wait()
- close(done)
}()
-
+ netDone := make(chan struct{}, 1)
+ go func() {
+ http.HandleFunc("/", ws.wsHandler)
+ err := server.ListenAndServe()
+ if err != nil && err != http.ErrServerClosed {
+ netErr = errs.Wrap(err, "ws start err", server.Addr)
+ close(netDone)
+ }
+ }()
+ ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
+ defer cancel()
+ var err error
select {
- case <-done:
- return nil
-
- case <-time.After(15 * time.Second):
- return utils.Wrap1(errors.New("timeout exit"))
+ case err = <-done:
+ sErr := server.Shutdown(ctx)
+ if sErr != nil {
+ return errs.Wrap(sErr, "shutdown err")
+ }
+ close(shutdownDone)
+ if err != nil {
+ return err
+ }
+ case <-netDone:
}
+ return netErr
}
var concurrentRequest = 3
func (ws *WsServer) sendUserOnlineInfoToOtherNode(ctx context.Context, client *Client) error {
- conns, err := ws.disCov.GetConns(ctx, config.Config.RpcRegisterName.OpenImMessageGatewayName)
+ conns, err := ws.disCov.GetConns(ctx, ws.globalConfig.RpcRegisterName.OpenImMessageGatewayName)
if err != nil {
return err
}
@@ -282,7 +278,7 @@ func (ws *WsServer) registerClient(client *Client) {
log.ZDebug(client.ctx, "user exist", "userID", client.UserID, "platformID", client.PlatformID)
if clientOK {
ws.clients.Set(client.UserID, client)
- // 已经有同平台的连接存在
+ // There is already a connection to the platform
log.ZInfo(client.ctx, "repeat login", "userID", client.UserID, "platformID", client.PlatformID, "old remote addr", getRemoteAdders(oldClients))
ws.onlineUserConnNum.Add(1)
} else {
@@ -292,7 +288,7 @@ func (ws *WsServer) registerClient(client *Client) {
}
wg := sync.WaitGroup{}
- if config.Config.Envs.Discovery == "zookeeper" {
+ if ws.globalConfig.Envs.Discovery == "zookeeper" {
wg.Add(1)
go func() {
defer wg.Done()
@@ -335,7 +331,7 @@ func (ws *WsServer) KickUserConn(client *Client) error {
}
func (ws *WsServer) multiTerminalLoginChecker(clientOK bool, oldClients []*Client, newClient *Client) {
- switch config.Config.MultiLoginPolicy {
+ switch ws.globalConfig.MultiLoginPolicy {
case constant.DefalutNotKick:
case constant.PCAndOther:
if constant.PlatformIDToClass(newClient.PlatformID) == constant.TerminalPC {
@@ -447,7 +443,7 @@ func (ws *WsServer) ParseWSArgs(r *http.Request) (args *WSArgs, err error) {
return nil, errs.ErrConnArgsErr.Wrap("platformID is not int")
}
v.PlatformID = platformID
- if err = authverify.WsVerifyToken(v.Token, v.UserID, platformID); err != nil {
+ if err = authverify.WsVerifyToken(v.Token, v.UserID, ws.globalConfig.Secret, platformID); err != nil {
return nil, err
}
if query.Get(Compression) == GzipCompressionProtocol {
diff --git a/internal/msggateway/options.go b/internal/msggateway/options.go
index 6513ac5dc..b65f8e36c 100644
--- a/internal/msggateway/options.go
+++ b/internal/msggateway/options.go
@@ -19,15 +19,15 @@ import "time"
type (
Option func(opt *configs)
configs struct {
- // 长连接监听端口
+ // Long connection listening port
port int
- // 长连接允许最大链接数
+ // Maximum number of connections allowed for long connection
maxConnNum int64
- // 连接握手超时时间
+ // Connection handshake timeout
handshakeTimeout time.Duration
- // 允许消息最大长度
+ // Maximum length allowed for messages
messageMaxMsgLength int
- // websocket write buffer, default: 4096, 4kb.
+ // Websocket write buffer, default: 4096, 4kb.
writeBufferSize int
}
)
diff --git a/internal/msggateway/user_map.go b/internal/msggateway/user_map.go
index 052d7de2d..b4cec59fa 100644
--- a/internal/msggateway/user_map.go
+++ b/internal/msggateway/user_map.go
@@ -58,12 +58,12 @@ func (u *UserMap) Get(key string, platformID int) ([]*Client, bool, bool) {
func (u *UserMap) Set(key string, v *Client) {
allClients, existed := u.m.Load(key)
if existed {
- log.ZDebug(context.Background(), "Set existed", "user_id", key, "client", *v)
+ log.ZDebug(context.Background(), "Set existed", "user_id", key, "client_user_id", v.UserID)
oldClients := allClients.([]*Client)
oldClients = append(oldClients, v)
u.m.Store(key, oldClients)
} else {
- log.ZDebug(context.Background(), "Set not existed", "user_id", key, "client", *v)
+ log.ZDebug(context.Background(), "Set not existed", "user_id", key, "client_user_id", v.UserID)
var clients []*Client
clients = append(clients, v)
u.m.Store(key, clients)
diff --git a/internal/msgtransfer/init.go b/internal/msgtransfer/init.go
index 7d692662d..ee62db9c1 100644
--- a/internal/msgtransfer/init.go
+++ b/internal/msgtransfer/init.go
@@ -15,19 +15,16 @@
package msgtransfer
import (
+ "context"
"errors"
"fmt"
- "log"
"net/http"
- "sync"
+ "os"
+ "os/signal"
+ "syscall"
+ "github.com/OpenIMSDK/tools/errs"
"github.com/OpenIMSDK/tools/mw"
- "github.com/prometheus/client_golang/prometheus"
- "github.com/prometheus/client_golang/prometheus/collectors"
- "github.com/prometheus/client_golang/prometheus/promhttp"
- "google.golang.org/grpc"
- "google.golang.org/grpc/credentials/insecure"
-
"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"
@@ -35,84 +32,134 @@ import (
kdisc "github.com/openimsdk/open-im-server/v3/pkg/common/discoveryregister"
"github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics"
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
+ util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil"
+ "github.com/prometheus/client_golang/prometheus"
+ "github.com/prometheus/client_golang/prometheus/collectors"
+ "github.com/prometheus/client_golang/prometheus/promhttp"
+ "google.golang.org/grpc"
+ "google.golang.org/grpc/credentials/insecure"
)
type MsgTransfer struct {
- historyCH *OnlineHistoryRedisConsumerHandler // 这个消费者聚合消息, 订阅的topic:ws2ms_chat, 修改通知发往msg_to_modify topic, 消息存入redis后Incr Redis, 再发消息到ms2pschat topic推送, 发消息到msg_to_mongo topic持久化
- historyMongoCH *OnlineHistoryMongoConsumerHandler // mongoDB批量插入, 成功后删除redis中消息,以及处理删除通知消息删除的 订阅的topic: msg_to_mongo
- // modifyCH *ModifyMsgConsumerHandler // 负责消费修改消息通知的consumer, 订阅的topic: msg_to_modify
+ // This consumer aggregated messages, subscribed to the topic:ws2ms_chat,
+ // the modification notification is sent to msg_to_modify topic, the message is stored in redis, Incr Redis,
+ // and then the message is sent to ms2pschat topic for push, and the message is sent to msg_to_mongo topic for persistence
+ historyCH *OnlineHistoryRedisConsumerHandler
+ historyMongoCH *OnlineHistoryMongoConsumerHandler
+ // mongoDB batch insert, delete messages in redis after success,
+ // and handle the deletion notification message deleted subscriptions topic: msg_to_mongo
+ ctx context.Context
+ cancel context.CancelFunc
+ config *config.GlobalConfig
}
-func StartTransfer(prometheusPort int) error {
- rdb, err := cache.NewRedis()
+func StartTransfer(config *config.GlobalConfig, prometheusPort int) error {
+ rdb, err := cache.NewRedis(config)
if err != nil {
return err
}
- mongo, err := unrelation.NewMongo()
+
+ mongo, err := unrelation.NewMongo(config)
if err != nil {
return err
}
- if err := mongo.CreateMsgIndex(); err != nil {
+
+ if err = mongo.CreateMsgIndex(); err != nil {
return err
}
- client, err := kdisc.NewDiscoveryRegister(config.Config.Envs.Discovery)
- /*
- client, err := openkeeper.NewClient(config.Config.Zookeeper.ZkAddr, config.Config.Zookeeper.Schema,
- openkeeper.WithFreq(time.Hour), openkeeper.WithRoundRobin(), openkeeper.WithUserNameAndPassword(config.Config.Zookeeper.Username,
- config.Config.Zookeeper.Password), openkeeper.WithTimeout(10), openkeeper.WithLogger(log.NewZkLogger()))*/
+ client, err := kdisc.NewDiscoveryRegister(config)
if err != nil {
return err
}
- if err := client.CreateRpcRootNodes(config.Config.GetServiceNames()); err != nil {
+
+ if err := client.CreateRpcRootNodes(config.GetServiceNames()); err != nil {
return err
}
+
client.AddOption(mw.GrpcClient(), grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithDefaultServiceConfig(fmt.Sprintf(`{"LoadBalancingPolicy": "%s"}`, "round_robin")))
- msgModel := cache.NewMsgCacheModel(rdb)
- msgDocModel := unrelation.NewMsgMongoDriver(mongo.GetDatabase())
- msgDatabase := controller.NewCommonMsgDatabase(msgDocModel, msgModel)
- conversationRpcClient := rpcclient.NewConversationRpcClient(client)
- groupRpcClient := rpcclient.NewGroupRpcClient(client)
- msgTransfer := NewMsgTransfer(msgDatabase, &conversationRpcClient, &groupRpcClient)
- return msgTransfer.Start(prometheusPort)
-}
-
-func NewMsgTransfer(msgDatabase controller.CommonMsgDatabase, conversationRpcClient *rpcclient.ConversationRpcClient, groupRpcClient *rpcclient.GroupRpcClient) *MsgTransfer {
- return &MsgTransfer{
- historyCH: NewOnlineHistoryRedisConsumerHandler(msgDatabase, conversationRpcClient, groupRpcClient),
- historyMongoCH: NewOnlineHistoryMongoConsumerHandler(msgDatabase),
+ msgModel := cache.NewMsgCacheModel(rdb, config)
+ msgDocModel := unrelation.NewMsgMongoDriver(mongo.GetDatabase(config.Mongo.Database))
+ msgDatabase, err := controller.NewCommonMsgDatabase(msgDocModel, msgModel, config)
+ if err != nil {
+ return err
}
+ conversationRpcClient := rpcclient.NewConversationRpcClient(client, config)
+ groupRpcClient := rpcclient.NewGroupRpcClient(client, config)
+ msgTransfer, err := NewMsgTransfer(config, msgDatabase, &conversationRpcClient, &groupRpcClient)
+ if err != nil {
+ return err
+ }
+ return msgTransfer.Start(prometheusPort, config)
}
-func (m *MsgTransfer) Start(prometheusPort int) error {
- var wg sync.WaitGroup
- wg.Add(1)
+func NewMsgTransfer(
+ config *config.GlobalConfig,
+ msgDatabase controller.CommonMsgDatabase,
+ conversationRpcClient *rpcclient.ConversationRpcClient,
+ groupRpcClient *rpcclient.GroupRpcClient,
+) (*MsgTransfer, error) {
+ historyCH, err := NewOnlineHistoryRedisConsumerHandler(config, msgDatabase, conversationRpcClient, groupRpcClient)
+ if err != nil {
+ return nil, err
+ }
+ historyMongoCH, err := NewOnlineHistoryMongoConsumerHandler(config, msgDatabase)
+ if err != nil {
+ return nil, err
+ }
+
+ return &MsgTransfer{
+ historyCH: historyCH,
+ historyMongoCH: historyMongoCH,
+ config: config,
+ }, nil
+}
+
+func (m *MsgTransfer) Start(prometheusPort int, config *config.GlobalConfig) error {
fmt.Println("start msg transfer", "prometheusPort:", prometheusPort)
if prometheusPort <= 0 {
- return errors.New("prometheusPort not correct")
+ return errs.Wrap(errors.New("prometheusPort not correct"))
}
- if config.Config.ChatPersistenceMysql {
- // go m.persistentCH.persistentConsumerGroup.RegisterHandleAndConsumer(m.persistentCH)
- } else {
- fmt.Println("msg transfer not start mysql consumer")
+ m.ctx, m.cancel = context.WithCancel(context.Background())
+
+ var (
+ netDone = make(chan struct{}, 1)
+ netErr error
+ )
+
+ go m.historyCH.historyConsumerGroup.RegisterHandleAndConsumer(m.ctx, m.historyCH)
+ go m.historyMongoCH.historyConsumerGroup.RegisterHandleAndConsumer(m.ctx, m.historyMongoCH)
+
+ if config.Prometheus.Enable {
+ go func() {
+ proreg := prometheus.NewRegistry()
+ proreg.MustRegister(
+ collectors.NewGoCollector(),
+ )
+ proreg.MustRegister(prommetrics.GetGrpcCusMetrics("Transfer", config)...)
+ http.Handle("/metrics", promhttp.HandlerFor(proreg, promhttp.HandlerOpts{Registry: proreg}))
+ err := http.ListenAndServe(fmt.Sprintf(":%d", prometheusPort), nil)
+ if err != nil && err != http.ErrServerClosed {
+ netErr = errs.Wrap(err, fmt.Sprintf("prometheus start err: %d", prometheusPort))
+ netDone <- struct{}{}
+ }
+ }()
}
- 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 {
- reg := prometheus.NewRegistry()
- reg.MustRegister(
- collectors.NewGoCollector(),
- )
- reg.MustRegister(prommetrics.GetGrpcCusMetrics("Transfer")...)
- http.Handle("/metrics", promhttp.HandlerFor(reg, promhttp.HandlerOpts{Registry: reg}))
- log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", prometheusPort), nil))
+
+ sigs := make(chan os.Signal, 1)
+ signal.Notify(sigs, syscall.SIGTERM)
+ select {
+ case <-sigs:
+ util.SIGTERMExit()
+ // graceful close kafka client.
+ m.cancel()
+ m.historyCH.historyConsumerGroup.Close()
+ m.historyMongoCH.historyConsumerGroup.Close()
+ return nil
+ case <-netDone:
+ m.cancel()
+ m.historyCH.historyConsumerGroup.Close()
+ m.historyMongoCH.historyConsumerGroup.Close()
+ close(netDone)
+ return netErr
}
- ////////////////////////////////////////
- wg.Wait()
- return nil
}
diff --git a/internal/msgtransfer/online_history_msg_handler.go b/internal/msgtransfer/online_history_msg_handler.go
index 127cede71..b81bd12b8 100644
--- a/internal/msgtransfer/online_history_msg_handler.go
+++ b/internal/msgtransfer/online_history_msg_handler.go
@@ -19,26 +19,23 @@ import (
"strconv"
"strings"
"sync"
+ "sync/atomic"
"time"
- "github.com/openimsdk/open-im-server/v3/pkg/msgprocessor"
-
- "github.com/OpenIMSDK/tools/errs"
-
"github.com/IBM/sarama"
- "github.com/go-redis/redis"
- "google.golang.org/protobuf/proto"
-
"github.com/OpenIMSDK/protocol/constant"
"github.com/OpenIMSDK/protocol/sdkws"
+ "github.com/OpenIMSDK/tools/errs"
"github.com/OpenIMSDK/tools/log"
"github.com/OpenIMSDK/tools/mcontext"
"github.com/OpenIMSDK/tools/utils"
-
+ "github.com/go-redis/redis"
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/controller"
"github.com/openimsdk/open-im-server/v3/pkg/common/kafka"
+ "github.com/openimsdk/open-im-server/v3/pkg/msgprocessor"
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
+ "google.golang.org/protobuf/proto"
)
const (
@@ -73,10 +70,10 @@ type OnlineHistoryRedisConsumerHandler struct {
chArrays [ChannelNum]chan Cmd2Value
msgDistributionCh chan Cmd2Value
- singleMsgSuccessCount uint64
- singleMsgFailedCount uint64
- singleMsgSuccessCountMutex sync.Mutex
- singleMsgFailedCountMutex sync.Mutex
+ // singleMsgSuccessCount uint64
+ // singleMsgFailedCount uint64
+ // singleMsgSuccessCountMutex sync.Mutex
+ // singleMsgFailedCountMutex sync.Mutex
msgDatabase controller.CommonMsgDatabase
conversationRpcClient *rpcclient.ConversationRpcClient
@@ -84,10 +81,11 @@ type OnlineHistoryRedisConsumerHandler struct {
}
func NewOnlineHistoryRedisConsumerHandler(
+ config *config.GlobalConfig,
database controller.CommonMsgDatabase,
conversationRpcClient *rpcclient.ConversationRpcClient,
groupRpcClient *rpcclient.GroupRpcClient,
-) *OnlineHistoryRedisConsumerHandler {
+) (*OnlineHistoryRedisConsumerHandler, error) {
var och OnlineHistoryRedisConsumerHandler
och.msgDatabase = database
och.msgDistributionCh = make(chan Cmd2Value) // no buffer channel
@@ -98,79 +96,87 @@ func NewOnlineHistoryRedisConsumerHandler(
}
och.conversationRpcClient = conversationRpcClient
och.groupRpcClient = groupRpcClient
- och.historyConsumerGroup = kafka.NewMConsumerGroup(&kafka.MConsumerGroupConfig{
+ var err error
+
+ var tlsConfig *kafka.TLSConfig
+ if config.Kafka.TLS != nil {
+ tlsConfig = &kafka.TLSConfig{
+ CACrt: config.Kafka.TLS.CACrt,
+ ClientCrt: config.Kafka.TLS.ClientCrt,
+ ClientKey: config.Kafka.TLS.ClientKey,
+ ClientKeyPwd: config.Kafka.TLS.ClientKeyPwd,
+ InsecureSkipVerify: false,
+ }
+ }
+
+ och.historyConsumerGroup, err = kafka.NewMConsumerGroup(&kafka.MConsumerGroupConfig{
KafkaVersion: sarama.V2_0_0_0,
- OffsetsInitial: sarama.OffsetNewest, IsReturnErr: false,
- }, []string{config.Config.Kafka.LatestMsgToRedis.Topic},
- config.Config.Kafka.Addr, config.Config.Kafka.ConsumerGroupID.MsgToRedis)
+ OffsetsInitial: sarama.OffsetNewest,
+ IsReturnErr: false,
+ UserName: config.Kafka.Username,
+ Password: config.Kafka.Password,
+ }, []string{config.Kafka.LatestMsgToRedis.Topic},
+ config.Kafka.Addr,
+ config.Kafka.ConsumerGroupID.MsgToRedis,
+ tlsConfig,
+ )
// statistics.NewStatistics(&och.singleMsgSuccessCount, config.Config.ModuleName.MsgTransferName, fmt.Sprintf("%d
// second singleMsgCount insert to mongo", constant.StatisticsTimeInterval), constant.StatisticsTimeInterval)
- return &och
+ return &och, err
}
func (och *OnlineHistoryRedisConsumerHandler) Run(channelID int) {
- for {
- select {
- case cmd := <-och.chArrays[channelID]:
- switch cmd.Cmd {
- case SourceMessages:
- msgChannelValue := cmd.Value.(MsgChannelValue)
- ctxMsgList := msgChannelValue.ctxMsgList
- ctx := msgChannelValue.ctx
- log.ZDebug(
- ctx,
- "msg arrived channel",
- "channel id",
- channelID,
- "msgList length",
- len(ctxMsgList),
- "uniqueKey",
- msgChannelValue.uniqueKey,
- )
- storageMsgList, notStorageMsgList, storageNotificationList, notStorageNotificationList, modifyMsgList := och.getPushStorageMsgList(
- ctxMsgList,
- )
- log.ZDebug(
- ctx,
- "msg lens",
- "storageMsgList",
- len(storageMsgList),
- "notStorageMsgList",
- len(notStorageMsgList),
- "storageNotificationList",
- len(storageNotificationList),
- "notStorageNotificationList",
- len(notStorageNotificationList),
- "modifyMsgList",
- len(modifyMsgList),
- )
- conversationIDMsg := msgprocessor.GetChatConversationIDByMsg(ctxMsgList[0].message)
- conversationIDNotification := msgprocessor.GetNotificationConversationIDByMsg(ctxMsgList[0].message)
- och.handleMsg(ctx, msgChannelValue.uniqueKey, conversationIDMsg, storageMsgList, notStorageMsgList)
- och.handleNotification(
- ctx,
- msgChannelValue.uniqueKey,
- conversationIDNotification,
- storageNotificationList,
- notStorageNotificationList,
- )
- if err := och.msgDatabase.MsgToModifyMQ(ctx, msgChannelValue.uniqueKey, conversationIDNotification, modifyMsgList); err != nil {
- log.ZError(
- ctx,
- "msg to modify mq error",
- err,
- "uniqueKey",
- msgChannelValue.uniqueKey,
- "modifyMsgList",
- modifyMsgList,
- )
- }
+ for cmd := range och.chArrays[channelID] {
+ switch cmd.Cmd {
+ case SourceMessages:
+ msgChannelValue := cmd.Value.(MsgChannelValue)
+ ctxMsgList := msgChannelValue.ctxMsgList
+ ctx := msgChannelValue.ctx
+ log.ZDebug(
+ ctx,
+ "msg arrived channel",
+ "channel id",
+ channelID,
+ "msgList length",
+ len(ctxMsgList),
+ "uniqueKey",
+ msgChannelValue.uniqueKey,
+ )
+ storageMsgList, notStorageMsgList, storageNotificationList, notStorageNotificationList, modifyMsgList := och.getPushStorageMsgList(
+ ctxMsgList,
+ )
+ log.ZDebug(
+ ctx,
+ "msg lens",
+ "storageMsgList",
+ len(storageMsgList),
+ "notStorageMsgList",
+ len(notStorageMsgList),
+ "storageNotificationList",
+ len(storageNotificationList),
+ "notStorageNotificationList",
+ len(notStorageNotificationList),
+ "modifyMsgList",
+ len(modifyMsgList),
+ )
+ conversationIDMsg := msgprocessor.GetChatConversationIDByMsg(ctxMsgList[0].message)
+ conversationIDNotification := msgprocessor.GetNotificationConversationIDByMsg(ctxMsgList[0].message)
+ och.handleMsg(ctx, msgChannelValue.uniqueKey, conversationIDMsg, storageMsgList, notStorageMsgList)
+ och.handleNotification(
+ ctx,
+ msgChannelValue.uniqueKey,
+ conversationIDNotification,
+ storageNotificationList,
+ notStorageNotificationList,
+ )
+ if err := och.msgDatabase.MsgToModifyMQ(ctx, msgChannelValue.uniqueKey, conversationIDNotification, modifyMsgList); err != nil {
+ log.ZError(ctx, "msg to modify mq error", err, "uniqueKey", msgChannelValue.uniqueKey, "modifyMsgList", modifyMsgList)
}
}
}
}
-// 获取消息/通知 存储的消息列表, 不存储并且推送的消息列表,.
+// Get messages/notifications stored message list, not stored and pushed message list.
func (och *OnlineHistoryRedisConsumerHandler) getPushStorageMsgList(
totalMsgs []*ContextMsg,
) (storageMsgList, notStorageMsgList, storageNotificatoinList, notStorageNotificationList, modifyMsgList []*sdkws.MsgData) {
@@ -191,7 +197,7 @@ func (och *OnlineHistoryRedisConsumerHandler) getPushStorageMsgList(
// clone msg from notificationMsg
if options.IsSendMsg() {
msg := proto.Clone(v.message).(*sdkws.MsgData)
- // 消息
+ // message
if v.message.Options != nil {
msg.Options = msgprocessor.NewMsgOptions()
}
@@ -266,7 +272,8 @@ func (och *OnlineHistoryRedisConsumerHandler) toPushTopic(
msgs []*sdkws.MsgData,
) {
for _, v := range msgs {
- och.msgDatabase.MsgToPushMQ(ctx, key, conversationID, v)
+ och.msgDatabase.MsgToPushMQ(ctx, key, conversationID, v) // nolint: errcheck
+
}
}
@@ -430,16 +437,30 @@ func (och *OnlineHistoryRedisConsumerHandler) ConsumeClaim(
log.ZDebug(context.Background(), "online new session msg come", "highWaterMarkOffset",
claim.HighWaterMarkOffset(), "topic", claim.Topic(), "partition", claim.Partition())
- split := 1000
- rwLock := new(sync.RWMutex)
- messages := make([]*sarama.ConsumerMessage, 0, 1000)
- ticker := time.NewTicker(time.Millisecond * 100)
+ var (
+ split = 1000
+ rwLock = new(sync.RWMutex)
+ messages = make([]*sarama.ConsumerMessage, 0, 1000)
+ ticker = time.NewTicker(time.Millisecond * 100)
+ wg = sync.WaitGroup{}
+ running = new(atomic.Bool)
+ )
+ running.Store(true)
+
+ wg.Add(1)
go func() {
+ defer wg.Done()
+
for {
select {
case <-ticker.C:
+ // if the buffer is empty and running is false, return loop.
if len(messages) == 0 {
+ if !running.Load() {
+ return
+ }
+
continue
}
@@ -472,17 +493,35 @@ func (och *OnlineHistoryRedisConsumerHandler) ConsumeClaim(
}
}()
- for msg := range claim.Messages() {
- if len(msg.Value) == 0 {
- continue
+ wg.Add(1)
+ go func() {
+ defer wg.Done()
+
+ for running.Load() {
+ select {
+ case msg, ok := <-claim.Messages():
+ if !ok {
+ running.Store(false)
+ return
+ }
+
+ if len(msg.Value) == 0 {
+ continue
+ }
+
+ rwLock.Lock()
+ messages = append(messages, msg)
+ rwLock.Unlock()
+
+ sess.MarkMessage(msg, "")
+
+ case <-sess.Context().Done():
+ running.Store(false)
+ return
+ }
}
+ }()
- rwLock.Lock()
- messages = append(messages, msg)
- rwLock.Unlock()
-
- sess.MarkMessage(msg, "")
- }
-
+ wg.Wait()
return nil
}
diff --git a/internal/msgtransfer/online_msg_to_mongo_handler.go b/internal/msgtransfer/online_msg_to_mongo_handler.go
index 8ef15fe72..045f82220 100644
--- a/internal/msgtransfer/online_msg_to_mongo_handler.go
+++ b/internal/msgtransfer/online_msg_to_mongo_handler.go
@@ -18,15 +18,13 @@ import (
"context"
"github.com/IBM/sarama"
- "google.golang.org/protobuf/proto"
-
pbmsg "github.com/OpenIMSDK/protocol/msg"
"github.com/OpenIMSDK/tools/log"
-
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/controller"
kfk "github.com/openimsdk/open-im-server/v3/pkg/common/kafka"
"github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics"
+ "google.golang.org/protobuf/proto"
)
type OnlineHistoryMongoConsumerHandler struct {
@@ -34,16 +32,37 @@ type OnlineHistoryMongoConsumerHandler struct {
msgDatabase controller.CommonMsgDatabase
}
-func NewOnlineHistoryMongoConsumerHandler(database controller.CommonMsgDatabase) *OnlineHistoryMongoConsumerHandler {
- mc := &OnlineHistoryMongoConsumerHandler{
- historyConsumerGroup: 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),
- msgDatabase: database,
+func NewOnlineHistoryMongoConsumerHandler(config *config.GlobalConfig, database controller.CommonMsgDatabase) (*OnlineHistoryMongoConsumerHandler, error) {
+ var tlsConfig *kfk.TLSConfig
+ if config.Kafka.TLS != nil {
+ tlsConfig = &kfk.TLSConfig{
+ CACrt: config.Kafka.TLS.CACrt,
+ ClientCrt: config.Kafka.TLS.ClientCrt,
+ ClientKey: config.Kafka.TLS.ClientKey,
+ ClientKeyPwd: config.Kafka.TLS.ClientKeyPwd,
+ InsecureSkipVerify: false,
+ }
}
- return mc
+ historyConsumerGroup, err := kfk.NewMConsumerGroup(&kfk.MConsumerGroupConfig{
+ KafkaVersion: sarama.V2_0_0_0,
+ OffsetsInitial: sarama.OffsetNewest,
+ IsReturnErr: false,
+ UserName: config.Kafka.Username,
+ Password: config.Kafka.Password,
+ }, []string{config.Kafka.MsgToMongo.Topic},
+ config.Kafka.Addr,
+ config.Kafka.ConsumerGroupID.MsgToMongo,
+ tlsConfig,
+ )
+ if err != nil {
+ return nil, err
+ }
+
+ mc := &OnlineHistoryMongoConsumerHandler{
+ historyConsumerGroup: historyConsumerGroup,
+ msgDatabase: database,
+ }
+ return mc, nil
}
func (mc *OnlineHistoryMongoConsumerHandler) handleChatWs2Mongo(
diff --git a/internal/push/callback.go b/internal/push/callback.go
index 90f918fc0..b8830cf9f 100644
--- a/internal/push/callback.go
+++ b/internal/push/callback.go
@@ -22,23 +22,19 @@ import (
"github.com/OpenIMSDK/protocol/sdkws"
"github.com/OpenIMSDK/tools/mcontext"
"github.com/OpenIMSDK/tools/utils"
-
"github.com/openimsdk/open-im-server/v3/pkg/callbackstruct"
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
"github.com/openimsdk/open-im-server/v3/pkg/common/http"
)
-func url() string {
- return config.Config.Callback.CallbackUrl
-}
-
func callbackOfflinePush(
ctx context.Context,
+ config *config.GlobalConfig,
userIDs []string,
msg *sdkws.MsgData,
offlinePushUserIDs *[]string,
) error {
- if !config.Config.Callback.CallbackOfflinePush.Enable || msg.ContentType == constant.Typing {
+ if !config.Callback.CallbackOfflinePush.Enable || msg.ContentType == constant.Typing {
return nil
}
req := &callbackstruct.CallbackBeforePushReq{
@@ -60,10 +56,12 @@ func callbackOfflinePush(
AtUserIDs: msg.AtUserIDList,
Content: GetContent(msg),
}
+
resp := &callbackstruct.CallbackBeforePushResp{}
- if err := http.CallBackPostReturn(ctx, url(), req, resp, config.Config.Callback.CallbackOfflinePush); err != nil {
+ if err := http.CallBackPostReturn(ctx, config.Callback.CallbackUrl, req, resp, config.Callback.CallbackOfflinePush); err != nil {
return err
}
+
if len(resp.UserIDs) != 0 {
*offlinePushUserIDs = resp.UserIDs
}
@@ -73,8 +71,8 @@ func callbackOfflinePush(
return nil
}
-func callbackOnlinePush(ctx context.Context, userIDs []string, msg *sdkws.MsgData) error {
- if !config.Config.Callback.CallbackOnlinePush.Enable || utils.Contain(msg.SendID, userIDs...) || msg.ContentType == constant.Typing {
+func callbackOnlinePush(ctx context.Context, config *config.GlobalConfig, userIDs []string, msg *sdkws.MsgData) error {
+ if !config.Callback.CallbackOnlinePush.Enable || utils.Contain(msg.SendID, userIDs...) || msg.ContentType == constant.Typing {
return nil
}
req := callbackstruct.CallbackBeforePushReq{
@@ -96,7 +94,7 @@ func callbackOnlinePush(ctx context.Context, userIDs []string, msg *sdkws.MsgDat
Content: GetContent(msg),
}
resp := &callbackstruct.CallbackBeforePushResp{}
- if err := http.CallBackPostReturn(ctx, url(), req, resp, config.Config.Callback.CallbackOnlinePush); err != nil {
+ if err := http.CallBackPostReturn(ctx, config.Callback.CallbackUrl, req, resp, config.Callback.CallbackOnlinePush); err != nil {
return err
}
return nil
@@ -104,11 +102,12 @@ func callbackOnlinePush(ctx context.Context, userIDs []string, msg *sdkws.MsgDat
func callbackBeforeSuperGroupOnlinePush(
ctx context.Context,
+ config *config.GlobalConfig,
groupID string,
msg *sdkws.MsgData,
pushToUserIDs *[]string,
) error {
- if !config.Config.Callback.CallbackBeforeSuperGroupOnlinePush.Enable || msg.ContentType == constant.Typing {
+ if !config.Callback.CallbackBeforeSuperGroupOnlinePush.Enable || msg.ContentType == constant.Typing {
return nil
}
req := callbackstruct.CallbackBeforeSuperGroupOnlinePushReq{
@@ -128,10 +127,10 @@ func callbackBeforeSuperGroupOnlinePush(
Seq: msg.Seq,
}
resp := &callbackstruct.CallbackBeforeSuperGroupOnlinePushResp{}
- if err := http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, req, resp, config.Config.Callback.CallbackBeforeSuperGroupOnlinePush); err != nil {
+ if err := http.CallBackPostReturn(ctx, config.Callback.CallbackUrl, req, resp, config.Callback.CallbackBeforeSuperGroupOnlinePush); err != nil {
return err
}
- return nil
+
if len(resp.UserIDs) != 0 {
*pushToUserIDs = resp.UserIDs
}
diff --git a/internal/push/consumer_init.go b/internal/push/consumer_init.go
new file mode 100644
index 000000000..e69de29bb
diff --git a/internal/push/offlinepush/fcm/push.go b/internal/push/offlinepush/fcm/push.go
index 508c70f55..6882a37c4 100644
--- a/internal/push/offlinepush/fcm/push.go
+++ b/internal/push/offlinepush/fcm/push.go
@@ -21,13 +21,13 @@ import (
firebase "firebase.google.com/go"
"firebase.google.com/go/messaging"
- "github.com/redis/go-redis/v9"
- "google.golang.org/api/option"
-
"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/db/cache"
+ "github.com/redis/go-redis/v9"
+ "google.golang.org/api/option"
)
const SinglePushCountLimit = 400
@@ -39,20 +39,22 @@ type Fcm struct {
cache cache.MsgModel
}
-func NewFcm(cache cache.MsgModel) *Fcm {
+// NewClient initializes a new FCM client using the Firebase Admin SDK.
+// It requires the FCM service account credentials file located within the project's configuration directory.
+func NewClient(globalConfig *config.GlobalConfig, cache cache.MsgModel) *Fcm {
projectRoot := config.GetProjectRoot()
- credentialsFilePath := filepath.Join(projectRoot, "config", config.Config.Push.Fcm.ServiceAccount)
+ credentialsFilePath := filepath.Join(projectRoot, "config", globalConfig.Push.Fcm.ServiceAccount)
opt := option.WithCredentialsFile(credentialsFilePath)
fcmApp, err := firebase.NewApp(context.Background(), nil, opt)
if err != nil {
return nil
}
-
ctx := context.Background()
fcmMsgClient, err := fcmApp.Messaging(ctx)
if err != nil {
return nil
}
+
return &Fcm{fcmMsgCli: fcmMsgClient, cache: cache}
}
@@ -125,7 +127,6 @@ func (f *Fcm) Push(ctx context.Context, userIDs []string, title, content string,
response, err := f.fcmMsgCli.SendAll(ctx, messages)
if err != nil {
Fail = Fail + messageCount
- // log.Info(operationID, "some token push err", err.Error(), messageCount)
} else {
Success = Success + response.SuccessCount
Fail = Fail + response.FailureCount
diff --git a/internal/push/offlinepush/getui/body.go b/internal/push/offlinepush/getui/body.go
index 01eb22e73..46479163f 100644
--- a/internal/push/offlinepush/getui/body.go
+++ b/internal/push/offlinepush/getui/body.go
@@ -133,13 +133,13 @@ type Payload struct {
IsSignal bool `json:"isSignal"`
}
-func newPushReq(title, content string) PushReq {
+func newPushReq(config *config.GlobalConfig, title, content string) PushReq {
pushReq := PushReq{PushMessage: &PushMessage{Notification: &Notification{
Title: title,
Body: content,
ClickType: "startapp",
- ChannelID: config.Config.Push.GeTui.ChannelID,
- ChannelName: config.Config.Push.GeTui.ChannelName,
+ ChannelID: config.Push.GeTui.ChannelID,
+ ChannelName: config.Push.GeTui.ChannelName,
}}}
return pushReq
}
diff --git a/internal/push/offlinepush/getui/push.go b/internal/push/offlinepush/getui/push.go
index 50308f6ab..ba80038f7 100644
--- a/internal/push/offlinepush/getui/push.go
+++ b/internal/push/offlinepush/getui/push.go
@@ -24,18 +24,16 @@ import (
"sync"
"time"
- "github.com/redis/go-redis/v9"
-
"github.com/OpenIMSDK/tools/errs"
"github.com/OpenIMSDK/tools/log"
"github.com/OpenIMSDK/tools/mcontext"
"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/db/cache"
http2 "github.com/openimsdk/open-im-server/v3/pkg/common/http"
-
- "github.com/OpenIMSDK/tools/utils"
+ "github.com/redis/go-redis/v9"
)
var (
@@ -59,13 +57,18 @@ type GeTui struct {
cache cache.MsgModel
tokenExpireTime int64
taskIDTTL int64
+ config *config.GlobalConfig
}
-func NewGeTui(cache cache.MsgModel) *GeTui {
- return &GeTui{cache: cache, tokenExpireTime: tokenExpireTime, taskIDTTL: taskIDTTL}
+func NewClient(config *config.GlobalConfig, cache cache.MsgModel) *Client {
+ return &Client{cache: cache,
+ tokenExpireTime: tokenExpireTime,
+ taskIDTTL: taskIDTTL,
+ config: config,
+ }
}
-func (g *GeTui) Push(ctx context.Context, userIDs []string, title, content string, opts *options.Opts) error {
+func (g *Client) Push(ctx context.Context, userIDs []string, title, content string, opts *offlinepush.Opts) error {
token, err := g.cache.GetGetuiToken(ctx)
if err != nil {
if errs.Unwrap(err) == redis.Nil {
@@ -78,7 +81,7 @@ func (g *GeTui) Push(ctx context.Context, userIDs []string, title, content strin
return err
}
}
- pushReq := newPushReq(title, content)
+ pushReq := newPushReq(g.config, title, content)
pushReq.setPushChannel(title, content)
if len(userIDs) > 1 {
maxNum := 999
@@ -89,9 +92,9 @@ func (g *GeTui) Push(ctx context.Context, userIDs []string, title, content strin
for i, v := range s.GetSplitResult() {
go func(index int, userIDs []string) {
defer wg.Done()
- if err2 := g.batchPush(ctx, token, userIDs, pushReq); err2 != nil {
- log.ZError(ctx, "batchPush failed", err2, "index", index, "token", token, "req", pushReq)
- err = err2
+ if err := g.batchPush(ctx, token, userIDs, pushReq); err != nil {
+ log.ZError(ctx, "batchPush failed", err, "index", index, "token", token, "req", pushReq)
+ err = err
}
}(i, v.Item)
}
@@ -111,16 +114,16 @@ func (g *GeTui) Push(ctx context.Context, userIDs []string, title, content strin
return err
}
-func (g *GeTui) Auth(ctx context.Context, timeStamp int64) (token string, expireTime int64, err error) {
+func (g *Client) Auth(ctx context.Context, timeStamp int64) (token string, expireTime int64, err error) {
h := sha256.New()
h.Write(
- []byte(config.Config.Push.GeTui.AppKey + strconv.Itoa(int(timeStamp)) + config.Config.Push.GeTui.MasterSecret),
+ []byte(g.config.Push.GeTui.AppKey + strconv.Itoa(int(timeStamp)) + g.config.Push.GeTui.MasterSecret),
)
sign := hex.EncodeToString(h.Sum(nil))
reqAuth := AuthReq{
Sign: sign,
Timestamp: strconv.Itoa(int(timeStamp)),
- AppKey: config.Config.Push.GeTui.AppKey,
+ AppKey: g.config.Push.GeTui.AppKey,
}
respAuth := AuthResp{}
err = g.request(ctx, authURL, reqAuth, "", &respAuth)
@@ -131,19 +134,19 @@ func (g *GeTui) Auth(ctx context.Context, timeStamp int64) (token string, expire
return respAuth.Token, int64(expire), err
}
-func (g *GeTui) GetTaskID(ctx context.Context, token string, pushReq PushReq) (string, error) {
+func (g *Client) GetTaskID(ctx context.Context, token string, pushReq PushReq) (string, error) {
respTask := TaskResp{}
ttl := int64(1000 * 60 * 5)
pushReq.Settings = &Settings{TTL: &ttl}
err := g.request(ctx, taskURL, pushReq, token, &respTask)
if err != nil {
- return "", utils.Wrap(err, "")
+ return "", errs.Wrap(err)
}
return respTask.TaskID, nil
}
// max num is 999.
-func (g *GeTui) batchPush(ctx context.Context, token string, userIDs []string, pushReq PushReq) error {
+func (g *Client) batchPush(ctx context.Context, token string, userIDs []string, pushReq PushReq) error {
taskID, err := g.GetTaskID(ctx, token, pushReq)
if err != nil {
return err
@@ -152,21 +155,21 @@ func (g *GeTui) batchPush(ctx context.Context, token string, userIDs []string, p
return g.request(ctx, batchPushURL, pushReq, token, nil)
}
-func (g *GeTui) singlePush(ctx context.Context, token, userID string, pushReq PushReq) error {
+func (g *Client) singlePush(ctx context.Context, token, userID string, pushReq PushReq) error {
operationID := mcontext.GetOperationID(ctx)
pushReq.RequestID = &operationID
pushReq.Audience = &Audience{Alias: []string{userID}}
return g.request(ctx, pushURL, pushReq, token, nil)
}
-func (g *GeTui) request(ctx context.Context, url string, input any, token string, output any) error {
+func (g *Client) request(ctx context.Context, url string, input any, token string, output any) error {
header := map[string]string{"token": token}
resp := &Resp{}
resp.Data = output
- return g.postReturn(ctx, config.Config.Push.GeTui.PushUrl+url, header, input, resp, 3)
+ return g.postReturn(ctx, g.config.Push.GeTui.PushUrl+url, header, input, resp, 3)
}
-func (g *GeTui) postReturn(
+func (g *Client) postReturn(
ctx context.Context,
url string,
header map[string]string,
@@ -181,7 +184,7 @@ func (g *GeTui) postReturn(
return output.parseError()
}
-func (g *GeTui) getTokenAndSave2Redis(ctx context.Context) (token string, err error) {
+func (g *Client) getTokenAndSave2Redis(ctx context.Context) (token string, err error) {
token, _, err = g.Auth(ctx, time.Now().UnixNano()/1e6)
if err != nil {
return
@@ -193,7 +196,7 @@ func (g *GeTui) getTokenAndSave2Redis(ctx context.Context) (token string, err er
return token, nil
}
-func (g *GeTui) GetTaskIDAndSave2Redis(ctx context.Context, token string, pushReq PushReq) (taskID string, err error) {
+func (g *Client) GetTaskIDAndSave2Redis(ctx context.Context, token string, pushReq PushReq) (taskID string, err error) {
pushReq.Settings = &Settings{TTL: &g.taskIDTTL}
taskID, err = g.GetTaskID(ctx, token, pushReq)
if err != nil {
diff --git a/internal/push/offlinepush/jpush/body/notification.go b/internal/push/offlinepush/jpush/body/notification.go
index ddf3802af..b25882ea5 100644
--- a/internal/push/offlinepush/jpush/body/notification.go
+++ b/internal/push/offlinepush/jpush/body/notification.go
@@ -46,7 +46,6 @@ type Extras struct {
func (n *Notification) SetAlert(alert string) {
n.Alert = alert
n.Android.Alert = alert
- n.SetAndroidIntent()
n.IOS.Alert = alert
n.IOS.Sound = "default"
n.IOS.Badge = "+1"
@@ -57,8 +56,8 @@ func (n *Notification) SetExtras(extras Extras) {
n.Android.Extras = extras
}
-func (n *Notification) SetAndroidIntent() {
- n.Android.Intent.URL = config.Config.Push.Jpns.PushIntent
+func (n *Notification) SetAndroidIntent(config *config.GlobalConfig) {
+ n.Android.Intent.URL = config.Push.Jpns.PushIntent
}
func (n *Notification) IOSEnableMutableContent() {
diff --git a/internal/push/offlinepush/jpush/push.go b/internal/push/offlinepush/jpush/push.go
index f25ff6f4c..55c4aea39 100644
--- a/internal/push/offlinepush/jpush/push.go
+++ b/internal/push/offlinepush/jpush/push.go
@@ -25,10 +25,12 @@ import (
http2 "github.com/openimsdk/open-im-server/v3/pkg/common/http"
)
-type JPush struct{}
+type JPush struct {
+ config *config.GlobalConfig
+}
-func NewJPush() *JPush {
- return &JPush{}
+func NewClient(config *config.GlobalConfig) *JPush {
+ return &JPush{config: config}
}
func (j *JPush) Auth(apiKey, secretKey string, timeStamp int64) (token string, err error) {
@@ -59,10 +61,12 @@ func (j *JPush) Push(ctx context.Context, userIDs []string, title, content strin
no.IOSEnableMutableContent()
no.SetExtras(extras)
no.SetAlert(title)
+ no.SetAndroidIntent(j.config)
+
var msg body.Message
msg.SetMsgContent(content)
var opt body.Options
- opt.SetApnsProduction(config.Config.IOSPush.Production)
+ opt.SetApnsProduction(j.config.IOSPush.Production)
var pushObj body.PushObj
pushObj.SetPlatform(&pf)
pushObj.SetAudience(&au)
@@ -76,9 +80,9 @@ func (j *JPush) Push(ctx context.Context, userIDs []string, title, content strin
func (j *JPush) request(ctx context.Context, po body.PushObj, resp any, timeout int) error {
return http2.PostReturn(
ctx,
- config.Config.Push.Jpns.PushUrl,
+ j.config.Push.Jpns.PushUrl,
map[string]string{
- "Authorization": j.getAuthorization(config.Config.Push.Jpns.AppKey, config.Config.Push.Jpns.MasterSecret),
+ "Authorization": j.getAuthorization(j.config.Push.Jpns.AppKey, j.config.Push.Jpns.MasterSecret),
},
po,
resp,
diff --git a/internal/push/push_handler.go b/internal/push/push_handler.go
index 82de8f250..61106e1f1 100644
--- a/internal/push/push_handler.go
+++ b/internal/push/push_handler.go
@@ -29,16 +29,14 @@ import (
"github.com/redis/go-redis/v9"
"github.com/IBM/sarama"
- "google.golang.org/protobuf/proto"
-
"github.com/OpenIMSDK/protocol/constant"
pbchat "github.com/OpenIMSDK/protocol/msg"
pbpush "github.com/OpenIMSDK/protocol/push"
"github.com/OpenIMSDK/tools/log"
"github.com/OpenIMSDK/tools/utils"
-
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
kfk "github.com/openimsdk/open-im-server/v3/pkg/common/kafka"
+ "google.golang.org/protobuf/proto"
)
type ConsumerHandler struct {
@@ -52,22 +50,33 @@ type ConsumerHandler struct {
groupRpcClient rpcclient.GroupRpcClient
}
-func NewConsumerHandler(offlinePusher offlinepush.OfflinePusher,
- rdb redis.UniversalClient, disCov discoveryregistry.SvcDiscoveryRegistry) *ConsumerHandler {
+func NewConsumerHandler(config *config.GlobalConfig, pusher *Pusher) (*ConsumerHandler, error) {
var consumerHandler ConsumerHandler
- consumerHandler.pushConsumerGroup = kfk.NewMConsumerGroup(&kfk.MConsumerGroupConfig{
+ consumerHandler.pusher = pusher
+ var err error
+ var tlsConfig *kfk.TLSConfig
+ if config.Kafka.TLS != nil {
+ tlsConfig = &kfk.TLSConfig{
+ CACrt: config.Kafka.TLS.CACrt,
+ ClientCrt: config.Kafka.TLS.ClientCrt,
+ ClientKey: config.Kafka.TLS.ClientKey,
+ ClientKeyPwd: config.Kafka.TLS.ClientKeyPwd,
+ InsecureSkipVerify: false,
+ }
+ }
+ consumerHandler.pushConsumerGroup, err = kfk.NewMConsumerGroup(&kfk.MConsumerGroupConfig{
KafkaVersion: sarama.V2_0_0_0,
- OffsetsInitial: sarama.OffsetNewest, IsReturnErr: false,
- }, []string{config.Config.Kafka.MsgToPush.Topic}, config.Config.Kafka.Addr,
- config.Config.Kafka.ConsumerGroupID.MsgToPush)
- consumerHandler.offlinePusher = offlinePusher
- consumerHandler.onlinePusher = NewOnlinePusher(disCov)
- consumerHandler.groupRpcClient = rpcclient.NewGroupRpcClient(disCov)
- 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
+ OffsetsInitial: sarama.OffsetNewest,
+ IsReturnErr: false,
+ UserName: config.Kafka.Username,
+ Password: config.Kafka.Password,
+ }, []string{config.Kafka.MsgToPush.Topic}, config.Kafka.Addr,
+ config.Kafka.ConsumerGroupID.MsgToPush,
+ tlsConfig)
+ if err != nil {
+ return nil, err
+ }
+ return &consumerHandler, nil
}
func (c *ConsumerHandler) handleMs2PsChat(ctx context.Context, msg []byte) {
diff --git a/internal/push/push_rpc_server.go b/internal/push/push_rpc_server.go
new file mode 100644
index 000000000..e69de29bb
diff --git a/internal/push/push_to_client.go b/internal/push/push_to_client.go
new file mode 100644
index 000000000..e69de29bb
diff --git a/internal/rpc/auth/auth.go b/internal/rpc/auth/auth.go
index ee8ead194..eb1e2f68a 100644
--- a/internal/rpc/auth/auth.go
+++ b/internal/rpc/auth/auth.go
@@ -17,10 +17,6 @@ package auth
import (
"context"
- "github.com/openimsdk/open-im-server/v3/pkg/authverify"
-
- "google.golang.org/grpc"
-
pbauth "github.com/OpenIMSDK/protocol/auth"
"github.com/OpenIMSDK/protocol/constant"
"github.com/OpenIMSDK/protocol/msggateway"
@@ -29,42 +25,45 @@ import (
"github.com/OpenIMSDK/tools/log"
"github.com/OpenIMSDK/tools/mcontext"
"github.com/OpenIMSDK/tools/tokenverify"
- "github.com/OpenIMSDK/tools/utils"
-
+ "github.com/openimsdk/open-im-server/v3/pkg/authverify"
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/cache"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/controller"
"github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics"
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
+ "google.golang.org/grpc"
)
type authServer struct {
authDatabase controller.AuthDatabase
userRpcClient *rpcclient.UserRpcClient
RegisterCenter discoveryregistry.SvcDiscoveryRegistry
+ config *config.GlobalConfig
}
-func Start(client discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) error {
- rdb, err := cache.NewRedis()
+func Start(config *config.GlobalConfig, client discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) error {
+ rdb, err := cache.NewRedis(config)
if err != nil {
return err
}
- userRpcClient := rpcclient.NewUserRpcClient(client)
+ userRpcClient := rpcclient.NewUserRpcClient(client, config)
pbauth.RegisterAuthServer(server, &authServer{
userRpcClient: &userRpcClient,
RegisterCenter: client,
authDatabase: controller.NewAuthDatabase(
- cache.NewMsgCacheModel(rdb),
- config.Config.Secret,
- config.Config.TokenPolicy.Expire,
+ cache.NewMsgCacheModel(rdb, config),
+ config.Secret,
+ config.TokenPolicy.Expire,
+ config,
),
+ config: config,
})
return nil
}
func (s *authServer) UserToken(ctx context.Context, req *pbauth.UserTokenReq) (*pbauth.UserTokenResp, error) {
resp := pbauth.UserTokenResp{}
- if req.Secret != config.Config.Secret {
+ if req.Secret != s.config.Secret {
return nil, errs.ErrNoPermission.Wrap("secret invalid")
}
if _, err := s.userRpcClient.GetUserInfo(ctx, req.UserID); err != nil {
@@ -76,14 +75,36 @@ func (s *authServer) UserToken(ctx context.Context, req *pbauth.UserTokenReq) (*
}
prommetrics.UserLoginCounter.Inc()
resp.Token = token
- resp.ExpireTimeSeconds = config.Config.TokenPolicy.Expire * 24 * 60 * 60
+ resp.ExpireTimeSeconds = s.config.TokenPolicy.Expire * 24 * 60 * 60
+ return &resp, nil
+}
+
+func (s *authServer) GetUserToken(ctx context.Context, req *pbauth.GetUserTokenReq) (*pbauth.GetUserTokenResp, error) {
+ if err := authverify.CheckAdmin(ctx, s.config); err != nil {
+ return nil, err
+ }
+ resp := pbauth.GetUserTokenResp{}
+
+ if authverify.IsManagerUserID(req.UserID, s.config) {
+ return nil, errs.ErrNoPermission.Wrap("don't get Admin token")
+ }
+
+ if _, err := s.userRpcClient.GetUserInfo(ctx, req.UserID); err != nil {
+ return nil, err
+ }
+ token, err := s.authDatabase.CreateToken(ctx, req.UserID, int(req.PlatformID))
+ if err != nil {
+ return nil, err
+ }
+ resp.Token = token
+ resp.ExpireTimeSeconds = s.config.TokenPolicy.Expire * 24 * 60 * 60
return &resp, nil
}
func (s *authServer) parseToken(ctx context.Context, tokensString string) (claims *tokenverify.Claims, err error) {
- claims, err = tokenverify.GetClaimFromToken(tokensString, authverify.Secret())
+ claims, err = tokenverify.GetClaimFromToken(tokensString, authverify.Secret(s.config.Secret))
if err != nil {
- return nil, utils.Wrap(err, "")
+ return nil, errs.Wrap(err)
}
m, err := s.authDatabase.GetTokensWithoutError(ctx, claims.UserID, claims.PlatformID)
if err != nil {
@@ -99,7 +120,7 @@ func (s *authServer) parseToken(ctx context.Context, tokensString string) (claim
case constant.KickedToken:
return nil, errs.ErrTokenKicked.Wrap()
default:
- return nil, utils.Wrap(errs.ErrTokenUnknown, "")
+ return nil, errs.Wrap(errs.ErrTokenUnknown)
}
}
return nil, errs.ErrTokenNotExist.Wrap()
@@ -121,7 +142,7 @@ func (s *authServer) ParseToken(
}
func (s *authServer) ForceLogout(ctx context.Context, req *pbauth.ForceLogoutReq) (*pbauth.ForceLogoutResp, error) {
- if err := authverify.CheckAdmin(ctx); err != nil {
+ if err := authverify.CheckAdmin(ctx, s.config); err != nil {
return nil, err
}
if err := s.forceKickOff(ctx, req.UserID, req.PlatformID, mcontext.GetOperationID(ctx)); err != nil {
@@ -131,7 +152,7 @@ func (s *authServer) ForceLogout(ctx context.Context, req *pbauth.ForceLogoutReq
}
func (s *authServer) forceKickOff(ctx context.Context, userID string, platformID int32, operationID string) error {
- conns, err := s.RegisterCenter.GetConns(ctx, config.Config.RpcRegisterName.OpenImMessageGatewayName)
+ conns, err := s.RegisterCenter.GetConns(ctx, s.config.RpcRegisterName.OpenImMessageGatewayName)
if err != nil {
return err
}
diff --git a/internal/rpc/conversation/conversaion.go b/internal/rpc/conversation/conversaion.go
index 2288113c5..9ae32cd8e 100644
--- a/internal/rpc/conversation/conversaion.go
+++ b/internal/rpc/conversation/conversaion.go
@@ -19,28 +19,24 @@ import (
"errors"
"sort"
- "github.com/OpenIMSDK/protocol/sdkws"
-
- "github.com/OpenIMSDK/tools/tx"
-
- "github.com/openimsdk/open-im-server/v3/pkg/common/db/mgo"
- "github.com/openimsdk/open-im-server/v3/pkg/common/db/unrelation"
-
- "google.golang.org/grpc"
-
"github.com/OpenIMSDK/protocol/constant"
pbconversation "github.com/OpenIMSDK/protocol/conversation"
+ "github.com/OpenIMSDK/protocol/sdkws"
"github.com/OpenIMSDK/tools/discoveryregistry"
"github.com/OpenIMSDK/tools/errs"
"github.com/OpenIMSDK/tools/log"
+ "github.com/OpenIMSDK/tools/tx"
"github.com/OpenIMSDK/tools/utils"
-
+ "github.com/openimsdk/open-im-server/v3/pkg/common/config"
"github.com/openimsdk/open-im-server/v3/pkg/common/convert"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/cache"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/controller"
+ "github.com/openimsdk/open-im-server/v3/pkg/common/db/mgo"
tablerelation "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
+ "github.com/openimsdk/open-im-server/v3/pkg/common/db/unrelation"
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient/notification"
+ "google.golang.org/grpc"
)
type conversationServer struct {
@@ -49,30 +45,40 @@ type conversationServer struct {
groupRpcClient *rpcclient.GroupRpcClient
conversationDatabase controller.ConversationDatabase
conversationNotificationSender *notification.ConversationNotificationSender
+ config *config.GlobalConfig
}
-func Start(client discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) error {
- rdb, err := cache.NewRedis()
+func (c *conversationServer) GetConversationNotReceiveMessageUserIDs(
+ ctx context.Context,
+ req *pbconversation.GetConversationNotReceiveMessageUserIDsReq,
+) (*pbconversation.GetConversationNotReceiveMessageUserIDsResp, error) {
+ //TODO implement me
+ panic("implement me")
+}
+
+func Start(config *config.GlobalConfig, client discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) error {
+ rdb, err := cache.NewRedis(config)
if err != nil {
return err
}
- mongo, err := unrelation.NewMongo()
+ mongo, err := unrelation.NewMongo(config)
if err != nil {
return err
}
- conversationDB, err := mgo.NewConversationMongo(mongo.GetDatabase())
+ conversationDB, err := mgo.NewConversationMongo(mongo.GetDatabase(config.Mongo.Database))
if err != nil {
return err
}
- groupRpcClient := rpcclient.NewGroupRpcClient(client)
- msgRpcClient := rpcclient.NewMessageRpcClient(client)
- userRpcClient := rpcclient.NewUserRpcClient(client)
+ groupRpcClient := rpcclient.NewGroupRpcClient(client, config)
+ msgRpcClient := rpcclient.NewMessageRpcClient(client, config)
+ userRpcClient := rpcclient.NewUserRpcClient(client, config)
pbconversation.RegisterConversationServer(server, &conversationServer{
msgRpcClient: &msgRpcClient,
user: &userRpcClient,
- conversationNotificationSender: notification.NewConversationNotificationSender(&msgRpcClient),
+ conversationNotificationSender: notification.NewConversationNotificationSender(config, &msgRpcClient),
groupRpcClient: &groupRpcClient,
conversationDatabase: controller.NewConversationDatabase(conversationDB, cache.NewConversationRedis(rdb, cache.GetDefaultOpt(), conversationDB), tx.NewMongo(mongo.GetClient())),
+ config: config,
})
return nil
}
@@ -302,7 +308,7 @@ func (c *conversationServer) SetConversations(ctx context.Context,
unequal++
}
}
- if err := c.conversationDatabase.SetUsersConversationFiledTx(ctx, req.UserIDs, &conversation, m); err != nil {
+ if err := c.conversationDatabase.SetUsersConversationFieldTx(ctx, req.UserIDs, &conversation, m); err != nil {
return nil, err
}
if unequal > 0 {
@@ -313,7 +319,7 @@ func (c *conversationServer) SetConversations(ctx context.Context,
return &pbconversation.SetConversationsResp{}, nil
}
-// 获取超级大群开启免打扰的用户ID.
+// Get user IDs with "Do Not Disturb" enabled in super large groups.
func (c *conversationServer) GetRecvMsgNotNotifyUserIDs(ctx context.Context, req *pbconversation.GetRecvMsgNotNotifyUserIDsReq) (*pbconversation.GetRecvMsgNotNotifyUserIDsResp, error) {
//userIDs, err := c.conversationDatabase.FindRecvMsgNotNotifyUserIDs(ctx, req.GroupID)
//if err != nil {
@@ -370,7 +376,7 @@ func (c *conversationServer) CreateGroupChatConversations(ctx context.Context, r
}
func (c *conversationServer) SetConversationMaxSeq(ctx context.Context, req *pbconversation.SetConversationMaxSeqReq) (*pbconversation.SetConversationMaxSeqResp, error) {
- if err := c.conversationDatabase.UpdateUsersConversationFiled(ctx, req.OwnerUserID, req.ConversationID,
+ if err := c.conversationDatabase.UpdateUsersConversationField(ctx, req.OwnerUserID, req.ConversationID,
map[string]any{"max_seq": req.MaxSeq}); err != nil {
return nil, err
}
diff --git a/internal/rpc/friend/black.go b/internal/rpc/friend/black.go
index ed5791c38..64c63eb73 100644
--- a/internal/rpc/friend/black.go
+++ b/internal/rpc/friend/black.go
@@ -18,11 +18,9 @@ import (
"context"
"time"
- "github.com/openimsdk/open-im-server/v3/pkg/authverify"
-
pbfriend "github.com/OpenIMSDK/protocol/friend"
"github.com/OpenIMSDK/tools/mcontext"
-
+ "github.com/openimsdk/open-im-server/v3/pkg/authverify"
"github.com/openimsdk/open-im-server/v3/pkg/common/convert"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
)
@@ -67,7 +65,7 @@ func (s *friendServer) RemoveBlack(ctx context.Context, req *pbfriend.RemoveBlac
}
func (s *friendServer) AddBlack(ctx context.Context, req *pbfriend.AddBlackReq) (*pbfriend.AddBlackResp, error) {
- if err := authverify.CheckAccessV3(ctx, req.OwnerUserID); err != nil {
+ if err := authverify.CheckAccessV3(ctx, req.OwnerUserID, s.config); err != nil {
return nil, err
}
_, err := s.userRpcClient.GetUsersInfo(ctx, []string{req.OwnerUserID, req.BlackUserID})
diff --git a/internal/rpc/friend/callback.go b/internal/rpc/friend/callback.go
index e5054d9a9..78d4fc926 100644
--- a/internal/rpc/friend/callback.go
+++ b/internal/rpc/friend/callback.go
@@ -19,14 +19,13 @@ import (
pbfriend "github.com/OpenIMSDK/protocol/friend"
"github.com/OpenIMSDK/tools/utils"
-
cbapi "github.com/openimsdk/open-im-server/v3/pkg/callbackstruct"
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
"github.com/openimsdk/open-im-server/v3/pkg/common/http"
)
-func CallbackBeforeAddFriend(ctx context.Context, req *pbfriend.ApplyToAddFriendReq) error {
- if !config.Config.Callback.CallbackBeforeAddFriend.Enable {
+func CallbackBeforeAddFriend(ctx context.Context, globalConfig *config.GlobalConfig, req *pbfriend.ApplyToAddFriendReq) error {
+ if !globalConfig.Callback.CallbackBeforeAddFriend.Enable {
return nil
}
cbReq := &cbapi.CallbackBeforeAddFriendReq{
@@ -37,14 +36,14 @@ func CallbackBeforeAddFriend(ctx context.Context, req *pbfriend.ApplyToAddFriend
Ex: req.Ex,
}
resp := &cbapi.CallbackBeforeAddFriendResp{}
- if err := http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, cbReq, resp, config.Config.Callback.CallbackBeforeAddFriend); err != nil {
+ if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, cbReq, resp, globalConfig.Callback.CallbackBeforeAddFriend); err != nil {
return err
}
return nil
}
-func CallbackBeforeSetFriendRemark(ctx context.Context, req *pbfriend.SetFriendRemarkReq) error {
- if !config.Config.Callback.CallbackBeforeSetFriendRemark.Enable {
+func CallbackBeforeSetFriendRemark(ctx context.Context, globalConfig *config.GlobalConfig, req *pbfriend.SetFriendRemarkReq) error {
+ if !globalConfig.Callback.CallbackBeforeSetFriendRemark.Enable {
return nil
}
cbReq := &cbapi.CallbackBeforeSetFriendRemarkReq{
@@ -54,15 +53,15 @@ func CallbackBeforeSetFriendRemark(ctx context.Context, req *pbfriend.SetFriendR
Remark: req.Remark,
}
resp := &cbapi.CallbackBeforeSetFriendRemarkResp{}
- if err := http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, cbReq, resp, config.Config.Callback.CallbackBeforeAddFriend); err != nil {
+ if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, cbReq, resp, globalConfig.Callback.CallbackBeforeAddFriend); err != nil {
return err
}
utils.NotNilReplace(&req.Remark, &resp.Remark)
return nil
}
-func CallbackAfterSetFriendRemark(ctx context.Context, req *pbfriend.SetFriendRemarkReq) error {
- if !config.Config.Callback.CallbackAfterSetFriendRemark.Enable {
+func CallbackAfterSetFriendRemark(ctx context.Context, globalConfig *config.GlobalConfig, req *pbfriend.SetFriendRemarkReq) error {
+ if !globalConfig.Callback.CallbackAfterSetFriendRemark.Enable {
return nil
}
cbReq := &cbapi.CallbackAfterSetFriendRemarkReq{
@@ -72,13 +71,13 @@ func CallbackAfterSetFriendRemark(ctx context.Context, req *pbfriend.SetFriendRe
Remark: req.Remark,
}
resp := &cbapi.CallbackAfterSetFriendRemarkResp{}
- if err := http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, cbReq, resp, config.Config.Callback.CallbackBeforeAddFriend); err != nil {
+ if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, cbReq, resp, globalConfig.Callback.CallbackBeforeAddFriend); err != nil {
return err
}
return nil
}
-func CallbackBeforeAddBlack(ctx context.Context, req *pbfriend.AddBlackReq) error {
- if !config.Config.Callback.CallbackBeforeAddBlack.Enable {
+func CallbackBeforeAddBlack(ctx context.Context, globalConfig *config.GlobalConfig, req *pbfriend.AddBlackReq) error {
+ if !globalConfig.Callback.CallbackBeforeAddBlack.Enable {
return nil
}
cbReq := &cbapi.CallbackBeforeAddBlackReq{
@@ -87,13 +86,13 @@ func CallbackBeforeAddBlack(ctx context.Context, req *pbfriend.AddBlackReq) erro
BlackUserID: req.BlackUserID,
}
resp := &cbapi.CallbackBeforeAddBlackResp{}
- if err := http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, cbReq, resp, config.Config.Callback.CallbackBeforeAddBlack); err != nil {
+ if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, cbReq, resp, globalConfig.Callback.CallbackBeforeAddBlack); err != nil {
return err
}
return nil
}
-func CallbackAfterAddFriend(ctx context.Context, req *pbfriend.ApplyToAddFriendReq) error {
- if !config.Config.Callback.CallbackAfterAddFriend.Enable {
+func CallbackAfterAddFriend(ctx context.Context, globalConfig *config.GlobalConfig, req *pbfriend.ApplyToAddFriendReq) error {
+ if !globalConfig.Callback.CallbackAfterAddFriend.Enable {
return nil
}
cbReq := &cbapi.CallbackAfterAddFriendReq{
@@ -103,14 +102,14 @@ func CallbackAfterAddFriend(ctx context.Context, req *pbfriend.ApplyToAddFriendR
ReqMsg: req.ReqMsg,
}
resp := &cbapi.CallbackAfterAddFriendResp{}
- if err := http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, cbReq, resp, config.Config.Callback.CallbackAfterAddFriend); err != nil {
+ if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, cbReq, resp, globalConfig.Callback.CallbackAfterAddFriend); err != nil {
return err
}
return nil
}
-func CallbackBeforeAddFriendAgree(ctx context.Context, req *pbfriend.RespondFriendApplyReq) error {
- if !config.Config.Callback.CallbackBeforeAddFriendAgree.Enable {
+func CallbackBeforeAddFriendAgree(ctx context.Context, globalConfig *config.GlobalConfig, req *pbfriend.RespondFriendApplyReq) error {
+ if !globalConfig.Callback.CallbackBeforeAddFriendAgree.Enable {
return nil
}
cbReq := &cbapi.CallbackBeforeAddFriendAgreeReq{
@@ -121,13 +120,13 @@ func CallbackBeforeAddFriendAgree(ctx context.Context, req *pbfriend.RespondFrie
HandleResult: req.HandleResult,
}
resp := &cbapi.CallbackBeforeAddFriendAgreeResp{}
- if err := http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, cbReq, resp, config.Config.Callback.CallbackBeforeAddFriendAgree); err != nil {
+ if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, cbReq, resp, globalConfig.Callback.CallbackBeforeAddFriendAgree); err != nil {
return err
}
return nil
}
-func CallbackAfterDeleteFriend(ctx context.Context, req *pbfriend.DeleteFriendReq) error {
- if !config.Config.Callback.CallbackAfterDeleteFriend.Enable {
+func CallbackAfterDeleteFriend(ctx context.Context, globalConfig *config.GlobalConfig, req *pbfriend.DeleteFriendReq) error {
+ if !globalConfig.Callback.CallbackAfterDeleteFriend.Enable {
return nil
}
cbReq := &cbapi.CallbackAfterDeleteFriendReq{
@@ -136,13 +135,13 @@ func CallbackAfterDeleteFriend(ctx context.Context, req *pbfriend.DeleteFriendRe
FriendUserID: req.FriendUserID,
}
resp := &cbapi.CallbackAfterDeleteFriendResp{}
- if err := http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, cbReq, resp, config.Config.Callback.CallbackAfterDeleteFriend); err != nil {
+ if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, cbReq, resp, globalConfig.Callback.CallbackAfterDeleteFriend); err != nil {
return err
}
return nil
}
-func CallbackBeforeImportFriends(ctx context.Context, req *pbfriend.ImportFriendReq) error {
- if !config.Config.Callback.CallbackBeforeImportFriends.Enable {
+func CallbackBeforeImportFriends(ctx context.Context, globalConfig *config.GlobalConfig, req *pbfriend.ImportFriendReq) error {
+ if !globalConfig.Callback.CallbackBeforeImportFriends.Enable {
return nil
}
cbReq := &cbapi.CallbackBeforeImportFriendsReq{
@@ -151,7 +150,7 @@ func CallbackBeforeImportFriends(ctx context.Context, req *pbfriend.ImportFriend
FriendUserIDs: req.FriendUserIDs,
}
resp := &cbapi.CallbackBeforeImportFriendsResp{}
- if err := http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, cbReq, resp, config.Config.Callback.CallbackBeforeImportFriends); err != nil {
+ if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, cbReq, resp, globalConfig.Callback.CallbackBeforeImportFriends); err != nil {
return err
}
if len(resp.FriendUserIDs) != 0 {
@@ -159,8 +158,8 @@ func CallbackBeforeImportFriends(ctx context.Context, req *pbfriend.ImportFriend
}
return nil
}
-func CallbackAfterImportFriends(ctx context.Context, req *pbfriend.ImportFriendReq) error {
- if !config.Config.Callback.CallbackAfterImportFriends.Enable {
+func CallbackAfterImportFriends(ctx context.Context, globalConfig *config.GlobalConfig, req *pbfriend.ImportFriendReq) error {
+ if !globalConfig.Callback.CallbackAfterImportFriends.Enable {
return nil
}
cbReq := &cbapi.CallbackAfterImportFriendsReq{
@@ -169,14 +168,14 @@ func CallbackAfterImportFriends(ctx context.Context, req *pbfriend.ImportFriendR
FriendUserIDs: req.FriendUserIDs,
}
resp := &cbapi.CallbackAfterImportFriendsResp{}
- if err := http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, cbReq, resp, config.Config.Callback.CallbackAfterImportFriends); err != nil {
+ if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, cbReq, resp, globalConfig.Callback.CallbackAfterImportFriends); err != nil {
return err
}
return nil
}
-func CallbackAfterRemoveBlack(ctx context.Context, req *pbfriend.RemoveBlackReq) error {
- if !config.Config.Callback.CallbackAfterRemoveBlack.Enable {
+func CallbackAfterRemoveBlack(ctx context.Context, globalConfig *config.GlobalConfig, req *pbfriend.RemoveBlackReq) error {
+ if !globalConfig.Callback.CallbackAfterRemoveBlack.Enable {
return nil
}
cbReq := &cbapi.CallbackAfterRemoveBlackReq{
@@ -185,7 +184,7 @@ func CallbackAfterRemoveBlack(ctx context.Context, req *pbfriend.RemoveBlackReq)
BlackUserID: req.BlackUserID,
}
resp := &cbapi.CallbackAfterRemoveBlackResp{}
- if err := http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, cbReq, resp, config.Config.Callback.CallbackAfterRemoveBlack); err != nil {
+ if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, cbReq, resp, globalConfig.Callback.CallbackAfterRemoveBlack); err != nil {
return err
}
return nil
diff --git a/internal/rpc/friend/friend.go b/internal/rpc/friend/friend.go
index 9c76c6009..75a3bc1d8 100644
--- a/internal/rpc/friend/friend.go
+++ b/internal/rpc/friend/friend.go
@@ -31,16 +31,23 @@ import (
"github.com/OpenIMSDK/protocol/constant"
pbfriend "github.com/OpenIMSDK/protocol/friend"
+ "github.com/OpenIMSDK/protocol/sdkws"
registry "github.com/OpenIMSDK/tools/discoveryregistry"
"github.com/OpenIMSDK/tools/errs"
+ "github.com/OpenIMSDK/tools/log"
+ "github.com/OpenIMSDK/tools/tx"
"github.com/OpenIMSDK/tools/utils"
-
+ "github.com/openimsdk/open-im-server/v3/pkg/authverify"
+ "github.com/openimsdk/open-im-server/v3/pkg/common/config"
+ "github.com/openimsdk/open-im-server/v3/pkg/common/convert"
"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/mgo"
tablerelation "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/unrelation"
+ "github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient/notification"
+ "google.golang.org/grpc"
)
type friendServer struct {
@@ -50,42 +57,44 @@ type friendServer struct {
notificationSender *notification.FriendNotificationSender
conversationRpcClient rpcclient.ConversationRpcClient
RegisterCenter registry.SvcDiscoveryRegistry
+ config *config.GlobalConfig
}
-func Start(client registry.SvcDiscoveryRegistry, server *grpc.Server) error {
+func Start(config *config.GlobalConfig, client registry.SvcDiscoveryRegistry, server *grpc.Server) error {
// Initialize MongoDB
- mongo, err := unrelation.NewMongo()
+ mongo, err := unrelation.NewMongo(config)
if err != nil {
return err
}
// Initialize Redis
- rdb, err := cache.NewRedis()
+ rdb, err := cache.NewRedis(config)
if err != nil {
return err
}
- friendMongoDB, err := mgo.NewFriendMongo(mongo.GetDatabase())
+ friendMongoDB, err := mgo.NewFriendMongo(mongo.GetDatabase(config.Mongo.Database))
if err != nil {
return err
}
- friendRequestMongoDB, err := mgo.NewFriendRequestMongo(mongo.GetDatabase())
+ friendRequestMongoDB, err := mgo.NewFriendRequestMongo(mongo.GetDatabase(config.Mongo.Database))
if err != nil {
return err
}
- blackMongoDB, err := mgo.NewBlackMongo(mongo.GetDatabase())
+ blackMongoDB, err := mgo.NewBlackMongo(mongo.GetDatabase(config.Mongo.Database))
if err != nil {
return err
}
// Initialize RPC clients
- userRpcClient := rpcclient.NewUserRpcClient(client)
- msgRpcClient := rpcclient.NewMessageRpcClient(client)
+ userRpcClient := rpcclient.NewUserRpcClient(client, config)
+ msgRpcClient := rpcclient.NewMessageRpcClient(client, config)
// Initialize notification sender
notificationSender := notification.NewFriendNotificationSender(
+ config,
&msgRpcClient,
notification.WithRpcFunc(userRpcClient.GetUsersInfo),
)
@@ -104,7 +113,8 @@ func Start(client registry.SvcDiscoveryRegistry, server *grpc.Server) error {
userRpcClient: &userRpcClient,
notificationSender: notificationSender,
RegisterCenter: client,
- conversationRpcClient: rpcclient.NewConversationRpcClient(client),
+ conversationRpcClient: rpcclient.NewConversationRpcClient(client, config),
+ config: config,
})
return nil
@@ -112,15 +122,14 @@ func Start(client registry.SvcDiscoveryRegistry, server *grpc.Server) error {
// ok.
func (s *friendServer) ApplyToAddFriend(ctx context.Context, req *pbfriend.ApplyToAddFriendReq) (resp *pbfriend.ApplyToAddFriendResp, err error) {
- defer log.ZInfo(ctx, utils.GetFuncName()+" Return")
resp = &pbfriend.ApplyToAddFriendResp{}
- if err := authverify.CheckAccessV3(ctx, req.FromUserID); err != nil {
+ if err := authverify.CheckAccessV3(ctx, req.FromUserID, s.config); err != nil {
return nil, err
}
if req.ToUserID == req.FromUserID {
- return nil, errs.ErrCanNotAddYourself.Wrap()
+ return nil, errs.ErrCanNotAddYourself.Wrap("req.ToUserID", req.ToUserID)
}
- if err = CallbackBeforeAddFriend(ctx, req); err != nil && err != errs.ErrCallbackContinue {
+ if err = CallbackBeforeAddFriend(ctx, s.config, req); err != nil && err != errs.ErrCallbackContinue {
return nil, err
}
if _, err := s.userRpcClient.GetUsersInfoMap(ctx, []string{req.ToUserID, req.FromUserID}); err != nil {
@@ -137,7 +146,7 @@ func (s *friendServer) ApplyToAddFriend(ctx context.Context, req *pbfriend.Apply
return nil, err
}
s.notificationSender.FriendApplicationAddNotification(ctx, req)
- if err = CallbackAfterAddFriend(ctx, req); err != nil && err != errs.ErrCallbackContinue {
+ if err = CallbackAfterAddFriend(ctx, s.config, req); err != nil && err != errs.ErrCallbackContinue {
return nil, err
}
return resp, nil
@@ -146,7 +155,7 @@ func (s *friendServer) ApplyToAddFriend(ctx context.Context, req *pbfriend.Apply
// ok.
func (s *friendServer) ImportFriends(ctx context.Context, req *pbfriend.ImportFriendReq) (resp *pbfriend.ImportFriendResp, err error) {
defer log.ZInfo(ctx, utils.GetFuncName()+" Return")
- if err := authverify.CheckAdmin(ctx); err != nil {
+ if err := authverify.CheckAdmin(ctx, s.config); err != nil {
return nil, err
}
if _, err := s.userRpcClient.GetUsersInfo(ctx, append([]string{req.OwnerUserID}, req.FriendUserIDs...)); err != nil {
@@ -158,7 +167,7 @@ func (s *friendServer) ImportFriends(ctx context.Context, req *pbfriend.ImportFr
if utils.Duplicate(req.FriendUserIDs) {
return nil, errs.ErrArgs.Wrap("friend userID repeated")
}
- if err := CallbackBeforeImportFriends(ctx, req); err != nil {
+ if err := CallbackBeforeImportFriends(ctx, s.config, req); err != nil {
return nil, err
}
@@ -172,7 +181,7 @@ func (s *friendServer) ImportFriends(ctx context.Context, req *pbfriend.ImportFr
HandleResult: constant.FriendResponseAgree,
})
}
- if err := CallbackAfterImportFriends(ctx, req); err != nil {
+ if err := CallbackAfterImportFriends(ctx, s.config, req); err != nil {
return nil, err
}
return &pbfriend.ImportFriendResp{}, nil
@@ -182,7 +191,7 @@ func (s *friendServer) ImportFriends(ctx context.Context, req *pbfriend.ImportFr
func (s *friendServer) RespondFriendApply(ctx context.Context, req *pbfriend.RespondFriendApplyReq) (resp *pbfriend.RespondFriendApplyResp, err error) {
defer log.ZInfo(ctx, utils.GetFuncName()+" Return")
resp = &pbfriend.RespondFriendApplyResp{}
- if err := authverify.CheckAccessV3(ctx, req.ToUserID); err != nil {
+ if err := authverify.CheckAccessV3(ctx, req.ToUserID, s.config); err != nil {
return nil, err
}
@@ -193,7 +202,7 @@ func (s *friendServer) RespondFriendApply(ctx context.Context, req *pbfriend.Res
HandleResult: req.HandleResult,
}
if req.HandleResult == constant.FriendResponseAgree {
- if err := CallbackBeforeAddFriendAgree(ctx, req); err != nil && err != errs.ErrCallbackContinue {
+ if err := CallbackBeforeAddFriendAgree(ctx, s.config, req); err != nil && err != errs.ErrCallbackContinue {
return nil, err
}
err := s.friendDatabase.AgreeFriendRequest(ctx, &friendRequest)
@@ -229,7 +238,7 @@ func (s *friendServer) DeleteFriend(ctx context.Context, req *pbfriend.DeleteFri
return nil, err
}
s.notificationSender.FriendDeletedNotification(ctx, req)
- if err := CallbackAfterDeleteFriend(ctx, req); err != nil {
+ if err := CallbackAfterDeleteFriend(ctx, s.config, req); err != nil {
return nil, err
}
return resp, nil
@@ -239,7 +248,7 @@ func (s *friendServer) DeleteFriend(ctx context.Context, req *pbfriend.DeleteFri
func (s *friendServer) SetFriendRemark(ctx context.Context, req *pbfriend.SetFriendRemarkReq) (resp *pbfriend.SetFriendRemarkResp, err error) {
defer log.ZInfo(ctx, utils.GetFuncName()+" Return")
- if err = CallbackBeforeSetFriendRemark(ctx, req); err != nil && err != errs.ErrCallbackContinue {
+ if err = CallbackBeforeSetFriendRemark(ctx, s.config, req); err != nil && err != errs.ErrCallbackContinue {
return nil, err
}
resp = &pbfriend.SetFriendRemarkResp{}
@@ -253,7 +262,7 @@ func (s *friendServer) SetFriendRemark(ctx context.Context, req *pbfriend.SetFri
if err := s.friendDatabase.UpdateRemark(ctx, req.OwnerUserID, req.FriendUserID, req.Remark); err != nil {
return nil, err
}
- if err := CallbackAfterSetFriendRemark(ctx, req); err != nil && err != errs.ErrCallbackContinue {
+ if err := CallbackAfterSetFriendRemark(ctx, s.config, req); err != nil && err != errs.ErrCallbackContinue {
return nil, err
}
s.notificationSender.FriendRemarkSetNotification(ctx, req.OwnerUserID, req.FriendUserID)
@@ -277,6 +286,7 @@ func (s *friendServer) GetDesignatedFriends(ctx context.Context, req *pbfriend.G
return resp, nil
}
+// Get the list of friend requests sent out proactively.
func (s *friendServer) GetDesignatedFriendsApply(ctx context.Context,
req *pbfriend.GetDesignatedFriendsApplyReq) (resp *pbfriend.GetDesignatedFriendsApplyResp, err error) {
friendRequests, err := s.friendDatabase.FindBothFriendRequests(ctx, req.FromUserID, req.ToUserID)
@@ -291,7 +301,7 @@ func (s *friendServer) GetDesignatedFriendsApply(ctx context.Context,
return resp, nil
}
-// ok 获取接收到的好友申请(即别人主动申请的).
+// Get received friend requests (i.e., those initiated by others).
func (s *friendServer) GetPaginationFriendsApplyTo(ctx context.Context, req *pbfriend.GetPaginationFriendsApplyToReq) (resp *pbfriend.GetPaginationFriendsApplyToResp, err error) {
defer log.ZInfo(ctx, utils.GetFuncName()+" Return")
if err := s.userRpcClient.Access(ctx, req.UserID); err != nil {
@@ -310,7 +320,6 @@ func (s *friendServer) GetPaginationFriendsApplyTo(ctx context.Context, req *pbf
return resp, nil
}
-// ok 获取主动发出去的好友申请列表.
func (s *friendServer) GetPaginationFriendsApplyFrom(ctx context.Context, req *pbfriend.GetPaginationFriendsApplyFromReq) (resp *pbfriend.GetPaginationFriendsApplyFromResp, err error) {
defer log.ZInfo(ctx, utils.GetFuncName()+" Return")
resp = &pbfriend.GetPaginationFriendsApplyFromResp{}
diff --git a/internal/rpc/group/cache.go b/internal/rpc/group/cache.go
index fc387736d..54b60c554 100644
--- a/internal/rpc/group/cache.go
+++ b/internal/rpc/group/cache.go
@@ -18,7 +18,6 @@ import (
"context"
pbgroup "github.com/OpenIMSDK/protocol/group"
-
"github.com/openimsdk/open-im-server/v3/pkg/common/convert"
)
diff --git a/internal/rpc/group/callback.go b/internal/rpc/group/callback.go
index d891f4d1e..e82177dde 100644
--- a/internal/rpc/group/callback.go
+++ b/internal/rpc/group/callback.go
@@ -18,16 +18,13 @@ import (
"context"
"time"
- "github.com/OpenIMSDK/tools/log"
-
"github.com/OpenIMSDK/protocol/constant"
"github.com/OpenIMSDK/protocol/group"
+ pbgroup "github.com/OpenIMSDK/protocol/group"
"github.com/OpenIMSDK/protocol/wrapperspb"
+ "github.com/OpenIMSDK/tools/log"
"github.com/OpenIMSDK/tools/mcontext"
"github.com/OpenIMSDK/tools/utils"
-
- pbgroup "github.com/OpenIMSDK/protocol/group"
-
"github.com/openimsdk/open-im-server/v3/pkg/apistruct"
"github.com/openimsdk/open-im-server/v3/pkg/callbackstruct"
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
@@ -35,8 +32,8 @@ import (
"github.com/openimsdk/open-im-server/v3/pkg/common/http"
)
-func CallbackBeforeCreateGroup(ctx context.Context, req *group.CreateGroupReq) (err error) {
- if !config.Config.Callback.CallbackBeforeCreateGroup.Enable {
+func CallbackBeforeCreateGroup(ctx context.Context, globalConfig *config.GlobalConfig, req *group.CreateGroupReq) (err error) {
+ if !globalConfig.Callback.CallbackBeforeCreateGroup.Enable {
return nil
}
cbReq := &callbackstruct.CallbackBeforeCreateGroupReq{
@@ -61,7 +58,7 @@ func CallbackBeforeCreateGroup(ctx context.Context, req *group.CreateGroupReq) (
})
}
resp := &callbackstruct.CallbackBeforeCreateGroupResp{}
- if err = http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, cbReq, resp, config.Config.Callback.CallbackBeforeCreateGroup); err != nil {
+ if err = http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, cbReq, resp, globalConfig.Callback.CallbackBeforeCreateGroup); err != nil {
return err
}
utils.NotNilReplace(&req.GroupInfo.GroupID, resp.GroupID)
@@ -79,8 +76,8 @@ func CallbackBeforeCreateGroup(ctx context.Context, req *group.CreateGroupReq) (
return nil
}
-func CallbackAfterCreateGroup(ctx context.Context, req *group.CreateGroupReq) (err error) {
- if !config.Config.Callback.CallbackAfterCreateGroup.Enable {
+func CallbackAfterCreateGroup(ctx context.Context, globalConfig *config.GlobalConfig, req *group.CreateGroupReq) (err error) {
+ if !globalConfig.Callback.CallbackAfterCreateGroup.Enable {
return nil
}
cbReq := &callbackstruct.CallbackAfterCreateGroupReq{
@@ -104,7 +101,7 @@ func CallbackAfterCreateGroup(ctx context.Context, req *group.CreateGroupReq) (e
})
}
resp := &callbackstruct.CallbackAfterCreateGroupResp{}
- if err = http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, cbReq, resp, config.Config.Callback.CallbackAfterCreateGroup); err != nil {
+ if err = http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, cbReq, resp, globalConfig.Callback.CallbackAfterCreateGroup); err != nil {
return err
}
return nil
@@ -112,10 +109,11 @@ func CallbackAfterCreateGroup(ctx context.Context, req *group.CreateGroupReq) (e
func CallbackBeforeMemberJoinGroup(
ctx context.Context,
+ globalConfig *config.GlobalConfig,
groupMember *relation.GroupMemberModel,
groupEx string,
) (err error) {
- if !config.Config.Callback.CallbackBeforeMemberJoinGroup.Enable {
+ if !globalConfig.Callback.CallbackBeforeMemberJoinGroup.Enable {
return nil
}
callbackReq := &callbackstruct.CallbackBeforeMemberJoinGroupReq{
@@ -128,10 +126,10 @@ func CallbackBeforeMemberJoinGroup(
resp := &callbackstruct.CallbackBeforeMemberJoinGroupResp{}
err = http.CallBackPostReturn(
ctx,
- config.Config.Callback.CallbackUrl,
+ globalConfig.Callback.CallbackUrl,
callbackReq,
resp,
- config.Config.Callback.CallbackBeforeMemberJoinGroup,
+ globalConfig.Callback.CallbackBeforeMemberJoinGroup,
)
if err != nil {
return err
@@ -146,8 +144,8 @@ func CallbackBeforeMemberJoinGroup(
return nil
}
-func CallbackBeforeSetGroupMemberInfo(ctx context.Context, req *group.SetGroupMemberInfo) (err error) {
- if !config.Config.Callback.CallbackBeforeSetGroupMemberInfo.Enable {
+func CallbackBeforeSetGroupMemberInfo(ctx context.Context, globalConfig *config.GlobalConfig, req *group.SetGroupMemberInfo) (err error) {
+ if !globalConfig.Callback.CallbackBeforeSetGroupMemberInfo.Enable {
return nil
}
callbackReq := callbackstruct.CallbackBeforeSetGroupMemberInfoReq{
@@ -170,10 +168,10 @@ func CallbackBeforeSetGroupMemberInfo(ctx context.Context, req *group.SetGroupMe
resp := &callbackstruct.CallbackBeforeSetGroupMemberInfoResp{}
err = http.CallBackPostReturn(
ctx,
- config.Config.Callback.CallbackUrl,
+ globalConfig.Callback.CallbackUrl,
callbackReq,
resp,
- config.Config.Callback.CallbackBeforeSetGroupMemberInfo,
+ globalConfig.Callback.CallbackBeforeSetGroupMemberInfo,
)
if err != nil {
return err
@@ -192,8 +190,8 @@ func CallbackBeforeSetGroupMemberInfo(ctx context.Context, req *group.SetGroupMe
}
return nil
}
-func CallbackAfterSetGroupMemberInfo(ctx context.Context, req *group.SetGroupMemberInfo) (err error) {
- if !config.Config.Callback.CallbackBeforeSetGroupMemberInfo.Enable {
+func CallbackAfterSetGroupMemberInfo(ctx context.Context, globalConfig *config.GlobalConfig, req *group.SetGroupMemberInfo) (err error) {
+ if !globalConfig.Callback.CallbackBeforeSetGroupMemberInfo.Enable {
return nil
}
callbackReq := callbackstruct.CallbackAfterSetGroupMemberInfoReq{
@@ -214,14 +212,14 @@ func CallbackAfterSetGroupMemberInfo(ctx context.Context, req *group.SetGroupMem
callbackReq.Ex = &req.Ex.Value
}
resp := &callbackstruct.CallbackAfterSetGroupMemberInfoResp{}
- if err = http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, callbackReq, resp, config.Config.Callback.CallbackAfterSetGroupMemberInfo); err != nil {
+ if err = http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, callbackReq, resp, globalConfig.Callback.CallbackAfterSetGroupMemberInfo); err != nil {
return err
}
return nil
}
-func CallbackQuitGroup(ctx context.Context, req *group.QuitGroupReq) (err error) {
- if !config.Config.Callback.CallbackQuitGroup.Enable {
+func CallbackQuitGroup(ctx context.Context, globalConfig *config.GlobalConfig, req *group.QuitGroupReq) (err error) {
+ if !globalConfig.Callback.CallbackQuitGroup.Enable {
return nil
}
cbReq := &callbackstruct.CallbackQuitGroupReq{
@@ -230,14 +228,14 @@ func CallbackQuitGroup(ctx context.Context, req *group.QuitGroupReq) (err error)
UserID: req.UserID,
}
resp := &callbackstruct.CallbackQuitGroupResp{}
- if err = http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, cbReq, resp, config.Config.Callback.CallbackQuitGroup); err != nil {
+ if err = http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, cbReq, resp, globalConfig.Callback.CallbackQuitGroup); err != nil {
return err
}
return nil
}
-func CallbackKillGroupMember(ctx context.Context, req *pbgroup.KickGroupMemberReq) (err error) {
- if !config.Config.Callback.CallbackKillGroupMember.Enable {
+func CallbackKillGroupMember(ctx context.Context, globalConfig *config.GlobalConfig, req *pbgroup.KickGroupMemberReq) (err error) {
+ if !globalConfig.Callback.CallbackKillGroupMember.Enable {
return nil
}
cbReq := &callbackstruct.CallbackKillGroupMemberReq{
@@ -246,41 +244,41 @@ func CallbackKillGroupMember(ctx context.Context, req *pbgroup.KickGroupMemberRe
KickedUserIDs: req.KickedUserIDs,
}
resp := &callbackstruct.CallbackKillGroupMemberResp{}
- if err = http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, cbReq, resp, config.Config.Callback.CallbackQuitGroup); err != nil {
+ if err = http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, cbReq, resp, globalConfig.Callback.CallbackQuitGroup); err != nil {
return err
}
return nil
}
-func CallbackDismissGroup(ctx context.Context, req *callbackstruct.CallbackDisMissGroupReq) (err error) {
- if !config.Config.Callback.CallbackDismissGroup.Enable {
+func CallbackDismissGroup(ctx context.Context, globalConfig *config.GlobalConfig, req *callbackstruct.CallbackDisMissGroupReq) (err error) {
+ if !globalConfig.Callback.CallbackDismissGroup.Enable {
return nil
}
req.CallbackCommand = callbackstruct.CallbackDisMissGroupCommand
resp := &callbackstruct.CallbackDisMissGroupResp{}
- if err = http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, req, resp, config.Config.Callback.CallbackQuitGroup); err != nil {
+ if err = http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, req, resp, globalConfig.Callback.CallbackQuitGroup); err != nil {
return err
}
return nil
}
-func CallbackApplyJoinGroupBefore(ctx context.Context, req *callbackstruct.CallbackJoinGroupReq) (err error) {
- if !config.Config.Callback.CallbackBeforeJoinGroup.Enable {
+func CallbackApplyJoinGroupBefore(ctx context.Context, globalConfig *config.GlobalConfig, req *callbackstruct.CallbackJoinGroupReq) (err error) {
+ if !globalConfig.Callback.CallbackBeforeJoinGroup.Enable {
return nil
}
req.CallbackCommand = callbackstruct.CallbackBeforeJoinGroupCommand
resp := &callbackstruct.CallbackJoinGroupResp{}
- if err = http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, req, resp, config.Config.Callback.CallbackBeforeJoinGroup); err != nil {
+ if err = http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, req, resp, globalConfig.Callback.CallbackBeforeJoinGroup); err != nil {
return err
}
return nil
}
-func CallbackAfterTransferGroupOwner(ctx context.Context, req *pbgroup.TransferGroupOwnerReq) (err error) {
- if !config.Config.Callback.CallbackAfterTransferGroupOwner.Enable {
+func CallbackAfterTransferGroupOwner(ctx context.Context, globalConfig *config.GlobalConfig, req *pbgroup.TransferGroupOwnerReq) (err error) {
+ if !globalConfig.Callback.CallbackAfterTransferGroupOwner.Enable {
return nil
}
@@ -292,13 +290,13 @@ func CallbackAfterTransferGroupOwner(ctx context.Context, req *pbgroup.TransferG
}
resp := &callbackstruct.CallbackTransferGroupOwnerResp{}
- if err = http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, cbReq, resp, config.Config.Callback.CallbackAfterTransferGroupOwner); err != nil {
+ if err = http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, cbReq, resp, globalConfig.Callback.CallbackAfterTransferGroupOwner); err != nil {
return err
}
return nil
}
-func CallbackBeforeInviteUserToGroup(ctx context.Context, req *group.InviteUserToGroupReq) (err error) {
- if !config.Config.Callback.CallbackBeforeInviteUserToGroup.Enable {
+func CallbackBeforeInviteUserToGroup(ctx context.Context, globalConfig *config.GlobalConfig, req *group.InviteUserToGroupReq) (err error) {
+ if !globalConfig.Callback.CallbackBeforeInviteUserToGroup.Enable {
return nil
}
@@ -313,10 +311,10 @@ func CallbackBeforeInviteUserToGroup(ctx context.Context, req *group.InviteUserT
resp := &callbackstruct.CallbackBeforeInviteUserToGroupResp{}
err = http.CallBackPostReturn(
ctx,
- config.Config.Callback.CallbackUrl,
+ globalConfig.Callback.CallbackUrl,
callbackReq,
resp,
- config.Config.Callback.CallbackBeforeInviteUserToGroup,
+ globalConfig.Callback.CallbackBeforeInviteUserToGroup,
)
if err != nil {
@@ -330,8 +328,8 @@ func CallbackBeforeInviteUserToGroup(ctx context.Context, req *group.InviteUserT
return nil
}
-func CallbackAfterJoinGroup(ctx context.Context, req *group.JoinGroupReq) error {
- if !config.Config.Callback.CallbackAfterJoinGroup.Enable {
+func CallbackAfterJoinGroup(ctx context.Context, globalConfig *config.GlobalConfig, req *group.JoinGroupReq) error {
+ if !globalConfig.Callback.CallbackAfterJoinGroup.Enable {
return nil
}
callbackReq := &callbackstruct.CallbackAfterJoinGroupReq{
@@ -343,14 +341,14 @@ func CallbackAfterJoinGroup(ctx context.Context, req *group.JoinGroupReq) error
InviterUserID: req.InviterUserID,
}
resp := &callbackstruct.CallbackAfterJoinGroupResp{}
- if err := http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, callbackReq, resp, config.Config.Callback.CallbackAfterJoinGroup); err != nil {
+ if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, callbackReq, resp, globalConfig.Callback.CallbackAfterJoinGroup); err != nil {
return err
}
return nil
}
-func CallbackBeforeSetGroupInfo(ctx context.Context, req *group.SetGroupInfoReq) error {
- if !config.Config.Callback.CallbackBeforeSetGroupInfo.Enable {
+func CallbackBeforeSetGroupInfo(ctx context.Context, globalConfig *config.GlobalConfig, req *group.SetGroupInfoReq) error {
+ if !globalConfig.Callback.CallbackBeforeSetGroupInfo.Enable {
return nil
}
callbackReq := &callbackstruct.CallbackBeforeSetGroupInfoReq{
@@ -377,7 +375,7 @@ func CallbackBeforeSetGroupInfo(ctx context.Context, req *group.SetGroupInfoReq)
}
resp := &callbackstruct.CallbackBeforeSetGroupInfoResp{}
- if err := http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, callbackReq, resp, config.Config.Callback.CallbackBeforeSetGroupInfo); err != nil {
+ if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, callbackReq, resp, globalConfig.Callback.CallbackBeforeSetGroupInfo); err != nil {
return err
}
@@ -399,8 +397,8 @@ func CallbackBeforeSetGroupInfo(ctx context.Context, req *group.SetGroupInfoReq)
utils.NotNilReplace(&req.GroupInfoForSet.Introduction, &resp.Introduction)
return nil
}
-func CallbackAfterSetGroupInfo(ctx context.Context, req *group.SetGroupInfoReq) error {
- if !config.Config.Callback.CallbackAfterSetGroupInfo.Enable {
+func CallbackAfterSetGroupInfo(ctx context.Context, globalConfig *config.GlobalConfig, req *group.SetGroupInfoReq) error {
+ if !globalConfig.Callback.CallbackAfterSetGroupInfo.Enable {
return nil
}
callbackReq := &callbackstruct.CallbackAfterSetGroupInfoReq{
@@ -424,7 +422,7 @@ func CallbackAfterSetGroupInfo(ctx context.Context, req *group.SetGroupInfoReq)
callbackReq.ApplyMemberFriend = &req.GroupInfoForSet.ApplyMemberFriend.Value
}
resp := &callbackstruct.CallbackAfterSetGroupInfoResp{}
- if err := http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, callbackReq, resp, config.Config.Callback.CallbackAfterSetGroupInfo); err != nil {
+ if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, callbackReq, resp, globalConfig.Callback.CallbackAfterSetGroupInfo); err != nil {
return err
}
return nil
diff --git a/internal/rpc/group/convert.go b/internal/rpc/group/convert.go
index 2ee7f5056..ab4d3a2a1 100644
--- a/internal/rpc/group/convert.go
+++ b/internal/rpc/group/convert.go
@@ -16,7 +16,6 @@ package group
import (
"github.com/OpenIMSDK/protocol/sdkws"
-
"github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
)
diff --git a/internal/rpc/group/db_map.go b/internal/rpc/group/db_map.go
index 07084873c..e4c18bb17 100644
--- a/internal/rpc/group/db_map.go
+++ b/internal/rpc/group/db_map.go
@@ -18,10 +18,9 @@ import (
"context"
"time"
- "github.com/OpenIMSDK/tools/mcontext"
-
pbgroup "github.com/OpenIMSDK/protocol/group"
"github.com/OpenIMSDK/protocol/sdkws"
+ "github.com/OpenIMSDK/tools/mcontext"
)
func UpdateGroupInfoMap(ctx context.Context, group *sdkws.GroupInfoForSet) map[string]any {
diff --git a/internal/rpc/group/group.go b/internal/rpc/group/group.go
index abc271651..4be8fab0c 100644
--- a/internal/rpc/group/group.go
+++ b/internal/rpc/group/group.go
@@ -23,71 +23,63 @@ import (
"strings"
"time"
- "github.com/openimsdk/open-im-server/v3/pkg/callbackstruct"
-
- pbconversation "github.com/OpenIMSDK/protocol/conversation"
- "github.com/OpenIMSDK/protocol/wrapperspb"
- "github.com/OpenIMSDK/tools/tx"
-
- "github.com/openimsdk/open-im-server/v3/pkg/common/db/mgo"
- "github.com/openimsdk/open-im-server/v3/pkg/rpcclient/grouphash"
-
- "github.com/openimsdk/open-im-server/v3/pkg/authverify"
- "github.com/openimsdk/open-im-server/v3/pkg/msgprocessor"
-
- "github.com/openimsdk/open-im-server/v3/pkg/rpcclient/notification"
-
- "github.com/OpenIMSDK/tools/mw/specialerror"
-
- "github.com/openimsdk/open-im-server/v3/pkg/common/convert"
- "github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
-
- "google.golang.org/grpc"
-
"github.com/OpenIMSDK/protocol/constant"
+ pbconversation "github.com/OpenIMSDK/protocol/conversation"
pbgroup "github.com/OpenIMSDK/protocol/group"
"github.com/OpenIMSDK/protocol/sdkws"
+ "github.com/OpenIMSDK/protocol/wrapperspb"
"github.com/OpenIMSDK/tools/discoveryregistry"
"github.com/OpenIMSDK/tools/errs"
"github.com/OpenIMSDK/tools/log"
"github.com/OpenIMSDK/tools/mcontext"
+ "github.com/OpenIMSDK/tools/mw/specialerror"
+ "github.com/OpenIMSDK/tools/tx"
"github.com/OpenIMSDK/tools/utils"
-
+ "github.com/openimsdk/open-im-server/v3/pkg/authverify"
+ "github.com/openimsdk/open-im-server/v3/pkg/callbackstruct"
+ "github.com/openimsdk/open-im-server/v3/pkg/common/config"
+ "github.com/openimsdk/open-im-server/v3/pkg/common/convert"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/cache"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/controller"
+ "github.com/openimsdk/open-im-server/v3/pkg/common/db/mgo"
relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/unrelation"
+ "github.com/openimsdk/open-im-server/v3/pkg/msgprocessor"
+ "github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
+ "github.com/openimsdk/open-im-server/v3/pkg/rpcclient/grouphash"
+ "github.com/openimsdk/open-im-server/v3/pkg/rpcclient/notification"
+ "google.golang.org/grpc"
)
-func Start(client discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) error {
- mongo, err := unrelation.NewMongo()
+func Start(config *config.GlobalConfig, client discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) error {
+ mongo, err := unrelation.NewMongo(config)
if err != nil {
return err
}
- rdb, err := cache.NewRedis()
+ rdb, err := cache.NewRedis(config)
if err != nil {
return err
}
- groupDB, err := mgo.NewGroupMongo(mongo.GetDatabase())
+ groupDB, err := mgo.NewGroupMongo(mongo.GetDatabase(config.Mongo.Database))
if err != nil {
return err
}
- groupMemberDB, err := mgo.NewGroupMember(mongo.GetDatabase())
+ groupMemberDB, err := mgo.NewGroupMember(mongo.GetDatabase(config.Mongo.Database))
if err != nil {
return err
}
- groupRequestDB, err := mgo.NewGroupRequestMgo(mongo.GetDatabase())
+ groupRequestDB, err := mgo.NewGroupRequestMgo(mongo.GetDatabase(config.Mongo.Database))
if err != nil {
return err
}
- userRpcClient := rpcclient.NewUserRpcClient(client)
- msgRpcClient := rpcclient.NewMessageRpcClient(client)
- conversationRpcClient := rpcclient.NewConversationRpcClient(client)
+ userRpcClient := rpcclient.NewUserRpcClient(client, config)
+ msgRpcClient := rpcclient.NewMessageRpcClient(client, config)
+ conversationRpcClient := rpcclient.NewConversationRpcClient(client, config)
var gs groupServer
database := controller.NewGroupDatabase(rdb, groupDB, groupMemberDB, groupRequestDB, tx.NewMongo(mongo.GetClient()), grouphash.NewGroupHashFromGroupServer(&gs))
gs.db = database
gs.User = userRpcClient
- gs.Notification = notification.NewGroupNotificationSender(database, &msgRpcClient, &userRpcClient, func(ctx context.Context, userIDs []string) ([]notification.CommonUser, error) {
+ gs.Notification = notification.NewGroupNotificationSender(database, &msgRpcClient, &userRpcClient, config, func(ctx context.Context, userIDs []string) ([]notification.CommonUser, error) {
users, err := userRpcClient.GetUsersInfo(ctx, userIDs)
if err != nil {
return nil, err
@@ -96,6 +88,7 @@ func Start(client discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) e
})
gs.conversationRpcClient = conversationRpcClient
gs.msgRpcClient = msgRpcClient
+ gs.config = config
pbgroup.RegisterGroupServer(server, &gs)
return nil
}
@@ -106,10 +99,15 @@ type groupServer struct {
Notification *notification.GroupNotificationSender
conversationRpcClient rpcclient.ConversationRpcClient
msgRpcClient rpcclient.MessageRpcClient
+ config *config.GlobalConfig
+}
+
+func (s *groupServer) GetJoinedGroupIDs(ctx context.Context, req *pbgroup.GetJoinedGroupIDsReq) (*pbgroup.GetJoinedGroupIDsResp, error) {
+ //TODO implement me
+ panic("implement me")
}
func (s *groupServer) NotificationUserInfoUpdate(ctx context.Context, req *pbgroup.NotificationUserInfoUpdateReq) (*pbgroup.NotificationUserInfoUpdateResp, error) {
- defer log.ZDebug(ctx, "NotificationUserInfoUpdate return")
members, err := s.db.FindGroupMemberUser(ctx, nil, req.UserID)
if err != nil {
return nil, err
@@ -121,21 +119,20 @@ func (s *groupServer) NotificationUserInfoUpdate(ctx context.Context, req *pbgro
}
groupIDs = append(groupIDs, member.GroupID)
}
- log.ZInfo(ctx, "NotificationUserInfoUpdate", "joinGroupNum", len(members), "updateNum", len(groupIDs), "updateGroupIDs", groupIDs)
for _, groupID := range groupIDs {
- if err := s.Notification.GroupMemberInfoSetNotification(ctx, groupID, req.UserID); err != nil {
- log.ZError(ctx, "NotificationUserInfoUpdate setGroupMemberInfo notification failed", err, "groupID", groupID)
+ if err = s.Notification.GroupMemberInfoSetNotification(ctx, groupID, req.UserID); err != nil {
+ return nil, err
}
}
- if err := s.db.DeleteGroupMemberHash(ctx, groupIDs); err != nil {
- log.ZError(ctx, "NotificationUserInfoUpdate DeleteGroupMemberHash", err, "groupID", groupIDs)
+ if err = s.db.DeleteGroupMemberHash(ctx, groupIDs); err != nil {
+ return nil, err
}
return &pbgroup.NotificationUserInfoUpdateResp{}, nil
}
func (s *groupServer) CheckGroupAdmin(ctx context.Context, groupID string) error {
- if !authverify.IsAppManagerUid(ctx) {
+ if !authverify.IsAppManagerUid(ctx, s.config) {
groupMember, err := s.db.TakeGroupMember(ctx, groupID, mcontext.GetOpUserID(ctx))
if err != nil {
return err
@@ -200,7 +197,7 @@ func (s *groupServer) CreateGroup(ctx context.Context, req *pbgroup.CreateGroupR
if req.OwnerUserID == "" {
return nil, errs.ErrArgs.Wrap("no group owner")
}
- if err := authverify.CheckAccessV3(ctx, req.OwnerUserID); err != nil {
+ if err := authverify.CheckAccessV3(ctx, req.OwnerUserID, s.config); err != nil {
return nil, err
}
userIDs := append(append(req.MemberUserIDs, req.AdminUserIDs...), req.OwnerUserID)
@@ -219,7 +216,7 @@ func (s *groupServer) CreateGroup(ctx context.Context, req *pbgroup.CreateGroupR
return nil, errs.ErrUserIDNotFound.Wrap("user not found")
}
// Callback Before create Group
- if err := CallbackBeforeCreateGroup(ctx, req); err != nil {
+ if err := CallbackBeforeCreateGroup(ctx, s.config, req); err != nil {
return nil, err
}
var groupMembers []*relationtb.GroupMemberModel
@@ -238,7 +235,7 @@ func (s *groupServer) CreateGroup(ctx context.Context, req *pbgroup.CreateGroupR
JoinTime: time.Now(),
MuteEndTime: time.UnixMilli(0),
}
- if err := CallbackBeforeMemberJoinGroup(ctx, groupMember, group.Ex); err != nil {
+ if err := CallbackBeforeMemberJoinGroup(ctx, s.config, groupMember, group.Ex); err != nil {
return err
}
groupMembers = append(groupMembers, groupMember)
@@ -306,7 +303,7 @@ func (s *groupServer) CreateGroup(ctx context.Context, req *pbgroup.CreateGroupR
AdminUserIDs: req.AdminUserIDs,
}
- if err := CallbackAfterCreateGroup(ctx, reqCallBackAfter); err != nil {
+ if err := CallbackAfterCreateGroup(ctx, s.config, reqCallBackAfter); err != nil {
return nil, err
}
@@ -315,7 +312,7 @@ func (s *groupServer) CreateGroup(ctx context.Context, req *pbgroup.CreateGroupR
func (s *groupServer) GetJoinedGroupList(ctx context.Context, req *pbgroup.GetJoinedGroupListReq) (*pbgroup.GetJoinedGroupListResp, error) {
resp := &pbgroup.GetJoinedGroupListResp{}
- if err := authverify.CheckAccessV3(ctx, req.FromUserID); err != nil {
+ if err := authverify.CheckAccessV3(ctx, req.FromUserID, s.config); err != nil {
return nil, err
}
total, members, err := s.db.PageGetJoinGroup(ctx, req.FromUserID, req.Pagination)
@@ -385,7 +382,7 @@ func (s *groupServer) InviteUserToGroup(ctx context.Context, req *pbgroup.Invite
}
var groupMember *relationtb.GroupMemberModel
var opUserID string
- if !authverify.IsAppManagerUid(ctx) {
+ if !authverify.IsAppManagerUid(ctx, s.config) {
opUserID = mcontext.GetOpUserID(ctx)
var err error
groupMember, err = s.db.TakeGroupMember(ctx, req.GroupID, opUserID)
@@ -397,11 +394,11 @@ func (s *groupServer) InviteUserToGroup(ctx context.Context, req *pbgroup.Invite
}
}
- if err := CallbackBeforeInviteUserToGroup(ctx, req); err != nil {
+ if err := CallbackBeforeInviteUserToGroup(ctx, s.config, req); err != nil {
return nil, err
}
if group.NeedVerification == constant.AllNeedVerification {
- if !authverify.IsAppManagerUid(ctx) {
+ if !authverify.IsAppManagerUid(ctx, s.config) {
if !(groupMember.RoleLevel == constant.GroupOwner || groupMember.RoleLevel == constant.GroupAdmin) {
var requests []*relationtb.GroupRequestModel
for _, userID := range req.InvitedUserIDs {
@@ -441,7 +438,7 @@ func (s *groupServer) InviteUserToGroup(ctx context.Context, req *pbgroup.Invite
JoinTime: time.Now(),
MuteEndTime: time.UnixMilli(0),
}
- if err := CallbackBeforeMemberJoinGroup(ctx, member, group.Ex); err != nil {
+ if err := CallbackBeforeMemberJoinGroup(ctx, s.config, member, group.Ex); err != nil {
return nil, err
}
groupMembers = append(groupMembers, member)
@@ -541,7 +538,7 @@ func (s *groupServer) KickGroupMember(ctx context.Context, req *pbgroup.KickGrou
for i, member := range members {
memberMap[member.UserID] = members[i]
}
- isAppManagerUid := authverify.IsAppManagerUid(ctx)
+ isAppManagerUid := authverify.IsAppManagerUid(ctx, s.config)
opMember := memberMap[opUserID]
for _, userID := range req.KickedUserIDs {
member, ok := memberMap[userID]
@@ -613,7 +610,7 @@ func (s *groupServer) KickGroupMember(ctx context.Context, req *pbgroup.KickGrou
return nil, err
}
- if err := CallbackKillGroupMember(ctx, req); err != nil {
+ if err := CallbackKillGroupMember(ctx, s.config, req); err != nil {
return nil, err
}
return resp, nil
@@ -739,7 +736,7 @@ func (s *groupServer) GroupApplicationResponse(ctx context.Context, req *pbgroup
if !utils.Contain(req.HandleResult, constant.GroupResponseAgree, constant.GroupResponseRefuse) {
return nil, errs.ErrArgs.Wrap("HandleResult unknown")
}
- if !authverify.IsAppManagerUid(ctx) {
+ if !authverify.IsAppManagerUid(ctx, s.config) {
groupMember, err := s.db.TakeGroupMember(ctx, req.GroupID, mcontext.GetOpUserID(ctx))
if err != nil {
return nil, err
@@ -761,7 +758,7 @@ func (s *groupServer) GroupApplicationResponse(ctx context.Context, req *pbgroup
}
var inGroup bool
if _, err := s.db.TakeGroupMember(ctx, req.GroupID, req.FromUserID); err == nil {
- inGroup = true // 已经在群里了
+ inGroup = true // Already in group
} else if !s.IsNotFound(err) {
return nil, err
}
@@ -783,7 +780,7 @@ func (s *groupServer) GroupApplicationResponse(ctx context.Context, req *pbgroup
OperatorUserID: mcontext.GetOpUserID(ctx),
Ex: groupRequest.Ex,
}
- if err = CallbackBeforeMemberJoinGroup(ctx, member, group.Ex); err != nil {
+ if err = CallbackBeforeMemberJoinGroup(ctx, s.config, member, group.Ex); err != nil {
return nil, err
}
}
@@ -831,7 +828,7 @@ func (s *groupServer) JoinGroup(ctx context.Context, req *pbgroup.JoinGroupReq)
Ex: req.Ex,
}
- if err = CallbackApplyJoinGroupBefore(ctx, reqCall); err != nil {
+ if err = CallbackApplyJoinGroupBefore(ctx, s.config, reqCall); err != nil {
return nil, err
}
_, err = s.db.TakeGroupMember(ctx, req.GroupID, req.InviterUserID)
@@ -852,7 +849,7 @@ func (s *groupServer) JoinGroup(ctx context.Context, req *pbgroup.JoinGroupReq)
JoinTime: time.Now(),
MuteEndTime: time.UnixMilli(0),
}
- if err := CallbackBeforeMemberJoinGroup(ctx, groupMember, group.Ex); err != nil {
+ if err := CallbackBeforeMemberJoinGroup(ctx, s.config, groupMember, group.Ex); err != nil {
return nil, err
}
if err := s.db.CreateGroup(ctx, nil, []*relationtb.GroupMemberModel{groupMember}); err != nil {
@@ -863,7 +860,7 @@ func (s *groupServer) JoinGroup(ctx context.Context, req *pbgroup.JoinGroupReq)
return nil, err
}
s.Notification.MemberEnterNotification(ctx, req.GroupID, req.InviterUserID)
- if err = CallbackAfterJoinGroup(ctx, req); err != nil {
+ if err = CallbackAfterJoinGroup(ctx, s.config, req); err != nil {
return nil, err
}
return resp, nil
@@ -877,7 +874,7 @@ func (s *groupServer) JoinGroup(ctx context.Context, req *pbgroup.JoinGroupReq)
HandledTime: time.Unix(0, 0),
Ex: req.Ex,
}
- if err := s.db.CreateGroupRequest(ctx, []*relationtb.GroupRequestModel{&groupRequest}); err != nil {
+ if err = s.db.CreateGroupRequest(ctx, []*relationtb.GroupRequestModel{&groupRequest}); err != nil {
return nil, err
}
s.Notification.JoinGroupApplicationNotification(ctx, req)
@@ -889,7 +886,7 @@ func (s *groupServer) QuitGroup(ctx context.Context, req *pbgroup.QuitGroupReq)
if req.UserID == "" {
req.UserID = mcontext.GetOpUserID(ctx)
} else {
- if err := authverify.CheckAccessV3(ctx, req.UserID); err != nil {
+ if err := authverify.CheckAccessV3(ctx, req.UserID, s.config); err != nil {
return nil, err
}
}
@@ -913,7 +910,7 @@ func (s *groupServer) QuitGroup(ctx context.Context, req *pbgroup.QuitGroupReq)
}
// callback
- if err := CallbackQuitGroup(ctx, req); err != nil {
+ if err := CallbackQuitGroup(ctx, s.config, req); err != nil {
return nil, err
}
return resp, nil
@@ -930,7 +927,7 @@ func (s *groupServer) deleteMemberAndSetConversationSeq(ctx context.Context, gro
func (s *groupServer) SetGroupInfo(ctx context.Context, req *pbgroup.SetGroupInfoReq) (*pbgroup.SetGroupInfoResp, error) {
var opMember *relationtb.GroupMemberModel
- if !authverify.IsAppManagerUid(ctx) {
+ if !authverify.IsAppManagerUid(ctx, s.config) {
var err error
opMember, err = s.db.TakeGroupMember(ctx, req.GroupInfoForSet.GroupID, mcontext.GetOpUserID(ctx))
if err != nil {
@@ -943,7 +940,7 @@ func (s *groupServer) SetGroupInfo(ctx context.Context, req *pbgroup.SetGroupInf
return nil, err
}
}
- if err := CallbackBeforeSetGroupInfo(ctx, req); err != nil {
+ if err := CallbackBeforeSetGroupInfo(ctx, s.config, req); err != nil {
return nil, err
}
group, err := s.db.TakeGroup(ctx, req.GroupInfoForSet.GroupID)
@@ -951,7 +948,7 @@ func (s *groupServer) SetGroupInfo(ctx context.Context, req *pbgroup.SetGroupInf
return nil, err
}
if group.Status == constant.GroupStatusDismissed {
- return nil, utils.Wrap(errs.ErrDismissedAlready, "")
+ return nil, errs.Wrap(errs.ErrDismissedAlready)
}
resp := &pbgroup.SetGroupInfoResp{}
count, err := s.db.FindGroupMemberNum(ctx, group.GroupID)
@@ -1012,7 +1009,7 @@ func (s *groupServer) SetGroupInfo(ctx context.Context, req *pbgroup.SetGroupInf
if num > 0 {
_ = s.Notification.GroupInfoSetNotification(ctx, tips)
}
- if err := CallbackAfterSetGroupInfo(ctx, req); err != nil {
+ if err := CallbackAfterSetGroupInfo(ctx, s.config, req); err != nil {
return nil, err
}
return resp, nil
@@ -1049,7 +1046,7 @@ func (s *groupServer) TransferGroupOwner(ctx context.Context, req *pbgroup.Trans
if newOwner == nil {
return nil, errs.ErrArgs.Wrap("NewOwnerUser not in group " + req.NewOwnerUserID)
}
- if !authverify.IsAppManagerUid(ctx) {
+ if !authverify.IsAppManagerUid(ctx, s.config) {
if !(mcontext.GetOpUserID(ctx) == oldOwner.UserID && oldOwner.RoleLevel == constant.GroupOwner) {
return nil, errs.ErrNoPermission.Wrap("no permission transfer group owner")
}
@@ -1058,7 +1055,7 @@ func (s *groupServer) TransferGroupOwner(ctx context.Context, req *pbgroup.Trans
return nil, err
}
- if err := CallbackAfterTransferGroupOwner(ctx, req); err != nil {
+ if err := CallbackAfterTransferGroupOwner(ctx, s.config, req); err != nil {
return nil, err
}
s.Notification.GroupOwnerTransferredNotification(ctx, req)
@@ -1190,7 +1187,7 @@ func (s *groupServer) DismissGroup(ctx context.Context, req *pbgroup.DismissGrou
if err != nil {
return nil, err
}
- if !authverify.IsAppManagerUid(ctx) {
+ if !authverify.IsAppManagerUid(ctx, s.config) {
if owner.UserID != mcontext.GetOpUserID(ctx) {
return nil, errs.ErrNoPermission.Wrap("not group owner")
}
@@ -1202,7 +1199,7 @@ func (s *groupServer) DismissGroup(ctx context.Context, req *pbgroup.DismissGrou
if err != nil {
return nil, err
}
- if req.DeleteMember == false && group.Status == constant.GroupStatusDismissed {
+ if !req.DeleteMember && group.Status == constant.GroupStatusDismissed {
return nil, errs.ErrDismissedAlready.Wrap("group status is dismissed")
}
if err := s.db.DismissGroup(ctx, req.GroupID, req.DeleteMember); err != nil {
@@ -1232,7 +1229,7 @@ func (s *groupServer) DismissGroup(ctx context.Context, req *pbgroup.DismissGrou
MembersID: membersID,
GroupType: string(group.GroupType),
}
- if err := CallbackDismissGroup(ctx, reqCall); err != nil {
+ if err := CallbackDismissGroup(ctx, s.config, reqCall); err != nil {
return nil, err
}
@@ -1248,7 +1245,7 @@ func (s *groupServer) MuteGroupMember(ctx context.Context, req *pbgroup.MuteGrou
if err := s.PopulateGroupMember(ctx, member); err != nil {
return nil, err
}
- if !authverify.IsAppManagerUid(ctx) {
+ if !authverify.IsAppManagerUid(ctx, s.config) {
opMember, err := s.db.TakeGroupMember(ctx, req.GroupID, mcontext.GetOpUserID(ctx))
if err != nil {
return nil, err
@@ -1282,7 +1279,7 @@ func (s *groupServer) CancelMuteGroupMember(ctx context.Context, req *pbgroup.Ca
if err := s.PopulateGroupMember(ctx, member); err != nil {
return nil, err
}
- if !authverify.IsAppManagerUid(ctx) {
+ if !authverify.IsAppManagerUid(ctx, s.config) {
opMember, err := s.db.TakeGroupMember(ctx, req.GroupID, mcontext.GetOpUserID(ctx))
if err != nil {
return nil, err
@@ -1341,7 +1338,7 @@ func (s *groupServer) SetGroupMemberInfo(ctx context.Context, req *pbgroup.SetGr
if opUserID == "" {
return nil, errs.ErrNoPermission.Wrap("no op user id")
}
- isAppManagerUid := authverify.IsAppManagerUid(ctx)
+ isAppManagerUid := authverify.IsAppManagerUid(ctx, s.config)
for i := range req.Members {
req.Members[i].FaceURL = nil
}
@@ -1424,7 +1421,7 @@ func (s *groupServer) SetGroupMemberInfo(ctx context.Context, req *pbgroup.SetGr
}
}
for i := 0; i < len(req.Members); i++ {
- if err := CallbackBeforeSetGroupMemberInfo(ctx, req.Members[i]); err != nil {
+ if err := CallbackBeforeSetGroupMemberInfo(ctx, s.config, req.Members[i]); err != nil {
return nil, err
}
}
@@ -1451,7 +1448,7 @@ func (s *groupServer) SetGroupMemberInfo(ctx context.Context, req *pbgroup.SetGr
}
}
for i := 0; i < len(req.Members); i++ {
- if err := CallbackAfterSetGroupMemberInfo(ctx, req.Members[i]); err != nil {
+ if err := CallbackAfterSetGroupMemberInfo(ctx, s.config, req.Members[i]); err != nil {
return nil, err
}
}
diff --git a/internal/rpc/msg/as_read.go b/internal/rpc/msg/as_read.go
index 5a4f8b5f3..ef7c72368 100644
--- a/internal/rpc/msg/as_read.go
+++ b/internal/rpc/msg/as_read.go
@@ -17,17 +17,14 @@ package msg
import (
"context"
- utils2 "github.com/OpenIMSDK/tools/utils"
-
- cbapi "github.com/openimsdk/open-im-server/v3/pkg/callbackstruct"
-
- "github.com/redis/go-redis/v9"
-
"github.com/OpenIMSDK/protocol/constant"
"github.com/OpenIMSDK/protocol/msg"
"github.com/OpenIMSDK/protocol/sdkws"
"github.com/OpenIMSDK/tools/errs"
"github.com/OpenIMSDK/tools/log"
+ utils2 "github.com/OpenIMSDK/tools/utils"
+ cbapi "github.com/openimsdk/open-im-server/v3/pkg/callbackstruct"
+ "github.com/redis/go-redis/v9"
)
func (m *msgServer) GetConversationsHasReadAndMaxSeq(ctx context.Context, req *msg.GetConversationsHasReadAndMaxSeqReq) (resp *msg.GetConversationsHasReadAndMaxSeqResp, err error) {
@@ -132,7 +129,7 @@ func (m *msgServer) MarkMsgsAsRead(
Seqs: req.Seqs,
ContentType: conversation.ConversationType,
}
- if err = CallbackSingleMsgRead(ctx, req_callback); err != nil {
+ if err = CallbackSingleMsgRead(ctx, m.config, req_callback); err != nil {
return nil, err
}
@@ -209,7 +206,7 @@ func (m *msgServer) MarkConversationAsRead(
UnreadMsgNum: req.HasReadSeq,
ContentType: int64(conversation.ConversationType),
}
- if err := CallbackGroupMsgRead(ctx, reqCall); err != nil {
+ if err := CallbackGroupMsgRead(ctx, m.config, reqCall); err != nil {
return nil, err
}
diff --git a/internal/rpc/msg/callback.go b/internal/rpc/msg/callback.go
index f98318bba..536402bf9 100644
--- a/internal/rpc/msg/callback.go
+++ b/internal/rpc/msg/callback.go
@@ -17,25 +17,18 @@ package msg
import (
"context"
- "github.com/OpenIMSDK/protocol/sdkws"
- "google.golang.org/protobuf/proto"
-
"github.com/OpenIMSDK/protocol/constant"
pbchat "github.com/OpenIMSDK/protocol/msg"
+ "github.com/OpenIMSDK/protocol/sdkws"
"github.com/OpenIMSDK/tools/log"
"github.com/OpenIMSDK/tools/mcontext"
"github.com/OpenIMSDK/tools/utils"
-
cbapi "github.com/openimsdk/open-im-server/v3/pkg/callbackstruct"
-
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
"github.com/openimsdk/open-im-server/v3/pkg/common/http"
+ "google.golang.org/protobuf/proto"
)
-func cbURL() string {
- return config.Config.Callback.CallbackUrl
-}
-
func toCommonCallback(ctx context.Context, msg *pbchat.SendMsgReq, command string) cbapi.CommonCallbackReq {
return cbapi.CommonCallbackReq{
SendID: msg.MsgData.SendID,
@@ -69,8 +62,8 @@ func GetContent(msg *sdkws.MsgData) string {
}
}
-func callbackBeforeSendSingleMsg(ctx context.Context, msg *pbchat.SendMsgReq) error {
- if !config.Config.Callback.CallbackBeforeSendSingleMsg.Enable || msg.MsgData.ContentType == constant.Typing {
+func callbackBeforeSendSingleMsg(ctx context.Context, globalConfig *config.GlobalConfig, msg *pbchat.SendMsgReq) error {
+ if !globalConfig.Callback.CallbackBeforeSendSingleMsg.Enable || msg.MsgData.ContentType == constant.Typing {
return nil
}
req := &cbapi.CallbackBeforeSendSingleMsgReq{
@@ -78,14 +71,14 @@ func callbackBeforeSendSingleMsg(ctx context.Context, msg *pbchat.SendMsgReq) er
RecvID: msg.MsgData.RecvID,
}
resp := &cbapi.CallbackBeforeSendSingleMsgResp{}
- if err := http.CallBackPostReturn(ctx, cbURL(), req, resp, config.Config.Callback.CallbackBeforeSendSingleMsg); err != nil {
+ if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, req, resp, globalConfig.Callback.CallbackBeforeSendSingleMsg); err != nil {
return err
}
return nil
}
-func callbackAfterSendSingleMsg(ctx context.Context, msg *pbchat.SendMsgReq) error {
- if !config.Config.Callback.CallbackAfterSendSingleMsg.Enable || msg.MsgData.ContentType == constant.Typing {
+func callbackAfterSendSingleMsg(ctx context.Context, globalConfig *config.GlobalConfig, msg *pbchat.SendMsgReq) error {
+ if !globalConfig.Callback.CallbackAfterSendSingleMsg.Enable || msg.MsgData.ContentType == constant.Typing {
return nil
}
req := &cbapi.CallbackAfterSendSingleMsgReq{
@@ -93,14 +86,14 @@ func callbackAfterSendSingleMsg(ctx context.Context, msg *pbchat.SendMsgReq) err
RecvID: msg.MsgData.RecvID,
}
resp := &cbapi.CallbackAfterSendSingleMsgResp{}
- if err := http.CallBackPostReturn(ctx, cbURL(), req, resp, config.Config.Callback.CallbackAfterSendSingleMsg); err != nil {
+ if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, req, resp, globalConfig.Callback.CallbackAfterSendSingleMsg); err != nil {
return err
}
return nil
}
-func callbackBeforeSendGroupMsg(ctx context.Context, msg *pbchat.SendMsgReq) error {
- if !config.Config.Callback.CallbackBeforeSendGroupMsg.Enable || msg.MsgData.ContentType == constant.Typing {
+func callbackBeforeSendGroupMsg(ctx context.Context, globalConfig *config.GlobalConfig, msg *pbchat.SendMsgReq) error {
+ if !globalConfig.Callback.CallbackBeforeSendGroupMsg.Enable || msg.MsgData.ContentType == constant.Typing {
return nil
}
req := &cbapi.CallbackBeforeSendGroupMsgReq{
@@ -108,14 +101,14 @@ func callbackBeforeSendGroupMsg(ctx context.Context, msg *pbchat.SendMsgReq) err
GroupID: msg.MsgData.GroupID,
}
resp := &cbapi.CallbackBeforeSendGroupMsgResp{}
- if err := http.CallBackPostReturn(ctx, cbURL(), req, resp, config.Config.Callback.CallbackBeforeSendGroupMsg); err != nil {
+ if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, req, resp, globalConfig.Callback.CallbackBeforeSendGroupMsg); err != nil {
return err
}
return nil
}
-func callbackAfterSendGroupMsg(ctx context.Context, msg *pbchat.SendMsgReq) error {
- if !config.Config.Callback.CallbackAfterSendGroupMsg.Enable || msg.MsgData.ContentType == constant.Typing {
+func callbackAfterSendGroupMsg(ctx context.Context, globalConfig *config.GlobalConfig, msg *pbchat.SendMsgReq) error {
+ if !globalConfig.Callback.CallbackAfterSendGroupMsg.Enable || msg.MsgData.ContentType == constant.Typing {
return nil
}
req := &cbapi.CallbackAfterSendGroupMsgReq{
@@ -123,21 +116,21 @@ func callbackAfterSendGroupMsg(ctx context.Context, msg *pbchat.SendMsgReq) erro
GroupID: msg.MsgData.GroupID,
}
resp := &cbapi.CallbackAfterSendGroupMsgResp{}
- if err := http.CallBackPostReturn(ctx, cbURL(), req, resp, config.Config.Callback.CallbackAfterSendGroupMsg); err != nil {
+ if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, req, resp, globalConfig.Callback.CallbackAfterSendGroupMsg); err != nil {
return err
}
return nil
}
-func callbackMsgModify(ctx context.Context, msg *pbchat.SendMsgReq) error {
- if !config.Config.Callback.CallbackMsgModify.Enable || msg.MsgData.ContentType != constant.Text {
+func callbackMsgModify(ctx context.Context, globalConfig *config.GlobalConfig, msg *pbchat.SendMsgReq) error {
+ if !globalConfig.Callback.CallbackMsgModify.Enable || msg.MsgData.ContentType != constant.Text {
return nil
}
req := &cbapi.CallbackMsgModifyCommandReq{
CommonCallbackReq: toCommonCallback(ctx, msg, cbapi.CallbackMsgModifyCommand),
}
resp := &cbapi.CallbackMsgModifyCommandResp{}
- if err := http.CallBackPostReturn(ctx, cbURL(), req, resp, config.Config.Callback.CallbackMsgModify); err != nil {
+ if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, req, resp, globalConfig.Callback.CallbackMsgModify); err != nil {
return err
}
if resp.Content != nil {
@@ -162,34 +155,34 @@ func callbackMsgModify(ctx context.Context, msg *pbchat.SendMsgReq) error {
log.ZDebug(ctx, "callbackMsgModify", "msg", msg.MsgData)
return nil
}
-func CallbackGroupMsgRead(ctx context.Context, req *cbapi.CallbackGroupMsgReadReq) error {
- if !config.Config.Callback.CallbackGroupMsgRead.Enable || req.ContentType != constant.Text {
+func CallbackGroupMsgRead(ctx context.Context, globalConfig *config.GlobalConfig, req *cbapi.CallbackGroupMsgReadReq) error {
+ if !globalConfig.Callback.CallbackGroupMsgRead.Enable || req.ContentType != constant.Text {
return nil
}
req.CallbackCommand = cbapi.CallbackGroupMsgReadCommand
resp := &cbapi.CallbackGroupMsgReadResp{}
- if err := http.CallBackPostReturn(ctx, cbURL(), req, resp, config.Config.Callback.CallbackMsgModify); err != nil {
+ if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, req, resp, globalConfig.Callback.CallbackMsgModify); err != nil {
return err
}
return nil
}
-func CallbackSingleMsgRead(ctx context.Context, req *cbapi.CallbackSingleMsgReadReq) error {
- if !config.Config.Callback.CallbackSingleMsgRead.Enable || req.ContentType != constant.Text {
+func CallbackSingleMsgRead(ctx context.Context, globalConfig *config.GlobalConfig, req *cbapi.CallbackSingleMsgReadReq) error {
+ if !globalConfig.Callback.CallbackSingleMsgRead.Enable || req.ContentType != constant.Text {
return nil
}
req.CallbackCommand = cbapi.CallbackSingleMsgRead
resp := &cbapi.CallbackSingleMsgReadResp{}
- if err := http.CallBackPostReturn(ctx, cbURL(), req, resp, config.Config.Callback.CallbackMsgModify); err != nil {
+ if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, req, resp, globalConfig.Callback.CallbackMsgModify); err != nil {
return err
}
return nil
}
-func CallbackAfterRevokeMsg(ctx context.Context, req *pbchat.RevokeMsgReq) error {
- if !config.Config.Callback.CallbackAfterRevokeMsg.Enable {
+func CallbackAfterRevokeMsg(ctx context.Context, globalConfig *config.GlobalConfig, req *pbchat.RevokeMsgReq) error {
+ if !globalConfig.Callback.CallbackAfterRevokeMsg.Enable {
return nil
}
callbackReq := &cbapi.CallbackAfterRevokeMsgReq{
@@ -199,7 +192,7 @@ func CallbackAfterRevokeMsg(ctx context.Context, req *pbchat.RevokeMsgReq) error
UserID: req.UserID,
}
resp := &cbapi.CallbackAfterRevokeMsgResp{}
- if err := http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, callbackReq, resp, config.Config.Callback.CallbackAfterRevokeMsg); err != nil {
+ if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, callbackReq, resp, globalConfig.Callback.CallbackAfterRevokeMsg); err != nil {
return err
}
return nil
diff --git a/internal/rpc/msg/delete.go b/internal/rpc/msg/delete.go
index b5c23bed6..14e24d23e 100644
--- a/internal/rpc/msg/delete.go
+++ b/internal/rpc/msg/delete.go
@@ -17,14 +17,13 @@ package msg
import (
"context"
- "github.com/openimsdk/open-im-server/v3/pkg/authverify"
-
"github.com/OpenIMSDK/protocol/constant"
"github.com/OpenIMSDK/protocol/conversation"
"github.com/OpenIMSDK/protocol/msg"
"github.com/OpenIMSDK/protocol/sdkws"
"github.com/OpenIMSDK/tools/log"
"github.com/OpenIMSDK/tools/utils"
+ "github.com/openimsdk/open-im-server/v3/pkg/authverify"
)
func (m *msgServer) getMinSeqs(maxSeqs map[string]int64) map[string]int64 {
@@ -46,7 +45,7 @@ func (m *msgServer) ClearConversationsMsg(
ctx context.Context,
req *msg.ClearConversationsMsgReq,
) (*msg.ClearConversationsMsgResp, error) {
- if err := authverify.CheckAccessV3(ctx, req.UserID); err != nil {
+ if err := authverify.CheckAccessV3(ctx, req.UserID, m.config); err != nil {
return nil, err
}
if err := m.clearConversation(ctx, req.ConversationIDs, req.UserID, req.DeleteSyncOpt); err != nil {
@@ -59,7 +58,7 @@ func (m *msgServer) UserClearAllMsg(
ctx context.Context,
req *msg.UserClearAllMsgReq,
) (*msg.UserClearAllMsgResp, error) {
- if err := authverify.CheckAccessV3(ctx, req.UserID); err != nil {
+ if err := authverify.CheckAccessV3(ctx, req.UserID, m.config); err != nil {
return nil, err
}
conversationIDs, err := m.ConversationLocalCache.GetConversationIDs(ctx, req.UserID)
@@ -74,7 +73,7 @@ func (m *msgServer) UserClearAllMsg(
}
func (m *msgServer) DeleteMsgs(ctx context.Context, req *msg.DeleteMsgsReq) (*msg.DeleteMsgsResp, error) {
- if err := authverify.CheckAccessV3(ctx, req.UserID); err != nil {
+ if err := authverify.CheckAccessV3(ctx, req.UserID, m.config); err != nil {
return nil, err
}
isSyncSelf, isSyncOther := m.validateDeleteSyncOpt(req.DeleteSyncOpt)
@@ -122,7 +121,7 @@ func (m *msgServer) DeleteMsgPhysical(
ctx context.Context,
req *msg.DeleteMsgPhysicalReq,
) (*msg.DeleteMsgPhysicalResp, error) {
- if err := authverify.CheckAdmin(ctx); err != nil {
+ if err := authverify.CheckAdmin(ctx, m.config); err != nil {
return nil, err
}
remainTime := utils.GetCurrentTimestampBySecond() - req.Timestamp
diff --git a/internal/rpc/msg/message_interceptor.go b/internal/rpc/msg/message_interceptor.go
index a98c31219..97eac613d 100644
--- a/internal/rpc/msg/message_interceptor.go
+++ b/internal/rpc/msg/message_interceptor.go
@@ -21,21 +21,20 @@ import (
"github.com/OpenIMSDK/protocol/msg"
"github.com/OpenIMSDK/protocol/sdkws"
"github.com/OpenIMSDK/tools/errs"
-
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
)
-type MessageInterceptorFunc func(ctx context.Context, req *msg.SendMsgReq) (*sdkws.MsgData, error)
+type MessageInterceptorFunc func(ctx context.Context, globalConfig *config.GlobalConfig, req *msg.SendMsgReq) (*sdkws.MsgData, error)
-func MessageHasReadEnabled(_ context.Context, req *msg.SendMsgReq) (*sdkws.MsgData, error) {
+func MessageHasReadEnabled(_ context.Context, globalConfig *config.GlobalConfig, req *msg.SendMsgReq) (*sdkws.MsgData, error) {
switch {
case req.MsgData.ContentType == constant.HasReadReceipt && req.MsgData.SessionType == constant.SingleChatType:
- if !config.Config.SingleMessageHasReadReceiptEnable {
+ if !globalConfig.SingleMessageHasReadReceiptEnable {
return nil, errs.ErrMessageHasReadDisable.Wrap()
}
return req.MsgData, nil
case req.MsgData.ContentType == constant.HasReadReceipt && req.MsgData.SessionType == constant.SuperGroupChatType:
- if !config.Config.GroupMessageHasReadReceiptEnable {
+ if !globalConfig.GroupMessageHasReadReceiptEnable {
return nil, errs.ErrMessageHasReadDisable.Wrap()
}
return req.MsgData, nil
diff --git a/internal/rpc/msg/revoke.go b/internal/rpc/msg/revoke.go
index c7257215a..99690b0cc 100644
--- a/internal/rpc/msg/revoke.go
+++ b/internal/rpc/msg/revoke.go
@@ -19,8 +19,6 @@ import (
"encoding/json"
"time"
- "github.com/openimsdk/open-im-server/v3/pkg/authverify"
-
"github.com/OpenIMSDK/protocol/constant"
"github.com/OpenIMSDK/protocol/msg"
"github.com/OpenIMSDK/protocol/sdkws"
@@ -28,8 +26,7 @@ import (
"github.com/OpenIMSDK/tools/log"
"github.com/OpenIMSDK/tools/mcontext"
"github.com/OpenIMSDK/tools/utils"
-
- "github.com/openimsdk/open-im-server/v3/pkg/common/config"
+ "github.com/openimsdk/open-im-server/v3/pkg/authverify"
unrelationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/unrelation"
)
@@ -44,7 +41,7 @@ func (m *msgServer) RevokeMsg(ctx context.Context, req *msg.RevokeMsgReq) (*msg.
if req.Seq < 0 {
return nil, errs.ErrArgs.Wrap("seq is invalid")
}
- if err := authverify.CheckAccessV3(ctx, req.UserID); err != nil {
+ if err := authverify.CheckAccessV3(ctx, req.UserID, m.config); err != nil {
return nil, err
}
user, err := m.UserLocalCache.GetUserInfo(ctx, req.UserID)
@@ -65,10 +62,10 @@ func (m *msgServer) RevokeMsg(ctx context.Context, req *msg.RevokeMsgReq) (*msg.
data, _ := json.Marshal(msgs[0])
log.ZInfo(ctx, "GetMsgBySeqs", "conversationID", req.ConversationID, "seq", req.Seq, "msg", string(data))
var role int32
- if !authverify.IsAppManagerUid(ctx) {
+ if !authverify.IsAppManagerUid(ctx, m.config) {
switch msgs[0].SessionType {
case constant.SingleChatType:
- if err := authverify.CheckAccessV3(ctx, msgs[0].SendID); err != nil {
+ if err := authverify.CheckAccessV3(ctx, msgs[0].SendID, m.config); err != nil {
return nil, err
}
role = user.AppMangerLevel
@@ -107,11 +104,11 @@ func (m *msgServer) RevokeMsg(ctx context.Context, req *msg.RevokeMsgReq) (*msg.
}
revokerUserID := mcontext.GetOpUserID(ctx)
var flag bool
- if len(config.Config.Manager.UserID) > 0 {
- flag = utils.Contain(revokerUserID, config.Config.Manager.UserID...)
+ if len(m.config.Manager.UserID) > 0 {
+ flag = utils.Contain(revokerUserID, m.config.Manager.UserID...)
}
- if len(config.Config.Manager.UserID) == 0 && len(config.Config.IMAdmin.UserID) > 0 {
- flag = utils.Contain(revokerUserID, config.Config.IMAdmin.UserID...)
+ if len(m.config.Manager.UserID) == 0 && len(m.config.IMAdmin.UserID) > 0 {
+ flag = utils.Contain(revokerUserID, m.config.IMAdmin.UserID...)
}
tips := sdkws.RevokeMsgTips{
RevokerUserID: revokerUserID,
@@ -131,7 +128,7 @@ func (m *msgServer) RevokeMsg(ctx context.Context, req *msg.RevokeMsgReq) (*msg.
if err := m.notificationSender.NotificationWithSesstionType(ctx, req.UserID, recvID, constant.MsgRevokeNotification, msgs[0].SessionType, &tips); err != nil {
return nil, err
}
- if err = CallbackAfterRevokeMsg(ctx, req); err != nil {
+ if err = CallbackAfterRevokeMsg(ctx, m.config, req); err != nil {
return nil, err
}
return &msg.RevokeMsgResp{}, nil
diff --git a/internal/rpc/msg/send.go b/internal/rpc/msg/send.go
index 20e3f85f1..ea59c40cf 100644
--- a/internal/rpc/msg/send.go
+++ b/internal/rpc/msg/send.go
@@ -17,9 +17,6 @@ package msg
import (
"context"
- "github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics"
- "github.com/openimsdk/open-im-server/v3/pkg/msgprocessor"
-
"github.com/OpenIMSDK/protocol/constant"
pbconversation "github.com/OpenIMSDK/protocol/conversation"
pbmsg "github.com/OpenIMSDK/protocol/msg"
@@ -29,12 +26,14 @@ import (
"github.com/OpenIMSDK/tools/log"
"github.com/OpenIMSDK/tools/mcontext"
"github.com/OpenIMSDK/tools/utils"
+ "github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics"
+ "github.com/openimsdk/open-im-server/v3/pkg/msgprocessor"
)
func (m *msgServer) SendMsg(ctx context.Context, req *pbmsg.SendMsgReq) (resp *pbmsg.SendMsgResp, error error) {
resp = &pbmsg.SendMsgResp{}
if req.MsgData != nil {
- flag := isMessageHasReadEnabled(req.MsgData)
+ flag := isMessageHasReadEnabled(req.MsgData, m.config)
if !flag {
return nil, errs.ErrMessageHasReadDisable.Wrap()
}
@@ -62,11 +61,11 @@ func (m *msgServer) sendMsgSuperGroupChat(
prommetrics.GroupChatMsgProcessFailedCounter.Inc()
return nil, err
}
- if err = callbackBeforeSendGroupMsg(ctx, req); err != nil {
+ if err = callbackBeforeSendGroupMsg(ctx, m.config, req); err != nil {
return nil, err
}
- if err := callbackMsgModify(ctx, req); err != nil {
+ if err := callbackMsgModify(ctx, m.config, req); err != nil {
return nil, err
}
err = m.MsgDatabase.MsgToMQ(ctx, utils.GenConversationUniqueKeyForGroup(req.MsgData.GroupID), req.MsgData)
@@ -76,7 +75,7 @@ func (m *msgServer) sendMsgSuperGroupChat(
if req.MsgData.ContentType == constant.AtText {
go m.setConversationAtInfo(ctx, req.MsgData)
}
- if err = callbackAfterSendGroupMsg(ctx, req); err != nil {
+ if err = callbackAfterSendGroupMsg(ctx, m.config, req); err != nil {
log.ZWarn(ctx, "CallbackAfterSendGroupMsg", err)
}
prommetrics.GroupChatMsgProcessSuccessCounter.Inc()
@@ -108,7 +107,7 @@ func (m *msgServer) setConversationAtInfo(nctx context.Context, msg *sdkws.MsgDa
conversation.GroupAtType = &wrapperspb.Int32Value{Value: constant.AtAll}
} else { //@Everyone and @other people
conversation.GroupAtType = &wrapperspb.Int32Value{Value: constant.AtAllAtMe}
- err := m.Conversation.SetConversations(ctx, atUserID, conversation)
+ err = m.Conversation.SetConversations(ctx, atUserID, conversation)
if err != nil {
log.ZWarn(ctx, "SetConversations", err, "userID", atUserID, "conversation", conversation)
}
@@ -166,18 +165,18 @@ func (m *msgServer) sendMsgSingleChat(ctx context.Context, req *pbmsg.SendMsgReq
prommetrics.SingleChatMsgProcessFailedCounter.Inc()
return nil, nil
} else {
- if err = callbackBeforeSendSingleMsg(ctx, req); err != nil {
+ if err = callbackBeforeSendSingleMsg(ctx, m.config, req); err != nil {
return nil, err
}
- if err := callbackMsgModify(ctx, req); err != nil {
+ if err := callbackMsgModify(ctx, m.config, req); err != nil {
return nil, err
}
if err := m.MsgDatabase.MsgToMQ(ctx, utils.GenConversationUniqueKeyForSingle(req.MsgData.SendID, req.MsgData.RecvID), req.MsgData); err != nil {
prommetrics.SingleChatMsgProcessFailedCounter.Inc()
return nil, err
}
- err = callbackAfterSendSingleMsg(ctx, req)
+ err = callbackAfterSendSingleMsg(ctx, m.config, req)
if err != nil {
log.ZWarn(ctx, "CallbackAfterSendSingleMsg", err, "req", req)
}
diff --git a/internal/rpc/msg/server.go b/internal/rpc/msg/server.go
index e1593443d..726cc3420 100644
--- a/internal/rpc/msg/server.go
+++ b/internal/rpc/msg/server.go
@@ -24,11 +24,12 @@ import (
"github.com/OpenIMSDK/protocol/conversation"
"github.com/OpenIMSDK/protocol/msg"
"github.com/OpenIMSDK/tools/discoveryregistry"
-
+ "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/unrelation"
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
+ "google.golang.org/grpc"
)
type (
@@ -43,6 +44,7 @@ type (
ConversationLocalCache *rpccache.ConversationLocalCache
Handlers MessageInterceptorChain
notificationSender *rpcclient.NotificationSender
+ config *config.GlobalConfig
}
)
@@ -50,37 +52,39 @@ func (m *msgServer) addInterceptorHandler(interceptorFunc ...MessageInterceptorF
m.Handlers = append(m.Handlers, interceptorFunc...)
}
-func (m *msgServer) execInterceptorHandler(ctx context.Context, req *msg.SendMsgReq) error {
- for _, handler := range m.Handlers {
- msgData, err := handler(ctx, req)
- if err != nil {
- return err
- }
- req.MsgData = msgData
- }
- return nil
-}
+//func (m *msgServer) execInterceptorHandler(ctx context.Context, config *config.GlobalConfig, req *msg.SendMsgReq) error {
+// for _, handler := range m.Handlers {
+// msgData, err := handler(ctx, config, req)
+// if err != nil {
+// return err
+// }
+// req.MsgData = msgData
+// }
+// return nil
+//}
-func Start(client discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) error {
- rdb, err := cache.NewRedis()
+func Start(config *config.GlobalConfig, client discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) error {
+ rdb, err := cache.NewRedis(config)
if err != nil {
return err
}
- mongo, err := unrelation.NewMongo()
+ mongo, err := unrelation.NewMongo(config)
if err != nil {
return err
}
if err := mongo.CreateMsgIndex(); err != nil {
return err
}
- cacheModel := cache.NewMsgCacheModel(rdb)
- msgDocModel := unrelation.NewMsgMongoDriver(mongo.GetDatabase())
- conversationClient := rpcclient.NewConversationRpcClient(client)
- userRpcClient := rpcclient.NewUserRpcClient(client)
- groupRpcClient := rpcclient.NewGroupRpcClient(client)
- friendRpcClient := rpcclient.NewFriendRpcClient(client)
- msgDatabase := controller.NewCommonMsgDatabase(msgDocModel, cacheModel)
-
+ cacheModel := cache.NewMsgCacheModel(rdb, config)
+ msgDocModel := unrelation.NewMsgMongoDriver(mongo.GetDatabase(config.Mongo.Database))
+ conversationClient := rpcclient.NewConversationRpcClient(client, config)
+ userRpcClient := rpcclient.NewUserRpcClient(client, config)
+ groupRpcClient := rpcclient.NewGroupRpcClient(client, config)
+ friendRpcClient := rpcclient.NewFriendRpcClient(client, config)
+ msgDatabase, err := controller.NewCommonMsgDatabase(msgDocModel, cacheModel, config)
+ if err != nil {
+ return err
+ }
s := &msgServer{
Conversation: &conversationClient,
MsgDatabase: msgDatabase,
@@ -89,8 +93,9 @@ func Start(client discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) e
GroupLocalCache: rpccache.NewGroupLocalCache(groupRpcClient, rdb),
ConversationLocalCache: rpccache.NewConversationLocalCache(conversationClient, rdb),
FriendLocalCache: rpccache.NewFriendLocalCache(friendRpcClient, rdb),
+ config: config,
}
- s.notificationSender = rpcclient.NewNotificationSender(rpcclient.WithLocalSendMsg(s.SendMsg))
+ s.notificationSender = rpcclient.NewNotificationSender(config, rpcclient.WithLocalSendMsg(s.SendMsg))
s.addInterceptorHandler(MessageHasReadEnabled)
msg.RegisterMsgServer(server, s)
return nil
diff --git a/internal/rpc/msg/statistics.go b/internal/rpc/msg/statistics.go
index 620e6c7b0..e62954dea 100644
--- a/internal/rpc/msg/statistics.go
+++ b/internal/rpc/msg/statistics.go
@@ -21,7 +21,6 @@ import (
"github.com/OpenIMSDK/protocol/msg"
"github.com/OpenIMSDK/protocol/sdkws"
"github.com/OpenIMSDK/tools/utils"
-
"github.com/openimsdk/open-im-server/v3/pkg/common/db/table/unrelation"
)
diff --git a/internal/rpc/msg/sync_msg.go b/internal/rpc/msg/sync_msg.go
index 404ca6218..6fa4a0c9d 100644
--- a/internal/rpc/msg/sync_msg.go
+++ b/internal/rpc/msg/sync_msg.go
@@ -17,15 +17,13 @@ package msg
import (
"context"
- "github.com/openimsdk/open-im-server/v3/pkg/authverify"
- "github.com/openimsdk/open-im-server/v3/pkg/msgprocessor"
-
"github.com/OpenIMSDK/protocol/constant"
"github.com/OpenIMSDK/protocol/msg"
-
"github.com/OpenIMSDK/protocol/sdkws"
"github.com/OpenIMSDK/tools/log"
"github.com/OpenIMSDK/tools/utils"
+ "github.com/openimsdk/open-im-server/v3/pkg/authverify"
+ "github.com/openimsdk/open-im-server/v3/pkg/msgprocessor"
)
func (m *msgServer) PullMessageBySeqs(
@@ -90,7 +88,7 @@ func (m *msgServer) PullMessageBySeqs(
}
func (m *msgServer) GetMaxSeq(ctx context.Context, req *sdkws.GetMaxSeqReq) (*sdkws.GetMaxSeqResp, error) {
- if err := authverify.CheckAccessV3(ctx, req.UserID); err != nil {
+ if err := authverify.CheckAccessV3(ctx, req.UserID, m.config); err != nil {
return nil, err
}
conversationIDs, err := m.ConversationLocalCache.GetConversationIDs(ctx, req.UserID)
diff --git a/internal/rpc/msg/utils.go b/internal/rpc/msg/utils.go
index e45d7b395..48665562a 100644
--- a/internal/rpc/msg/utils.go
+++ b/internal/rpc/msg/utils.go
@@ -18,22 +18,21 @@ import (
"github.com/OpenIMSDK/protocol/constant"
"github.com/OpenIMSDK/protocol/sdkws"
"github.com/OpenIMSDK/tools/utils"
+ "github.com/openimsdk/open-im-server/v3/pkg/common/config"
"github.com/redis/go-redis/v9"
"go.mongodb.org/mongo-driver/mongo"
-
- "github.com/openimsdk/open-im-server/v3/pkg/common/config"
)
-func isMessageHasReadEnabled(msgData *sdkws.MsgData) bool {
+func isMessageHasReadEnabled(msgData *sdkws.MsgData, config *config.GlobalConfig) bool {
switch {
case msgData.ContentType == constant.HasReadReceipt && msgData.SessionType == constant.SingleChatType:
- if config.Config.SingleMessageHasReadReceiptEnable {
+ if config.SingleMessageHasReadReceiptEnable {
return true
} else {
return false
}
case msgData.ContentType == constant.HasReadReceipt && msgData.SessionType == constant.SuperGroupChatType:
- if config.Config.GroupMessageHasReadReceiptEnable {
+ if config.GroupMessageHasReadReceiptEnable {
return true
} else {
return false
diff --git a/internal/rpc/msg/verify.go b/internal/rpc/msg/verify.go
index 710e95411..b964eca9b 100644
--- a/internal/rpc/msg/verify.go
+++ b/internal/rpc/msg/verify.go
@@ -26,8 +26,6 @@ import (
"github.com/OpenIMSDK/protocol/sdkws"
"github.com/OpenIMSDK/tools/errs"
"github.com/OpenIMSDK/tools/utils"
-
- "github.com/openimsdk/open-im-server/v3/pkg/common/config"
)
var ExcludeContentType = []int{constant.HasReadReceipt}
@@ -52,10 +50,10 @@ type MessageRevoked struct {
func (m *msgServer) messageVerification(ctx context.Context, data *msg.SendMsgReq) error {
switch data.MsgData.SessionType {
case constant.SingleChatType:
- if len(config.Config.Manager.UserID) > 0 && utils.IsContain(data.MsgData.SendID, config.Config.Manager.UserID) {
+ if len(m.config.Manager.UserID) > 0 && utils.IsContain(data.MsgData.SendID, m.config.Manager.UserID) {
return nil
}
- if utils.IsContain(data.MsgData.SendID, config.Config.IMAdmin.UserID) {
+ if utils.IsContain(data.MsgData.SendID, m.config.IMAdmin.UserID) {
return nil
}
if data.MsgData.ContentType <= constant.NotificationEnd &&
@@ -92,10 +90,10 @@ func (m *msgServer) messageVerification(ctx context.Context, data *msg.SendMsgRe
if groupInfo.GroupType == constant.SuperGroup {
return nil
}
- if len(config.Config.Manager.UserID) > 0 && utils.IsContain(data.MsgData.SendID, config.Config.Manager.UserID) {
+ if len(m.config.Manager.UserID) > 0 && utils.IsContain(data.MsgData.SendID, m.config.Manager.UserID) {
return nil
}
- if utils.IsContain(data.MsgData.SendID, config.Config.IMAdmin.UserID) {
+ if utils.IsContain(data.MsgData.SendID, m.config.IMAdmin.UserID) {
return nil
}
if data.MsgData.ContentType <= constant.NotificationEnd &&
diff --git a/internal/rpc/third/log.go b/internal/rpc/third/log.go
index 11c7467b8..b425dd819 100644
--- a/internal/rpc/third/log.go
+++ b/internal/rpc/third/log.go
@@ -25,7 +25,6 @@ import (
"github.com/OpenIMSDK/tools/errs"
"github.com/OpenIMSDK/tools/utils"
utils2 "github.com/OpenIMSDK/tools/utils"
-
"github.com/openimsdk/open-im-server/v3/pkg/authverify"
relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
)
@@ -83,7 +82,7 @@ func (t *thirdServer) UploadLogs(ctx context.Context, req *third.UploadLogsReq)
}
func (t *thirdServer) DeleteLogs(ctx context.Context, req *third.DeleteLogsReq) (*third.DeleteLogsResp, error) {
- if err := authverify.CheckAdmin(ctx); err != nil {
+ if err := authverify.CheckAdmin(ctx, t.config); err != nil {
return nil, err
}
userID := ""
@@ -124,7 +123,7 @@ func dbToPbLogInfos(logs []*relationtb.LogModel) []*third.LogInfo {
}
func (t *thirdServer) SearchLogs(ctx context.Context, req *third.SearchLogsReq) (*third.SearchLogsResp, error) {
- if err := authverify.CheckAdmin(ctx); err != nil {
+ if err := authverify.CheckAdmin(ctx, t.config); err != nil {
return nil, err
}
var (
diff --git a/internal/rpc/third/s3.go b/internal/rpc/third/s3.go
index 3b501d4ad..f79b73a99 100644
--- a/internal/rpc/third/s3.go
+++ b/internal/rpc/third/s3.go
@@ -23,18 +23,13 @@ import (
"strconv"
"time"
- "github.com/google/uuid"
-
- "github.com/openimsdk/open-im-server/v3/pkg/authverify"
-
- "github.com/openimsdk/open-im-server/v3/pkg/common/db/s3"
-
"github.com/OpenIMSDK/protocol/third"
"github.com/OpenIMSDK/tools/errs"
"github.com/OpenIMSDK/tools/log"
"github.com/OpenIMSDK/tools/mcontext"
"github.com/OpenIMSDK/tools/utils"
-
+ "github.com/google/uuid"
+ "github.com/openimsdk/open-im-server/v3/pkg/common/db/s3"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/s3/cont"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
)
@@ -58,7 +53,7 @@ func (t *thirdServer) PartSize(ctx context.Context, req *third.PartSizeReq) (*th
func (t *thirdServer) InitiateMultipartUpload(ctx context.Context, req *third.InitiateMultipartUploadReq) (*third.InitiateMultipartUploadResp, error) {
defer log.ZDebug(ctx, "return")
- if err := checkUploadName(ctx, req.Name); err != nil {
+ if err := t.checkUploadName(ctx, req.Name); err != nil {
return nil, err
}
expireTime := time.Now().Add(t.defaultExpire)
@@ -137,7 +132,7 @@ func (t *thirdServer) AuthSign(ctx context.Context, req *third.AuthSignReq) (*th
func (t *thirdServer) CompleteMultipartUpload(ctx context.Context, req *third.CompleteMultipartUploadReq) (*third.CompleteMultipartUploadResp, error) {
defer log.ZDebug(ctx, "return")
- if err := checkUploadName(ctx, req.Name); err != nil {
+ if err := t.checkUploadName(ctx, req.Name); err != nil {
return nil, err
}
result, err := t.s3dataBase.CompleteMultipartUpload(ctx, req.UploadID, req.Parts)
@@ -194,13 +189,13 @@ func (t *thirdServer) InitiateFormData(ctx context.Context, req *third.InitiateF
if req.Size <= 0 {
return nil, errs.ErrArgs.Wrap("size must be greater than 0")
}
- if err := checkUploadName(ctx, req.Name); err != nil {
+ if err := t.checkUploadName(ctx, req.Name); err != nil {
return nil, err
}
var duration time.Duration
opUserID := mcontext.GetOpUserID(ctx)
var key string
- if authverify.IsManagerUserID(opUserID) {
+ if t.IsManagerUserID(opUserID) {
if req.Millisecond <= 0 {
duration = time.Minute * 10
} else {
@@ -214,7 +209,7 @@ func (t *thirdServer) InitiateFormData(ctx context.Context, req *third.InitiateF
}
uid, err := uuid.NewRandom()
if err != nil {
- return nil, err
+ return nil, errs.Wrap(err, "uuid NewRandom failed")
}
if key == "" {
date := time.Now().Format("20060102")
@@ -229,7 +224,7 @@ func (t *thirdServer) InitiateFormData(ctx context.Context, req *third.InitiateF
}
mateData, err := json.Marshal(&mate)
if err != nil {
- return nil, err
+ return nil, errs.Wrap(err, "marshal failed")
}
resp, err := t.s3dataBase.FormData(ctx, key, req.Size, req.ContentType, duration)
if err != nil {
@@ -260,7 +255,7 @@ func (t *thirdServer) CompleteFormData(ctx context.Context, req *third.CompleteF
if err := json.Unmarshal(data, &mate); err != nil {
return nil, errs.ErrArgs.Wrap("invalid id " + err.Error())
}
- if err := checkUploadName(ctx, mate.Name); err != nil {
+ if err := t.checkUploadName(ctx, mate.Name); err != nil {
return nil, err
}
info, err := t.s3dataBase.StatObject(ctx, mate.Key)
diff --git a/internal/rpc/third/third.go b/internal/rpc/third/third.go
index 7a63d3526..5f6fc6c34 100644
--- a/internal/rpc/third/third.go
+++ b/internal/rpc/third/third.go
@@ -17,66 +17,63 @@ package third
import (
"context"
"fmt"
+ "github.com/OpenIMSDK/tools/errs"
"net/url"
"time"
+ "github.com/OpenIMSDK/protocol/third"
+ "github.com/OpenIMSDK/tools/discoveryregistry"
+ "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/mgo"
- "github.com/openimsdk/open-im-server/v3/pkg/common/db/unrelation"
-
"github.com/openimsdk/open-im-server/v3/pkg/common/db/s3"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/s3/cos"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/s3/minio"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/s3/oss"
-
- "google.golang.org/grpc"
-
- "github.com/OpenIMSDK/protocol/third"
- "github.com/OpenIMSDK/tools/discoveryregistry"
-
- "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/unrelation"
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
+ "google.golang.org/grpc"
)
-func Start(client discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) error {
- mongo, err := unrelation.NewMongo()
+func Start(config *config.GlobalConfig, client discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) error {
+ mongo, err := unrelation.NewMongo(config)
if err != nil {
return err
}
- logdb, err := mgo.NewLogMongo(mongo.GetDatabase())
+ logdb, err := mgo.NewLogMongo(mongo.GetDatabase(config.Mongo.Database))
if err != nil {
return err
}
- s3db, err := mgo.NewS3Mongo(mongo.GetDatabase())
+ s3db, err := mgo.NewS3Mongo(mongo.GetDatabase(config.Mongo.Database))
if err != nil {
return err
}
- apiURL := config.Config.Object.ApiURL
+ apiURL := config.Object.ApiURL
if apiURL == "" {
- return fmt.Errorf("api url is empty")
+ return errs.Wrap(fmt.Errorf("api is empty"))
}
- if _, err := url.Parse(config.Config.Object.ApiURL); err != nil {
+ if _, err := url.Parse(config.Object.ApiURL); err != nil {
return err
}
if apiURL[len(apiURL)-1] != '/' {
apiURL += "/"
}
apiURL += "object/"
- rdb, err := cache.NewRedis()
+ rdb, err := cache.NewRedis(config)
if err != nil {
return err
}
- // 根据配置文件策略选择 oss 方式
- enable := config.Config.Object.Enable
+ // Select the oss method according to the profile policy
+ enable := config.Object.Enable
var o s3.Interface
- switch config.Config.Object.Enable {
+ switch enable {
case "minio":
- o, err = minio.NewMinio(cache.NewMinioCache(rdb))
+ o, err = minio.NewMinio(cache.NewMinioCache(rdb), minio.Config(config.Object.Minio))
case "cos":
- o, err = cos.NewCos()
+ o, err = cos.NewCos(cos.Config(config.Object.Cos))
case "oss":
- o, err = oss.NewOSS()
+ o, err = oss.NewOSS(oss.Config(config.Object.Oss))
default:
err = fmt.Errorf("invalid object enable: %s", enable)
}
@@ -85,10 +82,11 @@ func Start(client discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) e
}
third.RegisterThirdServer(server, &thirdServer{
apiURL: apiURL,
- thirdDatabase: controller.NewThirdDatabase(cache.NewMsgCacheModel(rdb), logdb),
- userRpcClient: rpcclient.NewUserRpcClient(client),
+ thirdDatabase: controller.NewThirdDatabase(cache.NewMsgCacheModel(rdb, config), logdb),
+ userRpcClient: rpcclient.NewUserRpcClient(client, config),
s3dataBase: controller.NewS3Database(rdb, o, s3db),
defaultExpire: time.Hour * 24 * 7,
+ config: config,
})
return nil
}
@@ -99,6 +97,7 @@ type thirdServer struct {
s3dataBase controller.S3Database
userRpcClient rpcclient.UserRpcClient
defaultExpire time.Duration
+ config *config.GlobalConfig
}
func (t *thirdServer) FcmUpdateToken(ctx context.Context, req *third.FcmUpdateTokenReq) (resp *third.FcmUpdateTokenResp, err error) {
diff --git a/internal/rpc/third/tool.go b/internal/rpc/third/tool.go
index a6c16ff9d..d8491d354 100644
--- a/internal/rpc/third/tool.go
+++ b/internal/rpc/third/tool.go
@@ -21,11 +21,10 @@ import (
"strings"
"unicode/utf8"
- "github.com/openimsdk/open-im-server/v3/pkg/authverify"
-
"github.com/OpenIMSDK/protocol/third"
"github.com/OpenIMSDK/tools/errs"
"github.com/OpenIMSDK/tools/mcontext"
+ "github.com/openimsdk/open-im-server/v3/pkg/authverify"
)
func toPbMapArray(m map[string][]string) []*third.KeyValues {
@@ -42,7 +41,7 @@ func toPbMapArray(m map[string][]string) []*third.KeyValues {
return res
}
-func checkUploadName(ctx context.Context, name string) error {
+func (t *thirdServer) checkUploadName(ctx context.Context, name string) error {
if name == "" {
return errs.ErrArgs.Wrap("name is empty")
}
@@ -56,7 +55,7 @@ func checkUploadName(ctx context.Context, name string) error {
if opUserID == "" {
return errs.ErrNoPermission.Wrap("opUserID is empty")
}
- if !authverify.IsManagerUserID(opUserID) {
+ if !authverify.IsManagerUserID(opUserID, t.config) {
if !strings.HasPrefix(name, opUserID+"/") {
return errs.ErrNoPermission.Wrap(fmt.Sprintf("name must start with `%s/`", opUserID))
}
@@ -80,3 +79,7 @@ func checkValidObjectName(objectName string) error {
}
return checkValidObjectNamePrefix(objectName)
}
+
+func (t *thirdServer) IsManagerUserID(opUserID string) bool {
+ return authverify.IsManagerUserID(opUserID, t.config)
+}
diff --git a/internal/rpc/user/callback.go b/internal/rpc/user/callback.go
index 5276946a4..34f211973 100644
--- a/internal/rpc/user/callback.go
+++ b/internal/rpc/user/callback.go
@@ -19,14 +19,13 @@ import (
pbuser "github.com/OpenIMSDK/protocol/user"
"github.com/OpenIMSDK/tools/utils"
-
cbapi "github.com/openimsdk/open-im-server/v3/pkg/callbackstruct"
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
"github.com/openimsdk/open-im-server/v3/pkg/common/http"
)
-func CallbackBeforeUpdateUserInfo(ctx context.Context, req *pbuser.UpdateUserInfoReq) error {
- if !config.Config.Callback.CallbackBeforeUpdateUserInfo.Enable {
+func CallbackBeforeUpdateUserInfo(ctx context.Context, globalConfig *config.GlobalConfig, req *pbuser.UpdateUserInfoReq) error {
+ if !globalConfig.Callback.CallbackBeforeUpdateUserInfo.Enable {
return nil
}
cbReq := &cbapi.CallbackBeforeUpdateUserInfoReq{
@@ -36,7 +35,7 @@ func CallbackBeforeUpdateUserInfo(ctx context.Context, req *pbuser.UpdateUserInf
Nickname: &req.UserInfo.Nickname,
}
resp := &cbapi.CallbackBeforeUpdateUserInfoResp{}
- if err := http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, cbReq, resp, config.Config.Callback.CallbackBeforeUpdateUserInfo); err != nil {
+ if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, cbReq, resp, globalConfig.Callback.CallbackBeforeUpdateUserInfo); err != nil {
return err
}
utils.NotNilReplace(&req.UserInfo.FaceURL, resp.FaceURL)
@@ -44,8 +43,8 @@ func CallbackBeforeUpdateUserInfo(ctx context.Context, req *pbuser.UpdateUserInf
utils.NotNilReplace(&req.UserInfo.Nickname, resp.Nickname)
return nil
}
-func CallbackAfterUpdateUserInfo(ctx context.Context, req *pbuser.UpdateUserInfoReq) error {
- if !config.Config.Callback.CallbackAfterUpdateUserInfo.Enable {
+func CallbackAfterUpdateUserInfo(ctx context.Context, globalConfig *config.GlobalConfig, req *pbuser.UpdateUserInfoReq) error {
+ if !globalConfig.Callback.CallbackAfterUpdateUserInfo.Enable {
return nil
}
cbReq := &cbapi.CallbackAfterUpdateUserInfoReq{
@@ -55,13 +54,13 @@ func CallbackAfterUpdateUserInfo(ctx context.Context, req *pbuser.UpdateUserInfo
Nickname: req.UserInfo.Nickname,
}
resp := &cbapi.CallbackAfterUpdateUserInfoResp{}
- if err := http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, cbReq, resp, config.Config.Callback.CallbackBeforeUpdateUserInfo); err != nil {
+ if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, cbReq, resp, globalConfig.Callback.CallbackBeforeUpdateUserInfo); err != nil {
return err
}
return nil
}
-func CallbackBeforeUpdateUserInfoEx(ctx context.Context, req *pbuser.UpdateUserInfoExReq) error {
- if !config.Config.Callback.CallbackBeforeUpdateUserInfoEx.Enable {
+func CallbackBeforeUpdateUserInfoEx(ctx context.Context, globalConfig *config.GlobalConfig, req *pbuser.UpdateUserInfoExReq) error {
+ if !globalConfig.Callback.CallbackBeforeUpdateUserInfoEx.Enable {
return nil
}
cbReq := &cbapi.CallbackBeforeUpdateUserInfoExReq{
@@ -71,7 +70,7 @@ func CallbackBeforeUpdateUserInfoEx(ctx context.Context, req *pbuser.UpdateUserI
Nickname: req.UserInfo.Nickname,
}
resp := &cbapi.CallbackBeforeUpdateUserInfoExResp{}
- if err := http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, cbReq, resp, config.Config.Callback.CallbackBeforeUpdateUserInfoEx); err != nil {
+ if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, cbReq, resp, globalConfig.Callback.CallbackBeforeUpdateUserInfoEx); err != nil {
return err
}
utils.NotNilReplace(req.UserInfo.FaceURL, resp.FaceURL)
@@ -79,8 +78,8 @@ func CallbackBeforeUpdateUserInfoEx(ctx context.Context, req *pbuser.UpdateUserI
utils.NotNilReplace(req.UserInfo.Nickname, resp.Nickname)
return nil
}
-func CallbackAfterUpdateUserInfoEx(ctx context.Context, req *pbuser.UpdateUserInfoExReq) error {
- if !config.Config.Callback.CallbackAfterUpdateUserInfoEx.Enable {
+func CallbackAfterUpdateUserInfoEx(ctx context.Context, globalConfig *config.GlobalConfig, req *pbuser.UpdateUserInfoExReq) error {
+ if !globalConfig.Callback.CallbackAfterUpdateUserInfoEx.Enable {
return nil
}
cbReq := &cbapi.CallbackAfterUpdateUserInfoExReq{
@@ -90,14 +89,14 @@ func CallbackAfterUpdateUserInfoEx(ctx context.Context, req *pbuser.UpdateUserIn
Nickname: req.UserInfo.Nickname,
}
resp := &cbapi.CallbackAfterUpdateUserInfoExResp{}
- if err := http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, cbReq, resp, config.Config.Callback.CallbackBeforeUpdateUserInfoEx); err != nil {
+ if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, cbReq, resp, globalConfig.Callback.CallbackBeforeUpdateUserInfoEx); err != nil {
return err
}
return nil
}
-func CallbackBeforeUserRegister(ctx context.Context, req *pbuser.UserRegisterReq) error {
- if !config.Config.Callback.CallbackBeforeUserRegister.Enable {
+func CallbackBeforeUserRegister(ctx context.Context, globalConfig *config.GlobalConfig, req *pbuser.UserRegisterReq) error {
+ if !globalConfig.Callback.CallbackBeforeUserRegister.Enable {
return nil
}
cbReq := &cbapi.CallbackBeforeUserRegisterReq{
@@ -107,7 +106,7 @@ func CallbackBeforeUserRegister(ctx context.Context, req *pbuser.UserRegisterReq
}
resp := &cbapi.CallbackBeforeUserRegisterResp{}
- if err := http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, cbReq, resp, config.Config.Callback.CallbackBeforeUpdateUserInfo); err != nil {
+ if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, cbReq, resp, globalConfig.Callback.CallbackBeforeUpdateUserInfo); err != nil {
return err
}
if len(resp.Users) != 0 {
@@ -116,8 +115,8 @@ func CallbackBeforeUserRegister(ctx context.Context, req *pbuser.UserRegisterReq
return nil
}
-func CallbackAfterUserRegister(ctx context.Context, req *pbuser.UserRegisterReq) error {
- if !config.Config.Callback.CallbackAfterUserRegister.Enable {
+func CallbackAfterUserRegister(ctx context.Context, globalConfig *config.GlobalConfig, req *pbuser.UserRegisterReq) error {
+ if !globalConfig.Callback.CallbackAfterUserRegister.Enable {
return nil
}
cbReq := &cbapi.CallbackAfterUserRegisterReq{
@@ -127,7 +126,7 @@ func CallbackAfterUserRegister(ctx context.Context, req *pbuser.UserRegisterReq)
}
resp := &cbapi.CallbackAfterUserRegisterResp{}
- if err := http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, cbReq, resp, config.Config.Callback.CallbackAfterUpdateUserInfo); err != nil {
+ if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, cbReq, resp, globalConfig.Callback.CallbackAfterUpdateUserInfo); err != nil {
return err
}
return nil
diff --git a/internal/rpc/user/user.go b/internal/rpc/user/user.go
index e5567f436..3d13cd7b6 100644
--- a/internal/rpc/user/user.go
+++ b/internal/rpc/user/user.go
@@ -16,39 +16,31 @@ package user
import (
"context"
- "errors"
+ "fmt"
"math/rand"
"strings"
"time"
- "github.com/OpenIMSDK/tools/pagination"
-
- "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
-
- "github.com/OpenIMSDK/tools/tx"
-
- "github.com/openimsdk/open-im-server/v3/pkg/common/db/mgo"
-
"github.com/OpenIMSDK/protocol/constant"
"github.com/OpenIMSDK/protocol/sdkws"
+ pbuser "github.com/OpenIMSDK/protocol/user"
+ registry "github.com/OpenIMSDK/tools/discoveryregistry"
"github.com/OpenIMSDK/tools/errs"
"github.com/OpenIMSDK/tools/log"
-
+ "github.com/OpenIMSDK/tools/pagination"
+ "github.com/OpenIMSDK/tools/tx"
+ "github.com/OpenIMSDK/tools/utils"
"github.com/openimsdk/open-im-server/v3/pkg/authverify"
- "github.com/openimsdk/open-im-server/v3/pkg/common/db/unrelation"
-
- registry "github.com/OpenIMSDK/tools/discoveryregistry"
-
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
"github.com/openimsdk/open-im-server/v3/pkg/common/convert"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/cache"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/controller"
+ "github.com/openimsdk/open-im-server/v3/pkg/common/db/mgo"
+ "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
tablerelation "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
+ "github.com/openimsdk/open-im-server/v3/pkg/common/db/unrelation"
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient/notification"
-
- pbuser "github.com/OpenIMSDK/protocol/user"
- "github.com/OpenIMSDK/tools/utils"
"google.golang.org/grpc"
)
@@ -59,41 +51,48 @@ type userServer struct {
friendRpcClient *rpcclient.FriendRpcClient
groupRpcClient *rpcclient.GroupRpcClient
RegisterCenter registry.SvcDiscoveryRegistry
+ config *config.GlobalConfig
}
-func Start(client registry.SvcDiscoveryRegistry, server *grpc.Server) error {
- rdb, err := cache.NewRedis()
+func (s *userServer) GetGroupOnlineUser(ctx context.Context, req *pbuser.GetGroupOnlineUserReq) (*pbuser.GetGroupOnlineUserResp, error) {
+ //TODO implement me
+ panic("implement me")
+}
+
+func Start(config *config.GlobalConfig, client registry.SvcDiscoveryRegistry, server *grpc.Server) error {
+ rdb, err := cache.NewRedis(config)
if err != nil {
return err
}
- mongo, err := unrelation.NewMongo()
+ mongo, err := unrelation.NewMongo(config)
if err != nil {
return err
}
users := make([]*tablerelation.UserModel, 0)
- if len(config.Config.IMAdmin.UserID) != len(config.Config.IMAdmin.Nickname) {
- return errors.New("len(config.Config.AppNotificationAdmin.AppManagerUid) != len(config.Config.AppNotificationAdmin.Nickname)")
+ if len(config.IMAdmin.UserID) != len(config.IMAdmin.Nickname) {
+ return errs.Wrap(fmt.Errorf("the count of ImAdmin.UserID is not equal to the count of ImAdmin.Nickname"))
}
- for k, v := range config.Config.IMAdmin.UserID {
- users = append(users, &tablerelation.UserModel{UserID: v, Nickname: config.Config.IMAdmin.Nickname[k], AppMangerLevel: constant.AppNotificationAdmin})
+ for k, v := range config.IMAdmin.UserID {
+ users = append(users, &tablerelation.UserModel{UserID: v, Nickname: config.IMAdmin.Nickname[k], AppMangerLevel: constant.AppNotificationAdmin})
}
- userDB, err := mgo.NewUserMongo(mongo.GetDatabase())
+ userDB, err := mgo.NewUserMongo(mongo.GetDatabase(config.Mongo.Database))
if err != nil {
return err
}
cache := cache.NewUserCacheRedis(rdb, userDB, cache.GetDefaultOpt())
- userMongoDB := unrelation.NewUserMongoDriver(mongo.GetDatabase())
+ userMongoDB := unrelation.NewUserMongoDriver(mongo.GetDatabase(config.Mongo.Database))
database := controller.NewUserDatabase(userDB, cache, tx.NewMongo(mongo.GetClient()), userMongoDB)
- friendRpcClient := rpcclient.NewFriendRpcClient(client)
- groupRpcClient := rpcclient.NewGroupRpcClient(client)
- msgRpcClient := rpcclient.NewMessageRpcClient(client)
+ friendRpcClient := rpcclient.NewFriendRpcClient(client, config)
+ groupRpcClient := rpcclient.NewGroupRpcClient(client, config)
+ msgRpcClient := rpcclient.NewMessageRpcClient(client, config)
u := &userServer{
UserDatabase: database,
RegisterCenter: client,
friendRpcClient: &friendRpcClient,
groupRpcClient: &groupRpcClient,
- friendNotificationSender: notification.NewFriendNotificationSender(&msgRpcClient, notification.WithDBFunc(database.FindWithError)),
- userNotificationSender: notification.NewUserNotificationSender(&msgRpcClient, notification.WithUserFunc(database.FindWithError)),
+ friendNotificationSender: notification.NewFriendNotificationSender(config, &msgRpcClient, notification.WithDBFunc(database.FindWithError)),
+ userNotificationSender: notification.NewUserNotificationSender(config, &msgRpcClient, notification.WithUserFunc(database.FindWithError)),
+ config: config,
}
pbuser.RegisterUserServer(server, u)
return u.UserDatabase.InitOnce(context.Background(), users)
@@ -106,19 +105,16 @@ func (s *userServer) GetDesignateUsers(ctx context.Context, req *pbuser.GetDesig
return nil, err
}
resp.UsersInfo = convert.UsersDB2Pb(users)
- if err != nil {
- return nil, err
- }
return resp, nil
}
func (s *userServer) UpdateUserInfo(ctx context.Context, req *pbuser.UpdateUserInfoReq) (resp *pbuser.UpdateUserInfoResp, err error) {
resp = &pbuser.UpdateUserInfoResp{}
- err = authverify.CheckAccessV3(ctx, req.UserInfo.UserID)
+ err = authverify.CheckAccessV3(ctx, req.UserInfo.UserID, s.config)
if err != nil {
return nil, err
}
- if err := CallbackBeforeUpdateUserInfo(ctx, req); err != nil {
+ if err := CallbackBeforeUpdateUserInfo(ctx, s.config, req); err != nil {
return nil, err
}
data := convert.UserPb2DBMap(req.UserInfo)
@@ -131,29 +127,29 @@ func (s *userServer) UpdateUserInfo(ctx context.Context, req *pbuser.UpdateUserI
return nil, err
}
if req.UserInfo.Nickname != "" || req.UserInfo.FaceURL != "" {
- if err := s.groupRpcClient.NotificationUserInfoUpdate(ctx, req.UserInfo.UserID); err != nil {
- log.ZError(ctx, "NotificationUserInfoUpdate", err)
+ if err = s.groupRpcClient.NotificationUserInfoUpdate(ctx, req.UserInfo.UserID); err != nil {
+ return nil, err
}
}
for _, friendID := range friends {
s.friendNotificationSender.FriendInfoUpdatedNotification(ctx, req.UserInfo.UserID, friendID)
}
- if err := CallbackAfterUpdateUserInfo(ctx, req); err != nil {
+ if err = CallbackAfterUpdateUserInfo(ctx, s.config, req); err != nil {
return nil, err
}
- if err := s.groupRpcClient.NotificationUserInfoUpdate(ctx, req.UserInfo.UserID); err != nil {
- log.ZError(ctx, "NotificationUserInfoUpdate", err, "userID", req.UserInfo.UserID)
+ if err = s.groupRpcClient.NotificationUserInfoUpdate(ctx, req.UserInfo.UserID); err != nil {
+ return nil, err
}
return resp, nil
}
func (s *userServer) UpdateUserInfoEx(ctx context.Context, req *pbuser.UpdateUserInfoExReq) (resp *pbuser.UpdateUserInfoExResp, err error) {
resp = &pbuser.UpdateUserInfoExResp{}
- err = authverify.CheckAccessV3(ctx, req.UserInfo.UserID)
+ err = authverify.CheckAccessV3(ctx, req.UserInfo.UserID, s.config)
if err != nil {
return nil, err
}
- if err = CallbackBeforeUpdateUserInfoEx(ctx, req); err != nil {
+ if err = CallbackBeforeUpdateUserInfoEx(ctx, s.config, req); err != nil {
return nil, err
}
data := convert.UserPb2DBMapEx(req.UserInfo)
@@ -167,17 +163,17 @@ func (s *userServer) UpdateUserInfoEx(ctx context.Context, req *pbuser.UpdateUse
}
if req.UserInfo.Nickname != nil || req.UserInfo.FaceURL != nil {
if err := s.groupRpcClient.NotificationUserInfoUpdate(ctx, req.UserInfo.UserID); err != nil {
- log.ZError(ctx, "NotificationUserInfoUpdate", err)
+ return nil, err
}
}
for _, friendID := range friends {
s.friendNotificationSender.FriendInfoUpdatedNotification(ctx, req.UserInfo.UserID, friendID)
}
- if err := CallbackAfterUpdateUserInfoEx(ctx, req); err != nil {
+ if err := CallbackAfterUpdateUserInfoEx(ctx, s.config, req); err != nil {
return nil, err
}
if err := s.groupRpcClient.NotificationUserInfoUpdate(ctx, req.UserInfo.UserID); err != nil {
- log.ZError(ctx, "NotificationUserInfoUpdate", err, "userID", req.UserInfo.UserID)
+ return nil, err
}
return resp, nil
}
@@ -200,7 +196,7 @@ func (s *userServer) AccountCheck(ctx context.Context, req *pbuser.AccountCheckR
if utils.Duplicate(req.CheckUserIDs) {
return nil, errs.ErrArgs.Wrap("userID repeated")
}
- err = authverify.CheckAdmin(ctx)
+ err = authverify.CheckAdmin(ctx, s.config)
if err != nil {
return nil, err
}
@@ -247,8 +243,8 @@ func (s *userServer) UserRegister(ctx context.Context, req *pbuser.UserRegisterR
if len(req.Users) == 0 {
return nil, errs.ErrArgs.Wrap("users is empty")
}
- if req.Secret != config.Config.Secret {
- log.ZDebug(ctx, "UserRegister", config.Config.Secret, req.Secret)
+ if req.Secret != s.config.Secret {
+ log.ZDebug(ctx, "UserRegister", s.config.Secret, req.Secret)
return nil, errs.ErrNoPermission.Wrap("secret invalid")
}
if utils.DuplicateAny(req.Users, func(e *sdkws.UserInfo) string { return e.UserID }) {
@@ -271,7 +267,7 @@ func (s *userServer) UserRegister(ctx context.Context, req *pbuser.UserRegisterR
if exist {
return nil, errs.ErrRegisteredAlready.Wrap("userID registered already")
}
- if err := CallbackBeforeUserRegister(ctx, req); err != nil {
+ if err := CallbackBeforeUserRegister(ctx, s.config, req); err != nil {
return nil, err
}
now := time.Now()
@@ -291,7 +287,7 @@ func (s *userServer) UserRegister(ctx context.Context, req *pbuser.UserRegisterR
return nil, err
}
- if err := CallbackAfterUserRegister(ctx, req); err != nil {
+ if err := CallbackAfterUserRegister(ctx, s.config, req); err != nil {
return nil, err
}
return resp, nil
@@ -386,7 +382,7 @@ func (s *userServer) GetSubscribeUsersStatus(ctx context.Context,
// ProcessUserCommandAdd user general function add.
func (s *userServer) ProcessUserCommandAdd(ctx context.Context, req *pbuser.ProcessUserCommandAddReq) (*pbuser.ProcessUserCommandAddResp, error) {
- err := authverify.CheckAccessV3(ctx, req.UserID)
+ err := authverify.CheckAccessV3(ctx, req.UserID, s.config)
if err != nil {
return nil, err
}
@@ -417,7 +413,7 @@ func (s *userServer) ProcessUserCommandAdd(ctx context.Context, req *pbuser.Proc
// ProcessUserCommandDelete user general function delete.
func (s *userServer) ProcessUserCommandDelete(ctx context.Context, req *pbuser.ProcessUserCommandDeleteReq) (*pbuser.ProcessUserCommandDeleteResp, error) {
- err := authverify.CheckAccessV3(ctx, req.UserID)
+ err := authverify.CheckAccessV3(ctx, req.UserID, s.config)
if err != nil {
return nil, err
}
@@ -440,7 +436,7 @@ func (s *userServer) ProcessUserCommandDelete(ctx context.Context, req *pbuser.P
// ProcessUserCommandUpdate user general function update.
func (s *userServer) ProcessUserCommandUpdate(ctx context.Context, req *pbuser.ProcessUserCommandUpdateReq) (*pbuser.ProcessUserCommandUpdateResp, error) {
- err := authverify.CheckAccessV3(ctx, req.UserID)
+ err := authverify.CheckAccessV3(ctx, req.UserID, s.config)
if err != nil {
return nil, err
}
@@ -472,7 +468,7 @@ func (s *userServer) ProcessUserCommandUpdate(ctx context.Context, req *pbuser.P
func (s *userServer) ProcessUserCommandGet(ctx context.Context, req *pbuser.ProcessUserCommandGetReq) (*pbuser.ProcessUserCommandGetResp, error) {
- err := authverify.CheckAccessV3(ctx, req.UserID)
+ err := authverify.CheckAccessV3(ctx, req.UserID, s.config)
if err != nil {
return nil, err
}
@@ -501,7 +497,7 @@ func (s *userServer) ProcessUserCommandGet(ctx context.Context, req *pbuser.Proc
}
func (s *userServer) ProcessUserCommandGetAll(ctx context.Context, req *pbuser.ProcessUserCommandGetAllReq) (*pbuser.ProcessUserCommandGetAllResp, error) {
- err := authverify.CheckAccessV3(ctx, req.UserID)
+ err := authverify.CheckAccessV3(ctx, req.UserID, s.config)
if err != nil {
return nil, err
}
@@ -530,7 +526,7 @@ func (s *userServer) ProcessUserCommandGetAll(ctx context.Context, req *pbuser.P
}
func (s *userServer) AddNotificationAccount(ctx context.Context, req *pbuser.AddNotificationAccountReq) (*pbuser.AddNotificationAccountResp, error) {
- if err := authverify.CheckIMAdmin(ctx); err != nil {
+ if err := authverify.CheckIMAdmin(ctx, s.config); err != nil {
return nil, err
}
@@ -573,7 +569,7 @@ func (s *userServer) AddNotificationAccount(ctx context.Context, req *pbuser.Add
}
func (s *userServer) UpdateNotificationAccountInfo(ctx context.Context, req *pbuser.UpdateNotificationAccountInfoReq) (*pbuser.UpdateNotificationAccountInfoResp, error) {
- if err := authverify.CheckIMAdmin(ctx); err != nil {
+ if err := authverify.CheckIMAdmin(ctx, s.config); err != nil {
return nil, err
}
@@ -600,7 +596,7 @@ func (s *userServer) UpdateNotificationAccountInfo(ctx context.Context, req *pbu
func (s *userServer) SearchNotificationAccount(ctx context.Context, req *pbuser.SearchNotificationAccountReq) (*pbuser.SearchNotificationAccountResp, error) {
// Check if user is an admin
- if err := authverify.CheckIMAdmin(ctx); err != nil {
+ if err := authverify.CheckIMAdmin(ctx, s.config); err != nil {
return nil, err
}
@@ -674,7 +670,7 @@ func (s *userServer) userModelToResp(users []*relation.UserModel, pagination pag
accounts := make([]*pbuser.NotificationAccountInfo, 0)
var total int64
for _, v := range users {
- if v.AppMangerLevel == constant.AppNotificationAdmin && !utils.IsContain(v.UserID, config.Config.IMAdmin.UserID) {
+ if v.AppMangerLevel == constant.AppNotificationAdmin && !utils.IsContain(v.UserID, s.config.IMAdmin.UserID) {
temp := &pbuser.NotificationAccountInfo{
UserID: v.UserID,
FaceURL: v.FaceURL,
diff --git a/internal/tools/conversation.go b/internal/tools/conversation.go
index 0d0275339..b555a3361 100644
--- a/internal/tools/conversation.go
+++ b/internal/tools/conversation.go
@@ -20,11 +20,9 @@ import (
"time"
"github.com/OpenIMSDK/protocol/sdkws"
-
"github.com/OpenIMSDK/tools/log"
"github.com/OpenIMSDK/tools/mcontext"
"github.com/OpenIMSDK/tools/utils"
-
"github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
)
@@ -58,9 +56,9 @@ import (
// continue
// }
// if len(seqs) > 0 {
-// if err := c.conversationDatabase.UpdateUsersConversationFiled(ctx, []string{conversation.OwnerUserID}, conversation.ConversationID, map[string]interface{}{"latest_msg_destruct_time": now}); err
+// if err := c.conversationDatabase.UpdateUsersConversationField(ctx, []string{conversation.OwnerUserID}, conversation.ConversationID, map[string]interface{}{"latest_msg_destruct_time": now}); err
// != nil {
-// log.ZError(ctx, "updateUsersConversationFiled failed", err, "conversationID", conversation.ConversationID, "ownerUserID", conversation.OwnerUserID)
+// log.ZError(ctx, "updateUsersConversationField failed", err, "conversationID", conversation.ConversationID, "ownerUserID", conversation.OwnerUserID)
// continue
// }
// if err := c.msgNotificationSender.UserDeleteMsgsNotification(ctx, conversation.OwnerUserID, conversation.ConversationID, seqs); err != nil {
@@ -139,8 +137,8 @@ func (c *MsgTool) ConversationsDestructMsgs() {
continue
}
if len(seqs) > 0 {
- if err := c.conversationDatabase.UpdateUsersConversationFiled(ctx, []string{conversation.OwnerUserID}, conversation.ConversationID, map[string]any{"latest_msg_destruct_time": now}); err != nil {
- log.ZError(ctx, "updateUsersConversationFiled failed", err, "conversationID", conversation.ConversationID, "ownerUserID", conversation.OwnerUserID)
+ if err := c.conversationDatabase.UpdateUsersConversationField(ctx, []string{conversation.OwnerUserID}, conversation.ConversationID, map[string]any{"latest_msg_destruct_time": now}); err != nil {
+ log.ZError(ctx, "updateUsersConversationField failed", err, "conversationID", conversation.ConversationID, "ownerUserID", conversation.OwnerUserID)
continue
}
if err := c.msgNotificationSender.UserDeleteMsgsNotification(ctx, conversation.OwnerUserID, conversation.ConversationID, seqs); err != nil {
diff --git a/internal/tools/cron_task.go b/internal/tools/cron_task.go
index e22504bbb..7535e9b96 100644
--- a/internal/tools/cron_task.go
+++ b/internal/tools/cron_task.go
@@ -22,50 +22,47 @@ import (
"syscall"
"time"
- "github.com/redis/go-redis/v9"
- "github.com/robfig/cron/v3"
-
- "github.com/OpenIMSDK/tools/log"
-
+ "github.com/OpenIMSDK/tools/errs"
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/cache"
+ "github.com/redis/go-redis/v9"
+ "github.com/robfig/cron/v3"
)
-func StartTask() error {
- fmt.Println("cron task start, config", config.Config.ChatRecordsClearTime)
- msgTool, err := InitMsgTool()
+func StartTask(config *config.GlobalConfig) error {
+ fmt.Println("cron task start, config", config.ChatRecordsClearTime)
+
+ msgTool, err := InitMsgTool(config)
if err != nil {
return err
}
msgTool.convertTools()
- rdb, err := cache.NewRedis()
+ rdb, err := cache.NewRedis(config)
if err != nil {
return err
}
// register cron tasks
var crontab = cron.New()
- log.ZInfo(context.Background(), "start chatRecordsClearTime cron task", "cron config", config.Config.ChatRecordsClearTime)
- _, err = crontab.AddFunc(config.Config.ChatRecordsClearTime, cronWrapFunc(rdb, "cron_clear_msg_and_fix_seq", msgTool.AllConversationClearMsgAndFixSeq))
+ fmt.Printf("Start chatRecordsClearTime cron task, cron config: %s\n", config.ChatRecordsClearTime)
+ _, err = crontab.AddFunc(config.ChatRecordsClearTime, cronWrapFunc(config, rdb, "cron_clear_msg_and_fix_seq", msgTool.AllConversationClearMsgAndFixSeq))
if err != nil {
- log.ZError(context.Background(), "start allConversationClearMsgAndFixSeq cron failed", err)
- panic(err)
+ return errs.Wrap(err)
}
- 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))
+ fmt.Printf("Start msgDestruct cron task, cron config: %s\n", config.MsgDestructTime)
+ _, err = crontab.AddFunc(config.MsgDestructTime, cronWrapFunc(config, rdb, "cron_conversations_destruct_msgs", msgTool.ConversationsDestructMsgs))
if err != nil {
- log.ZError(context.Background(), "start conversationsDestructMsgs cron failed", err)
- panic(err)
+ return errs.Wrap(err, "cron_conversations_destruct_msgs")
}
// start crontab
crontab.Start()
sigs := make(chan os.Signal, 1)
- signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)
+ signal.Notify(sigs, syscall.SIGTERM)
<-sigs
// stop crontab, Wait for the running task to exit.
@@ -94,8 +91,8 @@ func netlock(rdb redis.UniversalClient, key string, ttl time.Duration) bool {
return ok
}
-func cronWrapFunc(rdb redis.UniversalClient, key string, fn func()) func() {
- enableCronLocker := config.Config.EnableCronLocker
+func cronWrapFunc(config *config.GlobalConfig, rdb redis.UniversalClient, key string, fn func()) func() {
+ enableCronLocker := config.EnableCronLocker
return func() {
// if don't enable cron-locker, call fn directly.
if !enableCronLocker {
diff --git a/internal/tools/cron_task_test.go b/internal/tools/cron_task_test.go
index 28bc2c945..17346b1c5 100644
--- a/internal/tools/cron_task_test.go
+++ b/internal/tools/cron_task_test.go
@@ -15,12 +15,17 @@
package tools
import (
+ "flag"
"fmt"
"math/rand"
+ "os"
"sync"
"testing"
"time"
+ "github.com/OpenIMSDK/tools/errs"
+ "gopkg.in/yaml.v3"
+
"github.com/redis/go-redis/v9"
"github.com/robfig/cron/v3"
"github.com/stretchr/testify/assert"
@@ -61,7 +66,7 @@ func TestCronWrapFunc(t *testing.T) {
start := time.Now()
key := fmt.Sprintf("cron-%v", rand.Int31())
crontab := cron.New(cron.WithSeconds())
- crontab.AddFunc("*/1 * * * * *", cronWrapFunc(rdb, key, cb))
+ crontab.AddFunc("*/1 * * * * *", cronWrapFunc(config.NewGlobalConfig(), rdb, key, cb))
crontab.Start()
<-done
@@ -71,7 +76,11 @@ func TestCronWrapFunc(t *testing.T) {
}
func TestCronWrapFuncWithNetlock(t *testing.T) {
- config.Config.EnableCronLocker = true
+ conf, err := initCfg()
+ if err != nil {
+ panic(err)
+ }
+ conf.EnableCronLocker = true
rdb := redis.NewClient(&redis.Options{})
defer rdb.Close()
@@ -80,10 +89,10 @@ func TestCronWrapFuncWithNetlock(t *testing.T) {
crontab := cron.New(cron.WithSeconds())
key := fmt.Sprintf("cron-%v", rand.Int31())
- crontab.AddFunc("*/1 * * * * *", cronWrapFunc(rdb, key, func() {
+ crontab.AddFunc("*/1 * * * * *", cronWrapFunc(conf, rdb, key, func() {
done <- "host1"
}))
- crontab.AddFunc("*/1 * * * * *", cronWrapFunc(rdb, key, func() {
+ crontab.AddFunc("*/1 * * * * *", cronWrapFunc(conf, rdb, key, func() {
done <- "host2"
}))
crontab.Start()
@@ -94,3 +103,22 @@ func TestCronWrapFuncWithNetlock(t *testing.T) {
crontab.Stop()
}
+
+func initCfg() (*config.GlobalConfig, error) {
+ const (
+ defaultCfgPath = "../../../../../config/config.yaml"
+ )
+
+ cfgPath := flag.String("c", defaultCfgPath, "Path to the configuration file")
+ data, err := os.ReadFile(*cfgPath)
+ if err != nil {
+ return nil, errs.Wrap(err, "ReadFile unmarshal failed")
+ }
+
+ conf := config.NewGlobalConfig()
+ err = yaml.Unmarshal(data, &conf)
+ if err != nil {
+ return nil, errs.Wrap(err, "InitConfig unmarshal failed")
+ }
+ return conf, nil
+}
diff --git a/internal/tools/msg.go b/internal/tools/msg.go
index 30006670e..67c3895cb 100644
--- a/internal/tools/msg.go
+++ b/internal/tools/msg.go
@@ -18,32 +18,26 @@ import (
"context"
"fmt"
"math"
-
- "github.com/OpenIMSDK/protocol/sdkws"
- "github.com/OpenIMSDK/tools/tx"
-
- "github.com/openimsdk/open-im-server/v3/pkg/common/db/mgo"
-
- "github.com/redis/go-redis/v9"
- "google.golang.org/grpc"
- "google.golang.org/grpc/credentials/insecure"
-
- kdisc "github.com/openimsdk/open-im-server/v3/pkg/common/discoveryregister"
-
"math/rand"
+ "github.com/OpenIMSDK/protocol/sdkws"
"github.com/OpenIMSDK/tools/errs"
"github.com/OpenIMSDK/tools/log"
"github.com/OpenIMSDK/tools/mcontext"
"github.com/OpenIMSDK/tools/mw"
+ "github.com/OpenIMSDK/tools/tx"
"github.com/OpenIMSDK/tools/utils"
-
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/cache"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/controller"
+ "github.com/openimsdk/open-im-server/v3/pkg/common/db/mgo"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/unrelation"
+ kdisc "github.com/openimsdk/open-im-server/v3/pkg/common/discoveryregister"
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient/notification"
+ "github.com/redis/go-redis/v9"
+ "google.golang.org/grpc"
+ "google.golang.org/grpc/credentials/insecure"
)
type MsgTool struct {
@@ -52,10 +46,12 @@ type MsgTool struct {
userDatabase controller.UserDatabase
groupDatabase controller.GroupDatabase
msgNotificationSender *notification.MsgNotificationSender
+ Config *config.GlobalConfig
}
func NewMsgTool(msgDatabase controller.CommonMsgDatabase, userDatabase controller.UserDatabase,
- groupDatabase controller.GroupDatabase, conversationDatabase controller.ConversationDatabase, msgNotificationSender *notification.MsgNotificationSender,
+ groupDatabase controller.GroupDatabase, conversationDatabase controller.ConversationDatabase,
+ msgNotificationSender *notification.MsgNotificationSender, config *config.GlobalConfig,
) *MsgTool {
return &MsgTool{
msgDatabase: msgDatabase,
@@ -63,29 +59,33 @@ func NewMsgTool(msgDatabase controller.CommonMsgDatabase, userDatabase controlle
groupDatabase: groupDatabase,
conversationDatabase: conversationDatabase,
msgNotificationSender: msgNotificationSender,
+ Config: config,
}
}
-func InitMsgTool() (*MsgTool, error) {
- rdb, err := cache.NewRedis()
+func InitMsgTool(config *config.GlobalConfig) (*MsgTool, error) {
+ rdb, err := cache.NewRedis(config)
if err != nil {
return nil, err
}
- mongo, err := unrelation.NewMongo()
+ mongo, err := unrelation.NewMongo(config)
if err != nil {
return nil, err
}
- discov, err := kdisc.NewDiscoveryRegister(config.Config.Envs.Discovery)
+ discov, err := kdisc.NewDiscoveryRegister(config)
if err != nil {
return nil, err
}
discov.AddOption(mw.GrpcClient(), grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithDefaultServiceConfig(fmt.Sprintf(`{"LoadBalancingPolicy": "%s"}`, "round_robin")))
- userDB, err := mgo.NewUserMongo(mongo.GetDatabase())
+ userDB, err := mgo.NewUserMongo(mongo.GetDatabase(config.Mongo.Database))
if err != nil {
return nil, err
}
- msgDatabase := controller.InitCommonMsgDatabase(rdb, mongo.GetDatabase())
- userMongoDB := unrelation.NewUserMongoDriver(mongo.GetDatabase())
+ msgDatabase, err := controller.InitCommonMsgDatabase(rdb, mongo.GetDatabase(config.Mongo.Database), config)
+ if err != nil {
+ return nil, err
+ }
+ userMongoDB := unrelation.NewUserMongoDriver(mongo.GetDatabase(config.Mongo.Database))
ctxTx := tx.NewMongo(mongo.GetClient())
userDatabase := controller.NewUserDatabase(
userDB,
@@ -93,19 +93,19 @@ func InitMsgTool() (*MsgTool, error) {
ctxTx,
userMongoDB,
)
- groupDB, err := mgo.NewGroupMongo(mongo.GetDatabase())
+ groupDB, err := mgo.NewGroupMongo(mongo.GetDatabase(config.Mongo.Database))
if err != nil {
return nil, err
}
- groupMemberDB, err := mgo.NewGroupMember(mongo.GetDatabase())
+ groupMemberDB, err := mgo.NewGroupMember(mongo.GetDatabase(config.Mongo.Database))
if err != nil {
return nil, err
}
- groupRequestDB, err := mgo.NewGroupRequestMgo(mongo.GetDatabase())
+ groupRequestDB, err := mgo.NewGroupRequestMgo(mongo.GetDatabase(config.Mongo.Database))
if err != nil {
return nil, err
}
- conversationDB, err := mgo.NewConversationMongo(mongo.GetDatabase())
+ conversationDB, err := mgo.NewConversationMongo(mongo.GetDatabase(config.Mongo.Database))
if err != nil {
return nil, err
}
@@ -115,9 +115,9 @@ func InitMsgTool() (*MsgTool, error) {
cache.NewConversationRedis(rdb, cache.GetDefaultOpt(), conversationDB),
ctxTx,
)
- msgRpcClient := rpcclient.NewMessageRpcClient(discov)
- msgNotificationSender := notification.NewMsgNotificationSender(rpcclient.WithRpcClient(&msgRpcClient))
- msgTool := NewMsgTool(msgDatabase, userDatabase, groupDatabase, conversationDatabase, msgNotificationSender)
+ msgRpcClient := rpcclient.NewMessageRpcClient(discov, config)
+ msgNotificationSender := notification.NewMsgNotificationSender(config, rpcclient.WithRpcClient(&msgRpcClient))
+ msgTool := NewMsgTool(msgDatabase, userDatabase, groupDatabase, conversationDatabase, msgNotificationSender, config)
return msgTool, nil
}
@@ -179,8 +179,8 @@ func (c *MsgTool) AllConversationClearMsgAndFixSeq() {
func (c *MsgTool) ClearConversationsMsg(ctx context.Context, conversationIDs []string) {
for _, conversationID := range conversationIDs {
- if err := c.msgDatabase.DeleteConversationMsgsAndSetMinSeq(ctx, conversationID, int64(config.Config.RetainChatRecords*24*60*60)); err != nil {
- log.ZError(ctx, "DeleteUserSuperGroupMsgsAndSetMinSeq failed", err, "conversationID", conversationID, "DBRetainChatRecords", config.Config.RetainChatRecords)
+ if err := c.msgDatabase.DeleteConversationMsgsAndSetMinSeq(ctx, conversationID, int64(c.Config.RetainChatRecords*24*60*60)); err != nil {
+ log.ZError(ctx, "DeleteUserSuperGroupMsgsAndSetMinSeq failed", err, "conversationID", conversationID, "DBRetainChatRecords", c.Config.RetainChatRecords)
}
if err := c.checkMaxSeq(ctx, conversationID); err != nil {
log.ZError(ctx, "fixSeq failed", err, "conversationID", conversationID)
@@ -194,7 +194,8 @@ func (c *MsgTool) checkMaxSeqWithMongo(ctx context.Context, conversationID strin
return err
}
if math.Abs(float64(maxSeqMongo-maxSeqCache)) > 10 {
- log.ZError(ctx, "cache max seq and mongo max seq is diff > 10", nil, "maxSeqMongo", maxSeqMongo, "minSeqMongo", minSeqMongo, "maxSeqCache", maxSeqCache, "conversationID", conversationID)
+ err = fmt.Errorf("cache max seq and mongo max seq is diff > 10, maxSeqMongo:%d,minSeqMongo:%d,maxSeqCache:%d,conversationID:%s", maxSeqMongo, minSeqMongo, maxSeqCache, conversationID)
+ return errs.Wrap(err)
}
return nil
}
@@ -216,7 +217,6 @@ func (c *MsgTool) checkMaxSeq(ctx context.Context, conversationID string) error
func (c *MsgTool) FixAllSeq(ctx context.Context) error {
conversationIDs, err := c.conversationDatabase.GetAllConversationIDs(ctx)
if err != nil {
- log.ZError(ctx, "GetAllConversationIDs failed", err)
return err
}
for _, conversationID := range conversationIDs {
diff --git a/internal/tools/msg_doc_convert.go b/internal/tools/msg_doc_convert.go
index b9150c362..eea1b69e8 100644
--- a/internal/tools/msg_doc_convert.go
+++ b/internal/tools/msg_doc_convert.go
@@ -18,7 +18,6 @@ import (
"github.com/OpenIMSDK/protocol/constant"
"github.com/OpenIMSDK/tools/log"
"github.com/OpenIMSDK/tools/mcontext"
-
"github.com/openimsdk/open-im-server/v3/pkg/msgprocessor"
)
diff --git a/pkg/apistruct/msg.go b/pkg/apistruct/msg.go
index d23db9bf5..d1ce427fc 100644
--- a/pkg/apistruct/msg.go
+++ b/pkg/apistruct/msg.go
@@ -67,6 +67,7 @@ type LocationElem struct {
Longitude float64 `mapstructure:"longitude" validate:"required"`
Latitude float64 `mapstructure:"latitude" validate:"required"`
}
+
type CustomElem struct {
Data string `mapstructure:"data" validate:"required"`
Description string `mapstructure:"description"`
diff --git a/pkg/authverify/token.go b/pkg/authverify/token.go
index 97bb03391..26c43532d 100644
--- a/pkg/authverify/token.go
+++ b/pkg/authverify/token.go
@@ -23,64 +23,63 @@ import (
"github.com/OpenIMSDK/tools/tokenverify"
"github.com/OpenIMSDK/tools/utils"
"github.com/golang-jwt/jwt/v4"
-
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
)
-func Secret() jwt.Keyfunc {
+func Secret(secret string) jwt.Keyfunc {
return func(token *jwt.Token) (any, error) {
- return []byte(config.Config.Secret), nil
+ return []byte(secret), nil
}
}
-func CheckAccessV3(ctx context.Context, ownerUserID string) (err error) {
+func CheckAccessV3(ctx context.Context, ownerUserID string, config *config.GlobalConfig) (err error) {
opUserID := mcontext.GetOpUserID(ctx)
- if len(config.Config.Manager.UserID) > 0 && utils.IsContain(opUserID, config.Config.Manager.UserID) {
+ if len(config.Manager.UserID) > 0 && utils.IsContain(opUserID, config.Manager.UserID) {
return nil
}
- if utils.IsContain(opUserID, config.Config.IMAdmin.UserID) {
+ if utils.IsContain(opUserID, config.IMAdmin.UserID) {
return nil
}
if opUserID == ownerUserID {
return nil
}
- return errs.ErrNoPermission.Wrap(utils.GetSelfFuncName())
+ return errs.ErrNoPermission.Wrap("ownerUserID", ownerUserID)
}
-func IsAppManagerUid(ctx context.Context) bool {
- return (len(config.Config.Manager.UserID) > 0 && utils.IsContain(mcontext.GetOpUserID(ctx), config.Config.Manager.UserID)) ||
- utils.IsContain(mcontext.GetOpUserID(ctx), config.Config.IMAdmin.UserID)
+func IsAppManagerUid(ctx context.Context, config *config.GlobalConfig) bool {
+ return (len(config.Manager.UserID) > 0 && utils.IsContain(mcontext.GetOpUserID(ctx), config.Manager.UserID)) ||
+ utils.IsContain(mcontext.GetOpUserID(ctx), config.IMAdmin.UserID)
}
-func CheckAdmin(ctx context.Context) error {
- if len(config.Config.Manager.UserID) > 0 && utils.IsContain(mcontext.GetOpUserID(ctx), config.Config.Manager.UserID) {
+func CheckAdmin(ctx context.Context, config *config.GlobalConfig) error {
+ if len(config.Manager.UserID) > 0 && utils.IsContain(mcontext.GetOpUserID(ctx), config.Manager.UserID) {
return nil
}
- if utils.IsContain(mcontext.GetOpUserID(ctx), config.Config.IMAdmin.UserID) {
+ if utils.IsContain(mcontext.GetOpUserID(ctx), config.IMAdmin.UserID) {
return nil
}
return errs.ErrNoPermission.Wrap(fmt.Sprintf("user %s is not admin userID", mcontext.GetOpUserID(ctx)))
}
-func CheckIMAdmin(ctx context.Context) error {
- if utils.IsContain(mcontext.GetOpUserID(ctx), config.Config.IMAdmin.UserID) {
+func CheckIMAdmin(ctx context.Context, config *config.GlobalConfig) error {
+ if utils.IsContain(mcontext.GetOpUserID(ctx), config.IMAdmin.UserID) {
return nil
}
- if len(config.Config.Manager.UserID) > 0 && utils.IsContain(mcontext.GetOpUserID(ctx), config.Config.Manager.UserID) {
+ if len(config.Manager.UserID) > 0 && utils.IsContain(mcontext.GetOpUserID(ctx), config.Manager.UserID) {
return nil
}
return errs.ErrNoPermission.Wrap(fmt.Sprintf("user %s is not CheckIMAdmin userID", mcontext.GetOpUserID(ctx)))
}
-func ParseRedisInterfaceToken(redisToken any) (*tokenverify.Claims, error) {
- return tokenverify.GetClaimFromToken(string(redisToken.([]uint8)), Secret())
+func ParseRedisInterfaceToken(redisToken any, secret string) (*tokenverify.Claims, error) {
+ return tokenverify.GetClaimFromToken(string(redisToken.([]uint8)), Secret(secret))
}
-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)
+func IsManagerUserID(opUserID string, config *config.GlobalConfig) bool {
+ return (len(config.Manager.UserID) > 0 && utils.IsContain(opUserID, config.Manager.UserID)) || utils.IsContain(opUserID, config.IMAdmin.UserID)
}
-func WsVerifyToken(token, userID string, platformID int) error {
- claim, err := tokenverify.GetClaimFromToken(token, Secret())
+func WsVerifyToken(token, userID, secret string, platformID int) error {
+ claim, err := tokenverify.GetClaimFromToken(token, Secret(secret))
if err != nil {
return err
}
diff --git a/pkg/callbackstruct/group.go b/pkg/callbackstruct/group.go
index 5968f1e55..467061a4a 100644
--- a/pkg/callbackstruct/group.go
+++ b/pkg/callbackstruct/group.go
@@ -16,7 +16,6 @@ package callbackstruct
import (
common "github.com/OpenIMSDK/protocol/sdkws"
-
"github.com/openimsdk/open-im-server/v3/pkg/apistruct"
)
diff --git a/pkg/common/cmd/api.go b/pkg/common/cmd/api.go
index 00c6cb241..bee16fdad 100644
--- a/pkg/common/cmd/api.go
+++ b/pkg/common/cmd/api.go
@@ -15,37 +15,43 @@
package cmd
import (
- "fmt"
-
"github.com/OpenIMSDK/protocol/constant"
+ "github.com/openimsdk/open-im-server/v3/internal/api"
+ "github.com/openimsdk/open-im-server/v3/pkg/common/config"
"github.com/spf13/cobra"
-
- config2 "github.com/openimsdk/open-im-server/v3/pkg/common/config"
)
type ApiCmd struct {
*RootCmd
+ initFunc func(config *config.GlobalConfig, port int, promPort int) error
}
func NewApiCmd() *ApiCmd {
- ret := &ApiCmd{NewRootCmd("api")}
+ ret := &ApiCmd{RootCmd: NewRootCmd("api"), initFunc: api.Start}
ret.SetRootCmdPt(ret)
-
+ ret.addPreRun()
+ ret.addRunE()
return ret
}
-func (a *ApiCmd) AddApi(f func(port int, promPort int) error) {
+func (a *ApiCmd) addPreRun() {
+ a.Command.PreRun = func(cmd *cobra.Command, args []string) {
+ a.port = a.getPortFlag(cmd)
+ a.prometheusPort = a.getPrometheusPortFlag(cmd)
+ }
+}
+
+func (a *ApiCmd) addRunE() {
a.Command.RunE = func(cmd *cobra.Command, args []string) error {
- return f(a.getPortFlag(cmd), a.getPrometheusPortFlag(cmd))
+ return a.initFunc(a.config, a.port, a.prometheusPort)
}
}
func (a *ApiCmd) GetPortFromConfig(portType string) int {
- fmt.Println("GetPortFromConfig:", portType)
if portType == constant.FlagPort {
- return config2.Config.Api.OpenImApiPort[0]
+ return a.config.Api.OpenImApiPort[0]
} else if portType == constant.FlagPrometheusPort {
- return config2.Config.Prometheus.ApiPrometheusPort[0]
+ return a.config.Prometheus.ApiPrometheusPort[0]
}
return 0
}
diff --git a/pkg/common/cmd/cron_task.go b/pkg/common/cmd/cron_task.go
index 1b0e796ac..d8c9dd2a8 100644
--- a/pkg/common/cmd/cron_task.go
+++ b/pkg/common/cmd/cron_task.go
@@ -14,25 +14,35 @@
package cmd
-import "github.com/spf13/cobra"
+import (
+ "github.com/openimsdk/open-im-server/v3/internal/tools"
+ "github.com/openimsdk/open-im-server/v3/pkg/common/config"
+ "github.com/spf13/cobra"
+)
type CronTaskCmd struct {
*RootCmd
+ initFunc func(config *config.GlobalConfig) error
}
func NewCronTaskCmd() *CronTaskCmd {
- ret := &CronTaskCmd{NewRootCmd("cronTask", WithCronTaskLogName())}
+ ret := &CronTaskCmd{RootCmd: NewRootCmd("cronTask", WithCronTaskLogName()),
+ initFunc: tools.StartTask}
+ ret.addRunE()
ret.SetRootCmdPt(ret)
return ret
}
-func (c *CronTaskCmd) addRunE(f func() error) {
+func (c *CronTaskCmd) addRunE() {
c.Command.RunE = func(cmd *cobra.Command, args []string) error {
- return f()
+ return c.initFunc(c.config)
}
}
-func (c *CronTaskCmd) Exec(f func() error) error {
- c.addRunE(f)
+func (c *CronTaskCmd) Exec() error {
return c.Execute()
}
+
+func (c *CronTaskCmd) GetPortFromConfig(portType string) int {
+ return 0
+}
diff --git a/pkg/common/cmd/msg_gateway.go b/pkg/common/cmd/msg_gateway.go
index 25fcc1177..37aedd933 100644
--- a/pkg/common/cmd/msg_gateway.go
+++ b/pkg/common/cmd/msg_gateway.go
@@ -17,12 +17,9 @@ package cmd
import (
"log"
- "github.com/spf13/cobra"
-
"github.com/OpenIMSDK/protocol/constant"
-
"github.com/openimsdk/open-im-server/v3/internal/msggateway"
- v3config "github.com/openimsdk/open-im-server/v3/pkg/common/config"
+ "github.com/spf13/cobra"
)
type MsgGatewayCmd struct {
@@ -31,6 +28,7 @@ type MsgGatewayCmd struct {
func NewMsgGatewayCmd() *MsgGatewayCmd {
ret := &MsgGatewayCmd{NewRootCmd("msgGateway")}
+ ret.addRunE()
ret.SetRootCmdPt(ret)
return ret
}
@@ -52,25 +50,24 @@ func (m *MsgGatewayCmd) getWsPortFlag(cmd *cobra.Command) int {
func (m *MsgGatewayCmd) addRunE() {
m.Command.RunE = func(cmd *cobra.Command, args []string) error {
- return msggateway.RunWsAndServer(m.getPortFlag(cmd), m.getWsPortFlag(cmd), m.getPrometheusPortFlag(cmd))
+ return msggateway.RunWsAndServer(m.config, m.getPortFlag(cmd), m.getWsPortFlag(cmd), m.getPrometheusPortFlag(cmd))
}
}
func (m *MsgGatewayCmd) Exec() error {
- m.addRunE()
return m.Execute()
}
func (m *MsgGatewayCmd) GetPortFromConfig(portType string) int {
switch portType {
case constant.FlagWsPort:
- return v3config.Config.LongConnSvr.OpenImWsPort[0]
+ return m.config.LongConnSvr.OpenImWsPort[0]
case constant.FlagPort:
- return v3config.Config.LongConnSvr.OpenImMessageGatewayPort[0]
+ return m.config.LongConnSvr.OpenImMessageGatewayPort[0]
case constant.FlagPrometheusPort:
- return v3config.Config.Prometheus.MessageGatewayPrometheusPort[0]
+ return m.config.Prometheus.MessageGatewayPrometheusPort[0]
default:
return 0
diff --git a/pkg/common/cmd/msg_transfer.go b/pkg/common/cmd/msg_transfer.go
index f99b625c7..d98154f3a 100644
--- a/pkg/common/cmd/msg_transfer.go
+++ b/pkg/common/cmd/msg_transfer.go
@@ -18,11 +18,8 @@ import (
"fmt"
"github.com/OpenIMSDK/protocol/constant"
- "github.com/spf13/cobra"
-
- config2 "github.com/openimsdk/open-im-server/v3/pkg/common/config"
-
"github.com/openimsdk/open-im-server/v3/internal/msgtransfer"
+ "github.com/spf13/cobra"
)
type MsgTransferCmd struct {
@@ -31,39 +28,40 @@ type MsgTransferCmd struct {
func NewMsgTransferCmd() *MsgTransferCmd {
ret := &MsgTransferCmd{NewRootCmd("msgTransfer")}
+ ret.addRunE()
ret.SetRootCmdPt(ret)
return ret
}
func (m *MsgTransferCmd) addRunE() {
m.Command.RunE = func(cmd *cobra.Command, args []string) error {
- return msgtransfer.StartTransfer(m.getPrometheusPortFlag(cmd))
+ return msgtransfer.StartTransfer(m.config, m.getPrometheusPortFlag(cmd))
}
}
func (m *MsgTransferCmd) Exec() error {
- m.addRunE()
return m.Execute()
}
func (m *MsgTransferCmd) GetPortFromConfig(portType string) int {
- fmt.Println("GetPortFromConfig:", portType)
if portType == constant.FlagPort {
return 0
} else if portType == constant.FlagPrometheusPort {
n := m.getTransferProgressFlagValue()
- return config2.Config.Prometheus.MessageTransferPrometheusPort[n]
+ return m.config.Prometheus.MessageTransferPrometheusPort[n]
}
return 0
}
+
func (m *MsgTransferCmd) AddTransferProgressFlag() {
m.Command.Flags().IntP(constant.FlagTransferProgressIndex, "n", 0, "transfer progress index")
}
+
func (m *MsgTransferCmd) getTransferProgressFlagValue() int {
- nindex, err := m.Command.Flags().GetInt(constant.FlagTransferProgressIndex)
+ nIndex, err := m.Command.Flags().GetInt(constant.FlagTransferProgressIndex)
if err != nil {
- fmt.Println("get transfercmd error,make sure it is k8s env or not")
+ fmt.Println("get transfer cmd error,make sure it is k8s env or not")
return 0
}
- return nindex
+ return nIndex
}
diff --git a/pkg/common/cmd/msg_utils.go b/pkg/common/cmd/msg_utils.go
index cfaf631ec..df15acd87 100644
--- a/pkg/common/cmd/msg_utils.go
+++ b/pkg/common/cmd/msg_utils.go
@@ -15,14 +15,14 @@
package cmd
import (
- "github.com/spf13/cobra"
-
"github.com/openimsdk/open-im-server/v3/internal/tools"
+ util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil"
+ "github.com/spf13/cobra"
)
type MsgUtilsCmd struct {
cobra.Command
- msgTool *tools.MsgTool
+ MsgTool *tools.MsgTool
}
func (m *MsgUtilsCmd) AddUserIDFlag() {
@@ -38,19 +38,19 @@ func (m *MsgUtilsCmd) AddFixAllFlag() {
m.Command.PersistentFlags().BoolP("fixAll", "f", false, "openIM fix all seqs")
}
-func (m *MsgUtilsCmd) getFixAllFlag(cmdLines *cobra.Command) bool {
+/* func (m *MsgUtilsCmd) getFixAllFlag(cmdLines *cobra.Command) bool {
fixAll, _ := cmdLines.Flags().GetBool("fixAll")
return fixAll
-}
+} */
func (m *MsgUtilsCmd) AddClearAllFlag() {
m.Command.PersistentFlags().BoolP("clearAll", "c", false, "openIM clear all seqs")
}
-func (m *MsgUtilsCmd) getClearAllFlag(cmdLines *cobra.Command) bool {
+/* func (m *MsgUtilsCmd) getClearAllFlag(cmdLines *cobra.Command) bool {
clearAll, _ := cmdLines.Flags().GetBool("clearAll")
return clearAll
-}
+} */
func (m *MsgUtilsCmd) AddSuperGroupIDFlag() {
m.Command.PersistentFlags().StringP("superGroupID", "g", "", "openIM superGroupID")
@@ -65,19 +65,19 @@ func (m *MsgUtilsCmd) AddBeginSeqFlag() {
m.Command.PersistentFlags().Int64P("beginSeq", "b", 0, "openIM beginSeq")
}
-func (m *MsgUtilsCmd) getBeginSeqFlag(cmdLines *cobra.Command) int64 {
+/* func (m *MsgUtilsCmd) getBeginSeqFlag(cmdLines *cobra.Command) int64 {
beginSeq, _ := cmdLines.Flags().GetInt64("beginSeq")
return beginSeq
-}
+} */
func (m *MsgUtilsCmd) AddLimitFlag() {
m.Command.PersistentFlags().Int64P("limit", "l", 0, "openIM limit")
}
-func (m *MsgUtilsCmd) getLimitFlag(cmdLines *cobra.Command) int64 {
+/* func (m *MsgUtilsCmd) getLimitFlag(cmdLines *cobra.Command) int64 {
limit, _ := cmdLines.Flags().GetInt64("limit")
return limit
-}
+} */
func (m *MsgUtilsCmd) Execute() error {
return m.Command.Execute()
@@ -136,9 +136,9 @@ func NewSeqCmd() *SeqCmd {
func (s *SeqCmd) GetSeqCmd() *cobra.Command {
s.Command.Run = func(cmdLines *cobra.Command, args []string) {
- _, err := tools.InitMsgTool()
+ _, err := tools.InitMsgTool(s.MsgTool.Config)
if err != nil {
- panic(err)
+ util.ExitWithError(err)
}
userID := s.getUserIDFlag(cmdLines)
superGroupID := s.getSuperGroupIDFlag(cmdLines)
diff --git a/pkg/common/cmd/root.go b/pkg/common/cmd/root.go
index 66bec61a7..478942a5b 100644
--- a/pkg/common/cmd/root.go
+++ b/pkg/common/cmd/root.go
@@ -17,26 +17,29 @@ package cmd
import (
"fmt"
- config2 "github.com/openimsdk/open-im-server/v3/pkg/common/config"
-
- "github.com/spf13/cobra"
- _ "go.uber.org/automaxprocs"
-
"github.com/OpenIMSDK/protocol/constant"
+ "github.com/OpenIMSDK/tools/errs"
"github.com/OpenIMSDK/tools/log"
-
"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"
)
type RootCmdPt interface {
GetPortFromConfig(portType string) int
}
+
type RootCmd struct {
Command cobra.Command
Name string
port int
prometheusPort int
cmdItf RootCmdPt
+ config *config.GlobalConfig
+}
+
+func (rc *RootCmd) Port() int {
+ return rc.port
}
type CmdOpts struct {
@@ -45,7 +48,7 @@ type CmdOpts struct {
func WithCronTaskLogName() func(*CmdOpts) {
return func(opts *CmdOpts) {
- opts.loggerPrefixName = "openim.crontask.log.all"
+ opts.loggerPrefixName = "openim-crontask"
}
}
@@ -56,7 +59,7 @@ func WithLogName(logName string) func(*CmdOpts) {
}
func NewRootCmd(name string, opts ...func(*CmdOpts)) *RootCmd {
- rootCmd := &RootCmd{Name: name}
+ rootCmd := &RootCmd{Name: name, config: config.NewGlobalConfig()}
cmd := cobra.Command{
Use: "Start openIM application",
Short: fmt.Sprintf(`Start %s `, name),
@@ -78,7 +81,7 @@ func (rc *RootCmd) persistentPreRun(cmd *cobra.Command, opts ...func(*CmdOpts))
cmdOpts := rc.applyOptions(opts...)
if err := rc.initializeLogger(cmdOpts); err != nil {
- return fmt.Errorf("failed to initialize from config: %w", err)
+ return errs.Wrap(err, "failed to initialize logger")
}
return nil
@@ -98,7 +101,7 @@ func (rc *RootCmd) applyOptions(opts ...func(*CmdOpts)) *CmdOpts {
}
func (rc *RootCmd) initializeLogger(cmdOpts *CmdOpts) error {
- logConfig := config.Config.Log
+ logConfig := rc.config.Log
return log.InitFromConfig(
@@ -115,7 +118,7 @@ func (rc *RootCmd) initializeLogger(cmdOpts *CmdOpts) error {
func defaultCmdOpts() *CmdOpts {
return &CmdOpts{
- loggerPrefixName: "OpenIM.log.all",
+ loggerPrefixName: "openim-all",
}
}
@@ -134,7 +137,8 @@ func (r *RootCmd) AddPortFlag() {
func (r *RootCmd) getPortFlag(cmd *cobra.Command) int {
port, err := cmd.Flags().GetInt(constant.FlagPort)
if err != nil {
- fmt.Println("Error getting ws port flag:", err)
+ // Wrapping the error with additional context
+ return 0
}
if port == 0 {
port = r.PortFromConfig(constant.FlagPort)
@@ -142,6 +146,7 @@ func (r *RootCmd) getPortFlag(cmd *cobra.Command) int {
return port
}
+// // GetPortFlag returns the port flag.
func (r *RootCmd) GetPortFlag() int {
return r.port
}
@@ -151,9 +156,12 @@ func (r *RootCmd) AddPrometheusPortFlag() {
}
func (r *RootCmd) getPrometheusPortFlag(cmd *cobra.Command) int {
- port, _ := cmd.Flags().GetInt(constant.FlagPrometheusPort)
- if port == 0 {
+ port, err := cmd.Flags().GetInt(constant.FlagPrometheusPort)
+ if err != nil || port == 0 {
port = r.PortFromConfig(constant.FlagPrometheusPort)
+ if err != nil {
+ return 0
+ }
}
return port
}
@@ -164,8 +172,8 @@ func (r *RootCmd) GetPrometheusPortFlag() int {
func (r *RootCmd) getConfFromCmdAndInit(cmdLines *cobra.Command) error {
configFolderPath, _ := cmdLines.Flags().GetString(constant.FlagConf)
- fmt.Println("configFolderPath:", configFolderPath)
- return config2.InitConfig(configFolderPath)
+ fmt.Println("The directory of the configuration file to start the process:", configFolderPath)
+ return config2.InitConfig(r.config, configFolderPath)
}
func (r *RootCmd) Execute() error {
@@ -176,11 +184,8 @@ func (r *RootCmd) AddCommand(cmds ...*cobra.Command) {
r.Command.AddCommand(cmds...)
}
-func (r *RootCmd) GetPortFromConfig(portType string) int {
- fmt.Println("RootCmd.GetPortFromConfig:", portType)
- return 0
-}
func (r *RootCmd) PortFromConfig(portType string) int {
- fmt.Println("PortFromConfig:", portType)
- return r.cmdItf.GetPortFromConfig(portType)
+ // Retrieve the port and cache it
+ port := r.cmdItf.GetPortFromConfig(portType)
+ return port
}
diff --git a/pkg/common/cmd/rpc.go b/pkg/common/cmd/rpc.go
index ea2a00b07..9c6dbddd6 100644
--- a/pkg/common/cmd/rpc.go
+++ b/pkg/common/cmd/rpc.go
@@ -18,99 +18,139 @@ import (
"errors"
"github.com/OpenIMSDK/protocol/constant"
+ "github.com/OpenIMSDK/tools/discoveryregistry"
+ "github.com/OpenIMSDK/tools/errs"
+ config2 "github.com/openimsdk/open-im-server/v3/pkg/common/config"
+ "github.com/openimsdk/open-im-server/v3/pkg/common/startrpc"
"github.com/spf13/cobra"
"google.golang.org/grpc"
-
- config2 "github.com/openimsdk/open-im-server/v3/pkg/common/config"
-
- "github.com/OpenIMSDK/tools/discoveryregistry"
-
- "github.com/openimsdk/open-im-server/v3/pkg/common/startrpc"
)
+type rpcInitFuc func(config *config2.GlobalConfig, disCov discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) error
+
type RpcCmd struct {
*RootCmd
+ RpcRegisterName string
+ initFunc rpcInitFuc
}
-func NewRpcCmd(name string) *RpcCmd {
- ret := &RpcCmd{NewRootCmd(name)}
+func NewRpcCmd(name string, initFunc rpcInitFuc) *RpcCmd {
+ ret := &RpcCmd{RootCmd: NewRootCmd(name), initFunc: initFunc}
+ ret.addPreRun()
+ ret.addRunE()
ret.SetRootCmdPt(ret)
return ret
}
-func (a *RpcCmd) Exec() error {
- a.Command.Run = func(cmd *cobra.Command, args []string) {
+func (a *RpcCmd) addPreRun() {
+ a.Command.PreRun = func(cmd *cobra.Command, args []string) {
a.port = a.getPortFlag(cmd)
a.prometheusPort = a.getPrometheusPortFlag(cmd)
}
+}
+
+func (a *RpcCmd) addRunE() {
+ a.Command.RunE = func(cmd *cobra.Command, args []string) error {
+ rpcRegisterName, err := a.GetRpcRegisterNameFromConfig()
+ if err != nil {
+ return err
+ } else {
+ return a.StartSvr(rpcRegisterName, a.initFunc)
+ }
+ }
+}
+
+func (a *RpcCmd) Exec() error {
return a.Execute()
}
-func (a *RpcCmd) StartSvr(name string, rpcFn func(discov discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) error) error {
+func (a *RpcCmd) StartSvr(name string, rpcFn func(config *config2.GlobalConfig, disCov discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) error) error {
if a.GetPortFlag() == 0 {
- return errors.New("port is required")
+ return errs.Wrap(errors.New("port is required"))
}
- return startrpc.Start(a.GetPortFlag(), name, a.GetPrometheusPortFlag(), rpcFn)
+ return startrpc.Start(a.GetPortFlag(), name, a.GetPrometheusPortFlag(), a.config, rpcFn)
}
func (a *RpcCmd) GetPortFromConfig(portType string) int {
switch a.Name {
case RpcPushServer:
if portType == constant.FlagPort {
- return config2.Config.RpcPort.OpenImPushPort[0]
+ return a.config.RpcPort.OpenImPushPort[0]
}
if portType == constant.FlagPrometheusPort {
- return config2.Config.Prometheus.PushPrometheusPort[0]
+ return a.config.Prometheus.PushPrometheusPort[0]
}
case RpcAuthServer:
if portType == constant.FlagPort {
- return config2.Config.RpcPort.OpenImAuthPort[0]
+ return a.config.RpcPort.OpenImAuthPort[0]
}
if portType == constant.FlagPrometheusPort {
- return config2.Config.Prometheus.AuthPrometheusPort[0]
+ return a.config.Prometheus.AuthPrometheusPort[0]
}
case RpcConversationServer:
if portType == constant.FlagPort {
- return config2.Config.RpcPort.OpenImConversationPort[0]
+ return a.config.RpcPort.OpenImConversationPort[0]
}
if portType == constant.FlagPrometheusPort {
- return config2.Config.Prometheus.ConversationPrometheusPort[0]
+ return a.config.Prometheus.ConversationPrometheusPort[0]
}
case RpcFriendServer:
if portType == constant.FlagPort {
- return config2.Config.RpcPort.OpenImFriendPort[0]
+ return a.config.RpcPort.OpenImFriendPort[0]
}
if portType == constant.FlagPrometheusPort {
- return config2.Config.Prometheus.FriendPrometheusPort[0]
+ return a.config.Prometheus.FriendPrometheusPort[0]
}
case RpcGroupServer:
if portType == constant.FlagPort {
- return config2.Config.RpcPort.OpenImGroupPort[0]
+ return a.config.RpcPort.OpenImGroupPort[0]
}
if portType == constant.FlagPrometheusPort {
- return config2.Config.Prometheus.GroupPrometheusPort[0]
+ return a.config.Prometheus.GroupPrometheusPort[0]
}
case RpcMsgServer:
if portType == constant.FlagPort {
- return config2.Config.RpcPort.OpenImMessagePort[0]
+ return a.config.RpcPort.OpenImMessagePort[0]
}
if portType == constant.FlagPrometheusPort {
- return config2.Config.Prometheus.MessagePrometheusPort[0]
+ return a.config.Prometheus.MessagePrometheusPort[0]
}
case RpcThirdServer:
if portType == constant.FlagPort {
- return config2.Config.RpcPort.OpenImThirdPort[0]
+ return a.config.RpcPort.OpenImThirdPort[0]
}
if portType == constant.FlagPrometheusPort {
- return config2.Config.Prometheus.ThirdPrometheusPort[0]
+ return a.config.Prometheus.ThirdPrometheusPort[0]
}
case RpcUserServer:
if portType == constant.FlagPort {
- return config2.Config.RpcPort.OpenImUserPort[0]
+ return a.config.RpcPort.OpenImUserPort[0]
}
if portType == constant.FlagPrometheusPort {
- return config2.Config.Prometheus.UserPrometheusPort[0]
+ return a.config.Prometheus.UserPrometheusPort[0]
}
}
return 0
}
+
+func (a *RpcCmd) GetRpcRegisterNameFromConfig() (string, error) {
+ switch a.Name {
+ case RpcPushServer:
+ return a.config.RpcRegisterName.OpenImPushName, nil
+ case RpcAuthServer:
+ return a.config.RpcRegisterName.OpenImAuthName, nil
+ case RpcConversationServer:
+ return a.config.RpcRegisterName.OpenImConversationName, nil
+ case RpcFriendServer:
+ return a.config.RpcRegisterName.OpenImFriendName, nil
+ case RpcGroupServer:
+ return a.config.RpcRegisterName.OpenImGroupName, nil
+ case RpcMsgServer:
+ return a.config.RpcRegisterName.OpenImMsgName, nil
+ case RpcThirdServer:
+ return a.config.RpcRegisterName.OpenImThirdName, nil
+ case RpcUserServer:
+ return a.config.RpcRegisterName.OpenImUserName, nil
+ }
+ return "", errs.Wrap(errors.New("can not get rpc register name"), a.Name)
+}
diff --git a/pkg/common/config/config.go b/pkg/common/config/config.go
index 20eea0464..8bc871355 100644
--- a/pkg/common/config/config.go
+++ b/pkg/common/config/config.go
@@ -22,7 +22,7 @@ import (
"gopkg.in/yaml.v3"
)
-var Config configStruct
+var Config GlobalConfig
const ConfKey = "conf"
@@ -58,7 +58,7 @@ type MYSQL struct {
SlowThreshold int `yaml:"slowThreshold"`
}
-type configStruct struct {
+type GlobalConfig struct {
Envs struct {
Discovery string `yaml:"discovery"`
}
@@ -165,6 +165,14 @@ type configStruct struct {
SessionToken string `yaml:"sessionToken"`
PublicRead bool `yaml:"publicRead"`
} `yaml:"kodo"`
+ Aws struct {
+ Endpoint string `yaml:"endpoint"`
+ Region string `yaml:"region"`
+ Bucket string `yaml:"bucket"`
+ AccessKeyID string `yaml:"accessKeyID"`
+ AccessKeySecret string `yaml:"accessKeySecret"`
+ PublicRead bool `yaml:"publicRead"`
+ } `yaml:"aws"`
} `yaml:"object"`
RpcPort struct {
@@ -334,6 +342,10 @@ type configStruct struct {
Notification notification `yaml:"notification"`
}
+func NewGlobalConfig() *GlobalConfig {
+ return &GlobalConfig{}
+}
+
type notification struct {
GroupCreated NotificationConf `yaml:"groupCreated"`
GroupInfoSet NotificationConf `yaml:"groupInfoSet"`
@@ -400,7 +412,7 @@ type localCache struct {
Conversation LocalCache `yaml:"conversation"`
}
-func (c *configStruct) GetServiceNames() []string {
+func (c *GlobalConfig) GetServiceNames() []string {
return []string{
c.RpcRegisterName.OpenImUserName,
c.RpcRegisterName.OpenImFriendName,
@@ -414,7 +426,7 @@ func (c *configStruct) GetServiceNames() []string {
}
}
-func (c *configStruct) RegisterConf2Registry(registry discoveryregistry.SvcDiscoveryRegistry) error {
+func (c *GlobalConfig) RegisterConf2Registry(registry discoveryregistry.SvcDiscoveryRegistry) error {
data, err := yaml.Marshal(c)
if err != nil {
return err
@@ -422,11 +434,11 @@ func (c *configStruct) RegisterConf2Registry(registry discoveryregistry.SvcDisco
return registry.RegisterConf2Registry(ConfKey, data)
}
-func (c *configStruct) GetConfFromRegistry(registry discoveryregistry.SvcDiscoveryRegistry) ([]byte, error) {
+func (c *GlobalConfig) GetConfFromRegistry(registry discoveryregistry.SvcDiscoveryRegistry) ([]byte, error) {
return registry.GetConfFromRegistry(ConfKey)
}
-func (c *configStruct) EncodeConfig() []byte {
+func (c *GlobalConfig) EncodeConfig() []byte {
buf := bytes.NewBuffer(nil)
if err := yaml.NewEncoder(buf).Encode(c); err != nil {
panic(err)
diff --git a/pkg/common/config/parse.go b/pkg/common/config/parse.go
index 64719d6a1..bfbf6daf7 100644
--- a/pkg/common/config/parse.go
+++ b/pkg/common/config/parse.go
@@ -83,6 +83,9 @@ func GetOptionsByNotification(cfg NotificationConf) msgprocessor.Options {
return opts
}
+// initConfig loads configuration from a specified path into the provided config structure.
+// If the specified config file does not exist, it attempts to load from the project's default "config" directory.
+// It logs informative messages regarding the configuration path being used.
func initConfig(config any, configName, configFolderPath string) error {
configFolderPath = filepath.Join(configFolderPath, configName)
_, err := os.Stat(configFolderPath)
@@ -101,12 +104,12 @@ func initConfig(config any, configName, configFolderPath string) error {
if err = yaml.Unmarshal(data, config); err != nil {
return fmt.Errorf("unmarshal yaml error: %w", err)
}
- fmt.Println("use config", configFolderPath)
+ fmt.Println("The path of the configuration file to start the process:", configFolderPath)
return nil
}
-func InitConfig(configFolderPath string) error {
+func InitConfig(config *GlobalConfig, configFolderPath string) error {
if configFolderPath == "" {
envConfigPath := os.Getenv("OPENIMCONFIG")
if envConfigPath != "" {
@@ -116,9 +119,9 @@ func InitConfig(configFolderPath string) error {
}
}
- if err := initConfig(&Config, FileName, configFolderPath); err != nil {
+ if err := initConfig(config, FileName, configFolderPath); err != nil {
return err
}
- return initConfig(&Config.Notification, NotificationFileName, configFolderPath)
+ return initConfig(&config.Notification, NotificationFileName, configFolderPath)
}
diff --git a/pkg/common/config/parse_test.go b/pkg/common/config/parse_test.go
index 30cb270fe..9b964a277 100644
--- a/pkg/common/config/parse_test.go
+++ b/pkg/common/config/parse_test.go
@@ -33,7 +33,7 @@ func TestGetDefaultConfigPath(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
- if got := GetDefaultConfigPath(); got != tt.want {
+ if got, _ := GetDefaultConfigPath(); got != tt.want {
t.Errorf("GetDefaultConfigPath() = %v, want %v", got, tt.want)
}
})
@@ -49,7 +49,7 @@ func TestGetProjectRoot(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
- if got := GetProjectRoot(); got != tt.want {
+ if got, _ := GetProjectRoot(); got != tt.want {
t.Errorf("GetProjectRoot() = %v, want %v", got, tt.want)
}
})
@@ -105,13 +105,14 @@ func TestInitConfig(t *testing.T) {
tests := []struct {
name string
args args
+ config *GlobalConfig
wantErr bool
}{
// TODO: Add test cases.
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
- if err := InitConfig(tt.args.configFolderPath); (err != nil) != tt.wantErr {
+ if err := InitConfig(tt.config, tt.args.configFolderPath); (err != nil) != tt.wantErr {
t.Errorf("InitConfig() error = %v, wantErr %v", err, tt.wantErr)
}
})
diff --git a/pkg/common/convert/black.go b/pkg/common/convert/black.go
index 50c270dcb..683517fbc 100644
--- a/pkg/common/convert/black.go
+++ b/pkg/common/convert/black.go
@@ -19,15 +19,10 @@ import (
"github.com/OpenIMSDK/protocol/sdkws"
sdk "github.com/OpenIMSDK/protocol/sdkws"
-
"github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
)
-func BlackDB2Pb(
- ctx context.Context,
- blackDBs []*relation.BlackModel,
- f func(ctx context.Context, userIDs []string) (map[string]*sdkws.UserInfo, error),
-) (blackPbs []*sdk.BlackInfo, err error) {
+func BlackDB2Pb(ctx context.Context, blackDBs []*relation.BlackModel, f func(ctx context.Context, userIDs []string) (map[string]*sdkws.UserInfo, error)) (blackPbs []*sdk.BlackInfo, err error) {
if len(blackDBs) == 0 {
return nil, nil
}
diff --git a/pkg/common/convert/conversation.go b/pkg/common/convert/conversation.go
index 165262b7f..b3f4913eb 100644
--- a/pkg/common/convert/conversation.go
+++ b/pkg/common/convert/conversation.go
@@ -17,7 +17,6 @@ package convert
import (
"github.com/OpenIMSDK/protocol/conversation"
"github.com/OpenIMSDK/tools/utils"
-
"github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
)
diff --git a/pkg/common/convert/friend.go b/pkg/common/convert/friend.go
index 27bd595ad..4231eb49d 100644
--- a/pkg/common/convert/friend.go
+++ b/pkg/common/convert/friend.go
@@ -20,13 +20,15 @@ import (
"github.com/OpenIMSDK/protocol/sdkws"
"github.com/OpenIMSDK/tools/utils"
-
"github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
)
func FriendPb2DB(friend *sdkws.FriendInfo) *relation.FriendModel {
dbFriend := &relation.FriendModel{}
- utils.CopyStructFields(dbFriend, friend)
+ err := utils.CopyStructFields(dbFriend, friend)
+ if err != nil {
+ return nil
+ }
dbFriend.FriendUserID = friend.FriendUser.UserID
dbFriend.CreateTime = utils.UnixSecondToTime(friend.CreateTime)
return dbFriend
@@ -69,7 +71,11 @@ func FriendsDB2Pb(
}
for _, friend := range friendsDB {
friendPb := &sdkws.FriendInfo{FriendUser: &sdkws.UserInfo{}}
- utils.CopyStructFields(friendPb, friend)
+ err := utils.CopyStructFields(friendPb, friend)
+ if err != nil {
+ return nil, err
+ }
+
friendPb.FriendUser.UserID = users[friend.FriendUserID].UserID
friendPb.FriendUser.Nickname = users[friend.FriendUserID].Nickname
friendPb.FriendUser.FaceURL = users[friend.FriendUserID].FaceURL
@@ -79,10 +85,10 @@ func FriendsDB2Pb(
friendsPb = append(friendsPb, friendPb)
}
return friendsPb, nil
+
}
-func FriendRequestDB2Pb(
- ctx context.Context,
+func FriendRequestDB2Pb(ctx context.Context,
friendRequests []*relation.FriendRequestModel,
getUsers func(ctx context.Context, userIDs []string) (map[string]*sdkws.UserInfo, error),
) ([]*sdkws.FriendRequest, error) {
diff --git a/pkg/common/convert/group.go b/pkg/common/convert/group.go
index 18940f518..63372f21d 100644
--- a/pkg/common/convert/group.go
+++ b/pkg/common/convert/group.go
@@ -19,7 +19,6 @@ import (
pbgroup "github.com/OpenIMSDK/protocol/group"
sdkws "github.com/OpenIMSDK/protocol/sdkws"
-
"github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
)
diff --git a/pkg/common/convert/msg.go b/pkg/common/convert/msg.go
index 56f71f018..34638049b 100644
--- a/pkg/common/convert/msg.go
+++ b/pkg/common/convert/msg.go
@@ -17,7 +17,6 @@ package convert
import (
"github.com/OpenIMSDK/protocol/constant"
"github.com/OpenIMSDK/protocol/sdkws"
-
"github.com/openimsdk/open-im-server/v3/pkg/common/db/table/unrelation"
)
diff --git a/pkg/common/convert/user.go b/pkg/common/convert/user.go
index 62f80e458..38afd8c19 100644
--- a/pkg/common/convert/user.go
+++ b/pkg/common/convert/user.go
@@ -18,7 +18,6 @@ import (
"time"
"github.com/OpenIMSDK/protocol/sdkws"
-
relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
)
diff --git a/pkg/common/db/cache/black.go b/pkg/common/db/cache/black.go
index 8328306ff..fd743e917 100644
--- a/pkg/common/db/cache/black.go
+++ b/pkg/common/db/cache/black.go
@@ -22,9 +22,8 @@ import (
"time"
"github.com/dtm-labs/rockscache"
- "github.com/redis/go-redis/v9"
-
relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
+ "github.com/redis/go-redis/v9"
)
const (
@@ -49,11 +48,7 @@ type BlackCacheRedis struct {
blackDB relationtb.BlackModelInterface
}
-func NewBlackCacheRedis(
- rdb redis.UniversalClient,
- blackDB relationtb.BlackModelInterface,
- options rockscache.Options,
-) BlackCache {
+func NewBlackCacheRedis(rdb redis.UniversalClient, blackDB relationtb.BlackModelInterface, options rockscache.Options) BlackCache {
rcClient := rockscache.NewClient(rdb, options)
mc := NewMetaCacheRedis(rcClient)
b := config.Config.LocalCache.Friend
diff --git a/pkg/common/db/cache/conversation.go b/pkg/common/db/cache/conversation.go
index 61489ff92..8aee6ded3 100644
--- a/pkg/common/db/cache/conversation.go
+++ b/pkg/common/db/cache/conversation.go
@@ -24,12 +24,10 @@ import (
"strings"
"time"
- "github.com/dtm-labs/rockscache"
- "github.com/redis/go-redis/v9"
-
"github.com/OpenIMSDK/tools/utils"
-
+ "github.com/dtm-labs/rockscache"
relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
+ "github.com/redis/go-redis/v9"
)
const (
@@ -227,16 +225,16 @@ func (c *ConversationRedisCache) DelConversations(ownerUserID string, conversati
return cache
}
-func (c *ConversationRedisCache) getConversationIndex(convsation *relationtb.ConversationModel, keys []string) (int, error) {
- key := c.getConversationKey(convsation.OwnerUserID, convsation.ConversationID)
- for _i, _key := range keys {
- if _key == key {
- return _i, nil
- }
- }
+// func (c *ConversationRedisCache) getConversationIndex(convsation *relationtb.ConversationModel, keys []string) (int, error) {
+// key := c.getConversationKey(convsation.OwnerUserID, convsation.ConversationID)
+// for _i, _key := range keys {
+// if _key == key {
+// return _i, nil
+// }
+// }
- return 0, errors.New("not found key:" + key + " in keys")
-}
+// return 0, errors.New("not found key:" + key + " in keys")
+// }
func (c *ConversationRedisCache) GetConversations(ctx context.Context, ownerUserID string, conversationIDs []string) ([]*relationtb.ConversationModel, error) {
//var keys []string
@@ -340,7 +338,7 @@ func (c *ConversationRedisCache) DelSuperGroupRecvMsgNotNotifyUserIDsHash(groupI
return cache
}
-func (c *ConversationRedisCache) getUserAllHasReadSeqsIndex(conversationID string, conversationIDs []string) (int, error) {
+/* func (c *ConversationRedisCache) getUserAllHasReadSeqsIndex(conversationID string, conversationIDs []string) (int, error) {
for _i, _conversationID := range conversationIDs {
if _conversationID == conversationID {
return _i, nil
@@ -348,21 +346,21 @@ func (c *ConversationRedisCache) getUserAllHasReadSeqsIndex(conversationID strin
}
return 0, errors.New("not found key:" + conversationID + " in keys")
-}
+} */
-//func (c *ConversationRedisCache) GetUserAllHasReadSeqs(ctx context.Context, ownerUserID string) (map[string]int64, error) {
-// conversationIDs, err := c.GetUserConversationIDs(ctx, ownerUserID)
-// if err != nil {
-// return nil, err
-// }
-// var keys []string
-// for _, conversarionID := range conversationIDs {
-// keys = append(keys, c.getConversationHasReadSeqKey(ownerUserID, conversarionID))
-// }
-// return batchGetCacheMap(ctx, c.rcClient, keys, conversationIDs, c.expireTime, c.getUserAllHasReadSeqsIndex, func(ctx context.Context) (map[string]int64, error) {
-// return c.conversationDB.GetUserAllHasReadSeqs(ctx, ownerUserID)
-// })
-//}
+/* func (c *ConversationRedisCache) GetUserAllHasReadSeqs(ctx context.Context, ownerUserID string) (map[string]int64, error) {
+ conversationIDs, err := c.GetUserConversationIDs(ctx, ownerUserID)
+ if err != nil {
+ return nil, err
+ }
+ var keys []string
+ for _, conversarionID := range conversationIDs {
+ keys = append(keys, c.getConversationHasReadSeqKey(ownerUserID, conversarionID))
+ }
+ return batchGetCacheMap(ctx, c.rcClient, keys, conversationIDs, c.expireTime, c.getUserAllHasReadSeqsIndex, func(ctx context.Context) (map[string]int64, error) {
+ return c.conversationDB.GetUserAllHasReadSeqs(ctx, ownerUserID)
+ })
+} */
func (c *ConversationRedisCache) DelUserAllHasReadSeqs(ownerUserID string, conversationIDs ...string) ConversationCache {
cache := c.NewCache()
diff --git a/pkg/common/db/cache/friend.go b/pkg/common/db/cache/friend.go
index d09d00312..30b8bf7ea 100644
--- a/pkg/common/db/cache/friend.go
+++ b/pkg/common/db/cache/friend.go
@@ -21,12 +21,10 @@ import (
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
"time"
- "github.com/dtm-labs/rockscache"
- "github.com/redis/go-redis/v9"
-
"github.com/OpenIMSDK/tools/utils"
-
+ "github.com/dtm-labs/rockscache"
relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
+ "github.com/redis/go-redis/v9"
)
const (
diff --git a/pkg/common/db/cache/group.go b/pkg/common/db/cache/group.go
index 71f5d06fd..37b21ae90 100644
--- a/pkg/common/db/cache/group.go
+++ b/pkg/common/db/cache/group.go
@@ -23,15 +23,11 @@ import (
"github.com/OpenIMSDK/protocol/constant"
"github.com/OpenIMSDK/tools/errs"
-
"github.com/OpenIMSDK/tools/log"
-
- "github.com/dtm-labs/rockscache"
- "github.com/redis/go-redis/v9"
-
"github.com/OpenIMSDK/tools/utils"
-
+ "github.com/dtm-labs/rockscache"
relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
+ "github.com/redis/go-redis/v9"
)
const (
diff --git a/pkg/common/db/cache/init_redis.go b/pkg/common/db/cache/init_redis.go
index 1308e9649..8f4e2c592 100644
--- a/pkg/common/db/cache/init_redis.go
+++ b/pkg/common/db/cache/init_redis.go
@@ -22,12 +22,10 @@ import (
"strings"
"time"
- "github.com/redis/go-redis/v9"
-
"github.com/OpenIMSDK/tools/errs"
"github.com/OpenIMSDK/tools/mw/specialerror"
-
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
+ "github.com/redis/go-redis/v9"
)
var (
@@ -40,32 +38,32 @@ const (
)
// NewRedis Initialize redis connection.
-func NewRedis() (redis.UniversalClient, error) {
+func NewRedis(config *config.GlobalConfig) (redis.UniversalClient, error) {
if redisClient != nil {
return redisClient, nil
}
// Read configuration from environment variables
- overrideConfigFromEnv()
+ overrideConfigFromEnv(config)
- if len(config.Config.Redis.Address) == 0 {
- return nil, errors.New("redis address is empty")
+ if len(config.Redis.Address) == 0 {
+ return nil, errs.Wrap(errors.New("redis address is empty"))
}
specialerror.AddReplace(redis.Nil, errs.ErrRecordNotFound)
var rdb redis.UniversalClient
- if len(config.Config.Redis.Address) > 1 || config.Config.Redis.ClusterMode {
+ if len(config.Redis.Address) > 1 || config.Redis.ClusterMode {
rdb = redis.NewClusterClient(&redis.ClusterOptions{
- Addrs: config.Config.Redis.Address,
- Username: config.Config.Redis.Username,
- Password: config.Config.Redis.Password, // no password set
+ Addrs: config.Redis.Address,
+ Username: config.Redis.Username,
+ Password: config.Redis.Password, // no password set
PoolSize: 50,
MaxRetries: maxRetry,
})
} else {
rdb = redis.NewClient(&redis.Options{
- Addr: config.Config.Redis.Address[0],
- Username: config.Config.Redis.Username,
- Password: config.Config.Redis.Password,
+ Addr: config.Redis.Address[0],
+ Username: config.Redis.Username,
+ Password: config.Redis.Password,
DB: 0, // use default DB
PoolSize: 100, // connection pool size
MaxRetries: maxRetry,
@@ -77,30 +75,33 @@ func NewRedis() (redis.UniversalClient, error) {
defer cancel()
err = rdb.Ping(ctx).Err()
if err != nil {
- return nil, fmt.Errorf("redis ping %w", err)
+ errMsg := fmt.Sprintf("address:%s, username:%s, password:%s, clusterMode:%t, enablePipeline:%t", config.Redis.Address, config.Redis.Username,
+ config.Redis.Password, config.Redis.ClusterMode, config.Redis.EnablePipeline)
+ return nil, errs.Wrap(err, errMsg)
}
-
redisClient = rdb
return rdb, err
}
// overrideConfigFromEnv overrides configuration fields with environment variables if present.
-func overrideConfigFromEnv() {
+func overrideConfigFromEnv(config *config.GlobalConfig) {
if envAddr := os.Getenv("REDIS_ADDRESS"); envAddr != "" {
if envPort := os.Getenv("REDIS_PORT"); envPort != "" {
addresses := strings.Split(envAddr, ",")
for i, addr := range addresses {
addresses[i] = addr + ":" + envPort
}
- config.Config.Redis.Address = addresses
+ config.Redis.Address = addresses
} else {
- config.Config.Redis.Address = strings.Split(envAddr, ",")
+ config.Redis.Address = strings.Split(envAddr, ",")
}
}
+
if envUser := os.Getenv("REDIS_USERNAME"); envUser != "" {
- config.Config.Redis.Username = envUser
+ config.Redis.Username = envUser
}
+
if envPass := os.Getenv("REDIS_PASSWORD"); envPass != "" {
- config.Config.Redis.Password = envPass
+ config.Redis.Password = envPass
}
}
diff --git a/pkg/common/db/cache/meta_cache.go b/pkg/common/db/cache/meta_cache.go
index 86ade0b68..b14851381 100644
--- a/pkg/common/db/cache/meta_cache.go
+++ b/pkg/common/db/cache/meta_cache.go
@@ -19,15 +19,14 @@ import (
"encoding/json"
"errors"
"github.com/redis/go-redis/v9"
+ "fmt"
"time"
- "github.com/OpenIMSDK/tools/mw/specialerror"
-
- "github.com/dtm-labs/rockscache"
-
"github.com/OpenIMSDK/tools/errs"
"github.com/OpenIMSDK/tools/log"
+ "github.com/OpenIMSDK/tools/mw/specialerror"
"github.com/OpenIMSDK/tools/utils"
+ "github.com/dtm-labs/rockscache"
)
const (
@@ -151,14 +150,14 @@ func getCache[T any](ctx context.Context, rcClient *rockscache.Client, key strin
}
bs, err := json.Marshal(t)
if err != nil {
- return "", utils.Wrap(err, "")
+ return "", errs.Wrap(err, "marshal failed")
}
write = true
return string(bs), nil
})
if err != nil {
- return t, err
+ return t, errs.Wrap(err)
}
if write {
return t, nil
@@ -168,9 +167,8 @@ func getCache[T any](ctx context.Context, rcClient *rockscache.Client, key strin
}
err = json.Unmarshal([]byte(v), &t)
if err != nil {
- log.ZError(ctx, "cache json.Unmarshal failed", err, "key", key, "value", v, "expire", expire)
-
- return t, utils.Wrap(err, "")
+ errInfo := fmt.Sprintf("cache json.Unmarshal failed, key:%s, value:%s, expire:%s", key, v, expire)
+ return t, errs.Wrap(err, errInfo)
}
return t, nil
@@ -234,7 +232,7 @@ func batchGetCache2[T any, K comparable](
if errs.ErrRecordNotFound.Is(specialerror.ErrCode(errs.Unwrap(err))) {
continue
}
- return nil, err
+ return nil, errs.Wrap(err)
}
res = append(res, val)
}
diff --git a/pkg/common/db/cache/msg.go b/pkg/common/db/cache/msg.go
index 768e75a27..00f715785 100644
--- a/pkg/common/db/cache/msg.go
+++ b/pkg/common/db/cache/msg.go
@@ -21,22 +21,16 @@ import (
"strconv"
"time"
- "golang.org/x/sync/errgroup"
-
- "github.com/openimsdk/open-im-server/v3/pkg/msgprocessor"
-
- "github.com/OpenIMSDK/tools/errs"
-
- "github.com/gogo/protobuf/jsonpb"
-
"github.com/OpenIMSDK/protocol/constant"
"github.com/OpenIMSDK/protocol/sdkws"
+ "github.com/OpenIMSDK/tools/errs"
"github.com/OpenIMSDK/tools/log"
"github.com/OpenIMSDK/tools/utils"
-
+ "github.com/gogo/protobuf/jsonpb"
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
-
+ "github.com/openimsdk/open-im-server/v3/pkg/msgprocessor"
"github.com/redis/go-redis/v9"
+ "golang.org/x/sync/errgroup"
)
const (
@@ -128,14 +122,14 @@ type MsgModel interface {
UnLockMessageTypeKey(ctx context.Context, clientMsgID string, TypeKey string) error
}
-func NewMsgCacheModel(client redis.UniversalClient) MsgModel {
- rcClient := rockscache.NewClient(client, rockscache.NewDefaultOptions())
- return &msgCache{metaCache: NewMetaCacheRedis(rcClient), rdb: client}
+func NewMsgCacheModel(client redis.UniversalClient, config *config.GlobalConfig) MsgModel {
+ return &msgCache{rdb: client, config: config}
}
type msgCache struct {
metaCache
- rdb redis.UniversalClient
+ rdb redis.UniversalClient
+ config *config.GlobalConfig
}
func (c *msgCache) getMaxSeqKey(conversationID string) string {
@@ -155,11 +149,15 @@ func (c *msgCache) getConversationUserMinSeqKey(conversationID, userID string) s
}
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 errs.Wrap(c.rdb.Set(ctx, getkey(conversationID), seq, 0).Err())
}
func (c *msgCache) getSeq(ctx context.Context, conversationID string, getkey func(conversationID string) string) (int64, error) {
- return utils.Wrap2(c.rdb.Get(ctx, getkey(conversationID)).Int64())
+ val, err := c.rdb.Get(ctx, getkey(conversationID)).Int64()
+ if err != nil {
+ return 0, errs.Wrap(err)
+ }
+ return val, nil
}
func (c *msgCache) getSeqs(ctx context.Context, items []string, getkey func(s string) string) (m map[string]int64, err error) {
@@ -216,7 +214,11 @@ func (c *msgCache) GetMinSeq(ctx context.Context, conversationID string) (int64,
}
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())
+ val, err := c.rdb.Get(ctx, c.getConversationUserMinSeqKey(conversationID, userID)).Int64()
+ if err != nil {
+ return 0, errs.Wrap(err)
+ }
+ return val, nil
}
func (c *msgCache) GetConversationUserMinSeqs(ctx context.Context, conversationID string, userIDs []string) (m map[string]int64, err error) {
@@ -226,7 +228,7 @@ func (c *msgCache) GetConversationUserMinSeqs(ctx context.Context, conversationI
}
func (c *msgCache) SetConversationUserMinSeq(ctx context.Context, conversationID string, userID string, minSeq int64) error {
- return utils.Wrap1(c.rdb.Set(ctx, c.getConversationUserMinSeqKey(conversationID, userID), minSeq, 0).Err())
+ return errs.Wrap(c.rdb.Set(ctx, c.getConversationUserMinSeqKey(conversationID, userID), minSeq, 0).Err())
}
func (c *msgCache) SetConversationUserMinSeqs(ctx context.Context, conversationID string, seqs map[string]int64) (err error) {
@@ -242,7 +244,7 @@ func (c *msgCache) SetUserConversationsMinSeqs(ctx context.Context, userID strin
}
func (c *msgCache) SetHasReadSeq(ctx context.Context, userID string, conversationID string, hasReadSeq int64) error {
- return utils.Wrap1(c.rdb.Set(ctx, c.getHasReadSeqKey(conversationID, userID), hasReadSeq, 0).Err())
+ return errs.Wrap(c.rdb.Set(ctx, c.getHasReadSeqKey(conversationID, userID), hasReadSeq, 0).Err())
}
func (c *msgCache) SetHasReadSeqs(ctx context.Context, conversationID string, hasReadSeqs map[string]int64) error {
@@ -264,12 +266,15 @@ func (c *msgCache) GetHasReadSeqs(ctx context.Context, userID string, conversati
}
func (c *msgCache) GetHasReadSeq(ctx context.Context, userID string, conversationID string) (int64, error) {
- return utils.Wrap2(c.rdb.Get(ctx, c.getHasReadSeqKey(conversationID, userID)).Int64())
+ val, err := c.rdb.Get(ctx, c.getHasReadSeqKey(conversationID, userID)).Int64()
+ if err != nil {
+ return 0, err
+ }
+ return val, nil
}
func (c *msgCache) AddTokenFlag(ctx context.Context, userID string, platformID int, token string, flag int) error {
key := uidPidToken + userID + ":" + constant.PlatformIDToName(platformID)
-
return errs.Wrap(c.rdb.HSet(ctx, key, token, flag).Err())
}
@@ -312,7 +317,7 @@ func (c *msgCache) allMessageCacheKey(conversationID string) string {
}
func (c *msgCache) GetMessagesBySeq(ctx context.Context, conversationID string, seqs []int64) (seqMsgs []*sdkws.MsgData, failedSeqs []int64, err error) {
- if config.Config.Redis.EnablePipeline {
+ if c.config.Redis.EnablePipeline {
return c.PipeGetMessagesBySeq(ctx, conversationID, seqs)
}
@@ -413,7 +418,7 @@ func (c *msgCache) ParallelGetMessagesBySeq(ctx context.Context, conversationID
}
func (c *msgCache) SetMessageToCache(ctx context.Context, conversationID string, msgs []*sdkws.MsgData) (int, error) {
- if config.Config.Redis.EnablePipeline {
+ if c.config.Redis.EnablePipeline {
return c.PipeSetMessageToCache(ctx, conversationID, msgs)
}
return c.ParallelSetMessageToCache(ctx, conversationID, msgs)
@@ -424,16 +429,16 @@ func (c *msgCache) PipeSetMessageToCache(ctx context.Context, conversationID str
for _, msg := range msgs {
s, err := msgprocessor.Pb2String(msg)
if err != nil {
- return 0, errs.Wrap(err, "pb.marshal")
+ return 0, err
}
key := c.getMessageCacheKey(conversationID, msg.Seq)
- _ = pipe.Set(ctx, key, s, time.Duration(config.Config.MsgCacheTimeout)*time.Second)
+ _ = pipe.Set(ctx, key, s, time.Duration(c.config.MsgCacheTimeout)*time.Second)
}
results, err := pipe.Exec(ctx)
if err != nil {
- return 0, errs.Wrap(err, "pipe.set")
+ return 0, errs.Wrap(err)
}
for _, res := range results {
@@ -458,7 +463,7 @@ func (c *msgCache) ParallelSetMessageToCache(ctx context.Context, conversationID
}
key := c.getMessageCacheKey(conversationID, msg.Seq)
- if err := c.rdb.Set(ctx, key, s, time.Duration(config.Config.MsgCacheTimeout)*time.Second).Err(); err != nil {
+ if err := c.rdb.Set(ctx, key, s, time.Duration(c.config.MsgCacheTimeout)*time.Second).Err(); err != nil {
return errs.Wrap(err)
}
return nil
@@ -467,7 +472,7 @@ func (c *msgCache) ParallelSetMessageToCache(ctx context.Context, conversationID
err := wg.Wait()
if err != nil {
- return 0, err
+ return 0, errs.Wrap(err, "wg.Wait failed")
}
return len(msgs), nil
@@ -493,10 +498,10 @@ func (c *msgCache) UserDeleteMsgs(ctx context.Context, conversationID string, se
if err != nil {
return errs.Wrap(err)
}
- if err := c.rdb.Expire(ctx, delUserListKey, time.Duration(config.Config.MsgCacheTimeout)*time.Second).Err(); err != nil {
+ if err := c.rdb.Expire(ctx, delUserListKey, time.Duration(c.config.MsgCacheTimeout)*time.Second).Err(); err != nil {
return errs.Wrap(err)
}
- if err := c.rdb.Expire(ctx, userDelListKey, time.Duration(config.Config.MsgCacheTimeout)*time.Second).Err(); err != nil {
+ if err := c.rdb.Expire(ctx, userDelListKey, time.Duration(c.config.MsgCacheTimeout)*time.Second).Err(); err != nil {
return errs.Wrap(err)
}
}
@@ -601,7 +606,7 @@ func (c *msgCache) DelUserDeleteMsgsList(ctx context.Context, conversationID str
}
func (c *msgCache) DeleteMessages(ctx context.Context, conversationID string, seqs []int64) error {
- if config.Config.Redis.EnablePipeline {
+ if c.config.Redis.EnablePipeline {
return c.PipeDeleteMessages(ctx, conversationID, seqs)
}
@@ -683,7 +688,7 @@ func (c *msgCache) DelMsgFromCache(ctx context.Context, userID string, seqs []in
if err != nil {
return errs.Wrap(err)
}
- if err := c.rdb.Set(ctx, key, s, time.Duration(config.Config.MsgCacheTimeout)*time.Second).Err(); err != nil {
+ if err := c.rdb.Set(ctx, key, s, time.Duration(c.config.MsgCacheTimeout)*time.Second).Err(); err != nil {
return errs.Wrap(err)
}
}
@@ -696,7 +701,11 @@ func (c *msgCache) SetGetuiToken(ctx context.Context, token string, expireTime i
}
func (c *msgCache) GetGetuiToken(ctx context.Context) (string, error) {
- return utils.Wrap2(c.rdb.Get(ctx, getuiToken).Result())
+ val, err := c.rdb.Get(ctx, getuiToken).Result()
+ if err != nil {
+ return "", errs.Wrap(err)
+ }
+ return val, nil
}
func (c *msgCache) SetGetuiTaskID(ctx context.Context, taskID string, expireTime int64) error {
@@ -704,7 +713,11 @@ func (c *msgCache) SetGetuiTaskID(ctx context.Context, taskID string, expireTime
}
func (c *msgCache) GetGetuiTaskID(ctx context.Context) (string, error) {
- return utils.Wrap2(c.rdb.Get(ctx, getuiTaskID).Result())
+ val, err := c.rdb.Get(ctx, getuiTaskID).Result()
+ if err != nil {
+ return "", errs.Wrap(err)
+ }
+ return val, nil
}
func (c *msgCache) SetSendMsgStatus(ctx context.Context, id string, status int32) error {
@@ -722,7 +735,11 @@ func (c *msgCache) SetFcmToken(ctx context.Context, account string, platformID i
}
func (c *msgCache) GetFcmToken(ctx context.Context, account string, platformID int) (string, error) {
- return utils.Wrap2(c.rdb.Get(ctx, FCM_TOKEN+account+":"+strconv.Itoa(platformID)).Result())
+ val, err := c.rdb.Get(ctx, FCM_TOKEN+account+":"+strconv.Itoa(platformID)).Result()
+ if err != nil {
+ return "", errs.Wrap(err)
+ }
+ return val, nil
}
func (c *msgCache) DelFcmToken(ctx context.Context, account string, platformID int) error {
@@ -740,7 +757,8 @@ func (c *msgCache) SetUserBadgeUnreadCountSum(ctx context.Context, userID string
}
func (c *msgCache) GetUserBadgeUnreadCountSum(ctx context.Context, userID string) (int, error) {
- return utils.Wrap2(c.rdb.Get(ctx, userBadgeUnreadCountSum+userID).Int())
+ val, err := c.rdb.Get(ctx, userBadgeUnreadCountSum+userID).Int()
+ return val, errs.Wrap(err)
}
func (c *msgCache) LockMessageTypeKey(ctx context.Context, clientMsgID string, TypeKey string) error {
@@ -773,42 +791,31 @@ func (c *msgCache) getMessageReactionExPrefix(clientMsgID string, sessionType in
func (c *msgCache) JudgeMessageReactionExist(ctx context.Context, clientMsgID string, sessionType int32) (bool, error) {
n, err := c.rdb.Exists(ctx, c.getMessageReactionExPrefix(clientMsgID, sessionType)).Result()
if err != nil {
- return false, utils.Wrap(err, "")
+ return false, errs.Wrap(err)
}
return n > 0, nil
}
-func (c *msgCache) SetMessageTypeKeyValue(
- ctx context.Context,
- clientMsgID string,
- sessionType int32,
- typeKey, value string,
-) error {
+func (c *msgCache) SetMessageTypeKeyValue(ctx context.Context, clientMsgID string, sessionType int32, typeKey, value string) error {
return errs.Wrap(c.rdb.HSet(ctx, c.getMessageReactionExPrefix(clientMsgID, sessionType), typeKey, value).Err())
}
func (c *msgCache) SetMessageReactionExpire(ctx context.Context, clientMsgID string, sessionType int32, expiration time.Duration) (bool, error) {
- return utils.Wrap2(c.rdb.Expire(ctx, c.getMessageReactionExPrefix(clientMsgID, sessionType), expiration).Result())
+ val, err := c.rdb.Expire(ctx, c.getMessageReactionExPrefix(clientMsgID, sessionType), expiration).Result()
+ return val, errs.Wrap(err)
}
func (c *msgCache) GetMessageTypeKeyValue(ctx context.Context, clientMsgID string, sessionType int32, typeKey string) (string, error) {
- return utils.Wrap2(c.rdb.HGet(ctx, c.getMessageReactionExPrefix(clientMsgID, sessionType), typeKey).Result())
+ val, err := c.rdb.HGet(ctx, c.getMessageReactionExPrefix(clientMsgID, sessionType), typeKey).Result()
+ return val, errs.Wrap(err)
}
-func (c *msgCache) GetOneMessageAllReactionList(
- ctx context.Context,
- clientMsgID string,
- sessionType int32,
-) (map[string]string, error) {
- return utils.Wrap2(c.rdb.HGetAll(ctx, c.getMessageReactionExPrefix(clientMsgID, sessionType)).Result())
+func (c *msgCache) GetOneMessageAllReactionList(ctx context.Context, clientMsgID string, sessionType int32) (map[string]string, error) {
+ val, err := c.rdb.HGetAll(ctx, c.getMessageReactionExPrefix(clientMsgID, sessionType)).Result()
+ return val, errs.Wrap(err)
}
-func (c *msgCache) DeleteOneMessageKey(
- ctx context.Context,
- clientMsgID string,
- sessionType int32,
- subKey string,
-) error {
+func (c *msgCache) DeleteOneMessageKey(ctx context.Context, clientMsgID string, sessionType int32, subKey string) error {
return errs.Wrap(c.rdb.HDel(ctx, c.getMessageReactionExPrefix(clientMsgID, sessionType), subKey).Err())
}
diff --git a/pkg/common/db/cache/s3.go b/pkg/common/db/cache/s3.go
index 1e68cedf8..28e993be0 100644
--- a/pkg/common/db/cache/s3.go
+++ b/pkg/common/db/cache/s3.go
@@ -20,10 +20,9 @@ import (
"time"
"github.com/dtm-labs/rockscache"
- "github.com/redis/go-redis/v9"
-
"github.com/openimsdk/open-im-server/v3/pkg/common/db/s3"
relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
+ "github.com/redis/go-redis/v9"
)
type ObjectCache interface {
diff --git a/pkg/common/db/cache/user.go b/pkg/common/db/cache/user.go
index c18f2af25..c081731ce 100644
--- a/pkg/common/db/cache/user.go
+++ b/pkg/common/db/cache/user.go
@@ -24,16 +24,12 @@ import (
"strconv"
"time"
- relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
-
- "github.com/OpenIMSDK/tools/log"
-
"github.com/OpenIMSDK/protocol/constant"
-
"github.com/OpenIMSDK/protocol/user"
"github.com/OpenIMSDK/tools/errs"
-
+ "github.com/OpenIMSDK/tools/log"
"github.com/dtm-labs/rockscache"
+ relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
"github.com/redis/go-redis/v9"
)
@@ -206,13 +202,13 @@ func (u *UserCacheRedis) SetUserStatus(ctx context.Context, userID string, statu
Status: constant.Online,
PlatformIDs: []int32{platformID},
}
- jsonData, err2 := json.Marshal(&onlineStatus)
- if err2 != nil {
- return errs.Wrap(err2)
+ jsonData, err := json.Marshal(&onlineStatus)
+ if err != nil {
+ return errs.Wrap(err)
}
- _, err2 = u.rdb.HSet(ctx, key, userID, string(jsonData)).Result()
- if err2 != nil {
- return errs.Wrap(err2)
+ _, err = u.rdb.HSet(ctx, key, userID, string(jsonData)).Result()
+ if err != nil {
+ return errs.Wrap(err)
}
u.rdb.Expire(ctx, key, userOlineStatusExpireTime)
@@ -286,9 +282,9 @@ func (u *UserCacheRedis) refreshStatusOffline(ctx context.Context, userID string
func (u *UserCacheRedis) refreshStatusOnline(ctx context.Context, userID string, platformID int32, isNil bool, err error, result, key string) error {
var onlineStatus user.OnlineStatus
if !isNil {
- err2 := json.Unmarshal([]byte(result), &onlineStatus)
+ err := json.Unmarshal([]byte(result), &onlineStatus)
if err != nil {
- return errs.Wrap(err2)
+ return errs.Wrap(err)
}
onlineStatus.PlatformIDs = RemoveRepeatedElementsInList(append(onlineStatus.PlatformIDs, platformID))
} else {
@@ -298,7 +294,7 @@ func (u *UserCacheRedis) refreshStatusOnline(ctx context.Context, userID string,
onlineStatus.UserID = userID
newjsonData, err := json.Marshal(&onlineStatus)
if err != nil {
- return errs.Wrap(err)
+ return errs.Wrap(err, "json.Marshal failed")
}
_, err = u.rdb.HSet(ctx, key, userID, string(newjsonData)).Result()
if err != nil {
diff --git a/pkg/common/db/controller/auth.go b/pkg/common/db/controller/auth.go
index 17b4a440d..7cafa1c48 100644
--- a/pkg/common/db/controller/auth.go
+++ b/pkg/common/db/controller/auth.go
@@ -17,45 +17,39 @@ package controller
import (
"context"
- "github.com/openimsdk/open-im-server/v3/pkg/authverify"
-
- "github.com/golang-jwt/jwt/v4"
-
"github.com/OpenIMSDK/protocol/constant"
+ "github.com/OpenIMSDK/tools/errs"
"github.com/OpenIMSDK/tools/tokenverify"
- "github.com/OpenIMSDK/tools/utils"
-
+ "github.com/golang-jwt/jwt/v4"
+ "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/db/cache"
)
type AuthDatabase interface {
- // 结果为空 不返回错误
+ // If the result is empty, no error is returned.
GetTokensWithoutError(ctx context.Context, userID string, platformID int) (map[string]int, error)
- // 创建token
+ // Create token
CreateToken(ctx context.Context, userID string, platformID int) (string, error)
}
type authDatabase struct {
- cache cache.MsgModel
-
+ cache cache.MsgModel
accessSecret string
accessExpire int64
+ config *config.GlobalConfig
}
-func NewAuthDatabase(cache cache.MsgModel, accessSecret string, accessExpire int64) AuthDatabase {
- return &authDatabase{cache: cache, accessSecret: accessSecret, accessExpire: accessExpire}
+func NewAuthDatabase(cache cache.MsgModel, accessSecret string, accessExpire int64, config *config.GlobalConfig) AuthDatabase {
+ return &authDatabase{cache: cache, accessSecret: accessSecret, accessExpire: accessExpire, config: config}
}
-// 结果为空 不返回错误.
-func (a *authDatabase) GetTokensWithoutError(
- ctx context.Context,
- userID string,
- platformID int,
-) (map[string]int, error) {
+// If the result is empty.
+func (a *authDatabase) GetTokensWithoutError(ctx context.Context, userID string, platformID int) (map[string]int, error) {
return a.cache.GetTokensWithoutError(ctx, userID, platformID)
}
-// 创建token.
+// Create Token.
func (a *authDatabase) CreateToken(ctx context.Context, userID string, platformID int) (string, error) {
tokens, err := a.cache.GetTokensWithoutError(ctx, userID, platformID)
if err != nil {
@@ -63,22 +57,23 @@ func (a *authDatabase) CreateToken(ctx context.Context, userID string, platformI
}
var deleteTokenKey []string
for k, v := range tokens {
- _, err = tokenverify.GetClaimFromToken(k, authverify.Secret())
+ _, err = tokenverify.GetClaimFromToken(k, authverify.Secret(a.config.Secret))
if err != nil || v != constant.NormalToken {
deleteTokenKey = append(deleteTokenKey, k)
}
}
if len(deleteTokenKey) != 0 {
- err := a.cache.DeleteTokenByUidPid(ctx, userID, platformID, deleteTokenKey)
+ err = a.cache.DeleteTokenByUidPid(ctx, userID, platformID, deleteTokenKey)
if err != nil {
return "", err
}
}
+
claims := tokenverify.BuildClaims(userID, platformID, a.accessExpire)
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
tokenString, err := token.SignedString([]byte(a.accessSecret))
if err != nil {
- return "", utils.Wrap(err, "")
+ return "", errs.Wrap(err, "token.SignedString")
}
return tokenString, a.cache.AddTokenFlag(ctx, userID, platformID, tokenString, constant.NormalToken)
}
diff --git a/pkg/common/db/controller/black.go b/pkg/common/db/controller/black.go
index e68d06b01..c4b253c2f 100644
--- a/pkg/common/db/controller/black.go
+++ b/pkg/common/db/controller/black.go
@@ -17,24 +17,22 @@ package controller
import (
"context"
- "github.com/OpenIMSDK/tools/pagination"
-
"github.com/OpenIMSDK/tools/log"
+ "github.com/OpenIMSDK/tools/pagination"
"github.com/OpenIMSDK/tools/utils"
-
"github.com/openimsdk/open-im-server/v3/pkg/common/db/cache"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
)
type BlackDatabase interface {
- // Create 增加黑名单
+ // Create add BlackList
Create(ctx context.Context, blacks []*relation.BlackModel) (err error)
- // Delete 删除黑名单
+ // Delete delete BlackList
Delete(ctx context.Context, blacks []*relation.BlackModel) (err error)
- // FindOwnerBlacks 获取黑名单列表
+ // FindOwnerBlacks get BlackList list
FindOwnerBlacks(ctx context.Context, ownerUserID string, pagination pagination.Pagination) (total int64, blacks []*relation.BlackModel, err error)
FindBlackInfos(ctx context.Context, ownerUserID string, userIDs []string) (blacks []*relation.BlackModel, err error)
- // CheckIn 检查user2是否在user1的黑名单列表中(inUser1Blacks==true) 检查user1是否在user2的黑名单列表中(inUser2Blacks==true)
+ // CheckIn Check whether user2 is in the black list of user1 (inUser1Blacks==true) Check whether user1 is in the black list of user2 (inUser2Blacks==true)
CheckIn(ctx context.Context, userID1, userID2 string) (inUser1Blacks bool, inUser2Blacks bool, err error)
}
@@ -47,7 +45,7 @@ func NewBlackDatabase(black relation.BlackModelInterface, cache cache.BlackCache
return &blackDatabase{black, cache}
}
-// Create 增加黑名单.
+// Create Add Blacklist.
func (b *blackDatabase) Create(ctx context.Context, blacks []*relation.BlackModel) (err error) {
if err := b.black.Create(ctx, blacks); err != nil {
return err
@@ -55,7 +53,7 @@ func (b *blackDatabase) Create(ctx context.Context, blacks []*relation.BlackMode
return b.deleteBlackIDsCache(ctx, blacks)
}
-// Delete 删除黑名单.
+// Delete Delete Blacklist.
func (b *blackDatabase) Delete(ctx context.Context, blacks []*relation.BlackModel) (err error) {
if err := b.black.Delete(ctx, blacks); err != nil {
return err
@@ -63,6 +61,7 @@ func (b *blackDatabase) Delete(ctx context.Context, blacks []*relation.BlackMode
return b.deleteBlackIDsCache(ctx, blacks)
}
+// FindOwnerBlacks Get Blacklist List.
func (b *blackDatabase) deleteBlackIDsCache(ctx context.Context, blacks []*relation.BlackModel) (err error) {
cache := b.cache.NewCache()
for _, black := range blacks {
@@ -71,16 +70,13 @@ func (b *blackDatabase) deleteBlackIDsCache(ctx context.Context, blacks []*relat
return cache.ExecDel(ctx)
}
-// FindOwnerBlacks 获取黑名单列表.
+// FindOwnerBlacks Get Blacklist List.
func (b *blackDatabase) FindOwnerBlacks(ctx context.Context, ownerUserID string, pagination pagination.Pagination) (total int64, blacks []*relation.BlackModel, err error) {
return b.black.FindOwnerBlacks(ctx, ownerUserID, pagination)
}
-// CheckIn 检查user2是否在user1的黑名单列表中(inUser1Blacks==true) 检查user1是否在user2的黑名单列表中(inUser2Blacks==true).
-func (b *blackDatabase) CheckIn(
- ctx context.Context,
- userID1, userID2 string,
-) (inUser1Blacks bool, inUser2Blacks bool, err error) {
+// FindOwnerBlacks Get Blacklist List.
+func (b *blackDatabase) CheckIn(ctx context.Context, userID1, userID2 string) (inUser1Blacks bool, inUser2Blacks bool, err error) {
userID1BlackIDs, err := b.cache.GetBlackIDs(ctx, userID1)
if err != nil {
return
@@ -93,10 +89,12 @@ func (b *blackDatabase) CheckIn(
return utils.IsContain(userID2, userID1BlackIDs), utils.IsContain(userID1, userID2BlackIDs), nil
}
+// FindBlackIDs Get Blacklist List.
func (b *blackDatabase) FindBlackIDs(ctx context.Context, ownerUserID string) (blackIDs []string, err error) {
return b.cache.GetBlackIDs(ctx, ownerUserID)
}
+// FindBlackInfos Get Blacklist List.
func (b *blackDatabase) FindBlackInfos(ctx context.Context, ownerUserID string, userIDs []string) (blacks []*relation.BlackModel, err error) {
return b.black.FindOwnerBlackInfos(ctx, ownerUserID, userIDs)
}
diff --git a/pkg/common/db/controller/conversation.go b/pkg/common/db/controller/conversation.go
index c6629e9c8..3d46e4fbc 100644
--- a/pkg/common/db/controller/conversation.go
+++ b/pkg/common/db/controller/conversation.go
@@ -18,46 +18,52 @@ import (
"context"
"time"
- "github.com/OpenIMSDK/tools/pagination"
-
- "github.com/openimsdk/open-im-server/v3/pkg/msgprocessor"
-
"github.com/OpenIMSDK/protocol/constant"
"github.com/OpenIMSDK/tools/log"
+ "github.com/OpenIMSDK/tools/pagination"
"github.com/OpenIMSDK/tools/tx"
"github.com/OpenIMSDK/tools/utils"
-
"github.com/openimsdk/open-im-server/v3/pkg/common/db/cache"
relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
+ "github.com/openimsdk/open-im-server/v3/pkg/msgprocessor"
)
type ConversationDatabase interface {
- // UpdateUserConversationFiled 更新用户该会话的属性信息
- UpdateUsersConversationFiled(ctx context.Context, userIDs []string, conversationID string, args map[string]any) error
- // CreateConversation 创建一批新的会话
+ // UpdateUsersConversationField updates the properties of a conversation for specified users.
+ UpdateUsersConversationField(ctx context.Context, userIDs []string, conversationID string, args map[string]any) error
+ // CreateConversation creates a batch of new conversations.
CreateConversation(ctx context.Context, conversations []*relationtb.ConversationModel) error
- // SyncPeerUserPrivateConversation 同步对端私聊会话内部保证事务操作
+ // SyncPeerUserPrivateConversationTx ensures transactional operation while syncing private conversations between peers.
SyncPeerUserPrivateConversationTx(ctx context.Context, conversation []*relationtb.ConversationModel) error
- // FindConversations 根据会话ID获取某个用户的多个会话
+ // FindConversations retrieves multiple conversations of a user by conversation IDs.
FindConversations(ctx context.Context, ownerUserID string, conversationIDs []string) ([]*relationtb.ConversationModel, error)
- // FindRecvMsgNotNotifyUserIDs 获取超级大群开启免打扰的用户ID
- //FindRecvMsgNotNotifyUserIDs(ctx context.Context, groupID string) ([]string, error)
- // GetUserAllConversation 获取一个用户在服务器上所有的会话
+ // GetUserAllConversation fetches all conversations of a user on the server.
GetUserAllConversation(ctx context.Context, ownerUserID string) ([]*relationtb.ConversationModel, error)
- // SetUserConversations 设置用户多个会话属性,如果会话不存在则创建,否则更新,内部保证原子性
+ // SetUserConversations sets multiple conversation properties for a user, creates new conversations if they do not exist, or updates them otherwise. This operation is atomic.
SetUserConversations(ctx context.Context, ownerUserID string, conversations []*relationtb.ConversationModel) error
- // SetUsersConversationFiledTx 设置多个用户会话关于某个字段的更新操作,如果会话不存在则创建,否则更新,内部保证事务操作
- SetUsersConversationFiledTx(ctx context.Context, userIDs []string, conversation *relationtb.ConversationModel, filedMap map[string]any) error
+ // SetUsersConversationFieldTx updates a specific field for multiple users' conversations, creating new conversations if they do not exist, or updates them otherwise. This operation is
+ // transactional.
+ SetUsersConversationFieldTx(ctx context.Context, userIDs []string, conversation *relationtb.ConversationModel, fieldMap map[string]any) error
+ // CreateGroupChatConversation creates a group chat conversation for the specified group ID and user IDs.
CreateGroupChatConversation(ctx context.Context, groupID string, userIDs []string) error
+ // GetConversationIDs retrieves conversation IDs for a given user.
GetConversationIDs(ctx context.Context, userID string) ([]string, error)
+ // GetUserConversationIDsHash gets the hash of conversation IDs for a given user.
GetUserConversationIDsHash(ctx context.Context, ownerUserID string) (hash uint64, err error)
+ // GetAllConversationIDs fetches all conversation IDs.
GetAllConversationIDs(ctx context.Context) ([]string, error)
+ // GetAllConversationIDsNumber returns the number of all conversation IDs.
GetAllConversationIDsNumber(ctx context.Context) (int64, error)
+ // PageConversationIDs paginates through conversation IDs based on the specified pagination settings.
PageConversationIDs(ctx context.Context, pagination pagination.Pagination) (conversationIDs []string, err error)
- //GetUserAllHasReadSeqs(ctx context.Context, ownerUserID string) (map[string]int64, error)
+ // GetConversationsByConversationID retrieves conversations by their IDs.
GetConversationsByConversationID(ctx context.Context, conversationIDs []string) ([]*relationtb.ConversationModel, error)
+ // GetConversationIDsNeedDestruct fetches conversations that need to be destructed based on specific criteria.
GetConversationIDsNeedDestruct(ctx context.Context) ([]*relationtb.ConversationModel, error)
+ // GetConversationNotReceiveMessageUserIDs gets user IDs for users in a conversation who have not received messages.
GetConversationNotReceiveMessageUserIDs(ctx context.Context, conversationID string) ([]string, error)
+ //GetUserAllHasReadSeqs(ctx context.Context, ownerUserID string) (map[string]int64, error)
+ //FindRecvMsgNotNotifyUserIDs(ctx context.Context, groupID string) ([]string, error)
}
func NewConversationDatabase(conversation relationtb.ConversationModelInterface, cache cache.ConversationCache, tx tx.CtxTx) ConversationDatabase {
@@ -74,7 +80,7 @@ type conversationDatabase struct {
tx tx.CtxTx
}
-func (c *conversationDatabase) SetUsersConversationFiledTx(ctx context.Context, userIDs []string, conversation *relationtb.ConversationModel, filedMap map[string]any) (err error) {
+func (c *conversationDatabase) SetUsersConversationFieldTx(ctx context.Context, userIDs []string, conversation *relationtb.ConversationModel, fieldMap map[string]any) (err error) {
return c.tx.Transaction(ctx, func(ctx context.Context) error {
cache := c.cache.NewCache()
if conversation.GroupID != "" {
@@ -85,27 +91,27 @@ func (c *conversationDatabase) SetUsersConversationFiledTx(ctx context.Context,
return err
}
if len(haveUserIDs) > 0 {
- _, err = c.conversationDB.UpdateByMap(ctx, haveUserIDs, conversation.ConversationID, filedMap)
+ _, err = c.conversationDB.UpdateByMap(ctx, haveUserIDs, conversation.ConversationID, fieldMap)
if err != nil {
return err
}
cache = cache.DelUsersConversation(conversation.ConversationID, haveUserIDs...)
- if _, ok := filedMap["has_read_seq"]; ok {
+ if _, ok := fieldMap["has_read_seq"]; ok {
for _, userID := range haveUserIDs {
cache = cache.DelUserAllHasReadSeqs(userID, conversation.ConversationID)
}
}
- if _, ok := filedMap["recv_msg_opt"]; ok {
+ if _, ok := fieldMap["recv_msg_opt"]; ok {
cache = cache.DelConversationNotReceiveMessageUserIDs(conversation.ConversationID)
}
}
NotUserIDs := utils.DifferenceString(haveUserIDs, userIDs)
- log.ZDebug(ctx, "SetUsersConversationFiledTx", "NotUserIDs", NotUserIDs, "haveUserIDs", haveUserIDs, "userIDs", userIDs)
+ log.ZDebug(ctx, "SetUsersConversationFieldTx", "NotUserIDs", NotUserIDs, "haveUserIDs", haveUserIDs, "userIDs", userIDs)
var conversations []*relationtb.ConversationModel
now := time.Now()
for _, v := range NotUserIDs {
temp := new(relationtb.ConversationModel)
- if err := utils.CopyStructFields(temp, conversation); err != nil {
+ if err = utils.CopyStructFields(temp, conversation); err != nil {
return err
}
temp.OwnerUserID = v
@@ -123,7 +129,7 @@ func (c *conversationDatabase) SetUsersConversationFiledTx(ctx context.Context,
})
}
-func (c *conversationDatabase) UpdateUsersConversationFiled(ctx context.Context, userIDs []string, conversationID string, args map[string]any) error {
+func (c *conversationDatabase) UpdateUsersConversationField(ctx context.Context, userIDs []string, conversationID string, args map[string]any) error {
_, err := c.conversationDB.UpdateByMap(ctx, userIDs, conversationID, args)
if err != nil {
return err
diff --git a/pkg/common/db/controller/friend.go b/pkg/common/db/controller/friend.go
index 3b98f5d7b..3c81d922c 100644
--- a/pkg/common/db/controller/friend.go
+++ b/pkg/common/db/controller/friend.go
@@ -16,17 +16,16 @@ package controller
import (
"context"
+ "fmt"
"time"
- "github.com/OpenIMSDK/tools/pagination"
-
"github.com/OpenIMSDK/protocol/constant"
"github.com/OpenIMSDK/tools/errs"
"github.com/OpenIMSDK/tools/log"
"github.com/OpenIMSDK/tools/mcontext"
+ "github.com/OpenIMSDK/tools/pagination"
"github.com/OpenIMSDK/tools/tx"
"github.com/OpenIMSDK/tools/utils"
-
"github.com/openimsdk/open-im-server/v3/pkg/common/db/cache"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
)
@@ -89,20 +88,30 @@ func NewFriendDatabase(friend relation.FriendModelInterface, friendRequest relat
return &friendDatabase{friend: friend, friendRequest: friendRequest, cache: cache, tx: tx}
}
-// ok 检查user2是否在user1的好友列表中(inUser1Friends==true) 检查user1是否在user2的好友列表中(inUser2Friends==true).
+// CheckIn verifies if user2 is in user1's friend list (inUser1Friends returns true) and
+// if user1 is in user2's friend list (inUser2Friends returns true).
func (f *friendDatabase) CheckIn(ctx context.Context, userID1, userID2 string) (inUser1Friends bool, inUser2Friends bool, err error) {
+ // Retrieve friend IDs of userID1 from the cache
userID1FriendIDs, err := f.cache.GetFriendIDs(ctx, userID1)
if err != nil {
+ err = fmt.Errorf("error retrieving friend IDs for user %s: %w", userID1, err)
return
}
+
+ // Retrieve friend IDs of userID2 from the cache
userID2FriendIDs, err := f.cache.GetFriendIDs(ctx, userID2)
if err != nil {
+ err = fmt.Errorf("error retrieving friend IDs for user %s: %w", userID2, err)
return
}
- return utils.IsContain(userID2, userID1FriendIDs), utils.IsContain(userID1, userID2FriendIDs), nil
+
+ // Check if userID2 is in userID1's friend list and vice versa
+ inUser1Friends = utils.IsContain(userID2, userID1FriendIDs)
+ inUser2Friends = utils.IsContain(userID1, userID2FriendIDs)
+ return inUser1Friends, inUser2Friends, nil
}
-// 增加或者更新好友申请 如果之前有记录则更新,没有记录则新增.
+// AddFriendRequest adds or updates a friend request.
func (f *friendDatabase) AddFriendRequest(ctx context.Context, fromUserID, toUserID string, reqMsg string, ex string) (err error) {
return f.tx.Transaction(ctx, func(ctx context.Context) error {
_, err := f.friendRequest.Take(ctx, fromUserID, toUserID)
@@ -126,11 +135,11 @@ func (f *friendDatabase) AddFriendRequest(ctx context.Context, fromUserID, toUse
})
}
-// (1)先判断是否在好友表 (在不在都不返回错误) (2)对于不在好友列表的 插入即可.
+// (1) First determine whether it is in the friends list (in or out does not return an error) (2) for not in the friends list can be inserted.
func (f *friendDatabase) BecomeFriends(ctx context.Context, ownerUserID string, friendUserIDs []string, addSource int32) (err error) {
return f.tx.Transaction(ctx, func(ctx context.Context) error {
cache := f.cache.NewCache()
- // 先find 找出重复的 去掉重复的
+ // User find friends
fs1, err := f.friend.FindFriends(ctx, ownerUserID, friendUserIDs)
if err != nil {
return err
@@ -170,26 +179,37 @@ func (f *friendDatabase) BecomeFriends(ctx context.Context, ownerUserID string,
})
}
-// 拒绝好友申请 (1)检查是否有申请记录且为未处理状态 (没有记录返回错误) (2)修改申请记录 已拒绝.
-func (f *friendDatabase) RefuseFriendRequest(ctx context.Context, friendRequest *relation.FriendRequestModel) (err error) {
+// RefuseFriendRequest rejects a friend request. It first checks for an existing, unprocessed request.
+// If no such request exists, it returns an error. Otherwise, it marks the request as refused.
+func (f *friendDatabase) RefuseFriendRequest(ctx context.Context, friendRequest *relation.FriendRequestModel) error {
+ // Attempt to retrieve the friend request from the database.
fr, err := f.friendRequest.Take(ctx, friendRequest.FromUserID, friendRequest.ToUserID)
if err != nil {
- return err
+ return fmt.Errorf("failed to retrieve friend request from %s to %s: %w", friendRequest.FromUserID, friendRequest.ToUserID, err)
}
+
+ // Check if the friend request has already been handled.
if fr.HandleResult != 0 {
- return errs.ErrArgs.Wrap("the friend request has been processed")
+ return fmt.Errorf("friend request from %s to %s has already been processed", friendRequest.FromUserID, friendRequest.ToUserID)
}
- log.ZDebug(ctx, "refuse friend request", "friendRequest db", fr, "friendRequest arg", friendRequest)
+
+ // Log the action of refusing the friend request for debugging and auditing purposes.
+ log.ZDebug(ctx, "Refusing friend request", map[string]interface{}{
+ "DB_FriendRequest": fr,
+ "Arg_FriendRequest": friendRequest,
+ })
+
+ // Mark the friend request as refused and update the handle time.
friendRequest.HandleResult = constant.FriendResponseRefuse
friendRequest.HandleTime = time.Now()
- err = f.friendRequest.Update(ctx, friendRequest)
- if err != nil {
- return err
+ if err := f.friendRequest.Update(ctx, friendRequest); err != nil {
+ return fmt.Errorf("failed to update friend request from %s to %s as refused: %w", friendRequest.FromUserID, friendRequest.ToUserID, err)
}
+
return nil
}
-// AgreeFriendRequest 同意好友申请 (1)检查是否有申请记录且为未处理状态 (没有记录返回错误) (2)检查是否好友(不返回错误) (3) 建立双向好友关系(存在的忽略).
+// AgreeFriendRequest accepts a friend request. It first checks for an existing, unprocessed request.
func (f *friendDatabase) AgreeFriendRequest(ctx context.Context, friendRequest *relation.FriendRequestModel) (err error) {
return f.tx.Transaction(ctx, func(ctx context.Context) error {
defer log.ZDebug(ctx, "return line")
@@ -227,10 +247,10 @@ func (f *friendDatabase) AgreeFriendRequest(ctx context.Context, friendRequest *
return err
}
existsMap := utils.SliceSet(utils.Slice(exists, func(friend *relation.FriendModel) [2]string {
- return [...]string{friend.OwnerUserID, friend.FriendUserID} // 自己 - 好友
+ return [...]string{friend.OwnerUserID, friend.FriendUserID} // My - Friend
}))
var adds []*relation.FriendModel
- if _, ok := existsMap[[...]string{friendRequest.ToUserID, friendRequest.FromUserID}]; !ok { // 自己 - 好友
+ if _, ok := existsMap[[...]string{friendRequest.ToUserID, friendRequest.FromUserID}]; !ok { // My - Friend
adds = append(
adds,
&relation.FriendModel{
@@ -241,7 +261,7 @@ func (f *friendDatabase) AgreeFriendRequest(ctx context.Context, friendRequest *
},
)
}
- if _, ok := existsMap[[...]string{friendRequest.FromUserID, friendRequest.ToUserID}]; !ok { // 好友 - 自己
+ if _, ok := existsMap[[...]string{friendRequest.FromUserID, friendRequest.ToUserID}]; !ok { // My - Friend
adds = append(
adds,
&relation.FriendModel{
@@ -261,7 +281,7 @@ func (f *friendDatabase) AgreeFriendRequest(ctx context.Context, friendRequest *
})
}
-// 删除好友 外部判断是否好友关系.
+// Delete removes a friend relationship. It is assumed that the external caller has verified the friendship status.
func (f *friendDatabase) Delete(ctx context.Context, ownerUserID string, friendUserIDs []string) (err error) {
if err := f.friend.Delete(ctx, ownerUserID, friendUserIDs); err != nil {
return err
@@ -269,7 +289,7 @@ func (f *friendDatabase) Delete(ctx context.Context, ownerUserID string, friendU
return f.cache.DelFriendIDs(append(friendUserIDs, ownerUserID)...).ExecDel(ctx)
}
-// 更新好友备注 零值也支持.
+// UpdateRemark updates the remark for a friend. Zero value for remark is also supported.
func (f *friendDatabase) UpdateRemark(ctx context.Context, ownerUserID, friendUserID, remark string) (err error) {
if err := f.friend.UpdateRemark(ctx, ownerUserID, friendUserID, remark); err != nil {
return err
@@ -277,27 +297,27 @@ func (f *friendDatabase) UpdateRemark(ctx context.Context, ownerUserID, friendUs
return f.cache.DelFriend(ownerUserID, friendUserID).ExecDel(ctx)
}
-// 获取ownerUserID的好友列表 无结果不返回错误.
+// PageOwnerFriends retrieves the list of friends for the ownerUserID. It does not return an error if the result is empty.
func (f *friendDatabase) PageOwnerFriends(ctx context.Context, ownerUserID string, pagination pagination.Pagination) (total int64, friends []*relation.FriendModel, err error) {
return f.friend.FindOwnerFriends(ctx, ownerUserID, pagination)
}
-// friendUserID在哪些人的好友列表中.
+// PageInWhoseFriends identifies in whose friend lists the friendUserID appears.
func (f *friendDatabase) PageInWhoseFriends(ctx context.Context, friendUserID string, pagination pagination.Pagination) (total int64, friends []*relation.FriendModel, err error) {
return f.friend.FindInWhoseFriends(ctx, friendUserID, pagination)
}
-// 获取我发出去的好友申请 无结果不返回错误.
+// PageFriendRequestFromMe retrieves friend requests sent by me. It does not return an error if the result is empty.
func (f *friendDatabase) PageFriendRequestFromMe(ctx context.Context, userID string, pagination pagination.Pagination) (total int64, friends []*relation.FriendRequestModel, err error) {
return f.friendRequest.FindFromUserID(ctx, userID, pagination)
}
-// 获取我收到的的好友申请 无结果不返回错误.
+// PageFriendRequestToMe retrieves friend requests received by me. It does not return an error if the result is empty.
func (f *friendDatabase) PageFriendRequestToMe(ctx context.Context, userID string, pagination pagination.Pagination) (total int64, friends []*relation.FriendRequestModel, err error) {
return f.friendRequest.FindToUserID(ctx, userID, pagination)
}
-// 获取某人指定好友的信息 如果有好友不存在,也返回错误.
+// FindFriendsWithError retrieves specified friends' information for ownerUserID. Returns an error if any friend does not exist.
func (f *friendDatabase) FindFriendsWithError(ctx context.Context, ownerUserID string, friendUserIDs []string) (friends []*relation.FriendModel, err error) {
friends, err = f.friend.FindFriends(ctx, ownerUserID, friendUserIDs)
if err != nil {
diff --git a/pkg/common/db/controller/group.go b/pkg/common/db/controller/group.go
index decd868d6..45bf87b6f 100644
--- a/pkg/common/db/controller/group.go
+++ b/pkg/common/db/controller/group.go
@@ -18,60 +18,90 @@ import (
"context"
"time"
- "github.com/OpenIMSDK/tools/pagination"
- "github.com/dtm-labs/rockscache"
-
"github.com/OpenIMSDK/protocol/constant"
+ "github.com/OpenIMSDK/tools/pagination"
"github.com/OpenIMSDK/tools/tx"
"github.com/OpenIMSDK/tools/utils"
- "github.com/redis/go-redis/v9"
-
+ "github.com/dtm-labs/rockscache"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/cache"
relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
+ "github.com/redis/go-redis/v9"
)
type GroupDatabase interface {
- // Group
+ // CreateGroup creates new groups along with their members.
CreateGroup(ctx context.Context, groups []*relationtb.GroupModel, groupMembers []*relationtb.GroupMemberModel) error
+ // TakeGroup retrieves a single group by its ID.
TakeGroup(ctx context.Context, groupID string) (group *relationtb.GroupModel, err error)
+ // FindGroup retrieves multiple groups by their IDs.
FindGroup(ctx context.Context, groupIDs []string) (groups []*relationtb.GroupModel, err error)
+ // SearchGroup searches for groups based on a keyword and pagination settings, returns total count and groups.
SearchGroup(ctx context.Context, keyword string, pagination pagination.Pagination) (int64, []*relationtb.GroupModel, error)
+ // UpdateGroup updates the properties of a group identified by its ID.
UpdateGroup(ctx context.Context, groupID string, data map[string]any) error
- DismissGroup(ctx context.Context, groupID string, deleteMember bool) error // 解散群,并删除群成员
+ // DismissGroup disbands a group and optionally removes its members based on the deleteMember flag.
+ DismissGroup(ctx context.Context, groupID string, deleteMember bool) error
+ // TakeGroupMember retrieves a specific group member by group ID and user ID.
TakeGroupMember(ctx context.Context, groupID string, userID string) (groupMember *relationtb.GroupMemberModel, err error)
+ // TakeGroupOwner retrieves the owner of a group by group ID.
TakeGroupOwner(ctx context.Context, groupID string) (*relationtb.GroupMemberModel, error)
- FindGroupMembers(ctx context.Context, groupID string, userIDs []string) (groupMembers []*relationtb.GroupMemberModel, err error) // *
- FindGroupMemberUser(ctx context.Context, groupIDs []string, userID string) (groupMembers []*relationtb.GroupMemberModel, err error) // *
- FindGroupMemberRoleLevels(ctx context.Context, groupID string, roleLevels []int32) (groupMembers []*relationtb.GroupMemberModel, err error) // *
- FindGroupMemberAll(ctx context.Context, groupID string) (groupMembers []*relationtb.GroupMemberModel, err error) // *
+ // FindGroupMembers retrieves members of a group filtered by user IDs.
+ FindGroupMembers(ctx context.Context, groupID string, userIDs []string) (groupMembers []*relationtb.GroupMemberModel, err error)
+ // FindGroupMemberUser retrieves groups that a user is a member of, filtered by group IDs.
+ FindGroupMemberUser(ctx context.Context, groupIDs []string, userID string) (groupMembers []*relationtb.GroupMemberModel, err error)
+ // FindGroupMemberRoleLevels retrieves group members filtered by their role levels within a group.
+ FindGroupMemberRoleLevels(ctx context.Context, groupID string, roleLevels []int32) (groupMembers []*relationtb.GroupMemberModel, err error)
+ // FindGroupMemberAll retrieves all members of a group.
+ FindGroupMemberAll(ctx context.Context, groupID string) (groupMembers []*relationtb.GroupMemberModel, err error)
+ // FindGroupsOwner retrieves the owners for multiple groups.
FindGroupsOwner(ctx context.Context, groupIDs []string) ([]*relationtb.GroupMemberModel, error)
+ // FindGroupMemberUserID retrieves the user IDs of all members in a group.
FindGroupMemberUserID(ctx context.Context, groupID string) ([]string, error)
+ // FindGroupMemberNum retrieves the number of members in a group.
FindGroupMemberNum(ctx context.Context, groupID string) (uint32, error)
+ // FindUserManagedGroupID retrieves group IDs managed by a user.
FindUserManagedGroupID(ctx context.Context, userID string) (groupIDs []string, err error)
+ // PageGroupRequest paginates through group requests for specified groups.
PageGroupRequest(ctx context.Context, groupIDs []string, pagination pagination.Pagination) (int64, []*relationtb.GroupRequestModel, error)
+ // GetGroupRoleLevelMemberIDs retrieves user IDs of group members with a specific role level.
GetGroupRoleLevelMemberIDs(ctx context.Context, groupID string, roleLevel int32) ([]string, error)
+ // PageGetJoinGroup paginates through groups that a user has joined.
PageGetJoinGroup(ctx context.Context, userID string, pagination pagination.Pagination) (total int64, totalGroupMembers []*relationtb.GroupMemberModel, err error)
+ // PageGetGroupMember paginates through members of a group.
PageGetGroupMember(ctx context.Context, groupID string, pagination pagination.Pagination) (total int64, totalGroupMembers []*relationtb.GroupMemberModel, err error)
+ // SearchGroupMember searches for group members based on a keyword, group ID, and pagination settings.
SearchGroupMember(ctx context.Context, keyword string, groupID string, pagination pagination.Pagination) (int64, []*relationtb.GroupMemberModel, error)
+ // HandlerGroupRequest processes a group join request with a specified result.
HandlerGroupRequest(ctx context.Context, groupID string, userID string, handledMsg string, handleResult int32, member *relationtb.GroupMemberModel) error
+ // DeleteGroupMember removes specified users from a group.
DeleteGroupMember(ctx context.Context, groupID string, userIDs []string) error
+ // MapGroupMemberUserID maps group IDs to their members' simplified user IDs.
MapGroupMemberUserID(ctx context.Context, groupIDs []string) (map[string]*relationtb.GroupSimpleUserID, error)
+ // MapGroupMemberNum maps group IDs to their member count.
MapGroupMemberNum(ctx context.Context, groupIDs []string) (map[string]uint32, error)
- TransferGroupOwner(ctx context.Context, groupID string, oldOwnerUserID, newOwnerUserID string, roleLevel int32) error // 转让群
+ // TransferGroupOwner transfers the ownership of a group to another user.
+ TransferGroupOwner(ctx context.Context, groupID string, oldOwnerUserID, newOwnerUserID string, roleLevel int32) error
+ // UpdateGroupMember updates properties of a group member.
UpdateGroupMember(ctx context.Context, groupID string, userID string, data map[string]any) error
+ // UpdateGroupMembers batch updates properties of group members.
UpdateGroupMembers(ctx context.Context, data []*relationtb.BatchUpdateGroupMember) error
- // GroupRequest
+
+ // CreateGroupRequest creates new group join requests.
CreateGroupRequest(ctx context.Context, requests []*relationtb.GroupRequestModel) error
+ // TakeGroupRequest retrieves a specific group join request.
TakeGroupRequest(ctx context.Context, groupID string, userID string) (*relationtb.GroupRequestModel, error)
+ // FindGroupRequests retrieves multiple group join requests.
FindGroupRequests(ctx context.Context, groupID string, userIDs []string) ([]*relationtb.GroupRequestModel, error)
+ // PageGroupRequestUser paginates through group join requests made by a user.
PageGroupRequestUser(ctx context.Context, userID string, pagination pagination.Pagination) (int64, []*relationtb.GroupRequestModel, error)
- // 获取群总数
+ // CountTotal counts the total number of groups as of a certain date.
CountTotal(ctx context.Context, before *time.Time) (count int64, err error)
- // 获取范围内群增量
+ // CountRangeEverydayTotal counts the daily group creation total within a specified date range.
CountRangeEverydayTotal(ctx context.Context, start time.Time, end time.Time) (map[string]int64, error)
+ // DeleteGroupMemberHash deletes the hash entries for group members in specified groups.
DeleteGroupMemberHash(ctx context.Context, groupIDs []string) error
}
diff --git a/pkg/common/db/controller/msg.go b/pkg/common/db/controller/msg.go
index dfff5c61d..ccf209b7a 100644
--- a/pkg/common/db/controller/msg.go
+++ b/pkg/common/db/controller/msg.go
@@ -21,26 +21,20 @@ import (
"time"
"github.com/OpenIMSDK/protocol/constant"
-
- "github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics"
-
- "github.com/redis/go-redis/v9"
-
+ pbmsg "github.com/OpenIMSDK/protocol/msg"
+ "github.com/OpenIMSDK/protocol/sdkws"
"github.com/OpenIMSDK/tools/errs"
"github.com/OpenIMSDK/tools/log"
-
- "go.mongodb.org/mongo-driver/mongo"
-
+ "github.com/OpenIMSDK/tools/utils"
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
"github.com/openimsdk/open-im-server/v3/pkg/common/convert"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/cache"
unrelationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/unrelation"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/unrelation"
"github.com/openimsdk/open-im-server/v3/pkg/common/kafka"
-
- pbmsg "github.com/OpenIMSDK/protocol/msg"
- "github.com/OpenIMSDK/protocol/sdkws"
- "github.com/OpenIMSDK/tools/utils"
+ "github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics"
+ "github.com/redis/go-redis/v9"
+ "go.mongodb.org/mongo-driver/mongo"
)
const (
@@ -48,33 +42,33 @@ const (
updateKeyRevoke
)
+// CommonMsgDatabase defines the interface for message database operations.
type CommonMsgDatabase interface {
- // 批量插入消息
+ // BatchInsertChat2DB inserts a batch of messages into the database for a specific conversation.
BatchInsertChat2DB(ctx context.Context, conversationID string, msgs []*sdkws.MsgData, currentMaxSeq int64) error
- // 撤回消息
+ // RevokeMsg revokes a message in a conversation.
RevokeMsg(ctx context.Context, conversationID string, seq int64, revoke *unrelationtb.RevokeModel) error
- // mark as read
+ // MarkSingleChatMsgsAsRead marks messages as read for a single chat by sequence numbers.
MarkSingleChatMsgsAsRead(ctx context.Context, userID string, conversationID string, seqs []int64) error
- // 刪除redis中消息缓存
+ // DeleteMessagesFromCache deletes message caches from Redis by sequence numbers.
DeleteMessagesFromCache(ctx context.Context, conversationID string, seqs []int64) error
+ // DelUserDeleteMsgsList deletes user's message deletion list.
DelUserDeleteMsgsList(ctx context.Context, conversationID string, seqs []int64)
- // incrSeq然后批量插入缓存
+ // BatchInsertChat2Cache increments the sequence number and then batch inserts messages into the cache.
BatchInsertChat2Cache(ctx context.Context, conversationID string, msgs []*sdkws.MsgData) (seq int64, isNewConversation bool, err error)
-
- // 通过seqList获取mongo中写扩散消息
+ // GetMsgBySeqsRange retrieves messages from MongoDB by a range of sequence numbers.
GetMsgBySeqsRange(ctx context.Context, userID string, conversationID string, begin, end, num, userMaxSeq int64) (minSeq int64, maxSeq int64, seqMsg []*sdkws.MsgData, err error)
- // 通过seqList获取大群在 mongo里面的消息
+ // GetMsgBySeqs retrieves messages for large groups from MongoDB by sequence numbers.
GetMsgBySeqs(ctx context.Context, userID string, conversationID string, seqs []int64) (minSeq int64, maxSeq int64, seqMsg []*sdkws.MsgData, err error)
- // 删除会话消息重置最小seq, remainTime为消息保留的时间单位秒,超时消息删除, 传0删除所有消息(此方法不删除redis cache)
+ // DeleteConversationMsgsAndSetMinSeq deletes conversation messages and resets the minimum sequence number. If `remainTime` is 0, all messages are deleted (this method does not delete Redis
+ // cache).
DeleteConversationMsgsAndSetMinSeq(ctx context.Context, conversationID string, remainTime int64) error
- // 用户标记删除过期消息返回标记删除的seq列表
+ // UserMsgsDestruct marks messages for deletion based on destruct time and returns a list of sequence numbers for marked messages.
UserMsgsDestruct(ctx context.Context, userID string, conversationID string, destructTime int64, lastMsgDestructTime time.Time) (seqs []int64, err error)
-
- // 用户根据seq删除消息
+ // DeleteUserMsgsBySeqs allows a user to delete messages based on sequence numbers.
DeleteUserMsgsBySeqs(ctx context.Context, userID string, conversationID string, seqs []int64) error
- // 物理删除消息置空
+ // DeleteMsgsPhysicalBySeqs physically deletes messages by emptying them based on sequence numbers.
DeleteMsgsPhysicalBySeqs(ctx context.Context, conversationID string, seqs []int64) error
-
SetMaxSeq(ctx context.Context, conversationID string, maxSeq int64) error
GetMaxSeqs(ctx context.Context, conversationIDs []string) (map[string]int64, error)
GetMaxSeq(ctx context.Context, conversationID string) (int64, error)
@@ -126,21 +120,49 @@ type CommonMsgDatabase interface {
ConvertMsgsDocLen(ctx context.Context, conversationIDs []string)
}
-func NewCommonMsgDatabase(msgDocModel unrelationtb.MsgDocModelInterface, cacheModel cache.MsgModel) CommonMsgDatabase {
+func NewCommonMsgDatabase(msgDocModel unrelationtb.MsgDocModelInterface, cacheModel cache.MsgModel, config *config.GlobalConfig) (CommonMsgDatabase, error) {
+ producerConfig := &kafka.ProducerConfig{
+ ProducerAck: config.Kafka.ProducerAck,
+ CompressType: config.Kafka.CompressType,
+ Username: config.Kafka.Username,
+ Password: config.Kafka.Password,
+ }
+
+ var tlsConfig *kafka.TLSConfig
+ if config.Kafka.TLS != nil {
+ tlsConfig = &kafka.TLSConfig{
+ CACrt: config.Kafka.TLS.CACrt,
+ ClientCrt: config.Kafka.TLS.ClientCrt,
+ ClientKey: config.Kafka.TLS.ClientKey,
+ ClientKeyPwd: config.Kafka.TLS.ClientKeyPwd,
+ InsecureSkipVerify: false,
+ }
+ }
+ producerToRedis, err := kafka.NewKafkaProducer(config.Kafka.Addr, config.Kafka.LatestMsgToRedis.Topic, producerConfig, tlsConfig)
+ if err != nil {
+ return nil, err
+ }
+ producerToMongo, err := kafka.NewKafkaProducer(config.Kafka.Addr, config.Kafka.MsgToMongo.Topic, producerConfig, tlsConfig)
+ if err != nil {
+ return nil, err
+ }
+ producerToPush, err := kafka.NewKafkaProducer(config.Kafka.Addr, config.Kafka.MsgToPush.Topic, producerConfig, tlsConfig)
+ if err != nil {
+ return nil, err
+ }
return &commonMsgDatabase{
msgDocDatabase: msgDocModel,
cache: cacheModel,
- producer: kafka.NewKafkaProducer(config.Config.Kafka.Addr, config.Config.Kafka.LatestMsgToRedis.Topic),
- producerToMongo: kafka.NewKafkaProducer(config.Config.Kafka.Addr, config.Config.Kafka.MsgToMongo.Topic),
- producerToPush: kafka.NewKafkaProducer(config.Config.Kafka.Addr, config.Config.Kafka.MsgToPush.Topic),
- }
+ producer: producerToRedis,
+ producerToMongo: producerToMongo,
+ producerToPush: producerToPush,
+ }, nil
}
-func InitCommonMsgDatabase(rdb redis.UniversalClient, database *mongo.Database) CommonMsgDatabase {
- cacheModel := cache.NewMsgCacheModel(rdb)
+func InitCommonMsgDatabase(rdb redis.UniversalClient, database *mongo.Database, config *config.GlobalConfig) (CommonMsgDatabase, error) {
+ cacheModel := cache.NewMsgCacheModel(rdb, config)
msgDocModel := unrelation.NewMsgMongoDriver(database)
- CommonMsgDatabase := NewCommonMsgDatabase(msgDocModel, cacheModel)
- return CommonMsgDatabase
+ return NewCommonMsgDatabase(msgDocModel, cacheModel, config)
}
type commonMsgDatabase struct {
@@ -189,7 +211,7 @@ func (db *commonMsgDatabase) BatchInsertBlock(ctx context.Context, conversationI
}
num := db.msg.GetSingleGocMsgNum()
// num = 100
- for i, field := range fields { // 检查类型
+ for i, field := range fields { // Check the type of the field
var ok bool
switch key {
case updateKeyMsg:
@@ -207,7 +229,7 @@ func (db *commonMsgDatabase) BatchInsertBlock(ctx context.Context, conversationI
return errs.ErrInternalServer.Wrap("field type is invalid")
}
}
- // 返回值为true表示数据库存在该文档,false表示数据库不存在该文档
+ // Returns true if the document exists in the database, false if the document does not exist in the database
updateMsgModel := func(seq int64, i int) (bool, error) {
var (
res *mongo.UpdateResult
@@ -229,21 +251,21 @@ func (db *commonMsgDatabase) BatchInsertBlock(ctx context.Context, conversationI
}
tryUpdate := true
for i := 0; i < len(fields); i++ {
- seq := firstSeq + int64(i) // 当前seq
+ seq := firstSeq + int64(i) // Current sequence number
if tryUpdate {
matched, err := updateMsgModel(seq, i)
if err != nil {
return err
}
if matched {
- continue // 匹配到了,继续下一个(不一定修改)
+ continue // The current data has been updated, skip the current data
}
}
doc := unrelationtb.MsgDocModel{
DocID: db.msg.GetDocID(conversationID, seq),
Msg: make([]*unrelationtb.MsgInfoModel, num),
}
- var insert int // 插入的数量
+ var insert int // Inserted data number
for j := i; j < len(fields); j++ {
seq = firstSeq + int64(j)
if db.msg.GetDocID(conversationID, seq) != doc.DocID {
@@ -272,14 +294,14 @@ func (db *commonMsgDatabase) BatchInsertBlock(ctx context.Context, conversationI
}
if err := db.msgDocDatabase.Create(ctx, &doc); err != nil {
if mongo.IsDuplicateKeyError(err) {
- i-- // 存在并发,重试当前数据
- tryUpdate = true // 以修改模式
+ i-- // already inserted
+ tryUpdate = true // next block use update mode
continue
}
return err
}
- tryUpdate = false // 当前以插入成功,下一块优先插入模式
- i += insert - 1 // 跳过已插入的数据
+ tryUpdate = false // The current block is inserted successfully, and the next block is inserted preferentially
+ i += insert - 1 // Skip the inserted data
}
return nil
}
@@ -392,12 +414,12 @@ func (db *commonMsgDatabase) BatchInsertChat2Cache(ctx context.Context, conversa
log.ZError(ctx, "db.cache.SetMaxSeq error", err, "conversationID", conversationID)
prommetrics.SeqSetFailedCounter.Inc()
}
- err2 := db.cache.SetHasReadSeqs(ctx, conversationID, userSeqMap)
+ err = db.cache.SetHasReadSeqs(ctx, conversationID, userSeqMap)
if err != nil {
- log.ZError(ctx, "SetHasReadSeqs error", err2, "userSeqMap", userSeqMap, "conversationID", conversationID)
+ log.ZError(ctx, "SetHasReadSeqs error", err, "userSeqMap", userSeqMap, "conversationID", conversationID)
prommetrics.SeqSetFailedCounter.Inc()
}
- return lastMaxSeq, isNew, utils.Wrap(err, "")
+ return lastMaxSeq, isNew, errs.Wrap(err)
}
func (db *commonMsgDatabase) getMsgBySeqs(ctx context.Context, userID, conversationID string, seqs []int64) (totalMsgs []*sdkws.MsgData, err error) {
@@ -743,7 +765,7 @@ func (db *commonMsgDatabase) UserMsgsDestruct(ctx context.Context, userID string
log.ZError(ctx, "deleteMsgRecursion GetUserMsgListByIndex failed", err, "conversationID", conversationID, "index", index)
}
}
- // 获取报错,或者获取不到了,物理删除并且返回seq delMongoMsgsPhysical(delStruct.delDocIDList), 结束递归
+ // If an error is reported, or the error cannot be obtained, it is physically deleted and seq delMongoMsgsPhysical(delStruct.delDocIDList) is returned to end the recursion
break
}
index++
@@ -798,7 +820,7 @@ func (d *delMsgRecursionStruct) getSetMinSeq() int64 {
// index 0....19(del) 20...69
// seq 70
// set minSeq 21
-// recursion 删除list并且返回设置的最小seq.
+// recursion deletes the list and returns the set minimum seq.
func (db *commonMsgDatabase) deleteMsgRecursion(ctx context.Context, conversationID string, index int64, delStruct *delMsgRecursionStruct, remainTime int64) (int64, error) {
// find from oldest list
msgDocModel, err := db.msgDocDatabase.GetMsgDocModelByIndex(ctx, conversationID, index, 1)
@@ -810,7 +832,7 @@ func (db *commonMsgDatabase) deleteMsgRecursion(ctx context.Context, conversatio
log.ZError(ctx, "deleteMsgRecursion GetUserMsgListByIndex failed", err, "conversationID", conversationID, "index", index)
}
}
- // 获取报错,或者获取不到了,物理删除并且返回seq delMongoMsgsPhysical(delStruct.delDocIDList), 结束递归
+ // If an error is reported, or the error cannot be obtained, it is physically deleted and seq delMongoMsgsPhysical(delStruct.delDocIDList) is returned to end the recursion
err = db.msgDocDatabase.DeleteDocs(ctx, delStruct.delDocIDs)
if err != nil {
return 0, err
@@ -835,7 +857,7 @@ func (db *commonMsgDatabase) deleteMsgRecursion(ctx context.Context, conversatio
}
}
if len(delMsgIndexs) > 0 {
- if err := db.msgDocDatabase.DeleteMsgsInOneDocByIndex(ctx, msgDocModel.DocID, delMsgIndexs); err != nil {
+ if err = db.msgDocDatabase.DeleteMsgsInOneDocByIndex(ctx, msgDocModel.DocID, delMsgIndexs); err != nil {
log.ZError(ctx, "deleteMsgRecursion DeleteMsgsInOneDocByIndex failed", err, "conversationID", conversationID, "index", index)
}
delStruct.minSeq = int64(msgDocModel.Msg[delMsgIndexs[len(delMsgIndexs)-1]].Msg.Seq)
diff --git a/pkg/common/db/controller/msg_test.go b/pkg/common/db/controller/msg_test.go
index 70c055bf3..4c2ab20da 100644
--- a/pkg/common/db/controller/msg_test.go
+++ b/pkg/common/db/controller/msg_test.go
@@ -33,27 +33,28 @@ import (
)
func Test_BatchInsertChat2DB(t *testing.T) {
- config.Config.Mongo.Address = []string{"192.168.44.128:37017"}
- // config.Config.Mongo.Timeout = 60
- config.Config.Mongo.Database = "openIM"
- // config.Config.Mongo.Source = "admin"
- config.Config.Mongo.Username = "root"
- config.Config.Mongo.Password = "openIM123"
- config.Config.Mongo.MaxPoolSize = 100
- config.Config.RetainChatRecords = 3650
- config.Config.ChatRecordsClearTime = "0 2 * * 3"
+ conf := config.NewGlobalConfig()
+ conf.Mongo.Address = []string{"192.168.44.128:37017"}
+ // conf.Mongo.Timeout = 60
+ conf.Mongo.Database = "openIM"
+ // conf.Mongo.Source = "admin"
+ conf.Mongo.Username = "root"
+ conf.Mongo.Password = "openIM123"
+ conf.Mongo.MaxPoolSize = 100
+ conf.RetainChatRecords = 3650
+ conf.ChatRecordsClearTime = "0 2 * * 3"
- mongo, err := unrelation.NewMongo()
+ mongo, err := unrelation.NewMongo(conf)
if err != nil {
t.Fatal(err)
}
- err = mongo.GetDatabase().Client().Ping(context.Background(), nil)
+ err = mongo.GetDatabase(conf.Mongo.Database).Client().Ping(context.Background(), nil)
if err != nil {
panic(err)
}
db := &commonMsgDatabase{
- msgDocDatabase: unrelation.NewMsgMongoDriver(mongo.GetDatabase()),
+ msgDocDatabase: unrelation.NewMsgMongoDriver(mongo.GetDatabase(conf.Mongo.Database)),
}
//ctx := context.Background()
@@ -70,7 +71,7 @@ func Test_BatchInsertChat2DB(t *testing.T) {
//}
_ = db.BatchInsertChat2DB
- c := mongo.GetDatabase().Collection("msg")
+ c := mongo.GetDatabase(conf.Mongo.Database).Collection("msg")
ch := make(chan int)
rand.Seed(time.Now().UnixNano())
@@ -144,26 +145,27 @@ func Test_BatchInsertChat2DB(t *testing.T) {
}
func GetDB() *commonMsgDatabase {
- config.Config.Mongo.Address = []string{"203.56.175.233:37017"}
- // config.Config.Mongo.Timeout = 60
- config.Config.Mongo.Database = "openim_v3"
- // config.Config.Mongo.Source = "admin"
- config.Config.Mongo.Username = "root"
- config.Config.Mongo.Password = "openIM123"
- config.Config.Mongo.MaxPoolSize = 100
- config.Config.RetainChatRecords = 3650
- config.Config.ChatRecordsClearTime = "0 2 * * 3"
+ conf := config.NewGlobalConfig()
+ conf.Mongo.Address = []string{"203.56.175.233:37017"}
+ // conf.Mongo.Timeout = 60
+ conf.Mongo.Database = "openim_v3"
+ // conf.Mongo.Source = "admin"
+ conf.Mongo.Username = "root"
+ conf.Mongo.Password = "openIM123"
+ conf.Mongo.MaxPoolSize = 100
+ conf.RetainChatRecords = 3650
+ conf.ChatRecordsClearTime = "0 2 * * 3"
- mongo, err := unrelation.NewMongo()
+ mongo, err := unrelation.NewMongo(conf)
if err != nil {
panic(err)
}
- err = mongo.GetDatabase().Client().Ping(context.Background(), nil)
+ err = mongo.GetDatabase(conf.Mongo.Database).Client().Ping(context.Background(), nil)
if err != nil {
panic(err)
}
return &commonMsgDatabase{
- msgDocDatabase: unrelation.NewMsgMongoDriver(mongo.GetDatabase()),
+ msgDocDatabase: unrelation.NewMsgMongoDriver(mongo.GetDatabase(conf.Mongo.Database)),
}
}
diff --git a/pkg/common/db/controller/s3.go b/pkg/common/db/controller/s3.go
index 95505de41..e847c9c8f 100644
--- a/pkg/common/db/controller/s3.go
+++ b/pkg/common/db/controller/s3.go
@@ -19,12 +19,11 @@ import (
"path/filepath"
"time"
- "github.com/redis/go-redis/v9"
-
"github.com/openimsdk/open-im-server/v3/pkg/common/db/cache"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/s3"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/s3/cont"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
+ "github.com/redis/go-redis/v9"
)
type S3Database interface {
diff --git a/pkg/common/db/controller/third.go b/pkg/common/db/controller/third.go
index fb5b0ccbe..996d82c45 100644
--- a/pkg/common/db/controller/third.go
+++ b/pkg/common/db/controller/third.go
@@ -19,7 +19,6 @@ import (
"time"
"github.com/OpenIMSDK/tools/pagination"
-
"github.com/openimsdk/open-im-server/v3/pkg/common/db/cache"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
)
@@ -63,13 +62,7 @@ func NewThirdDatabase(cache cache.MsgModel, logdb relation.LogInterface) ThirdDa
return &thirdDatabase{cache: cache, logdb: logdb}
}
-func (t *thirdDatabase) FcmUpdateToken(
- ctx context.Context,
- account string,
- platformID int,
- fcmToken string,
- expireTime int64,
-) error {
+func (t *thirdDatabase) FcmUpdateToken(ctx context.Context, account string, platformID int, fcmToken string, expireTime int64) error {
return t.cache.SetFcmToken(ctx, account, platformID, fcmToken, expireTime)
}
diff --git a/pkg/common/db/controller/user.go b/pkg/common/db/controller/user.go
index 8ba1c01d3..0e1bdd314 100644
--- a/pkg/common/db/controller/user.go
+++ b/pkg/common/db/controller/user.go
@@ -18,19 +18,14 @@ import (
"context"
"time"
+ "github.com/OpenIMSDK/protocol/user"
+ "github.com/OpenIMSDK/tools/errs"
"github.com/OpenIMSDK/tools/pagination"
"github.com/OpenIMSDK/tools/tx"
-
- "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
-
- "github.com/OpenIMSDK/protocol/user"
-
- unrelationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/unrelation"
-
- "github.com/OpenIMSDK/tools/errs"
"github.com/OpenIMSDK/tools/utils"
-
"github.com/openimsdk/open-im-server/v3/pkg/common/db/cache"
+ "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
+ unrelationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/unrelation"
)
type UserDatabase interface {
diff --git a/pkg/common/db/localcache/conversation.go b/pkg/common/db/localcache/conversation.go
new file mode 100644
index 000000000..e69de29bb
diff --git a/pkg/common/db/localcache/group.go b/pkg/common/db/localcache/group.go
new file mode 100644
index 000000000..e69de29bb
diff --git a/pkg/common/db/mgo/black.go b/pkg/common/db/mgo/black.go
index 1047e5c30..c555e0b77 100644
--- a/pkg/common/db/mgo/black.go
+++ b/pkg/common/db/mgo/black.go
@@ -19,11 +19,10 @@ import (
"github.com/OpenIMSDK/tools/mgoutil"
"github.com/OpenIMSDK/tools/pagination"
+ "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
-
- "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
)
func NewBlackMongo(db *mongo.Database) (relation.BlackModelInterface, error) {
diff --git a/pkg/common/db/mgo/conversation.go b/pkg/common/db/mgo/conversation.go
index 640c7a3d5..bc37ed759 100644
--- a/pkg/common/db/mgo/conversation.go
+++ b/pkg/common/db/mgo/conversation.go
@@ -19,13 +19,13 @@ import (
"time"
"github.com/OpenIMSDK/protocol/constant"
+ "github.com/OpenIMSDK/tools/errs"
"github.com/OpenIMSDK/tools/mgoutil"
"github.com/OpenIMSDK/tools/pagination"
+ "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
-
- "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
)
func NewConversationMongo(db *mongo.Database) (*ConversationMgo, error) {
@@ -38,7 +38,7 @@ func NewConversationMongo(db *mongo.Database) (*ConversationMgo, error) {
Options: options.Index().SetUnique(true),
})
if err != nil {
- return nil, err
+ return nil, errs.Wrap(err)
}
return &ConversationMgo{coll: coll}, nil
}
diff --git a/pkg/common/db/mgo/friend.go b/pkg/common/db/mgo/friend.go
index 851db6157..aa7775ce0 100644
--- a/pkg/common/db/mgo/friend.go
+++ b/pkg/common/db/mgo/friend.go
@@ -19,12 +19,10 @@ import (
"github.com/OpenIMSDK/tools/mgoutil"
"github.com/OpenIMSDK/tools/pagination"
- "go.mongodb.org/mongo-driver/mongo/options"
-
+ "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
-
- "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
+ "go.mongodb.org/mongo-driver/mongo/options"
)
// FriendMgo implements FriendModelInterface using MongoDB as the storage backend.
diff --git a/pkg/common/db/mgo/friend_request.go b/pkg/common/db/mgo/friend_request.go
index bfc101917..3e0588a0b 100644
--- a/pkg/common/db/mgo/friend_request.go
+++ b/pkg/common/db/mgo/friend_request.go
@@ -19,12 +19,10 @@ import (
"github.com/OpenIMSDK/tools/mgoutil"
"github.com/OpenIMSDK/tools/pagination"
- "go.mongodb.org/mongo-driver/mongo/options"
-
+ "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
-
- "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
+ "go.mongodb.org/mongo-driver/mongo/options"
)
func NewFriendRequestMongo(db *mongo.Database) (relation.FriendRequestModelInterface, error) {
diff --git a/pkg/common/db/mgo/group.go b/pkg/common/db/mgo/group.go
index a9c6d1eb8..1bef90ebe 100644
--- a/pkg/common/db/mgo/group.go
+++ b/pkg/common/db/mgo/group.go
@@ -18,13 +18,13 @@ import (
"context"
"time"
+ "github.com/OpenIMSDK/tools/errs"
"github.com/OpenIMSDK/tools/mgoutil"
"github.com/OpenIMSDK/tools/pagination"
+ "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
-
- "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
)
func NewGroupMongo(db *mongo.Database) (relation.GroupModelInterface, error) {
@@ -36,7 +36,7 @@ func NewGroupMongo(db *mongo.Database) (relation.GroupModelInterface, error) {
Options: options.Index().SetUnique(true),
})
if err != nil {
- return nil, err
+ return nil, errs.Wrap(err)
}
return &GroupMgo{coll: coll}, nil
}
diff --git a/pkg/common/db/mgo/group_member.go b/pkg/common/db/mgo/group_member.go
index 8e3dd1efa..e1af34f7c 100644
--- a/pkg/common/db/mgo/group_member.go
+++ b/pkg/common/db/mgo/group_member.go
@@ -18,13 +18,13 @@ import (
"context"
"github.com/OpenIMSDK/protocol/constant"
+ "github.com/OpenIMSDK/tools/errs"
"github.com/OpenIMSDK/tools/mgoutil"
"github.com/OpenIMSDK/tools/pagination"
+ "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
-
- "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
)
func NewGroupMember(db *mongo.Database) (relation.GroupMemberModelInterface, error) {
@@ -37,7 +37,7 @@ func NewGroupMember(db *mongo.Database) (relation.GroupMemberModelInterface, err
Options: options.Index().SetUnique(true),
})
if err != nil {
- return nil, err
+ return nil, errs.Wrap(err)
}
return &GroupMemberMgo{coll: coll}, nil
}
diff --git a/pkg/common/db/mgo/group_request.go b/pkg/common/db/mgo/group_request.go
index cb04d2308..9aee0e960 100644
--- a/pkg/common/db/mgo/group_request.go
+++ b/pkg/common/db/mgo/group_request.go
@@ -17,13 +17,13 @@ package mgo
import (
"context"
+ "github.com/OpenIMSDK/tools/errs"
"github.com/OpenIMSDK/tools/mgoutil"
"github.com/OpenIMSDK/tools/pagination"
+ "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
-
- "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
)
func NewGroupRequestMgo(db *mongo.Database) (relation.GroupRequestModelInterface, error) {
@@ -36,7 +36,7 @@ func NewGroupRequestMgo(db *mongo.Database) (relation.GroupRequestModelInterface
Options: options.Index().SetUnique(true),
})
if err != nil {
- return nil, err
+ return nil, errs.Wrap(err)
}
return &GroupRequestMgo{coll: coll}, nil
}
diff --git a/pkg/common/db/mgo/log.go b/pkg/common/db/mgo/log.go
index 09f002ee3..ca28d5964 100644
--- a/pkg/common/db/mgo/log.go
+++ b/pkg/common/db/mgo/log.go
@@ -20,11 +20,10 @@ import (
"github.com/OpenIMSDK/tools/mgoutil"
"github.com/OpenIMSDK/tools/pagination"
+ "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
-
- "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
)
func NewLogMongo(db *mongo.Database) (relation.LogInterface, error) {
diff --git a/pkg/common/db/mgo/object.go b/pkg/common/db/mgo/object.go
index 88bfde213..a527fa60d 100644
--- a/pkg/common/db/mgo/object.go
+++ b/pkg/common/db/mgo/object.go
@@ -16,13 +16,13 @@ package mgo
import (
"context"
+ "github.com/OpenIMSDK/tools/errs"
"github.com/OpenIMSDK/tools/mgoutil"
+ "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
-
- "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
)
func NewS3Mongo(db *mongo.Database) (relation.ObjectInfoModelInterface, error) {
@@ -34,7 +34,7 @@ func NewS3Mongo(db *mongo.Database) (relation.ObjectInfoModelInterface, error) {
Options: options.Index().SetUnique(true),
})
if err != nil {
- return nil, err
+ return nil, errs.Wrap(err)
}
return &S3Mongo{coll: coll}, nil
}
diff --git a/pkg/common/db/mgo/user.go b/pkg/common/db/mgo/user.go
index 34a25ed08..9ca2eb178 100644
--- a/pkg/common/db/mgo/user.go
+++ b/pkg/common/db/mgo/user.go
@@ -20,15 +20,13 @@ import (
"github.com/OpenIMSDK/protocol/user"
"github.com/OpenIMSDK/tools/errs"
- "go.mongodb.org/mongo-driver/bson/primitive"
-
"github.com/OpenIMSDK/tools/mgoutil"
"github.com/OpenIMSDK/tools/pagination"
+ "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
"go.mongodb.org/mongo-driver/bson"
+ "go.mongodb.org/mongo-driver/bson/primitive"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
-
- "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
)
func NewUserMongo(db *mongo.Database) (relation.UserModelInterface, error) {
@@ -40,7 +38,7 @@ func NewUserMongo(db *mongo.Database) (relation.UserModelInterface, error) {
Options: options.Index().SetUnique(true),
})
if err != nil {
- return nil, err
+ return nil, errs.Wrap(err)
}
return &UserMgo{coll: coll}, nil
}
@@ -159,7 +157,7 @@ func (u *UserMgo) AddUserCommand(ctx context.Context, userID string, Type int32,
}
_, err := collection.InsertOne(ctx, doc)
- return err
+ return errs.Wrap(err)
}
func (u *UserMgo) DeleteUserCommand(ctx context.Context, userID string, Type int32, UUID string) error {
@@ -172,7 +170,7 @@ func (u *UserMgo) DeleteUserCommand(ctx context.Context, userID string, Type int
// No records found to update
return errs.Wrap(errs.ErrRecordNotFound)
}
- return err
+ return errs.Wrap(err)
}
func (u *UserMgo) UpdateUserCommand(ctx context.Context, userID string, Type int32, UUID string, val map[string]any) error {
if len(val) == 0 {
@@ -186,7 +184,7 @@ func (u *UserMgo) UpdateUserCommand(ctx context.Context, userID string, Type int
result, err := collection.UpdateOne(ctx, filter, update)
if err != nil {
- return err
+ return errs.Wrap(err)
}
if result.MatchedCount == 0 {
@@ -235,7 +233,7 @@ func (u *UserMgo) GetUserCommand(ctx context.Context, userID string, Type int32)
}
if err := cursor.Err(); err != nil {
- return nil, err
+ return nil, errs.Wrap(err)
}
return commands, nil
@@ -246,7 +244,7 @@ func (u *UserMgo) GetAllUserCommand(ctx context.Context, userID string) ([]*user
cursor, err := collection.Find(ctx, filter)
if err != nil {
- return nil, err
+ return nil, errs.Wrap(err)
}
defer cursor.Close(ctx)
@@ -263,7 +261,7 @@ func (u *UserMgo) GetAllUserCommand(ctx context.Context, userID string) ([]*user
}
if err := cursor.Decode(&document); err != nil {
- return nil, err
+ return nil, errs.Wrap(err)
}
commandInfo := &user.AllCommandInfoResp{
@@ -278,7 +276,7 @@ func (u *UserMgo) GetAllUserCommand(ctx context.Context, userID string) ([]*user
}
if err := cursor.Err(); err != nil {
- return nil, err
+ return nil, errs.Wrap(err)
}
return commands, nil
}
diff --git a/pkg/common/db/s3/cont/consts.go b/pkg/common/db/s3/cont/consts.go
index a01a8312c..b51878e49 100644
--- a/pkg/common/db/s3/cont/consts.go
+++ b/pkg/common/db/s3/cont/consts.go
@@ -15,10 +15,24 @@
package cont
const (
- hashPath = "openim/data/hash/"
- tempPath = "openim/temp/"
- DirectPath = "openim/direct"
- UploadTypeMultipart = 1 // 分片上传
- UploadTypePresigned = 2 // 预签名上传
- partSeparator = ","
+ // hashPath defines the storage path for hash data within the 'openim' directory.
+ hashPath = "openim/data/hash/"
+
+ // tempPath specifies the directory for temporary files in the 'openim' structure.
+ tempPath = "openim/temp/"
+
+ // DirectPath indicates the directory for direct uploads or access within the 'openim' structure.
+ DirectPath = "openim/direct"
+
+ // UploadTypeMultipart represents the identifier for multipart uploads,
+ // allowing large files to be uploaded in chunks.
+ UploadTypeMultipart = 1
+
+ // UploadTypePresigned signifies the use of presigned URLs for uploads,
+ // facilitating secure, authorized file transfers without requiring direct access to the storage credentials.
+ UploadTypePresigned = 2
+
+ // partSeparator is used as a delimiter in multipart upload processes,
+ // separating individual file parts.
+ partSeparator = ","
)
diff --git a/pkg/common/db/s3/cont/controller.go b/pkg/common/db/s3/cont/controller.go
index 82c27c1f2..915109aa5 100644
--- a/pkg/common/db/s3/cont/controller.go
+++ b/pkg/common/db/s3/cont/controller.go
@@ -24,13 +24,10 @@ import (
"strings"
"time"
- "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache"
-
- "github.com/google/uuid"
-
"github.com/OpenIMSDK/tools/errs"
"github.com/OpenIMSDK/tools/log"
-
+ "github.com/google/uuid"
+ "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/s3"
)
@@ -106,7 +103,7 @@ func (c *Controller) InitiateUpload(ctx context.Context, hash string, size int64
partNumber++
}
if maxParts > 0 && partNumber > 0 && partNumber < maxParts {
- return nil, errors.New(fmt.Sprintf("too many parts: %d", partNumber))
+ return nil, fmt.Errorf("too many parts: %d", partNumber)
}
if info, err := c.StatObject(ctx, c.HashPath(hash)); err == nil {
return nil, &HashAlreadyExistsError{Object: info}
@@ -114,7 +111,7 @@ func (c *Controller) InitiateUpload(ctx context.Context, hash string, size int64
return nil, err
}
if size <= partSize {
- // 预签名上传
+ // Pre-signed upload
key := path.Join(tempPath, c.NowPath(), fmt.Sprintf("%s_%d_%s.presigned", hash, size, c.UUID()))
rawURL, err := c.impl.PresignedPutObject(ctx, key, expire)
if err != nil {
@@ -139,7 +136,7 @@ func (c *Controller) InitiateUpload(ctx context.Context, hash string, size int64
},
}, nil
} else {
- // 分片上传
+ // Fragment upload
upload, err := c.impl.InitiateMultipartUpload(ctx, c.HashPath(hash))
if err != nil {
return nil, err
@@ -206,7 +203,7 @@ func (c *Controller) CompleteUpload(ctx context.Context, uploadID string, partHa
ETag: part,
}
}
- // todo: 验证大小
+ // todo: Validation size
result, err := c.impl.CompleteMultipartUpload(ctx, upload.ID, upload.Key, parts)
if err != nil {
return nil, err
@@ -225,7 +222,7 @@ func (c *Controller) CompleteUpload(ctx context.Context, uploadID string, partHa
if md5val := hex.EncodeToString(md5Sum[:]); md5val != upload.Hash {
return nil, errs.ErrArgs.Wrap(fmt.Sprintf("md5 mismatching %s != %s", md5val, upload.Hash))
}
- // 防止在这个时候,并发操作,导致文件被覆盖
+ // Prevents concurrent operations at this time that cause files to be overwritten
copyInfo, err := c.impl.CopyObject(ctx, uploadInfo.Key, upload.Key+"."+c.UUID())
if err != nil {
return nil, err
diff --git a/pkg/common/db/s3/cont/structs.go b/pkg/common/db/s3/cont/structs.go
index ff5ca7943..de484cc5f 100644
--- a/pkg/common/db/s3/cont/structs.go
+++ b/pkg/common/db/s3/cont/structs.go
@@ -17,9 +17,14 @@ package cont
import "github.com/openimsdk/open-im-server/v3/pkg/common/db/s3"
type InitiateUploadResult struct {
- UploadID string `json:"uploadID"` // 上传ID
- PartSize int64 `json:"partSize"` // 分片大小
- Sign *s3.AuthSignResult `json:"sign"` // 分片信息
+ // UploadID uniquely identifies the upload session for tracking and management purposes.
+ UploadID string `json:"uploadID"`
+
+ // PartSize specifies the size of each part in a multipart upload. This is relevant for breaking down large uploads into manageable pieces.
+ PartSize int64 `json:"partSize"`
+
+ // Sign contains the authentication and signature information necessary for securely uploading each part. This could include signed URLs or tokens.
+ Sign *s3.AuthSignResult `json:"sign"`
}
type UploadResult struct {
diff --git a/pkg/common/db/s3/cos/cos.go b/pkg/common/db/s3/cos/cos.go
index a82ffe670..9852d2a98 100644
--- a/pkg/common/db/s3/cos/cos.go
+++ b/pkg/common/db/s3/cos/cos.go
@@ -29,10 +29,9 @@ import (
"strings"
"time"
- "github.com/tencentyun/cos-go-sdk-v5"
-
- "github.com/openimsdk/open-im-server/v3/pkg/common/config"
+ "github.com/OpenIMSDK/tools/errs"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/s3"
+ "github.com/tencentyun/cos-go-sdk-v5"
)
const (
@@ -51,13 +50,15 @@ const (
const successCode = http.StatusOK
-const (
- videoSnapshotImagePng = "png"
- videoSnapshotImageJpg = "jpg"
-)
+type Config struct {
+ BucketURL string
+ SecretID string
+ SecretKey string
+ SessionToken string
+ PublicRead bool
+}
-func NewCos() (s3.Interface, error) {
- conf := config.Config.Object.Cos
+func NewCos(conf Config) (s3.Interface, error) {
u, err := url.Parse(conf.BucketURL)
if err != nil {
panic(err)
@@ -70,6 +71,7 @@ func NewCos() (s3.Interface, error) {
},
})
return &Cos{
+ publicRead: conf.PublicRead,
copyURL: u.Host + "/",
client: client,
credential: client.GetCredential(),
@@ -77,6 +79,7 @@ func NewCos() (s3.Interface, error) {
}
type Cos struct {
+ publicRead bool
copyURL string
client *cos.Client
credential *cos.Credential
@@ -227,7 +230,7 @@ func (c *Cos) CopyObject(ctx context.Context, src string, dst string) (*s3.CopyO
}
func (c *Cos) IsNotFound(err error) bool {
- switch e := err.(type) {
+ switch e := errs.Unwrap(err).(type) {
case *cos.ErrorResponse:
return e.Response.StatusCode == http.StatusNotFound || e.Code == "NoSuchKey"
default:
@@ -328,7 +331,7 @@ func (c *Cos) AccessURL(ctx context.Context, name string, expire time.Duration,
}
func (c *Cos) getPresignedURL(ctx context.Context, name string, expire time.Duration, opt *cos.PresignedURLOptions) (*url.URL, error) {
- if !config.Config.Object.Cos.PublicRead {
+ if !c.publicRead {
return c.client.Object.GetPresignedURL(ctx, http.MethodGet, name, c.credential.SecretID, c.credential.SecretKey, expire, opt)
}
return c.client.Object.GetObjectURL(name), nil
diff --git a/pkg/common/db/s3/minio/image.go b/pkg/common/db/s3/minio/image.go
index 71db1ea51..3223993f4 100644
--- a/pkg/common/db/s3/minio/image.go
+++ b/pkg/common/db/s3/minio/image.go
@@ -47,27 +47,27 @@ func resizeImage(img image.Image, maxWidth, maxHeight int) image.Image {
imgWidth := bounds.Max.X
imgHeight := bounds.Max.Y
- // 计算缩放比例
+ // Calculating scaling
scaleWidth := float64(maxWidth) / float64(imgWidth)
scaleHeight := float64(maxHeight) / float64(imgHeight)
- // 如果都为0,则不缩放,返回原始图片
+ // If both are 0, then no scaling is done and the original image is returned
if maxWidth == 0 && maxHeight == 0 {
return img
}
- // 如果宽度和高度都大于0,则选择较小的缩放比例,以保持宽高比
+ // If both width and height are greater than 0, select a smaller zoom ratio to maintain the aspect ratio
if maxWidth > 0 && maxHeight > 0 {
scale := scaleWidth
if scaleHeight < scaleWidth {
scale = scaleHeight
}
- // 计算缩略图尺寸
+ // Calculate Thumbnail Size
thumbnailWidth := int(float64(imgWidth) * scale)
thumbnailHeight := int(float64(imgHeight) * scale)
- // 使用"image"库的Resample方法生成缩略图
+ // Thumbnails are generated using the Resample method of the "image" library.
thumbnail := image.NewRGBA(image.Rect(0, 0, thumbnailWidth, thumbnailHeight))
for y := 0; y < thumbnailHeight; y++ {
for x := 0; x < thumbnailWidth; x++ {
@@ -80,12 +80,12 @@ func resizeImage(img image.Image, maxWidth, maxHeight int) image.Image {
return thumbnail
}
- // 如果只指定了宽度或高度,则根据最大不超过的规则生成缩略图
+ // If only width or height is specified, thumbnails are generated based on the maximum not to exceed rule
if maxWidth > 0 {
thumbnailWidth := maxWidth
thumbnailHeight := int(float64(imgHeight) * scaleWidth)
- // 使用"image"库的Resample方法生成缩略图
+ // Thumbnails are generated using the Resample method of the "image" library.
thumbnail := image.NewRGBA(image.Rect(0, 0, thumbnailWidth, thumbnailHeight))
for y := 0; y < thumbnailHeight; y++ {
for x := 0; x < thumbnailWidth; x++ {
@@ -102,7 +102,7 @@ func resizeImage(img image.Image, maxWidth, maxHeight int) image.Image {
thumbnailWidth := int(float64(imgWidth) * scaleHeight)
thumbnailHeight := maxHeight
- // 使用"image"库的Resample方法生成缩略图
+ // Thumbnails are generated using the Resample method of the "image" library.
thumbnail := image.NewRGBA(image.Rect(0, 0, thumbnailWidth, thumbnailHeight))
for y := 0; y < thumbnailHeight; y++ {
for x := 0; x < thumbnailWidth; x++ {
@@ -115,6 +115,6 @@ func resizeImage(img image.Image, maxWidth, maxHeight int) image.Image {
return thumbnail
}
- // 默认情况下,返回原始图片
+ // By default, the original image is returned
return img
}
diff --git a/pkg/common/db/s3/minio/minio.go b/pkg/common/db/s3/minio/minio.go
index 5a615dcfd..10526998f 100644
--- a/pkg/common/db/s3/minio/minio.go
+++ b/pkg/common/db/s3/minio/minio.go
@@ -29,14 +29,12 @@ import (
"time"
"unsafe"
- "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache"
-
+ "github.com/OpenIMSDK/tools/errs"
"github.com/OpenIMSDK/tools/log"
"github.com/minio/minio-go/v7"
"github.com/minio/minio-go/v7/pkg/credentials"
"github.com/minio/minio-go/v7/pkg/signer"
-
- "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/s3"
)
@@ -45,7 +43,7 @@ const (
)
const (
- minPartSize int64 = 1024 * 1024 * 5 // 1MB
+ minPartSize int64 = 1024 * 1024 * 5 // 5MB
maxPartSize int64 = 1024 * 1024 * 1024 * 5 // 5GB
maxNumSize int64 = 10000
)
@@ -59,13 +57,23 @@ const (
const successCode = http.StatusOK
-func NewMinio(cache cache.MinioCache) (s3.Interface, error) {
- u, err := url.Parse(config.Config.Object.Minio.Endpoint)
+type Config struct {
+ Bucket string
+ Endpoint string
+ AccessKeyID string
+ SecretAccessKey string
+ SessionToken string
+ SignEndpoint string
+ PublicRead bool
+}
+
+func NewMinio(cache cache.MinioCache, conf Config) (s3.Interface, error) {
+ u, err := url.Parse(conf.Endpoint)
if err != nil {
return nil, err
}
opts := &minio.Options{
- Creds: credentials.NewStaticV4(config.Config.Object.Minio.AccessKeyID, config.Config.Object.Minio.SecretAccessKey, config.Config.Object.Minio.SessionToken),
+ Creds: credentials.NewStaticV4(conf.AccessKeyID, conf.SecretAccessKey, conf.SessionToken),
Secure: u.Scheme == "https",
}
client, err := minio.New(u.Host, opts)
@@ -73,26 +81,27 @@ func NewMinio(cache cache.MinioCache) (s3.Interface, error) {
return nil, err
}
m := &Minio{
- bucket: config.Config.Object.Minio.Bucket,
+ conf: conf,
+ bucket: conf.Bucket,
core: &minio.Core{Client: client},
lock: &sync.Mutex{},
init: false,
cache: cache,
}
- if config.Config.Object.Minio.SignEndpoint == "" || config.Config.Object.Minio.SignEndpoint == config.Config.Object.Minio.Endpoint {
+ if conf.SignEndpoint == "" || conf.SignEndpoint == conf.Endpoint {
m.opts = opts
m.sign = m.core.Client
m.prefix = u.Path
u.Path = ""
- config.Config.Object.Minio.Endpoint = u.String()
- m.signEndpoint = config.Config.Object.Minio.Endpoint
+ conf.Endpoint = u.String()
+ m.signEndpoint = conf.Endpoint
} else {
- su, err := url.Parse(config.Config.Object.Minio.SignEndpoint)
+ su, err := url.Parse(conf.SignEndpoint)
if err != nil {
return nil, err
}
m.opts = &minio.Options{
- Creds: credentials.NewStaticV4(config.Config.Object.Minio.AccessKeyID, config.Config.Object.Minio.SecretAccessKey, config.Config.Object.Minio.SessionToken),
+ Creds: credentials.NewStaticV4(conf.AccessKeyID, conf.SecretAccessKey, conf.SessionToken),
Secure: su.Scheme == "https",
}
m.sign, err = minio.New(su.Host, m.opts)
@@ -101,8 +110,8 @@ func NewMinio(cache cache.MinioCache) (s3.Interface, error) {
}
m.prefix = su.Path
su.Path = ""
- config.Config.Object.Minio.SignEndpoint = su.String()
- m.signEndpoint = config.Config.Object.Minio.SignEndpoint
+ conf.SignEndpoint = su.String()
+ m.signEndpoint = conf.SignEndpoint
}
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
@@ -113,6 +122,7 @@ func NewMinio(cache cache.MinioCache) (s3.Interface, error) {
}
type Minio struct {
+ conf Config
bucket string
signEndpoint string
location string
@@ -134,31 +144,30 @@ func (m *Minio) initMinio(ctx context.Context) error {
if m.init {
return nil
}
- conf := config.Config.Object.Minio
- exists, err := m.core.Client.BucketExists(ctx, conf.Bucket)
+ exists, err := m.core.Client.BucketExists(ctx, m.conf.Bucket)
if err != nil {
return fmt.Errorf("check bucket exists error: %w", err)
}
if !exists {
- if err := m.core.Client.MakeBucket(ctx, conf.Bucket, minio.MakeBucketOptions{}); err != nil {
+ if err = m.core.Client.MakeBucket(ctx, m.conf.Bucket, minio.MakeBucketOptions{}); err != nil {
return fmt.Errorf("make bucket error: %w", err)
}
}
- if conf.PublicRead {
+ if m.conf.PublicRead {
policy := fmt.Sprintf(
`{"Version": "2012-10-17","Statement": [{"Action": ["s3:GetObject","s3:PutObject"],"Effect": "Allow","Principal": {"AWS": ["*"]},"Resource": ["arn:aws:s3:::%s/*"],"Sid": ""}]}`,
- conf.Bucket,
+ m.conf.Bucket,
)
- if err := m.core.Client.SetBucketPolicy(ctx, conf.Bucket, policy); err != nil {
+ if err = m.core.Client.SetBucketPolicy(ctx, m.conf.Bucket, policy); err != nil {
return err
}
}
- m.location, err = m.core.Client.GetBucketLocation(ctx, conf.Bucket)
+ m.location, err = m.core.Client.GetBucketLocation(ctx, m.conf.Bucket)
if err != nil {
return err
}
func() {
- if conf.SignEndpoint == "" || conf.SignEndpoint == conf.Endpoint {
+ if m.conf.SignEndpoint == "" || m.conf.SignEndpoint == m.conf.Endpoint {
return
}
defer func() {
@@ -178,7 +187,7 @@ func (m *Minio) initMinio(ctx context.Context) error {
blc := reflect.ValueOf(m.sign).Elem().FieldByName("bucketLocCache")
vblc := reflect.New(reflect.PtrTo(blc.Type()))
*(*unsafe.Pointer)(vblc.UnsafePointer()) = unsafe.Pointer(blc.UnsafeAddr())
- vblc.Elem().Elem().Interface().(interface{ Set(string, string) }).Set(conf.Bucket, m.location)
+ vblc.Elem().Elem().Interface().(interface{ Set(string, string) }).Set(m.conf.Bucket, m.location)
}()
m.init = true
return nil
@@ -343,10 +352,7 @@ func (m *Minio) CopyObject(ctx context.Context, src string, dst string) (*s3.Cop
}
func (m *Minio) IsNotFound(err error) bool {
- if err == nil {
- return false
- }
- switch e := err.(type) {
+ switch e := errs.Unwrap(err).(type) {
case minio.ErrorResponse:
return e.StatusCode == http.StatusNotFound || e.Code == "NoSuchKey"
case *minio.ErrorResponse:
@@ -399,7 +405,7 @@ func (m *Minio) PresignedGetObject(ctx context.Context, name string, expire time
rawURL *url.URL
err error
)
- if config.Config.Object.Minio.PublicRead {
+ if m.conf.PublicRead {
rawURL, err = makeTargetURL(m.sign, m.bucket, name, m.location, false, query)
} else {
rawURL, err = m.sign.PresignedGetObject(ctx, m.bucket, name, expire, query)
diff --git a/pkg/common/db/s3/minio/thumbnail.go b/pkg/common/db/s3/minio/thumbnail.go
index 49c376c9f..1bf96c27c 100644
--- a/pkg/common/db/s3/minio/thumbnail.go
+++ b/pkg/common/db/s3/minio/thumbnail.go
@@ -31,7 +31,6 @@ import (
"github.com/OpenIMSDK/tools/errs"
"github.com/OpenIMSDK/tools/log"
"github.com/minio/minio-go/v7"
-
"github.com/openimsdk/open-im-server/v3/pkg/common/db/cache"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/s3"
)
@@ -82,7 +81,8 @@ func (m *Minio) getImageThumbnailURL(ctx context.Context, name string, expire ti
}
key, err := m.cache.GetThumbnailKey(ctx, name, opt.Format, opt.Width, opt.Height, func(ctx context.Context) (string, error) {
if img == nil {
- reader, err := m.core.Client.GetObject(ctx, m.bucket, name, minio.GetObjectOptions{})
+ var reader *minio.Object
+ reader, err = m.core.Client.GetObject(ctx, m.bucket, name, minio.GetObjectOptions{})
if err != nil {
return "", err
}
@@ -103,7 +103,7 @@ func (m *Minio) getImageThumbnailURL(ctx context.Context, name string, expire ti
err = gif.Encode(buf, thumbnail, nil)
}
cacheKey := filepath.Join(imageThumbnailPath, info.Etag, fmt.Sprintf("image_w%d_h%d.%s", opt.Width, opt.Height, opt.Format))
- if _, err := m.core.Client.PutObject(ctx, m.bucket, cacheKey, buf, int64(buf.Len()), minio.PutObjectOptions{}); err != nil {
+ if _, err = m.core.Client.PutObject(ctx, m.bucket, cacheKey, buf, int64(buf.Len()), minio.PutObjectOptions{}); err != nil {
return "", err
}
return cacheKey, nil
diff --git a/pkg/common/db/s3/oss/oss.go b/pkg/common/db/s3/oss/oss.go
index 0bba97ee7..e485db277 100644
--- a/pkg/common/db/s3/oss/oss.go
+++ b/pkg/common/db/s3/oss/oss.go
@@ -30,9 +30,8 @@ import (
"strings"
"time"
+ "github.com/OpenIMSDK/tools/errs"
"github.com/aliyun/aliyun-oss-go-sdk/oss"
-
- "github.com/openimsdk/open-im-server/v3/pkg/common/config"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/s3"
)
@@ -52,15 +51,19 @@ const (
const successCode = http.StatusOK
-const (
- videoSnapshotImagePng = "png"
- videoSnapshotImageJpg = "jpg"
-)
+type Config struct {
+ Endpoint string
+ Bucket string
+ BucketURL string
+ AccessKeyID string
+ AccessKeySecret string
+ SessionToken string
+ PublicRead bool
+}
-func NewOSS() (s3.Interface, error) {
- conf := config.Config.Object.Oss
+func NewOSS(conf Config) (s3.Interface, error) {
if conf.BucketURL == "" {
- return nil, errors.New("bucket url is empty")
+ return nil, errs.Wrap(errors.New("bucket url is empty"))
}
client, err := oss.New(conf.Endpoint, conf.AccessKeyID, conf.AccessKeySecret)
if err != nil {
@@ -68,7 +71,7 @@ func NewOSS() (s3.Interface, error) {
}
bucket, err := client.Bucket(conf.Bucket)
if err != nil {
- return nil, err
+ return nil, errs.Wrap(err, "ali-oss bucket error")
}
if conf.BucketURL[len(conf.BucketURL)-1] != '/' {
conf.BucketURL += "/"
@@ -78,6 +81,7 @@ func NewOSS() (s3.Interface, error) {
bucket: bucket,
credentials: client.Config.GetCredentials(),
um: *(*urlMaker)(reflect.ValueOf(bucket.Client.Conn).Elem().FieldByName("url").UnsafePointer()),
+ publicRead: conf.PublicRead,
}, nil
}
@@ -86,6 +90,7 @@ type OSS struct {
bucket *oss.Bucket
credentials oss.Credentials
um urlMaker
+ publicRead bool
}
func (o *OSS) Engine() string {
@@ -138,10 +143,10 @@ func (o *OSS) CompleteMultipartUpload(ctx context.Context, uploadID string, name
func (o *OSS) PartSize(ctx context.Context, size int64) (int64, error) {
if size <= 0 {
- return 0, errors.New("size must be greater than 0")
+ return 0, errs.Wrap(errors.New("size must be greater than 0"))
}
if size > maxPartSize*maxNumSize {
- return 0, fmt.Errorf("OSS size must be less than the maximum allowed limit")
+ return 0, errs.Wrap(errors.New("size must be less than the maximum allowed limit"))
}
if size <= minPartSize*maxNumSize {
return minPartSize, nil
@@ -196,25 +201,25 @@ func (o *OSS) StatObject(ctx context.Context, name string) (*s3.ObjectInfo, erro
}
res := &s3.ObjectInfo{Key: name}
if res.ETag = strings.ToLower(strings.ReplaceAll(header.Get("ETag"), `"`, ``)); res.ETag == "" {
- return nil, errors.New("StatObject etag not found")
+ return nil, errs.Wrap(errors.New("StatObject etag not found"))
}
if contentLengthStr := header.Get("Content-Length"); contentLengthStr == "" {
return nil, errors.New("StatObject content-length not found")
} else {
res.Size, err = strconv.ParseInt(contentLengthStr, 10, 64)
if err != nil {
- return nil, fmt.Errorf("StatObject content-length parse error: %w", err)
+ return nil, errs.Wrap(err, "StatObject content-length parse error")
}
if res.Size < 0 {
- return nil, errors.New("StatObject content-length must be greater than 0")
+ return nil, errs.Wrap(errors.New("StatObject content-length must be greater than 0"))
}
}
if lastModified := header.Get("Last-Modified"); lastModified == "" {
- return nil, errors.New("StatObject last-modified not found")
+ return nil, errs.Wrap(errors.New("StatObject last-modified not found"))
} else {
res.LastModified, err = time.Parse(http.TimeFormat, lastModified)
if err != nil {
- return nil, fmt.Errorf("StatObject last-modified parse error: %w", err)
+ return nil, errs.Wrap(err, "StatObject last-modified parse error")
}
}
return res, nil
@@ -227,7 +232,7 @@ func (o *OSS) DeleteObject(ctx context.Context, name string) error {
func (o *OSS) CopyObject(ctx context.Context, src string, dst string) (*s3.CopyObjectInfo, error) {
result, err := o.bucket.CopyObject(src, dst)
if err != nil {
- return nil, err
+ return nil, errs.Wrap(err, "CopyObject error")
}
return &s3.CopyObjectInfo{
Key: dst,
@@ -236,7 +241,7 @@ func (o *OSS) CopyObject(ctx context.Context, src string, dst string) (*s3.CopyO
}
func (o *OSS) IsNotFound(err error) bool {
- switch e := err.(type) {
+ switch e := errs.Unwrap(err).(type) {
case oss.ServiceError:
return e.StatusCode == http.StatusNotFound || e.Code == "NoSuchKey"
case *oss.ServiceError:
@@ -261,7 +266,7 @@ func (o *OSS) ListUploadedParts(ctx context.Context, uploadID string, name strin
Bucket: o.bucket.BucketName,
}, oss.MaxUploads(100), oss.MaxParts(maxParts), oss.PartNumberMarker(partNumberMarker))
if err != nil {
- return nil, err
+ return nil, errs.Wrap(err, "ListUploadedParts error")
}
res := &s3.ListUploadedPartsResult{
Key: result.Key,
@@ -282,11 +287,10 @@ func (o *OSS) ListUploadedParts(ctx context.Context, uploadID string, name strin
}
func (o *OSS) AccessURL(ctx context.Context, name string, expire time.Duration, opt *s3.AccessURLOption) (string, error) {
- publicRead := config.Config.Object.Oss.PublicRead
var opts []oss.Option
if opt != nil {
if opt.Image != nil {
- // 文档地址: https://help.aliyun.com/zh/oss/user-guide/resize-images-4?spm=a2c4g.11186623.0.0.4b3b1e4fWW6yji
+ // Docs Address: https://help.aliyun.com/zh/oss/user-guide/resize-images-4?spm=a2c4g.11186623.0.0.4b3b1e4fWW6yji
var format string
switch opt.Image.Format {
case
@@ -310,7 +314,7 @@ func (o *OSS) AccessURL(ctx context.Context, name string, expire time.Duration,
process += ",format," + format
opts = append(opts, oss.Process(process))
}
- if !publicRead {
+ if !o.publicRead {
if opt.ContentType != "" {
opts = append(opts, oss.ResponseContentType(opt.ContentType))
}
@@ -324,12 +328,12 @@ func (o *OSS) AccessURL(ctx context.Context, name string, expire time.Duration,
} else if expire < time.Second {
expire = time.Second
}
- if !publicRead {
+ if !o.publicRead {
return o.bucket.SignURL(name, http.MethodGet, int64(expire/time.Second), opts...)
}
rawParams, err := oss.GetRawParams(opts)
if err != nil {
- return "", err
+ return "", errs.Wrap(err, "AccessURL error")
}
params := getURLParams(*o.bucket.Client.Conn, rawParams)
return getURL(o.um, o.bucket.BucketName, name, params).String(), nil
@@ -351,12 +355,12 @@ func (o *OSS) FormData(ctx context.Context, name string, size int64, contentType
}
policyJson, err := json.Marshal(policy)
if err != nil {
- return nil, err
+ return nil, errs.Wrap(err, "Marshal json error")
}
policyStr := base64.StdEncoding.EncodeToString(policyJson)
h := hmac.New(sha1.New, []byte(o.credentials.GetAccessKeySecret()))
if _, err := io.WriteString(h, policyStr); err != nil {
- return nil, err
+ return nil, errs.Wrap(err, "WriteString error")
}
fd := &s3.FormData{
URL: o.bucketURL,
diff --git a/pkg/common/db/table/relation/group.go b/pkg/common/db/table/relation/group.go
index 57d6b1d62..1f969cd4f 100644
--- a/pkg/common/db/table/relation/group.go
+++ b/pkg/common/db/table/relation/group.go
@@ -46,8 +46,8 @@ type GroupModelInterface interface {
Find(ctx context.Context, groupIDs []string) (groups []*GroupModel, err error)
Take(ctx context.Context, groupID string) (group *GroupModel, err error)
Search(ctx context.Context, keyword string, pagination pagination.Pagination) (total int64, groups []*GroupModel, err error)
- // 获取群总数
+ // Get Group total quantity
CountTotal(ctx context.Context, before *time.Time) (count int64, err error)
- // 获取范围内群增量
+ // Get Group total quantity every day
CountRangeEverydayTotal(ctx context.Context, start time.Time, end time.Time) (map[string]int64, error)
}
diff --git a/pkg/common/db/table/relation/user.go b/pkg/common/db/table/relation/user.go
index dbb2ff464..375930ddf 100644
--- a/pkg/common/db/table/relation/user.go
+++ b/pkg/common/db/table/relation/user.go
@@ -19,7 +19,6 @@ import (
"time"
"github.com/OpenIMSDK/protocol/user"
-
"github.com/OpenIMSDK/tools/pagination"
)
@@ -62,9 +61,9 @@ type UserModelInterface interface {
Exist(ctx context.Context, userID string) (exist bool, err error)
GetAllUserID(ctx context.Context, pagination pagination.Pagination) (count int64, userIDs []string, err error)
GetUserGlobalRecvMsgOpt(ctx context.Context, userID string) (opt int, err error)
- // 获取用户总数
+ // Get user total quantity
CountTotal(ctx context.Context, before *time.Time) (count int64, err error)
- // 获取范围内用户增量
+ // Get user total quantity every day
CountRangeEverydayTotal(ctx context.Context, start time.Time, end time.Time) (map[string]int64, error)
//CRUD user command
AddUserCommand(ctx context.Context, userID string, Type int32, UUID string, value string, ex string) error
diff --git a/pkg/common/db/table/unrelation/msg.go b/pkg/common/db/table/unrelation/msg.go
index c95b211a8..60dd7c260 100644
--- a/pkg/common/db/table/unrelation/msg.go
+++ b/pkg/common/db/table/unrelation/msg.go
@@ -20,10 +20,8 @@ import (
"time"
"github.com/OpenIMSDK/protocol/msg"
-
- "go.mongodb.org/mongo-driver/mongo"
-
"github.com/OpenIMSDK/protocol/sdkws"
+ "go.mongodb.org/mongo-driver/mongo"
)
const (
diff --git a/pkg/common/db/unrelation/mongo.go b/pkg/common/db/unrelation/mongo.go
index b8184d767..834e81237 100644
--- a/pkg/common/db/unrelation/mongo.go
+++ b/pkg/common/db/unrelation/mongo.go
@@ -21,16 +21,13 @@ import (
"strings"
"time"
+ "github.com/OpenIMSDK/tools/errs"
+ "github.com/OpenIMSDK/tools/mw/specialerror"
+ "github.com/openimsdk/open-im-server/v3/pkg/common/config"
+ "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/unrelation"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
-
- "github.com/OpenIMSDK/tools/errs"
- "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/db/table/unrelation"
)
const (
@@ -39,13 +36,14 @@ const (
)
type Mongo struct {
- db *mongo.Client
+ db *mongo.Client
+ config *config.GlobalConfig
}
// NewMongo Initialize MongoDB connection.
-func NewMongo() (*Mongo, error) {
+func NewMongo(config *config.GlobalConfig) (*Mongo, error) {
specialerror.AddReplace(mongo.ErrNoDocuments, errs.ErrRecordNotFound)
- uri := buildMongoURI()
+ uri := buildMongoURI(config)
var mongoClient *mongo.Client
var err error
@@ -56,26 +54,27 @@ func NewMongo() (*Mongo, error) {
defer cancel()
mongoClient, err = mongo.Connect(ctx, options.Client().ApplyURI(uri))
if err == nil {
- return &Mongo{db: mongoClient}, nil
+ if err = mongoClient.Ping(ctx, nil); err != nil {
+ return nil, errs.Wrap(err, uri)
+ }
+ return &Mongo{db: mongoClient, config: config}, nil
}
if shouldRetry(err) {
- fmt.Printf("Failed to connect to MongoDB, retrying: %s\n", err)
time.Sleep(time.Second) // exponential backoff could be implemented here
continue
}
- return nil, err
}
- return nil, err
+ return nil, errs.Wrap(err, uri)
}
-func buildMongoURI() string {
+func buildMongoURI(config *config.GlobalConfig) string {
uri := os.Getenv("MONGO_URI")
if uri != "" {
return uri
}
- if config.Config.Mongo.Uri != "" {
- return config.Config.Mongo.Uri
+ if config.Mongo.Uri != "" {
+ return config.Mongo.Uri
}
username := os.Getenv("MONGO_OPENIM_USERNAME")
@@ -86,29 +85,28 @@ func buildMongoURI() string {
maxPoolSize := os.Getenv("MONGO_MAX_POOL_SIZE")
if username == "" {
- username = config.Config.Mongo.Username
+ username = config.Mongo.Username
}
if password == "" {
- password = config.Config.Mongo.Password
+ password = config.Mongo.Password
}
if address == "" {
- address = strings.Join(config.Config.Mongo.Address, ",")
+ address = strings.Join(config.Mongo.Address, ",")
} else if port != "" {
address = fmt.Sprintf("%s:%s", address, port)
}
if database == "" {
- database = config.Config.Mongo.Database
+ database = config.Mongo.Database
}
if maxPoolSize == "" {
- maxPoolSize = fmt.Sprint(config.Config.Mongo.MaxPoolSize)
+ maxPoolSize = fmt.Sprint(config.Mongo.MaxPoolSize)
}
- uriFormat := "mongodb://%s/%s?maxPoolSize=%s"
if username != "" && password != "" {
- uriFormat = "mongodb://%s:%s@%s/%s?maxPoolSize=%s"
- return fmt.Sprintf(uriFormat, username, password, address, database, maxPoolSize)
+
+ return fmt.Sprintf("mongodb://%s:%s@%s/%s?maxPoolSize=%s", username, password, address, database, maxPoolSize)
}
- return fmt.Sprintf(uriFormat, address, database, maxPoolSize)
+ return fmt.Sprintf("mongodb://%s/%s?maxPoolSize=%s", address, database, maxPoolSize)
}
func shouldRetry(err error) bool {
@@ -124,8 +122,8 @@ func (m *Mongo) GetClient() *mongo.Client {
}
// GetDatabase returns the specific database from MongoDB.
-func (m *Mongo) GetDatabase() *mongo.Database {
- return m.db.Database(config.Config.Mongo.Database)
+func (m *Mongo) GetDatabase(database string) *mongo.Database {
+ return m.db.Database(database)
}
// CreateMsgIndex creates an index for messages in MongoDB.
@@ -135,7 +133,7 @@ func (m *Mongo) CreateMsgIndex() error {
// createMongoIndex creates an index in a MongoDB collection.
func (m *Mongo) createMongoIndex(collection string, isUnique bool, keys ...string) error {
- db := m.GetDatabase().Collection(collection)
+ db := m.GetDatabase(m.config.Mongo.Database).Collection(collection)
opts := options.CreateIndexes().SetMaxTime(10 * time.Second)
indexView := db.Indexes()
@@ -150,7 +148,7 @@ func (m *Mongo) createMongoIndex(collection string, isUnique bool, keys ...strin
_, err := indexView.CreateOne(context.Background(), index, opts)
if err != nil {
- return utils.Wrap(err, "CreateIndex")
+ return errs.Wrap(err, "CreateIndex")
}
return nil
}
diff --git a/pkg/common/db/unrelation/msg.go b/pkg/common/db/unrelation/msg.go
index 9b461dd1f..4deca56f8 100644
--- a/pkg/common/db/unrelation/msg.go
+++ b/pkg/common/db/unrelation/msg.go
@@ -21,23 +21,17 @@ import (
"fmt"
"time"
- "github.com/OpenIMSDK/tools/log"
-
- "github.com/OpenIMSDK/protocol/msg"
-
"github.com/OpenIMSDK/protocol/constant"
-
+ "github.com/OpenIMSDK/protocol/msg"
+ "github.com/OpenIMSDK/protocol/sdkws"
+ "github.com/OpenIMSDK/tools/errs"
+ "github.com/OpenIMSDK/tools/log"
+ table "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/unrelation"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
"google.golang.org/protobuf/proto"
-
- "github.com/OpenIMSDK/protocol/sdkws"
- "github.com/OpenIMSDK/tools/errs"
- "github.com/OpenIMSDK/tools/utils"
-
- table "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/unrelation"
)
var ErrMsgListNotExist = errors.New("user not have msg in mongoDB")
@@ -79,7 +73,7 @@ func (m *MsgMongoDriver) UpdateMsg(
update := bson.M{"$set": bson.M{field: value}}
res, err := m.MsgCollection.UpdateOne(ctx, filter, update)
if err != nil {
- return nil, utils.Wrap(err, "")
+ return nil, errs.Wrap(err)
}
return res, nil
}
@@ -106,7 +100,7 @@ func (m *MsgMongoDriver) PushUnique(
}
res, err := m.MsgCollection.UpdateOne(ctx, filter, update)
if err != nil {
- return nil, utils.Wrap(err, "")
+ return nil, errs.Wrap(err)
}
return res, nil
}
@@ -118,22 +112,16 @@ func (m *MsgMongoDriver) UpdateMsgContent(ctx context.Context, docID string, ind
bson.M{"$set": bson.M{fmt.Sprintf("msgs.%d.msg", index): msg}},
)
if err != nil {
- return utils.Wrap(err, "")
+ return errs.Wrap(err)
}
return nil
}
-func (m *MsgMongoDriver) UpdateMsgStatusByIndexInOneDoc(
- ctx context.Context,
- docID string,
- msg *sdkws.MsgData,
- seqIndex int,
- status int32,
-) error {
+func (m *MsgMongoDriver) UpdateMsgStatusByIndexInOneDoc(ctx context.Context, docID string, msg *sdkws.MsgData, seqIndex int, status int32) error {
msg.Status = status
bytes, err := proto.Marshal(msg)
if err != nil {
- return utils.Wrap(err, "")
+ return errs.Wrap(err)
}
_, err = m.MsgCollection.UpdateOne(
ctx,
@@ -141,7 +129,7 @@ func (m *MsgMongoDriver) UpdateMsgStatusByIndexInOneDoc(
bson.M{"$set": bson.M{fmt.Sprintf("msgs.%d.msg", seqIndex): bytes}},
)
if err != nil {
- return utils.Wrap(err, "")
+ return errs.Wrap(err, fmt.Sprintf("docID is %s, seqIndex is %d", docID, seqIndex))
}
return nil
}
@@ -167,12 +155,12 @@ func (m *MsgMongoDriver) GetMsgDocModelByIndex(
findOpts,
)
if err != nil {
- return nil, utils.Wrap(err, "")
+ return nil, errs.Wrap(err, fmt.Sprintf("conversationID is %s", conversationID))
}
var msgs []table.MsgDocModel
err = cursor.All(ctx, &msgs)
if err != nil {
- return nil, utils.Wrap(err, fmt.Sprintf("cursor is %s", cursor.Current.String()))
+ return nil, errs.Wrap(err, fmt.Sprintf("cursor is %s", cursor.Current.String()))
}
if len(msgs) > 0 {
return &msgs[0], nil
@@ -223,7 +211,7 @@ func (m *MsgMongoDriver) DeleteMsgsInOneDocByIndex(ctx context.Context, docID st
}
_, err := m.MsgCollection.UpdateMany(ctx, bson.M{"doc_id": docID}, updates)
if err != nil {
- return utils.Wrap(err, "")
+ return errs.Wrap(err, fmt.Sprintf("docID is %s, indexes is %v", docID, indexes))
}
return nil
}
@@ -247,47 +235,42 @@ func (m *MsgMongoDriver) GetMsgBySeqIndexIn1Doc(
indexs = append(indexs, m.model.GetMsgIndex(seq))
}
pipeline := mongo.Pipeline{
- {
- {"$match", bson.D{
- {"doc_id", docID},
- }},
- },
- {
- {"$project", bson.D{
- {"_id", 0},
- {"doc_id", 1},
- {"msgs", bson.D{
- {"$map", bson.D{
- {"input", indexs},
- {"as", "index"},
- {"in", bson.D{
- {"$let", bson.D{
- {"vars", bson.D{
- {"currentMsg", bson.D{
- {"$arrayElemAt", []string{"$msgs", "$$index"}},
- }},
+ bson.D{{Key: "$match", Value: bson.D{
+ {Key: "doc_id", Value: docID},
+ }}},
+ bson.D{{Key: "$project", Value: bson.D{
+ {Key: "_id", Value: 0},
+ {Key: "doc_id", Value: 1},
+ {Key: "msgs", Value: bson.D{
+ {Key: "$map", Value: bson.D{
+ {Key: "input", Value: indexs},
+ {Key: "as", Value: "index"},
+ {Key: "in", Value: bson.D{
+ {Key: "$let", Value: bson.D{
+ {Key: "vars", Value: bson.D{
+ {Key: "currentMsg", Value: bson.D{
+ {Key: "$arrayElemAt", Value: bson.A{"$msgs", "$$index"}},
}},
- {"in", bson.D{
- {"$cond", bson.D{
- {"if", bson.D{
- {"$in", []string{userID, "$$currentMsg.del_list"}},
- }},
- {"then", nil},
- {"else", "$$currentMsg"},
+ }},
+ {Key: "in", Value: bson.D{
+ {Key: "$cond", Value: bson.D{
+ {Key: "if", Value: bson.D{
+ {Key: "$in", Value: bson.A{userID, "$$currentMsg.del_list"}},
}},
+ {Key: "then", Value: nil},
+ {Key: "else", Value: "$$currentMsg"},
}},
}},
}},
}},
}},
}},
- },
- {
- {"$project", bson.D{
- {"msgs.del_list", 0},
- }},
- },
+ }}},
+ bson.D{{Key: "$project", Value: bson.D{
+ {Key: "msgs.del_list", Value: 0},
+ }}},
}
+
cur, err := m.MsgCollection.Aggregate(ctx, pipeline)
if err != nil {
return nil, errs.Wrap(err)
@@ -295,7 +278,7 @@ func (m *MsgMongoDriver) GetMsgBySeqIndexIn1Doc(
defer cur.Close(ctx)
var msgDocModel []table.MsgDocModel
if err := cur.All(ctx, &msgDocModel); err != nil {
- return nil, errs.Wrap(err)
+ return nil, errs.Wrap(err, fmt.Sprintf("docID is %s, seqs is %v", docID, seqs))
}
if len(msgDocModel) == 0 {
return nil, errs.Wrap(mongo.ErrNoDocuments)
@@ -322,14 +305,14 @@ func (m *MsgMongoDriver) GetMsgBySeqIndexIn1Doc(
}
data, err := json.Marshal(&revokeContent)
if err != nil {
- return nil, err
+ return nil, errs.Wrap(err, fmt.Sprintf("docID is %s, seqs is %v", docID, seqs))
}
elem := sdkws.NotificationElem{
Detail: string(data),
}
content, err := json.Marshal(&elem)
if err != nil {
- return nil, err
+ return nil, errs.Wrap(err, fmt.Sprintf("docID is %s, seqs is %v", docID, seqs))
}
msg.Msg.ContentType = constant.MsgRevokeNotification
msg.Msg.Content = string(content)
@@ -342,17 +325,12 @@ func (m *MsgMongoDriver) GetMsgBySeqIndexIn1Doc(
func (m *MsgMongoDriver) IsExistDocID(ctx context.Context, docID string) (bool, error) {
count, err := m.MsgCollection.CountDocuments(ctx, bson.M{"doc_id": docID})
if err != nil {
- return false, errs.Wrap(err)
+ return false, errs.Wrap(err, fmt.Sprintf("docID is %s", docID))
}
return count > 0, nil
}
-func (m *MsgMongoDriver) MarkSingleChatMsgsAsRead(
- ctx context.Context,
- userID string,
- docID string,
- indexes []int64,
-) error {
+func (m *MsgMongoDriver) MarkSingleChatMsgsAsRead(ctx context.Context, userID string, docID string, indexes []int64) error {
updates := []mongo.WriteModel{}
for _, index := range indexes {
filter := bson.M{
@@ -372,7 +350,7 @@ func (m *MsgMongoDriver) MarkSingleChatMsgsAsRead(
updates = append(updates, updateModel)
}
_, err := m.MsgCollection.BulkWrite(ctx, updates)
- return err
+ return errs.Wrap(err, fmt.Sprintf("docID is %s, indexes is %v", docID, indexes))
}
// RangeUserSendCount
@@ -668,7 +646,7 @@ func (m *MsgMongoDriver) RangeUserSendCount(
"$dateToString": bson.M{
"format": "%Y-%m-%d",
"date": bson.M{
- "$toDate": "$$item.msg.send_time", // 毫秒时间戳
+ "$toDate": "$$item.msg.send_time", // Millisecond timestamp
},
},
},
@@ -801,7 +779,7 @@ func (m *MsgMongoDriver) RangeUserSendCount(
}
defer cur.Close(ctx)
var result []Result
- if err := cur.All(ctx, &result); err != nil {
+ if err = cur.All(ctx, &result); err != nil {
return 0, 0, nil, nil, errs.Wrap(err)
}
if len(result) == 0 {
@@ -917,7 +895,7 @@ func (m *MsgMongoDriver) RangeGroupSendCount(
"$dateToString": bson.M{
"format": "%Y-%m-%d",
"date": bson.M{
- "$toDate": "$$item.msg.send_time", // 毫秒时间戳
+ "$toDate": "$$item.msg.send_time", // Millisecond timestamp
},
},
},
@@ -1050,7 +1028,7 @@ func (m *MsgMongoDriver) RangeGroupSendCount(
}
defer cur.Close(ctx)
var result []Result
- if err := cur.All(ctx, &result); err != nil {
+ if err = cur.All(ctx, &result); err != nil {
return 0, 0, nil, nil, errs.Wrap(err)
}
if len(result) == 0 {
@@ -1082,6 +1060,7 @@ func (m *MsgMongoDriver) searchMessage(ctx context.Context, req *msg.SearchMessa
var pipe mongo.Pipeline
condition := bson.A{}
if req.SendTime != "" {
+ // Changed to keyed fields for bson.M to avoid govet errors
condition = append(condition, bson.M{"$eq": bson.A{bson.M{"$dateToString": bson.M{"format": "%Y-%m-%d", "date": bson.M{"$toDate": "$$item.msg.send_time"}}}, req.SendTime}})
}
if req.MsgType != 0 {
@@ -1098,62 +1077,26 @@ func (m *MsgMongoDriver) searchMessage(ctx context.Context, req *msg.SearchMessa
}
or := bson.A{
- bson.M{
- "doc_id": bson.M{
- "$regex": "^si_",
- "$options": "i",
- },
- },
+ bson.M{"doc_id": bson.M{"$regex": "^si_", "$options": "i"}},
+ bson.M{"doc_id": bson.M{"$regex": "^g_", "$options": "i"}},
+ bson.M{"doc_id": bson.M{"$regex": "^sg_", "$options": "i"}},
}
- or = append(or,
- bson.M{
- "doc_id": bson.M{
- "$regex": "^g_",
- "$options": "i",
- },
- },
- bson.M{
- "doc_id": bson.M{
- "$regex": "^sg_",
- "$options": "i",
- },
- },
- )
+ // Use bson.D with keyed fields to specify the order explicitly
pipe = mongo.Pipeline{
- {
- {"$match", bson.D{
- {
- "$or", or,
- },
+ {{"$match", bson.D{{Key: "$or", Value: or}}}},
+ {{"$project", bson.D{
+ {Key: "msgs", Value: bson.D{
+ {Key: "$filter", Value: bson.D{
+ {Key: "input", Value: "$msgs"},
+ {Key: "as", Value: "item"},
+ {Key: "cond", Value: bson.D{{Key: "$and", Value: condition}}},
+ }},
}},
- },
- {
- {"$project", bson.D{
- {
- "msgs", bson.D{
- {
- "$filter", bson.D{
- {"input", "$msgs"},
- {"as", "item"},
- {
- "cond", bson.D{
- {"$and", condition},
- },
- },
- },
- },
- },
- },
- {"doc_id", 1},
- }},
- },
- {
- {"$unwind", bson.M{"path": "$msgs"}},
- },
- {
- {"$sort", bson.M{"msgs.msg.send_time": -1}},
- },
+ {Key: "doc_id", Value: 1},
+ }}},
+ {{"$unwind", bson.M{"path": "$msgs"}}},
+ {{"$sort", bson.M{"msgs.msg.send_time": -1}}},
}
cursor, err := m.MsgCollection.Aggregate(ctx, pipe)
if err != nil {
@@ -1166,12 +1109,12 @@ func (m *MsgMongoDriver) searchMessage(ctx context.Context, req *msg.SearchMessa
var msgsDocs []docModel
err = cursor.All(ctx, &msgsDocs)
if err != nil {
- return 0, nil, err
+ return 0, nil, errs.Wrap(err, "cursor.All msgsDocs")
}
log.ZDebug(ctx, "query mongoDB", "result", msgsDocs)
msgs := make([]*table.MsgInfoModel, 0)
- for index := range msgsDocs {
- msgInfo := msgsDocs[index].Msg
+ for _, doc := range msgsDocs {
+ msgInfo := doc.Msg
if msgInfo == nil || msgInfo.Msg == nil {
continue
}
@@ -1191,14 +1134,12 @@ func (m *MsgMongoDriver) searchMessage(ctx context.Context, req *msg.SearchMessa
}
data, err := json.Marshal(&revokeContent)
if err != nil {
- return 0, nil, err
- }
- elem := sdkws.NotificationElem{
- Detail: string(data),
+ return 0, nil, errs.Wrap(err, "json.Marshal revokeContent")
}
+ elem := sdkws.NotificationElem{Detail: string(data)}
content, err := json.Marshal(&elem)
if err != nil {
- return 0, nil, err
+ return 0, nil, errs.Wrap(err, "json.Marshal elem")
}
msgInfo.Msg.ContentType = constant.MsgRevokeNotification
msgInfo.Msg.Content = string(content)
@@ -1209,7 +1150,8 @@ func (m *MsgMongoDriver) searchMessage(ctx context.Context, req *msg.SearchMessa
n := int32(len(msgs))
if start >= n {
return n, []*table.MsgInfoModel{}, nil
- } else if start+req.Pagination.ShowNumber < n {
+ }
+ if start+req.Pagination.ShowNumber < n {
msgs = msgs[start : start+req.Pagination.ShowNumber]
} else {
msgs = msgs[start:]
diff --git a/pkg/common/db/unrelation/msg_convert.go b/pkg/common/db/unrelation/msg_convert.go
index 373bc843e..30c74e927 100644
--- a/pkg/common/db/unrelation/msg_convert.go
+++ b/pkg/common/db/unrelation/msg_convert.go
@@ -19,10 +19,9 @@ import (
"fmt"
"github.com/OpenIMSDK/tools/log"
+ table "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/unrelation"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
-
- table "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/unrelation"
)
func (m *MsgMongoDriver) ConvertMsgsDocLen(ctx context.Context, conversationIDs []string) {
diff --git a/pkg/common/db/unrelation/user.go b/pkg/common/db/unrelation/user.go
index 4b4a78c79..cbf395bf8 100644
--- a/pkg/common/db/unrelation/user.go
+++ b/pkg/common/db/unrelation/user.go
@@ -18,12 +18,10 @@ import (
"context"
"github.com/OpenIMSDK/tools/errs"
- "github.com/OpenIMSDK/tools/utils"
+ "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/unrelation"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
-
- "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/unrelation"
)
// prefixes and suffixes.
@@ -65,7 +63,7 @@ func (u *UserMongoDriver) AddSubscriptionList(ctx context.Context, userID string
}
// iterate over aggregated results
for cursor.Next(ctx) {
- err := cursor.Decode(&cnt)
+ err = cursor.Decode(&cnt)
if err != nil {
return errs.Wrap(err)
}
@@ -119,7 +117,7 @@ func (u *UserMongoDriver) AddSubscriptionList(ctx context.Context, userID string
opts,
)
if err != nil {
- return utils.Wrap(err, "transaction failed")
+ return errs.Wrap(err, "transaction failed")
}
}
return nil
diff --git a/pkg/common/discoveryregister/direct/directconn.go b/pkg/common/discoveryregister/direct/directconn.go
index 84f173ea6..df03825e5 100644
--- a/pkg/common/discoveryregister/direct/directconn.go
+++ b/pkg/common/discoveryregister/direct/directconn.go
@@ -20,25 +20,24 @@ import (
"fmt"
"github.com/OpenIMSDK/tools/errs"
+ config2 "github.com/openimsdk/open-im-server/v3/pkg/common/config"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
-
- config2 "github.com/openimsdk/open-im-server/v3/pkg/common/config"
)
type ServiceAddresses map[string][]int
-func getServiceAddresses() ServiceAddresses {
+func getServiceAddresses(config *config2.GlobalConfig) ServiceAddresses {
return ServiceAddresses{
- config2.Config.RpcRegisterName.OpenImUserName: config2.Config.RpcPort.OpenImUserPort,
- config2.Config.RpcRegisterName.OpenImFriendName: config2.Config.RpcPort.OpenImFriendPort,
- config2.Config.RpcRegisterName.OpenImMsgName: config2.Config.RpcPort.OpenImMessagePort,
- config2.Config.RpcRegisterName.OpenImMessageGatewayName: config2.Config.LongConnSvr.OpenImMessageGatewayPort,
- config2.Config.RpcRegisterName.OpenImGroupName: config2.Config.RpcPort.OpenImGroupPort,
- config2.Config.RpcRegisterName.OpenImAuthName: config2.Config.RpcPort.OpenImAuthPort,
- config2.Config.RpcRegisterName.OpenImPushName: config2.Config.RpcPort.OpenImPushPort,
- config2.Config.RpcRegisterName.OpenImConversationName: config2.Config.RpcPort.OpenImConversationPort,
- config2.Config.RpcRegisterName.OpenImThirdName: config2.Config.RpcPort.OpenImThirdPort,
+ config.RpcRegisterName.OpenImUserName: config.RpcPort.OpenImUserPort,
+ config.RpcRegisterName.OpenImFriendName: config.RpcPort.OpenImFriendPort,
+ config.RpcRegisterName.OpenImMsgName: config.RpcPort.OpenImMessagePort,
+ config.RpcRegisterName.OpenImMessageGatewayName: config.LongConnSvr.OpenImMessageGatewayPort,
+ config.RpcRegisterName.OpenImGroupName: config.RpcPort.OpenImGroupPort,
+ config.RpcRegisterName.OpenImAuthName: config.RpcPort.OpenImAuthPort,
+ config.RpcRegisterName.OpenImPushName: config.RpcPort.OpenImPushPort,
+ config.RpcRegisterName.OpenImConversationName: config.RpcPort.OpenImConversationPort,
+ config.RpcRegisterName.OpenImThirdName: config.RpcPort.OpenImThirdPort,
}
}
@@ -47,6 +46,7 @@ type ConnDirect struct {
currentServiceAddress string
conns map[string][]*grpc.ClientConn
resolverDirect *ResolverDirect
+ config *config2.GlobalConfig
}
func (cd *ConnDirect) GetClientLocalConns() map[string][]*grpc.ClientConn {
@@ -81,10 +81,11 @@ func (cd *ConnDirect) Close() {
}
-func NewConnDirect() (*ConnDirect, error) {
+func NewConnDirect(config *config2.GlobalConfig) (*ConnDirect, error) {
return &ConnDirect{
conns: make(map[string][]*grpc.ClientConn),
resolverDirect: NewResolverDirect(),
+ config: config,
}, nil
}
@@ -94,25 +95,25 @@ func (cd *ConnDirect) GetConns(ctx context.Context,
if conns, exists := cd.conns[serviceName]; exists {
return conns, nil
}
- ports := getServiceAddresses()[serviceName]
+ ports := getServiceAddresses(cd.config)[serviceName]
var connections []*grpc.ClientConn
for _, port := range ports {
- conn, err := cd.dialServiceWithoutResolver(ctx, fmt.Sprintf(config2.Config.Rpc.ListenIP+":%d", port), append(cd.additionalOpts, opts...)...)
+ conn, err := cd.dialServiceWithoutResolver(ctx, fmt.Sprintf(cd.config.Rpc.ListenIP+":%d", port), append(cd.additionalOpts, opts...)...)
if err != nil {
- fmt.Printf("connect to port %d failed,serviceName %s, IP %s\n", port, serviceName, config2.Config.Rpc.ListenIP)
+ return nil, errs.Wrap(fmt.Errorf("connect to port %d failed,serviceName %s, IP %s", port, serviceName, cd.config.Rpc.ListenIP))
}
connections = append(connections, conn)
}
if len(connections) == 0 {
- return nil, fmt.Errorf("no connections found for service: %s", serviceName)
+ return nil, errs.Wrap(errors.New("no connections found for service"), "serviceName", serviceName)
}
return connections, nil
}
func (cd *ConnDirect) GetConn(ctx context.Context, serviceName string, opts ...grpc.DialOption) (*grpc.ClientConn, error) {
// Get service addresses
- addresses := getServiceAddresses()
+ addresses := getServiceAddresses(cd.config)
address, ok := addresses[serviceName]
if !ok {
return nil, errs.Wrap(errors.New("unknown service name"), "serviceName", serviceName)
@@ -120,9 +121,9 @@ func (cd *ConnDirect) GetConn(ctx context.Context, serviceName string, opts ...g
var result string
for _, addr := range address {
if result != "" {
- result = result + "," + fmt.Sprintf(config2.Config.Rpc.ListenIP+":%d", addr)
+ result = result + "," + fmt.Sprintf(cd.config.Rpc.ListenIP+":%d", addr)
} else {
- result = fmt.Sprintf(config2.Config.Rpc.ListenIP+":%d", addr)
+ result = fmt.Sprintf(cd.config.Rpc.ListenIP+":%d", addr)
}
}
// Try to dial a new connection
@@ -155,16 +156,17 @@ func (cd *ConnDirect) dialService(ctx context.Context, address string, opts ...g
conn, err := grpc.DialContext(ctx, cd.resolverDirect.Scheme()+":///"+address, options...)
if err != nil {
- return nil, err
+ return nil, errs.Wrap(err, "address", address)
}
return conn, nil
}
+
func (cd *ConnDirect) dialServiceWithoutResolver(ctx context.Context, address string, opts ...grpc.DialOption) (*grpc.ClientConn, error) {
options := append(opts, grpc.WithTransportCredentials(insecure.NewCredentials()))
conn, err := grpc.DialContext(ctx, address, options...)
if err != nil {
- return nil, err
+ return nil, errs.Wrap(err)
}
return conn, nil
}
diff --git a/pkg/common/discoveryregister/discoveryregister.go b/pkg/common/discoveryregister/discoveryregister.go
index 23a9e3245..d3acf85f6 100644
--- a/pkg/common/discoveryregister/discoveryregister.go
+++ b/pkg/common/discoveryregister/discoveryregister.go
@@ -18,29 +18,29 @@ import (
"errors"
"os"
+ "github.com/OpenIMSDK/tools/discoveryregistry"
+ "github.com/OpenIMSDK/tools/errs"
+ "github.com/openimsdk/open-im-server/v3/pkg/common/config"
"github.com/openimsdk/open-im-server/v3/pkg/common/discoveryregister/direct"
-
"github.com/openimsdk/open-im-server/v3/pkg/common/discoveryregister/kubernetes"
"github.com/openimsdk/open-im-server/v3/pkg/common/discoveryregister/zookeeper"
-
- "github.com/OpenIMSDK/tools/discoveryregistry"
)
// NewDiscoveryRegister creates a new service discovery and registry client based on the provided environment type.
-func NewDiscoveryRegister(envType string) (discoveryregistry.SvcDiscoveryRegistry, error) {
+func NewDiscoveryRegister(config *config.GlobalConfig) (discoveryregistry.SvcDiscoveryRegistry, error) {
if os.Getenv("ENVS_DISCOVERY") != "" {
- envType = os.Getenv("ENVS_DISCOVERY")
+ config.Envs.Discovery = os.Getenv("ENVS_DISCOVERY")
}
- switch envType {
+ switch config.Envs.Discovery {
case "zookeeper":
- return zookeeper.NewZookeeperDiscoveryRegister()
+ return zookeeper.NewZookeeperDiscoveryRegister(config)
case "k8s":
- return kubernetes.NewK8sDiscoveryRegister()
+ return kubernetes.NewK8sDiscoveryRegister(config.RpcRegisterName.OpenImMessageGatewayName)
case "direct":
- return direct.NewConnDirect()
+ return direct.NewConnDirect(config)
default:
- return nil, errors.New("envType not correct")
+ return nil, errs.Wrap(errors.New("envType not correct"))
}
}
diff --git a/pkg/common/discoveryregister/discoveryregister_test.go b/pkg/common/discoveryregister/discoveryregister_test.go
index 5317db5c6..08aa5d5d5 100644
--- a/pkg/common/discoveryregister/discoveryregister_test.go
+++ b/pkg/common/discoveryregister/discoveryregister_test.go
@@ -18,6 +18,8 @@ import (
"os"
"testing"
+ "github.com/openimsdk/open-im-server/v3/pkg/common/config"
+
"github.com/OpenIMSDK/tools/discoveryregistry"
"github.com/stretchr/testify/assert"
)
@@ -32,20 +34,23 @@ func setupTestEnvironment() {
func TestNewDiscoveryRegister(t *testing.T) {
setupTestEnvironment()
-
+ conf := config.NewGlobalConfig()
tests := []struct {
envType string
+ gatewayName string
expectedError bool
expectedResult bool
}{
- {"zookeeper", false, true},
- {"k8s", false, true}, // 假设 k8s 配置也已正确设置
- {"direct", false, true},
- {"invalid", true, false},
+ {"zookeeper", "MessageGateway", false, true},
+ {"k8s", "MessageGateway", false, true},
+ {"direct", "MessageGateway", false, true},
+ {"invalid", "MessageGateway", true, false},
}
for _, test := range tests {
- client, err := NewDiscoveryRegister(test.envType)
+ conf.Envs.Discovery = test.envType
+ conf.RpcRegisterName.OpenImMessageGatewayName = test.gatewayName
+ client, err := NewDiscoveryRegister(conf)
if test.expectedError {
assert.Error(t, err)
diff --git a/pkg/common/discoveryregister/kubernetes/kubernetes.go b/pkg/common/discoveryregister/kubernetes/kubernetes.go
index 7c40399a3..83af53db0 100644
--- a/pkg/common/discoveryregister/kubernetes/kubernetes.go
+++ b/pkg/common/discoveryregister/kubernetes/kubernetes.go
@@ -22,14 +22,10 @@ import (
"strconv"
"strings"
- "github.com/stathat/consistent"
-
- "google.golang.org/grpc"
-
"github.com/OpenIMSDK/tools/discoveryregistry"
"github.com/OpenIMSDK/tools/log"
-
- "github.com/openimsdk/open-im-server/v3/pkg/common/config"
+ "github.com/stathat/consistent"
+ "google.golang.org/grpc"
)
// K8sDR represents the Kubernetes service discovery and registration client.
@@ -37,11 +33,12 @@ type K8sDR struct {
options []grpc.DialOption
rpcRegisterAddr string
gatewayHostConsistent *consistent.Consistent
+ gatewayName string
}
-func NewK8sDiscoveryRegister() (discoveryregistry.SvcDiscoveryRegistry, error) {
+func NewK8sDiscoveryRegister(gatewayName string) (discoveryregistry.SvcDiscoveryRegistry, error) {
gatewayConsistent := consistent.New()
- gatewayHosts := getMsgGatewayHost(context.Background())
+ gatewayHosts := getMsgGatewayHost(context.Background(), gatewayName)
for _, v := range gatewayHosts {
gatewayConsistent.Add(v)
}
@@ -49,10 +46,10 @@ func NewK8sDiscoveryRegister() (discoveryregistry.SvcDiscoveryRegistry, error) {
}
func (cli *K8sDR) Register(serviceName, host string, port int, opts ...grpc.DialOption) error {
- if serviceName != config.Config.RpcRegisterName.OpenImMessageGatewayName {
+ if serviceName != cli.gatewayName {
cli.rpcRegisterAddr = serviceName
} else {
- cli.rpcRegisterAddr = getSelfHost(context.Background())
+ cli.rpcRegisterAddr = getSelfHost(context.Background(), cli.gatewayName)
}
return nil
@@ -84,15 +81,15 @@ func (cli *K8sDR) GetUserIdHashGatewayHost(ctx context.Context, userId string) (
}
return host, err
}
-func getSelfHost(ctx context.Context) string {
+func getSelfHost(ctx context.Context, gatewayName string) string {
port := 88
instance := "openimserver"
selfPodName := os.Getenv("MY_POD_NAME")
ns := os.Getenv("MY_POD_NAMESPACE")
statefuleIndex := 0
- gatewayEnds := strings.Split(config.Config.RpcRegisterName.OpenImMessageGatewayName, ":")
+ gatewayEnds := strings.Split(gatewayName, ":")
if len(gatewayEnds) != 2 {
- log.ZError(ctx, "msggateway RpcRegisterName is error:config.Config.RpcRegisterName.OpenImMessageGatewayName", errors.New("config error"))
+ log.ZError(ctx, "msggateway RpcRegisterName is error:config.RpcRegisterName.OpenImMessageGatewayName", errors.New("config error"))
} else {
port, _ = strconv.Atoi(gatewayEnds[1])
}
@@ -105,15 +102,15 @@ func getSelfHost(ctx context.Context) string {
}
// like openimserver-openim-msggateway-0.openimserver-openim-msggateway-headless.openim-lin.svc.cluster.local:88.
-func getMsgGatewayHost(ctx context.Context) []string {
+func getMsgGatewayHost(ctx context.Context, gatewayName string) []string {
port := 88
instance := "openimserver"
selfPodName := os.Getenv("MY_POD_NAME")
replicas := os.Getenv("MY_MSGGATEWAY_REPLICACOUNT")
ns := os.Getenv("MY_POD_NAMESPACE")
- gatewayEnds := strings.Split(config.Config.RpcRegisterName.OpenImMessageGatewayName, ":")
+ gatewayEnds := strings.Split(gatewayName, ":")
if len(gatewayEnds) != 2 {
- log.ZError(ctx, "msggateway RpcRegisterName is error:config.Config.RpcRegisterName.OpenImMessageGatewayName", errors.New("config error"))
+ log.ZError(ctx, "msggateway RpcRegisterName is error:config.RpcRegisterName.OpenImMessageGatewayName", errors.New("config error"))
} else {
port, _ = strconv.Atoi(gatewayEnds[1])
}
@@ -134,7 +131,7 @@ func (cli *K8sDR) GetConns(ctx context.Context, serviceName string, opts ...grpc
// This conditional checks if the serviceName is not the OpenImMessageGatewayName.
// It seems to handle a special case for the OpenImMessageGateway.
- if serviceName != config.Config.RpcRegisterName.OpenImMessageGatewayName {
+ if serviceName != cli.gatewayName {
// DialContext creates a client connection to the given target (serviceName) using the specified context.
// 'cli.options' are likely default or common options for all connections in this struct.
// 'opts...' allows for additional gRPC dial options to be passed and used.
@@ -149,7 +146,7 @@ func (cli *K8sDR) GetConns(ctx context.Context, serviceName string, opts ...grpc
// getMsgGatewayHost presumably retrieves hosts for the message gateway service.
// The context is passed, likely for cancellation and timeout control.
- gatewayHosts := getMsgGatewayHost(ctx)
+ gatewayHosts := getMsgGatewayHost(ctx, cli.gatewayName)
// Iterating over the retrieved gateway hosts.
for _, host := range gatewayHosts {
@@ -194,5 +191,5 @@ func (cli *K8sDR) GetClientLocalConns() map[string][]*grpc.ClientConn {
return nil
}
func (cli *K8sDR) Close() {
- return
+
}
diff --git a/pkg/common/discoveryregister/zookeeper/zookeeper.go b/pkg/common/discoveryregister/zookeeper/zookeeper.go
index db1a5c6c4..0aa40a907 100644
--- a/pkg/common/discoveryregister/zookeeper/zookeeper.go
+++ b/pkg/common/discoveryregister/zookeeper/zookeeper.go
@@ -15,25 +15,26 @@
package zookeeper
import (
+ "fmt"
"os"
"strings"
"time"
"github.com/OpenIMSDK/tools/discoveryregistry"
openkeeper "github.com/OpenIMSDK/tools/discoveryregistry/zookeeper"
+ "github.com/OpenIMSDK/tools/errs"
"github.com/OpenIMSDK/tools/log"
-
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
)
// NewZookeeperDiscoveryRegister creates a new instance of ZookeeperDR for Zookeeper service discovery and registration.
-func NewZookeeperDiscoveryRegister() (discoveryregistry.SvcDiscoveryRegistry, error) {
- schema := getEnv("ZOOKEEPER_SCHEMA", config.Config.Zookeeper.Schema)
- zkAddr := getZkAddrFromEnv(config.Config.Zookeeper.ZkAddr)
- username := getEnv("ZOOKEEPER_USERNAME", config.Config.Zookeeper.Username)
- password := getEnv("ZOOKEEPER_PASSWORD", config.Config.Zookeeper.Password)
+func NewZookeeperDiscoveryRegister(config *config.GlobalConfig) (discoveryregistry.SvcDiscoveryRegistry, error) {
+ schema := getEnv("ZOOKEEPER_SCHEMA", config.Zookeeper.Schema)
+ zkAddr := getZkAddrFromEnv(config.Zookeeper.ZkAddr)
+ username := getEnv("ZOOKEEPER_USERNAME", config.Zookeeper.Username)
+ password := getEnv("ZOOKEEPER_PASSWORD", config.Zookeeper.Password)
- return openkeeper.NewClient(
+ zk, err := openkeeper.NewClient(
zkAddr,
schema,
openkeeper.WithFreq(time.Hour),
@@ -42,6 +43,16 @@ func NewZookeeperDiscoveryRegister() (discoveryregistry.SvcDiscoveryRegistry, er
openkeeper.WithTimeout(10),
openkeeper.WithLogger(log.NewZkLogger()),
)
+ if err != nil {
+ uriFormat := "address:%s, username:%s, password:%s, schema:%s."
+ errInfo := fmt.Sprintf(uriFormat,
+ config.Zookeeper.ZkAddr,
+ config.Zookeeper.Username,
+ config.Zookeeper.Password,
+ 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.
diff --git a/pkg/common/ginprometheus/ginprometheus.go b/pkg/common/ginprometheus/ginprometheus.go
index 1ee8f8e34..c2e6bdcca 100644
--- a/pkg/common/ginprometheus/ginprometheus.go
+++ b/pkg/common/ginprometheus/ginprometheus.go
@@ -197,30 +197,32 @@ func (p *Prometheus) SetListenAddressWithRouter(listenAddress string, r *gin.Eng
}
// SetMetricsPath set metrics paths.
-func (p *Prometheus) SetMetricsPath(e *gin.Engine) {
+func (p *Prometheus) SetMetricsPath(e *gin.Engine) error {
if p.listenAddress != "" {
p.router.GET(p.MetricsPath, prometheusHandler())
- p.runServer()
+ return p.runServer()
} else {
e.GET(p.MetricsPath, prometheusHandler())
+ return nil
}
}
// SetMetricsPathWithAuth set metrics paths with authentication.
-func (p *Prometheus) SetMetricsPathWithAuth(e *gin.Engine, accounts gin.Accounts) {
+func (p *Prometheus) SetMetricsPathWithAuth(e *gin.Engine, accounts gin.Accounts) error {
if p.listenAddress != "" {
p.router.GET(p.MetricsPath, gin.BasicAuth(accounts), prometheusHandler())
- p.runServer()
+ return p.runServer()
} else {
e.GET(p.MetricsPath, gin.BasicAuth(accounts), prometheusHandler())
+ return nil
}
}
-func (p *Prometheus) runServer() {
- go p.router.Run(p.listenAddress)
+func (p *Prometheus) runServer() error {
+ return p.router.Run(p.listenAddress)
}
func (p *Prometheus) getMetrics() []byte {
@@ -366,15 +368,15 @@ func (p *Prometheus) registerMetrics(subsystem string) {
}
// Use adds the middleware to a gin engine.
-func (p *Prometheus) Use(e *gin.Engine) {
+func (p *Prometheus) Use(e *gin.Engine) error {
e.Use(p.HandlerFunc())
- p.SetMetricsPath(e)
+ return p.SetMetricsPath(e)
}
// UseWithAuth adds the middleware to a gin engine with BasicAuth.
-func (p *Prometheus) UseWithAuth(e *gin.Engine, accounts gin.Accounts) {
+func (p *Prometheus) UseWithAuth(e *gin.Engine, accounts gin.Accounts) error {
e.Use(p.HandlerFunc())
- p.SetMetricsPathWithAuth(e, accounts)
+ return p.SetMetricsPathWithAuth(e, accounts)
}
// HandlerFunc defines handler function for middleware.
diff --git a/pkg/common/http/http_client.go b/pkg/common/http/http_client.go
index a80d1c9a4..83908b8d3 100644
--- a/pkg/common/http/http_client.go
+++ b/pkg/common/http/http_client.go
@@ -25,7 +25,6 @@ import (
"github.com/OpenIMSDK/protocol/constant"
"github.com/OpenIMSDK/tools/errs"
"github.com/OpenIMSDK/tools/log"
-
"github.com/openimsdk/open-im-server/v3/pkg/callbackstruct"
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
)
@@ -66,12 +65,12 @@ func Post(ctx context.Context, url string, header map[string]string, data any, t
jsonStr, err := json.Marshal(data)
if err != nil {
- return nil, err
+ return nil, errs.Wrap(err, "Post: JSON marshal failed")
}
req, err := http.NewRequestWithContext(ctx, http.MethodPost, url, bytes.NewBuffer(jsonStr))
if err != nil {
- return nil, err
+ return nil, errs.Wrap(err, "Post: NewRequestWithContext failed")
}
if operationID, _ := ctx.Value(constant.OperationID).(string); operationID != "" {
@@ -84,13 +83,13 @@ func Post(ctx context.Context, url string, header map[string]string, data any, t
resp, err := client.Do(req)
if err != nil {
- return nil, err
+ return nil, errs.Wrap(err, "Post: client.Do failed")
}
defer resp.Body.Close()
result, err := io.ReadAll(resp.Body)
if err != nil {
- return nil, err
+ return nil, errs.Wrap(err, "Post: ReadAll failed")
}
return result, nil
@@ -102,35 +101,37 @@ func PostReturn(ctx context.Context, url string, header map[string]string, input
return err
}
err = json.Unmarshal(b, output)
- return err
+ if err != nil {
+ return errs.Wrap(err, "PostReturn: JSON unmarshal failed")
+ }
+ return nil
}
func callBackPostReturn(ctx context.Context, url, command string, input interface{}, output callbackstruct.CallbackResp, callbackConfig config.CallBackConfig) error {
- defer log.ZDebug(ctx, "callback", "url", url, "command", command, "input", input, "output", output, "callbackConfig", callbackConfig)
- //
- //v := urllib.Values{}
- //v.Set(constant.CallbackCommand, command)
- //url = url + "/" + v.Encode()
url = url + "/" + command
+ log.ZInfo(ctx, "callback", "url", url, "input", input, "config", callbackConfig)
b, err := Post(ctx, url, nil, input, callbackConfig.CallbackTimeOut)
if err != nil {
if callbackConfig.CallbackFailedContinue != nil && *callbackConfig.CallbackFailedContinue {
- log.ZWarn(ctx, "callback failed but continue", err, "url", url)
+ log.ZInfo(ctx, "callback failed but continue", err, "url", url)
return nil
}
+ log.ZWarn(ctx, "callback network failed", err, "url", url, "input", input)
return errs.ErrNetwork.Wrap(err.Error())
}
- defer log.ZDebug(ctx, "callback", "data", string(b))
-
if err = json.Unmarshal(b, output); err != nil {
if callbackConfig.CallbackFailedContinue != nil && *callbackConfig.CallbackFailedContinue {
log.ZWarn(ctx, "callback failed but continue", err, "url", url)
return nil
}
+ log.ZWarn(ctx, "callback json unmarshal failed", err, "url", url, "input", input, "response", string(b))
return errs.ErrData.WithDetail(err.Error() + "response format error")
}
-
- return output.Parse()
+ if err := output.Parse(); err != nil {
+ log.ZWarn(ctx, "callback parse failed", err, "url", url, "input", input, "response", string(b))
+ }
+ log.ZInfo(ctx, "callback success", "url", url, "input", input, "response", string(b))
+ return nil
}
func CallBackPostReturn(ctx context.Context, url string, req callbackstruct.CallbackReq, resp callbackstruct.CallbackResp, callbackConfig config.CallBackConfig) error {
diff --git a/pkg/common/kafka/consumer.go b/pkg/common/kafka/consumer.go
index 98adfdcf1..6627c21ae 100644
--- a/pkg/common/kafka/consumer.go
+++ b/pkg/common/kafka/consumer.go
@@ -17,9 +17,9 @@ package kafka
import (
"sync"
- "github.com/openimsdk/open-im-server/v3/pkg/common/config"
-
"github.com/IBM/sarama"
+ "github.com/OpenIMSDK/tools/errs"
+ "github.com/openimsdk/open-im-server/v3/pkg/common/config"
)
type Consumer struct {
@@ -30,28 +30,42 @@ type Consumer struct {
Consumer sarama.Consumer
}
-func NewKafkaConsumer(addr []string, topic string) *Consumer {
+func NewKafkaConsumer(addr []string, topic string, config *config.GlobalConfig) (*Consumer, error) {
p := Consumer{}
p.Topic = topic
p.addr = addr
consumerConfig := sarama.NewConfig()
- if config.Config.Kafka.Username != "" && config.Config.Kafka.Password != "" {
+ if config.Kafka.Username != "" && config.Kafka.Password != "" {
consumerConfig.Net.SASL.Enable = true
- consumerConfig.Net.SASL.User = config.Config.Kafka.Username
- consumerConfig.Net.SASL.Password = config.Config.Kafka.Password
+ consumerConfig.Net.SASL.User = config.Kafka.Username
+ consumerConfig.Net.SASL.Password = config.Kafka.Password
+ }
+ var tlsConfig *TLSConfig
+ if config.Kafka.TLS != nil {
+ tlsConfig = &TLSConfig{
+ CACrt: config.Kafka.TLS.CACrt,
+ ClientCrt: config.Kafka.TLS.ClientCrt,
+ ClientKey: config.Kafka.TLS.ClientKey,
+ ClientKeyPwd: config.Kafka.TLS.ClientKeyPwd,
+ InsecureSkipVerify: false,
+ }
+ }
+ err := SetupTLSConfig(consumerConfig, tlsConfig)
+ if err != nil {
+ return nil, err
}
- SetupTLSConfig(consumerConfig)
consumer, err := sarama.NewConsumer(p.addr, consumerConfig)
if err != nil {
- panic(err.Error())
+ return nil, errs.Wrap(err, "NewKafkaConsumer: creating consumer failed")
}
p.Consumer = consumer
partitionList, err := consumer.Partitions(p.Topic)
if err != nil {
- panic(err.Error())
+ return nil, errs.Wrap(err, "NewKafkaConsumer: getting partitions failed")
}
p.PartitionList = partitionList
- return &p
+ return &p, nil
+
}
diff --git a/pkg/common/kafka/consumer_group.go b/pkg/common/kafka/consumer_group.go
index 1eb7b522a..95794aacb 100644
--- a/pkg/common/kafka/consumer_group.go
+++ b/pkg/common/kafka/consumer_group.go
@@ -16,12 +16,12 @@ package kafka
import (
"context"
-
- "github.com/OpenIMSDK/tools/log"
-
- "github.com/openimsdk/open-im-server/v3/pkg/common/config"
+ "errors"
+ "strings"
"github.com/IBM/sarama"
+ "github.com/OpenIMSDK/tools/errs"
+ "github.com/OpenIMSDK/tools/log"
)
type MConsumerGroup struct {
@@ -34,41 +34,54 @@ type MConsumerGroupConfig struct {
KafkaVersion sarama.KafkaVersion
OffsetsInitial int64
IsReturnErr bool
+ UserName string
+ Password string
}
-func NewMConsumerGroup(consumerConfig *MConsumerGroupConfig, topics, addrs []string, groupID string) *MConsumerGroup {
+func NewMConsumerGroup(consumerConfig *MConsumerGroupConfig, topics, addrs []string, groupID string, tlsConfig *TLSConfig) (*MConsumerGroup, error) {
consumerGroupConfig := sarama.NewConfig()
consumerGroupConfig.Version = consumerConfig.KafkaVersion
consumerGroupConfig.Consumer.Offsets.Initial = consumerConfig.OffsetsInitial
consumerGroupConfig.Consumer.Return.Errors = consumerConfig.IsReturnErr
- if config.Config.Kafka.Username != "" && config.Config.Kafka.Password != "" {
+ if consumerConfig.UserName != "" && consumerConfig.Password != "" {
consumerGroupConfig.Net.SASL.Enable = true
- consumerGroupConfig.Net.SASL.User = config.Config.Kafka.Username
- consumerGroupConfig.Net.SASL.Password = config.Config.Kafka.Password
+ consumerGroupConfig.Net.SASL.User = consumerConfig.UserName
+ consumerGroupConfig.Net.SASL.Password = consumerConfig.Password
}
- SetupTLSConfig(consumerGroupConfig)
+
+ SetupTLSConfig(consumerGroupConfig, tlsConfig)
consumerGroup, err := sarama.NewConsumerGroup(addrs, groupID, consumerGroupConfig)
if err != nil {
- panic(err.Error())
+ return nil, errs.Wrap(err, strings.Join(topics, ","), strings.Join(addrs, ","), groupID, consumerConfig.UserName, consumerConfig.Password)
}
+
return &MConsumerGroup{
consumerGroup,
groupID,
topics,
- }
+ }, nil
}
func (mc *MConsumerGroup) GetContextFromMsg(cMsg *sarama.ConsumerMessage) context.Context {
return GetContextWithMQHeader(cMsg.Headers)
}
-func (mc *MConsumerGroup) RegisterHandleAndConsumer(handler sarama.ConsumerGroupHandler) {
- log.ZDebug(context.Background(), "register consumer group", "groupID", mc.groupID)
- ctx := context.Background()
+func (mc *MConsumerGroup) RegisterHandleAndConsumer(ctx context.Context, handler sarama.ConsumerGroupHandler) {
+ log.ZDebug(ctx, "register consumer group", "groupID", mc.groupID)
for {
err := mc.ConsumerGroup.Consume(ctx, mc.topics, handler)
+ if errors.Is(err, sarama.ErrClosedConsumerGroup) {
+ return
+ }
+ if errors.Is(err, context.Canceled) {
+ return
+ }
if err != nil {
- panic(err.Error())
+ log.ZWarn(ctx, "consume err", err, "topic", mc.topics, "groupID", mc.groupID)
}
}
}
+
+func (mc *MConsumerGroup) Close() error {
+ return mc.ConsumerGroup.Close()
+}
diff --git a/pkg/common/kafka/producer.go b/pkg/common/kafka/producer.go
index 06b1e2b4c..8ee938b51 100644
--- a/pkg/common/kafka/producer.go
+++ b/pkg/common/kafka/producer.go
@@ -18,17 +18,16 @@ import (
"bytes"
"context"
"errors"
+ "fmt"
"strings"
"time"
"github.com/IBM/sarama"
"github.com/OpenIMSDK/protocol/constant"
+ "github.com/OpenIMSDK/tools/errs"
"github.com/OpenIMSDK/tools/log"
"github.com/OpenIMSDK/tools/mcontext"
- "github.com/OpenIMSDK/tools/utils"
"google.golang.org/protobuf/proto"
-
- "github.com/openimsdk/open-im-server/v3/pkg/common/config"
)
const maxRetry = 10 // number of retries
@@ -43,8 +42,15 @@ type Producer struct {
producer sarama.SyncProducer
}
+type ProducerConfig struct {
+ ProducerAck string
+ CompressType string
+ Username string
+ Password string
+}
+
// NewKafkaProducer initializes a new Kafka producer.
-func NewKafkaProducer(addr []string, topic string) *Producer {
+func NewKafkaProducer(addr []string, topic string, producerConfig *ProducerConfig, tlsConfig *TLSConfig) (*Producer, error) {
p := Producer{
addr: addr,
topic: topic,
@@ -59,14 +65,14 @@ func NewKafkaProducer(addr []string, topic string) *Producer {
p.config.Producer.Partitioner = sarama.NewHashPartitioner
// Configure producer acknowledgement level
- configureProducerAck(&p, config.Config.Kafka.ProducerAck)
+ configureProducerAck(&p, producerConfig.ProducerAck)
// Configure message compression
- configureCompression(&p, config.Config.Kafka.CompressType)
+ configureCompression(&p, producerConfig.CompressType)
// Get Kafka configuration from environment variables or fallback to config file
- kafkaUsername := getEnvOrConfig("KAFKA_USERNAME", config.Config.Kafka.Username)
- kafkaPassword := getEnvOrConfig("KAFKA_PASSWORD", config.Config.Kafka.Password)
+ kafkaUsername := getEnvOrConfig("KAFKA_USERNAME", producerConfig.Username)
+ kafkaPassword := getEnvOrConfig("KAFKA_PASSWORD", producerConfig.Password)
kafkaAddr := getKafkaAddrFromEnv(addr) // Updated to use the new function
// Configure SASL authentication if credentials are provided
@@ -80,24 +86,23 @@ func NewKafkaProducer(addr []string, topic string) *Producer {
p.addr = kafkaAddr
// Set up TLS configuration (if required)
- SetupTLSConfig(p.config)
+ SetupTLSConfig(p.config, tlsConfig)
// Create the producer with retries
var err error
for i := 0; i <= maxRetry; i++ {
p.producer, err = sarama.NewSyncProducer(p.addr, p.config)
if err == nil {
- return &p
+ return &p, errs.Wrap(err)
}
time.Sleep(1 * time.Second) // Wait before retrying
}
-
// Panic if unable to create producer after retries
if err != nil {
- panic("Failed to create Kafka producer: " + err.Error())
+ return nil, errs.Wrap(errors.New("failed to create Kafka producer: " + err.Error()))
}
- return &p
+ return &p, nil
}
// configureProducerAck configures the producer's acknowledgement level.
@@ -116,8 +121,12 @@ func configureProducerAck(p *Producer, ackConfig string) {
// configureCompression configures the message compression type for the producer.
func configureCompression(p *Producer, compressType string) {
- var compress sarama.CompressionCodec = sarama.CompressionNone
- compress.UnmarshalText(bytes.ToLower([]byte(compressType)))
+ var compress = sarama.CompressionNone
+ err := compress.UnmarshalText(bytes.ToLower([]byte(compressType)))
+ if err != nil {
+ fmt.Printf("Failed to configure compression: %v\n", err)
+ return
+ }
p.config.Producer.Compression = compress
}
@@ -151,10 +160,10 @@ func (p *Producer) SendMessage(ctx context.Context, key string, msg proto.Messag
// Marshal the protobuf message
bMsg, err := proto.Marshal(msg)
if err != nil {
- return 0, 0, utils.Wrap(err, "kafka proto Marshal err")
+ return 0, 0, errs.Wrap(err, "kafka proto Marshal err")
}
if len(bMsg) == 0 {
- return 0, 0, utils.Wrap(errEmptyMsg, "")
+ return 0, 0, errs.Wrap(errEmptyMsg, "")
}
// Prepare Kafka message
@@ -166,13 +175,13 @@ func (p *Producer) SendMessage(ctx context.Context, key string, msg proto.Messag
// Validate message key and value
if kMsg.Key.Length() == 0 || kMsg.Value.Length() == 0 {
- return 0, 0, utils.Wrap(errEmptyMsg, "")
+ return 0, 0, errs.Wrap(errEmptyMsg)
}
// Attach context metadata as headers
header, err := GetMQHeaderWithContext(ctx)
if err != nil {
- return 0, 0, utils.Wrap(err, "")
+ return 0, 0, err
}
kMsg.Headers = header
@@ -180,7 +189,7 @@ func (p *Producer) SendMessage(ctx context.Context, key string, msg proto.Messag
partition, offset, err := p.producer.SendMessage(kMsg)
if err != nil {
log.ZWarn(ctx, "p.producer.SendMessage error", err)
- return 0, 0, utils.Wrap(err, "")
+ return 0, 0, errs.Wrap(err)
}
log.ZDebug(ctx, "ByteEncoder SendMessage end", "key", kMsg.Key, "key length", kMsg.Value.Length())
diff --git a/pkg/common/kafka/util.go b/pkg/common/kafka/util.go
index f318ecf73..4e2a02714 100644
--- a/pkg/common/kafka/util.go
+++ b/pkg/common/kafka/util.go
@@ -20,22 +20,34 @@ import (
"strings"
"github.com/IBM/sarama"
-
- "github.com/openimsdk/open-im-server/v3/pkg/common/config"
"github.com/openimsdk/open-im-server/v3/pkg/common/tls"
)
+type TLSConfig struct {
+ CACrt string
+ ClientCrt string
+ ClientKey string
+ ClientKeyPwd string
+ InsecureSkipVerify bool
+}
+
// SetupTLSConfig set up the TLS config from config file.
-func SetupTLSConfig(cfg *sarama.Config) {
- if config.Config.Kafka.TLS != nil {
+func SetupTLSConfig(cfg *sarama.Config, tlsConfig *TLSConfig) error {
+ if tlsConfig != nil {
cfg.Net.TLS.Enable = true
- cfg.Net.TLS.Config = tls.NewTLSConfig(
- config.Config.Kafka.TLS.ClientCrt,
- config.Config.Kafka.TLS.ClientKey,
- config.Config.Kafka.TLS.CACrt,
- []byte(config.Config.Kafka.TLS.ClientKeyPwd),
+ tlsConfig, err := tls.NewTLSConfig(
+ tlsConfig.ClientCrt,
+ tlsConfig.ClientKey,
+ tlsConfig.CACrt,
+ []byte(tlsConfig.ClientKeyPwd),
+ tlsConfig.InsecureSkipVerify,
)
+ if err != nil {
+ return err
+ }
+ cfg.Net.TLS.Config = tlsConfig
}
+ return nil
}
// getEnvOrConfig returns the value of the environment variable if it exists,
diff --git a/pkg/common/prommetrics/prommetrics.go b/pkg/common/prommetrics/prommetrics.go
index b7c5e07f4..9089e7b5f 100644
--- a/pkg/common/prommetrics/prommetrics.go
+++ b/pkg/common/prommetrics/prommetrics.go
@@ -16,15 +16,13 @@ package prommetrics
import (
gp "github.com/grpc-ecosystem/go-grpc-prometheus"
- "github.com/prometheus/client_golang/prometheus"
- "github.com/prometheus/client_golang/prometheus/collectors"
-
config2 "github.com/openimsdk/open-im-server/v3/pkg/common/config"
"github.com/openimsdk/open-im-server/v3/pkg/common/ginprometheus"
+ "github.com/prometheus/client_golang/prometheus"
+ "github.com/prometheus/client_golang/prometheus/collectors"
)
func NewGrpcPromObj(cusMetrics []prometheus.Collector) (*prometheus.Registry, *gp.ServerMetrics, error) {
- ////////////////////////////////////////////////////////
reg := prometheus.NewRegistry()
grpcMetrics := gp.NewServerMetrics()
grpcMetrics.EnableHandlingTimeHistogram()
@@ -33,17 +31,17 @@ func NewGrpcPromObj(cusMetrics []prometheus.Collector) (*prometheus.Registry, *g
return reg, grpcMetrics, nil
}
-func GetGrpcCusMetrics(registerName string) []prometheus.Collector {
+func GetGrpcCusMetrics(registerName string, config *config2.GlobalConfig) []prometheus.Collector {
switch registerName {
- case config2.Config.RpcRegisterName.OpenImMessageGatewayName:
+ case config.RpcRegisterName.OpenImMessageGatewayName:
return []prometheus.Collector{OnlineUserGauge}
- case config2.Config.RpcRegisterName.OpenImMsgName:
+ case config.RpcRegisterName.OpenImMsgName:
return []prometheus.Collector{SingleChatMsgProcessSuccessCounter, SingleChatMsgProcessFailedCounter, GroupChatMsgProcessSuccessCounter, GroupChatMsgProcessFailedCounter}
case "Transfer":
return []prometheus.Collector{MsgInsertRedisSuccessCounter, MsgInsertRedisFailedCounter, MsgInsertMongoSuccessCounter, MsgInsertMongoFailedCounter, SeqSetFailedCounter}
- case config2.Config.RpcRegisterName.OpenImPushName:
+ case config.RpcRegisterName.OpenImPushName:
return []prometheus.Collector{MsgOfflinePushFailedCounter}
- case config2.Config.RpcRegisterName.OpenImAuthName:
+ case config.RpcRegisterName.OpenImAuthName:
return []prometheus.Collector{UserLoginCounter}
default:
return nil
diff --git a/pkg/common/prommetrics/prommetrics_test.go b/pkg/common/prommetrics/prommetrics_test.go
index 1e48c63ba..eb6f3c771 100644
--- a/pkg/common/prommetrics/prommetrics_test.go
+++ b/pkg/common/prommetrics/prommetrics_test.go
@@ -58,17 +58,20 @@ func TestNewGrpcPromObj(t *testing.T) {
}
func TestGetGrpcCusMetrics(t *testing.T) {
+ conf := config2.NewGlobalConfig()
+
+ config2.InitConfig(conf, "../../config")
// Test various cases based on the switch statement in the GetGrpcCusMetrics function.
testCases := []struct {
name string
expected int // The expected number of metrics for each case.
}{
- {config2.Config.RpcRegisterName.OpenImMessageGatewayName, 1},
+ {conf.RpcRegisterName.OpenImMessageGatewayName, 1},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
- metrics := GetGrpcCusMetrics(tc.name)
+ metrics := GetGrpcCusMetrics(tc.name, conf)
assert.Len(t, metrics, tc.expected)
})
}
diff --git a/pkg/common/startrpc/start.go b/pkg/common/startrpc/start.go
index 8295404d3..bf95509d1 100644
--- a/pkg/common/startrpc/start.go
+++ b/pkg/common/startrpc/start.go
@@ -15,9 +15,9 @@
package startrpc
import (
+ "context"
"errors"
"fmt"
- "log"
"net"
"net/http"
"os"
@@ -27,23 +27,20 @@ import (
"syscall"
"time"
- "github.com/prometheus/client_golang/prometheus"
- "github.com/prometheus/client_golang/prometheus/promhttp"
- "golang.org/x/sync/errgroup"
-
- "github.com/openimsdk/open-im-server/v3/pkg/common/config"
- "github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics"
-
- grpcprometheus "github.com/grpc-ecosystem/go-grpc-prometheus"
- "google.golang.org/grpc"
- "google.golang.org/grpc/credentials/insecure"
-
- kdisc "github.com/openimsdk/open-im-server/v3/pkg/common/discoveryregister"
-
"github.com/OpenIMSDK/tools/discoveryregistry"
+ "github.com/OpenIMSDK/tools/errs"
"github.com/OpenIMSDK/tools/mw"
"github.com/OpenIMSDK/tools/network"
- "github.com/OpenIMSDK/tools/utils"
+ grpcprometheus "github.com/grpc-ecosystem/go-grpc-prometheus"
+ "github.com/openimsdk/open-im-server/v3/pkg/common/config"
+ config2 "github.com/openimsdk/open-im-server/v3/pkg/common/config"
+ kdisc "github.com/openimsdk/open-im-server/v3/pkg/common/discoveryregister"
+ "github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics"
+ util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil"
+ "github.com/prometheus/client_golang/prometheus"
+ "github.com/prometheus/client_golang/prometheus/promhttp"
+ "google.golang.org/grpc"
+ "google.golang.org/grpc/credentials/insecure"
)
// Start rpc server.
@@ -51,36 +48,38 @@ func Start(
rpcPort int,
rpcRegisterName string,
prometheusPort int,
- rpcFn func(client discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) error,
+ config *config2.GlobalConfig,
+ rpcFn func(config *config.GlobalConfig, client discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) error,
options ...grpc.ServerOption,
) error {
fmt.Printf("start %s server, port: %d, prometheusPort: %d, OpenIM version: %s\n",
- rpcRegisterName, rpcPort, prometheusPort, config.Version)
+ rpcRegisterName, rpcPort, prometheusPort, config2.Version)
+ rpcTcpAddr := net.JoinHostPort(network.GetListenIP(config.Rpc.ListenIP), strconv.Itoa(rpcPort))
listener, err := net.Listen(
"tcp",
- net.JoinHostPort(network.GetListenIP(config.Config.Rpc.ListenIP), strconv.Itoa(rpcPort)),
+ rpcTcpAddr,
)
if err != nil {
- return err
+ return errs.Wrap(err, "listen err", rpcTcpAddr)
}
defer listener.Close()
- client, err := kdisc.NewDiscoveryRegister(config.Config.Envs.Discovery)
+ client, err := kdisc.NewDiscoveryRegister(config)
if err != nil {
- return utils.Wrap1(err)
+ return err
}
defer client.Close()
client.AddOption(mw.GrpcClient(), grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithDefaultServiceConfig(fmt.Sprintf(`{"LoadBalancingPolicy": "%s"}`, "round_robin")))
- registerIP, err := network.GetRpcRegisterIP(config.Config.Rpc.RegisterIP)
+ registerIP, err := network.GetRpcRegisterIP(config.Rpc.RegisterIP)
if err != nil {
- return err
+ return errs.Wrap(err)
}
var reg *prometheus.Registry
var metric *grpcprometheus.ServerMetrics
- if config.Config.Prometheus.Enable {
- cusMetrics := prommetrics.GetGrpcCusMetrics(rpcRegisterName)
+ if config.Prometheus.Enable {
+ cusMetrics := prommetrics.GetGrpcCusMetrics(rpcRegisterName, config)
reg, metric, _ = prommetrics.NewGrpcPromObj(cusMetrics)
options = append(options, mw.GrpcServer(), grpc.StreamInterceptor(metric.StreamServerInterceptor()),
grpc.UnaryInterceptor(metric.UnaryServerInterceptor()))
@@ -94,9 +93,9 @@ func Start(
once.Do(srv.GracefulStop)
}()
- err = rpcFn(client, srv)
+ err = rpcFn(config, client, srv)
if err != nil {
- return utils.Wrap1(err)
+ return err
}
err = client.Register(
rpcRegisterName,
@@ -105,48 +104,67 @@ func Start(
grpc.WithTransportCredentials(insecure.NewCredentials()),
)
if err != nil {
- return utils.Wrap1(err)
+ return errs.Wrap(err)
}
- var wg errgroup.Group
-
- wg.Go(func() error {
- if config.Config.Prometheus.Enable && prometheusPort != 0 {
- metric.InitializeMetrics(srv)
- // Create a HTTP server for prometheus.
- httpServer := &http.Server{Handler: promhttp.HandlerFor(reg, promhttp.HandlerOpts{}), Addr: fmt.Sprintf("0.0.0.0:%d", prometheusPort)}
- if err := httpServer.ListenAndServe(); err != nil {
- log.Fatal("Unable to start a http server.")
- }
- }
- return nil
- })
-
- wg.Go(func() error {
- return utils.Wrap1(srv.Serve(listener))
- })
-
- sigs := make(chan os.Signal, 1)
- signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)
- <-sigs
-
var (
- done = make(chan struct{}, 1)
- gerr error
+ netDone = make(chan struct{}, 2)
+ netErr error
+ httpServer *http.Server
)
-
go func() {
- once.Do(srv.GracefulStop)
- gerr = wg.Wait()
- close(done)
+ if config.Prometheus.Enable && prometheusPort != 0 {
+ metric.InitializeMetrics(srv)
+ // Create a HTTP server for prometheus.
+ httpServer = &http.Server{Handler: promhttp.HandlerFor(reg, promhttp.HandlerOpts{}), Addr: fmt.Sprintf("0.0.0.0:%d", prometheusPort)}
+ if err := httpServer.ListenAndServe(); err != nil && err != http.ErrServerClosed {
+ netErr = errs.Wrap(err, "prometheus start err", httpServer.Addr)
+ netDone <- struct{}{}
+ }
+ }
}()
+ go func() {
+ err := srv.Serve(listener)
+ if err != nil {
+ netErr = errs.Wrap(err, "rpc start err: ", rpcTcpAddr)
+ netDone <- struct{}{}
+ }
+ }()
+
+ sigs := make(chan os.Signal, 1)
+ signal.Notify(sigs, syscall.SIGTERM)
select {
- case <-done:
- return gerr
-
- case <-time.After(15 * time.Second):
- return utils.Wrap1(errors.New("timeout exit"))
+ case <-sigs:
+ util.SIGTERMExit()
+ ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
+ defer cancel()
+ if err := gracefulStopWithCtx(ctx, srv.GracefulStop); err != nil {
+ return err
+ }
+ ctx, cancel = context.WithTimeout(context.Background(), 15*time.Second)
+ defer cancel()
+ err := httpServer.Shutdown(ctx)
+ if err != nil {
+ return errs.Wrap(err, "shutdown err")
+ }
+ return nil
+ case <-netDone:
+ close(netDone)
+ return netErr
+ }
+}
+
+func gracefulStopWithCtx(ctx context.Context, f func()) error {
+ done := make(chan struct{}, 1)
+ go func() {
+ f()
+ close(done)
+ }()
+ select {
+ case <-ctx.Done():
+ return errs.Wrap(errors.New("timeout, ctx graceful stop"))
+ case <-done:
+ return nil
}
-
}
diff --git a/pkg/common/startrpc/start_test.go b/pkg/common/startrpc/start_test.go
index 481986e15..754fc9c50 100644
--- a/pkg/common/startrpc/start_test.go
+++ b/pkg/common/startrpc/start_test.go
@@ -20,12 +20,14 @@ import (
"testing"
"time"
+ "github.com/openimsdk/open-im-server/v3/pkg/common/config"
+
"github.com/OpenIMSDK/tools/discoveryregistry"
"google.golang.org/grpc"
)
// mockRpcFn is a mock gRPC function for testing.
-func mockRpcFn(client discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) error {
+func mockRpcFn(config *config.GlobalConfig, client discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) error {
// Implement a mock gRPC service registration logic if needed
return nil
}
@@ -40,7 +42,8 @@ func TestStart(t *testing.T) {
doneChan := make(chan error, 1)
go func() {
- err := Start(testRpcPort, testRpcRegisterName, testPrometheusPort, mockRpcFn)
+ err := Start(testRpcPort, testRpcRegisterName, testPrometheusPort,
+ config.NewGlobalConfig(), mockRpcFn)
doneChan <- err
}()
diff --git a/pkg/common/tls/tls.go b/pkg/common/tls/tls.go
index dba49e605..9666ed9c8 100755
--- a/pkg/common/tls/tls.go
+++ b/pkg/common/tls/tls.go
@@ -21,7 +21,7 @@ import (
"errors"
"os"
- "github.com/openimsdk/open-im-server/v3/pkg/common/config"
+ "github.com/OpenIMSDK/tools/errs"
)
// decryptPEM decrypts a PEM block using a password.
@@ -49,37 +49,40 @@ func readEncryptablePEMBlock(path string, pwd []byte) ([]byte, error) {
}
// NewTLSConfig setup the TLS config from general config file.
-func NewTLSConfig(clientCertFile, clientKeyFile, caCertFile string, keyPwd []byte) *tls.Config {
+func NewTLSConfig(clientCertFile, clientKeyFile, caCertFile string, keyPwd []byte, insecureSkipVerify bool) (*tls.Config, error) {
tlsConfig := tls.Config{}
if clientCertFile != "" && clientKeyFile != "" {
certPEMBlock, err := os.ReadFile(clientCertFile)
if err != nil {
- panic(err)
+ return nil, errs.Wrap(err, "NewTLSConfig: failed to read client cert file")
}
keyPEMBlock, err := readEncryptablePEMBlock(clientKeyFile, keyPwd)
if err != nil {
- panic(err)
+ return nil, err
}
+
cert, err := tls.X509KeyPair(certPEMBlock, keyPEMBlock)
if err != nil {
- panic(err)
+ return nil, errs.Wrap(err, "NewTLSConfig: failed to create X509 key pair")
}
tlsConfig.Certificates = []tls.Certificate{cert}
}
- caCert, err := os.ReadFile(caCertFile)
- if err != nil {
- panic(err)
- }
- caCertPool := x509.NewCertPool()
- ok := caCertPool.AppendCertsFromPEM(caCert)
- if !ok {
- panic(errors.New("not a valid CA cert"))
- }
- tlsConfig.RootCAs = caCertPool
+ if caCertFile != "" {
+ caCert, err := os.ReadFile(caCertFile)
+ if err != nil {
+ return nil, errs.Wrap(err, "NewTLSConfig: failed to read CA cert file")
+ }
- tlsConfig.InsecureSkipVerify = config.Config.Kafka.TLS.InsecureSkipVerify
+ caCertPool := x509.NewCertPool()
+ if ok := caCertPool.AppendCertsFromPEM(caCert); !ok {
+ return nil, errors.New("NewTLSConfig: not a valid CA cert")
+ }
+ tlsConfig.RootCAs = caCertPool
+ }
- return &tlsConfig
+ tlsConfig.InsecureSkipVerify = insecureSkipVerify
+
+ return &tlsConfig, nil
}
diff --git a/pkg/msgprocessor/conversation.go b/pkg/msgprocessor/conversation.go
index 7477bea7a..e3ea89fad 100644
--- a/pkg/msgprocessor/conversation.go
+++ b/pkg/msgprocessor/conversation.go
@@ -20,6 +20,7 @@ import (
"github.com/OpenIMSDK/protocol/constant"
"github.com/OpenIMSDK/protocol/sdkws"
+ "github.com/OpenIMSDK/tools/errs"
"google.golang.org/protobuf/proto"
)
@@ -188,7 +189,7 @@ func (s MsgBySeq) Swap(i, j int) {
func Pb2String(pb proto.Message) (string, error) {
s, err := proto.Marshal(pb)
if err != nil {
- return "", err
+ return "", errs.Wrap(err)
}
return string(s), nil
}
diff --git a/pkg/rpcclient/auth.go b/pkg/rpcclient/auth.go
index 0ee021de1..24597120f 100644
--- a/pkg/rpcclient/auth.go
+++ b/pkg/rpcclient/auth.go
@@ -17,25 +17,25 @@ package rpcclient
import (
"context"
- "google.golang.org/grpc"
-
"github.com/OpenIMSDK/protocol/auth"
"github.com/OpenIMSDK/tools/discoveryregistry"
-
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
+ util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil"
+ "google.golang.org/grpc"
)
-func NewAuth(discov discoveryregistry.SvcDiscoveryRegistry) *Auth {
- conn, err := discov.GetConn(context.Background(), config.Config.RpcRegisterName.OpenImAuthName)
+func NewAuth(discov discoveryregistry.SvcDiscoveryRegistry, config *config.GlobalConfig) *Auth {
+ conn, err := discov.GetConn(context.Background(), config.RpcRegisterName.OpenImAuthName)
if err != nil {
- panic(err)
+ util.ExitWithError(err)
}
client := auth.NewAuthClient(conn)
- return &Auth{discov: discov, conn: conn, Client: client}
+ return &Auth{discov: discov, conn: conn, Client: client, Config: config}
}
type Auth struct {
conn grpc.ClientConnInterface
Client auth.AuthClient
discov discoveryregistry.SvcDiscoveryRegistry
+ Config *config.GlobalConfig
}
diff --git a/pkg/rpcclient/conversation.go b/pkg/rpcclient/conversation.go
index 80053e870..127e029e1 100644
--- a/pkg/rpcclient/conversation.go
+++ b/pkg/rpcclient/conversation.go
@@ -18,34 +18,34 @@ import (
"context"
"fmt"
- "google.golang.org/grpc"
-
pbconversation "github.com/OpenIMSDK/protocol/conversation"
"github.com/OpenIMSDK/tools/discoveryregistry"
"github.com/OpenIMSDK/tools/errs"
-
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
+ util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil"
+ "google.golang.org/grpc"
)
type Conversation struct {
Client pbconversation.ConversationClient
conn grpc.ClientConnInterface
discov discoveryregistry.SvcDiscoveryRegistry
+ Config *config.GlobalConfig
}
-func NewConversation(discov discoveryregistry.SvcDiscoveryRegistry) *Conversation {
- conn, err := discov.GetConn(context.Background(), config.Config.RpcRegisterName.OpenImConversationName)
+func NewConversation(discov discoveryregistry.SvcDiscoveryRegistry, config *config.GlobalConfig) *Conversation {
+ conn, err := discov.GetConn(context.Background(), config.RpcRegisterName.OpenImConversationName)
if err != nil {
- panic(err)
+ util.ExitWithError(err)
}
client := pbconversation.NewConversationClient(conn)
- return &Conversation{discov: discov, conn: conn, Client: client}
+ return &Conversation{discov: discov, conn: conn, Client: client, Config: config}
}
type ConversationRpcClient Conversation
-func NewConversationRpcClient(discov discoveryregistry.SvcDiscoveryRegistry) ConversationRpcClient {
- return ConversationRpcClient(*NewConversation(discov))
+func NewConversationRpcClient(discov discoveryregistry.SvcDiscoveryRegistry, config *config.GlobalConfig) ConversationRpcClient {
+ return ConversationRpcClient(*NewConversation(discov, config))
}
func (c *ConversationRpcClient) GetSingleConversationRecvMsgOpt(ctx context.Context, userID, conversationID string) (int32, error) {
@@ -122,11 +122,7 @@ func (c *ConversationRpcClient) GetConversationOfflinePushUserIDs(ctx context.Co
return resp.UserIDs, nil
}
-func (c *ConversationRpcClient) GetConversations(
- ctx context.Context,
- ownerUserID string,
- conversationIDs []string,
-) ([]*pbconversation.Conversation, error) {
+func (c *ConversationRpcClient) GetConversations(ctx context.Context, ownerUserID string, conversationIDs []string) ([]*pbconversation.Conversation, error) {
if len(conversationIDs) == 0 {
return nil, nil
}
diff --git a/pkg/rpcclient/friend.go b/pkg/rpcclient/friend.go
index 7158ed569..5a5f38698 100644
--- a/pkg/rpcclient/friend.go
+++ b/pkg/rpcclient/friend.go
@@ -17,34 +17,34 @@ package rpcclient
import (
"context"
- "google.golang.org/grpc"
-
"github.com/OpenIMSDK/protocol/friend"
sdkws "github.com/OpenIMSDK/protocol/sdkws"
"github.com/OpenIMSDK/tools/discoveryregistry"
-
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
+ util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil"
+ "google.golang.org/grpc"
)
type Friend struct {
conn grpc.ClientConnInterface
Client friend.FriendClient
discov discoveryregistry.SvcDiscoveryRegistry
+ Config *config.GlobalConfig
}
-func NewFriend(discov discoveryregistry.SvcDiscoveryRegistry) *Friend {
- conn, err := discov.GetConn(context.Background(), config.Config.RpcRegisterName.OpenImFriendName)
+func NewFriend(discov discoveryregistry.SvcDiscoveryRegistry, config *config.GlobalConfig) *Friend {
+ conn, err := discov.GetConn(context.Background(), config.RpcRegisterName.OpenImFriendName)
if err != nil {
- panic(err)
+ util.ExitWithError(err)
}
client := friend.NewFriendClient(conn)
- return &Friend{discov: discov, conn: conn, Client: client}
+ return &Friend{discov: discov, conn: conn, Client: client, Config: config}
}
type FriendRpcClient Friend
-func NewFriendRpcClient(discov discoveryregistry.SvcDiscoveryRegistry) FriendRpcClient {
- return FriendRpcClient(*NewFriend(discov))
+func NewFriendRpcClient(discov discoveryregistry.SvcDiscoveryRegistry, config *config.GlobalConfig) FriendRpcClient {
+ return FriendRpcClient(*NewFriend(discov, config))
}
func (f *FriendRpcClient) GetFriendsInfo(
@@ -62,7 +62,7 @@ func (f *FriendRpcClient) GetFriendsInfo(
return
}
-// possibleFriendUserID是否在userID的好友中.
+// possibleFriendUserID Is PossibleFriendUserId's friends.
func (f *FriendRpcClient) IsFriend(ctx context.Context, possibleFriendUserID, userID string) (bool, error) {
resp, err := f.Client.IsFriend(ctx, &friend.IsFriendReq{UserID1: userID, UserID2: possibleFriendUserID})
if err != nil {
diff --git a/pkg/rpcclient/group.go b/pkg/rpcclient/group.go
index 98c8387e5..607ea74ed 100644
--- a/pkg/rpcclient/group.go
+++ b/pkg/rpcclient/group.go
@@ -24,27 +24,30 @@ import (
"github.com/OpenIMSDK/tools/discoveryregistry"
"github.com/OpenIMSDK/tools/errs"
"github.com/OpenIMSDK/tools/utils"
-
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
+ util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil"
+ "google.golang.org/grpc"
)
type Group struct {
Client group.GroupClient
+ discov discoveryregistry.SvcDiscoveryRegistry
+ Config *config.GlobalConfig
}
-func NewGroup(discov discoveryregistry.SvcDiscoveryRegistry) *Group {
- conn, err := discov.GetConn(context.Background(), config.Config.RpcRegisterName.OpenImGroupName)
+func NewGroup(discov discoveryregistry.SvcDiscoveryRegistry, config *config.GlobalConfig) *Group {
+ conn, err := discov.GetConn(context.Background(), config.RpcRegisterName.OpenImGroupName)
if err != nil {
- panic(err)
+ util.ExitWithError(err)
}
client := group.NewGroupClient(conn)
- return &Group{Client: client}
+ return &Group{discov: discov, conn: conn, Client: client, Config: config}
}
type GroupRpcClient Group
-func NewGroupRpcClient(discov discoveryregistry.SvcDiscoveryRegistry) GroupRpcClient {
- return GroupRpcClient(*NewGroup(discov))
+func NewGroupRpcClient(discov discoveryregistry.SvcDiscoveryRegistry, config *config.GlobalConfig) GroupRpcClient {
+ return GroupRpcClient(*NewGroup(discov, config))
}
func (g *GroupRpcClient) GetGroupInfos(
diff --git a/pkg/rpcclient/msg.go b/pkg/rpcclient/msg.go
index 56167d7f4..4daf897a1 100644
--- a/pkg/rpcclient/msg.go
+++ b/pkg/rpcclient/msg.go
@@ -17,9 +17,9 @@ package rpcclient
import (
"context"
"encoding/json"
-
- "google.golang.org/grpc"
- "google.golang.org/protobuf/proto"
+ "fmt"
+ "github.com/OpenIMSDK/tools/errs"
+ util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil"
"github.com/OpenIMSDK/protocol/constant"
"github.com/OpenIMSDK/protocol/msg"
@@ -27,52 +27,52 @@ import (
"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"
- // "google.golang.org/protobuf/proto".
+ "google.golang.org/grpc"
+ "google.golang.org/protobuf/proto"
)
-func newContentTypeConf() map[int32]config.NotificationConf {
+func newContentTypeConf(conf *config.GlobalConfig) map[int32]config.NotificationConf {
return map[int32]config.NotificationConf{
// group
- constant.GroupCreatedNotification: config.Config.Notification.GroupCreated,
- constant.GroupInfoSetNotification: config.Config.Notification.GroupInfoSet,
- constant.JoinGroupApplicationNotification: config.Config.Notification.JoinGroupApplication,
- constant.MemberQuitNotification: config.Config.Notification.MemberQuit,
- constant.GroupApplicationAcceptedNotification: config.Config.Notification.GroupApplicationAccepted,
- constant.GroupApplicationRejectedNotification: config.Config.Notification.GroupApplicationRejected,
- constant.GroupOwnerTransferredNotification: config.Config.Notification.GroupOwnerTransferred,
- constant.MemberKickedNotification: config.Config.Notification.MemberKicked,
- constant.MemberInvitedNotification: config.Config.Notification.MemberInvited,
- constant.MemberEnterNotification: config.Config.Notification.MemberEnter,
- constant.GroupDismissedNotification: config.Config.Notification.GroupDismissed,
- constant.GroupMutedNotification: config.Config.Notification.GroupMuted,
- constant.GroupCancelMutedNotification: config.Config.Notification.GroupCancelMuted,
- constant.GroupMemberMutedNotification: config.Config.Notification.GroupMemberMuted,
- constant.GroupMemberCancelMutedNotification: config.Config.Notification.GroupMemberCancelMuted,
- constant.GroupMemberInfoSetNotification: config.Config.Notification.GroupMemberInfoSet,
- constant.GroupMemberSetToAdminNotification: config.Config.Notification.GroupMemberSetToAdmin,
- constant.GroupMemberSetToOrdinaryUserNotification: config.Config.Notification.GroupMemberSetToOrdinary,
- constant.GroupInfoSetAnnouncementNotification: config.Config.Notification.GroupInfoSetAnnouncement,
- constant.GroupInfoSetNameNotification: config.Config.Notification.GroupInfoSetName,
+ constant.GroupCreatedNotification: conf.Notification.GroupCreated,
+ constant.GroupInfoSetNotification: conf.Notification.GroupInfoSet,
+ constant.JoinGroupApplicationNotification: conf.Notification.JoinGroupApplication,
+ constant.MemberQuitNotification: conf.Notification.MemberQuit,
+ constant.GroupApplicationAcceptedNotification: conf.Notification.GroupApplicationAccepted,
+ constant.GroupApplicationRejectedNotification: conf.Notification.GroupApplicationRejected,
+ constant.GroupOwnerTransferredNotification: conf.Notification.GroupOwnerTransferred,
+ constant.MemberKickedNotification: conf.Notification.MemberKicked,
+ constant.MemberInvitedNotification: conf.Notification.MemberInvited,
+ constant.MemberEnterNotification: conf.Notification.MemberEnter,
+ constant.GroupDismissedNotification: conf.Notification.GroupDismissed,
+ constant.GroupMutedNotification: conf.Notification.GroupMuted,
+ constant.GroupCancelMutedNotification: conf.Notification.GroupCancelMuted,
+ constant.GroupMemberMutedNotification: conf.Notification.GroupMemberMuted,
+ constant.GroupMemberCancelMutedNotification: conf.Notification.GroupMemberCancelMuted,
+ constant.GroupMemberInfoSetNotification: conf.Notification.GroupMemberInfoSet,
+ constant.GroupMemberSetToAdminNotification: conf.Notification.GroupMemberSetToAdmin,
+ constant.GroupMemberSetToOrdinaryUserNotification: conf.Notification.GroupMemberSetToOrdinary,
+ constant.GroupInfoSetAnnouncementNotification: conf.Notification.GroupInfoSetAnnouncement,
+ constant.GroupInfoSetNameNotification: conf.Notification.GroupInfoSetName,
// user
- constant.UserInfoUpdatedNotification: config.Config.Notification.UserInfoUpdated,
- constant.UserStatusChangeNotification: config.Config.Notification.UserStatusChanged,
+ constant.UserInfoUpdatedNotification: conf.Notification.UserInfoUpdated,
+ constant.UserStatusChangeNotification: conf.Notification.UserStatusChanged,
// friend
- constant.FriendApplicationNotification: config.Config.Notification.FriendApplicationAdded,
- constant.FriendApplicationApprovedNotification: config.Config.Notification.FriendApplicationApproved,
- constant.FriendApplicationRejectedNotification: config.Config.Notification.FriendApplicationRejected,
- constant.FriendAddedNotification: config.Config.Notification.FriendAdded,
- constant.FriendDeletedNotification: config.Config.Notification.FriendDeleted,
- constant.FriendRemarkSetNotification: config.Config.Notification.FriendRemarkSet,
- constant.BlackAddedNotification: config.Config.Notification.BlackAdded,
- constant.BlackDeletedNotification: config.Config.Notification.BlackDeleted,
- constant.FriendInfoUpdatedNotification: config.Config.Notification.FriendInfoUpdated,
- constant.FriendsInfoUpdateNotification: config.Config.Notification.FriendInfoUpdated, //use the same FriendInfoUpdated
+ constant.FriendApplicationNotification: conf.Notification.FriendApplicationAdded,
+ constant.FriendApplicationApprovedNotification: conf.Notification.FriendApplicationApproved,
+ constant.FriendApplicationRejectedNotification: conf.Notification.FriendApplicationRejected,
+ constant.FriendAddedNotification: conf.Notification.FriendAdded,
+ constant.FriendDeletedNotification: conf.Notification.FriendDeleted,
+ constant.FriendRemarkSetNotification: conf.Notification.FriendRemarkSet,
+ constant.BlackAddedNotification: conf.Notification.BlackAdded,
+ constant.BlackDeletedNotification: conf.Notification.BlackDeleted,
+ constant.FriendInfoUpdatedNotification: conf.Notification.FriendInfoUpdated,
+ constant.FriendsInfoUpdateNotification: conf.Notification.FriendInfoUpdated, //use the same FriendInfoUpdated
// conversation
- constant.ConversationChangeNotification: config.Config.Notification.ConversationChanged,
- constant.ConversationUnreadNotification: config.Config.Notification.ConversationChanged,
- constant.ConversationPrivateChatNotification: config.Config.Notification.ConversationSetPrivate,
+ constant.ConversationChangeNotification: conf.Notification.ConversationChanged,
+ constant.ConversationUnreadNotification: conf.Notification.ConversationChanged,
+ constant.ConversationPrivateChatNotification: conf.Notification.ConversationSetPrivate,
// msg
constant.MsgRevokeNotification: {IsSendMsg: false, ReliabilityLevel: constant.ReliableNotificationNoMsg},
constant.HasReadReceipt: {IsSendMsg: false, ReliabilityLevel: constant.ReliableNotificationNoMsg},
@@ -130,31 +130,42 @@ type Message struct {
conn grpc.ClientConnInterface
Client msg.MsgClient
discov discoveryregistry.SvcDiscoveryRegistry
+ Config *config.GlobalConfig
}
-func NewMessage(discov discoveryregistry.SvcDiscoveryRegistry) *Message {
- conn, err := discov.GetConn(context.Background(), config.Config.RpcRegisterName.OpenImMsgName)
+func NewMessage(discov discoveryregistry.SvcDiscoveryRegistry, config *config.GlobalConfig) *Message {
+ conn, err := discov.GetConn(context.Background(), config.RpcRegisterName.OpenImMsgName)
if err != nil {
- panic(err)
+ util.ExitWithError(err)
}
client := msg.NewMsgClient(conn)
- return &Message{discov: discov, conn: conn, Client: client}
+ return &Message{discov: discov, conn: conn, Client: client, Config: config}
}
type MessageRpcClient Message
-func NewMessageRpcClient(discov discoveryregistry.SvcDiscoveryRegistry) MessageRpcClient {
- return MessageRpcClient(*NewMessage(discov))
+func NewMessageRpcClient(discov discoveryregistry.SvcDiscoveryRegistry, config *config.GlobalConfig) MessageRpcClient {
+ return MessageRpcClient(*NewMessage(discov, config))
}
+// SendMsg sends a message through the gRPC client and returns the response.
+// It wraps any encountered error for better error handling and context understanding.
func (m *MessageRpcClient) SendMsg(ctx context.Context, req *msg.SendMsgReq) (*msg.SendMsgResp, error) {
resp, err := m.Client.SendMsg(ctx, req)
- return resp, err
+ if err != nil {
+ return nil, err
+ }
+ return resp, nil
}
+// GetMaxSeq retrieves the maximum sequence number from the gRPC client.
+// Errors during the gRPC call are wrapped to provide additional context.
func (m *MessageRpcClient) GetMaxSeq(ctx context.Context, req *sdkws.GetMaxSeqReq) (*sdkws.GetMaxSeqResp, error) {
resp, err := m.Client.GetMaxSeq(ctx, req)
- return resp, err
+ if err != nil {
+ return nil, err
+ }
+ return resp, nil
}
func (m *MessageRpcClient) GetMaxSeqs(ctx context.Context, conversationIDs []string) (map[string]int64, error) {
@@ -181,9 +192,15 @@ func (m *MessageRpcClient) GetMsgByConversationIDs(ctx context.Context, docIDs [
return resp.MsgDatas, err
}
+// PullMessageBySeqList retrieves messages by their sequence numbers using the gRPC client.
+// It directly forwards the request to the gRPC client and returns the response along with any error encountered.
func (m *MessageRpcClient) PullMessageBySeqList(ctx context.Context, req *sdkws.PullMessageBySeqsReq) (*sdkws.PullMessageBySeqsResp, error) {
resp, err := m.Client.PullMessageBySeqs(ctx, req)
- return resp, err
+ if err != nil {
+ // Wrap the error to provide more context if the gRPC call fails.
+ return nil, err
+ }
+ return resp, nil
}
func (m *MessageRpcClient) GetConversationMaxSeq(ctx context.Context, conversationID string) (int64, error) {
@@ -221,8 +238,8 @@ func WithUserRpcClient(userRpcClient *UserRpcClient) NotificationSenderOptions {
}
}
-func NewNotificationSender(opts ...NotificationSenderOptions) *NotificationSender {
- notificationSender := &NotificationSender{contentTypeConf: newContentTypeConf(), sessionTypeConf: newSessionTypeConf()}
+func NewNotificationSender(config *config.GlobalConfig, opts ...NotificationSenderOptions) *NotificationSender {
+ notificationSender := &NotificationSender{contentTypeConf: newContentTypeConf(config), sessionTypeConf: newSessionTypeConf()}
for _, opt := range opts {
opt(notificationSender)
}
@@ -245,8 +262,8 @@ func (s *NotificationSender) NotificationWithSesstionType(ctx context.Context, s
n := sdkws.NotificationElem{Detail: utils.StructToJsonString(m)}
content, err := json.Marshal(&n)
if err != nil {
- log.ZError(ctx, "MsgClient Notification json.Marshal failed", err, "sendID", sendID, "recvID", recvID, "contentType", contentType, "msg", m)
- return err
+ errInfo := fmt.Sprintf("MsgClient Notification json.Marshal failed, sendID:%s, recvID:%s, contentType:%d, msg:%s", sendID, recvID, contentType, m)
+ return errs.Wrap(err, errInfo)
}
notificationOpt := ¬ificationOpt{}
for _, opt := range opts {
@@ -258,7 +275,8 @@ func (s *NotificationSender) NotificationWithSesstionType(ctx context.Context, s
if notificationOpt.WithRpcGetUsername && s.getUserInfo != nil {
userInfo, err = s.getUserInfo(ctx, sendID)
if err != nil {
- log.ZWarn(ctx, "getUserInfo failed", err, "sendID", sendID)
+ errInfo := fmt.Sprintf("getUserInfo failed, sendID:%s", sendID)
+ return errs.Wrap(err, errInfo)
} else {
msg.SenderNickname = userInfo.Nickname
msg.SenderFaceURL = userInfo.FaceURL
@@ -290,10 +308,9 @@ func (s *NotificationSender) NotificationWithSesstionType(ctx context.Context, s
msg.OfflinePushInfo = &offlineInfo
req.MsgData = &msg
_, err = s.sendMsg(ctx, &req)
- if err == nil {
- log.ZDebug(ctx, "MsgClient Notification SendMsg success", "req", &req)
- } else {
- log.ZError(ctx, "MsgClient Notification SendMsg failed", err, "req", &req)
+ if err != nil {
+ errInfo := fmt.Sprintf("MsgClient Notification SendMsg failed, req:%s", &req)
+ return errs.Wrap(err, errInfo)
}
return err
}
diff --git a/pkg/rpcclient/notification/conversation.go b/pkg/rpcclient/notification/conversation.go
index 0fefb147e..1544d6a1f 100644
--- a/pkg/rpcclient/notification/conversation.go
+++ b/pkg/rpcclient/notification/conversation.go
@@ -19,7 +19,7 @@ import (
"github.com/OpenIMSDK/protocol/constant"
"github.com/OpenIMSDK/protocol/sdkws"
-
+ "github.com/openimsdk/open-im-server/v3/pkg/common/config"
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
)
@@ -27,11 +27,11 @@ type ConversationNotificationSender struct {
*rpcclient.NotificationSender
}
-func NewConversationNotificationSender(msgRpcClient *rpcclient.MessageRpcClient) *ConversationNotificationSender {
- return &ConversationNotificationSender{rpcclient.NewNotificationSender(rpcclient.WithRpcClient(msgRpcClient))}
+func NewConversationNotificationSender(config *config.GlobalConfig, msgRpcClient *rpcclient.MessageRpcClient) *ConversationNotificationSender {
+ return &ConversationNotificationSender{rpcclient.NewNotificationSender(config, rpcclient.WithRpcClient(msgRpcClient))}
}
-// SetPrivate调用.
+// SetPrivate invote.
func (c *ConversationNotificationSender) ConversationSetPrivateNotification(ctx context.Context, sendID, recvID string,
isPrivateChat bool, conversationID string,
) error {
@@ -45,7 +45,6 @@ func (c *ConversationNotificationSender) ConversationSetPrivateNotification(ctx
return c.Notification(ctx, sendID, recvID, constant.ConversationPrivateChatNotification, tips)
}
-// 会话改变.
func (c *ConversationNotificationSender) ConversationChangeNotification(ctx context.Context, userID string, conversationIDs []string) error {
tips := &sdkws.ConversationUpdateTips{
UserID: userID,
@@ -55,7 +54,6 @@ func (c *ConversationNotificationSender) ConversationChangeNotification(ctx cont
return c.Notification(ctx, userID, userID, constant.ConversationChangeNotification, tips)
}
-// 会话未读数同步.
func (c *ConversationNotificationSender) ConversationUnreadChangeNotification(
ctx context.Context,
userID, conversationID string,
diff --git a/pkg/rpcclient/notification/friend.go b/pkg/rpcclient/notification/friend.go
index b98a1d38e..dafca055a 100644
--- a/pkg/rpcclient/notification/friend.go
+++ b/pkg/rpcclient/notification/friend.go
@@ -17,12 +17,11 @@ package notification
import (
"context"
- "github.com/OpenIMSDK/tools/mcontext"
-
"github.com/OpenIMSDK/protocol/constant"
pbfriend "github.com/OpenIMSDK/protocol/friend"
"github.com/OpenIMSDK/protocol/sdkws"
-
+ "github.com/OpenIMSDK/tools/mcontext"
+ "github.com/openimsdk/open-im-server/v3/pkg/common/config"
"github.com/openimsdk/open-im-server/v3/pkg/common/convert"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/controller"
relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
@@ -31,7 +30,7 @@ import (
type FriendNotificationSender struct {
*rpcclient.NotificationSender
- // 找不到报错
+ // Target not found err
getUsersInfo func(ctx context.Context, userIDs []string) ([]CommonUser, error)
// db controller
db controller.FriendDatabase
@@ -82,11 +81,12 @@ func WithRpcFunc(
}
func NewFriendNotificationSender(
+ config *config.GlobalConfig,
msgRpcClient *rpcclient.MessageRpcClient,
opts ...friendNotificationSenderOptions,
) *FriendNotificationSender {
f := &FriendNotificationSender{
- NotificationSender: rpcclient.NewNotificationSender(rpcclient.WithRpcClient(msgRpcClient)),
+ NotificationSender: rpcclient.NewNotificationSender(config, rpcclient.WithRpcClient(msgRpcClient)),
}
for _, opt := range opts {
opt(f)
@@ -109,6 +109,7 @@ func (f *FriendNotificationSender) getUsersInfoMap(
return result, nil
}
+//nolint:unused
func (f *FriendNotificationSender) getFromToUserNickname(
ctx context.Context,
fromUserID, toUserID string,
@@ -214,7 +215,9 @@ func (f *FriendNotificationSender) BlackDeletedNotification(ctx context.Context,
FromUserID: req.OwnerUserID,
ToUserID: req.BlackUserID,
}}
- f.Notification(ctx, req.OwnerUserID, req.BlackUserID, constant.BlackDeletedNotification, &blackDeletedTips)
+ if err := f.Notification(ctx, req.OwnerUserID, req.BlackUserID, constant.BlackDeletedNotification, &blackDeletedTips); err != nil {
+ //err
+ }
}
func (f *FriendNotificationSender) FriendInfoUpdatedNotification(
@@ -223,5 +226,8 @@ func (f *FriendNotificationSender) FriendInfoUpdatedNotification(
needNotifiedUserID string,
) {
tips := sdkws.UserInfoUpdatedTips{UserID: changedUserID}
- f.Notification(ctx, mcontext.GetOpUserID(ctx), needNotifiedUserID, constant.FriendInfoUpdatedNotification, &tips)
+ if err := f.Notification(ctx, mcontext.GetOpUserID(ctx), needNotifiedUserID,
+ constant.FriendInfoUpdatedNotification, &tips); err != nil {
+ // err
+ }
}
diff --git a/pkg/rpcclient/notification/group.go b/pkg/rpcclient/notification/group.go
old mode 100755
new mode 100644
index 8c3719b2c..c72aa839b
--- a/pkg/rpcclient/notification/group.go
+++ b/pkg/rpcclient/notification/group.go
@@ -18,8 +18,6 @@ import (
"context"
"fmt"
- "github.com/openimsdk/open-im-server/v3/pkg/authverify"
-
"github.com/OpenIMSDK/protocol/constant"
pbgroup "github.com/OpenIMSDK/protocol/group"
"github.com/OpenIMSDK/protocol/sdkws"
@@ -27,7 +25,8 @@ import (
"github.com/OpenIMSDK/tools/log"
"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/common/config"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/controller"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
@@ -37,12 +36,14 @@ func NewGroupNotificationSender(
db controller.GroupDatabase,
msgRpcClient *rpcclient.MessageRpcClient,
userRpcClient *rpcclient.UserRpcClient,
+ config *config.GlobalConfig,
fn func(ctx context.Context, userIDs []string) ([]CommonUser, error),
) *GroupNotificationSender {
return &GroupNotificationSender{
- NotificationSender: rpcclient.NewNotificationSender(rpcclient.WithRpcClient(msgRpcClient), rpcclient.WithUserRpcClient(userRpcClient)),
+ NotificationSender: rpcclient.NewNotificationSender(config, rpcclient.WithRpcClient(msgRpcClient), rpcclient.WithUserRpcClient(userRpcClient)),
getUsersInfo: fn,
db: db,
+ config: config,
}
}
@@ -50,6 +51,7 @@ type GroupNotificationSender struct {
*rpcclient.NotificationSender
getUsersInfo func(ctx context.Context, userIDs []string) ([]CommonUser, error)
db controller.GroupDatabase
+ config *config.GlobalConfig
}
func (g *GroupNotificationSender) PopulateGroupMember(ctx context.Context, members ...*relation.GroupMemberModel) error {
@@ -192,6 +194,7 @@ func (g *GroupNotificationSender) getGroupOwnerAndAdminUserID(ctx context.Contex
return utils.Slice(members, fn), nil
}
+//nolint:unused
func (g *GroupNotificationSender) groupDB2PB(group *relation.GroupModel, ownerUserID string, memberCount uint32) *sdkws.GroupInfo {
return &sdkws.GroupInfo{
GroupID: group.GroupID,
@@ -231,7 +234,7 @@ func (g *GroupNotificationSender) groupMemberDB2PB(member *relation.GroupMemberM
}
}
-func (g *GroupNotificationSender) getUsersInfoMap(ctx context.Context, userIDs []string) (map[string]*sdkws.UserInfo, error) {
+/* func (g *GroupNotificationSender) getUsersInfoMap(ctx context.Context, userIDs []string) (map[string]*sdkws.UserInfo, error) {
users, err := g.getUsersInfo(ctx, userIDs)
if err != nil {
return nil, err
@@ -241,24 +244,15 @@ func (g *GroupNotificationSender) getUsersInfoMap(ctx context.Context, userIDs [
result[user.GetUserID()] = user.(*sdkws.UserInfo)
}
return result, nil
-}
+} */
func (g *GroupNotificationSender) fillOpUser(ctx context.Context, opUser **sdkws.GroupMemberFullInfo, groupID string) (err error) {
- defer log.ZDebug(ctx, "return")
- defer func() {
- if err != nil {
- log.ZError(ctx, utils.GetFuncName(1)+" failed", err)
- }
- }()
if opUser == nil {
return errs.ErrInternalServer.Wrap("**sdkws.GroupMemberFullInfo is nil")
}
- if *opUser != nil {
- return nil
- }
userID := mcontext.GetOpUserID(ctx)
if groupID != "" {
- if authverify.IsManagerUserID(userID) {
+ if authverify.IsManagerUserID(userID, g.config) {
*opUser = &sdkws.GroupMemberFullInfo{
GroupID: groupID,
UserID: userID,
@@ -410,7 +404,7 @@ func (g *GroupNotificationSender) GroupApplicationAcceptedNotification(ctx conte
return err
}
tips := &sdkws.GroupApplicationAcceptedTips{Group: group, HandleMsg: req.HandledMsg}
- if err := g.fillOpUser(ctx, &tips.OpUser, tips.Group.GroupID); err != nil {
+ if err = g.fillOpUser(ctx, &tips.OpUser, tips.Group.GroupID); err != nil {
return err
}
for _, userID := range append(userIDs, req.FromUserID) {
@@ -443,7 +437,7 @@ func (g *GroupNotificationSender) GroupApplicationRejectedNotification(ctx conte
return err
}
tips := &sdkws.GroupApplicationRejectedTips{Group: group, HandleMsg: req.HandledMsg}
- if err := g.fillOpUser(ctx, &tips.OpUser, tips.Group.GroupID); err != nil {
+ if err = g.fillOpUser(ctx, &tips.OpUser, tips.Group.GroupID); err != nil {
return err
}
for _, userID := range append(userIDs, req.FromUserID) {
@@ -651,12 +645,6 @@ func (g *GroupNotificationSender) GroupCancelMutedNotification(ctx context.Conte
}
func (g *GroupNotificationSender) GroupMemberInfoSetNotification(ctx context.Context, groupID, groupMemberUserID string) (err error) {
- defer log.ZDebug(ctx, "return")
- defer func() {
- if err != nil {
- log.ZError(ctx, utils.GetFuncName(1)+" failed", err)
- }
- }()
group, err := g.getGroupInfo(ctx, groupID)
if err != nil {
return err
@@ -673,12 +661,6 @@ func (g *GroupNotificationSender) GroupMemberInfoSetNotification(ctx context.Con
}
func (g *GroupNotificationSender) GroupMemberSetToAdminNotification(ctx context.Context, groupID, groupMemberUserID string) (err error) {
- defer log.ZDebug(ctx, "return")
- defer func() {
- if err != nil {
- log.ZError(ctx, utils.GetFuncName(1)+" failed", err)
- }
- }()
group, err := g.getGroupInfo(ctx, groupID)
if err != nil {
return err
diff --git a/pkg/rpcclient/notification/msg.go b/pkg/rpcclient/notification/msg.go
index 60fa64f40..beaef1d96 100644
--- a/pkg/rpcclient/notification/msg.go
+++ b/pkg/rpcclient/notification/msg.go
@@ -19,7 +19,7 @@ import (
"github.com/OpenIMSDK/protocol/constant"
"github.com/OpenIMSDK/protocol/sdkws"
-
+ "github.com/openimsdk/open-im-server/v3/pkg/common/config"
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
)
@@ -27,8 +27,8 @@ type MsgNotificationSender struct {
*rpcclient.NotificationSender
}
-func NewMsgNotificationSender(opts ...rpcclient.NotificationSenderOptions) *MsgNotificationSender {
- return &MsgNotificationSender{rpcclient.NewNotificationSender(opts...)}
+func NewMsgNotificationSender(config *config.GlobalConfig, opts ...rpcclient.NotificationSenderOptions) *MsgNotificationSender {
+ return &MsgNotificationSender{rpcclient.NewNotificationSender(config, opts...)}
}
func (m *MsgNotificationSender) UserDeleteMsgsNotification(ctx context.Context, userID, conversationID string, seqs []int64) error {
diff --git a/pkg/rpcclient/notification/user.go b/pkg/rpcclient/notification/user.go
index 4347faece..610967fd5 100644
--- a/pkg/rpcclient/notification/user.go
+++ b/pkg/rpcclient/notification/user.go
@@ -19,7 +19,7 @@ import (
"github.com/OpenIMSDK/protocol/constant"
"github.com/OpenIMSDK/protocol/sdkws"
-
+ "github.com/openimsdk/open-im-server/v3/pkg/common/config"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/controller"
relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
@@ -59,11 +59,12 @@ func WithUserFunc(
}
func NewUserNotificationSender(
+ config *config.GlobalConfig,
msgRpcClient *rpcclient.MessageRpcClient,
opts ...userNotificationSenderOptions,
) *UserNotificationSender {
f := &UserNotificationSender{
- NotificationSender: rpcclient.NewNotificationSender(rpcclient.WithRpcClient(msgRpcClient)),
+ NotificationSender: rpcclient.NewNotificationSender(config, rpcclient.WithRpcClient(msgRpcClient)),
}
for _, opt := range opts {
opt(f)
@@ -71,7 +72,7 @@ func NewUserNotificationSender(
return f
}
-func (u *UserNotificationSender) getUsersInfoMap(
+/* func (u *UserNotificationSender) getUsersInfoMap(
ctx context.Context,
userIDs []string,
) (map[string]*sdkws.UserInfo, error) {
@@ -84,9 +85,9 @@ func (u *UserNotificationSender) getUsersInfoMap(
result[user.GetUserID()] = user.(*sdkws.UserInfo)
}
return result, nil
-}
+} */
-func (u *UserNotificationSender) getFromToUserNickname(
+/* func (u *UserNotificationSender) getFromToUserNickname(
ctx context.Context,
fromUserID, toUserID string,
) (string, string, error) {
@@ -95,7 +96,7 @@ func (u *UserNotificationSender) getFromToUserNickname(
return "", "", nil
}
return users[fromUserID].Nickname, users[toUserID].Nickname, nil
-}
+} */
func (u *UserNotificationSender) UserStatusChangeNotification(
ctx context.Context,
diff --git a/pkg/rpcclient/push.go b/pkg/rpcclient/push.go
index 6d0876972..c0aa9efa4 100644
--- a/pkg/rpcclient/push.go
+++ b/pkg/rpcclient/push.go
@@ -17,12 +17,11 @@ package rpcclient
import (
"context"
- "google.golang.org/grpc"
-
"github.com/OpenIMSDK/protocol/push"
"github.com/OpenIMSDK/tools/discoveryregistry"
-
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
+ util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil"
+ "google.golang.org/grpc"
)
type Push struct {
@@ -31,10 +30,10 @@ type Push struct {
discov discoveryregistry.SvcDiscoveryRegistry
}
-func NewPush(discov discoveryregistry.SvcDiscoveryRegistry) *Push {
- conn, err := discov.GetConn(context.Background(), config.Config.RpcRegisterName.OpenImPushName)
+func NewPush(discov discoveryregistry.SvcDiscoveryRegistry, config *config.GlobalConfig) *Push {
+ conn, err := discov.GetConn(context.Background(), config.RpcRegisterName.OpenImPushName)
if err != nil {
- panic(err)
+ util.ExitWithError(err)
}
return &Push{
discov: discov,
@@ -45,13 +44,10 @@ func NewPush(discov discoveryregistry.SvcDiscoveryRegistry) *Push {
type PushRpcClient Push
-func NewPushRpcClient(discov discoveryregistry.SvcDiscoveryRegistry) PushRpcClient {
- return PushRpcClient(*NewPush(discov))
+func NewPushRpcClient(discov discoveryregistry.SvcDiscoveryRegistry, config *config.GlobalConfig) PushRpcClient {
+ return PushRpcClient(*NewPush(discov, config))
}
-func (p *PushRpcClient) DelUserPushToken(
- ctx context.Context,
- req *push.DelUserPushTokenReq,
-) (*push.DelUserPushTokenResp, error) {
+func (p *PushRpcClient) DelUserPushToken(ctx context.Context, req *push.DelUserPushTokenReq) (*push.DelUserPushTokenResp, error) {
return p.Client.DelUserPushToken(ctx, req)
}
diff --git a/pkg/rpcclient/third.go b/pkg/rpcclient/third.go
old mode 100755
new mode 100644
index 48a537112..a1f8ae180
--- a/pkg/rpcclient/third.go
+++ b/pkg/rpcclient/third.go
@@ -18,15 +18,14 @@ import (
"context"
"net/url"
- "github.com/minio/minio-go/v7"
- "github.com/minio/minio-go/v7/pkg/credentials"
-
- "google.golang.org/grpc"
-
"github.com/OpenIMSDK/protocol/third"
"github.com/OpenIMSDK/tools/discoveryregistry"
-
+ "github.com/OpenIMSDK/tools/errs"
+ "github.com/minio/minio-go/v7"
+ "github.com/minio/minio-go/v7/pkg/credentials"
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
+ util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil"
+ "google.golang.org/grpc"
)
type Third struct {
@@ -34,29 +33,32 @@ type Third struct {
Client third.ThirdClient
discov discoveryregistry.SvcDiscoveryRegistry
MinioClient *minio.Client
+ Config *config.GlobalConfig
}
-func NewThird(discov discoveryregistry.SvcDiscoveryRegistry) *Third {
- conn, err := discov.GetConn(context.Background(), config.Config.RpcRegisterName.OpenImThirdName)
+func NewThird(discov discoveryregistry.SvcDiscoveryRegistry, config *config.GlobalConfig) *Third {
+ conn, err := discov.GetConn(context.Background(), config.RpcRegisterName.OpenImThirdName)
if err != nil {
- panic(err)
+ util.ExitWithError(err)
}
client := third.NewThirdClient(conn)
- minioClient, err := minioInit()
- return &Third{discov: discov, Client: client, conn: conn, MinioClient: minioClient}
+ minioClient, err := minioInit(config)
+ if err != nil {
+ util.ExitWithError(err)
+ }
+ return &Third{discov: discov, Client: client, conn: conn, MinioClient: minioClient, Config: config}
}
-func minioInit() (*minio.Client, error) {
+func minioInit(config *config.GlobalConfig) (*minio.Client, error) {
minioClient := &minio.Client{}
- var initUrl string
- initUrl = config.Config.Object.Minio.Endpoint
+ initUrl := config.Object.Minio.Endpoint
minioUrl, err := url.Parse(initUrl)
if err != nil {
- return nil, err
+ return nil, errs.Wrap(err, "minioInit: failed to parse MinIO endpoint URL")
}
opts := &minio.Options{
- Creds: credentials.NewStaticV4(config.Config.Object.Minio.AccessKeyID, config.Config.Object.Minio.SecretAccessKey, ""),
- // Region: config.Config.Credential.Minio.Location,
+ Creds: credentials.NewStaticV4(config.Object.Minio.AccessKeyID, config.Object.Minio.SecretAccessKey, ""),
+ // Region: config.Credential.Minio.Location,
}
if minioUrl.Scheme == "http" {
opts.Secure = false
@@ -65,7 +67,7 @@ func minioInit() (*minio.Client, error) {
}
minioClient, err = minio.New(minioUrl.Host, opts)
if err != nil {
- return nil, err
+ return nil, errs.Wrap(err, "minioInit: failed to create MinIO client")
}
return minioClient, nil
}
diff --git a/pkg/rpcclient/user.go b/pkg/rpcclient/user.go
index 451914cd3..08ad41dc1 100644
--- a/pkg/rpcclient/user.go
+++ b/pkg/rpcclient/user.go
@@ -18,17 +18,15 @@ import (
"context"
"strings"
- "github.com/openimsdk/open-im-server/v3/pkg/authverify"
-
- "google.golang.org/grpc"
-
"github.com/OpenIMSDK/protocol/sdkws"
"github.com/OpenIMSDK/protocol/user"
"github.com/OpenIMSDK/tools/discoveryregistry"
"github.com/OpenIMSDK/tools/errs"
"github.com/OpenIMSDK/tools/utils"
-
+ "github.com/openimsdk/open-im-server/v3/pkg/authverify"
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
+ util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil"
+ "google.golang.org/grpc"
)
// User represents a structure holding connection details for the User RPC client.
@@ -36,16 +34,17 @@ type User struct {
conn grpc.ClientConnInterface
Client user.UserClient
Discov discoveryregistry.SvcDiscoveryRegistry
+ Config *config.GlobalConfig
}
// NewUser initializes and returns a User instance based on the provided service discovery registry.
-func NewUser(discov discoveryregistry.SvcDiscoveryRegistry) *User {
- conn, err := discov.GetConn(context.Background(), config.Config.RpcRegisterName.OpenImUserName)
+func NewUser(discov discoveryregistry.SvcDiscoveryRegistry, config *config.GlobalConfig) *User {
+ conn, err := discov.GetConn(context.Background(), config.RpcRegisterName.OpenImUserName)
if err != nil {
- panic(err)
+ util.ExitWithError(err)
}
client := user.NewUserClient(conn)
- return &User{Discov: discov, Client: client, conn: conn}
+ return &User{Discov: discov, Client: client, conn: conn, Config: config}
}
// UserRpcClient represents the structure for a User RPC client.
@@ -58,8 +57,8 @@ func NewUserRpcClientByUser(user *User) *UserRpcClient {
}
// NewUserRpcClient initializes a UserRpcClient based on the provided service discovery registry.
-func NewUserRpcClient(client discoveryregistry.SvcDiscoveryRegistry) UserRpcClient {
- return UserRpcClient(*NewUser(client))
+func NewUserRpcClient(client discoveryregistry.SvcDiscoveryRegistry, config *config.GlobalConfig) UserRpcClient {
+ return UserRpcClient(*NewUser(client, config))
}
// GetUsersInfo retrieves information for multiple users based on their user IDs.
@@ -162,7 +161,7 @@ func (u *UserRpcClient) Access(ctx context.Context, ownerUserID string) error {
if err != nil {
return err
}
- return authverify.CheckAccessV3(ctx, ownerUserID)
+ return authverify.CheckAccessV3(ctx, ownerUserID, u.Config)
}
// GetAllUserIDs retrieves all user IDs with pagination options.
diff --git a/pkg/statistics/statistics.go b/pkg/statistics/statistics.go
index de6d04fec..6dfc8155c 100644
--- a/pkg/statistics/statistics.go
+++ b/pkg/statistics/statistics.go
@@ -36,9 +36,7 @@ func (s *Statistics) output() {
var timeIntervalNum uint64
for {
sum = *s.AllCount
- select {
- case <-t.C:
- }
+ <-t.C
if *s.AllCount-sum <= 0 {
intervalCount = 0
} else {
diff --git a/pkg/util/genutil/genutil.go b/pkg/util/genutil/genutil.go
index 0948a7c49..95735485d 100644
--- a/pkg/util/genutil/genutil.go
+++ b/pkg/util/genutil/genutil.go
@@ -18,6 +18,8 @@ import (
"fmt"
"os"
"path/filepath"
+
+ "github.com/OpenIMSDK/tools/errs"
)
// OutDir creates the absolute path name from path and checks path exists.
@@ -25,17 +27,28 @@ import (
func OutDir(path string) (string, error) {
outDir, err := filepath.Abs(path)
if err != nil {
- return "", err
+ return "", errs.Wrap(err, "output directory %s does not exist", path)
}
stat, err := os.Stat(outDir)
if err != nil {
- return "", err
+ return "", errs.Wrap(err, "output directory %s does not exist", outDir)
}
if !stat.IsDir() {
- return "", fmt.Errorf("output directory %s is not a directory", outDir)
+ return "", errs.Wrap(err, "output directory %s is not a directory", outDir)
}
outDir += "/"
return outDir, nil
}
+
+func ExitWithError(err error) {
+ progName := filepath.Base(os.Args[0])
+ fmt.Fprintf(os.Stderr, "%s exit -1: %+v\n", progName, err)
+ os.Exit(-1)
+}
+
+func SIGTERMExit() {
+ progName := filepath.Base(os.Args[0])
+ fmt.Fprintf(os.Stderr, "Warning %s receive process terminal SIGTERM exit 0\n", progName)
+}
diff --git a/scripts/.spelling_failures b/scripts/.spelling_failures
index 149d314ba..347246f2e 100644
--- a/scripts/.spelling_failures
+++ b/scripts/.spelling_failures
@@ -5,4 +5,27 @@ third_party/
translations/
logs
.git
-.golangci.yml
\ No newline at end of file
+.golangci.yml
+docs/readme/README_uk.md
+docs/readme/README_cs.md
+docs/readme/README_hu.md
+docs/readme/README_es.md
+docs/readme/README_fa.md
+docs/readme/README_fr.md
+docs/readme/README_de.md
+docs/readme/README_pl.md
+docs/readme/README_id.md
+docs/readme/README_fi.md
+docs/readme/README_ml.md
+docs/readme/README_ja.md
+docs/readme/README_nl.md
+docs/readme/README_it.md
+docs/readme/README_ru.md
+docs/readme/README_pt_BR
+docs/readme/README_eo.md
+docs/readme/README_ko.md
+docs/readme/README_ar.md
+docs/readme/README_vi.md
+docs/readme/README_da.md
+docs/readme/README_el.md
+docs/readme/README_tr.md
diff --git a/scripts/advertise.sh b/scripts/advertise.sh
index 3effc4f2b..958b4e3ae 100755
--- a/scripts/advertise.sh
+++ b/scripts/advertise.sh
@@ -14,7 +14,7 @@
# limitations under the License.
set -e
-set -o pipefail
+
. $(dirname ${BASH_SOURCE})/lib/init.sh
diff --git a/scripts/build-all-service.sh b/scripts/build-all-service.sh
index b5578fca6..eea380b4f 100755
--- a/scripts/build-all-service.sh
+++ b/scripts/build-all-service.sh
@@ -22,9 +22,6 @@
# Usage: `scripts/build-all-service.sh`.
# Example: `scripts/build-go.sh WHAT=cmd/kubelet`.
-set -o errexit
-set -o nounset
-set -o pipefail
OPENIM_ROOT=$(dirname "${BASH_SOURCE[0]}")/..
source "${OPENIM_ROOT}/scripts/lib/init.sh"
diff --git a/scripts/check-all.sh b/scripts/check-all.sh
index 1f6b740e6..a9b07d65b 100755
--- a/scripts/check-all.sh
+++ b/scripts/check-all.sh
@@ -19,9 +19,9 @@
# Encapsulated as: `make check`.
# READ: https://github.com/openimsdk/open-im-server/tree/main/scripts/install/environment.sh
-set -o errexit
-set -o nounset
-set -o pipefail
+
+
+
OPENIM_ROOT=$(dirname "${BASH_SOURCE[0]}")/..
source "${OPENIM_ROOT}/scripts/install/common.sh"
@@ -49,6 +49,7 @@ print_services_and_ports() {
echo "+-------------------------+----------+"
}
+
# Assuming OPENIM_SERVER_NAME_TARGETS and OPENIM_SERVER_PORT_TARGETS are defined
# Similarly for OPENIM_DEPENDENCY_TARGETS and OPENIM_DEPENDENCY_PORT_TARGETS
@@ -63,7 +64,6 @@ echo "++ The port being checked: ${OPENIM_SERVER_PORT_LISTARIES[@]}"
openim::log::info "\n## Check all dependent service ports"
echo "++ The port being checked: ${OPENIM_DEPENDENCY_PORT_LISTARIES[@]}"
-set +e
# Later, after discarding Docker, the Docker keyword is unreliable, and Kubepods is used
if grep -qE 'docker|kubepods' /proc/1/cgroup || [ -f /.dockerenv ]; then
@@ -77,20 +77,29 @@ if [[ $? -ne 0 ]]; then
openim::log::error_exit "The service does not start properly, please check the port, query variable definition!"
echo "+++ https://github.com/openimsdk/open-im-server/tree/main/scripts/install/environment.sh +++"
else
- echo "++++ Check all dependent service ports successfully !"
+ openim::log::success "All components depended on by openim are running normally! "
fi
-openim::log::info "\n## Check OpenIM service name"
-. $(dirname ${BASH_SOURCE})/install/openim-msgtransfer.sh openim::msgtransfer::check
-openim::log::info "\n## Check all OpenIM service ports"
-echo "+++ The port being checked: ${OPENIM_SERVER_PORT_LISTARIES[@]}"
-openim::util::check_ports ${OPENIM_SERVER_PORT_LISTARIES[@]}
+openim::log::info "\n## Check openim service name:\n${OPENIM_OUTPUT_HOSTBIN}/openim-msgtransfer"
+result=$(. $(dirname ${BASH_SOURCE})/install/openim-msgtransfer.sh openim::msgtransfer::check)
if [[ $? -ne 0 ]]; then
echo "+++ cat openim log file >>> ${LOG_FILE}"
- openim::log::error_exit "The service does not start properly, please check the port, query variable definition!"
-else
- echo "++++ Check all openim service ports successfully !"
+ openim::log::error "check process failed.\n $result"
+fi
+
+
+echo "Check openim service name:"
+for item in "${OPENIM_ALL_SERVICE_LIBRARIES_NO_TRANSFER[@]}"; do
+ echo "$item"
+done
+
+result=$(openim::util::check_process_names ${OPENIM_ALL_SERVICE_LIBRARIES_NO_TRANSFER[@]})
+if [[ $? -ne 0 ]]; then
+ echo "+++ cat openim log file >>> ${LOG_FILE}"
+ openim::log::error "check process failed.\n "
+ echo "$result"
+else
+ openim::log::success "All openim services are running normally! "
fi
-set -e
diff --git a/scripts/cherry-pick.sh b/scripts/cherry-pick.sh
index 8a1f8dd79..f8d7912f8 100755
--- a/scripts/cherry-pick.sh
+++ b/scripts/cherry-pick.sh
@@ -21,9 +21,9 @@
# checks them out to a branch named:
# automated-cherry-pick-of---
-set -o errexit
-set -o nounset
-set -o pipefail
+
+
+
OPENIM_ROOT=$(dirname "${BASH_SOURCE[0]}")/..
source "${OPENIM_ROOT}/scripts/lib/init.sh"
diff --git a/scripts/common.sh b/scripts/common.sh
index d67389d56..f7155fca2 100755
--- a/scripts/common.sh
+++ b/scripts/common.sh
@@ -18,9 +18,6 @@
# shellcheck disable=SC2034 # Variables sourced in other scripts.
# Common utilities, variables and checks for all build scripts.
-set -o errexit
-set +o nounset
-set -o pipefail
# Unset CDPATH, having it set messes up with script import paths
unset CDPATH
diff --git a/scripts/docker-start-all.sh b/scripts/docker-start-all.sh
index 162655553..c47069e3b 100755
--- a/scripts/docker-start-all.sh
+++ b/scripts/docker-start-all.sh
@@ -14,9 +14,9 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-set -o errexit
-set -o nounset
-set -o pipefail
+
+
+
#fixme This scripts is the total startup scripts
#fixme The full name of the shell scripts that needs to be started is placed in the need_to_start_server_shell array
diff --git a/scripts/gen-swagger-docs.sh b/scripts/gen-swagger-docs.sh
index 68410e79c..e768f9106 100755
--- a/scripts/gen-swagger-docs.sh
+++ b/scripts/gen-swagger-docs.sh
@@ -15,9 +15,9 @@
# Script to generate docs from the latest swagger spec.
-set -o errexit
-set -o nounset
-set -o pipefail
+
+
+
# The root of the build/dist directory
OPENIM_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd -P)"
diff --git a/scripts/githooks/pre-commit.sh b/scripts/githooks/pre-commit.sh
index cc756c9ad..d8396b560 100644
--- a/scripts/githooks/pre-commit.sh
+++ b/scripts/githooks/pre-commit.sh
@@ -105,7 +105,7 @@ fi
if [[ ! $local_branch =~ $valid_branch_regex ]]
then
printError "There is something wrong with your branch name. Branch names in this project must adhere to this contract: $valid_branch_regex.
-Your commit will be rejected. You should rename your branch to a valid name(feat/name OR bug/name) and try again."
+Your commit will be rejected. You should rename your branch to a valid name(feat/name OR fix/name) and try again."
printError "For more on this, read on: https://gist.github.com/cubxxw/126b72104ac0b0ca484c9db09c3e5694"
exit 1
fi
\ No newline at end of file
diff --git a/scripts/init-config.sh b/scripts/init-config.sh
index 82eefbb54..c7cf16320 100755
--- a/scripts/init-config.sh
+++ b/scripts/init-config.sh
@@ -15,9 +15,9 @@
# This script automatically initializes various configuration files and can generate example files.
-set -o errexit
-set -o nounset
-set -o pipefail
+
+
+
# Root directory of the OpenIM project
OPENIM_ROOT=$(dirname "${BASH_SOURCE[0]}")/..
diff --git a/scripts/init-env.sh b/scripts/init-env.sh
index 75b871b08..1e802c3be 100755
--- a/scripts/init-env.sh
+++ b/scripts/init-env.sh
@@ -16,8 +16,8 @@
#FIXME This script is the startup script for multiple servers.
#FIXME The full names of the shell scripts that need to be started are placed in the `need_to_start_server_shell` array.
-set -o nounset
-set -o pipefail
+
+
OPENIM_ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")"/.. && pwd -P)
source "${OPENIM_ROOT}/scripts/install/common.sh"
diff --git a/scripts/install-im-server.sh b/scripts/install-im-server.sh
index c1224e30c..d11a49dc8 100755
--- a/scripts/install-im-server.sh
+++ b/scripts/install-im-server.sh
@@ -27,9 +27,9 @@
# Usage:
# SERVER_IMAGE_VERSION=latest IMAGE_REGISTRY=myregistry ./this_script.sh
-set -o errexit
-set -o nounset
-set -o pipefail
+
+
+
OPENIM_ROOT=$(dirname "${BASH_SOURCE[0]}")/..
source "${OPENIM_ROOT}/scripts/lib/init.sh"
diff --git a/scripts/install/common.sh b/scripts/install/common.sh
index f6ee5d3ad..ed1ba1a4b 100755
--- a/scripts/install/common.sh
+++ b/scripts/install/common.sh
@@ -15,9 +15,9 @@
# Common utilities, variables and checks for all build scripts.
-set -o errexit
-set +o nounset
-set -o pipefail
+
+
+
# Sourced flag
COMMON_SOURCED=true
@@ -99,6 +99,22 @@ IFS=" " read -ra OPENIM_SERVER_PORT_TARGETS <<< "$(openim::common::service_port)
readonly OPENIM_SERVER_PORT_TARGETS
readonly OPENIM_SERVER_PORT_LISTARIES=("${OPENIM_SERVER_PORT_TARGETS[@]##*/}")
+
+OPENIM_ALL_SERVICE_LIBRARIES_NO_TRANSFER=()
+
+for target in "${OPENIM_SERVER_BINARIES_NO_TRANSFER[@]}"; do
+ OPENIM_ALL_SERVICE_LIBRARIES_NO_TRANSFER+=("${OPENIM_OUTPUT_HOSTBIN}/${target}")
+done
+readonly OPENIM_ALL_SERVICE_LIBRARIES_NO_TRANSFER
+
+
+
+OPENIM_ALL_SERVICE_LIBRARIES=()
+for target in "${OPENIM_SERVER_BINARIES_NO_CMDUTILS[@]}"; do
+ OPENIM_ALL_SERVICE_LIBRARIES+=("${OPENIM_OUTPUT_HOSTBIN}/${target}")
+done
+readonly OPENIM_ALL_SERVICE_LIBRARIES
+
openim::common::dependency_name() {
local targets=(
redis
diff --git a/scripts/install/dependency.sh b/scripts/install/dependency.sh
index e7c7eb426..bad1cb6f9 100755
--- a/scripts/install/dependency.sh
+++ b/scripts/install/dependency.sh
@@ -15,9 +15,9 @@
# This script will install the dependencies required for openim
-set -o errexit
-set +o nounset
-set -o pipefail
+
+
+
OPENIM_ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")"/../.. && pwd -P)
[[ -z ${COMMON_SOURCED} ]] && source "${OPENIM_ROOT}"/scripts/install/common.sh
diff --git a/scripts/install/environment.sh b/scripts/install/environment.sh
index b1d2354b9..64e76853d 100755
--- a/scripts/install/environment.sh
+++ b/scripts/install/environment.sh
@@ -222,6 +222,14 @@ def "KODO_ACCESS_KEY_SECRET" # 七
def "KODO_SESSION_TOKEN" # 七牛云OSS的会话令牌
def "KODO_PUBLIC_READ" "false" # 公有读
+# AWS Configuration Information
+def "AWS_ENDPOINT" "" # AWS endpoint, generally not needed unless using a specific service
+def "AWS_REGION" "us-east-1" # AWS Region
+def "AWS_BUCKET" "demo-9999999" # AWS S3 Bucket Name
+def "AWS_ACCESS_KEY_ID" # AWS Access Key ID
+def "AWS_SECRET_ACCESS_KEY" # AWS Secret Access Key
+def "AWS_PUBLIC_READ" "false" # Public read access
+
###################### Redis 配置信息 ######################
def "REDIS_PORT" "16379" # Redis的端口
def "REDIS_ADDRESS" "${DOCKER_BRIDGE_GATEWAY}" # Redis的地址
@@ -324,7 +332,7 @@ def "OPENIM_CONVERSATION_NAME" "Conversation" # OpenIM对话服务名称
def "OPENIM_THIRD_NAME" "Third" # OpenIM第三方服务名称
###################### Log Configuration Variables ######################
-def "LOG_STORAGE_LOCATION" "${OPENIM_ROOT}/logs/" # 日志存储位置
+def "LOG_STORAGE_LOCATION" "${OPENIM_ROOT}/_output/logs/" # 日志存储位置
def "LOG_ROTATION_TIME" "24" # 日志轮替时间
def "LOG_REMAIN_ROTATION_COUNT" "2" # 保留的日志轮替数量
def "LOG_REMAIN_LOG_LEVEL" "6" # 保留的日志级别
diff --git a/scripts/install/install.sh b/scripts/install/install.sh
index d5ec5b7f7..bb09675bf 100755
--- a/scripts/install/install.sh
+++ b/scripts/install/install.sh
@@ -109,7 +109,7 @@ function openim::uninstall::uninstall_openim() {
openim::common::sudo "systemctl stop openim.target"
openim::common::sudo "systemctl disable openim.target"
openim::common::sudo "rm -f /etc/systemd/system/openim.target"
- set -o errexit
+
openim::log::success "openim uninstall success"
}
diff --git a/scripts/install/openim-api.sh b/scripts/install/openim-api.sh
index 2c3c19afb..cd3d5eb08 100755
--- a/scripts/install/openim-api.sh
+++ b/scripts/install/openim-api.sh
@@ -14,9 +14,9 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-set -o errexit
-set +o nounset
-set -o pipefail
+
+
+
OPENIM_ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")"/../.. && pwd -P)
[[ -z ${COMMON_SOURCED} ]] && source "${OPENIM_ROOT}"/scripts/install/common.sh
@@ -33,45 +33,45 @@ readonly OPENIM_API_SERVICE_TARGETS=(
)
readonly OPENIM_API_SERVICE_LISTARIES=("${OPENIM_API_SERVICE_TARGETS[@]##*/}")
+readonly OPENIM_API_PROMETHEUS_PORT_TARGETS=(
+ ${API_PROM_PORT}
+)
+readonly OPENIM_API_PROMETHEUS_PORT_LISTARIES=("${OPENIM_API_PROMETHEUS_PORT_TARGETS[@]##*/}")
+
function openim::api::start() {
+ rm -rf "$TMP_LOG_FILE"
+
echo "++ OPENIM_API_SERVICE_LISTARIES: ${OPENIM_API_SERVICE_LISTARIES[@]}"
echo "++ OPENIM_API_PORT_LISTARIES: ${OPENIM_API_PORT_LISTARIES[@]}"
echo "++ OpenIM API config path: ${OPENIM_API_CONFIG}"
-
+
openim::log::info "Starting ${SERVER_NAME} ..."
-
+
+ readonly OPENIM_API_SERVER_LIBRARIES="${OPENIM_OUTPUT_HOSTBIN}/${SERVER_NAME}"
+
+
printf "+------------------------+--------------+\n"
printf "| Service Name | Port |\n"
printf "+------------------------+--------------+\n"
-
- length=${#OPENIM_API_SERVICE_LISTARIES[@]}
-
- for ((i=0; i<$length; i++)); do
+
+
+ local length=${#OPENIM_API_SERVICE_LISTARIES[@]}
+ for ((i=0; i> "${LOG_FILE}" 2>&1 &
+ # Append Prometheus port argument if specified
+ if [ -n "${prometheus_port}" ]; then
+ cmd+=" --prometheus_port ${prometheus_port}"
+ fi
+
+ echo "Starting service with command: $cmd"
+ #nohup $cmd >> "${LOG_FILE}" 2> >(tee -a "${STDERR_LOG_FILE}" "$TMP_LOG_FILE" >&2) &
+ nohup ${cmd} >> "${LOG_FILE}" 2> >(tee -a "$TMP_LOG_FILE" | while read line; do echo -e "\e[31m${line}\e[0m"; done >&2) >/dev/null &
if [ $? -ne 0 ]; then
openim::log::error_exit "Failed to start ${binary_name} on port ${service_port}."
+ return 1
fi
+ return 0
}
###################################### Linux Systemd ######################################
@@ -138,7 +147,7 @@ function openim::api::uninstall() {
openim::common::sudo "rm -f ${OPENIM_INSTALL_DIR}/${SERVER_NAME}"
openim::common::sudo "rm -f ${OPENIM_CONFIG_DIR}/${SERVER_NAME}.yaml"
openim::common::sudo "rm -f /etc/systemd/system/${SERVER_NAME}.service"
- set -o errexit
+
openim::log::info "uninstall ${SERVER_NAME} successfully"
}
diff --git a/scripts/install/openim-crontask.sh b/scripts/install/openim-crontask.sh
index cc9e686ff..191701082 100755
--- a/scripts/install/openim-crontask.sh
+++ b/scripts/install/openim-crontask.sh
@@ -44,14 +44,18 @@ OPENIM_ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")"/../.. && pwd -P)
SERVER_NAME="openim-crontask"
function openim::crontask::start() {
+
+ rm -rf "$TMP_LOG_FILE"
+
openim::log::info "Start OpenIM Cron, binary root: ${SERVER_NAME}"
openim::log::status "Start OpenIM Cron, path: ${OPENIM_CRONTASK_BINARY}"
-
- openim::util::stop_services_with_name ${OPENIM_CRONTASK_BINARY}
-
+
openim::log::status "start cron_task process, path: ${OPENIM_CRONTASK_BINARY}"
- nohup ${OPENIM_CRONTASK_BINARY} -c ${OPENIM_PUSH_CONFIG} >> ${LOG_FILE} 2>&1 &
- openim::util::check_process_names ${SERVER_NAME}
+ #nohup ${OPENIM_CRONTASK_BINARY} -c ${OPENIM_PUSH_CONFIG} >> ${LOG_FILE} 2> >(tee -a "${STDERR_LOG_FILE}" "$TMP_LOG_FILE" >&2) &
+ cmd="${OPENIM_CRONTASK_BINARY} -c ${OPENIM_PUSH_CONFIG}"
+ nohup ${cmd} >> "${LOG_FILE}" 2> >(tee -a "$TMP_LOG_FILE" | while read line; do echo -e "\e[31m${line}\e[0m"; done >&2) >/dev/null &
+ return 0
+
}
###################################### Linux Systemd ######################################
@@ -102,7 +106,7 @@ function openim::crontask::uninstall() {
openim::common::sudo "rm -f ${OPENIM_INSTALL_DIR}/${SERVER_NAME}"
openim::common::sudo "rm -f ${OPENIM_CONFIG_DIR}/${SERVER_NAME}.yaml"
openim::common::sudo "rm -f /etc/systemd/system/${SERVER_NAME}.service"
- set -o errexit
+
openim::log::info "uninstall ${SERVER_NAME} successfully"
}
diff --git a/scripts/install/openim-man.sh b/scripts/install/openim-man.sh
index fac5cebea..642588a28 100755
--- a/scripts/install/openim-man.sh
+++ b/scripts/install/openim-man.sh
@@ -76,7 +76,7 @@ function openim::man::uninstall() {
# Turn off exit-on-error temporarily to handle non-existing files gracefully
set +o errexit
openim::common::sudo "rm -f /usr/share/man/man1/openim-*"
- set -o errexit
+
openim::log::info "Uninstalled openim man pages successfully"
}
diff --git a/scripts/install/openim-msggateway.sh b/scripts/install/openim-msggateway.sh
index d9fec4928..25051aa6e 100755
--- a/scripts/install/openim-msggateway.sh
+++ b/scripts/install/openim-msggateway.sh
@@ -14,22 +14,23 @@
# limitations under the License.
# Common utilities, variables and checks for all build scripts.
-set -o errexit
-set +o nounset
-set -o pipefail
+
+
+
OPENIM_ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")"/../.. && pwd -P)
[[ -z ${COMMON_SOURCED} ]] && source "${OPENIM_ROOT}"/scripts/install/common.sh
-openim::util::set_max_fd 200000
SERVER_NAME="openim-msggateway"
function openim::msggateway::start() {
+
+ rm -rf "$TMP_LOG_FILE"
+
openim::log::info "Start OpenIM Msggateway, binary root: ${SERVER_NAME}"
openim::log::status "Start OpenIM Msggateway, path: ${OPENIM_MSGGATEWAY_BINARY}"
-
- openim::util::stop_services_with_name ${OPENIM_MSGGATEWAY_BINARY}
+
# OpenIM message gateway service port
OPENIM_MESSAGE_GATEWAY_PORTS=$(openim::util::list-to-string ${OPENIM_MESSAGE_GATEWAY_PORT} )
@@ -60,11 +61,12 @@ function openim::msggateway::start() {
if [[ -n "${MSG_GATEWAY_PROM_PORTS_ARRAY[$i]}" ]]; then
PROMETHEUS_PORT_OPTION="--prometheus_port ${MSG_GATEWAY_PROM_PORTS_ARRAY[$i]}"
fi
+ cmd="${OPENIM_MSGGATEWAY_BINARY} --port ${OPENIM_MSGGATEWAY_PORTS_ARRAY[$i]} --ws_port ${OPENIM_WS_PORTS_ARRAY[$i]} $PROMETHEUS_PORT_OPTION -c ${OPENIM_MSGGATEWAY_CONFIG}"
+ nohup ${cmd} >> "${LOG_FILE}" 2> >(tee -a "$TMP_LOG_FILE" | while read line; do echo -e "\e[31m${line}\e[0m"; done >&2) >/dev/null &
+ # nohup ${OPENIM_MSGGATEWAY_BINARY} --port ${OPENIM_MSGGATEWAY_PORTS_ARRAY[$i]} --ws_port ${OPENIM_WS_PORTS_ARRAY[$i]} $PROMETHEUS_PORT_OPTION -c ${OPENIM_MSGGATEWAY_CONFIG} >> ${LOG_FILE} 2> >(tee -a "${STDERR_LOG_FILE}" "$TMP_LOG_FILE" >&2) &
- nohup ${OPENIM_MSGGATEWAY_BINARY} --port ${OPENIM_MSGGATEWAY_PORTS_ARRAY[$i]} --ws_port ${OPENIM_WS_PORTS_ARRAY[$i]} $PROMETHEUS_PORT_OPTION -c ${OPENIM_MSGGATEWAY_CONFIG} >> ${LOG_FILE} 2>&1 &
done
-
- openim::util::check_process_names ${SERVER_NAME}
+ return 0
}
###################################### Linux Systemd ######################################
@@ -114,7 +116,7 @@ function openim::msggateway::uninstall() {
openim::common::sudo "rm -f ${OPENIM_INSTALL_DIR}/${SERVER_NAME}"
openim::common::sudo "rm -f ${OPENIM_CONFIG_DIR}/${SERVER_NAME}.yaml"
openim::common::sudo "rm -f /etc/systemd/system/${SERVER_NAME}.service"
- set -o errexit
+
openim::log::info "uninstall ${SERVER_NAME} successfully"
}
diff --git a/scripts/install/openim-msgtransfer.sh b/scripts/install/openim-msgtransfer.sh
index 1cead3a9a..23ce79c36 100755
--- a/scripts/install/openim-msgtransfer.sh
+++ b/scripts/install/openim-msgtransfer.sh
@@ -16,26 +16,25 @@
# ./scripts/install/openim-msgtransfer.sh openim::msgtransfer::start
# Common utilities, variables and checks for all build scripts.
-set -o errexit
-set +o nounset
-set -o pipefail
+
+
+
OPENIM_ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")"/../.. && pwd -P)
[[ -z ${COMMON_SOURCED} ]] && source "${OPENIM_ROOT}"/scripts/install/common.sh
-openim::util::set_max_fd 200000
-
SERVER_NAME="openim-msgtransfer"
function openim::msgtransfer::start() {
+
+ rm -rf "$TMP_LOG_FILE"
+
openim::log::info "Start OpenIM Msggateway, binary root: ${SERVER_NAME}"
openim::log::status "Start OpenIM Msggateway, path: ${OPENIM_MSGTRANSFER_BINARY}"
-
- openim::util::stop_services_with_name ${OPENIM_MSGTRANSFER_BINARY}
-
+
# Message Transfer Prometheus port list
MSG_TRANSFER_PROM_PORTS=(openim::util::list-to-string ${MSG_TRANSFER_PROM_PORT} )
-
+
openim::log::status "OpenIM Prometheus ports: ${MSG_TRANSFER_PROM_PORTS[*]}"
openim::log::status "OpenIM Msggateway config path: ${OPENIM_MSGTRANSFER_CONFIG}"
@@ -43,32 +42,36 @@ function openim::msgtransfer::start() {
openim::log::info "openim maggateway num: ${OPENIM_MSGGATEWAY_NUM}"
if [ "${OPENIM_MSGGATEWAY_NUM}" -lt 1 ]; then
- opeim::log::error_exit "OPENIM_MSGGATEWAY_NUM must be greater than 0"
+ opeim::log::error "OPENIM_MSGGATEWAY_NUM must be greater than 0"
fi
if [ ${OPENIM_MSGGATEWAY_NUM} -ne $((${#MSG_TRANSFER_PROM_PORTS[@]} - 1)) ]; then
- openim::log::error_exit "OPENIM_MSGGATEWAY_NUM must be equal to the number of MSG_TRANSFER_PROM_PORTS"
+ openim::log::error "OPENIM_MSGGATEWAY_NUM must be equal to the number of MSG_TRANSFER_PROM_PORTS"
fi
for (( i=0; i<$OPENIM_MSGGATEWAY_NUM; i++ )) do
- openim::log::info "prometheus port: ${MSG_TRANSFER_PROM_PORTS[$i]}"
- PROMETHEUS_PORT_OPTION=""
- if [[ -n "${OPENIM_PROMETHEUS_PORTS[$i]}" ]]; then
- PROMETHEUS_PORT_OPTION="--prometheus_port ${OPENIM_PROMETHEUS_PORTS[$i]}"
- fi
- nohup ${OPENIM_MSGTRANSFER_BINARY} ${PROMETHEUS_PORT_OPTION} -c ${OPENIM_MSGTRANSFER_CONFIG} -n ${i}>> ${LOG_FILE} 2>&1 &
+ openim::log::info "prometheus port: ${MSG_TRANSFER_PROM_PORTS[$i]}"
+ PROMETHEUS_PORT_OPTION=""
+ if [[ -n "${MSG_TRANSFER_PROM_PORTS[$i+1]}" ]]; then
+ PROMETHEUS_MSG_TRANSFER_PORT="${MSG_TRANSFER_PROM_PORTS[$i+1]%,}"
+ openim::util::stop_services_on_ports ${PROMETHEUS_MSG_TRANSFER_PORT}
+ PROMETHEUS_PORT_OPTION="--prometheus_port ${PROMETHEUS_MSG_TRANSFER_PORT}"
+ fi
+ cmd="${OPENIM_MSGTRANSFER_BINARY} ${PROMETHEUS_PORT_OPTION} -c ${OPENIM_MSGTRANSFER_CONFIG} -n ${i}"
+ nohup ${cmd} >> "${LOG_FILE}" 2> >(tee -a "$TMP_LOG_FILE" | while read line; do echo -e "\e[31m${line}\e[0m"; done >&2) >/dev/null &
+ #nohup ${OPENIM_MSGTRANSFER_BINARY} ${PROMETHEUS_PORT_OPTION} -c ${OPENIM_MSGTRANSFER_CONFIG} -n ${i} >> ${LOG_FILE} 2> >(tee -a "${STDERR_LOG_FILE}" "$TMP_LOG_FILE" >&2) &
done
-
- openim::util::check_process_names "${OPENIM_OUTPUT_HOSTBIN}/${SERVER_NAME}"
+ return 0
}
function openim::msgtransfer::check() {
PIDS=$(pgrep -f "${OPENIM_OUTPUT_HOSTBIN}/openim-msgtransfer")
-
- NUM_PROCESSES=$(echo "$PIDS" | wc -l)
-
+ if [ -z "$PIDS" ]; then
+ NUM_PROCESSES=0
+ else
+ NUM_PROCESSES=$(echo "$PIDS" | wc -l)
+ fi
if [ "$NUM_PROCESSES" -eq "$OPENIM_MSGGATEWAY_NUM" ]; then
- openim::log::info "Found $OPENIM_MSGGATEWAY_NUM processes named $OPENIM_OUTPUT_HOSTBIN"
for PID in $PIDS; do
if [[ "$OSTYPE" == "linux-gnu"* ]]; then
ps -p $PID -o pid,cmd
@@ -79,10 +82,39 @@ function openim::msgtransfer::check() {
fi
done
else
- openim::log::error_exit "Expected $OPENIM_MSGGATEWAY_NUM openim msgtransfer processes, but found $NUM_PROCESSES msgtransfer processes."
+ openim::log::error "Expected $OPENIM_MSGGATEWAY_NUM openim msgtransfer processes, but found $NUM_PROCESSES msgtransfer processes."
+ return 1
fi
+ return 0
}
+function openim::msgtransfer::check_for_stop() {
+ PIDS=$(pgrep -f "${OPENIM_OUTPUT_HOSTBIN}/openim-msgtransfer") || PIDS="0"
+ if [ "$PIDS" = "0" ]; then
+ return 0
+ fi
+
+ NUM_PROCESSES=$(echo "$PIDS" | wc -l | xargs)
+
+ if [ "$NUM_PROCESSES" -gt 0 ]; then
+ openim::log::error "Found $NUM_PROCESSES processes for $OPENIM_OUTPUT_HOSTBIN/openim-msgtransfer"
+ for PID in $PIDS; do
+ if [[ "$OSTYPE" == "linux-gnu"* ]]; then
+ echo -e "\033[31m$(ps -p $PID -o pid,cmd)\033[0m"
+ elif [[ "$OSTYPE" == "darwin"* ]]; then
+ echo -e "\033[31m$(ps -p $PID -o pid,comm)\033[0m"
+ else
+ openim::log::error "Unsupported OS type: $OSTYPE"
+ fi
+ done
+ openim::log::error "Processes have not been stopped properly."
+ else
+ openim::log::success "All openim-msgtransfer processes have been stopped properly."
+ fi
+ return 0
+}
+
+
###################################### Linux Systemd ######################################
SYSTEM_FILE_PATH="/etc/systemd/system/${SERVER_NAME}.service"
@@ -133,7 +165,7 @@ function openim::msgtransfer::uninstall() {
openim::common::sudo "rm -f ${OPENIM_INSTALL_DIR}/${SERVER_NAME}"
openim::common::sudo "rm -f ${OPENIM_CONFIG_DIR}/${SERVER_NAME}.yaml"
openim::common::sudo "rm -f /etc/systemd/system/${SERVER_NAME}.service"
- set -o errexit
+
openim::log::info "uninstall ${SERVER_NAME} successfully"
}
diff --git a/scripts/install/openim-push.sh b/scripts/install/openim-push.sh
index d43743e4f..8dea4b1f1 100755
--- a/scripts/install/openim-push.sh
+++ b/scripts/install/openim-push.sh
@@ -40,9 +40,9 @@
#
# Note: Ensure that the appropriate permissions and environmental variables are set prior to script execution.
#
-set -o errexit
-set +o nounset
-set -o pipefail
+
+
+
OPENIM_ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")"/../.. && pwd -P)
[[ -z ${COMMON_SOURCED} ]] && source "${OPENIM_ROOT}"/scripts/install/common.sh
@@ -50,6 +50,9 @@ OPENIM_ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")"/../.. && pwd -P)
SERVER_NAME="openim-push"
function openim::push::start() {
+
+ rm -rf "$TMP_LOG_FILE"
+
openim::log::status "Start OpenIM Push, binary root: ${SERVER_NAME}"
openim::log::info "Start OpenIM Push, path: ${OPENIM_PUSH_BINARY}"
@@ -58,22 +61,22 @@ function openim::push::start() {
OPENIM_PUSH_PORTS_ARRAY=$(openim::util::list-to-string ${OPENIM_PUSH_PORT} )
PUSH_PROM_PORTS_ARRAY=$(openim::util::list-to-string ${PUSH_PROM_PORT} )
-
- openim::util::stop_services_with_name ${SERVER_NAME}
-
+
openim::log::status "push port list: ${OPENIM_PUSH_PORTS_ARRAY[@]}"
openim::log::status "prometheus port list: ${PUSH_PROM_PORTS_ARRAY[@]}"
if [ ${#OPENIM_PUSH_PORTS_ARRAY[@]} -ne ${#PUSH_PROM_PORTS_ARRAY[@]} ]; then
- openim::log::error_exit "The length of the two port lists is different!"
+ openim::log::error "The length of the two port lists is different!"
fi
for (( i=0; i<${#OPENIM_PUSH_PORTS_ARRAY[@]}; i++ )); do
openim::log::info "start push process, port: ${OPENIM_PUSH_PORTS_ARRAY[$i]}, prometheus port: ${PUSH_PROM_PORTS_ARRAY[$i]}"
- nohup ${OPENIM_PUSH_BINARY} --port ${OPENIM_PUSH_PORTS_ARRAY[$i]} -c ${OPENIM_PUSH_CONFIG} --prometheus_port ${PUSH_PROM_PORTS_ARRAY[$i]} >> ${LOG_FILE} 2>&1 &
+ cmd="${OPENIM_PUSH_BINARY} --port ${OPENIM_PUSH_PORTS_ARRAY[$i]} -c ${OPENIM_PUSH_CONFIG} --prometheus_port ${PUSH_PROM_PORTS_ARRAY[$i]}"
+ nohup ${cmd} >> "${LOG_FILE}" 2> >(tee -a "$TMP_LOG_FILE" | while read line; do echo -e "\e[31m${line}\e[0m"; done >&2) >/dev/null &
+ #nohup ${OPENIM_PUSH_BINARY} --port ${OPENIM_PUSH_PORTS_ARRAY[$i]} -c ${OPENIM_PUSH_CONFIG} --prometheus_port ${PUSH_PROM_PORTS_ARRAY[$i]} >> ${LOG_FILE} 2> >(tee -a "${STDERR_LOG_FILE}" "$TMP_LOG_FILE" >&2) &
done
-
- openim::util::check_process_names ${SERVER_NAME}
+ return 0
+
}
###################################### Linux Systemd ######################################
@@ -122,7 +125,7 @@ function openim::push::uninstall() {
openim::common::sudo "rm -f ${OPENIM_INSTALL_DIR}/${SERVER_NAME}"
openim::common::sudo "rm -f ${OPENIM_CONFIG_DIR}/${SERVER_NAME}.yaml"
openim::common::sudo "rm -f /etc/systemd/system/${SERVER_NAME}.service"
- set -o errexit
+
openim::log::info "uninstall ${SERVER_NAME} successfully"
}
diff --git a/scripts/install/openim-rpc.sh b/scripts/install/openim-rpc.sh
index 966eef928..c3ac12449 100755
--- a/scripts/install/openim-rpc.sh
+++ b/scripts/install/openim-rpc.sh
@@ -38,10 +38,6 @@
# Note: Before executing this script, ensure that the necessary permissions are granted and relevant environmental variables are set.
#
-set -o errexit
-set +o nounset
-set -o pipefail
-
OPENIM_ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")"/../.. && pwd -P)
[[ -z ${COMMON_SOURCED} ]] && source "${OPENIM_ROOT}"/scripts/install/common.sh
@@ -64,6 +60,16 @@ IFS=" " read -ra OPENIM_RPC_SERVICE_TARGETS <<< "$(openim::rpc::service_name)"
readonly OPENIM_RPC_SERVICE_TARGETS
readonly OPENIM_RPC_SERVICE_LISTARIES=("${OPENIM_RPC_SERVICE_TARGETS[@]##*/}")
+
+OPENIM_ALL_RPC_FULL_PATH=()
+for target in openim::rpc::service_name; do
+ OPENIM_ALL_RPC_FULL_PATH+=("${OPENIM_OUTPUT_HOSTBIN}/${target}")
+done
+readonly OPENIM_ALL_RPC_FULL_PATH
+
+
+
+
# Make sure the environment is only called via common to avoid too much nesting
openim::rpc::service_port() {
local targets=(
@@ -102,6 +108,8 @@ readonly OPENIM_RPC_PROM_PORT_TARGETS
readonly OPENIM_RPC_PROM_PORT_LISTARIES=("${OPENIM_RPC_PROM_PORT_TARGETS[@]##*/}")
function openim::rpc::start() {
+ rm -rf "$TMP_LOG_FILE"
+
echo "OPENIM_RPC_SERVICE_LISTARIES: ${OPENIM_RPC_SERVICE_LISTARIES[@]}"
echo "OPENIM_RPC_PROM_PORT_LISTARIES: ${OPENIM_RPC_PROM_PORT_LISTARIES[@]}"
echo "OPENIM_RPC_PORT_LISTARIES: ${OPENIM_RPC_PORT_LISTARIES[@]}"
@@ -119,13 +127,11 @@ function openim::rpc::start() {
printf "+------------------------+-------+-----------------+\n"
done
+
# start all rpc services
for ((i = 0; i < ${#OPENIM_RPC_SERVICE_LISTARIES[*]}; i++)); do
- # openim::util::stop_services_with_name ${OPENIM_RPC_SERVICE_LISTARIES
- openim::util::stop_services_on_ports ${OPENIM_RPC_PORT_LISTARIES[$i]}
openim::log::info "OpenIM ${OPENIM_RPC_SERVICE_LISTARIES[$i]} config path: ${OPENIM_RPC_CONFIG}"
-
# Get the service and Prometheus ports.
OPENIM_RPC_SERVICE_PORTS=( $(openim::util::list-to-string ${OPENIM_RPC_PORT_LISTARIES[$i]}) )
read -a OPENIM_RPC_SERVICE_PORTS_ARRAY <<< ${OPENIM_RPC_SERVICE_PORTS}
@@ -135,15 +141,17 @@ function openim::rpc::start() {
for ((j = 0; j < ${#OPENIM_RPC_SERVICE_PORTS_ARRAY[@]}; j++)); do
openim::log::info "Starting ${OPENIM_RPC_SERVICE_LISTARIES[$i]} service, port: ${OPENIM_RPC_SERVICE_PORTS[j]}, prometheus port: ${OPENIM_RPC_PROM_PORTS[j]}, binary root: ${OPENIM_OUTPUT_HOSTBIN}/${OPENIM_RPC_SERVICE_LISTARIES[$i]}"
- openim::rpc::start_service "${OPENIM_RPC_SERVICE_LISTARIES[$i]}" "${OPENIM_RPC_SERVICE_PORTS[j]}" "${OPENIM_RPC_PROM_PORTS[j]}"
+ result=$(openim::rpc::start_service "${OPENIM_RPC_SERVICE_LISTARIES[$i]}" "${OPENIM_RPC_SERVICE_PORTS[j]}" "${OPENIM_RPC_PROM_PORTS[j]}")
+ if [[ $? -ne 0 ]]; then
+ openim::log::error "start ${SERVER_NAME} failed"
+ else
+ openim::log::info "$result"
+ fi
done
done
- sleep 5
-
- openim::util::check_ports ${OPENIM_RPC_PORT_TARGETS[@]}
- # openim::util::check_ports ${OPENIM_RPC_PROM_PORT_TARGETS[@]}
+ return 0
}
function openim::rpc::start_service() {
@@ -157,7 +165,9 @@ function openim::rpc::start_service() {
printf "Specifying prometheus port: %s\n" "${prometheus_port}"
cmd="${cmd} --prometheus_port ${prometheus_port}"
fi
- nohup ${cmd} >> "${LOG_FILE}" 2>&1 &
+ #nohup ${cmd} >> "${LOG_FILE}" 2> >(tee -a "${STDERR_LOG_FILE}" "$TMP_LOG_FILE" >&2) &
+ nohup ${cmd} >> "${LOG_FILE}" 2> >(tee -a "$TMP_LOG_FILE" | while read line; do echo -e "\e[31m${line}\e[0m"; done >&2) >/dev/null &
+ return 0
}
###################################### Linux Systemd ######################################
@@ -217,7 +227,7 @@ function openim::rpc::uninstall() {
openim::common::sudo "rm -f ${OPENIM_CONFIG_DIR}/${service}.yaml"
openim::common::sudo "rm -f ${SYSTEM_FILE_PATHS[$service]}"
done
- set -o errexit
+
openim::log::info "uninstall openim-rpc successfully"
}
diff --git a/scripts/install/openim-tools.sh b/scripts/install/openim-tools.sh
index ac60a5f45..4eb722c6e 100755
--- a/scripts/install/openim-tools.sh
+++ b/scripts/install/openim-tools.sh
@@ -38,9 +38,6 @@
# Example: ./openim-tools.sh openim::tools::install
#
-set -o errexit
-set +o nounset
-set -o pipefail
OPENIM_ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")"/../.. && pwd -P)
[[ -z ${COMMON_SOURCED} ]] && source "${OPENIM_ROOT}"/scripts/install/common.sh
@@ -103,14 +100,14 @@ function openim::tools::start_service() {
printf "Specifying prometheus port: %s\n" "${prometheus_port}"
cmd="${cmd} --prometheus_port ${prometheus_port}"
fi
- openim::log::status "Starting ${binary_name}..."
+ openim::log::status "Starting binary ${binary_name}..."
${cmd} | tee -a "${LOG_FILE}"
}
function openim::tools::start() {
openim::log::info "Starting OpenIM Tools..."
for tool in "${OPENIM_TOOLS_NAME_LISTARIES[@]}"; do
- openim::log::info "Starting ${tool}..."
+ openim::log::info "Starting tool ${tool}..."
# openim::tools::start_service ${tool}
sleep 0.2
done
@@ -120,18 +117,16 @@ function openim::tools::start() {
function openim::tools::pre-start() {
openim::log::info "Preparing to start OpenIM Tools..."
for tool in "${OPENIM_TOOLS_PRE_START_NAME_LISTARIES[@]}"; do
- openim::log::info "Starting ${tool}..."
+ openim::log::info "Starting tool ${tool}..."
openim::tools::start_service ${tool} ${OPNEIM_CONFIG}
- sleep 0.2
done
}
function openim::tools::post-start() {
openim::log::info "Post-start actions for OpenIM Tools..."
for tool in "${OPENIM_TOOLS_POST_START_NAME_LISTARIES[@]}"; do
- openim::log::info "Starting ${tool}..."
+ openim::log::info "Starting tool ${tool}..."
openim::tools::start_service ${tool}
- sleep 0.2
done
}
diff --git a/scripts/install/test.sh b/scripts/install/test.sh
index 4a78e4504..4ea3f16ca 100755
--- a/scripts/install/test.sh
+++ b/scripts/install/test.sh
@@ -34,8 +34,8 @@
#
# The root of the build/dist directory
-IAM_ROOT=$(dirname "${BASH_SOURCE[0]}")/../..
-[[ -z ${COMMON_SOURCED} ]] && source ${IAM_ROOT}/scripts/install/common.sh
+OPENIM_ROOT=$(dirname "${BASH_SOURCE[0]}")/../..
+[[ -z ${COMMON_SOURCED} ]] && source ${OPENIM_ROOT}/scripts/install/common.sh
# API Server API Address:Port
INSECURE_OPENIMAPI="http://${OPENIM_API_HOST}:${API_OPENIM_PORT}"
@@ -72,7 +72,7 @@ function openim::test::auth() {
# Define a function to get a token for a specific user
openim::test::get_token() {
- local user_id="${1:-openIM123456}" # Default user ID if not provided
+ local user_id="${1:-imAdmin}" # Default user ID if not provided
token_response=$(
${CCURL} "${OperationID}" "${Header}" ${INSECURE_OPENIMAPI}/auth/user_token \
-d'{"secret": "'"$SECRET"'","platformID": 1,"userID": "'$user_id'"}'
@@ -142,10 +142,7 @@ openim::test::check_user_account() {
cat <&2
+ # Apply red color for error message
+ echo_log "${red}!!! ${timestamp} ${1-}${nc}" >&2
shift
for message; do
- echo_log " ${message}" >&2
+ # Apply red color for subsequent lines of the error message
+ echo_log "${red} ${message}${nc}" >&2
done
}
+
# Print an usage message to stderr. The arguments are printed directly.
openim::log::usage() {
echo_log >&2
@@ -193,22 +206,27 @@ openim::log::status() {
fi
timestamp=$(date +"[%Y-%m-%d %H:%M:%S %Z]")
- echo_log "+++ ${timestamp} ${1}"
+ echo_log "${timestamp} ${1}"
shift
for message; do
echo_log " ${message}"
done
}
+
openim::log::success() {
local V="${V:-0}"
if [[ ${OPENIM_VERBOSE} < ${V} ]]; then
return
fi
- timestamp=$(date +"%m%d %H:%M:%S")
- echo_log -e "${COLOR_GREEN}[success ${timestamp}] ${COLOR_SUFFIX}==> " "$@"
+ local timestamp=$(date +"%m%d %H:%M:%S")
+ local reset_color='\033[0m'
+ echo_log -e "${COLOR_GREEN}[success ${timestamp}]${COLOR_SUFFIX}==> ${COLOR_GREEN}$@${reset_color}"
}
+
+
+
function openim::log::test_log() {
echo_log "test log"
openim::log::info "openim::log::info"
@@ -219,4 +237,9 @@ function openim::log::test_log() {
openim::log::error_exit "openim::log::error_exit"
}
-# openim::log::test_log
\ No newline at end of file
+# openim::log::test_log
+
+function openim::log::print_blue() {
+ echo -e "\033[0;36m$1\033[0m"
+}
+
diff --git a/scripts/lib/release.sh b/scripts/lib/release.sh
index 521e5cedc..c1fbd00a1 100755
--- a/scripts/lib/release.sh
+++ b/scripts/lib/release.sh
@@ -152,6 +152,7 @@ function openim::release::package_src_tarball() {
-path "${OPENIM_ROOT}"/.github\* -o \
-path "${OPENIM_ROOT}"/components\* -o \
-path "${OPENIM_ROOT}"/logs\* -o \
+ -path "${OPENIM_ROOT}"/_output\* -o \
-path "${OPENIM_ROOT}"/.gitignore\* -o \
-path "${OPENIM_ROOT}"/.gsemver.yml\* -o \
-path "${OPENIM_ROOT}"/.config\* -o \
diff --git a/scripts/lib/util.sh b/scripts/lib/util.sh
index a40668d70..d84562c1d 100755
--- a/scripts/lib/util.sh
+++ b/scripts/lib/util.sh
@@ -298,7 +298,7 @@ openim::util::check_ports() {
# An array to collect information about processes that are running.
local started=()
- openim::log::info "Checking ports: $*"
+ echo "Checking ports: $*"
# Iterate over each given port.
for port in "$@"; do
# Initialize variables
@@ -344,7 +344,7 @@ openim::util::check_ports() {
# Print information about ports whose processes are not running.
if [[ ${#not_started[@]} -ne 0 ]]; then
- openim::log::info "\n### Not started ports:"
+ echo "### Not started ports:"
for port in "${not_started[@]}"; do
openim::log::error "Port $port is not started."
done
@@ -352,18 +352,20 @@ openim::util::check_ports() {
# Print information about ports whose processes are running.
if [[ ${#started[@]} -ne 0 ]]; then
- openim::log::info "\n### Started ports:"
+ echo "### Started ports:"
for info in "${started[@]}"; do
- openim::log::info "$info"
+ echo "$info"
done
fi
# If any of the processes is not running, return a status of 1.
if [[ ${#not_started[@]} -ne 0 ]]; then
- echo "++++ OpenIM Log >> cat ${LOG_FILE}"
+ openim::color::echo $COLOR_RED "OpenIM Stdout Log >> cat ${LOG_FILE}"
+ openim::color::echo $COLOR_RED "OpenIM Stderr Log >> cat ${STDERR_LOG_FILE}"
+ cat "$TMP_LOG_FILE" | awk '{print "\033[31m" $0 "\033[0m"}'
return 1
else
- openim::log::success "All specified processes are running."
+ #openim::log::success "All specified ports are running."
return 0
fi
}
@@ -371,7 +373,7 @@ openim::util::check_ports() {
# set +o errexit
# Sample call for testing:
# openim::util::check_ports 10002 1004 12345 13306
-# set -o errexit
+#
# The `openim::util::check_process_names` function analyzes the state of processes based on given names.
# It accepts multiple process names as arguments and prints:
@@ -399,13 +401,88 @@ openim::util::check_process_names() {
# Arrays to collect details of processes
local not_started=()
local started=()
+
+ # Iterate over each given process name
+ for process_name in "$@"; do
+ # Use `pgrep` to find process IDs related to the given process name
+ local pids=($(pgrep -f $process_name))
+
+ # Check if any process IDs were found
+ if [[ ${#pids[@]} -eq 0 ]]; then
+ not_started+=($process_name)
+ else
+ # If there are PIDs, loop through each one
+ for pid in "${pids[@]}"; do
+ local command=$(ps -p $pid -o cmd=)
+ local start_time=$(ps -p $pid -o lstart=)
+ local port=$(get_port $pid)
+
+ # Check if port information was found for the PID
+ if [[ -z $port ]]; then
+ port="N/A"
+ fi
+
+ started+=("Process $process_name - Command: $command, PID: $pid, Port: $port, Start time: $start_time")
+ done
+ fi
+ done
+
- openim::log::info "Checking processes: $*"
+ # Print information
+ if [[ ${#not_started[@]} -ne 0 ]]; then
+ echo "Not started processes:"
+ for process_name in "${not_started[@]}"; do
+ echo "Process $process_name is not started."
+ done
+ fi
+
+ if [[ ${#started[@]} -ne 0 ]]; then
+ echo
+ echo "Started processes:"
+ for info in "${started[@]}"; do
+ echo "$info"
+ done
+ fi
+
+ # Return status
+ if [[ ${#not_started[@]} -ne 0 ]]; then
+ openim::color::echo $COLOR_RED "OpenIM Stdout Log >> cat ${LOG_FILE}"
+ openim::color::echo $COLOR_RED "OpenIM Stderr Log >> cat ${STDERR_LOG_FILE}"
+ cat "$TMP_LOG_FILE" | awk '{print "\033[31m" $0 "\033[0m"}'
+ return 1
+ else
+ echo ""
+ openim::log::success "All processes are running."
+ return 0
+ fi
+}
+
+openim::util::check_process_names_for_stop() {
+ # Function to get the port of a process
+ get_port() {
+ local pid=$1
+ if [[ "$OSTYPE" == "linux-gnu"* ]]; then
+ # Linux
+ ss -ltnp 2>/dev/null | grep $pid | awk '{print $4}' | cut -d ':' -f2
+ elif [[ "$OSTYPE" == "darwin"* ]]; then
+ # macOS
+ lsof -nP -iTCP -sTCP:LISTEN -a -p $pid | awk 'NR>1 {print $9}' | sed 's/.*://'
+ else
+ echo "Unsupported OS"
+ return 1
+ fi
+ }
+
+ # Arrays to collect details of processes
+ local not_started=()
+ local started=()
+
+
# Iterate over each given process name
for process_name in "$@"; do
# Use `pgrep` to find process IDs related to the given process name
local pids=($(pgrep -f $process_name))
-
+
# Check if any process IDs were found
if [[ ${#pids[@]} -eq 0 ]]; then
not_started+=($process_name)
@@ -415,41 +492,29 @@ openim::util::check_process_names() {
local command=$(ps -p $pid -o cmd=)
local start_time=$(ps -p $pid -o lstart=)
local port=$(get_port $pid)
-
+
# Check if port information was found for the PID
if [[ -z $port ]]; then
port="N/A"
fi
-
+
started+=("Process $process_name - Command: $command, PID: $pid, Port: $port, Start time: $start_time")
done
fi
done
-
- # Print information
- if [[ ${#not_started[@]} -ne 0 ]]; then
- openim::log::info "Not started processes:"
- for process_name in "${not_started[@]}"; do
- openim::log::error "Process $process_name is not started."
- done
- fi
-
+
+
if [[ ${#started[@]} -ne 0 ]]; then
echo
- openim::log::info "Started processes:"
+ echo "The programs that have not exited are:"
for info in "${started[@]}"; do
- openim::log::info "$info"
+ echo "$info "
done
- fi
-
- # Return status
- if [[ ${#not_started[@]} -ne 0 ]]; then
- echo "++++ OpenIM Log >> cat ${LOG_FILE}"
return 1
- else
- openim::log::success "All processes are running."
- return 0
fi
+
+ return 0
+
}
# openim::util::check_process_names docker-pr
@@ -468,7 +533,7 @@ openim::util::stop_services_on_ports() {
# An array to collect information about processes that were stopped.
local stopped=()
- openim::log::info "Stopping services on ports: $*"
+ echo "Stopping services on ports: $*"
# Iterate over each given port.
for port in "$@"; do
# Use the `lsof` command to find process information related to the given port.
@@ -481,7 +546,7 @@ openim::util::stop_services_on_ports() {
local pid=$(echo $line | awk '{print $2}')
# Try to stop the service by killing its process.
- if kill -TERM $pid; then
+ if kill -15 $pid; then
stopped+=($port)
else
not_stopped+=($port)
@@ -492,7 +557,7 @@ openim::util::stop_services_on_ports() {
# Print information about ports whose processes couldn't be stopped.
if [[ ${#not_stopped[@]} -ne 0 ]]; then
- openim::log::info "Ports that couldn't be stopped:"
+ echo "Ports that couldn't be stopped:"
for port in "${not_stopped[@]}"; do
openim::log::status "Failed to stop service on port $port."
done
@@ -500,10 +565,8 @@ openim::util::stop_services_on_ports() {
# Print information about ports whose processes were successfully stopped.
if [[ ${#stopped[@]} -ne 0 ]]; then
- echo
- openim::log::info "Stopped services on ports:"
for port in "${stopped[@]}"; do
- openim::log::info "Successfully stopped service on port $port."
+ echo "Successfully stopped service on port $port."
done
fi
@@ -536,7 +599,7 @@ openim::util::stop_services_with_name() {
# An array to collect information about processes that were stopped.
local stopped=()
- openim::log::info "Stopping services with names: $*"
+ echo "Stopping services with names: $*"
# Iterate over each given service name.
for server_name in "$@"; do
# Use the `pgrep` command to find process IDs related to the given service name.
@@ -558,7 +621,7 @@ openim::util::stop_services_with_name() {
# If there's a Process ID, it means the service with the name is running.
if [[ -n $pid ]]; then
# Try to stop the service by killing its process.
- if kill -TERM $pid 2>/dev/null; then
+ if kill -15 $pid 2>/dev/null; then
stopped_this_time=true
fi
fi
@@ -570,26 +633,8 @@ openim::util::stop_services_with_name() {
not_stopped+=("$server_name")
fi
done
+ return 0
- # Print information about services whose processes couldn't be stopped.
- if [[ ${#not_stopped[@]} -ne 0 ]]; then
- openim::log::info "Services that couldn't be stopped:"
- for name in "${not_stopped[@]}"; do
- openim::log::status "Failed to stop the $name service."
- done
- fi
-
- # Print information about services whose processes were successfully stopped.
- if [[ ${#stopped[@]} -ne 0 ]]; then
- echo
- openim::log::info "Stopped services:"
- for name in "${stopped[@]}"; do
- openim::log::info "Successfully stopped the $name service."
- done
- fi
-
- openim::log::success "All specified services were stopped."
- echo ""
}
# sleep 333333&
# sleep 444444&
@@ -1528,7 +1573,7 @@ openim::util::check_ports() {
# An array to collect information about processes that are running.
local started=()
- openim::log::info "Checking ports: $*"
+ echo "Checking ports: $*"
# Iterate over each given port.
for port in "$@"; do
# Initialize variables
@@ -1536,12 +1581,8 @@ openim::util::check_ports() {
if [[ "$OSTYPE" == "linux-gnu"* ]]; then
if command -v ss > /dev/null 2>&1; then
info=$(ss -ltnp | grep ":$port" || true)
- echo "!!!!!!!!!!! port=$port"
- echo "!!!!!!!!!!! info=$info"
else
info=$(netstat -ltnp | grep ":$port" || true)
- echo "!!!!!!!!!!! port=$port"
- echo "!!!!!!!!!!! info=$info"
fi
elif [[ "$OSTYPE" == "darwin"* ]]; then
# For macOS, use lsof
@@ -1578,7 +1619,7 @@ openim::util::check_ports() {
# Print information about ports whose processes are not running.
if [[ ${#not_started[@]} -ne 0 ]]; then
- openim::log::info "\n### Not started ports:"
+ printf "\n### Not started ports:"
for port in "${not_started[@]}"; do
openim::log::error "Port $port is not started."
done
@@ -1586,15 +1627,18 @@ openim::util::check_ports() {
# Print information about ports whose processes are running.
if [[ ${#started[@]} -ne 0 ]]; then
- openim::log::info "\n### Started ports:"
+ printf "\n### Started ports:"
for info in "${started[@]}"; do
- openim::log::info "$info"
+ echo "$info"
done
fi
# If any of the processes is not running, return a status of 1.
if [[ ${#not_started[@]} -ne 0 ]]; then
- echo "++++ OpenIM Log >> cat ${LOG_FILE}"
+ openim::color::echo $COLOR_RED "OpenIM Stdout Log >> cat ${LOG_FILE}"
+ openim::color::echo $COLOR_RED "OpenIM Stderr Log >> cat ${STDERR_LOG_FILE}"
+ echo ""
+ cat "$TMP_LOG_FILE" | awk '{print "\033[31m" $0 "\033[0m"}'
return 1
else
openim::log::success "All specified processes are running."
@@ -1605,7 +1649,7 @@ openim::util::check_ports() {
# set +o errexit
# Sample call for testing:
# openim::util::check_ports 10002 1004 12345 13306
-# set -o errexit
+#
# The `openim::util::check_process_names` function analyzes the state of processes based on given names.
# It accepts multiple process names as arguments and prints:
@@ -1634,35 +1678,35 @@ openim::util::check_process_names() {
local not_started=()
local started=()
- openim::log::info "Checking processes: $*"
+ echo "Checking processes: $*"
# Iterate over each given process name
- for process_name in "$@"; do
- # Use `pgrep` to find process IDs related to the given process name
- local pids=($(pgrep -f $process_name))
+ for process_name in "$@"; do
+ # Use `pgrep` to find process IDs related to the given process name
+ local pids=($(pgrep -f $process_name))
- # Check if any process IDs were found
- if [[ ${#pids[@]} -eq 0 ]]; then
- not_started+=($process_name)
- else
- # If there are PIDs, loop through each one
- for pid in "${pids[@]}"; do
- local command=$(ps -p $pid -o cmd=)
- local start_time=$(ps -p $pid -o lstart=)
- local port=$(get_port $pid)
+ # Check if any process IDs were found
+ if [[ ${#pids[@]} -eq 0 ]]; then
+ not_started+=($process_name)
+ else
+ # If there are PIDs, loop through each one
+ for pid in "${pids[@]}"; do
+ local command=$(ps -p $pid -o cmd=)
+ local start_time=$(ps -p $pid -o lstart=)
+ local port=$(get_port $pid)
- # Check if port information was found for the PID
- if [[ -z $port ]]; then
- port="N/A"
- fi
+ # Check if port information was found for the PID
+ if [[ -z $port ]]; then
+ port="N/A"
+ fi
- started+=("Process $process_name - Command: $command, PID: $pid, Port: $port, Start time: $start_time")
- done
- fi
- done
+ started+=("Process $process_name - Command: $command, PID: $pid, Port: $port, Start time: $start_time")
+ done
+ fi
+ done
# Print information
if [[ ${#not_started[@]} -ne 0 ]]; then
- openim::log::info "Not started processes:"
+ echo "Not started processes:"
for process_name in "${not_started[@]}"; do
openim::log::error "Process $process_name is not started."
done
@@ -1670,17 +1714,20 @@ openim::util::check_process_names() {
if [[ ${#started[@]} -ne 0 ]]; then
echo
- openim::log::info "Started processes:"
+ echo "Started processes:"
for info in "${started[@]}"; do
- openim::log::info "$info"
+ echo "$info"
done
fi
# Return status
if [[ ${#not_started[@]} -ne 0 ]]; then
- echo "++++ OpenIM Log >> cat ${LOG_FILE}"
+ openim::color::echo $COLOR_RED " OpenIM Stdout Log >> cat ${LOG_FILE}"
+ openim::color::echo $COLOR_RED " OpenIM Stderr Log >> cat ${STDERR_LOG_FILE}"
+ cat "$TMP_LOG_FILE" | awk '{print "\033[31m" $0 "\033[0m"}'
return 1
else
+ echo ""
openim::log::success "All processes are running."
return 0
fi
@@ -1702,7 +1749,7 @@ openim::util::stop_services_on_ports() {
# An array to collect information about processes that were stopped.
local stopped=()
- openim::log::info "Stopping services on ports: $*"
+ echo "Stopping services on ports: $*"
# Iterate over each given port.
for port in "$@"; do
# Use the `lsof` command to find process information related to the given port.
@@ -1715,7 +1762,7 @@ openim::util::stop_services_on_ports() {
local pid=$(echo $line | awk '{print $2}')
# Try to stop the service by killing its process.
- if kill -TERM $pid; then
+ if kill -10 $pid; then
stopped+=($port)
else
not_stopped+=($port)
@@ -1726,7 +1773,7 @@ openim::util::stop_services_on_ports() {
# Print information about ports whose processes couldn't be stopped.
if [[ ${#not_stopped[@]} -ne 0 ]]; then
- openim::log::info "Ports that couldn't be stopped:"
+ echo "Ports that couldn't be stopped:"
for port in "${not_stopped[@]}"; do
openim::log::status "Failed to stop service on port $port."
done
@@ -1734,10 +1781,8 @@ openim::util::stop_services_on_ports() {
# Print information about ports whose processes were successfully stopped.
if [[ ${#stopped[@]} -ne 0 ]]; then
- echo
- openim::log::info "Stopped services on ports:"
for port in "${stopped[@]}"; do
- openim::log::info "Successfully stopped service on port $port."
+ echo "Successfully stopped service on port $port."
done
fi
@@ -1770,7 +1815,7 @@ openim::util::stop_services_with_name() {
# An array to collect information about processes that were stopped.
local stopped=()
- openim::log::info "Stopping services with names: $*"
+ echo "Stopping services with names: $*"
# Iterate over each given service name.
for server_name in "$@"; do
# Use the `pgrep` command to find process IDs related to the given service name.
@@ -1792,7 +1837,7 @@ openim::util::stop_services_with_name() {
# If there's a Process ID, it means the service with the name is running.
if [[ -n $pid ]]; then
# Try to stop the service by killing its process.
- if kill -TERM $pid 2>/dev/null; then
+ if kill -10 $pid 2>/dev/null; then
stopped_this_time=true
fi
fi
@@ -1807,7 +1852,7 @@ openim::util::stop_services_with_name() {
# Print information about services whose processes couldn't be stopped.
if [[ ${#not_stopped[@]} -ne 0 ]]; then
- openim::log::info "Services that couldn't be stopped:"
+ echo "Services that couldn't be stopped:"
for name in "${not_stopped[@]}"; do
openim::log::status "Failed to stop the $name service."
done
@@ -1816,9 +1861,9 @@ openim::util::stop_services_with_name() {
# Print information about services whose processes were successfully stopped.
if [[ ${#stopped[@]} -ne 0 ]]; then
echo
- openim::log::info "Stopped services:"
+ echo "Stopped services:"
for name in "${stopped[@]}"; do
- openim::log::info "Successfully stopped the $name service."
+ echo "Successfully stopped the $name service."
done
fi
@@ -2819,6 +2864,46 @@ function openim::util::gen_os_arch() {
fi
}
+
+
+function openim::util::check_process_names_for_stop() {
+ local all_stopped=true
+ for service in "${OPENIM_ALL_SERVICE_LIBRARIES[@]}"; do
+
+ PIDS=$(pgrep -f "${service}") || PIDS="0"
+ if [ "$PIDS" = "0" ]; then
+ continue
+ fi
+
+
+ NUM_PROCESSES=$(echo "$PIDS" | wc -l | xargs)
+ if [ "$NUM_PROCESSES" -gt 0 ]; then
+ all_stopped=false
+ echo "Found $NUM_PROCESSES processes for ${service}"
+ for PID in $PIDS; do
+ if [[ "$OSTYPE" == "linux-gnu"* ]]; then
+ echo -e "\033[31m$(ps -p $PID -o pid,cmd)\033[0m"
+ elif [[ "$OSTYPE" == "darwin"* ]]; then
+ echo -e "\033[31m$(ps -p $PID -o pid,comm)\033[0m"
+ else
+ openim::log::error "Unsupported OS type: $OSTYPE"
+ fi
+ done
+ echo "Processes for ${service} have not been stopped properly. " "$NUM_PROCESSES"
+ fi
+ done
+
+ if [ "$all_stopped" = true ]; then
+ openim::log::success "All processes have been stopped properly."
+ return 0
+ fi
+
+ return 1
+}
+
+
+
+
if [[ "$*" =~ openim::util:: ]];then
eval $*
fi
diff --git a/scripts/list-feature-tests.sh b/scripts/list-feature-tests.sh
index 438474bae..d6eaa4873 100755
--- a/scripts/list-feature-tests.sh
+++ b/scripts/list-feature-tests.sh
@@ -18,9 +18,9 @@
#
# Usage: `scripts/list-feature-tests.sh`.
-set -o errexit
-set -o nounset
-set -o pipefail
+
+
+
OPENIM_ROOT=$(dirname "${BASH_SOURCE[0]}")/..
grep "\[Feature:\w+\]" "${OPENIM_ROOT}"/test/e2e/**/*.go -Eoh | LC_ALL=C sort -u
\ No newline at end of file
diff --git a/scripts/make-rules/golang.mk b/scripts/make-rules/golang.mk
index 915639b61..5a5d1a788 100644
--- a/scripts/make-rules/golang.mk
+++ b/scripts/make-rules/golang.mk
@@ -17,7 +17,7 @@
#
GO := go
-GO_SUPPORTED_VERSIONS ?= 1.19|1.20|1.21|1.22
+GO_SUPPORTED_VERSIONS ?= 1.19|1.20|1.21|1.22|1.23
GO_LDFLAGS += -X $(VERSION_PACKAGE).gitVersion=$(GIT_TAG) \
-X $(VERSION_PACKAGE).gitCommit=$(GIT_COMMIT) \
diff --git a/scripts/release.sh b/scripts/release.sh
index a34d5ee22..eb8b04359 100755
--- a/scripts/release.sh
+++ b/scripts/release.sh
@@ -47,9 +47,9 @@
# images and other build artifacts.
# Build a OpenIM release. This script supports various flags for flexible execution control.
-set -o errexit
-set -o nounset
-set -o pipefail
+
+
+
OPENIM_ROOT=$(dirname "${BASH_SOURCE[0]}")/..
source "${OPENIM_ROOT}/scripts/common.sh"
source "${OPENIM_ROOT}/scripts/lib/release.sh"
diff --git a/scripts/run-in-gopath.sh b/scripts/run-in-gopath.sh
index 9bb8ec882..6af986975 100755
--- a/scripts/run-in-gopath.sh
+++ b/scripts/run-in-gopath.sh
@@ -20,9 +20,9 @@
# the project.
# Usage: `scripts/run-in-gopath.sh `.
-set -o errexit
-set -o nounset
-set -o pipefail
+
+
+
OPENIM_ROOT=$(dirname "${BASH_SOURCE[0]}")/..
source "${OPENIM_ROOT}/scripts/lib/init.sh"
diff --git a/scripts/start-all.sh b/scripts/start-all.sh
index 5f34cbdbe..c27f2010c 100755
--- a/scripts/start-all.sh
+++ b/scripts/start-all.sh
@@ -16,70 +16,98 @@
#FIXME This script is the startup script for multiple servers.
#FIXME The full names of the shell scripts that need to be started are placed in the `need_to_start_server_shell` array.
-set -o nounset
-set -o pipefail
+
+
OPENIM_ROOT=$(dirname "${BASH_SOURCE[0]}")/..
source "${OPENIM_ROOT}/scripts/install/common.sh"
-openim::log::info "\n# Begin to start all openim service scripts"
-set +o errexit
+# Function to execute the scripts.
+function execute_start_scripts() {
+ for script_path in "${OPENIM_SERVER_SCRIPT_START_LIST[@]}"; do
+ # Extract the script name without extension for argument generation.
+ script_name_with_prefix=$(basename "$script_path" .sh)
+
+ # Remove the "openim-" prefix.
+ script_name=${script_name_with_prefix#openim-}
+
+ # Construct the argument based on the script name.
+ arg="openim::${script_name}::start"
+
+ # Check if the script file exists and is executable.
+ if [[ -x "$script_path" ]]; then
+ openim::log::print_blue "Starting script: ${script_path##*/}" # Log the script name.
+
+ # Execute the script with the constructed argument.
+ result=$("$script_path" "$arg")
+ if [[ $? -ne 0 ]]; then
+ openim::log::error "Start script: ${script_path##*/} failed"
+ openim::log::error "$result"
+ return 1
+ fi
+
+ else
+ openim::log::errexit "Script ${script_path##*/} is missing or not executable."
+ return 1
+ fi
+ done
+}
+
+
+
+
+
+
+
openim::golang::check_openim_binaries
if [[ $? -ne 0 ]]; then
openim::log::error "OpenIM binaries are not found. Please run 'make build' to build binaries."
"${OPENIM_ROOT}"/scripts/build-all-service.sh
fi
-set -o errexit
+
"${OPENIM_ROOT}"/scripts/init-config.sh --skip
-echo "You need to start the following scripts in order: ${OPENIM_SERVER_SCRIPTARIES[@]}"
-openim::log::install_errexit
-
-# Function to execute the scripts.
-function execute_scripts() {
- for script_path in "${OPENIM_SERVER_SCRIPT_START_LIST[@]}"; do
- # Extract the script name without extension for argument generation.
- script_name_with_prefix=$(basename "$script_path" .sh)
-
- # Remove the "openim-" prefix.
- script_name=${script_name_with_prefix#openim-}
-
- # Construct the argument based on the script name.
- arg="openim::${script_name}::start"
-
- # Check if the script file exists and is executable.
- if [[ -x "$script_path" ]]; then
- openim::log::status "Starting script: ${script_path##*/}" # Log the script name.
-
- # Execute the script with the constructed argument.
- "$script_path" "$arg"
-
- # Check if the script executed successfully.
- if [[ $? -eq 0 ]]; then
- openim::log::info "${script_path##*/} executed successfully."
- else
- openim::log::errexit "Error executing ${script_path##*/}."
- fi
- else
- openim::log::errexit "Script ${script_path##*/} is missing or not executable."
- fi
- done
- sleep 0.5
-}
+#openim::log::print_blue "Execute the following script in sequence: ${OPENIM_SERVER_SCRIPTARIES[@]}"
# TODO Prelaunch tools, simple for now, can abstract functions later
TOOLS_START_SCRIPTS_PATH=${START_SCRIPTS_PATH}/openim-tools.sh
-openim::log::info "\n## Pre Starting OpenIM services"
+openim::log::status "\n## Pre Starting OpenIM services"
${TOOLS_START_SCRIPTS_PATH} openim::tools::pre-start
-openim::log::info "\n## Starting OpenIM services"
-execute_scripts
-openim::log::info "\n## Post Starting OpenIM services"
+result=$("${OPENIM_ROOT}"/scripts/stop-all.sh)
+if [[ $? -ne 0 ]]; then
+ openim::log::error "View the error logs from this startup. ${LOG_FILE} \n"
+ openim::log::error "Some programs have not exited; the start process is aborted .\n $result"
+ exit 1
+fi
+
+
+
+openim::log::status "\n## Starting openim scripts: "
+execute_start_scripts
+
+sleep 2
+
+result=$(. $(dirname ${BASH_SOURCE})/install/openim-msgtransfer.sh openim::msgtransfer::check)
+if [[ $? -ne 0 ]]; then
+ openim::log::error "The program may fail to start.\n $result"
+ exit 1
+fi
+
+
+result=$(openim::util::check_process_names ${OPENIM_ALL_SERVICE_LIBRARIES_NO_TRANSFER[@]})
+if [[ $? -ne 0 ]]; then
+ openim::log::error "The program may fail to start.\n $result"
+ exit 1
+fi
+
+
+openim::log::info "\n## Post Starting openim services"
${TOOLS_START_SCRIPTS_PATH} openim::tools::post-start
-openim::log::success "✨ All OpenIM services have been successfully started!"
\ No newline at end of file
+openim::log::success "All openim services have been successfully started!"
\ No newline at end of file
diff --git a/scripts/stop-all.sh b/scripts/stop-all.sh
index 1d2eddd78..b2572f7d5 100755
--- a/scripts/stop-all.sh
+++ b/scripts/stop-all.sh
@@ -18,29 +18,43 @@
# Usage: `scripts/stop.sh`.
# Encapsulated as: `make stop`.
-set -o errexit
-set -o nounset
-set -o pipefail
+
+
+
OPENIM_ROOT=$(dirname "${BASH_SOURCE[0]}")/..
source "${OPENIM_ROOT}/scripts/install/common.sh"
-openim::log::info "\n# Begin to stop all openim service"
+openim::log::status "Begin to stop all openim service"
-echo "++ Ready to stop port: ${OPENIM_SERVER_PORT_LISTARIES[@]}"
-
-openim::util::stop_services_on_ports ${OPENIM_SERVER_PORT_LISTARIES[@]}
-
-echo -e "\n++ Stop all processes in the path ${OPENIM_OUTPUT_HOSTBIN}"
+openim::log::status "Stop all processes in the path ${OPENIM_OUTPUT_HOSTBIN}"
openim::util::stop_services_with_name "${OPENIM_OUTPUT_HOSTBIN}"
+# todo OPENIM_ALL_SERVICE_LIBRARIES
-echo -n "Stopping services 15 seconds."
-for i in {1..15}; do
- echo -n "."
- sleep 1
+
+
+
+max_retries=15
+attempt=0
+
+while [[ $attempt -lt $max_retries ]]
+do
+ result=$(openim::util::check_process_names_for_stop)
+
+ if [[ $? -ne 0 ]]; then
+ if [[ $attempt -ne 0 ]] ; then
+ echo "+++ cat openim log file >>> ${LOG_FILE} " $attempt
+ openim::log::error "stop process failed. continue waiting\n" "${result}"
+ fi
+ sleep 1
+ ((attempt++))
+ else
+ openim::log::success " All openim processes to be stopped"
+ exit 0
+ fi
done
-echo -e "\nServices stopped."
-openim::log::success "✨ Wait 15 seconds for all processes to be killed"
\ No newline at end of file
+openim::log::error "openim processes stopped failed"
+exit 1
diff --git a/scripts/update-generated-docs.sh b/scripts/update-generated-docs.sh
index c37c4a1f9..d48a4067b 100755
--- a/scripts/update-generated-docs.sh
+++ b/scripts/update-generated-docs.sh
@@ -18,9 +18,9 @@
# immediately before exporting docs. We do not want to check these documents in
# by default.
-set -o errexit
-set -o nounset
-set -o pipefail
+
+
+
OPENIM_ROOT=$(dirname "${BASH_SOURCE[0]}")/..
source "${OPENIM_ROOT}/scripts/lib/init.sh"
diff --git a/scripts/update-yamlfmt.sh b/scripts/update-yamlfmt.sh
index 90ec8aa62..24ec60de9 100755
--- a/scripts/update-yamlfmt.sh
+++ b/scripts/update-yamlfmt.sh
@@ -14,9 +14,9 @@
# limitations under the License.
-set -o errexit
-set -o nounset
-set -o pipefail
+
+
+
OPENIM_ROOT=$(dirname "${BASH_SOURCE[0]}")/..
source "${OPENIM_ROOT}/scripts/lib/init.sh"
diff --git a/scripts/verify-annotation-language.sh b/scripts/verify-annotation-language.sh
new file mode 100755
index 000000000..6b863776c
--- /dev/null
+++ b/scripts/verify-annotation-language.sh
@@ -0,0 +1,46 @@
+#!/usr/bin/env bash
+# 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.
+
+
+# This script verifies whether codes follow golang convention.
+# Usage: `scripts/verify-pkg-names.sh`.
+
+set -o errexit
+
+OPENIM_ROOT=$(dirname "${BASH_SOURCE[0]}")/..
+source "${OPENIM_ROOT}/scripts/lib/init.sh"
+
+openim::golang::verify_go_version
+
+openim::golang::verify_go_version
+
+OPENIM_OUTPUT_HOSTBIN_TOOLS="${OPENIM_ROOT}/_output/bin/tools/linux/amd64"
+CODESCAN_BINARY="${OPENIM_OUTPUT_HOSTBIN_TOOLS}/codescan"
+
+if [[ ! -f "${CODESCAN_BINARY}" ]]; then
+ echo "codescan binary not found, building..."
+ pushd "${OPENIM_ROOT}" >/dev/null
+ make build BINS="codescan"
+ popd >/dev/null
+fi
+
+if [[ ! -f "${CODESCAN_BINARY}" ]]; then
+ echo "Failed to build codescan binary."
+ exit 1
+fi
+
+CONFIG_PATH="${OPENIM_ROOT}/tools/codescan/config.yaml"
+
+"${CODESCAN_BINARY}" -config "${CONFIG_PATH}"
\ No newline at end of file
diff --git a/scripts/verify-pkg-names.sh b/scripts/verify-pkg-names.sh
index 1459992e9..be1acd015 100755
--- a/scripts/verify-pkg-names.sh
+++ b/scripts/verify-pkg-names.sh
@@ -17,9 +17,6 @@
# This script verifies whether codes follow golang convention.
# Usage: `scripts/verify-pkg-names.sh`.
-set -o errexit
-set -o nounset
-set -o pipefail
OPENIM_ROOT=$(dirname "${BASH_SOURCE[0]}")/..
source "${OPENIM_ROOT}/scripts/lib/init.sh"
diff --git a/scripts/verify-shellcheck.sh b/scripts/verify-shellcheck.sh
index 8a5ad7321..c7e713d09 100755
--- a/scripts/verify-shellcheck.sh
+++ b/scripts/verify-shellcheck.sh
@@ -17,9 +17,9 @@
# This script lints each shell script by `shellcheck`.
# Usage: `scripts/verify-shellcheck.sh`.
-set -o errexit
-set -o nounset
-set -o pipefail
+
+
+
OPENIM_ROOT=$(dirname "${BASH_SOURCE[0]}")/..
source "${OPENIM_ROOT}/scripts/lib/init.sh"
diff --git a/scripts/verify-spelling.sh b/scripts/verify-spelling.sh
index 2c02dccf7..fa0852866 100755
--- a/scripts/verify-spelling.sh
+++ b/scripts/verify-spelling.sh
@@ -17,9 +17,9 @@
# working directory by client9/misspell package.
# Usage: `scripts/verify-spelling.sh`.
-set -o errexit
-set -o nounset
-set -o pipefail
+
+
+
OPENIM_ROOT=$(dirname "${BASH_SOURCE[0]}")/..
export OPENIM_ROOT
diff --git a/scripts/verify-typecheck.sh b/scripts/verify-typecheck.sh
index 62fca4049..c9b2aaf30 100755
--- a/scripts/verify-typecheck.sh
+++ b/scripts/verify-typecheck.sh
@@ -16,9 +16,9 @@
# This script does a fast type check of script srnetes code for all platforms.
# Usage: `scripts/verify-typecheck.sh`.
-set -o errexit
-set -o nounset
-set -o pipefail
+
+
+
OPENIM_ROOT=$(dirname "${BASH_SOURCE[0]}")/..
source "${OPENIM_ROOT}/scripts/lib/init.sh"
diff --git a/scripts/verify-yamlfmt.sh b/scripts/verify-yamlfmt.sh
index 3d0a0180d..3acbf457c 100755
--- a/scripts/verify-yamlfmt.sh
+++ b/scripts/verify-yamlfmt.sh
@@ -19,9 +19,9 @@
#
# Usage: `scripts/verify-yamlfmt.sh`.
-set -o errexit
-set -o nounset
-set -o pipefail
+
+
+
OPENIM_ROOT=$(dirname "${BASH_SOURCE[0]}")/..
source "${OPENIM_ROOT}/scripts/lib/init.sh"
diff --git a/test/e2e/README.md b/test/e2e/README.md
index 1e73dbaec..49215e811 100644
--- a/test/e2e/README.md
+++ b/test/e2e/README.md
@@ -128,6 +128,8 @@ Open issue: https://github.com/openimsdk/open-im-server/issues/new/choose, choos
The E2E test suite is integrated with CI, which runs the tests automatically on each code commit. The results are reported back to the pull request or commit to provide immediate feedback on the impact of the changes.
+[](https://github.com/openimsdk/open-im-server/actions/workflows/e2e-test.yml)
+
## Contact
diff --git a/test/e2e/api/token/token.go b/test/e2e/api/token/token.go
index 88af72058..908f9b8a0 100644
--- a/test/e2e/api/token/token.go
+++ b/test/e2e/api/token/token.go
@@ -19,7 +19,6 @@ import (
"encoding/json"
"fmt"
"io"
- "log"
"net/http"
)
@@ -58,7 +57,7 @@ type UserRegisterRequest struct {
Users []User `json:"users"`
}
-func main() {
+/* func main() {
// Example usage of functions
token, err := GetUserToken("openIM123456")
if err != nil {
@@ -70,7 +69,7 @@ func main() {
if err != nil {
log.Fatalf("Error registering user: %v", err)
}
-}
+} */
// GetUserToken requests a user token from the API.
func GetUserToken(userID string) (string, error) {
diff --git a/test/e2e/framework/config/config_test.go b/test/e2e/framework/config/config_test.go
index b7259bf37..66f845db3 100644
--- a/test/e2e/framework/config/config_test.go
+++ b/test/e2e/framework/config/config_test.go
@@ -76,7 +76,7 @@ func TestCopyFlags(t *testing.T) {
}()
CopyFlags(tt.args.source, tt.args.target)
- // 验证复制的标记
+ // Verify the replicated tag
if !tt.wantErr {
tt.args.source.VisitAll(func(f *flag.Flag) {
if gotFlag := tt.args.target.Lookup(f.Name); gotFlag == nil || !reflect.DeepEqual(gotFlag, f) {
diff --git a/test/e2e/framework/helpers/chat/chat.go b/test/e2e/framework/helpers/chat/chat.go
index a4ead528b..aa37c34b5 100644
--- a/test/e2e/framework/helpers/chat/chat.go
+++ b/test/e2e/framework/helpers/chat/chat.go
@@ -38,6 +38,9 @@ func main() {
// }
latestVersion := defaultTemplateVersion
+ // getLatestVersion
+ // getLatestVersion
+
// Construct the download URL
downloadURL := fmt.Sprintf("https://github.com/openimsdk/chat/releases/download/%s/chat_Linux_x86_64.tar.gz", latestVersion)
@@ -99,22 +102,22 @@ func main() {
}
// getLatestVersion fetches the latest version number from a given URL.
-func getLatestVersion(url string) (string, error) {
+/* func getLatestVersion(url string) (string, error) {
resp, err := http.Get(url)
if err != nil {
return "", err
}
defer resp.Body.Close()
- location := resp.Header.Get("Location")
- if location == "" {
- return defaultTemplateVersion, nil
- }
+// location := resp.Header.Get("Location")
+// if location == "" {
+// return defaultTemplateVersion, nil
+// }
// Extract the version number from the URL
latestVersion := filepath.Base(location)
return latestVersion, nil
-}
+} */
// downloadAndExtract downloads a file from a URL and extracts it to a destination directory.
func downloadAndExtract(url, destDir string) error {
diff --git a/test/e2e/page/chat_page.go b/test/e2e/page/chat_page.go
new file mode 100644
index 000000000..d92c7ec6e
--- /dev/null
+++ b/test/e2e/page/chat_page.go
@@ -0,0 +1,15 @@
+// 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 page
diff --git a/test/e2e/page/login_page.go b/test/e2e/page/login_page.go
new file mode 100644
index 000000000..d92c7ec6e
--- /dev/null
+++ b/test/e2e/page/login_page.go
@@ -0,0 +1,15 @@
+// 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 page
diff --git a/test/e2e/web/.keep b/test/e2e/web/.keep
deleted file mode 100644
index 4f07f1caf..000000000
--- a/test/e2e/web/.keep
+++ /dev/null
@@ -1 +0,0 @@
-.keep
\ No newline at end of file
diff --git a/test/e2e/web/Readme.md b/test/e2e/web/Readme.md
new file mode 100644
index 000000000..741ca51d5
--- /dev/null
+++ b/test/e2e/web/Readme.md
@@ -0,0 +1,2 @@
+# OpenIM Web E2E
+
diff --git a/tools/codescan/checker/checker.go b/tools/codescan/checker/checker.go
new file mode 100644
index 000000000..ad724dd5b
--- /dev/null
+++ b/tools/codescan/checker/checker.go
@@ -0,0 +1,104 @@
+// 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 checker
+
+import (
+ "bufio"
+ "fmt"
+ "os"
+ "path/filepath"
+ "regexp"
+ "strings"
+
+ "github.com/openimsdk/open-im-server/tools/codescan/config"
+)
+
+type CheckResult struct {
+ FilePath string
+ Lines []int
+}
+
+func checkFileForChineseComments(filePath string) ([]CheckResult, error) {
+ file, err := os.Open(filePath)
+ if err != nil {
+ return nil, err
+ }
+ defer file.Close()
+
+ var results []CheckResult
+ scanner := bufio.NewScanner(file)
+ reg := regexp.MustCompile(`[\p{Han}]+`)
+ lineNumber := 0
+
+ var linesWithChinese []int
+ for scanner.Scan() {
+ lineNumber++
+ if reg.FindString(scanner.Text()) != "" {
+ linesWithChinese = append(linesWithChinese, lineNumber)
+ }
+ }
+
+ if len(linesWithChinese) > 0 {
+ results = append(results, CheckResult{
+ FilePath: filePath,
+ Lines: linesWithChinese,
+ })
+ }
+
+ if err := scanner.Err(); err != nil {
+ return nil, err
+ }
+
+ return results, nil
+}
+
+func WalkDirAndCheckComments(cfg config.Config) error {
+ var allResults []CheckResult
+ err := filepath.Walk(cfg.Directory, func(path string, info os.FileInfo, err error) error {
+ if err != nil {
+ return err
+ }
+ if info.IsDir() {
+ return nil
+ }
+ for _, fileType := range cfg.FileTypes {
+ if filepath.Ext(path) == fileType {
+ results, err := checkFileForChineseComments(path)
+ if err != nil {
+ return err
+ }
+ if len(results) > 0 {
+ allResults = append(allResults, results...)
+ }
+ }
+ }
+ return nil
+ })
+
+ if err != nil {
+ return err
+ }
+
+ if len(allResults) > 0 {
+ var errMsg strings.Builder
+ errMsg.WriteString("Files containing Chinese comments:\n")
+ for _, result := range allResults {
+ errMsg.WriteString(fmt.Sprintf("%s: Lines %v\n", result.FilePath, result.Lines))
+ }
+ return fmt.Errorf(errMsg.String())
+ }
+
+ return nil
+}
diff --git a/tools/codescan/codescan.go b/tools/codescan/codescan.go
new file mode 100644
index 000000000..a83e895fc
--- /dev/null
+++ b/tools/codescan/codescan.go
@@ -0,0 +1,34 @@
+// 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 main
+
+import (
+ "log"
+
+ "github.com/openimsdk/open-im-server/tools/codescan/checker"
+ "github.com/openimsdk/open-im-server/tools/codescan/config"
+)
+
+func main() {
+ cfg, err := config.ParseConfig()
+ if err != nil {
+ log.Fatalf("Error parsing config: %v", err)
+ }
+
+ err = checker.WalkDirAndCheckComments(cfg)
+ if err != nil {
+ panic(err)
+ }
+}
diff --git a/tools/codescan/config.yaml b/tools/codescan/config.yaml
new file mode 100644
index 000000000..32a8c1f54
--- /dev/null
+++ b/tools/codescan/config.yaml
@@ -0,0 +1,21 @@
+# 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.
+
+directory: ./
+file_types:
+ - .go
+ - .yaml
+ - .yml
+languages:
+ - Chinese
\ No newline at end of file
diff --git a/tools/codescan/config/config.go b/tools/codescan/config/config.go
new file mode 100644
index 000000000..aebf0d4f7
--- /dev/null
+++ b/tools/codescan/config/config.go
@@ -0,0 +1,49 @@
+// 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 config
+
+import (
+ "flag"
+ "log"
+ "os"
+
+ "gopkg.in/yaml.v2"
+)
+
+type Config struct {
+ Directory string `yaml:"directory"`
+ FileTypes []string `yaml:"file_types"`
+ Languages []string `yaml:"languages"`
+}
+
+func ParseConfig() (Config, error) {
+ var configPath string
+ flag.StringVar(&configPath, "config", "./", "Path to config file")
+ flag.Parse()
+
+ var config Config
+ if configPath != "" {
+ configFile, err := os.ReadFile(configPath)
+ if err != nil {
+ return Config{}, err
+ }
+ if err := yaml.Unmarshal(configFile, &config); err != nil {
+ return Config{}, err
+ }
+ } else {
+ log.Fatal("Config file must be provided")
+ }
+ return config, nil
+}
diff --git a/tools/codescan/go.mod b/tools/codescan/go.mod
new file mode 100644
index 000000000..2ad132101
--- /dev/null
+++ b/tools/codescan/go.mod
@@ -0,0 +1,3 @@
+module github.com/openimsdk/open-im-server/tools/codescan
+
+go 1.19
diff --git a/tools/component/component.go b/tools/component/component.go
index 220b845ee..34d3dff6b 100644
--- a/tools/component/component.go
+++ b/tools/component/component.go
@@ -15,82 +15,79 @@
package main
import (
- "context"
"errors"
"flag"
"fmt"
- "net"
- "net/url"
"os"
+ "strconv"
"strings"
"time"
"github.com/IBM/sarama"
+
+ "github.com/openimsdk/open-im-server/v3/pkg/common/kafka"
+
+ "github.com/OpenIMSDK/tools/component"
"github.com/OpenIMSDK/tools/errs"
- "github.com/go-zookeeper/zk"
- "go.mongodb.org/mongo-driver/mongo"
- "go.mongodb.org/mongo-driver/mongo/options"
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
- "github.com/minio/minio-go/v7"
- "github.com/minio/minio-go/v7/pkg/credentials"
- "github.com/redis/go-redis/v9"
"gopkg.in/yaml.v3"
)
const (
// defaultCfgPath is the default path of the configuration file.
- defaultCfgPath = "../../../../../config/config.yaml"
- minioHealthCheckDuration = 1
- maxRetry = 300
- componentStartErrCode = 6000
- configErrCode = 6001
- mongoConnTimeout = 30 * time.Second
-)
-
-const (
- colorRed = 31
- colorGreen = 32
- colorYellow = 33
+ defaultCfgPath = "../../../../../config/config.yaml"
+ maxRetry = 100
)
var (
- cfgPath = flag.String("c", defaultCfgPath, "Path to the configuration file")
- ErrComponentStart = errs.NewCodeError(componentStartErrCode, "ComponentStartErr")
- ErrConfig = errs.NewCodeError(configErrCode, "Config file is incorrect")
+ cfgPath = flag.String("c", defaultCfgPath, "Path to the configuration file")
)
-func initCfg() error {
+func initCfg() (*config.GlobalConfig, error) {
data, err := os.ReadFile(*cfgPath)
if err != nil {
- return err
+ return nil, errs.Wrap(err, "ReadFile unmarshal failed")
}
- return yaml.Unmarshal(data, &config.Config)
+ conf := config.NewGlobalConfig()
+ err = yaml.Unmarshal(data, &conf)
+ if err != nil {
+ return nil, errs.Wrap(err, "InitConfig unmarshal failed")
+ }
+ return conf, nil
}
type checkFunc struct {
name string
- function func() (string, error)
+ function func(*config.GlobalConfig) error
+ flag bool
+ config *config.GlobalConfig
}
func main() {
flag.Parse()
- if err := initCfg(); err != nil {
+ conf, err := initCfg()
+ if err != nil {
fmt.Printf("Read config failed: %v\n", err)
+ return
+ }
+ err = configGetEnv(conf)
+ if err != nil {
+ fmt.Printf("configGetEnv failed,err:%v", err)
return
}
checks := []checkFunc{
//{name: "Mysql", function: checkMysql},
- {name: "Mongo", function: checkMongo},
- {name: "Minio", function: checkMinio},
- {name: "Redis", function: checkRedis},
- {name: "Zookeeper", function: checkZookeeper},
- {name: "Kafka", function: checkKafka},
+ {name: "Mongo", function: checkMongo, config: conf},
+ {name: "Redis", function: checkRedis, config: conf},
+ {name: "Minio", function: checkMinio, config: conf},
+ {name: "Zookeeper", function: checkZookeeper, config: conf},
+ {name: "Kafka", function: checkKafka, config: conf},
}
for i := 0; i < maxRetry; i++ {
@@ -99,274 +96,166 @@ func main() {
}
fmt.Printf("Checking components Round %v...\n", i+1)
+ var err error
allSuccess := true
- for _, check := range checks {
- str, err := check.function()
- if err != nil {
- errorPrint(fmt.Sprintf("Starting %s failed, %v", check.name, err))
- allSuccess = false
- break
- } else {
- successPrint(fmt.Sprintf("%s connected successfully, %s", check.name, str))
+ for index, check := range checks {
+ if !check.flag {
+ err = check.function(check.config)
+ if err != nil {
+ allSuccess = false
+ component.ErrorPrint(fmt.Sprintf("Starting %s failed:%v.", check.name, errs.Unwrap(err).Error()))
+ if !strings.Contains(errs.Unwrap(err).Error(), "connection refused") &&
+ !strings.Contains(errs.Unwrap(err).Error(), "timeout waiting") {
+ component.ErrorPrint("Some components started failed!")
+ os.Exit(-1)
+ }
+ } else {
+ checks[index].flag = true
+ component.SuccessPrint(fmt.Sprintf("%s connected successfully", check.name))
+ }
}
}
if allSuccess {
- successPrint("All components started successfully!")
-
+ component.SuccessPrint("All components started successfully!")
return
}
}
- os.Exit(1)
-}
-
-func exactIP(urll string) string {
- u, _ := url.Parse(urll)
- host, _, err := net.SplitHostPort(u.Host)
- if err != nil {
- host = u.Host
- }
- if strings.HasSuffix(host, ":") {
- host = host[0 : len(host)-1]
- }
-
- return host
-}
-
-// Helper function to get environment variable or default value
-func getEnv(key, fallback string) string {
- if value, exists := os.LookupEnv(key); exists {
- return value
- }
- return fallback
+ component.ErrorPrint("Some components started failed!")
+ os.Exit(-1)
}
// checkMongo checks the MongoDB connection without retries
-func checkMongo() (string, error) {
- uri := getEnv("MONGO_URI", buildMongoURI())
-
- ctx, cancel := context.WithTimeout(context.Background(), mongoConnTimeout)
- defer cancel()
-
- str := "ths addr is:" + strings.Join(config.Config.Mongo.Address, ",")
-
- client, err := mongo.Connect(ctx, options.Client().ApplyURI(uri))
- if err != nil {
- return "", errs.Wrap(errStr(err, str))
+func checkMongo(config *config.GlobalConfig) error {
+ mongoStu := &component.Mongo{
+ URL: config.Mongo.Uri,
+ Address: config.Mongo.Address,
+ Database: config.Mongo.Database,
+ Username: config.Mongo.Username,
+ Password: config.Mongo.Password,
+ MaxPoolSize: config.Mongo.MaxPoolSize,
}
- defer client.Disconnect(context.Background())
+ err := component.CheckMongo(mongoStu)
- ctx, cancel = context.WithTimeout(context.Background(), mongoConnTimeout)
- defer cancel()
-
- if err = client.Ping(ctx, nil); err != nil {
- return "", errs.Wrap(errStr(err, str))
- }
-
- return str, nil
-}
-
-// buildMongoURI constructs the MongoDB URI using configuration settings
-func buildMongoURI() string {
- // Fallback to config if environment variables are not set
- username := config.Config.Mongo.Username
- password := config.Config.Mongo.Password
- database := config.Config.Mongo.Database
- maxPoolSize := config.Config.Mongo.MaxPoolSize
-
- mongodbHosts := strings.Join(config.Config.Mongo.Address, ",")
-
- if username != "" && password != "" {
- return fmt.Sprintf("mongodb://%s:%s@%s/%s?maxPoolSize=%d",
- username, password, mongodbHosts, database, maxPoolSize)
- }
- return fmt.Sprintf("mongodb://%s/%s?maxPoolSize=%d",
- mongodbHosts, database, maxPoolSize)
-}
-
-// checkMinio checks the MinIO connection
-func checkMinio() (string, error) {
- // Check if MinIO is enabled
- if config.Config.Object.Enable != "minio" {
- return "", nil
- }
-
- // Prioritize environment variables
- endpoint := getEnv("MINIO_ENDPOINT", config.Config.Object.Minio.Endpoint)
- accessKeyID := getEnv("MINIO_ACCESS_KEY_ID", config.Config.Object.Minio.AccessKeyID)
- secretAccessKey := getEnv("MINIO_SECRET_ACCESS_KEY", config.Config.Object.Minio.SecretAccessKey)
- useSSL := getEnv("MINIO_USE_SSL", "false") // Assuming SSL is not used by default
-
- if endpoint == "" || accessKeyID == "" || secretAccessKey == "" {
- return "", ErrConfig.Wrap("MinIO configuration missing")
- }
-
- // Parse endpoint URL to determine if SSL is enabled
- u, err := url.Parse(endpoint)
- if err != nil {
- str := "the endpoint is:" + endpoint
- return "", errs.Wrap(errStr(err, str))
- }
- secure := u.Scheme == "https" || useSSL == "true"
-
- // Initialize MinIO client
- minioClient, err := minio.New(u.Host, &minio.Options{
- Creds: credentials.NewStaticV4(accessKeyID, secretAccessKey, ""),
- Secure: secure,
- })
- str := "ths addr is:" + u.Host
- if err != nil {
- strs := fmt.Sprintf("%v;host:%s,accessKeyID:%s,secretAccessKey:%s,Secure:%v", err, u.Host, accessKeyID, secretAccessKey, secure)
- return "", errs.Wrap(err, strs)
- }
-
- // Perform health check
- cancel, err := minioClient.HealthCheck(time.Duration(minioHealthCheckDuration) * time.Second)
- if err != nil {
- return "", errs.Wrap(errStr(err, str))
- }
- defer cancel()
-
- if minioClient.IsOffline() {
- str := fmt.Sprintf("Minio server is offline;%s", str)
- return "", ErrComponentStart.Wrap(str)
- }
-
- // Check for localhost in API URL and Minio SignEndpoint
- if exactIP(config.Config.Object.ApiURL) == "127.0.0.1" || exactIP(config.Config.Object.Minio.SignEndpoint) == "127.0.0.1" {
- return "", ErrConfig.Wrap("apiURL or Minio SignEndpoint endpoint contain 127.0.0.1")
- }
-
- return str, nil
+ return err
}
// checkRedis checks the Redis connection
-func checkRedis() (string, error) {
- // Prioritize environment variables
- address := getEnv("REDIS_ADDRESS", strings.Join(config.Config.Redis.Address, ","))
- username := getEnv("REDIS_USERNAME", config.Config.Redis.Username)
- password := getEnv("REDIS_PASSWORD", config.Config.Redis.Password)
-
- // Split address to handle multiple addresses for cluster setup
- redisAddresses := strings.Split(address, ",")
-
- var redisClient redis.UniversalClient
- if len(redisAddresses) > 1 {
- // Use cluster client for multiple addresses
- redisClient = redis.NewClusterClient(&redis.ClusterOptions{
- Addrs: redisAddresses,
- Username: username,
- Password: password,
- })
- } else {
- // Use regular client for single address
- redisClient = redis.NewClient(&redis.Options{
- Addr: redisAddresses[0],
- Username: username,
- Password: password,
- })
+func checkRedis(config *config.GlobalConfig) error {
+ redisStu := &component.Redis{
+ Address: config.Redis.Address,
+ Username: config.Redis.Username,
+ Password: config.Redis.Password,
}
- defer redisClient.Close()
+ err := component.CheckRedis(redisStu)
+ return err
+}
- // Ping Redis to check connectivity
- _, err := redisClient.Ping(context.Background()).Result()
- str := "the addr is:" + strings.Join(redisAddresses, ",")
- if err != nil {
- return "", errs.Wrap(errStr(err, str))
+// checkMinio checks the MinIO connection
+func checkMinio(config *config.GlobalConfig) error {
+ // Check if MinIO is enabled
+ if config.Object.Enable != "minio" {
+ return errs.Wrap(errors.New("minio.Enable is empty"))
}
-
- return str, nil
+ minio := &component.Minio{
+ ApiURL: config.Object.ApiURL,
+ Endpoint: config.Object.Minio.Endpoint,
+ AccessKeyID: config.Object.Minio.AccessKeyID,
+ SecretAccessKey: config.Object.Minio.SecretAccessKey,
+ SignEndpoint: config.Object.Minio.SignEndpoint,
+ UseSSL: getEnv("MINIO_USE_SSL", "false"),
+ }
+ err := component.CheckMinio(minio)
+ return err
}
// checkZookeeper checks the Zookeeper connection
-func checkZookeeper() (string, error) {
- // Prioritize environment variables
- schema := getEnv("ZOOKEEPER_SCHEMA", "digest")
- address := getEnv("ZOOKEEPER_ADDRESS", strings.Join(config.Config.Zookeeper.ZkAddr, ","))
- username := getEnv("ZOOKEEPER_USERNAME", config.Config.Zookeeper.Username)
- password := getEnv("ZOOKEEPER_PASSWORD", config.Config.Zookeeper.Password)
-
- // Split addresses to handle multiple Zookeeper nodes
- zookeeperAddresses := strings.Split(address, ",")
-
- // Connect to Zookeeper
- str := "the addr is:" + address
- c, eventChan, err := zk.Connect(zookeeperAddresses, time.Second) // Adjust the timeout as necessary
- if err != nil {
- return "", errs.Wrap(errStr(err, str))
+func checkZookeeper(config *config.GlobalConfig) error {
+ zkStu := &component.Zookeeper{
+ Schema: config.Zookeeper.Schema,
+ ZkAddr: config.Zookeeper.ZkAddr,
+ Username: config.Zookeeper.Username,
+ Password: config.Zookeeper.Password,
}
- timeout := time.After(5 * time.Second)
- for {
- select {
- case event := <-eventChan:
- if event.State == zk.StateConnected {
- fmt.Println("Connected to Zookeeper")
- goto Connected
- }
- case <-timeout:
- return "", errs.Wrap(errors.New("timeout waiting for Zookeeper connection"), "Zookeeper Addr: "+strings.Join(config.Config.Zookeeper.ZkAddr, " "))
- }
- }
-Connected:
- defer c.Close()
-
- // Set authentication if username and password are provided
- if username != "" && password != "" {
- if err := c.AddAuth(schema, []byte(username+":"+password)); err != nil {
- return "", errs.Wrap(errStr(err, str))
- }
- }
-
- return str, nil
+ err := component.CheckZookeeper(zkStu)
+ return err
}
// checkKafka checks the Kafka connection
-func checkKafka() (string, error) {
+func checkKafka(config *config.GlobalConfig) error {
// Prioritize environment variables
- username := getEnv("KAFKA_USERNAME", config.Config.Kafka.Username)
- password := getEnv("KAFKA_PASSWORD", config.Config.Kafka.Password)
- address := getEnv("KAFKA_ADDRESS", strings.Join(config.Config.Kafka.Addr, ","))
-
- // Split addresses to handle multiple Kafka brokers
- kafkaAddresses := strings.Split(address, ",")
-
- // Configure Kafka client
- cfg := sarama.NewConfig()
- if username != "" && password != "" {
- cfg.Net.SASL.Enable = true
- cfg.Net.SASL.User = username
- cfg.Net.SASL.Password = password
+ kafkaStu := &component.Kafka{
+ Username: config.Kafka.Username,
+ Password: config.Kafka.Password,
+ Addr: config.Kafka.Addr,
}
- // Additional Kafka setup (e.g., TLS configuration) can be added here
- // kafka.SetupTLSConfig(cfg)
- // Create Kafka client
- str := "the addr is:" + address
- kafkaClient, err := sarama.NewClient(kafkaAddresses, cfg)
+ kafkaClient, err := component.CheckKafka(kafkaStu)
if err != nil {
- return "", errs.Wrap(errStr(err, str))
+ return err
}
defer kafkaClient.Close()
// Verify if necessary topics exist
topics, err := kafkaClient.Topics()
if err != nil {
- return "", errs.Wrap(err)
+ return errs.Wrap(err)
}
requiredTopics := []string{
- config.Config.Kafka.MsgToMongo.Topic,
- config.Config.Kafka.MsgToPush.Topic,
- config.Config.Kafka.LatestMsgToRedis.Topic,
+ config.Kafka.MsgToMongo.Topic,
+ config.Kafka.MsgToPush.Topic,
+ config.Kafka.LatestMsgToRedis.Topic,
}
for _, requiredTopic := range requiredTopics {
if !isTopicPresent(requiredTopic, topics) {
- return "", ErrComponentStart.Wrap(fmt.Sprintf("Kafka doesn't contain topic: %v", requiredTopic))
+ return errs.Wrap(err, fmt.Sprintf("Kafka doesn't contain topic: %v", requiredTopic))
}
}
- return str, nil
+ var tlsConfig *kafka.TLSConfig
+ if config.Kafka.TLS != nil {
+ tlsConfig = &kafka.TLSConfig{
+ CACrt: config.Kafka.TLS.CACrt,
+ ClientCrt: config.Kafka.TLS.ClientCrt,
+ ClientKey: config.Kafka.TLS.ClientKey,
+ ClientKeyPwd: config.Kafka.TLS.ClientKeyPwd,
+ InsecureSkipVerify: config.Kafka.TLS.InsecureSkipVerify,
+ }
+ }
+
+ _, err = kafka.NewMConsumerGroup(&kafka.MConsumerGroupConfig{
+ KafkaVersion: sarama.V2_0_0_0,
+ OffsetsInitial: sarama.OffsetNewest,
+ IsReturnErr: false,
+ UserName: config.Kafka.Username,
+ Password: config.Kafka.Password,
+ }, []string{config.Kafka.LatestMsgToRedis.Topic},
+ config.Kafka.Addr, config.Kafka.ConsumerGroupID.MsgToRedis, tlsConfig)
+ if err != nil {
+ return err
+ }
+
+ _, err = kafka.NewMConsumerGroup(&kafka.MConsumerGroupConfig{
+ KafkaVersion: sarama.V2_0_0_0,
+ OffsetsInitial: sarama.OffsetNewest, IsReturnErr: false,
+ }, []string{config.Kafka.MsgToPush.Topic},
+ config.Kafka.Addr, config.Kafka.ConsumerGroupID.MsgToMongo, tlsConfig)
+ if err != nil {
+ return err
+ }
+
+ kafka.NewMConsumerGroup(&kafka.MConsumerGroupConfig{
+ KafkaVersion: sarama.V2_0_0_0,
+ OffsetsInitial: sarama.OffsetNewest, IsReturnErr: false,
+ }, []string{config.Kafka.MsgToPush.Topic}, config.Kafka.Addr,
+ config.Kafka.ConsumerGroupID.MsgToPush, tlsConfig)
+ if err != nil {
+ return err
+ }
+
+ return nil
}
// isTopicPresent checks if a topic is present in the list of topics
@@ -379,22 +268,99 @@ func isTopicPresent(topic string, topics []string) bool {
return false
}
-func colorPrint(colorCode int, format string, a ...interface{}) {
- fmt.Printf("\x1b[%dm%s\x1b[0m\n", colorCode, fmt.Sprintf(format, a...))
+func configGetEnv(config *config.GlobalConfig) error {
+ config.Mongo.Uri = getEnv("MONGO_URI", config.Mongo.Uri)
+ config.Mongo.Username = getEnv("MONGO_OPENIM_USERNAME", config.Mongo.Username)
+ config.Mongo.Password = getEnv("MONGO_OPENIM_PASSWORD", config.Mongo.Password)
+ config.Mongo.Address = getArrEnv("MONGO_ADDRESS", "MONGO_PORT", config.Mongo.Address)
+ config.Mongo.Database = getEnv("MONGO_DATABASE", config.Mongo.Database)
+ maxPoolSize, err := getEnvInt("MONGO_DATABASE", config.Mongo.MaxPoolSize)
+ if err != nil {
+ return err
+ }
+ config.Mongo.MaxPoolSize = maxPoolSize
+
+ config.Redis.Username = getEnv("REDIS_USERNAME", config.Redis.Username)
+ config.Redis.Password = getEnv("REDIS_PASSWORD", config.Redis.Password)
+ config.Redis.Address = getArrEnv("REDIS_ADDRESS", "REDIS_PASSWORD", config.Redis.Address)
+
+ config.Object.ApiURL = getEnv("OBJECT_APIURL", config.Object.ApiURL)
+ config.Object.Minio.Endpoint = getEnv("MINIO_ENDPOINT", config.Object.Minio.Endpoint)
+ config.Object.Minio.AccessKeyID = getEnv("MINIO_ACCESS_KEY_ID", config.Object.Minio.AccessKeyID)
+ config.Object.Minio.SecretAccessKey = getEnv("MINIO_SECRET_ACCESS_KEY", config.Object.Minio.SecretAccessKey)
+ config.Object.Minio.SignEndpoint = getEnv("MINIO_SIGN_ENDPOINT", config.Object.Minio.SignEndpoint)
+
+ config.Zookeeper.Schema = getEnv("ZOOKEEPER_SCHEMA", config.Zookeeper.Schema)
+ config.Zookeeper.ZkAddr = getArrEnv("ZOOKEEPER_ADDRESS", "ZOOKEEPER_PORT", config.Zookeeper.ZkAddr)
+ config.Zookeeper.Username = getEnv("ZOOKEEPER_USERNAME", config.Zookeeper.Username)
+ config.Zookeeper.Password = getEnv("ZOOKEEPER_PASSWORD", config.Zookeeper.Password)
+
+ config.Kafka.Username = getEnv("KAFKA_USERNAME", config.Kafka.Username)
+ config.Kafka.Password = getEnv("KAFKA_PASSWORD", config.Kafka.Password)
+ config.Kafka.Addr = getArrEnv("KAFKA_ADDRESS", "KAFKA_PORT", config.Kafka.Addr)
+ config.Object.Minio.Endpoint = getMinioAddr("MINIO_ENDPOINT", "MINIO_ADDRESS", "MINIO_PORT", config.Object.Minio.Endpoint)
+ return nil
}
-func errorPrint(s string) {
- colorPrint(colorRed, "%v", s)
+func getMinioAddr(key1, key2, key3, fallback string) string {
+ // Prioritize environment variables
+ endpoint := getEnv(key1, fallback)
+ address, addressExist := os.LookupEnv(key2)
+ port, portExist := os.LookupEnv(key3)
+ if portExist && addressExist {
+ endpoint = "http://" + address + ":" + port
+ return endpoint
+ }
+ return endpoint
}
-func successPrint(s string) {
- colorPrint(colorGreen, "%v", s)
+// Helper function to get environment variable or default value
+func getEnv(key, fallback string) string {
+ if value, exists := os.LookupEnv(key); exists {
+ return value
+ }
+ return fallback
}
-func warningPrint(s string) {
- colorPrint(colorYellow, "Warning: But %v", s)
+// Helper function to get environment variable or default value
+func getEnvInt(key string, fallback int) (int, error) {
+ if value, exists := os.LookupEnv(key); exists {
+ val, err := strconv.Atoi(value)
+ if err != nil {
+ return 0, errs.Wrap(err, "string to int failed")
+ }
+ return val, nil
+ }
+ return fallback, nil
}
-func errStr(err error, str string) error {
- return fmt.Errorf("%v;%s", err, str)
+func getArrEnv(key1, key2 string, fallback []string) []string {
+ address, addrExists := os.LookupEnv(key1)
+ port, portExists := os.LookupEnv(key2)
+
+ if addrExists && portExists {
+ addresses := strings.Split(address, ",")
+ for i, addr := range addresses {
+ addresses[i] = addr + ":" + port
+ }
+ return addresses
+ }
+
+ if addrExists && !portExists {
+ addresses := strings.Split(address, ",")
+ for i, addr := range addresses {
+ addresses[i] = addr + ":" + "0"
+ }
+ return addresses
+ }
+
+ if !addrExists && portExists {
+ result := make([]string, len(fallback))
+ for i, addr := range fallback {
+ add := strings.Split(addr, ":")
+ result[i] = add[0] + ":" + port
+ }
+ return result
+ }
+ return fallback
}
diff --git a/tools/component/component_test.go b/tools/component/component_test.go
index 4488c029e..c56361b2c 100644
--- a/tools/component/component_test.go
+++ b/tools/component/component_test.go
@@ -21,20 +21,11 @@ import (
"time"
"github.com/redis/go-redis/v9"
-
- "github.com/openimsdk/open-im-server/v3/pkg/common/config"
)
-// Mock for initCfg for testing purpose
-func mockInitCfg() error {
- config.Config.Mysql.Username = "root"
- config.Config.Mysql.Password = "openIM123"
- config.Config.Mysql.Address = []string{"127.0.0.1:13306"}
- return nil
-}
-
func TestRedis(t *testing.T) {
- config.Config.Redis.Address = []string{
+ conf, err := initCfg()
+ conf.Redis.Address = []string{
"172.16.8.142:7000",
//"172.16.8.142:7000", "172.16.8.142:7001", "172.16.8.142:7002", "172.16.8.142:7003", "172.16.8.142:7004", "172.16.8.142:7005",
}
@@ -45,20 +36,20 @@ func TestRedis(t *testing.T) {
redisClient.Close()
}
}()
- if len(config.Config.Redis.Address) > 1 {
+ if len(conf.Redis.Address) > 1 {
redisClient = redis.NewClusterClient(&redis.ClusterOptions{
- Addrs: config.Config.Redis.Address,
- Username: config.Config.Redis.Username,
- Password: config.Config.Redis.Password,
+ Addrs: conf.Redis.Address,
+ Username: conf.Redis.Username,
+ Password: conf.Redis.Password,
})
} else {
redisClient = redis.NewClient(&redis.Options{
- Addr: config.Config.Redis.Address[0],
- Username: config.Config.Redis.Username,
- Password: config.Config.Redis.Password,
+ Addr: conf.Redis.Address[0],
+ Username: conf.Redis.Username,
+ Password: conf.Redis.Password,
})
}
- _, err := redisClient.Ping(context.Background()).Result()
+ _, err = redisClient.Ping(context.Background()).Result()
if err != nil {
t.Fatal(err)
}
diff --git a/tools/data-conversion/chat/cmd/conversion-chat/chat.go b/tools/data-conversion/chat/cmd/conversion-chat/chat.go
index 0fc49c782..f68b71b16 100644
--- a/tools/data-conversion/chat/cmd/conversion-chat/chat.go
+++ b/tools/data-conversion/chat/cmd/conversion-chat/chat.go
@@ -28,20 +28,20 @@ import (
func main() {
var (
- usernameV2 = "root" // v2版本mysql用户名
- passwordV2 = "openIM" // v2版本mysql密码
- addrV2 = "127.0.0.1:13306" // v2版本mysql地址
- databaseV2 = "admin_chat" // v2版本mysql数据库名字
+ usernameV2 = "root" // Username for MySQL v2 version
+ passwordV2 = "openIM" // Password for MySQL v2 version
+ addrV2 = "127.0.0.1:13306" // Address for MySQL v2 version
+ databaseV2 = "admin_chat" // Database name for MySQL v2 version
)
var (
- usernameV3 = "root" // v3版本mysql用户名
- passwordV3 = "openIM123" // v3版本mysql密码
- addrV3 = "127.0.0.1:13306" // v3版本mysql地址
- databaseV3 = "openim_enterprise" // v3版本mysql数据库名字
+ usernameV3 = "root" // Username for MySQL v3 version
+ passwordV3 = "openIM123" // Password for MySQL v3 version
+ addrV3 = "127.0.0.1:13306" // Address for MySQL v3 version
+ databaseV3 = "openim_enterprise" // Database name for MySQL v3 version
)
- var concurrency = 1 // 并发数量
+ var concurrency = 1 // Concurrency quantity
log.SetFlags(log.LstdFlags | log.Llongfile)
dsnV2 := fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=utf8mb4&parseTime=True&loc=Local", usernameV2, passwordV2, addrV2, databaseV2)
diff --git a/tools/data-conversion/chat/v2/admin.go b/tools/data-conversion/chat/v2/admin.go
index fec11ff5b..20cf22a36 100644
--- a/tools/data-conversion/chat/v2/admin.go
+++ b/tools/data-conversion/chat/v2/admin.go
@@ -18,7 +18,7 @@ import (
"time"
)
-// AppVersion pc端版本管理
+// AppVersion manages PC client versions
type AppVersion struct {
Version string `gorm:"column:version;size:64" json:"version"`
Type int `gorm:"column:type;primary_key" json:"type"`
@@ -29,7 +29,7 @@ type AppVersion struct {
UpdateLog string `gorm:"column:update_log" json:"update_log"`
}
-// Admin 后台管理员
+// Admin manages backend administrators
type Admin struct {
Account string `gorm:"column:account;primary_key;type:char(64)" json:"account"`
Password string `gorm:"column:Password;type:char(64)" json:"password"`
@@ -40,19 +40,19 @@ type Admin struct {
CreateTime time.Time `gorm:"column:create_time" json:"createTime"`
}
-// RegisterAddFriend 注册时默认好友
+// RegisterAddFriend specifies default friends when registering
type RegisterAddFriend struct {
UserID string `gorm:"column:user_id;primary_key;type:char(64)" json:"userID"`
CreateTime time.Time `gorm:"column:create_time" json:"createTime"`
}
-// RegisterAddGroup 注册时默认群组
+// RegisterAddGroup specifies default groups when registering
type RegisterAddGroup struct {
GroupID string `gorm:"column:group_id;primary_key;type:char(64)" json:"userID"`
CreateTime time.Time `gorm:"column:create_time" json:"createTime"`
}
-// ClientInitConfig 系统相关配置项
+// ClientInitConfig contains system-related configuration items
type ClientInitConfig struct {
DiscoverPageURL string `gorm:"column:discover_page_url;size:128" json:"discoverPageURL"`
OrdinaryUserAddFriend int32 `gorm:"column:ordinary_user_add_friend; default:1" json:"ordinaryUserAddFriend"`
diff --git a/tools/data-conversion/chat/v2/chat.go b/tools/data-conversion/chat/v2/chat.go
index 15cc4797f..4e0a0c04a 100644
--- a/tools/data-conversion/chat/v2/chat.go
+++ b/tools/data-conversion/chat/v2/chat.go
@@ -18,7 +18,7 @@ import (
"time"
)
-// Register 注册信息表
+// Register Registration information sheet
type Register struct {
UserID string `gorm:"column:user_id;primary_key;type:char(64)" json:"userID"`
DeviceID string `gorm:"column:device_id;type:varchar(255)" json:"deviceID"`
@@ -29,7 +29,7 @@ type Register struct {
CreateTime time.Time `gorm:"column:create_time" json:"createTime"`
}
-// Account 账号密码表
+// Account username and password table
type Account struct {
UserID string `gorm:"column:user_id;primary_key;type:char(64)" json:"userID"`
Password string `gorm:"column:password;type:varchar(255)" json:"password"`
@@ -38,7 +38,7 @@ type Account struct {
OperatorUserID string `gorm:"column:operator_user_id;type:varchar(64)" json:"operatorUserID"`
}
-// Attribute 用户属性表
+// Attribute user information table
type Attribute struct {
UserID string `gorm:"column:user_id;primary_key;type:char(64)" json:"userID"`
Account string `gorm:"column:account;type:char(64)" json:"account"`
@@ -58,7 +58,7 @@ type Attribute struct {
AllowAddFriend int32 `gorm:"column:allow_add_friend;default:1" json:"allowAddFriend"`
}
-// 封号表
+// User friend relationship table
type ForbiddenAccount struct {
UserID string `gorm:"column:user_id;index:userID;primary_key;type:char(64)" json:"userID"`
CreateTime time.Time `gorm:"column:create_time" json:"createTime"`
@@ -66,7 +66,7 @@ type ForbiddenAccount struct {
OperatorUserID string `gorm:"column:operator_user_id;type:varchar(255)" json:"operatorUserID"`
}
-// 用户登录信息表
+// user login record table
type UserLoginRecord struct {
UserID string `gorm:"column:user_id;size:64" json:"userID"`
LoginTime time.Time `gorm:"column:login_time" json:"loginTime"`
@@ -75,7 +75,7 @@ type UserLoginRecord struct {
Platform string `gorm:"column:platform;type:varchar(32)" json:"platform"`
}
-// 禁止ip登录 注册
+// ip login registration is prohibited
type IPForbidden struct {
IP string `gorm:"column:ip;primary_key;type:char(32)" json:"ip"`
LimitRegister int32 `gorm:"column:limit_register" json:"limitRegister"`
@@ -83,14 +83,14 @@ type IPForbidden struct {
CreateTime time.Time `gorm:"column:create_time" json:"createTime"`
}
-// 限制userID只能在某些ip登录
+// Restrict userids to certain ip addresses
type LimitUserLoginIP struct {
UserID string `gorm:"column:user_id;primary_key;type:char(64)" json:"userID"`
IP string `gorm:"column:ip;primary_key;type:char(32)" json:"ip"`
CreateTime time.Time `gorm:"column:create_time" json:"createTime"`
}
-// 邀请码被注册使用
+// The invitation code is registered for use
type InvitationRegister struct {
InvitationCode string `gorm:"column:invitation_code;primary_key;type:char(32)" json:"invitationCode"`
CreateTime time.Time `gorm:"column:create_time" json:"createTime"`
diff --git a/tools/data-conversion/chat/v3/admin/admin.go b/tools/data-conversion/chat/v3/admin/admin.go
index 22a81a068..90bd7f8f7 100644
--- a/tools/data-conversion/chat/v3/admin/admin.go
+++ b/tools/data-conversion/chat/v3/admin/admin.go
@@ -18,7 +18,7 @@ import (
"time"
)
-// Admin 后台管理员.
+// Admin Background administrator.
type Admin struct {
Account string `gorm:"column:account;primary_key;type:varchar(64)"`
Password string `gorm:"column:password;type:varchar(64)"`
diff --git a/tools/data-conversion/chat/v3/admin/client_config.go b/tools/data-conversion/chat/v3/admin/client_config.go
index ceccd5105..48869fceb 100644
--- a/tools/data-conversion/chat/v3/admin/client_config.go
+++ b/tools/data-conversion/chat/v3/admin/client_config.go
@@ -14,7 +14,7 @@
package admin
-// ClientConfig 客户端相关配置项.
+// ClientConfig Client related configuration items.
type ClientConfig struct {
Key string `gorm:"column:key;primary_key;type:varchar(255)"`
Value string `gorm:"column:value;not null;type:text"`
diff --git a/tools/data-conversion/chat/v3/admin/forbidden_account.go b/tools/data-conversion/chat/v3/admin/forbidden_account.go
index 104e793b0..e08125699 100644
--- a/tools/data-conversion/chat/v3/admin/forbidden_account.go
+++ b/tools/data-conversion/chat/v3/admin/forbidden_account.go
@@ -18,7 +18,7 @@ import (
"time"
)
-// ForbiddenAccount 封号表.
+// ForbiddenAccount forbidden account.
type ForbiddenAccount struct {
UserID string `gorm:"column:user_id;index:userID;primary_key;type:char(64)"`
Reason string `gorm:"column:reason;type:varchar(255)" `
diff --git a/tools/data-conversion/chat/v3/admin/invitation_register.go b/tools/data-conversion/chat/v3/admin/invitation_register.go
index 60f9067e2..4b71ccfe0 100644
--- a/tools/data-conversion/chat/v3/admin/invitation_register.go
+++ b/tools/data-conversion/chat/v3/admin/invitation_register.go
@@ -18,7 +18,7 @@ import (
"time"
)
-// 邀请码被注册使用.
+// The invitation code is registered for use.
type InvitationRegister struct {
InvitationCode string `gorm:"column:invitation_code;primary_key;type:char(32)"`
UsedByUserID string `gorm:"column:user_id;index:userID;type:char(64)"`
diff --git a/tools/data-conversion/chat/v3/admin/ip_forbidden.go b/tools/data-conversion/chat/v3/admin/ip_forbidden.go
index 40c9257ef..886924abb 100644
--- a/tools/data-conversion/chat/v3/admin/ip_forbidden.go
+++ b/tools/data-conversion/chat/v3/admin/ip_forbidden.go
@@ -18,7 +18,7 @@ import (
"time"
)
-// 禁止ip登录 注册.
+// ip login registration is prohibited.
type IPForbidden struct {
IP string `gorm:"column:ip;primary_key;type:char(32)"`
LimitRegister bool `gorm:"column:limit_register"`
diff --git a/tools/data-conversion/chat/v3/admin/limit_user_login_ip.go b/tools/data-conversion/chat/v3/admin/limit_user_login_ip.go
index 8427eaf80..0eaa5bc1e 100644
--- a/tools/data-conversion/chat/v3/admin/limit_user_login_ip.go
+++ b/tools/data-conversion/chat/v3/admin/limit_user_login_ip.go
@@ -18,7 +18,7 @@ import (
"time"
)
-// 限制userID只能在某些ip登录.
+// Restrict userids to certain ip addresses.
type LimitUserLoginIP struct {
UserID string `gorm:"column:user_id;primary_key;type:char(64)"`
IP string `gorm:"column:ip;primary_key;type:char(32)"`
diff --git a/tools/data-conversion/chat/v3/admin/register_add_friend.go b/tools/data-conversion/chat/v3/admin/register_add_friend.go
index e21896d90..8281f6485 100644
--- a/tools/data-conversion/chat/v3/admin/register_add_friend.go
+++ b/tools/data-conversion/chat/v3/admin/register_add_friend.go
@@ -18,7 +18,7 @@ import (
"time"
)
-// RegisterAddFriend 注册时默认好友.
+// RegisterAddFriend Indicates the default friend when registering.
type RegisterAddFriend struct {
UserID string `gorm:"column:user_id;primary_key;type:char(64)"`
CreateTime time.Time `gorm:"column:create_time"`
diff --git a/tools/data-conversion/chat/v3/admin/register_add_group.go b/tools/data-conversion/chat/v3/admin/register_add_group.go
index e9c1317b9..1204ff97b 100644
--- a/tools/data-conversion/chat/v3/admin/register_add_group.go
+++ b/tools/data-conversion/chat/v3/admin/register_add_group.go
@@ -18,7 +18,7 @@ import (
"time"
)
-// RegisterAddGroup 注册时默认群组.
+// RegisterAddGroup Indicates the default group for registration.
type RegisterAddGroup struct {
GroupID string `gorm:"column:group_id;primary_key;type:char(64)"`
CreateTime time.Time `gorm:"column:create_time"`
diff --git a/tools/data-conversion/chat/v3/chat/account.go b/tools/data-conversion/chat/v3/chat/account.go
index d2117e7ca..6d01c20e2 100644
--- a/tools/data-conversion/chat/v3/chat/account.go
+++ b/tools/data-conversion/chat/v3/chat/account.go
@@ -18,7 +18,7 @@ import (
"time"
)
-// Account 账号密码表.
+// Account Account password table.
type Account struct {
UserID string `gorm:"column:user_id;primary_key;type:char(64)"`
Password string `gorm:"column:password;type:varchar(32)"`
diff --git a/tools/data-conversion/chat/v3/chat/attribute.go b/tools/data-conversion/chat/v3/chat/attribute.go
index 6a6f975d1..23de217bd 100644
--- a/tools/data-conversion/chat/v3/chat/attribute.go
+++ b/tools/data-conversion/chat/v3/chat/attribute.go
@@ -18,7 +18,7 @@ import (
"time"
)
-// Attribute 用户属性表.
+// Attribute Indicates the user attribute table.
type Attribute struct {
UserID string `gorm:"column:user_id;primary_key;type:char(64)"`
Account string `gorm:"column:account;type:char(64)"`
diff --git a/tools/data-conversion/chat/v3/chat/register.go b/tools/data-conversion/chat/v3/chat/register.go
index 740159436..29e5cb698 100644
--- a/tools/data-conversion/chat/v3/chat/register.go
+++ b/tools/data-conversion/chat/v3/chat/register.go
@@ -18,7 +18,7 @@ import (
"time"
)
-// Register 注册信息表.
+// Register Indicates the registration information.
type Register struct {
UserID string `gorm:"column:user_id;primary_key;type:char(64)"`
DeviceID string `gorm:"column:device_id;type:varchar(255)"`
diff --git a/tools/data-conversion/chat/v3/chat/user_login_record.go b/tools/data-conversion/chat/v3/chat/user_login_record.go
index 8db3699d6..31e57b6ce 100644
--- a/tools/data-conversion/chat/v3/chat/user_login_record.go
+++ b/tools/data-conversion/chat/v3/chat/user_login_record.go
@@ -18,7 +18,7 @@ import (
"time"
)
-// 用户登录信息表.
+// User login information table.
type UserLoginRecord struct {
UserID string `gorm:"column:user_id;size:64"`
LoginTime time.Time `gorm:"column:login_time"`
diff --git a/tools/data-conversion/openim/cmd/conversion-msg/conversion-msg.go b/tools/data-conversion/openim/cmd/conversion-msg/conversion-msg.go
index f2b9623a6..416fdcb9f 100644
--- a/tools/data-conversion/openim/cmd/conversion-msg/conversion-msg.go
+++ b/tools/data-conversion/openim/cmd/conversion-msg/conversion-msg.go
@@ -38,11 +38,20 @@ import (
func main() {
var (
- topic = "ws2ms_chat" // v2版本配置文件kafka.topic.ws2ms_chat
- kafkaAddr = "127.0.0.1:9092" // v2版本配置文件kafka.topic.addr
- rpcAddr = "127.0.0.1:10130" // v3版本配置文件rpcPort.openImMessagePort
- adminUserID = "openIM123456" // v3版本管理员userID
- concurrency = 1 // 并发数量
+ // The Kafka topic for ws2ms_chat in version 2 configuration
+ topic = "ws2ms_chat"
+
+ // The Kafka address in version 2 configuration
+ kafkaAddr = "127.0.0.1:9092"
+
+ // The RPC address in version 3 configuration
+ rpcAddr = "127.0.0.1:10130"
+
+ // The administrator userID in version 3
+ adminUserID = "openIM123456"
+
+ // The number of concurrent processes
+ concurrency = 1
)
getRpcConn := func() (*grpc.ClientConn, error) {
@@ -99,7 +108,7 @@ func main() {
ch := pc.Messages()
for {
select {
- case <-time.After(time.Second * 10): // 10s读取不到就关闭
+ case <-time.After(time.Second * 10): // 10s Shuts down when the data cannot be read
return
case message, ok := <-ch:
if !ok {
diff --git a/tools/data-conversion/openim/cmd/conversion-mysql/conversion-mysql.go b/tools/data-conversion/openim/cmd/conversion-mysql/conversion-mysql.go
index 8a951e16f..08fa4ca55 100644
--- a/tools/data-conversion/openim/cmd/conversion-mysql/conversion-mysql.go
+++ b/tools/data-conversion/openim/cmd/conversion-mysql/conversion-mysql.go
@@ -27,21 +27,37 @@ import (
)
func main() {
+
var (
- usernameV2 = "root" // v2版本mysql用户名
- passwordV2 = "openIM" // v2版本mysql密码
- addrV2 = "127.0.0.1:13306" // v2版本mysql地址
- databaseV2 = "openIM_v2" // v2版本mysql数据库名字
+ // MySQL username for version 2
+ usernameV2 = "root"
+
+ // MySQL password for version 2
+ passwordV2 = "openIM"
+
+ // MySQL address for version 2
+ addrV2 = "127.0.0.1:13306"
+
+ // MySQL database name for version 2
+ databaseV2 = "openIM_v2"
)
var (
- usernameV3 = "root" // v3版本mysql用户名
- passwordV3 = "openIM123" // v3版本mysql密码
- addrV3 = "127.0.0.1:13306" // v3版本mysql地址
- databaseV3 = "openim_v3" // v3版本mysql数据库名字
+ // MySQL username for version 3
+ usernameV3 = "root"
+
+ // MySQL password for version 3
+ passwordV3 = "openIM123"
+
+ // MySQL address for version 3
+ addrV3 = "127.0.0.1:13306"
+
+ // MySQL database name for version 3
+ databaseV3 = "openim_v3"
)
- var concurrency = 1 // 并发数量
+ // The number of concurrent processes
+ var concurrency = 1
log.SetFlags(log.LstdFlags | log.Llongfile)
dsnV2 := fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=utf8mb4&parseTime=True&loc=Local", usernameV2, passwordV2, addrV2, databaseV2)
diff --git a/tools/data-conversion/openim/mysql/v3/friend.go b/tools/data-conversion/openim/mysql/v3/friend.go
index 58d8d1d34..4f3fb6bdf 100644
--- a/tools/data-conversion/openim/mysql/v3/friend.go
+++ b/tools/data-conversion/openim/mysql/v3/friend.go
@@ -38,41 +38,30 @@ func (FriendModel) TableName() string {
}
type FriendModelInterface interface {
- // 插入多条记录
- Create(ctx context.Context, friends []*FriendModel) (err error)
- // 删除ownerUserID指定的好友
- Delete(ctx context.Context, ownerUserID string, friendUserIDs []string) (err error)
- // 更新ownerUserID单个好友信息 更新零值
- UpdateByMap(ctx context.Context, ownerUserID string, friendUserID string, args map[string]interface{}) (err error)
- // 更新好友信息的非零值
- Update(ctx context.Context, friends []*FriendModel) (err error)
- // 更新好友备注(也支持零值 )
- UpdateRemark(ctx context.Context, ownerUserID, friendUserID, remark string) (err error)
- // 获取单个好友信息,如没找到 返回错误
- Take(ctx context.Context, ownerUserID, friendUserID string) (friend *FriendModel, err error)
- // 查找好友关系,如果是双向关系,则都返回
- FindUserState(ctx context.Context, userID1, userID2 string) (friends []*FriendModel, err error)
- // 获取 owner指定的好友列表 如果有friendUserIDs不存在,也不返回错误
- FindFriends(ctx context.Context, ownerUserID string, friendUserIDs []string) (friends []*FriendModel, err error)
- // 获取哪些人添加了friendUserID 如果有ownerUserIDs不存在,也不返回错误
- FindReversalFriends(
- ctx context.Context,
- friendUserID string,
- ownerUserIDs []string,
- ) (friends []*FriendModel, err error)
- // 获取ownerUserID好友列表 支持翻页
- FindOwnerFriends(
- ctx context.Context,
- ownerUserID string,
- pageNumber, showNumber int32,
- ) (friends []*FriendModel, total int64, err error)
- // 获取哪些人添加了friendUserID 支持翻页
- FindInWhoseFriends(
- ctx context.Context,
- friendUserID string,
- pageNumber, showNumber int32,
- ) (friends []*FriendModel, total int64, err error)
- // 获取好友UserID列表
- FindFriendUserIDs(ctx context.Context, ownerUserID string) (friendUserIDs []string, err error)
+ // Create inserts multiple friend records.
+ Create(ctx context.Context, friends []*FriendModel) error
+ // Delete removes specified friends for an owner user.
+ Delete(ctx context.Context, ownerUserID string, friendUserIDs []string) error
+ // UpdateByMap updates a single friend's information for an owner user based on a map of arguments. Zero values are updated.
+ UpdateByMap(ctx context.Context, ownerUserID string, friendUserID string, args map[string]interface{}) error
+ // Update modifies the information of friends, excluding zero values.
+ Update(ctx context.Context, friends []*FriendModel) error
+ // UpdateRemark updates the remark for a friend, supporting zero values.
+ UpdateRemark(ctx context.Context, ownerUserID, friendUserID, remark string) error
+ // Take retrieves a single friend's information. Returns an error if not found.
+ Take(ctx context.Context, ownerUserID, friendUserID string) (*FriendModel, error)
+ // FindUserState finds the friendship status between two users, returning both if a mutual friendship exists.
+ FindUserState(ctx context.Context, userID1, userID2 string) ([]*FriendModel, error)
+ // FindFriends retrieves a list of friends for an owner, not returning an error for non-existent friendUserIDs.
+ FindFriends(ctx context.Context, ownerUserID string, friendUserIDs []string) ([]*FriendModel, error)
+ // FindReversalFriends finds who has added the specified user as a friend, not returning an error for non-existent ownerUserIDs.
+ FindReversalFriends(ctx context.Context, friendUserID string, ownerUserIDs []string) ([]*FriendModel, error)
+ // FindOwnerFriends paginates through the friends list of an owner user.
+ FindOwnerFriends(ctx context.Context, ownerUserID string, pageNumber, showNumber int32) ([]*FriendModel, int64, error)
+ // FindInWhoseFriends paginates through users who have added the specified user as a friend.
+ FindInWhoseFriends(ctx context.Context, friendUserID string, pageNumber, showNumber int32) ([]*FriendModel, int64, error)
+ // FindFriendUserIDs retrieves a list of friend user IDs for an owner user.
+ FindFriendUserIDs(ctx context.Context, ownerUserID string) ([]string, error)
+ // NewTx creates a new transactional instance of the FriendModelInterface.
NewTx(tx any) FriendModelInterface
}
diff --git a/tools/data-conversion/openim/mysql/v3/friend_request.go b/tools/data-conversion/openim/mysql/v3/friend_request.go
index 51ea0ef6e..4fc5ba7c1 100644
--- a/tools/data-conversion/openim/mysql/v3/friend_request.go
+++ b/tools/data-conversion/openim/mysql/v3/friend_request.go
@@ -38,29 +38,33 @@ func (FriendRequestModel) TableName() string {
}
type FriendRequestModelInterface interface {
- // 插入多条记录
+ // Insert multiple records
Create(ctx context.Context, friendRequests []*FriendRequestModel) (err error)
- // 删除记录
+
+ // Delete a record
Delete(ctx context.Context, fromUserID, toUserID string) (err error)
- // 更新零值
- UpdateByMap(ctx context.Context, formUserID string, toUserID string, args map[string]interface{}) (err error)
- // 更新多条记录 (非零值)
+
+ // Update records with zero values based on a map of changes
+ UpdateByMap(ctx context.Context, formUserID, toUserID string, args map[string]interface{}) (err error)
+
+ // Update multiple records (non-zero values)
Update(ctx context.Context, friendRequest *FriendRequestModel) (err error)
- // 获取来指定用户的好友申请 未找到 不返回错误
+
+ // Find a friend request sent to a specific user; does not return an error if not found
Find(ctx context.Context, fromUserID, toUserID string) (friendRequest *FriendRequestModel, err error)
+
+ // Alias for Find (retrieves a friend request between two users)
Take(ctx context.Context, fromUserID, toUserID string) (friendRequest *FriendRequestModel, err error)
- // 获取toUserID收到的好友申请列表
- FindToUserID(
- ctx context.Context,
- toUserID string,
- pageNumber, showNumber int32,
- ) (friendRequests []*FriendRequestModel, total int64, err error)
- // 获取fromUserID发出去的好友申请列表
- FindFromUserID(
- ctx context.Context,
- fromUserID string,
- pageNumber, showNumber int32,
- ) (friendRequests []*FriendRequestModel, total int64, err error)
+
+ // Get a list of friend requests received by `toUserID`
+ FindToUserID(ctx context.Context, toUserID string, pageNumber, showNumber int32) (friendRequests []*FriendRequestModel, total int64, err error)
+
+ // Get a list of friend requests sent by `fromUserID`
+ FindFromUserID(ctx context.Context, fromUserID string, pageNumber, showNumber int32) (friendRequests []*FriendRequestModel, total int64, err error)
+
+ // Find all friend requests between two users (both directions)
FindBothFriendRequests(ctx context.Context, fromUserID, toUserID string) (friends []*FriendRequestModel, err error)
+
+ // Create a new transaction
NewTx(tx any) FriendRequestModelInterface
}
diff --git a/tools/data-conversion/openim/mysql/v3/group.go b/tools/data-conversion/openim/mysql/v3/group.go
index 6759e0d35..ccf61266a 100644
--- a/tools/data-conversion/openim/mysql/v3/group.go
+++ b/tools/data-conversion/openim/mysql/v3/group.go
@@ -58,9 +58,10 @@ type GroupModelInterface interface {
keyword string,
pageNumber, showNumber int32,
) (total uint32, groups []*GroupModel, err error)
+ // GetGroupIDsByCreatorUserID retrieves a list of group IDs created by the specified user.
GetGroupIDsByGroupType(ctx context.Context, groupType int) (groupIDs []string, err error)
- // 获取群总数
+ // CountTotal retrieves the total number of groups.
CountTotal(ctx context.Context, before *time.Time) (count int64, err error)
- // 获取范围内群增量
+ // CountRangeEverydayTotal retrieves the total number of groups created every day within the specified time range.
CountRangeEverydayTotal(ctx context.Context, start time.Time, end time.Time) (map[string]int64, error)
}
diff --git a/tools/data-conversion/openim/mysql/v3/user.go b/tools/data-conversion/openim/mysql/v3/user.go
index 10a715bda..409689933 100644
--- a/tools/data-conversion/openim/mysql/v3/user.go
+++ b/tools/data-conversion/openim/mysql/v3/user.go
@@ -53,20 +53,35 @@ func (UserModel) TableName() string {
return UserModelTableName
}
+// UserModelInterface defines the operations available for managing user models.
type UserModelInterface interface {
+ // Create inserts a new user or multiple users into the database.
Create(ctx context.Context, users []*UserModel) (err error)
+
+ // UpdateByMap updates a user's information based on a map of changes.
UpdateByMap(ctx context.Context, userID string, args map[string]interface{}) (err error)
+
+ // Update modifies a user's information in the database.
Update(ctx context.Context, user *UserModel) (err error)
- // 获取指定用户信息 不存在,也不返回错误
+
+ // Find retrieves information for a list of users by their IDs. If a user does not exist, it is simply skipped without returning an error.
Find(ctx context.Context, userIDs []string) (users []*UserModel, err error)
- // 获取某个用户信息 不存在,则返回错误
+
+ // Take retrieves a specific user's information by their ID. Returns an error if the user does not exist.
Take(ctx context.Context, userID string) (user *UserModel, err error)
- // 获取用户信息 不存在,不返回错误
+
+ // Page retrieves a paginated list of users and the total count of users. If no users exist, returns an empty list without an error.
Page(ctx context.Context, pageNumber, showNumber int32) (users []*UserModel, count int64, err error)
+
+ // GetAllUserID retrieves all user IDs in a paginated manner.
GetAllUserID(ctx context.Context, pageNumber, showNumber int32) (userIDs []string, err error)
+
+ // GetUserGlobalRecvMsgOpt retrieves a user's global message receiving option.
GetUserGlobalRecvMsgOpt(ctx context.Context, userID string) (opt int, err error)
- // 获取用户总数
+
+ // CountTotal returns the total number of users before a specified time.
CountTotal(ctx context.Context, before *time.Time) (count int64, err error)
- // 获取范围内用户增量
+
+ // CountRangeEverydayTotal calculates the daily increment of users within a specified time range.
CountRangeEverydayTotal(ctx context.Context, start time.Time, end time.Time) (map[string]int64, error)
}
diff --git a/tools/formitychecker/checker/checker.go b/tools/formitychecker/checker/checker.go
index 7a1643358..b17cc5427 100644
--- a/tools/formitychecker/checker/checker.go
+++ b/tools/formitychecker/checker/checker.go
@@ -21,6 +21,8 @@ import (
"regexp"
"strings"
+ "github.com/OpenIMSDK/tools/errs"
+
"github.com/openimsdk/open-im-server/tools/formitychecker/config"
)
@@ -29,7 +31,7 @@ var (
hyphenRegex = regexp.MustCompile(`^[a-zA-Z0-9\-]+\.[a-zA-Z0-9]+$`)
)
-// CheckDirectoCheckDirectoryries initiates the checking process for the specified directories using configuration from config.Config.
+// CheckDirectory initiates the checking process for the specified directories using configuration from config.Config.
func CheckDirectory(cfg *config.Config) error {
ignoreMap := make(map[string]struct{})
for _, dir := range cfg.IgnoreDirs {
@@ -39,7 +41,7 @@ func CheckDirectory(cfg *config.Config) error {
for _, targetDir := range cfg.TargetDirs {
err := filepath.Walk(targetDir, func(path string, info os.FileInfo, err error) error {
if err != nil {
- return err
+ return errs.Wrap(err, fmt.Sprintf("error walking directory '%s'", targetDir))
}
// Skip if the directory is in the ignore list
diff --git a/tools/infra/infra.go b/tools/infra/infra.go
index c14b92fa3..bc01a00eb 100644
--- a/tools/infra/infra.go
+++ b/tools/infra/infra.go
@@ -20,7 +20,7 @@ import (
"github.com/fatih/color"
)
-// 定义一个函数以打印重要的链接信息
+// Define a function to print important link information
func printLinks() {
blue := color.New(color.FgBlue).SprintFunc()
fmt.Printf("OpenIM Github: %s\n", blue("https://github.com/OpenIMSDK/Open-IM-Server"))
@@ -47,5 +47,5 @@ Keep checking for updates!
`
blue.Println(message)
- printLinks() // 调用函数以打印链接信息
+ printLinks() // Call the function to print the link information
}
diff --git a/tools/ncpu/ncpu.go b/tools/ncpu/ncpu.go
index 7ca3dff5e..062618b27 100644
--- a/tools/ncpu/ncpu.go
+++ b/tools/ncpu/ncpu.go
@@ -1,4 +1,4 @@
-// Copyright © 2023 OpenIM. All rights reserved.
+// 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.
@@ -22,6 +22,11 @@ import (
)
func main() {
- maxprocs.Set()
- fmt.Print(runtime.GOMAXPROCS(0))
+ // Set maxprocs with a custom logger that does nothing to ignore logs.
+ maxprocs.Set(maxprocs.Logger(func(string, ...interface{}) {
+ // Intentionally left blank to suppress all log output from automaxprocs.
+ }))
+
+ // Now this will print the GOMAXPROCS value without printing the automaxprocs log message.
+ fmt.Println(runtime.GOMAXPROCS(0))
}
diff --git a/tools/up35/pkg/pkg.go b/tools/up35/pkg/pkg.go
index b7e7c01f5..54aef1ce9 100644
--- a/tools/up35/pkg/pkg.go
+++ b/tools/up35/pkg/pkg.go
@@ -23,6 +23,8 @@ import (
"reflect"
"strconv"
+ "github.com/OpenIMSDK/tools/errs"
+
"gopkg.in/yaml.v3"
"github.com/go-sql-driver/mysql"
@@ -45,36 +47,43 @@ const (
versionValue = 35
)
-func InitConfig(path string) error {
+func InitConfig(path string) (*config.GlobalConfig, error) {
data, err := os.ReadFile(path)
if err != nil {
- return err
+ return nil, errs.Wrap(err, "ReadFile unmarshal failed")
}
- return yaml.Unmarshal(data, &config.Config)
+
+ conf := config.NewGlobalConfig()
+ err = yaml.Unmarshal(data, &conf)
+ if err != nil {
+ return nil, errs.Wrap(err, "InitConfig unmarshal failed")
+ }
+ return conf, nil
}
-func GetMysql() (*gorm.DB, error) {
- conf := config.Config.Mysql
+func GetMysql(config *config.GlobalConfig) (*gorm.DB, error) {
+ conf := config.Mysql
mysqlDSN := fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=utf8mb4&parseTime=True&loc=Local", conf.Username, conf.Password, conf.Address[0], conf.Database)
return gorm.Open(gormmysql.Open(mysqlDSN), &gorm.Config{Logger: logger.Discard})
}
-func GetMongo() (*mongo.Database, error) {
- mgo, err := unrelation.NewMongo()
+func GetMongo(config *config.GlobalConfig) (*mongo.Database, error) {
+ mgo, err := unrelation.NewMongo(config)
if err != nil {
return nil, err
}
- return mgo.GetDatabase(), nil
+ return mgo.GetDatabase(config.Mongo.Database), nil
}
func Main(path string) error {
- if err := InitConfig(path); err != nil {
+ conf, err := InitConfig(path)
+ if err != nil {
return err
}
- if config.Config.Mysql == nil {
+ if conf.Mysql == nil {
return nil
}
- mongoDB, err := GetMongo()
+ mongoDB, err := GetMongo(conf)
if err != nil {
return err
}
@@ -91,7 +100,7 @@ func Main(path string) error {
default:
return err
}
- mysqlDB, err := GetMysql()
+ mysqlDB, err := GetMysql(conf)
if err != nil {
if mysqlErr, ok := err.(*mysql.MySQLError); ok && mysqlErr.Number == 1049 {
if err := SetMongoDataVersion(mongoDB, version.Value); err != nil {
@@ -113,7 +122,7 @@ func Main(path string) error {
func() error { return NewTask(mysqlDB, mongoDB, mgo.NewGroupMember, c.GroupMember) },
func() error { return NewTask(mysqlDB, mongoDB, mgo.NewGroupRequestMgo, c.GroupRequest) },
func() error { return NewTask(mysqlDB, mongoDB, mgo.NewConversationMongo, c.Conversation) },
- func() error { return NewTask(mysqlDB, mongoDB, mgo.NewS3Mongo, c.Object(config.Config.Object.Enable)) },
+ func() error { return NewTask(mysqlDB, mongoDB, mgo.NewS3Mongo, c.Object(conf.Object.Enable)) },
func() error { return NewTask(mysqlDB, mongoDB, mgo.NewLogMongo, c.Log) },
func() error { return NewTask(mysqlDB, mongoDB, rtcmgo.NewSignal, c.SignalModel) },
@@ -152,7 +161,7 @@ func NewTask[A interface{ TableName() string }, B any, C any](gormDB *gorm.DB, m
tableName := zero.TableName()
coll, err := getColl(obj)
if err != nil {
- return fmt.Errorf("get mongo collection %s failed, err: %w", tableName, err)
+ return errs.Wrap(fmt.Errorf("get mongo collection %s failed, err: %w", tableName, err))
}
var count int
defer func() {
@@ -165,7 +174,7 @@ func NewTask[A interface{ TableName() string }, B any, C any](gormDB *gorm.DB, m
if mysqlErr, ok := err.(*mysql.MySQLError); ok && mysqlErr.Number == 1146 {
return nil // table not exist
}
- return fmt.Errorf("find mysql table %s failed, err: %w", tableName, err)
+ return errs.Wrap(fmt.Errorf("find mysql table %s failed, err: %w", tableName, err))
}
if len(res) == 0 {
return nil
@@ -175,7 +184,7 @@ func NewTask[A interface{ TableName() string }, B any, C any](gormDB *gorm.DB, m
temp[i] = convert(res[i])
}
if err := insertMany(coll, temp); err != nil {
- return fmt.Errorf("insert mongo table %s failed, err: %w", tableName, err)
+ return errs.Wrap(fmt.Errorf("insert mongo table %s failed, err: %w", tableName, err))
}
count += len(res)
if len(res) < batch {
@@ -188,7 +197,7 @@ func NewTask[A interface{ TableName() string }, B any, C any](gormDB *gorm.DB, m
func insertMany(coll *mongo.Collection, objs []any) error {
if _, err := coll.InsertMany(context.Background(), objs); err != nil {
if !mongo.IsDuplicateKeyError(err) {
- return err
+ return errs.Wrap(err)
}
}
for i := range objs {
diff --git a/tools/url2im/main.go b/tools/url2im/main.go
index 8d6151b09..9e319932f 100644
--- a/tools/url2im/main.go
+++ b/tools/url2im/main.go
@@ -31,17 +31,38 @@ import (
*/
func main() {
- var conf pkg.Config // 后面带*的为必填项
- flag.StringVar(&conf.TaskPath, "task", "take.txt", "task path") // 任务日志文件*
- flag.StringVar(&conf.ProgressPath, "progress", "", "progress path") // 进度日志文件
- flag.IntVar(&conf.Concurrency, "concurrency", 1, "concurrency num") // 并发数
- flag.IntVar(&conf.Retry, "retry", 1, "retry num") // 重试次数
- flag.StringVar(&conf.TempDir, "temp", "", "temp dir") // 临时文件夹
- flag.Int64Var(&conf.CacheSize, "cache", 1024*1024*100, "cache size") // 缓存大小(超过时,下载到磁盘)
- flag.Int64Var((*int64)(&conf.Timeout), "timeout", 5000, "timeout") // 请求超时时间(毫秒)
- flag.StringVar(&conf.Api, "api", "http://127.0.0.1:10002", "api") // im地址*
- flag.StringVar(&conf.UserID, "userID", "openIM123456", "userID") // im管理员
- flag.StringVar(&conf.Secret, "secret", "openIM123", "secret") // im config secret
+ var conf pkg.Config // Configuration object, '*' denotes required fields
+
+ // *Required*: Path for the task log file
+ flag.StringVar(&conf.TaskPath, "task", "take.txt", "Path for the task log file")
+
+ // Optional: Path for the progress log file
+ flag.StringVar(&conf.ProgressPath, "progress", "", "Path for the progress log file")
+
+ // Number of concurrent operations
+ flag.IntVar(&conf.Concurrency, "concurrency", 1, "Number of concurrent operations")
+
+ // Number of retry attempts
+ flag.IntVar(&conf.Retry, "retry", 1, "Number of retry attempts")
+
+ // Optional: Path for the temporary directory
+ flag.StringVar(&conf.TempDir, "temp", "", "Path for the temporary directory")
+
+ // Cache size in bytes (downloads move to disk when exceeded)
+ flag.Int64Var(&conf.CacheSize, "cache", 1024*1024*100, "Cache size in bytes")
+
+ // Request timeout in milliseconds
+ flag.Int64Var((*int64)(&conf.Timeout), "timeout", 5000, "Request timeout in milliseconds")
+
+ // *Required*: API endpoint for the IM service
+ flag.StringVar(&conf.Api, "api", "http://127.0.0.1:10002", "API endpoint for the IM service")
+
+ // IM administrator's user ID
+ flag.StringVar(&conf.UserID, "userID", "openIM123456", "IM administrator's user ID")
+
+ // Secret for the IM configuration
+ flag.StringVar(&conf.Secret, "secret", "openIM123", "Secret for the IM configuration")
+
flag.Parse()
if !filepath.IsAbs(conf.TaskPath) {
var err error