Merge branch 'openimsdk:main' into main

pull/2087/head
chao 7 months ago committed by GitHub
commit 39a6141787
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -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 "<details><summary>Command Output for OpenIM E2E Test</summary>" >> ./tmp/test.md

@ -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

@ -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,7 +140,7 @@ 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
@ -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`.

@ -8,6 +8,12 @@
## [Unreleased]
<a name="v3.5.1-alpha.2"></a>
## [v3.5.1-alpha.2] - 2024-01-26
<a name="v3.5.1-rc.1"></a>
## [v3.5.1-rc.1] - 2024-01-23
<a name="v3.5.1-alpha.1"></a>
## [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

@ -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

@ -51,6 +51,15 @@
</p>
## :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.
@ -118,6 +127,8 @@ We support many platforms. Here are the addresses for quick experience on the we
[![Open in Dev Container](https://img.shields.io/static/v1?label=Dev%20Container&message=Open&color=blue&logo=visualstudiocode)](https://vscode.dev/github/openimsdk/open-im-server)
[![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](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).
@ -154,16 +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)
+ 👫 [Join our Reddit](https://www.reddit.com/r/OpenIMessaging)
+ 💬 [Follow our Twitter account](https://twitter.com/openimsdk)
## :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.

@ -15,118 +15,17 @@
package main
import (
"context"
"fmt"
"net"
"net/http"
_ "net/http/pprof"
"os"
"os/signal"
"strconv"
"syscall"
"time"
util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil"
"github.com/OpenIMSDK/tools/errs"
"github.com/OpenIMSDK/protocol/constant"
"github.com/OpenIMSDK/tools/discoveryregistry"
"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.AddPrometheusPortFlag()
apiCmd.AddApi(run)
if err := apiCmd.Execute(); err != nil {
util.ExitWithError(err)
}
}
func run(port int, proPort int) error {
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()
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.Config.Envs.Discovery)
if err != nil {
return errs.Wrap(err, "register discovery err")
}
if err = client.CreateRpcRootNodes(config.Config.GetServiceNames()); err != nil {
return errs.Wrap(err, "create rpc root nodes error")
}
if err = client.RegisterConf2Registry(constant.OpenIMCommonConfigKey, config.Config.EncodeConfig()); err != nil {
return err
}
var (
netDone = make(chan struct{}, 1)
netErr error
)
router := api.NewGinRouter(client, rdb)
if config.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.Config.Api.ListenIP != "" {
address = net.JoinHostPort(config.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.SIGUSR1Exit()
err := server.Shutdown(ctx)
if err != nil {
return errs.Wrap(err, "shutdown err")
}
case <-netDone:
close(netDone)
return netErr
}
return nil
}

@ -15,14 +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 {
if err := cronTaskCmd.Exec(); err != nil {
util.ExitWithError(err)
}
}

@ -24,7 +24,6 @@ func main() {
msgGatewayCmd.AddWsPortFlag()
msgGatewayCmd.AddPortFlag()
msgGatewayCmd.AddPrometheusPortFlag()
if err := msgGatewayCmd.Exec(); err != nil {
util.ExitWithError(err)
}

@ -17,18 +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 {
util.ExitWithError(err)
}
}

@ -17,19 +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 {
util.ExitWithError(err)
}
}

@ -17,18 +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 {
util.ExitWithError(err)
}
}

@ -17,18 +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 {
util.ExitWithError(err)
}
}

@ -17,18 +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 {
util.ExitWithError(err)
}
}

@ -17,18 +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 {
util.ExitWithError(err)
}
}

@ -17,18 +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 {
util.ExitWithError(err)
}
}

@ -17,18 +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 {
util.ExitWithError(err)
}
}

@ -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

@ -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"
}
],

@ -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

@ -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

@ -449,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 |

@ -26,19 +26,19 @@ jwt "github.com/dgrijalva/jwt-go/v4"
```go
import (
// go standard package
"fmt"
// go standard package
"fmt"
// third party package
"github.com/jinzhu/gorm"
"github.com/spf13/cobra"
"github.com/spf13/viper"
// 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"
// Anonymous packages are grouped separately, and anonymous package references are explained
// import mysql driver
_ "github.com/jinzhu/gorm/dialects/mysql"
// inner package
// 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"
// bad
sptr := new(T)
sptr.Name = "bar"
// good
sptr := &T{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
}
user := User{
Username: "belm",
Email: "nosbelm@qq.com",
type User struct{
Username string
Email string
}
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**
[![OpenIM golangci-lint](https://github.com/openimsdk/open-im-server/actions/workflows/golangci-lint.yml/badge.svg)](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.

@ -0,0 +1,186 @@
<p align="center">
<a href="https://openim.io">
<img src="../../assets/logo-gif/openim-logo.gif" width="60%" height="30%"/>
</a>
</p>
<div align="center">
[![Stars](https://img.shields.io/github/stars/openimsdk/open-im-server?style=for-the-badge&logo=github&colorB=ff69b4)](https://github.com/openimsdk/open-im-server/stargazers)
[![Forks](https://img.shields.io/github/forks/openimsdk/open-im-server?style=for-the-badge&logo=github&colorB=blue)](https://github.com/openimsdk/open-im-server/network/members)
[![Codecov](https://img.shields.io/codecov/c/github/openimsdk/open-im-server?style=for-the-badge&logo=codecov&colorB=orange)](https://app.codecov.io/gh/openimsdk/open-im-server)
[![Go Report Card](https://goreportcard.com/badge/github.com/openimsdk/open-im-server?style=for-the-badge)](https://goreportcard.com/report/github.com/openimsdk/open-im-server)
[![Go Reference](https://img.shields.io/badge/Go%20Reference-blue.svg?style=for-the-badge&logo=go&logoColor=white)](https://pkg.go.dev/github.com/openimsdk/open-im-server/v3)
[![License](https://img.shields.io/badge/license-Apache--2.0-green?style=for-the-badge)](https://github.com/openimsdk/open-im-server/blob/main/LICENSE)
[![Slack](https://img.shields.io/badge/Slack-500%2B-blueviolet?style=for-the-badge&logo=slack&logoColor=white)](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q)
[![Best Practices](https://img.shields.io/badge/Best%20Practices-purple?style=for-the-badge)](https://www.bestpractices.dev/projects/8045)
[![Good First Issues](https://img.shields.io/github/issues/openimsdk/open-im-server/good%20first%20issue?style=for-the-badge&logo=github)](https://github.com/openimsdk/open-im-server/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc+label%3A%22good+first+issue%22)
[![Language](https://img.shields.io/badge/Language-Go-blue.svg?style=for-the-badge&logo=go&logoColor=white)](https://golang.org/)
<p align="center">
<a href="../../README.md">Englist</a> ·
<a href="../../README_zh_CN.md">中文</a> ·
<a href="./README_uk.md">Українська</a> ·
<a href="./README_cs.md">Česky</a> ·
<a href="./README_hu.md">Magyar</a> ·
<a href="./README_es.md">Español</a> ·
<a href="./README_fa.md">فارسی</a> ·
<a href="./README_fr.md">Français</a> ·
<a href="./README_de.md">Deutsch</a> ·
<a href="./README_pl.md">Polski</a> ·
<a href="./README_id.md">Indonesian</a> ·
<a href="./README_fi.md">Suomi</a> ·
<a href="./README_ml.md">മലയാളം</a> ·
<a href="./README_ja.md">日本語</a> ·
<a href="./README_nl.md">Nederlands</a> ·
<a href="./README_it.md">Italiano</a> ·
<a href="./README_ru.md">Русский</a> ·
<a href="./README_pt_BR.md">Português (Brasil)</a> ·
<a href="./README_eo.md">Esperanto</a> ·
<a href="./README_ko.md">한국어</a> ·
<a href="./README_ar.md">العربي</a> ·
<a href="./README_vi.md">Tiếng Việt</a> ·
<a href="./README_da.md">Dansk</a> ·
<a href="./README_el.md">Ελληνικά</a> ·
<a href="./README_tr.md">Türkçe</a>
</p>
</div>
</p>
## Ⓜ️ Σχετικά με το OpenIM
Το OpenIM είναι μια πλατφόρμα υπηρεσιών σχεδιασμένη ειδικά για την ενσωμάτωση συνομιλίας, κλήσεων ήχου-βίντεο, ειδοποιήσεων και chatbots AI σε εφαρμογές. Παρέχει μια σειρά από ισχυρά API και Webhooks, επιτρέποντας στους προγραμματιστές να ενσωματώσουν εύκολα αυτές τις αλληλεπιδραστικές λειτουργίες στις εφαρμογές τους. Το OpenIM δεν είναι μια αυτόνομη εφαρμογή συνομιλίας, αλλά λειτουργεί ως πλατφόρμα υποστήριξης άλλων εφαρμογών για την επίτευξη πλούσιων λειτουργιών επικοινωνίας. Το παρακάτω διάγραμμα απεικονίζει την αλληλεπίδραση μεταξύ AppServer, AppClient, OpenIMServer και OpenIMSDK για να εξηγήσει αναλυτικά.
![App-OpenIM Relationship](../../docs/images/oepnim-design.png)
## 🚀 Σχετικά με το 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 με το διάγραμμα αρχιτεκτονικής μας.
![Overall Architecture](../../docs/images/architecture-layers.png)
## :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
[![Άνοιγμα σε Dev Container](https://img.shields.io/static/v1?label=Dev%20Container&message=Open&color=blue&logo=visualstudiocode)](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) προστατεύονται από τους νόμους περί πνευματικής ιδιοκτησίας.
## 🔮 Ευχαριστούμε τους συνεισφέροντες μας!
<a href="https://github.com/openimsdk/open-im-server/graphs/contributors">
<img src="https://contrib.rocks/image?repo=openimsdk/open-im-server" />
</a>

@ -5,7 +5,7 @@ go 1.19
require (
firebase.google.com/go v3.13.0+incompatible
github.com/OpenIMSDK/protocol v0.0.55
github.com/OpenIMSDK/tools v0.0.35
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

@ -20,8 +20,8 @@ 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.35 h1:YH8UYoaErXqfNrwpUvQxe8nhL++gFH6qCisQPyzk0w8=
github.com/OpenIMSDK/tools v0.0.35/go.mod h1:wBfR5CYmEyvxl03QJbTkhz1CluK6J4/lX0lviu8JAjE=
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=

@ -3,6 +3,7 @@ go 1.19
use (
.
./test/typecheck
./tools/codescan
./tools/changelog
./tools/component
./tools/data-conversion

@ -18,7 +18,7 @@
#
set -e
set -o pipefail
############################## OpenIM Github ##############################
# ... rest of the script ...

@ -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"
)

@ -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"
)

@ -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
}

@ -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

@ -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

@ -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
}

@ -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"
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
}
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
)
var client discoveryregistry.SvcDiscoveryRegistry
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中间件
// 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)
@ -157,8 +242,8 @@ func NewGinRouter(discov discoveryregistry.SvcDiscoveryRegistry, rdb redis.Unive
// 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)
@ -225,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 {
@ -241,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())
@ -250,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
@ -265,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
@ -286,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()
// }

@ -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"
)

@ -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)
}

@ -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...)

@ -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

@ -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)

@ -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")
}
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")
}
_ = reader.Close()
return compressedData, nil
return decompressedData, nil
}

@ -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++ {

@ -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
}

@ -17,8 +17,6 @@ package msggateway
import (
"context"
"google.golang.org/grpc"
"github.com/OpenIMSDK/protocol/constant"
"github.com/OpenIMSDK/protocol/msggateway"
"github.com/OpenIMSDK/tools/discoveryregistry"
@ -26,31 +24,32 @@ 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/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,
)
}
@ -60,18 +59,20 @@ type Server struct {
prometheusPort int
LongConnServer LongConnServer
pushTerminal []int
config *config.GlobalConfig
}
func (s *Server) SetLongConnServer(LongConnServer LongConnServer) {
s.LongConnServer = LongConnServer
}
func NewServer(rpcPort int, proPort int, longConnServer LongConnServer) *Server {
func NewServer(rpcPort int, proPort int, longConnServer LongConnServer, config *config.GlobalConfig) *Server {
return &Server{
rpcPort: rpcPort,
prometheusPort: proPort,
LongConnServer: longConnServer,
pushTerminal: []int{constant.IOSPlatformID, constant.AndroidPlatformID},
config: config,
}
}
@ -86,7 +87,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

@ -22,33 +22,25 @@ import (
)
// 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)
hubServer := NewServer(rpcPort, prometheusPort, longServer, conf)
netDone := make(chan error)
go func() {
err = hubServer.Start()
if err != nil {
netDone <- err
}
err = hubServer.Start(conf)
netDone <- err
}()
return hubServer.LongConnServer.Run(netDone)
}

@ -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() {

@ -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
}

@ -25,24 +25,21 @@ import (
"sync/atomic"
"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 {
@ -52,7 +49,7 @@ type LongConnServer interface {
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)
@ -61,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
@ -87,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
}
@ -107,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)
}
@ -128,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
}
@ -140,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,
@ -220,7 +223,7 @@ func (ws *WsServer) Run(done chan error) error {
var concurrentRequest = 3
func (ws *WsServer) sendUserOnlineInfoToOtherNode(ctx context.Context, client *Client) error {
conns, err := ws.disCov.GetConns(ctx, config.Config.RpcRegisterName.OpenImMessageGatewayName)
conns, err := ws.disCov.GetConns(ctx, ws.globalConfig.RpcRegisterName.OpenImMessageGatewayName)
if err != nil {
return err
}
@ -275,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 {
@ -285,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()
@ -328,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 {
@ -440,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 {

@ -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
}
)

@ -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)

@ -18,24 +18,13 @@ import (
"context"
"errors"
"fmt"
"github.com/OpenIMSDK/tools/errs"
"github.com/OpenIMSDK/tools/log"
util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil"
"net/http"
"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"
@ -43,22 +32,34 @@ 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 // 这个消费者聚合消息, 订阅的topicws2ms_chat, 修改通知发往msg_to_modify topic, 消息存入redis后Incr Redis, 再发消息到ms2pschat topic推送 发消息到msg_to_mongo topic持久化
historyMongoCH *OnlineHistoryMongoConsumerHandler // mongoDB批量插入, 成功后删除redis中消息以及处理删除通知消息删除的 订阅的topic: msg_to_mongo
ctx context.Context
cancel context.CancelFunc
// 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
}
@ -66,36 +67,42 @@ func StartTransfer(prometheusPort int) error {
if err = mongo.CreateMsgIndex(); err != nil {
return err
}
client, err := kdisc.NewDiscoveryRegister(config.Config.Envs.Discovery)
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, err := controller.NewCommonMsgDatabase(msgDocModel, msgModel)
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)
groupRpcClient := rpcclient.NewGroupRpcClient(client)
msgTransfer, err := NewMsgTransfer(msgDatabase, &conversationRpcClient, &groupRpcClient)
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)
return msgTransfer.Start(prometheusPort, config)
}
func NewMsgTransfer(msgDatabase controller.CommonMsgDatabase, conversationRpcClient *rpcclient.ConversationRpcClient, groupRpcClient *rpcclient.GroupRpcClient) (*MsgTransfer, error) {
historyCH, err := NewOnlineHistoryRedisConsumerHandler(msgDatabase, conversationRpcClient, groupRpcClient)
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(msgDatabase)
historyMongoCH, err := NewOnlineHistoryMongoConsumerHandler(config, msgDatabase)
if err != nil {
return nil, err
}
@ -103,10 +110,11 @@ func NewMsgTransfer(msgDatabase controller.CommonMsgDatabase, conversationRpcCli
return &MsgTransfer{
historyCH: historyCH,
historyMongoCH: historyMongoCH,
config: config,
}, nil
}
func (m *MsgTransfer) Start(prometheusPort int) error {
func (m *MsgTransfer) Start(prometheusPort int, config *config.GlobalConfig) error {
fmt.Println("start msg transfer", "prometheusPort:", prometheusPort)
if prometheusPort <= 0 {
return errs.Wrap(errors.New("prometheusPort not correct"))
@ -118,19 +126,16 @@ func (m *MsgTransfer) Start(prometheusPort int) error {
netErr error
)
onError := func(ctx context.Context, err error, errInfo string) {
log.ZWarn(ctx, errInfo, err)
}
go m.historyCH.historyConsumerGroup.RegisterHandleAndConsumer(m.ctx, m.historyCH, onError)
go m.historyMongoCH.historyConsumerGroup.RegisterHandleAndConsumer(m.ctx, m.historyMongoCH, onError)
go m.historyCH.historyConsumerGroup.RegisterHandleAndConsumer(m.ctx, m.historyCH)
go m.historyMongoCH.historyConsumerGroup.RegisterHandleAndConsumer(m.ctx, m.historyMongoCH)
if config.Config.Prometheus.Enable {
if config.Prometheus.Enable {
go func() {
proreg := prometheus.NewRegistry()
proreg.MustRegister(
collectors.NewGoCollector(),
)
proreg.MustRegister(prommetrics.GetGrpcCusMetrics("Transfer")...)
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 {
@ -144,12 +149,12 @@ func (m *MsgTransfer) Start(prometheusPort int) error {
signal.Notify(sigs, syscall.SIGTERM)
select {
case <-sigs:
util.SIGUSR1Exit()
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()
@ -157,6 +162,4 @@ func (m *MsgTransfer) Start(prometheusPort int) error {
close(netDone)
return netErr
}
return nil
}

@ -22,24 +22,20 @@ import (
"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 (
@ -74,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
@ -85,6 +81,7 @@ type OnlineHistoryRedisConsumerHandler struct {
}
func NewOnlineHistoryRedisConsumerHandler(
config *config.GlobalConfig,
database controller.CommonMsgDatabase,
conversationRpcClient *rpcclient.ConversationRpcClient,
groupRpcClient *rpcclient.GroupRpcClient,
@ -100,79 +97,86 @@ func NewOnlineHistoryRedisConsumerHandler(
och.conversationRpcClient = conversationRpcClient
och.groupRpcClient = groupRpcClient
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, 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) {
@ -193,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()
}
@ -268,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
}
}
@ -441,6 +446,7 @@ func (och *OnlineHistoryRedisConsumerHandler) ConsumeClaim(
wg = sync.WaitGroup{}
running = new(atomic.Bool)
)
running.Store(true)
wg.Add(1)
go func() {

@ -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,12 +32,28 @@ type OnlineHistoryMongoConsumerHandler struct {
msgDatabase controller.CommonMsgDatabase
}
func NewOnlineHistoryMongoConsumerHandler(database controller.CommonMsgDatabase) (*OnlineHistoryMongoConsumerHandler, error) {
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,
}
}
historyConsumerGroup, err := kfk.NewMConsumerGroup(&kfk.MConsumerGroupConfig{
KafkaVersion: sarama.V2_0_0_0,
OffsetsInitial: sarama.OffsetNewest, IsReturnErr: false,
}, []string{config.Config.Kafka.MsgToMongo.Topic},
config.Config.Kafka.Addr, config.Config.Kafka.ConsumerGroupID.MsgToMongo)
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
}

@ -21,23 +21,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{
@ -59,10 +55,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
}
@ -72,8 +70,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{
@ -95,7 +93,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
@ -103,11 +101,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{
@ -127,7 +126,7 @@ 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
}

@ -17,16 +17,17 @@ package push
import (
"context"
"github.com/OpenIMSDK/tools/log"
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
)
type Consumer struct {
pushCh ConsumerHandler
successCount uint64
pushCh ConsumerHandler
// successCount is unused
// successCount uint64
}
func NewConsumer(pusher *Pusher) (*Consumer, error) {
c, err := NewConsumerHandler(pusher)
func NewConsumer(config *config.GlobalConfig, pusher *Pusher) (*Consumer, error) {
c, err := NewConsumerHandler(config, pusher)
if err != nil {
return nil, err
}
@ -36,9 +37,5 @@ func NewConsumer(pusher *Pusher) (*Consumer, error) {
}
func (c *Consumer) Start() {
onError := func(ctx context.Context, err error, errInfo string) {
log.ZWarn(ctx, errInfo, err)
}
go c.pushCh.pushConsumerGroup.RegisterHandleAndConsumer(context.Background(), &c.pushCh, onError)
go c.pushCh.pushConsumerGroup.RegisterHandleAndConsumer(context.Background(), &c.pushCh)
}

@ -20,14 +20,12 @@ 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 +37,22 @@ type Fcm struct {
cache cache.MsgModel
}
func NewClient(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 +125,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

@ -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
}

@ -23,19 +23,15 @@ 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,10 +55,15 @@ type Client struct {
cache cache.MsgModel
tokenExpireTime int64
taskIDTTL int64
config *config.GlobalConfig
}
func NewClient(cache cache.MsgModel) *Client {
return &Client{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 *Client) Push(ctx context.Context, userIDs []string, title, content string, opts *offlinepush.Opts) error {
@ -78,7 +79,7 @@ func (g *Client) Push(ctx context.Context, userIDs []string, title, content stri
return err
}
}
pushReq := newPushReq(title, content)
pushReq := newPushReq(g.config, title, content)
pushReq.setPushChannel(title, content)
if len(userIDs) > 1 {
maxNum := 999
@ -89,9 +90,9 @@ func (g *Client) Push(ctx context.Context, userIDs []string, title, content stri
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)
}
@ -114,13 +115,13 @@ func (g *Client) Push(ctx context.Context, userIDs []string, title, content stri
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)
@ -137,7 +138,7 @@ func (g *Client) GetTaskID(ctx context.Context, token string, pushReq PushReq) (
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
}
@ -163,7 +164,7 @@ func (g *Client) request(ctx context.Context, url string, input any, token strin
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 *Client) postReturn(

@ -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() {

@ -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 NewClient() *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,

@ -18,16 +18,14 @@ import (
"context"
"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 {
@ -35,15 +33,29 @@ type ConsumerHandler struct {
pusher *Pusher
}
func NewConsumerHandler(pusher *Pusher) (*ConsumerHandler, error) {
func NewConsumerHandler(config *config.GlobalConfig, pusher *Pusher) (*ConsumerHandler, error) {
var consumerHandler ConsumerHandler
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)
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
}

@ -17,37 +17,37 @@ package push
import (
"context"
"github.com/OpenIMSDK/tools/utils"
"google.golang.org/grpc"
"github.com/OpenIMSDK/protocol/constant"
pbpush "github.com/OpenIMSDK/protocol/push"
"github.com/OpenIMSDK/tools/discoveryregistry"
"github.com/OpenIMSDK/tools/log"
"github.com/OpenIMSDK/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/localcache"
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
"google.golang.org/grpc"
)
type pushServer struct {
pusher *Pusher
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
}
cacheModel := cache.NewMsgCacheModel(rdb)
offlinePusher := NewOfflinePusher(cacheModel)
cacheModel := cache.NewMsgCacheModel(rdb, config)
offlinePusher := NewOfflinePusher(config, cacheModel)
database := controller.NewPushDatabase(cacheModel)
groupRpcClient := rpcclient.NewGroupRpcClient(client)
conversationRpcClient := rpcclient.NewConversationRpcClient(client)
msgRpcClient := rpcclient.NewMessageRpcClient(client)
groupRpcClient := rpcclient.NewGroupRpcClient(client, config)
conversationRpcClient := rpcclient.NewConversationRpcClient(client, config)
msgRpcClient := rpcclient.NewMessageRpcClient(client, config)
pusher := NewPusher(
config,
client,
offlinePusher,
database,
@ -60,9 +60,10 @@ func Start(client discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) e
pbpush.RegisterPushMsgServiceServer(server, &pushServer{
pusher: pusher,
config: config,
})
consumer, err := NewConsumer(pusher)
consumer, err := NewConsumer(config, pusher)
if err != nil {
return err
}

@ -20,10 +20,6 @@ import (
"errors"
"sync"
"google.golang.org/grpc"
"golang.org/x/sync/errgroup"
"github.com/OpenIMSDK/protocol/constant"
"github.com/OpenIMSDK/protocol/conversation"
"github.com/OpenIMSDK/protocol/msggateway"
@ -32,7 +28,6 @@ import (
"github.com/OpenIMSDK/tools/log"
"github.com/OpenIMSDK/tools/mcontext"
"github.com/OpenIMSDK/tools/utils"
"github.com/openimsdk/open-im-server/v3/internal/push/offlinepush"
"github.com/openimsdk/open-im-server/v3/internal/push/offlinepush/dummy"
"github.com/openimsdk/open-im-server/v3/internal/push/offlinepush/fcm"
@ -45,9 +40,12 @@ import (
"github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics"
"github.com/openimsdk/open-im-server/v3/pkg/msgprocessor"
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
"golang.org/x/sync/errgroup"
"google.golang.org/grpc"
)
type Pusher struct {
config *config.GlobalConfig
database controller.PushDatabase
discov discoveryregistry.SvcDiscoveryRegistry
offlinePusher offlinepush.OfflinePusher
@ -60,11 +58,12 @@ type Pusher struct {
var errNoOfflinePusher = errors.New("no offlinePusher is configured")
func NewPusher(discov discoveryregistry.SvcDiscoveryRegistry, offlinePusher offlinepush.OfflinePusher, database controller.PushDatabase,
func NewPusher(config *config.GlobalConfig, discov discoveryregistry.SvcDiscoveryRegistry, offlinePusher offlinepush.OfflinePusher, database controller.PushDatabase,
groupLocalCache *localcache.GroupLocalCache, conversationLocalCache *localcache.ConversationLocalCache,
conversationRpcClient *rpcclient.ConversationRpcClient, groupRpcClient *rpcclient.GroupRpcClient, msgRpcClient *rpcclient.MessageRpcClient,
) *Pusher {
return &Pusher{
config: config,
discov: discov,
database: database,
offlinePusher: offlinePusher,
@ -76,15 +75,15 @@ func NewPusher(discov discoveryregistry.SvcDiscoveryRegistry, offlinePusher offl
}
}
func NewOfflinePusher(cache cache.MsgModel) offlinepush.OfflinePusher {
func NewOfflinePusher(config *config.GlobalConfig, cache cache.MsgModel) offlinepush.OfflinePusher {
var offlinePusher offlinepush.OfflinePusher
switch config.Config.Push.Enable {
switch config.Push.Enable {
case "getui":
offlinePusher = getui.NewClient(cache)
offlinePusher = getui.NewClient(config, cache)
case "fcm":
offlinePusher = fcm.NewClient(cache)
offlinePusher = fcm.NewClient(config, cache)
case "jpush":
offlinePusher = jpush.NewClient()
offlinePusher = jpush.NewClient(config)
default:
offlinePusher = dummy.NewClient()
}
@ -102,7 +101,7 @@ func (p *Pusher) DeleteMemberAndSetConversationSeq(ctx context.Context, groupID
func (p *Pusher) Push2User(ctx context.Context, userIDs []string, msg *sdkws.MsgData) error {
log.ZDebug(ctx, "Get msg from msg_transfer And push msg", "userIDs", userIDs, "msg", msg.String())
if err := callbackOnlinePush(ctx, userIDs, msg); err != nil {
if err := callbackOnlinePush(ctx, p.config, userIDs, msg); err != nil {
return err
}
// push
@ -130,7 +129,7 @@ func (p *Pusher) Push2User(ctx context.Context, userIDs []string, msg *sdkws.Msg
})
if len(offlinePushUserIDList) > 0 {
if err = callbackOfflinePush(ctx, offlinePushUserIDList, msg, &[]string{}); err != nil {
if err = callbackOfflinePush(ctx, p.config, offlinePushUserIDList, msg, &[]string{}); err != nil {
return err
}
err = p.offlinePushMsg(ctx, msg.SendID, msg, offlinePushUserIDList)
@ -163,7 +162,7 @@ func (p *Pusher) k8sOfflinePush2SuperGroup(ctx context.Context, groupID string,
}
if len(needOfflinePushUserIDs) > 0 {
var offlinePushUserIDs []string
err := callbackOfflinePush(ctx, needOfflinePushUserIDs, msg, &offlinePushUserIDs)
err := callbackOfflinePush(ctx, p.config, needOfflinePushUserIDs, msg, &offlinePushUserIDs)
if err != nil {
return err
}
@ -194,7 +193,7 @@ func (p *Pusher) k8sOfflinePush2SuperGroup(ctx context.Context, groupID string,
func (p *Pusher) Push2SuperGroup(ctx context.Context, groupID string, msg *sdkws.MsgData) (err error) {
log.ZDebug(ctx, "Get super group msg from msg_transfer and push msg", "msg", msg.String(), "groupID", groupID)
var pushToUserIDs []string
if err = callbackBeforeSuperGroupOnlinePush(ctx, groupID, msg, &pushToUserIDs); err != nil {
if err = callbackBeforeSuperGroupOnlinePush(ctx, p.config, groupID, msg, &pushToUserIDs); err != nil {
return err
}
@ -229,17 +228,18 @@ func (p *Pusher) Push2SuperGroup(ctx context.Context, groupID string, msg *sdkws
}(groupID, kickedUsers)
pushToUserIDs = append(pushToUserIDs, kickedUsers...)
case constant.GroupDismissedNotification:
if msgprocessor.IsNotification(msgprocessor.GetConversationIDByMsg(msg)) { // 消息先到,通知后到
// Messages arrive first, notifications arrive later
if msgprocessor.IsNotification(msgprocessor.GetConversationIDByMsg(msg)) {
var tips sdkws.GroupDismissedTips
if p.UnmarshalNotificationElem(msg.Content, &tips) != nil {
return err
}
log.ZInfo(ctx, "GroupDismissedNotificationInfo****", "groupID", groupID, "num", len(pushToUserIDs), "list", pushToUserIDs)
if len(config.Config.Manager.UserID) > 0 {
ctx = mcontext.WithOpUserIDContext(ctx, config.Config.Manager.UserID[0])
if len(p.config.Manager.UserID) > 0 {
ctx = mcontext.WithOpUserIDContext(ctx, p.config.Manager.UserID[0])
}
if len(config.Config.Manager.UserID) == 0 && len(config.Config.IMAdmin.UserID) > 0 {
ctx = mcontext.WithOpUserIDContext(ctx, config.Config.IMAdmin.UserID[0])
if len(p.config.Manager.UserID) == 0 && len(p.config.IMAdmin.UserID) > 0 {
ctx = mcontext.WithOpUserIDContext(ctx, p.config.IMAdmin.UserID[0])
}
defer func(groupID string) {
if err = p.groupRpcClient.DismissGroup(ctx, groupID); err != nil {
@ -257,10 +257,10 @@ func (p *Pusher) Push2SuperGroup(ctx context.Context, groupID string, msg *sdkws
log.ZDebug(ctx, "get conn and online push success", "result", wsResults, "msg", msg)
isOfflinePush := utils.GetSwitchFromOptions(msg.Options, constant.IsOfflinePush)
if isOfflinePush && config.Config.Envs.Discovery == "k8s" {
if isOfflinePush && p.config.Envs.Discovery == "k8s" {
return p.k8sOfflinePush2SuperGroup(ctx, groupID, msg, wsResults)
}
if isOfflinePush && config.Config.Envs.Discovery == "zookeeper" {
if isOfflinePush && p.config.Envs.Discovery == "zookeeper" {
var (
onlineSuccessUserIDs = []string{msg.SendID}
webAndPcBackgroundUserIDs []string
@ -298,7 +298,7 @@ func (p *Pusher) Push2SuperGroup(ctx context.Context, groupID string, msg *sdkws
// Use offline push messaging
if len(needOfflinePushUserIDs) > 0 {
var offlinePushUserIDs []string
err = callbackOfflinePush(ctx, needOfflinePushUserIDs, msg, &offlinePushUserIDs)
err = callbackOfflinePush(ctx, p.config, needOfflinePushUserIDs, msg, &offlinePushUserIDs)
if err != nil {
return err
}
@ -357,7 +357,7 @@ func (p *Pusher) k8sOnlinePush(ctx context.Context, msg *sdkws.MsgData, pushToUs
var (
mu sync.Mutex
wg = errgroup.Group{}
maxWorkers = config.Config.Push.MaxConcurrentWorkers
maxWorkers = p.config.Push.MaxConcurrentWorkers
)
if maxWorkers < 3 {
maxWorkers = 3
@ -386,10 +386,10 @@ func (p *Pusher) k8sOnlinePush(ctx context.Context, msg *sdkws.MsgData, pushToUs
return wsResults, nil
}
func (p *Pusher) GetConnsAndOnlinePush(ctx context.Context, msg *sdkws.MsgData, pushToUserIDs []string) (wsResults []*msggateway.SingleMsgToUserResults, err error) {
if config.Config.Envs.Discovery == "k8s" {
if p.config.Envs.Discovery == "k8s" {
return p.k8sOnlinePush(ctx, msg, pushToUserIDs)
}
conns, err := p.discov.GetConns(ctx, config.Config.RpcRegisterName.OpenImMessageGatewayName)
conns, err := p.discov.GetConns(ctx, p.config.RpcRegisterName.OpenImMessageGatewayName)
log.ZDebug(ctx, "get gateway conn", "conn length", len(conns))
if err != nil {
return nil, err
@ -399,7 +399,7 @@ func (p *Pusher) GetConnsAndOnlinePush(ctx context.Context, msg *sdkws.MsgData,
mu sync.Mutex
wg = errgroup.Group{}
input = &msggateway.OnlineBatchPushOneMsgReq{MsgData: msg, PushToUserIDs: pushToUserIDs}
maxWorkers = config.Config.Push.MaxConcurrentWorkers
maxWorkers = p.config.Push.MaxConcurrentWorkers
)
if maxWorkers < 3 {

@ -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,17 +75,17 @@ 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); err != nil {
if err := authverify.CheckAdmin(ctx, s.config); err != nil {
return nil, err
}
resp := pbauth.GetUserTokenResp{}
if authverify.IsManagerUserID(req.UserID) {
if authverify.IsManagerUserID(req.UserID, s.config) {
return nil, errs.ErrNoPermission.Wrap("don't get Admin token")
}
@ -98,14 +97,14 @@ func (s *authServer) GetUserToken(ctx context.Context, req *pbauth.GetUserTokenR
return nil, err
}
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) 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 {
@ -121,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()
@ -143,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 {
@ -153,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
}

@ -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,6 +45,7 @@ type conversationServer struct {
groupRpcClient *rpcclient.GroupRpcClient
conversationDatabase controller.ConversationDatabase
conversationNotificationSender *notification.ConversationNotificationSender
config *config.GlobalConfig
}
func (c *conversationServer) GetConversationNotReceiveMessageUserIDs(
@ -59,28 +56,29 @@ func (c *conversationServer) GetConversationNotReceiveMessageUserIDs(
panic("implement me")
}
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
}
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
}
@ -310,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 {
@ -321,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 {
@ -378,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
}

@ -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})

@ -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

@ -17,31 +17,25 @@ package friend
import (
"context"
"github.com/OpenIMSDK/tools/tx"
"github.com/OpenIMSDK/protocol/sdkws"
"github.com/openimsdk/open-im-server/v3/pkg/authverify"
"github.com/OpenIMSDK/tools/log"
"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"
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 {
@ -51,42 +45,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),
)
@ -105,7 +101,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
@ -113,15 +110,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 {
@ -138,7 +134,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
@ -147,7 +143,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 {
@ -159,7 +155,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
}
@ -173,7 +169,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
@ -183,7 +179,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
}
@ -194,7 +190,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)
@ -230,7 +226,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
@ -240,7 +236,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{}
@ -254,7 +250,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)
@ -278,6 +274,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)
@ -292,7 +289,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 {
@ -311,7 +308,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{}

@ -18,7 +18,6 @@ import (
"context"
pbgroup "github.com/OpenIMSDK/protocol/group"
"github.com/openimsdk/open-im-server/v3/pkg/common/convert"
)

@ -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

@ -16,7 +16,6 @@ package group
import (
"github.com/OpenIMSDK/protocol/sdkws"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
)

@ -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 {

@ -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,6 +99,7 @@ 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) {
@ -114,7 +108,6 @@ func (s *groupServer) GetJoinedGroupIDs(ctx context.Context, req *pbgroup.GetJoi
}
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
@ -126,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
@ -205,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)
@ -224,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
@ -243,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)
@ -311,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
}
@ -320,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)
@ -390,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)
@ -402,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 {
@ -446,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)
@ -546,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]
@ -618,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
@ -744,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
@ -765,8 +757,8 @@ func (s *groupServer) GroupApplicationResponse(ctx context.Context, req *pbgroup
return nil, errs.ErrGroupRequestHandled.Wrap("group request already processed")
}
var inGroup bool
if _, err := s.db.TakeGroupMember(ctx, req.GroupID, req.FromUserID); err == nil {
inGroup = true // 已经在群里了
if _, takeErr := s.db.TakeGroupMember(ctx, req.GroupID, req.FromUserID); takeErr == nil {
inGroup = true // Already in group
} else if !s.IsNotFound(err) {
return nil, err
}
@ -788,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
}
}
@ -836,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)
@ -857,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 {
@ -868,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
@ -882,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)
@ -894,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
}
}
@ -918,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
@ -935,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 {
@ -948,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)
@ -956,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)
@ -1017,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
@ -1054,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")
}
@ -1063,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)
@ -1195,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")
}
@ -1207,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 {
@ -1237,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
}
@ -1253,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
@ -1287,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
@ -1346,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
}
@ -1429,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
}
}
@ -1456,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
}
}

@ -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
}

@ -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

@ -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

@ -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

@ -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.User.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
@ -112,11 +109,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,
@ -136,7 +133,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

@ -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)
}
@ -165,18 +164,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)
}

@ -15,20 +15,17 @@
package msg
import (
"context"
"google.golang.org/grpc"
"github.com/OpenIMSDK/protocol/constant"
"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/localcache"
"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 (
@ -44,6 +41,7 @@ type (
ConversationLocalCache *localcache.ConversationLocalCache
Handlers MessageInterceptorChain
notificationSender *rpcclient.NotificationSender
config *config.GlobalConfig
}
)
@ -51,36 +49,36 @@ 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, err := 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
}
@ -93,8 +91,9 @@ func Start(client discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) e
GroupLocalCache: localcache.NewGroupLocalCache(&groupRpcClient),
ConversationLocalCache: localcache.NewConversationLocalCache(&conversationClient),
friend: &friendRpcClient,
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

@ -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"
)

@ -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)

@ -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

@ -25,8 +25,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}
@ -51,10 +49,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 &&
@ -68,7 +66,7 @@ func (m *msgServer) messageVerification(ctx context.Context, data *msg.SendMsgRe
if black {
return errs.ErrBlockedByPeer.Wrap()
}
if *config.Config.MessageVerify.FriendVerify {
if *m.config.MessageVerify.FriendVerify {
friend, err := m.friend.IsFriend(ctx, data.MsgData.SendID, data.MsgData.RecvID)
if err != nil {
return err
@ -91,10 +89,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 &&
@ -159,9 +157,6 @@ func (m *msgServer) encapsulateMsgData(msg *sdkws.MsgData) {
case constant.Custom:
fallthrough
case constant.Quote:
utils.SetSwitchFromOptions(msg.Options, constant.IsConversationUpdate, true)
utils.SetSwitchFromOptions(msg.Options, constant.IsUnreadCount, true)
utils.SetSwitchFromOptions(msg.Options, constant.IsSenderSync, true)
case constant.Revoke:
utils.SetSwitchFromOptions(msg.Options, constant.IsUnreadCount, false)
utils.SetSwitchFromOptions(msg.Options, constant.IsOfflinePush, false)

@ -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 (

@ -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)

@ -17,66 +17,63 @@ package third
import (
"context"
"fmt"
"github.com/OpenIMSDK/tools/errs"
"net/url"
"time"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/mgo"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/unrelation"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/s3"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/s3/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/mgo"
"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"
"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) {

@ -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)
}

@ -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

@ -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,6 +51,7 @@ type userServer struct {
friendRpcClient *rpcclient.FriendRpcClient
groupRpcClient *rpcclient.GroupRpcClient
RegisterCenter registry.SvcDiscoveryRegistry
config *config.GlobalConfig
}
func (s *userServer) GetGroupOnlineUser(ctx context.Context, req *pbuser.GetGroupOnlineUserReq) (*pbuser.GetGroupOnlineUserResp, error) {
@ -66,39 +59,40 @@ func (s *userServer) GetGroupOnlineUser(ctx context.Context, req *pbuser.GetGrou
panic("implement me")
}
func Start(client registry.SvcDiscoveryRegistry, server *grpc.Server) error {
rdb, err := cache.NewRedis()
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)
@ -111,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)
@ -136,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)
@ -172,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
}
@ -205,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
}
@ -252,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 }) {
@ -276,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()
@ -296,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
@ -391,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
}
@ -422,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
}
@ -445,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
}
@ -477,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
}
@ -506,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
}
@ -535,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
}
@ -578,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
}
@ -605,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
}
@ -679,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,

@ -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 {

@ -23,41 +23,39 @@ import (
"time"
"github.com/OpenIMSDK/tools/errs"
"github.com/redis/go-redis/v9"
"github.com/robfig/cron/v3"
"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)
func StartTask(config *config.GlobalConfig) error {
fmt.Println("cron task start, config", config.ChatRecordsClearTime)
msgTool, err := InitMsgTool()
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()
fmt.Println("start chatRecordsClearTime cron task", "cron config", config.Config.ChatRecordsClearTime)
_, err = crontab.AddFunc(config.Config.ChatRecordsClearTime, cronWrapFunc(rdb, "cron_clear_msg_and_fix_seq", msgTool.AllConversationClearMsgAndFixSeq))
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 {
return errs.Wrap(err)
}
fmt.Println("start msgDestruct cron task", "cron config", config.Config.MsgDestructTime)
_, err = crontab.AddFunc(config.Config.MsgDestructTime, cronWrapFunc(rdb, "cron_conversations_destruct_msgs", msgTool.ConversationsDestructMsgs))
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 {
return errs.Wrap(err)
return errs.Wrap(err, "cron_conversations_destruct_msgs")
}
// start crontab
@ -93,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 {

@ -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
}

@ -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,32 +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, err := controller.InitCommonMsgDatabase(rdb, mongo.GetDatabase())
msgDatabase, err := controller.InitCommonMsgDatabase(rdb, mongo.GetDatabase(config.Mongo.Database), config)
if err != nil {
return nil, err
}
userMongoDB := unrelation.NewUserMongoDriver(mongo.GetDatabase())
userMongoDB := unrelation.NewUserMongoDriver(mongo.GetDatabase(config.Mongo.Database))
ctxTx := tx.NewMongo(mongo.GetClient())
userDatabase := controller.NewUserDatabase(
userDB,
@ -96,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
}
@ -118,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
}
@ -182,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)
@ -197,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
}
@ -219,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 {

@ -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"
)

@ -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"`

@ -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
}

@ -16,7 +16,6 @@ package callbackstruct
import (
common "github.com/OpenIMSDK/protocol/sdkws"
"github.com/openimsdk/open-im-server/v3/pkg/apistruct"
)

@ -16,33 +16,42 @@ package cmd
import (
"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 {
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
}

@ -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
}

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

Loading…
Cancel
Save